From 49154fbec68bb4f19a42379d209f3bb6bf901254 Mon Sep 17 00:00:00 2001 From: wiechula Date: Fri, 19 Feb 2021 12:59:43 +0100 Subject: [PATCH 1/4] Link-based zero suppression in RawReader o add automatic detection and processing of link-based zero suppression in raw reader o processing helper to decode zero suppressed data from memory and fill data using a callback funciton o minor code cleanup --- .../DataFormatsTPC/ZeroSuppressionLinkBased.h | 2 + Detectors/TPC/calibration/macro/drawPulser.C | 10 +- Detectors/TPC/calibration/macro/runPulser.C | 9 +- .../TPC/calibration/src/CalibRawBase.cxx | 6 + Detectors/TPC/reconstruction/CMakeLists.txt | 4 +- .../TPCReconstruction/RawProcessingHelpers.h | 32 ++++ .../include/TPCReconstruction/RawReaderCRU.h | 98 +++++++--- .../src/RawProcessingHelpers.cxx | 105 ++++++++++ .../TPC/reconstruction/src/RawReaderCRU.cxx | 179 +++++++++--------- 9 files changed, 319 insertions(+), 126 deletions(-) create mode 100644 Detectors/TPC/reconstruction/include/TPCReconstruction/RawProcessingHelpers.h create mode 100644 Detectors/TPC/reconstruction/src/RawProcessingHelpers.cxx diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/ZeroSuppressionLinkBased.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/ZeroSuppressionLinkBased.h index c7cbde57af313..956c0c667b417 100644 --- a/DataFormats/Detectors/TPC/include/DataFormatsTPC/ZeroSuppressionLinkBased.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/ZeroSuppressionLinkBased.h @@ -54,6 +54,8 @@ struct Header { return std::bitset<80>((std::bitset<80>(bitMaskHigh) << 64) | std::bitset<80>(bitMaskLow)); } + bool isFillWord() const { return (word0 == 0xffffffffffffffff) && (word1 == 0xffffffffffffffff); } + bool hasCorrectMagicWord() const { return magicWord == MagicWord; } }; diff --git a/Detectors/TPC/calibration/macro/drawPulser.C b/Detectors/TPC/calibration/macro/drawPulser.C index 34a595cbeedc8..485bb5e222c5a 100644 --- a/Detectors/TPC/calibration/macro/drawPulser.C +++ b/Detectors/TPC/calibration/macro/drawPulser.C @@ -138,17 +138,17 @@ TObjArray* drawPulser(TString pulserFile, int mode = 0, std::string_view outDir const auto medianWidth = TMath::Median(rocWidth.getData().size(), rocWidth.getData().data()); const auto medianQtot = TMath::Median(rocQtot.getData().size(), rocQtot.getData().data()); - const float rangeT0 = 1.5; + const float rangeT0 = 0.5; const float minT0 = medianT0 - rangeT0; const float maxT0 = medianT0 + rangeT0; - const float rangeWidth = 0.1; + const float rangeWidth = 0.5; const float minWidth = medianWidth - rangeWidth; const float maxWidth = medianWidth + rangeWidth; - const float rangeQtot = 150; - const float minQtot = medianQtot - 50; - const float maxQtot = medianQtot + rangeQtot; + //const float rangeQtot = 150; + const float minQtot = medianQtot / 2.; + const float maxQtot = medianQtot * 2.; // ===| histograms for calT0, calWidth and calQtot |=== auto hT0 = new TH1F(Form("hT0%02d", iroc), Form("T0 distribution ROC %02d;time bins (0.2 #mus)", iroc), 100, minT0, maxT0); diff --git a/Detectors/TPC/calibration/macro/runPulser.C b/Detectors/TPC/calibration/macro/runPulser.C index 4db55cb3ff669..4b4ded15cf3f8 100644 --- a/Detectors/TPC/calibration/macro/runPulser.C +++ b/Detectors/TPC/calibration/macro/runPulser.C @@ -29,7 +29,8 @@ void runPulser(std::vector fileInfos, TString outputFileName = calib.setADCRange(adcMin, adcMax); calib.setTimeBinRange(firstTimeBin, lastTimeBin); calib.setDebugLevel(); - calib.setQtotBinning(140, 22, 302); + //calib.setQtotBinning(140, 22, 302); + calib.setQtotBinning(500, 10, 1010); if (type == 1) { calib.setQtotBinning(150, 2, 302); calib.setMinQtot(8); @@ -66,10 +67,8 @@ void runPulser(std::vector fileInfos, TString outputFileName = for (Int_t i = 0; i < nevents; ++i) { status = calib.processEvent(i); std::cout << "Processing event " << i << " with status " << int(status) << '\n'; - if (status == CalibRawBase::ProcessStatus::IncompleteEvent) { - continue; - } else if (status != CalibRawBase::ProcessStatus::Ok) { - //break; + if (status == CalibRawBase::ProcessStatus::LastEvent) { + break; } } } diff --git a/Detectors/TPC/calibration/src/CalibRawBase.cxx b/Detectors/TPC/calibration/src/CalibRawBase.cxx index 79328a2110cfd..d00e19f2b2083 100644 --- a/Detectors/TPC/calibration/src/CalibRawBase.cxx +++ b/Detectors/TPC/calibration/src/CalibRawBase.cxx @@ -14,6 +14,7 @@ #include "TSystem.h" #include "TObjString.h" #include "TObjArray.h" +#include "TPCBase/RDHUtils.h" #include "TPCCalibration/CalibRawBase.h" @@ -74,6 +75,11 @@ void CalibRawBase::setupContainers(TString fileInfo, uint32_t verbosity, uint32_ mProcessedTimeBins = std::max(mProcessedTimeBins, size_t(timeBins)); return timeBins; }); + mRawReaderCRUManager.setLinkZSCallback([this](int cru, int rowInSector, int padInRow, int timeBin, float adcValue) -> bool { + updateROC(CRU(cru).roc(), rowInSector - (rowInSector > 62) * 63, padInRow, timeBin, adcValue); + return true; + }); + for (auto file : *arr) { // fix the number of time bins auto& reader = mRawReaderCRUManager.createReader(file->GetName(), timeBins); diff --git a/Detectors/TPC/reconstruction/CMakeLists.txt b/Detectors/TPC/reconstruction/CMakeLists.txt index 4c74d866cb587..0cd7aed576691 100644 --- a/Detectors/TPC/reconstruction/CMakeLists.txt +++ b/Detectors/TPC/reconstruction/CMakeLists.txt @@ -27,6 +27,7 @@ o2_add_library(TPCReconstruction src/DigitalCurrentClusterIntegrator.cxx src/TPCFastTransformHelperO2.cxx src/CTFCoder.cxx + src/RawProcessingHelpers.cxx PUBLIC_LINK_LIBRARIES FairRoot::Base O2::SimulationDataFormat O2::TPCBase @@ -54,7 +55,8 @@ o2_target_root_dictionary( include/TPCReconstruction/HardwareClusterDecoder.h include/TPCReconstruction/DigitalCurrentClusterIntegrator.h include/TPCReconstruction/TPCFastTransformHelperO2.h - include/TPCReconstruction/CTFCoder.h) + include/TPCReconstruction/CTFCoder.h + include/TPCReconstruction/RawProcessingHelpers.h) o2_add_executable(read-gbtframes COMPONENT_NAME tpc diff --git a/Detectors/TPC/reconstruction/include/TPCReconstruction/RawProcessingHelpers.h b/Detectors/TPC/reconstruction/include/TPCReconstruction/RawProcessingHelpers.h new file mode 100644 index 0000000000000..161d2f79dfe55 --- /dev/null +++ b/Detectors/TPC/reconstruction/include/TPCReconstruction/RawProcessingHelpers.h @@ -0,0 +1,32 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_TPC_RawProcessingHelpers_H +#define O2_TPC_RawProcessingHelpers_H + +#include + +#include "TPCBase/RDHUtils.h" + +namespace o2 +{ +namespace tpc +{ +namespace raw_processing_helpers +{ + +using ADCCallback = std::function; + +bool processZSdata(const char* data, size_t size, rdh_utils::FEEIDType feeId, uint32_t globalBCoffset, ADCCallback fillADC); + +} // namespace raw_processing_helpers +} // namespace tpc +} // namespace o2 +#endif diff --git a/Detectors/TPC/reconstruction/include/TPCReconstruction/RawReaderCRU.h b/Detectors/TPC/reconstruction/include/TPCReconstruction/RawReaderCRU.h index a1562e2f84e76..0938c7b60a3ed 100644 --- a/Detectors/TPC/reconstruction/include/TPCReconstruction/RawReaderCRU.h +++ b/Detectors/TPC/reconstruction/include/TPCReconstruction/RawReaderCRU.h @@ -34,8 +34,11 @@ #include "MemoryResources/Types.h" #include "TPCBase/CRU.h" #include "Headers/RAWDataHeader.h" +#include "Headers/RDHAny.h" #include "TPCBase/PadPos.h" #include "TPCBase/PadROCPos.h" +#include "TPCBase/RDHUtils.h" +#include "TPCReconstruction/RawProcessingHelpers.h" //#include "git_info.hpp" namespace o2 @@ -46,6 +49,7 @@ namespace rawreader { using RDHUtils = o2::raw::RDHUtils; +using RDH = o2::header::RDHAny; /// debug level bits enum DebugLevel : uint8_t { @@ -75,7 +79,6 @@ enum class RAWDataType : uint8_t { LinkZS = 1, ///< Link based zero suppression }; -using RDH = o2::header::RAWDataHeader; static constexpr int MaxNumberOfLinks = 24; ///< maximum number of links // =========================================================================== @@ -306,8 +309,6 @@ class RawReaderCRUEventSync static constexpr size_t ExpectedNumberOfPacketsPerHBFrame{8}; ///< expected number of packets in one HB frame per link for HB scaling mode static constexpr size_t ExpectedPayloadSize{64000}; ///< expected payload size in case of triggered mode (4000 GBT Frames of 16byte) - using RDH = o2::header::RAWDataHeader; - /// default ctor RawReaderCRUEventSync() { reset(); } @@ -337,7 +338,7 @@ class RawReaderCRUEventSync /// \struct CRUInfo /// \brief summary information of on CRU struct CRUInfo { - CRUInfo() : LinkInformation(24) {} + CRUInfo() : LinkInformation(MaxNumberOfLinks) {} bool isPresent() const { @@ -349,12 +350,19 @@ class RawReaderCRUEventSync return false; } - bool isComplete() const + bool isComplete(RAWDataType rawDataType = RAWDataType::GBT) const { for (const auto& link : LinkInformation) { - if (link.WasSeen && !link.IsPresent && !link.isComplete()) { + if (link.WasSeen && !link.IsPresent) { return false; } + if (rawDataType == RAWDataType::GBT) { + return link.isComplete(); + } + if (rawDataType == RAWDataType::LinkZS) { + return link.HBEndSeen; + } + return false; } return true; } @@ -386,7 +394,9 @@ class RawReaderCRUEventSync bool operator<(const EventInfo& other) const { return HeartbeatOrbits.back() < other.HeartbeatOrbits[0]; } /// check if heartbeatOrbit contributes to the event - bool hasHearbeatOrbit(uint32_t heartbeatOrbit) { return std::find(HeartbeatOrbits.begin(), HeartbeatOrbits.end(), heartbeatOrbit) != HeartbeatOrbits.end(); } + bool hasHearbeatOrbit(uint32_t heartbeatOrbit) const { return std::find(HeartbeatOrbits.begin(), HeartbeatOrbits.end(), heartbeatOrbit) != HeartbeatOrbits.end(); } + + uint32_t getFirstOrbit() const { return HeartbeatOrbits.size() ? *std::min_element(HeartbeatOrbits.begin(), HeartbeatOrbits.end()) : 0; } std::vector HeartbeatOrbits{}; ///< vector of heartbeat orbits contributing to the event CRUInfoArray_t CRUInfoArray; ///< Link information for each cru @@ -403,11 +413,13 @@ class RawReaderCRUEventSync createEvent(rdh, dataType); } - const auto dataWrapperID = RDHUtils::getEndPointID(rdh); - const auto linkID = RDHUtils::getLinkID(rdh); - const auto globalLinkID = linkID + dataWrapperID * 12; + const auto feeId = RDHUtils::getFEEID(rdh); + const auto endPoint = rdh_utils::getEndPoint(feeId); + const auto link = rdh_utils::getLink(feeId); + const auto globalLink = link + endPoint * 12; + const auto cru = rdh_utils::getCRU(feeId); - return mLastEvent->CRUInfoArray[RDHUtils::getCRUID(rdh)].LinkInformation[globalLinkID]; + return mLastEvent->CRUInfoArray[cru].LinkInformation[globalLink]; } /// get array with all link informaiton for a specific event number and cru @@ -446,10 +458,14 @@ class RawReaderCRUEventSync EventInfo& createEvent(const RDH& rdh, DataType dataType); /// analyse events and mark complete events - void analyse(); + void analyse(RAWDataType rawDataType = RAWDataType::GBT); + /// all event information const EventInfoVector& getEventInfoVector() const { return mEventInformation; } + /// information of specific event + const EventInfo& getEventInfo(size_t eventNumber) const { return mEventInformation[eventNumber]; } + /// write data to ostream void streamTo(std::ostream& output) const; @@ -583,6 +599,9 @@ class RawReaderCRU /// process all data for the selected link reading single 8k packet from file int processDataFile(); + /// process data in case of Link based zero suppression + void processLinkZS(); + /// Collect data to memory and process data void processDataMemory(); @@ -650,6 +669,19 @@ class RawReaderCRU /// get packet descriptor map array const PacketDescriptorMapArray& getPacketDescriptorMaps() const { return mPacketDescriptorMaps; } + /// file handling + std::ifstream& getFileHandle() + { + if (!mFileHandle.is_open()) { + mFileHandle.open(mInputFileName, std::ios::binary); + if (!mFileHandle.good()) { + throw std::runtime_error("Unable to open or access file " + mInputFileName); + } + } + + return mFileHandle; + } + //=========================================================================== //===| Nested helper classes |=============================================== // @@ -686,10 +718,15 @@ class RawReaderCRU class PacketDescriptor { public: - PacketDescriptor(size_t headOff, uint32_t cruID, uint32_t linkID, uint32_t dataWrapperID, uint16_t memorySize = 7840, uint16_t packetSize = 8192) : mHeaderOffset(headOff), - mFEEID(cruID + (linkID << 9) + (dataWrapperID << 13)), - mMemorySize(memorySize), - mPacketSize(packetSize) + using FEEIDType = rdh_utils::FEEIDType; + + PacketDescriptor(size_t headOff, uint32_t cru, uint32_t link, uint32_t endPoint, + uint16_t memorySize = 7840, uint16_t packetSize = 8192, + uint32_t heartbeatOrbit = 0) : mHeaderOffset(headOff), + mFEEID(rdh_utils::getFEEID(cru, endPoint, link)), + mMemorySize(memorySize), + mPacketSize(packetSize), + mHeartbeatOrbit(heartbeatOrbit) { } @@ -697,15 +734,18 @@ class RawReaderCRU { return sizeof(RDH); } - uint32_t getHeaderOffset() const { return mHeaderOffset; } - uint32_t getPayloadOffset() const { return mHeaderOffset + getHeaderSize(); } + + uint32_t getHeartBeatOrbit() const { return mHeartbeatOrbit; } + size_t getHeaderOffset() const { return mHeaderOffset; } + size_t getPayloadOffset() const { return mHeaderOffset + getHeaderSize(); } uint32_t getPayloadSize() const { return mMemorySize - getHeaderSize(); } uint32_t getPacketSize() const { return mPacketSize; } - uint16_t getCRUID() const { return mFEEID & 0x01FF; } - uint16_t getLinkID() const { return (mFEEID >> 9) & 0x0F; } - uint16_t getGlobalLinkID() const { return ((mFEEID >> 9) & 0x0F) + getDataWrapperID() * 12; } - uint16_t getDataWrapperID() const { return (mFEEID >> 13) & 0x01; } + FEEIDType getFEEID() const { return mFEEID; } + FEEIDType getCRUID() const { return rdh_utils::getCRU(mFEEID); } + FEEIDType getLinkID() const { return rdh_utils::getLink(mFEEID); } + FEEIDType getGlobalLinkID() const { return getLinkID() + getEndPoint() * 12; } + FEEIDType getEndPoint() const { return rdh_utils::getEndPoint(mFEEID); } /// write data to ostream void streamTo(std::ostream& output) const; @@ -717,10 +757,11 @@ class RawReaderCRU } private: - size_t mHeaderOffset; ///< header offset - uint16_t mMemorySize; ///< payload size - uint16_t mPacketSize; ///< packet size - uint16_t mFEEID; ///< link ID -- BIT 0-8: CRUid -- BIT 9-12: LinkID -- BIT 13: DataWrapperID -- BIT 14,15: unused + size_t mHeaderOffset; ///< header offset + uint32_t mHeartbeatOrbit; ///< heartbeatOrbit + uint16_t mMemorySize; ///< payload size + uint16_t mPacketSize; ///< packet size + FEEIDType mFEEID; ///< FEEid as defined in TPCBase/RDHUtils.h }; // =========================================================================== @@ -890,6 +931,7 @@ class RawReaderCRUManager { public: using ADCDataCallback = std::function)>; + using LinkZSCallback = o2::tpc::raw_processing_helpers::ADCCallback; using EndReaderCallback = std::function; /// constructor @@ -997,6 +1039,9 @@ class RawReaderCRUManager /// set a callback function void setADCDataCallback(ADCDataCallback function) { mADCDataCallback = function; } + /// set a callback function for decoded LinkZS data + void setLinkZSCallback(LinkZSCallback function) { mLinkZSCallback = function; } + /// process event calling mADCDataCallback to process values void processEvent(uint32_t eventNumber, EndReaderCallback endReader = nullptr); @@ -1009,6 +1054,7 @@ class RawReaderCRUManager bool mDetectDataType{true}; ///< try to detect data types bool mIsInitialized{false}; ///< if init was called already ADCDataCallback mADCDataCallback{nullptr}; ///< callback function for filling the ADC data + LinkZSCallback mLinkZSCallback{nullptr}; ///< callback for decoded linkZS data friend class RawReaderCRU; diff --git a/Detectors/TPC/reconstruction/src/RawProcessingHelpers.cxx b/Detectors/TPC/reconstruction/src/RawProcessingHelpers.cxx new file mode 100644 index 0000000000000..3f2f85ea2baed --- /dev/null +++ b/Detectors/TPC/reconstruction/src/RawProcessingHelpers.cxx @@ -0,0 +1,105 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include + +#include "Framework/Logger.h" +#include "TPCBase/Mapper.h" +#include "DataFormatsTPC/ZeroSuppressionLinkBased.h" + +#include "TPCReconstruction/RawProcessingHelpers.h" + +using namespace o2::tpc; + +//______________________________________________________________________________ +bool raw_processing_helpers::processZSdata(const char* data, size_t size, rdh_utils::FEEIDType feeId, uint32_t globalBCoffset, ADCCallback fillADC) +{ + const auto& mapper = Mapper::instance(); + + const auto link = rdh_utils::getLink(feeId); + const auto cruID = rdh_utils::getCRU(feeId); + const auto endPoint = rdh_utils::getEndPoint(feeId); + const CRU cru(cruID); + const int fecLinkOffsetCRU = (mapper.getPartitionInfo(cru.partition()).getNumberOfFECs() + 1) / 2; + const int fecInPartition = link + endPoint * fecLinkOffsetCRU; + + // temporarily store the sync offset until it is available in the ZS header + // WARNING: This only works until the TB counter wrapped afterwards the alignment might change + const int globalLinkID = int(link) + int(endPoint * 12); + const int tpcGlobalLinkID = cruID * 24 + globalLinkID; + static std::array syncOffset; + + bool hasData{false}; + + zerosupp_link_based::ContainerZS* zsdata = (zerosupp_link_based::ContainerZS*)data; + const zerosupp_link_based::ContainerZS* const zsdataEnd = (zerosupp_link_based::ContainerZS*)(data + size); + + while (zsdata < zsdataEnd) { + const auto& header = zsdata->cont.header; + + // align to header word if needed + if (!header.hasCorrectMagicWord()) { + zsdata = (zerosupp_link_based::ContainerZS*)((const char*)zsdata + sizeof(zerosupp_link_based::Header)); + if (!header.isFillWord()) { + LOGP(error, "Bad LinkZS magic word (0x{:08x}), for feeId 0x{:05x} (CRU: {:3}, link: {:2}, EP {}) , skipping data block", header.magicWord, feeId, rdh_utils::getCRU(feeId), rdh_utils::getLink(feeId), rdh_utils::getEndPoint(feeId)); + LOGP(error, "Full 128b word is: 0x{:016x}{:016x}", header.word1, header.word0); + } + continue; + } + + const auto channelBits = zsdata->getChannelBits(); + const uint32_t expectedWords = std::ceil(channelBits.count() * 0.1f); + const uint32_t numberOfWords = zsdata->getDataWords(); + assert(expectedWords == numberOfWords); + + const uint32_t timebinHeader = header.timeBin; + const uint32_t bunchCrossingHeader = zsdata->getBunchCrossing(); + + if (syncOffset[tpcGlobalLinkID] == 0) { + syncOffset[tpcGlobalLinkID] = (bunchCrossingHeader + 3564 - (timebinHeader * 8) % 3564) % 3564 % 16; + } + + const int timebin = (int(globalBCoffset) + int(bunchCrossingHeader) - int(syncOffset[tpcGlobalLinkID])) / 8; + if (timebin < 0) { + LOGP(info, "skipping negative time bin with (globalBCoffset ({}) + bunchCrossingHeader ({}) - syncOffset({})) / 8 = {}", globalBCoffset, bunchCrossingHeader, syncOffset[tpcGlobalLinkID], timebin); + + // go to next time bin + zsdata = zsdata->next(); + continue; + } + + std::size_t processedChannels = 0; + for (std::size_t ichannel = 0; ichannel < channelBits.size(); ++ichannel) { + if (!channelBits[ichannel]) { + continue; + } + + // adc value + const auto adcValue = zsdata->getADCValueFloat(processedChannels); + + // mapping to row, pad sector + int sampaOnFEC{}, channelOnSAMPA{}; + Mapper::getSampaAndChannelOnFEC(cruID, ichannel, sampaOnFEC, channelOnSAMPA); + const auto padSecPos = mapper.padSecPos(cru, fecInPartition, sampaOnFEC, channelOnSAMPA); + const auto& padPos = padSecPos.getPadPos(); + + // add digit using callback + fillADC(int(cruID), int(padPos.getRow()), int(padPos.getPad()), timebin, adcValue); + + ++processedChannels; + hasData = true; + } + + // go to next time bin + zsdata = zsdata->next(); + } + + return hasData; +} diff --git a/Detectors/TPC/reconstruction/src/RawReaderCRU.cxx b/Detectors/TPC/reconstruction/src/RawReaderCRU.cxx index 2609bdbd63e3a..bb0cba6782847 100644 --- a/Detectors/TPC/reconstruction/src/RawReaderCRU.cxx +++ b/Detectors/TPC/reconstruction/src/RawReaderCRU.cxx @@ -23,10 +23,8 @@ #include "DetectorsRaw/RDHUtils.h" #define CHECK_BIT(var, pos) ((var) & (1 << (pos))) -using RDH = o2::header::RAWDataHeader; -//using namespace o2::tpc; + using namespace o2::tpc::rawreader; -using RDHUtils = o2::raw::RDHUtils; std::ostream& operator<<(std::ostream& output, const RDH& rdh); std::istream& operator>>(std::istream& input, RDH& rdh); @@ -68,7 +66,7 @@ RawReaderCRUEventSync::EventInfo& RawReaderCRUEventSync::createEvent(const RDH& return ev; } -void RawReaderCRUEventSync::analyse() +void RawReaderCRUEventSync::analyse(RAWDataType rawDataType) { //expected number of packets in one HBorbit const size_t numberOfPackets = ExpectedNumberOfPacketsPerHBFrame; @@ -81,6 +79,7 @@ void RawReaderCRUEventSync::analyse() const auto& cruInfo = event.CRUInfoArray[iCRU]; if (!cruInfo.isPresent()) { if (mCRUSeen[iCRU] >= 0) { + LOGP(info, "CRU {} missing in event {}", iCRU, iEvent); event.IsComplete = false; break; } @@ -90,7 +89,7 @@ void RawReaderCRUEventSync::analyse() totalPayloadSize += cruInfo.totalPayloadSize(); } - if (!cruInfo.isComplete()) { + if (!cruInfo.isComplete(rawDataType)) { event.IsComplete = false; break; } @@ -208,13 +207,7 @@ int RawReaderCRU::scanFile() //const uint64_t RDH_HEADERWORD0 = 0x00004003; const uint64_t RDH_HEADERWORD0 = 0x00004000; // + RDHUtils::getVersion(); - std::ifstream& file = mFileHandle; - if (!file.is_open()) { - file.open(mInputFileName, std::ifstream::binary); - if (!file.good()) { - throw std::runtime_error("Unable to open or access file " + mInputFileName); - } - } + auto& file = getFileHandle(); // get length of file in bytes file.seekg(0, file.end); @@ -241,6 +234,13 @@ int RawReaderCRU::scanFile() const size_t packetSize = RDHUtils::getOffsetToNext(rdh); const size_t offset = packetSize - RDHUtils::getHeaderSize(rdh); + // ===| check for truncated file |========================================== + const size_t curPos = file.tellg(); + if ((curPos + offset) > mFileSize) { + LOGP(error, "File truncated at {}, offset {} would exceed file size of {}", curPos, offset, mFileSize); + break; + } + // ===| try to detect data type if not already set |======================== // // for now we assume only HB scaling and triggered mode @@ -258,6 +258,7 @@ int RawReaderCRU::scanFile() if (pageCnt == 0) { if (linkID == 15) { mManager->mRawDataType = RAWDataType::LinkZS; + LOGP(info, "Detected LinkZS data"); mManager->mDetectDataType = false; } } @@ -276,17 +277,26 @@ int RawReaderCRU::scanFile() } // ===| get relavant data information |===================================== + auto feeId = RDHUtils::getFEEID(rdh); + // treat old RDH where feeId was not set properly + if (feeId == 4844) { + const rdh_utils::FEEIDType cru = RDHUtils::getCRUID(rdh); + const rdh_utils::FEEIDType link = RDHUtils::getLinkID(rdh); + const rdh_utils::FEEIDType endPoint = RDHUtils::getEndPointID(rdh); + feeId = rdh_utils::getFEEID(cru, endPoint, link); + + RDHUtils::setFEEID(rdh, feeId); + } const auto heartbeatOrbit = RDHUtils::getHeartBeatOrbit(rdh); - const auto dataWrapperID = RDHUtils::getEndPointID(rdh); - const auto linkID = RDHUtils::getLinkID(rdh); - const auto globalLinkID = linkID + dataWrapperID * 12; - //const auto blockLength = rdh.blockLength; + const auto endPoint = rdh_utils::getEndPoint(feeId); + const auto linkID = rdh_utils::getLink(feeId); + const auto globalLinkID = linkID + endPoint * 12; const auto memorySize = RDHUtils::getMemorySize(rdh); const auto payloadSize = memorySize - RDHUtils::getHeaderSize(rdh); // ===| check if cru should be forced |===================================== if (!mForceCRU) { - mCRU = RDHUtils::getCRUID(rdh); + mCRU = rdh_utils::getCRU(feeId); } else { //overwrite cru id in rdh for further processing RDHUtils::setCRUID(rdh, mCRU); @@ -303,7 +313,6 @@ int RawReaderCRU::scanFile() linkInfo = &mManager->mEventSync.getLinkInfo(rdh, mManager->getDataType()); mManager->mEventSync.setCRUSeen(mCRU, mReaderNumber); } - //std::cout << "block length: " << blockLength << '\n'; // ===| set up packet descriptor map for GBT frames |======================= // @@ -313,8 +322,8 @@ int RawReaderCRU::scanFile() // if ((rdh.word0 & 0x0000FFF0) == RDH_HEADERWORD0) { // non 0 stop bit means data with payload - if (RDHUtils::getStop(rdh) == 0) { - mPacketDescriptorMaps[globalLinkID].emplace_back(currentPos, mCRU, linkID, dataWrapperID, memorySize, packetSize); + if (payloadSize) { + mPacketDescriptorMaps[globalLinkID].emplace_back(currentPos, mCRU, linkID, endPoint, memorySize, packetSize, heartbeatOrbit); mLinkPresent[globalLinkID] = true; mPacketsPerLink[globalLinkID]++; if (linkInfo) { @@ -322,31 +331,27 @@ int RawReaderCRU::scanFile() linkInfo->IsPresent = true; linkInfo->PayloadSize += payloadSize; } - } else if (RDHUtils::getStop(rdh) == 1) { + } + if (RDHUtils::getStop(rdh) == 1) { // stop bit 1 means we hit the HB end frame without payload. // This marks the end of an "event" in HB scaling mode. if (linkInfo) { linkInfo->HBEndSeen = true; } - } else { - O2ERROR("Unknown stop code: %lu", (unsigned long)RDHUtils::getStop(rdh)); } - //std::cout << dataWrapperID << "." << linkID << " (" << globalLinkID << ")\n"; } else { O2ERROR("Found header word %x and required header word %x don't match", rdh.word0, RDH_HEADERWORD0); - }; + } // debug output if (mVerbosity && CHECK_BIT(mDebugLevel, DebugLevel::RDHDump)) { - //std::cout << "Packet " << std::setw(5) << currentPacket << " - Link " << int(linkID) << "\n"; - //std::cout << rdh; printHorizontal(rdh); if (RDHUtils::getStop(rdh)) { std::cout << "\n"; printHeader(); } - }; - // std::cout << "Position after read : " << std::dec << file.tellg() << std::endl; + } + file.seekg(offset, file.cur); ++currentPacket; currentPos = file.tellg(); @@ -398,13 +403,7 @@ int RawReaderCRU::scanFile() void RawReaderCRU::findSyncPositions() { - std::ifstream& file = mFileHandle; - if (!file.is_open()) { - file.open(mInputFileName, std::ifstream::binary); - if (!file.good()) { - throw std::runtime_error("Unable to open or access file " + mInputFileName); - } - } + auto& file = getFileHandle(); // loop over the MaxNumberOfLinks potential links in the data // only if data from the link is present and selected @@ -461,13 +460,7 @@ void RawReaderCRU::findSyncPositions() int RawReaderCRU::processPacket(GBTFrame& gFrame, uint32_t startPos, uint32_t size, ADCRawData& rawData) { // open the data file - std::ifstream& file = mFileHandle; - if (!file.is_open()) { - file.open(mInputFileName, std::ifstream::binary); - if (!file.good()) { - throw std::runtime_error("Unable to open or access file " + mInputFileName); - } - } + auto& file = getFileHandle(); // jump to the start position of the packet file.seekg(startPos, file.beg); @@ -537,7 +530,7 @@ int RawReaderCRU::processMemory(const std::vector& data, ADCRawData& r auto& syncPos = syncPositions[s]; if (syncPos.synched()) { file << mEventNumber << "\t" - << mCRU << "\t" + << mCRU.number() << "\t" << mLink << "\t" << s << "\t" << syncPos.getPacketNumber() << "\t" @@ -706,7 +699,8 @@ void RawReaderCRU::processDataMemory() //dataSize = 4000 * 16; //} - std::vector data(dataSize); + std::vector data; + data.reserve(dataSize); collectGBTData(data); ADCRawData rawData; @@ -716,35 +710,26 @@ void RawReaderCRU::processDataMemory() if (mFillADCdataMap) { fillADCdataMap(rawData); } - if (mManager && mManager->mADCDataCallback) { + if (mManager->mADCDataCallback) { runADCDataCallback(rawData); } } void RawReaderCRU::collectGBTData(std::vector& data) { - const int link = mLink; - - const auto& mapper = Mapper::instance(); - const auto& linkInfoArray = mManager->mEventSync.getLinkInfoArrayForEvent(mEventNumber, mCRU); - std::ifstream& file = mFileHandle; - if (!file.is_open()) { - file.open(mInputFileName, std::ios::binary); - if (!file.good()) { - throw std::runtime_error("Unable to open or access file " + mInputFileName); - } - } + auto& file = getFileHandle(); size_t presentDataPosition = 0; // loop over the packets for each link and process them //for (const auto& packet : mPacketDescriptorMaps[link]) { - for (auto packetNumber : linkInfoArray[link].PacketPositions) { - const auto& packet = mPacketDescriptorMaps[link][packetNumber]; + for (auto packetNumber : linkInfoArray[mLink].PacketPositions) { + const auto& packet = mPacketDescriptorMaps[mLink][packetNumber]; const auto payloadStart = packet.getPayloadOffset(); - const auto payloadSize = std::min(size_t(packet.getPayloadSize()), data.size() - presentDataPosition); + const auto payloadSize = size_t(packet.getPayloadSize()); + data.insert(data.end(), payloadSize, 0); // jump to the start position of the packet file.seekg(payloadStart, std::ios::beg); @@ -752,18 +737,50 @@ void RawReaderCRU::collectGBTData(std::vector& data) file.read(((char*)data.data()) + presentDataPosition, payloadSize); presentDataPosition += payloadSize; - }; + } +} + +void RawReaderCRU::processLinkZS() +{ + const auto& eventInfo = mManager->mEventSync.getEventInfo(mEventNumber); + const auto& linkInfoArray = eventInfo.CRUInfoArray[mCRU].LinkInformation; + const auto firstOrbitInEvent = eventInfo.getFirstOrbit(); + + auto& file = getFileHandle(); + + char buffer[8192]; + + // loop over the packets for each link and process them + for (const auto packetNumber : linkInfoArray[mLink].PacketPositions) { + const auto& packet = mPacketDescriptorMaps[mLink][packetNumber]; + const size_t payloadOffset = packet.getPayloadOffset(); + const size_t payloadSize = packet.getPayloadSize(); + if ((payloadOffset + payloadSize) > mFileSize) { + LOGP(error, "File truncated at {}, size {} would exceed file size of {}", payloadOffset, payloadSize, mFileSize); + break; + } + file.seekg(payloadOffset, file.beg); + file.read(buffer, payloadSize); + + const auto globalBCOffset = (packet.getHeartBeatOrbit() - firstOrbitInEvent) * 3564; + o2::tpc::raw_processing_helpers::processZSdata(buffer, payloadSize, packet.getFEEID(), globalBCOffset, mManager->mLinkZSCallback); + } } void RawReaderCRU::processLinks(const uint32_t linkMask) { + if (!mManager) { + LOGP(error, "cannont run without manager"); + return; + } + try { // read the input data from file, create the packet descriptor map // and the mLinkPresent map. scanFile(); // check if selected event is valid - if (mManager && mEventNumber >= mManager->mEventSync.getNumberOfEvents()) { + if (mEventNumber >= mManager->mEventSync.getNumberOfEvents()) { O2ERROR("Selected event number %u is larger then the events in the file %lu", mEventNumber, mManager->mEventSync.getNumberOfEvents()); return; } @@ -773,24 +790,20 @@ void RawReaderCRU::processLinks(const uint32_t linkMask) // for decoding it will be decoded. for (int lnk = 0; lnk < MaxNumberOfLinks; lnk++) { // all links have been selected - if (linkMask == 0 && checkLinkPresent(lnk) == true) { + if (((linkMask == 0) || ((linkMask >> lnk) & 1)) && checkLinkPresent(lnk) == true) { // set the active link variable and process the data if (mDebugLevel) { fmt::print("Processing link {}\n", lnk); } setLink(lnk); - //processDataFile(); - processDataMemory(); - } else if (((linkMask >> lnk) & 0x1) == 0x1 && checkLinkPresent(lnk) == true) { - // set the active link variable and process the data - if (mDebugLevel) { - fmt::print("Processing link {}\n", lnk); + if (mManager->mRawDataType == RAWDataType::GBT) { + //processDataFile(); + processDataMemory(); + } else { + processLinkZS(); } - setLink(lnk); - //processDataFile(); - processDataMemory(); - }; - }; + } + } } catch (const RawReaderCRU::Error& e) { std::cout << e.what() << std::endl; @@ -859,13 +872,7 @@ void RawReaderCRU::copyEvents(const std::vector& eventNumbers, std::st std::ofstream outputFile(outputFileName, std::ios_base::binary | mode); // open the input file - std::ifstream& file = mFileHandle; - if (!file.is_open()) { - file.open(mInputFileName, std::ifstream::binary); - if (!file.good()) { - throw std::runtime_error("Unable to open or access file " + mInputFileName); - } - } + auto& file = getFileHandle(); // data buffer. Maximum size is 8k char buffer[8192]; @@ -893,13 +900,7 @@ void RawReaderCRU::copyEvents(const std::vector& eventNumbers, std::st void RawReaderCRU::writeGBTDataPerLink(std::string_view outputDirectory, int maxEvents) { // open the input file - std::ifstream& file = mFileHandle; - if (!file.is_open()) { - file.open(mInputFileName, std::ifstream::binary); - if (!file.good()) { - throw std::runtime_error("Unable to open or access file " + mInputFileName); - } - } + auto& file = getFileHandle(); // data buffer. Maximum size is 8k char buffer[8192]; @@ -1099,7 +1100,7 @@ void RawReaderCRUManager::init() } mEventSync.sortEvents(); - mEventSync.analyse(); + mEventSync.analyse(mRawDataType); O2INFO("Event information:"); O2INFO(" Number of all events: %lu", getNumberOfEvents()); From 277e944dfc56a2b7bfd52318e90449b541fd09fa Mon Sep 17 00:00:00 2001 From: wiechula Date: Wed, 24 Feb 2021 14:46:16 +0100 Subject: [PATCH 2/4] Change ADC rage to float --- .../TPC/calibration/include/TPCCalibration/DigitDump.h | 6 +++--- Detectors/TPC/calibration/macro/dumpDigits.C | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Detectors/TPC/calibration/include/TPCCalibration/DigitDump.h b/Detectors/TPC/calibration/include/TPCCalibration/DigitDump.h index 284e0f50c9119..75549ed837eac 100644 --- a/Detectors/TPC/calibration/include/TPCCalibration/DigitDump.h +++ b/Detectors/TPC/calibration/include/TPCCalibration/DigitDump.h @@ -92,7 +92,7 @@ class DigitDump : public CalibRawBase void setNoiseThreshold(float noiseThreshold) { mNoiseThreshold = noiseThreshold; } /// set the adc range - void setADCRange(int minADC, int maxADC) + void setADCRange(float minADC, float maxADC) { mADCMin = minADC; mADCMax = maxADC; @@ -152,8 +152,8 @@ class DigitDump : public CalibRawBase int mFirstTimeBin{0}; ///< first time bin used in analysis int mLastTimeBin{1000}; ///< first time bin used in analysis - int mADCMin{-100}; ///< minimum adc value - int mADCMax{1024}; ///< maximum adc value + float mADCMin{-100}; ///< minimum adc value + float mADCMax{1024}; ///< maximum adc value float mNoiseThreshold{-1}; ///< zero suppression threshold in noise sigma bool mInMemoryOnly{false}; ///< if processing is only done in memory, no file writing bool mInitialized{false}; ///< if init was called diff --git a/Detectors/TPC/calibration/macro/dumpDigits.C b/Detectors/TPC/calibration/macro/dumpDigits.C index c8c051e8c2fa2..6305e3a70a45a 100644 --- a/Detectors/TPC/calibration/macro/dumpDigits.C +++ b/Detectors/TPC/calibration/macro/dumpDigits.C @@ -17,7 +17,7 @@ #endif void dumpDigits(std::vector fileInfos, TString outputFileName = "", int nevents = 100, - int adcMin = -100, int adcMax = 1100, + float adcMin = -100, float adcMax = 1100, int firstTimeBin = 0, int lastTimeBin = 1000, float noiseThreshold = -1, TString pedestalAndNoiseFile = "", From 7ca0d415b75759392fadea47abc877bfd1d3849d Mon Sep 17 00:00:00 2001 From: wiechula Date: Wed, 24 Feb 2021 14:56:40 +0100 Subject: [PATCH 3/4] Update header definition --- .../DataFormatsTPC/ZeroSuppressionLinkBased.h | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/ZeroSuppressionLinkBased.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/ZeroSuppressionLinkBased.h index 956c0c667b417..db70f5ab1102d 100644 --- a/DataFormats/Detectors/TPC/include/DataFormatsTPC/ZeroSuppressionLinkBased.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/ZeroSuppressionLinkBased.h @@ -32,20 +32,21 @@ struct Header { static constexpr uint32_t MagicWord = 0xFC; union { - uint64_t word0 = 0; ///< lower 64 bits - struct { /// - uint64_t bitMaskLow : 64; ///< lower bits of the 80 bit bitmask - }; /// - }; /// - /// - union { /// - uint64_t word1 = 0; ///< upper bits of the 80 bit bitmask - struct { /// - uint64_t bitMaskHigh : 16; ///< higher bits of the 80 bit bitmask - uint32_t bunchCrossing : 12; ///< bunch crossing number - uint32_t numWordsPayload : 4; ///< number of 128bit words with 12bit ADC values - uint32_t timeBin : 24; ///< time bin number issues by UL, mainly for debugging, since it might wrap - uint32_t magicWord : 8; ///< not used + uint64_t word0 = 0; ///< lower 64 bits + struct { /// + uint64_t bitMaskLow : 64; ///< lower bits of the 80 bit bitmask + }; /// + }; /// + /// + union { /// + uint64_t word1 = 0; ///< upper bits of the 80 bit bitmask + struct { /// + uint64_t bitMaskHigh : 16; ///< higher bits of the 80 bit bitmask + uint32_t bunchCrossing : 12; ///< bunch crossing number + uint32_t numWordsPayload : 4; ///< number of 128bit words with 12bit ADC values + uint32_t syncOffsetBC : 8; ///< sync offset in bunch crossings + uint32_t syncOffsetCRUCycles : 16; ///< sync offset in 240MHz CRU clock cycles + uint32_t magicWord : 8; ///< not used }; }; From 6302c54fc40d958d73030e9cf40d699c2e2f269d Mon Sep 17 00:00:00 2001 From: wiechula Date: Wed, 24 Feb 2021 14:57:21 +0100 Subject: [PATCH 4/4] Modifications to process link-based zero suppression --- .../include/TPCCalibration/CalibTreeDump.h | 15 +- Detectors/TPC/calibration/macro/dumpDigits.C | 1 + .../TPC/calibration/src/CalibRawBase.cxx | 5 +- .../TPCReconstruction/RawProcessingHelpers.h | 2 +- .../include/TPCReconstruction/RawReaderCRU.h | 6 + .../src/RawProcessingHelpers.cxx | 18 ++- .../TPC/reconstruction/src/RawReaderCRU.cxx | 5 +- .../TPCWorkflow/TPCCalibPedestalSpec.h | 8 + .../workflow/src/CalibProcessingHelper.cxx | 137 +++++++++++++----- .../TPC/workflow/src/RawToDigitsSpec.cxx | 14 +- .../src/tpc-raw-to-digits-workflow.cxx | 21 +-- 11 files changed, 159 insertions(+), 73 deletions(-) diff --git a/Detectors/TPC/calibration/include/TPCCalibration/CalibTreeDump.h b/Detectors/TPC/calibration/include/TPCCalibration/CalibTreeDump.h index 6bb611bf40ebb..9579e3d81a69c 100644 --- a/Detectors/TPC/calibration/include/TPCCalibration/CalibTreeDump.h +++ b/Detectors/TPC/calibration/include/TPCCalibration/CalibTreeDump.h @@ -13,6 +13,7 @@ #include #include +#include #include @@ -75,12 +76,16 @@ class CalibTreeDump /// Dump the registered calibration data to file void dumpToFile(const std::string filename = "CalibTree.root"); + /// Add complementary information + void addInfo(const std::string_view name, float value) { mAddInfo[name.data()] = value; } + private: - std::vector mCalDetObjects{}; ///< array of CalDet objects - std::vector mCalArrayObjects{}; ///< array of CalArray objects - bool mAddFEEInfo{false}; ///< add front end electronics mappings - std::vector mTraceLengthIROC; ///< trace lengths IROC - std::vector mTraceLengthOROC; ///< trace lengths OROC + std::unordered_map mAddInfo{}; ///< additional common information to be added to the output tree + std::vector mCalDetObjects{}; ///< array of CalDet objects + std::vector mCalArrayObjects{}; ///< array of CalArray objects + bool mAddFEEInfo{false}; ///< add front end electronics mappings + std::vector mTraceLengthIROC; ///< trace lengths IROC + std::vector mTraceLengthOROC; ///< trace lengths OROC /// add default mapping like local, global x/y positions void addDefaultMapping(TTree* tree); diff --git a/Detectors/TPC/calibration/macro/dumpDigits.C b/Detectors/TPC/calibration/macro/dumpDigits.C index 6305e3a70a45a..730c1f9ce2844 100644 --- a/Detectors/TPC/calibration/macro/dumpDigits.C +++ b/Detectors/TPC/calibration/macro/dumpDigits.C @@ -30,6 +30,7 @@ void dumpDigits(std::vector fileInfos, TString outputFileName dig.setADCRange(adcMin, adcMax); dig.setTimeBinRange(firstTimeBin, lastTimeBin); dig.setNoiseThreshold(noiseThreshold); + dig.setSkipIncompleteEvents(false); CalibRawBase::ProcessStatus status = CalibRawBase::ProcessStatus::Ok; for (const auto& fileInfo : fileInfos) { diff --git a/Detectors/TPC/calibration/src/CalibRawBase.cxx b/Detectors/TPC/calibration/src/CalibRawBase.cxx index d00e19f2b2083..811d68edb03cd 100644 --- a/Detectors/TPC/calibration/src/CalibRawBase.cxx +++ b/Detectors/TPC/calibration/src/CalibRawBase.cxx @@ -76,7 +76,10 @@ void CalibRawBase::setupContainers(TString fileInfo, uint32_t verbosity, uint32_ return timeBins; }); mRawReaderCRUManager.setLinkZSCallback([this](int cru, int rowInSector, int padInRow, int timeBin, float adcValue) -> bool { - updateROC(CRU(cru).roc(), rowInSector - (rowInSector > 62) * 63, padInRow, timeBin, adcValue); + CRU cruID(cru); + updateROC(cruID.roc(), rowInSector - (rowInSector > 62) * 63, padInRow, timeBin, adcValue); + const PadRegionInfo& regionInfo = mMapper.getPadRegionInfo(cruID.region()); + updateCRU(cruID, rowInSector - regionInfo.getGlobalRowOffset(), padInRow, timeBin, adcValue); return true; }); diff --git a/Detectors/TPC/reconstruction/include/TPCReconstruction/RawProcessingHelpers.h b/Detectors/TPC/reconstruction/include/TPCReconstruction/RawProcessingHelpers.h index 161d2f79dfe55..b1aa4c2016466 100644 --- a/Detectors/TPC/reconstruction/include/TPCReconstruction/RawProcessingHelpers.h +++ b/Detectors/TPC/reconstruction/include/TPCReconstruction/RawProcessingHelpers.h @@ -24,7 +24,7 @@ namespace raw_processing_helpers using ADCCallback = std::function; -bool processZSdata(const char* data, size_t size, rdh_utils::FEEIDType feeId, uint32_t globalBCoffset, ADCCallback fillADC); +bool processZSdata(const char* data, size_t size, rdh_utils::FEEIDType feeId, uint32_t globalBCoffset, ADCCallback fillADC, bool useTimeBin = false); } // namespace raw_processing_helpers } // namespace tpc diff --git a/Detectors/TPC/reconstruction/include/TPCReconstruction/RawReaderCRU.h b/Detectors/TPC/reconstruction/include/TPCReconstruction/RawReaderCRU.h index 0938c7b60a3ed..d61893cd36f14 100644 --- a/Detectors/TPC/reconstruction/include/TPCReconstruction/RawReaderCRU.h +++ b/Detectors/TPC/reconstruction/include/TPCReconstruction/RawReaderCRU.h @@ -651,6 +651,9 @@ class RawReaderCRU /// set the event sync void setManager(RawReaderCRUManager* manager) { mManager = manager; } + /// get manager + RawReaderCRUManager* getManager() { return mManager; } + /// copy single events to another file void copyEvents(const std::vector& eventNumbers, std::string outputDirectory, std::ios_base::openmode mode = std::ios_base::openmode(0)); @@ -1042,6 +1045,9 @@ class RawReaderCRUManager /// set a callback function for decoded LinkZS data void setLinkZSCallback(LinkZSCallback function) { mLinkZSCallback = function; } + /// get LinkZSCallback + LinkZSCallback getLinkZSCallback() { return mLinkZSCallback; } + /// process event calling mADCDataCallback to process values void processEvent(uint32_t eventNumber, EndReaderCallback endReader = nullptr); diff --git a/Detectors/TPC/reconstruction/src/RawProcessingHelpers.cxx b/Detectors/TPC/reconstruction/src/RawProcessingHelpers.cxx index 3f2f85ea2baed..f069e28530f91 100644 --- a/Detectors/TPC/reconstruction/src/RawProcessingHelpers.cxx +++ b/Detectors/TPC/reconstruction/src/RawProcessingHelpers.cxx @@ -19,7 +19,7 @@ using namespace o2::tpc; //______________________________________________________________________________ -bool raw_processing_helpers::processZSdata(const char* data, size_t size, rdh_utils::FEEIDType feeId, uint32_t globalBCoffset, ADCCallback fillADC) +bool raw_processing_helpers::processZSdata(const char* data, size_t size, rdh_utils::FEEIDType feeId, uint32_t globalBCoffset, ADCCallback fillADC, bool useTimeBin) { const auto& mapper = Mapper::instance(); @@ -34,7 +34,7 @@ bool raw_processing_helpers::processZSdata(const char* data, size_t size, rdh_ut // WARNING: This only works until the TB counter wrapped afterwards the alignment might change const int globalLinkID = int(link) + int(endPoint * 12); const int tpcGlobalLinkID = cruID * 24 + globalLinkID; - static std::array syncOffset; + static std::array syncOffsetLinks; bool hasData{false}; @@ -59,16 +59,20 @@ bool raw_processing_helpers::processZSdata(const char* data, size_t size, rdh_ut const uint32_t numberOfWords = zsdata->getDataWords(); assert(expectedWords == numberOfWords); - const uint32_t timebinHeader = header.timeBin; const uint32_t bunchCrossingHeader = zsdata->getBunchCrossing(); + uint32_t syncOffset = header.syncOffsetBC % 16; - if (syncOffset[tpcGlobalLinkID] == 0) { - syncOffset[tpcGlobalLinkID] = (bunchCrossingHeader + 3564 - (timebinHeader * 8) % 3564) % 3564 % 16; + if (useTimeBin) { + const uint32_t timebinHeader = (header.syncOffsetCRUCycles << 8) | header.syncOffsetBC; + if (syncOffsetLinks[tpcGlobalLinkID] == 0) { + syncOffsetLinks[tpcGlobalLinkID] = (bunchCrossingHeader + 3564 - (timebinHeader * 8) % 3564) % 3564 % 16; + } + syncOffset = syncOffsetLinks[tpcGlobalLinkID]; } - const int timebin = (int(globalBCoffset) + int(bunchCrossingHeader) - int(syncOffset[tpcGlobalLinkID])) / 8; + const int timebin = (int(globalBCoffset) + int(bunchCrossingHeader) - int(syncOffset)) / 8; if (timebin < 0) { - LOGP(info, "skipping negative time bin with (globalBCoffset ({}) + bunchCrossingHeader ({}) - syncOffset({})) / 8 = {}", globalBCoffset, bunchCrossingHeader, syncOffset[tpcGlobalLinkID], timebin); + LOGP(info, "skipping negative time bin with (globalBCoffset ({}) + bunchCrossingHeader ({}) - syncOffset({})) / 8 = {}", globalBCoffset, bunchCrossingHeader, syncOffset, timebin); // go to next time bin zsdata = zsdata->next(); diff --git a/Detectors/TPC/reconstruction/src/RawReaderCRU.cxx b/Detectors/TPC/reconstruction/src/RawReaderCRU.cxx index bb0cba6782847..4fc05a50647b7 100644 --- a/Detectors/TPC/reconstruction/src/RawReaderCRU.cxx +++ b/Detectors/TPC/reconstruction/src/RawReaderCRU.cxx @@ -55,7 +55,7 @@ RawReaderCRUEventSync::EventInfo& RawReaderCRUEventSync::createEvent(const RDH& if (hbMatch) { mLastEvent = &ev; return ev; - } else if (ev.HeartbeatOrbits.back() == heartbeatOrbit - 1) { + } else if (std::abs(long(ev.HeartbeatOrbits.back()) - long(heartbeatOrbit)) < 54) { ev.HeartbeatOrbits.emplace_back(heartbeatOrbit); mLastEvent = &ev; return ev; @@ -297,6 +297,7 @@ int RawReaderCRU::scanFile() // ===| check if cru should be forced |===================================== if (!mForceCRU) { mCRU = rdh_utils::getCRU(feeId); + //mCRU = RDHUtils::getCRUID(rdh); // work-around for MW2 data } else { //overwrite cru id in rdh for further processing RDHUtils::setCRUID(rdh, mCRU); @@ -763,7 +764,7 @@ void RawReaderCRU::processLinkZS() file.read(buffer, payloadSize); const auto globalBCOffset = (packet.getHeartBeatOrbit() - firstOrbitInEvent) * 3564; - o2::tpc::raw_processing_helpers::processZSdata(buffer, payloadSize, packet.getFEEID(), globalBCOffset, mManager->mLinkZSCallback); + o2::tpc::raw_processing_helpers::processZSdata(buffer, payloadSize, packet.getFEEID(), globalBCOffset, mManager->mLinkZSCallback, false); // last parameter should be true for MW2 data } } diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/TPCCalibPedestalSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/TPCCalibPedestalSpec.h index 52b5287bccbff..938fed2d18819 100644 --- a/Detectors/TPC/workflow/include/TPCWorkflow/TPCCalibPedestalSpec.h +++ b/Detectors/TPC/workflow/include/TPCWorkflow/TPCCalibPedestalSpec.h @@ -51,14 +51,22 @@ class TPCCalibPedestalDevice : public o2::framework::Task void init(o2::framework::InitContext& ic) final { // set up ADC value filling + // TODO: clean up to not go via RawReaderCRUManager mCalibPedestal.init(); // initialize configuration via configKeyValues mRawReader.createReader(""); + mRawReader.setADCDataCallback([this](const PadROCPos& padROCPos, const CRU& cru, const gsl::span data) -> int { const int timeBins = mCalibPedestal.update(padROCPos, cru, data); mCalibPedestal.setNumberOfProcessedTimeBins(std::max(mCalibPedestal.getNumberOfProcessedTimeBins(), size_t(timeBins))); return timeBins; }); + mRawReader.setLinkZSCallback([this](int cru, int rowInSector, int padInRow, int timeBin, float adcValue) -> bool { + CRU cruID(cru); + mCalibPedestal.updateROC(cruID.roc(), rowInSector - (rowInSector > 62) * 63, padInRow, timeBin, adcValue); + return true; + }); + mMaxEvents = static_cast(ic.options().get("max-events")); mUseOldSubspec = ic.options().get("use-old-subspec"); mForceQuit = ic.options().get("force-quit"); diff --git a/Detectors/TPC/workflow/src/CalibProcessingHelper.cxx b/Detectors/TPC/workflow/src/CalibProcessingHelper.cxx index bf705b33a9a12..91444086579e9 100644 --- a/Detectors/TPC/workflow/src/CalibProcessingHelper.cxx +++ b/Detectors/TPC/workflow/src/CalibProcessingHelper.cxx @@ -14,21 +14,31 @@ #include "Framework/ConcreteDataMatcher.h" #include "Framework/InputRecordWalker.h" #include "Framework/Logger.h" - #include "DPLUtils/RawParser.h" +#include "DetectorsRaw/RDHUtils.h" +#include "CommonConstants/LHCConstants.h" + #include "TPCBase/RDHUtils.h" #include "TPCReconstruction/RawReaderCRU.h" +#include "TPCReconstruction/RawProcessingHelpers.h" #include "TPCWorkflow/CalibProcessingHelper.h" using namespace o2::tpc; using namespace o2::framework; +using RDHUtils = o2::raw::RDHUtils; + +void processGBT(o2::framework::RawParser<>& parser, std::unique_ptr& reader, const rdh_utils::FEEIDType feeID); +void processLinkZS(o2::framework::RawParser<>& parser, std::unique_ptr& reader, uint32_t firstOrbit); uint64_t calib_processing_helper::processRawData(o2::framework::InputRecord& inputs, std::unique_ptr& reader, bool useOldSubspec, const std::vector& sectors) { std::vector filter = {{"check", ConcreteDataTypeMatcher{o2::header::gDataOriginTPC, "RAWDATA"}, Lifetime::Timeframe}}; uint64_t activeSectors = 0; + bool isLinkZS = false; + bool readFirst = false; + uint32_t firstOrbit = 0; for (auto const& ref : InputRecordWalker(inputs, filter)) { const auto* dh = DataRefUtils::getHeader(ref); @@ -36,19 +46,17 @@ uint64_t calib_processing_helper::processRawData(o2::framework::InputRecord& inp // ---| extract hardware information to do the processing |--- const auto subSpecification = dh->subSpecification; rdh_utils::FEEIDType feeID = (rdh_utils::FEEIDType)dh->subSpecification; - rdh_utils::FEEIDType cruID, linkID, endPoint; if (useOldSubspec) { //---| old definition by Gvozden |--- - cruID = (rdh_utils::FEEIDType)(subSpecification >> 16); - linkID = (rdh_utils::FEEIDType)((subSpecification + (subSpecification >> 8)) & 0xFF) - 1; - endPoint = (rdh_utils::FEEIDType)((subSpecification >> 8) & 0xFF) > 0; - } else { - //---| new definition by David |--- - rdh_utils::getMapping(feeID, cruID, endPoint, linkID); + // TODO: make auto detect from firt RDH? + const auto cruID = (rdh_utils::FEEIDType)(subSpecification >> 16); + const auto linkID = (rdh_utils::FEEIDType)((subSpecification + (subSpecification >> 8)) & 0xFF) - 1; + const auto endPoint = (rdh_utils::FEEIDType)((subSpecification >> 8) & 0xFF) > 0; + feeID = rdh_utils::getFEEID(cruID, endPoint, linkID); } - const uint64_t sector = cruID / 10; + const uint64_t sector = rdh_utils::getCRU(feeID) / 10; // sector selection should be better done by directly subscribing to a range of subspecs. But this might not be that simple if (sectors.size() && (std::find(sectors.begin(), sectors.end(), int(sector)) == sectors.end())) { @@ -57,48 +65,107 @@ uint64_t calib_processing_helper::processRawData(o2::framework::InputRecord& inp activeSectors |= (0x1 << sector); + // ===| for debugging only |=== + // remove later + rdh_utils::FEEIDType cruID, linkID, endPoint; + rdh_utils::getMapping(feeID, cruID, endPoint, linkID); const auto globalLinkID = linkID + endPoint * 12; - - // ---| update hardware information in the reader |--- - reader->forceCRU(cruID); - reader->setLink(globalLinkID); - LOGP(info, "Specifier: {}/{}/{}", dh->dataOrigin.as(), dh->dataDescription.as(), subSpecification); LOGP(info, "Payload size: {}", dh->payloadSize); LOGP(info, "CRU: {}; linkID: {}; endPoint: {}; globalLinkID: {}", cruID, linkID, endPoint, globalLinkID); + // ^^^^^^ // TODO: exception handling needed? const gsl::span raw = inputs.get>(ref); o2::framework::RawParser parser(raw.data(), raw.size()); - // TODO: it would be better to have external event handling and then moving the event processing functionality to CalibRawBase and RawReader to not repeat it in other places - rawreader::ADCRawData rawData; - rawreader::GBTFrame gFrame; + // detect decoder type by analysing first RDH + if (!readFirst) { + auto it = parser.begin(); + auto* rdhPtr = it.get_if(); + if (!rdhPtr) { + LOGP(fatal, "could not get RDH from packet"); + } + const auto link = RDHUtils::getLinkID(*rdhPtr); + if (link == rdh_utils::UserLogicLinkID) { + LOGP(info, "Detected Link-based zero suppression"); + isLinkZS = true; + if (!reader->getManager() || !reader->getManager()->getLinkZSCallback()) { + LOGP(fatal, "LinkZSCallback must be set in RawReaderCRUManager"); + } + } - for (auto it = parser.begin(), end = parser.end(); it != end; ++it) { + firstOrbit = RDHUtils::getHeartBeatOrbit(*rdhPtr); + LOGP(info, "First orbit in present TF: {}", firstOrbit); + readFirst = true; + } - const auto size = it.size(); - auto data = it.data(); - //LOGP(info, "Data size: {}", size); + if (isLinkZS) { + processLinkZS(parser, reader, firstOrbit); + } else { + processGBT(parser, reader, feeID); + } + } - int iFrame = 0; - for (int i = 0; i < size; i += 16) { - gFrame.setFrameNumber(iFrame); - gFrame.setPacketNumber(iFrame / 508); - gFrame.readFromMemory(gsl::span(data + i, 16)); + return activeSectors; +} - // extract the half words from the 4 32-bit words - gFrame.getFrameHalfWords(); +void processGBT(o2::framework::RawParser<>& parser, std::unique_ptr& reader, const rdh_utils::FEEIDType feeID) +{ + rdh_utils::FEEIDType cruID, linkID, endPoint; + rdh_utils::getMapping(feeID, cruID, endPoint, linkID); + const auto globalLinkID = linkID + endPoint * 12; - gFrame.getAdcValues(rawData); - gFrame.updateSyncCheck(false); + // ---| update hardware information in the reader |--- + reader->forceCRU(cruID); + reader->setLink(globalLinkID); - ++iFrame; - } - } + rawreader::ADCRawData rawData; + rawreader::GBTFrame gFrame; + + for (auto it = parser.begin(), end = parser.end(); it != end; ++it) { + + const auto size = it.size(); + auto data = it.data(); + //LOGP(info, "Data size: {}", size); + + int iFrame = 0; + for (int i = 0; i < size; i += 16) { + gFrame.setFrameNumber(iFrame); + gFrame.setPacketNumber(iFrame / 508); + gFrame.readFromMemory(gsl::span(data + i, 16)); + + // extract the half words from the 4 32-bit words + gFrame.getFrameHalfWords(); + + gFrame.getAdcValues(rawData); + gFrame.updateSyncCheck(false); - reader->runADCDataCallback(rawData); + ++iFrame; + } } - return activeSectors; + reader->runADCDataCallback(rawData); +} + +void processLinkZS(o2::framework::RawParser<>& parser, std::unique_ptr& reader, uint32_t firstOrbit) +{ + for (auto it = parser.begin(), end = parser.end(); it != end; ++it) { + auto* rdhPtr = it.get_if(); + if (!rdhPtr) { + LOGP(fatal, "could not get RDH from packet"); + } + // workaround for MW2 data + //const bool useTimeBins = true; + //const auto cru = RDHUtils::getCRUID(*rdhPtr); + //const auto feeID = (RDHUtils::getFEEID(*rdhPtr) & 0x7f) | (cru << 7); + + const bool useTimeBins = false; + const auto feeID = RDHUtils::getFEEID(*rdhPtr); + const auto orbit = RDHUtils::getHeartBeatOrbit(*rdhPtr); + const auto data = (const char*)it.data(); + const auto size = it.size(); + const auto globalBCOffset = (orbit - firstOrbit) * o2::constants::lhc::LHCMaxBunches; + raw_processing_helpers::processZSdata(data, size, feeID, globalBCOffset, reader->getManager()->getLinkZSCallback(), useTimeBins); + } } diff --git a/Detectors/TPC/workflow/src/RawToDigitsSpec.cxx b/Detectors/TPC/workflow/src/RawToDigitsSpec.cxx index bc36ab063c59a..1c392bb605a5e 100644 --- a/Detectors/TPC/workflow/src/RawToDigitsSpec.cxx +++ b/Detectors/TPC/workflow/src/RawToDigitsSpec.cxx @@ -24,6 +24,7 @@ #include "CCDB/CcdbApi.h" #include "DetectorsCalibration/Utils.h" +#include "TPCBase/Mapper.h" #include "TPCCalibration/DigitDump.h" #include "TPCReconstruction/RawReaderCRU.h" #include "TPCWorkflow/CalibProcessingHelper.h" @@ -47,8 +48,10 @@ class TPCDigitDumpDevice : public o2::framework::Task mDigitDump.init(); mDigitDump.setInMemoryOnly(); const auto pedestalFile = ic.options().get("pedestal-file"); - LOGP(info, "Setting pedestal file: {}", pedestalFile); - mDigitDump.setPedestalAndNoiseFile(pedestalFile); + if (pedestalFile.length()) { + LOGP(info, "Setting pedestal file: {}", pedestalFile); + mDigitDump.setPedestalAndNoiseFile(pedestalFile); + } mRawReader.setADCDataCallback([this](const PadROCPos& padROCPos, const CRU& cru, const gsl::span data) -> int { const int timeBins = mDigitDump.update(padROCPos, cru, data); @@ -56,6 +59,13 @@ class TPCDigitDumpDevice : public o2::framework::Task return timeBins; }); + mRawReader.setLinkZSCallback([this](int cru, int rowInSector, int padInRow, int timeBin, float adcValue) -> bool { + CRU cruID(cru); + const PadRegionInfo& regionInfo = Mapper::instance().getPadRegionInfo(cruID.region()); + mDigitDump.updateCRU(cruID, rowInSector - regionInfo.getGlobalRowOffset(), padInRow, timeBin, adcValue); + return true; + }); + mMaxEvents = static_cast(ic.options().get("max-events")); mUseOldSubspec = ic.options().get("use-old-subspec"); mForceQuit = ic.options().get("force-quit"); diff --git a/Detectors/TPC/workflow/src/tpc-raw-to-digits-workflow.cxx b/Detectors/TPC/workflow/src/tpc-raw-to-digits-workflow.cxx index b1ebf0fc1e8ea..6c98aff0f13f4 100644 --- a/Detectors/TPC/workflow/src/tpc-raw-to-digits-workflow.cxx +++ b/Detectors/TPC/workflow/src/tpc-raw-to-digits-workflow.cxx @@ -27,16 +27,6 @@ using namespace o2::framework; -enum class DecoderType { - GBT, ///< GBT frame raw decoding - LinkZS ///< Link based zero suppression -}; - -const std::unordered_map DecoderTypeMap{ - {"GBT", DecoderType::GBT}, - {"LinkZS", DecoderType::LinkZS}, -}; - // we need to add workflow options before including Framework/runDataProcessing void customize(std::vector& workflowOptions) { @@ -54,7 +44,6 @@ void customize(std::vector& workflowOptions) {"tpc-lanes", VariantType::Int, defaultlanes, {laneshelp}}, {"tpc-sectors", VariantType::String, sectorDefault.c_str(), {sectorshelp}}, {"tpc-reco-output", VariantType::String, "", {tpcrthelp}}, - {"decoder-type", VariantType::String, "GBT", {decoderHelp}}, {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings (e.g.: 'TPCCalibPedestal.FirstTimeBin=10;...')"}}, {"configFile", VariantType::String, "", {"configuration file for configurable parameters"}}}; @@ -91,17 +80,9 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) auto tpcSectors = o2::RangeTokenizer::tokenize(configcontext.options().get("tpc-sectors")); auto lanes = 1; //getNumTPCLanes(tpcSectors, config); - const auto decoderType = DecoderTypeMap.at(configcontext.options().get("decoder-type")); - int fanoutsize = 0; for (int l = 0; l < lanes; ++l) { - if (decoderType == DecoderType::GBT) { - specs.emplace_back(o2::tpc::getRawToDigitsSpec(fanoutsize, configcontext.options().get("input-spec"), tpcSectors)); - } else if (decoderType == DecoderType::LinkZS) { - specs.emplace_back(o2::tpc::getLinkZSToDigitsSpec(fanoutsize, configcontext.options().get("input-spec"), tpcSectors)); - } else { - LOG(FATAL) << "bad decoder type"; - } + specs.emplace_back(o2::tpc::getRawToDigitsSpec(fanoutsize, configcontext.options().get("input-spec"), tpcSectors)); fanoutsize++; }