diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/ZeroSuppressionLinkBased.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/ZeroSuppressionLinkBased.h index 0f14e9a6b74af..c7cbde57af313 100644 --- a/DataFormats/Detectors/TPC/include/DataFormatsTPC/ZeroSuppressionLinkBased.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/ZeroSuppressionLinkBased.h @@ -10,7 +10,7 @@ /// \file ZeroSuppressionLinkBased.h /// \brief definitions to deal with the link based zero suppression format -/// \author Jens Wiechula +/// @author Jens Wiechula, Jens.Wiechula@ikf.uni-frankfurt.de #ifndef ALICEO2_DATAFORMATSTPC_ZeroSuppressionLinkBased_H #define ALICEO2_DATAFORMATSTPC_ZeroSuppressionLinkBased_H @@ -29,7 +29,7 @@ static constexpr uint32_t DataWordSizeBytes = DataWordSizeBits / 8; ///< size of /// header definition of the zero suppressed link based data format struct Header { - static constexpr uint32_t MagicWord = 0xFC000000; + static constexpr uint32_t MagicWord = 0xFC; union { uint64_t word0 = 0; ///< lower 64 bits @@ -44,7 +44,8 @@ struct Header { 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 magicWord : 32; ///< not used + uint32_t timeBin : 24; ///< time bin number issues by UL, mainly for debugging, since it might wrap + uint32_t magicWord : 8; ///< not used }; }; diff --git a/Detectors/TPC/base/include/TPCBase/Painter.h b/Detectors/TPC/base/include/TPCBase/Painter.h index bab3d989180ee..1171cf03eb915 100644 --- a/Detectors/TPC/base/include/TPCBase/Painter.h +++ b/Detectors/TPC/base/include/TPCBase/Painter.h @@ -49,7 +49,7 @@ namespace painter /// \param CalDet object to draw /// \return TCanvas containing CalDet content template -TCanvas* draw(const CalDet& calDet, int nbins1D = 300, float xMin1D = 0, float xMax1D = 0); +TCanvas* draw(const CalDet& calDet, int nbins1D = 300, float xMin1D = 0, float xMax1D = 0, TCanvas* outputCanvas = nullptr); /// Drawing of a CalDet object /// \param CalArray object to draw @@ -93,9 +93,10 @@ TH2* getHistogram2D(const CalArray& calArray); /// \param nbins1D number of bins used for the 1D projections /// \param xMin1D minimum value for 1D distribution (xMin = 0 and xMax = 0 for auto scaling) /// \param xMax1D maximum value for 1D distribution (xMin = 0 and xMax = 0 for auto scaling) +/// \param outputCanvases if outputCanvases are given, use them instead of creating new ones, 3 are required /// \return TCanvas containing CalDet content template -std::vector makeSummaryCanvases(const CalDet& calDet, int nbins1D = 300, float xMin1D = 0, float xMax1D = 0, bool onlyFilled = true); +std::vector makeSummaryCanvases(const CalDet& calDet, int nbins1D = 300, float xMin1D = 0, float xMax1D = 0, bool onlyFilled = true, std::vector* outputCanvases = nullptr); /// Create summary canvases for a CalDet object /// diff --git a/Detectors/TPC/base/src/Painter.cxx b/Detectors/TPC/base/src/Painter.cxx index f818bad0e7add..9a37b47eb03de 100644 --- a/Detectors/TPC/base/src/Painter.cxx +++ b/Detectors/TPC/base/src/Painter.cxx @@ -29,7 +29,7 @@ using namespace o2::tpc; template -TCanvas* painter::draw(const CalDet& calDet, int nbins1D, float xMin1D, float xMax1D) +TCanvas* painter::draw(const CalDet& calDet, int nbins1D, float xMin1D, float xMax1D, TCanvas* outputCanvas) { using DetType = CalDet; using CalType = CalArray; @@ -93,7 +93,11 @@ TCanvas* painter::draw(const CalDet& calDet, int nbins1D, float xMin1D, float } // ===| Draw histograms |===================================================== - auto c = new TCanvas(Form("c_%s", name.c_str()), title, 1000, 1000); + auto c = outputCanvas; + if (!c) { + c = new TCanvas(Form("c_%s", name.c_str()), title, 1000, 1000); + } + c->Clear(); c->Divide(2, 2); c->cd(1); @@ -235,7 +239,7 @@ std::enable_if_t::value, bool> hasData(const CalArray& ca } template -std::vector painter::makeSummaryCanvases(const CalDet& calDet, int nbins1D, float xMin1D, float xMax1D, bool onlyFilled) +std::vector painter::makeSummaryCanvases(const CalDet& calDet, int nbins1D, float xMin1D, float xMax1D, bool onlyFilled, std::vector* outputCanvases) { std::vector vecCanvases; @@ -258,14 +262,33 @@ std::vector painter::makeSummaryCanvases(const CalDet& calDet, int } // ===| set up canvases |=== + TCanvas* cSides = nullptr; + TCanvas* cROCs1D = nullptr; + TCanvas* cROCs2D = nullptr; const std::string_view calName = calDet.getName(); - auto cSides = draw(calDet, nbins1D, xMin1D, xMax1D); - auto cROCs1D = new TCanvas(fmt::format("c_ROCs_{}_1D", calName).data(), fmt::format("{} values for each ROC", calName).data(), 1400, 1000); - auto cROCs2D = new TCanvas(fmt::format("c_ROCs_{}_2D", calName).data(), fmt::format("{} values for each ROC", calName).data(), 1400, 1000); + + if (outputCanvases) { + if (!(outputCanvases->size() < 3)) { + LOGP(error, "At least 3 canvases are needed to fill the output, only {} given", outputCanvases->size()); + return vecCanvases; + } + + cSides = outputCanvases->at(0); + cROCs1D = outputCanvases->at(1); + cROCs2D = outputCanvases->at(2); + cSides->Clear(); + cROCs1D->Clear(); + cROCs2D->Clear(); + } else { + + cROCs1D = new TCanvas(fmt::format("c_ROCs_{}_1D", calName).data(), fmt::format("{} values for each ROC", calName).data(), 1400, 1000); + cROCs2D = new TCanvas(fmt::format("c_ROCs_{}_2D", calName).data(), fmt::format("{} values for each ROC", calName).data(), 1400, 1000); + } vecCanvases.emplace_back(cSides); vecCanvases.emplace_back(cROCs1D); vecCanvases.emplace_back(cROCs2D); + cSides = draw(calDet, nbins1D, xMin1D, xMax1D, cSides); cROCs1D->DivideSquare(nROCs); cROCs2D->DivideSquare(nROCs); @@ -327,34 +350,34 @@ std::vector painter::makeSummaryCanvases(const std::string_view fileNa // ===| explicit instantiations |=============================================== // this is required to force the compiler to create instances with the types // we usually would like to deal with -template TCanvas* painter::draw(const CalDet& calDet, int, float, float); -template std::vector painter::makeSummaryCanvases(const CalDet& calDet, int, float, float, bool); +template TCanvas* painter::draw(const CalDet& calDet, int, float, float, TCanvas*); +template std::vector painter::makeSummaryCanvases(const CalDet& calDet, int, float, float, bool, std::vector*); template TCanvas* painter::draw(const CalArray& calArray); template void painter::fillHistogram2D(TH2& h2D, const CalDet& calDet, Side side); template void painter::fillHistogram2D(TH2& h2D, const CalArray& calArray); template TH2* painter::getHistogram2D(const CalDet& calDet, Side side); template TH2* painter::getHistogram2D(const CalArray& calArray); -template TCanvas* painter::draw(const CalDet& calDet, int, float, float); -template std::vector painter::makeSummaryCanvases(const CalDet& calDet, int, float, float, bool); +template TCanvas* painter::draw(const CalDet& calDet, int, float, float, TCanvas*); +template std::vector painter::makeSummaryCanvases(const CalDet& calDet, int, float, float, bool, std::vector*); template TCanvas* painter::draw(const CalArray& calArray); template TH2* painter::getHistogram2D(const CalDet& calDet, Side side); template TH2* painter::getHistogram2D(const CalArray& calArray); -template TCanvas* painter::draw(const CalDet& calDet, int, float, float); -template std::vector painter::makeSummaryCanvases(const CalDet& calDet, int, float, float, bool); +template TCanvas* painter::draw(const CalDet& calDet, int, float, float, TCanvas*); +template std::vector painter::makeSummaryCanvases(const CalDet& calDet, int, float, float, bool, std::vector*); template TCanvas* painter::draw(const CalArray& calArray); template TH2* painter::getHistogram2D(const CalDet& calDet, Side side); template TH2* painter::getHistogram2D(const CalArray& calArray); -template TCanvas* painter::draw(const CalDet& calDet, int, float, float); -template std::vector painter::makeSummaryCanvases(const CalDet& calDet, int, float, float, bool); +template TCanvas* painter::draw(const CalDet& calDet, int, float, float, TCanvas*); +template std::vector painter::makeSummaryCanvases(const CalDet& calDet, int, float, float, bool, std::vector*); template TCanvas* painter::draw(const CalArray& calArray); template TH2* painter::getHistogram2D(const CalDet& calDet, Side side); template TH2* painter::getHistogram2D(const CalArray& calArray); -template TCanvas* painter::draw(const CalDet& calDet, int, float, float); -template std::vector painter::makeSummaryCanvases(const CalDet& calDet, int, float, float, bool); +template TCanvas* painter::draw(const CalDet& calDet, int, float, float, TCanvas*); +template std::vector painter::makeSummaryCanvases(const CalDet& calDet, int, float, float, bool, std::vector*); template TCanvas* painter::draw(const CalArray& calArray); template TH2* painter::getHistogram2D(const CalDet& calDet, Side side); template TH2* painter::getHistogram2D(const CalArray& calArray); diff --git a/Detectors/TPC/base/src/TPCBaseLinkDef.h b/Detectors/TPC/base/src/TPCBaseLinkDef.h index 024e19c34961a..f63c1fada7ee9 100644 --- a/Detectors/TPC/base/src/TPCBaseLinkDef.h +++ b/Detectors/TPC/base/src/TPCBaseLinkDef.h @@ -27,6 +27,7 @@ #pragma link C++ class o2::tpc::CalDet < short> + ; #pragma link C++ class o2::tpc::CalDet < bool> + ; #pragma link C++ class std::vector < o2::tpc::CalDet < float>> + ; +#pragma link C++ class std::vector < o2::tpc::CalDet < float>*> + ; #pragma link C++ class std::unordered_map < std::string, o2::tpc::CalDet < float>> + ; #pragma link C++ class o2::tpc::CDBInterface; #pragma link C++ class o2::tpc::ContainerFactory; diff --git a/Detectors/TPC/calibration/include/TPCCalibration/CalibPedestal.h b/Detectors/TPC/calibration/include/TPCCalibration/CalibPedestal.h index f285f93a8e494..f5074e1f4e47c 100644 --- a/Detectors/TPC/calibration/include/TPCCalibration/CalibPedestal.h +++ b/Detectors/TPC/calibration/include/TPCCalibration/CalibPedestal.h @@ -105,6 +105,9 @@ class CalibPedestal : public CalibRawBase /// \return noise calibration object const CalPad& getNoise() const { return mNoise; } + /// return all pad clibrations as vector + const std::vector*> getCalDets() const { return std::vector*>{&mPedestal, &mNoise}; } + /// Get the statistics type StatisticsType getStatisticsType() const { return mStatisticsType; } diff --git a/Detectors/TPC/calibration/include/TPCCalibration/CalibPedestalParam.h b/Detectors/TPC/calibration/include/TPCCalibration/CalibPedestalParam.h index 1788e5053cc6c..c1278f4862d1e 100644 --- a/Detectors/TPC/calibration/include/TPCCalibration/CalibPedestalParam.h +++ b/Detectors/TPC/calibration/include/TPCCalibration/CalibPedestalParam.h @@ -26,11 +26,11 @@ namespace tpc { struct CalibPedestalParam : public o2::conf::ConfigurableParamHelper { - int FirstTimeBin{0}; ///< first time bin used in analysis - int LastTimeBin{500}; ///< first time bin used in analysis - int ADCMin{0}; ///< minimum adc value - int ADCMax{120}; ///< maximum adc value - StatisticsType StatType{StatisticsType::GausFit}; ///< statistics type to be used for pedestal and noise evaluation + int FirstTimeBin{0}; ///< first time bin used in analysis + int LastTimeBin{500}; ///< first time bin used in analysis + int ADCMin{0}; ///< minimum adc value + int ADCMax{120}; ///< maximum adc value + StatisticsType StatType{StatisticsType::GausFitFast}; ///< statistics type to be used for pedestal and noise evaluation O2ParamDef(CalibPedestalParam, "TPCCalibPedestal"); }; diff --git a/Detectors/TPC/calibration/include/TPCCalibration/CalibRawBase.h b/Detectors/TPC/calibration/include/TPCCalibration/CalibRawBase.h index a1f84dee74fc4..8f24ea2b2572e 100644 --- a/Detectors/TPC/calibration/include/TPCCalibration/CalibRawBase.h +++ b/Detectors/TPC/calibration/include/TPCCalibration/CalibRawBase.h @@ -130,7 +130,7 @@ class CalibRawBase size_t getPresentEventNumber() const { return mPresentEventNumber; } /// return number of events - int getNumberOfEvents() const { return mRawReaderCRUManager.getNumberOfEvents(); } + int getNumberOfEvents() const; /// check if present event is complete bool isPresentEventComplete() const { return mRawReaderCRUManager.isEventComplete(mPresentEventNumber); } @@ -189,6 +189,21 @@ class CalibRawBase //---------------------------------------------------------------- // Inline Functions //---------------------------------------------------------------- +inline int CalibRawBase::getNumberOfEvents() const +{ + if (mGBTFrameContainers.size()) { + return 0; // to be checked + } else if (mRawReaders.size()) { + return 0; // to be checked + } else if (mRawReaderCRUManager.getNumberOfReaders()) { + return mRawReaderCRUManager.getNumberOfEvents(); + } else if (mDigitTree) { + return mDigitTree->GetEntries(); + } else { + return 0; + } +} + inline CalibRawBase::ProcessStatus CalibRawBase::processEvent(int eventNumber) { if (mGBTFrameContainers.size()) { diff --git a/Detectors/TPC/calibration/macro/drawPulser.C b/Detectors/TPC/calibration/macro/drawPulser.C index f4f1d28a87964..34a595cbeedc8 100644 --- a/Detectors/TPC/calibration/macro/drawPulser.C +++ b/Detectors/TPC/calibration/macro/drawPulser.C @@ -138,7 +138,7 @@ 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 = 0.5; + const float rangeT0 = 1.5; const float minT0 = medianT0 - rangeT0; const float maxT0 = medianT0 + rangeT0; diff --git a/Detectors/TPC/calibration/macro/runPedestal.sh b/Detectors/TPC/calibration/macro/runPedestal.sh index a36bb53a60d11..c73309181052d 100755 --- a/Detectors/TPC/calibration/macro/runPedestal.sh +++ b/Detectors/TPC/calibration/macro/runPedestal.sh @@ -40,7 +40,7 @@ outputFile=pedestals.root nevents=1000 firstTimeBin=0 lastTimeBin=450 -statisticsType=0 +statisticsType=1 verbosity=0 debugLevel=0 writeDebug=0 diff --git a/Detectors/TPC/calibration/macro/runPulser.C b/Detectors/TPC/calibration/macro/runPulser.C index d1b8b4898a701..4db55cb3ff669 100644 --- a/Detectors/TPC/calibration/macro/runPulser.C +++ b/Detectors/TPC/calibration/macro/runPulser.C @@ -69,7 +69,7 @@ void runPulser(std::vector fileInfos, TString outputFileName = if (status == CalibRawBase::ProcessStatus::IncompleteEvent) { continue; } else if (status != CalibRawBase::ProcessStatus::Ok) { - break; + //break; } } } diff --git a/Detectors/TPC/reconstruction/include/TPCReconstruction/RawReaderCRU.h b/Detectors/TPC/reconstruction/include/TPCReconstruction/RawReaderCRU.h index f8ba8d82401ea..a1562e2f84e76 100644 --- a/Detectors/TPC/reconstruction/include/TPCReconstruction/RawReaderCRU.h +++ b/Detectors/TPC/reconstruction/include/TPCReconstruction/RawReaderCRU.h @@ -498,6 +498,8 @@ class RawReaderCRU { public: class PacketDescriptor; + using PacketDescriptorMap = std::vector; + using PacketDescriptorMapArray = std::array; /// constructor /// \param @@ -645,6 +647,9 @@ class RawReaderCRU /// output file prefix const std::string& getOutputFilePrefix() const { return mOutputFilePrefix; } + /// get packet descriptor map array + const PacketDescriptorMapArray& getPacketDescriptorMaps() const { return mPacketDescriptorMaps; } + //=========================================================================== //===| Nested helper classes |=============================================== // @@ -723,26 +728,25 @@ class RawReaderCRU // private: - using PacketDescriptorMap = std::vector; - uint32_t mDebugLevel; ///< debug level - uint32_t mVerbosity; ///< verbosity - uint32_t mNumTimeBins; ///< number of time bins to process - uint32_t mLink; ///< present link being processed - uint32_t mStream; ///< present stream being processed - uint32_t mEventNumber = 0; ///< current event number to process - uint32_t mReaderNumber = 0; ///< raw reader number in manager - CRU mCRU; ///< CRU - size_t mFileSize; ///< size of the input file - bool mDumpTextFiles = false; ///< dump debugging text files - bool mFillADCdataMap = true; ///< fill the ADC data map - bool mForceCRU = false; ///< force CRU: overwrite value from RDH - bool mFileIsScanned = false; ///< if file was already scanned - std::array mPacketsPerLink; ///< array to keep track of the number of packets per link - std::bitset mLinkPresent; ///< info if link is present in data; information retrieved from scanning the RDH headers - std::array mPacketDescriptorMaps; ///< array to hold vectors thhe packet descriptors - std::string mInputFileName; ///< input file name - std::string mOutputFilePrefix; ///< input file name - std::array mSyncPositions{}; ///< sync positions for each link + uint32_t mDebugLevel; ///< debug level + uint32_t mVerbosity; ///< verbosity + uint32_t mNumTimeBins; ///< number of time bins to process + uint32_t mLink; ///< present link being processed + uint32_t mStream; ///< present stream being processed + uint32_t mEventNumber = 0; ///< current event number to process + uint32_t mReaderNumber = 0; ///< raw reader number in manager + CRU mCRU; ///< CRU + size_t mFileSize; ///< size of the input file + bool mDumpTextFiles = false; ///< dump debugging text files + bool mFillADCdataMap = true; ///< fill the ADC data map + bool mForceCRU = false; ///< force CRU: overwrite value from RDH + bool mFileIsScanned = false; ///< if file was already scanned + std::array mPacketsPerLink; ///< array to keep track of the number of packets per link + std::bitset mLinkPresent; ///< info if link is present in data; information retrieved from scanning the RDH headers + PacketDescriptorMapArray mPacketDescriptorMaps; ///< array to hold vectors thhe packet descriptors + std::string mInputFileName; ///< input file name + std::string mOutputFilePrefix; ///< input file name + std::array mSyncPositions{}; ///< sync positions for each link // not so nice but simplest way to store the ADC data std::map> mADCdata; ///< decoded ADC data RawReaderCRUManager* mManager{nullptr}; ///< event synchronization information @@ -952,6 +956,9 @@ class RawReaderCRUManager } } + /// get the event sync + const RawReaderCRUEventSync& getEventSync() const { return mEventSync; } + /// get number of all events size_t getNumberOfEvents() const { return mEventSync.getNumberOfEvents(); } diff --git a/Detectors/TPC/reconstruction/src/RawReaderCRU.cxx b/Detectors/TPC/reconstruction/src/RawReaderCRU.cxx index cf40997ba1d7b..2609bdbd63e3a 100644 --- a/Detectors/TPC/reconstruction/src/RawReaderCRU.cxx +++ b/Detectors/TPC/reconstruction/src/RawReaderCRU.cxx @@ -231,9 +231,9 @@ int RawReaderCRU::scanFile() RDH rdh; uint32_t currentPacket = 0; uint32_t lastHeartbeatOrbit = 0; + size_t currentPos = 0; - while ((currentPacket < numPackets) && !file.eof()) { - const size_t currentPos = file.tellg(); + while ((currentPos < mFileSize) && !file.eof()) { // ===| read in the RawDataHeader at the current position |================= file >> rdh; @@ -349,6 +349,7 @@ int RawReaderCRU::scanFile() // std::cout << "Position after read : " << std::dec << file.tellg() << std::endl; file.seekg(offset, file.cur); ++currentPacket; + currentPos = file.tellg(); } // close the File @@ -905,7 +906,7 @@ void RawReaderCRU::writeGBTDataPerLink(std::string_view outputDirectory, int max // loop over events for (int eventNumber = 0; eventNumber < getNumberOfEvents(); ++eventNumber) { - if ((maxEvents > -1) && (eventNumber > maxEvents)) { + if ((maxEvents > -1) && (eventNumber >= maxEvents)) { break; } @@ -916,11 +917,12 @@ void RawReaderCRU::writeGBTDataPerLink(std::string_view outputDirectory, int max if (!linkInfo.IsPresent) { continue; } + printf("Event %4d, Link %2d\n", eventNumber, iLink); const int ep = iLink >= 12; const int link = iLink - (ep)*12; auto outputFileName = fmt::format("{}/CRU_{:02}_EP_{}_Link_{:02}", outputDirectory.data(), mCRU, ep, link); - std::ofstream outputFile(outputFileName, std::ios_base::binary); + std::ofstream outputFile(outputFileName, std::ios_base::binary | std::ios_base::app); for (auto packetNumber : linkInfo.PacketPositions) { const auto& packet = mPacketDescriptorMaps[iLink][packetNumber]; @@ -1136,8 +1138,15 @@ void RawReaderCRUManager::copyEvents(const std::vector eventNumbers, s { // make sure events have been built init(); - for (auto& rawReader : mRawReadersCRU) { - rawReader->copyEvents(eventNumbers, outputDirectory.data(), mode); + const auto& cruSeen = mEventSync.getCRUSeen(); + + for (size_t iCRU = 0; iCRU < cruSeen.size(); ++iCRU) { + const auto readerNumber = cruSeen[iCRU]; + if (readerNumber >= 0) { + auto& reader = mRawReadersCRU[readerNumber]; + reader->forceCRU(iCRU); + reader->copyEvents(eventNumbers, outputDirectory.data(), mode); + } } } diff --git a/Detectors/TPC/workflow/CMakeLists.txt b/Detectors/TPC/workflow/CMakeLists.txt index e01faa1402162..27696d822f721 100644 --- a/Detectors/TPC/workflow/CMakeLists.txt +++ b/Detectors/TPC/workflow/CMakeLists.txt @@ -26,6 +26,7 @@ o2_add_library(TPCWorkflow src/CalibProcessingHelper.cxx src/ClusterSharingMapSpec.cxx src/FileReaderWorkflow.cxx + src/CalDetMergerPublisherSpec.cxx TARGETVARNAME targetName PUBLIC_LINK_LIBRARIES O2::Framework O2::DataFormatsTPC O2::DPLUtils O2::TPCReconstruction diff --git a/Detectors/TPC/workflow/README.md b/Detectors/TPC/workflow/README.md index 85d3fdd4e3c60..c72edb70e72e0 100644 --- a/Detectors/TPC/workflow/README.md +++ b/Detectors/TPC/workflow/README.md @@ -152,10 +152,12 @@ bz= magnetic field ### Pedestal calibration #### Options ```bash ---direct-file-dump write final calibration to local root file ---max-events maximum number of events to process ---no-calib-output don't send the calibration data via DPL (required in case the calibration write is not attached) ---use-old-subspec Subspecification is built from RDH like +--direct-file-dump write final calibration to local root file +--max-events maximum number of events to process +--no-write-ccdb don't send the calibration data via DPL (required in case the calibration write is not attached) +--use-old-subspec use old subspec definition (CruId << 16) | ((LinkId + 1) << (CruEndPoint == 1 ? 8 : 0)) +--lanes arg (=1) number of parallel processes +--sectors arg (=0-35) list of TPC sectors, comma separated ranges, e.g. 0-3,7,9-15 ``` #### Running with data distribution @@ -183,7 +185,7 @@ o2-raw-file-reader-workflow --input-conf raw-reader.cfg --nocheck-hbf-per-tf -- ``` #### Send data to CCDB -Remove the `--no-calib-output` option and add +Remove the `--no-write-ccdb` option and add ```bash | o2-calibration-ccdb-populator-workflow ``` diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/CalDetMergerPublisherSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/CalDetMergerPublisherSpec.h new file mode 100644 index 0000000000000..190aca4eca42e --- /dev/null +++ b/Detectors/TPC/workflow/include/TPCWorkflow/CalDetMergerPublisherSpec.h @@ -0,0 +1,30 @@ +// 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_CalDetMergerPublisherSpec_H +#define O2_TPC_CalDetMergerPublisherSpec_H + +/// @file CalDetMergerPublisherSpec.h +/// @brief TPC CalDet merger and CCDB publisher +/// @author Jens Wiechula, Jens.Wiechula@ikf.uni-frankfurt.de + +#include "Framework/DataProcessorSpec.h" + +namespace o2 +{ +namespace tpc +{ + +o2::framework::DataProcessorSpec getCalDetMergerPublisherSpec(bool skipCCDB); + +} // namespace tpc +} // namespace o2 + +#endif diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/CalibProcessingHelper.h b/Detectors/TPC/workflow/include/TPCWorkflow/CalibProcessingHelper.h index 74158f92ee406..83a7323e2980c 100644 --- a/Detectors/TPC/workflow/include/TPCWorkflow/CalibProcessingHelper.h +++ b/Detectors/TPC/workflow/include/TPCWorkflow/CalibProcessingHelper.h @@ -28,7 +28,7 @@ class RawReaderCRU; namespace calib_processing_helper { -uint64_t processRawData(o2::framework::InputRecord& inputs, std::unique_ptr& reader, bool useOldSubspec = false); +uint64_t processRawData(o2::framework::InputRecord& inputs, std::unique_ptr& reader, bool useOldSubspec = false, const std::vector& sectors = {}); } // namespace calib_processing_helper } // namespace tpc } // namespace o2 diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/TPCCalibPedestalSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/TPCCalibPedestalSpec.h index 2243aa8713428..52b5287bccbff 100644 --- a/Detectors/TPC/workflow/include/TPCWorkflow/TPCCalibPedestalSpec.h +++ b/Detectors/TPC/workflow/include/TPCWorkflow/TPCCalibPedestalSpec.h @@ -17,14 +17,16 @@ #include #include #include +#include #include "Framework/Task.h" #include "Framework/ControlService.h" #include "Framework/Logger.h" #include "Framework/ConfigParamRegistry.h" +#include "Framework/DataProcessorSpec.h" +#include "CommonUtils/MemFileHelper.h" #include "Headers/DataHeader.h" -#include "CCDB/CcdbApi.h" #include "DetectorsCalibration/Utils.h" #include "TPCBase/CDBInterface.h" @@ -38,13 +40,13 @@ using clbUtils = o2::calibration::Utils; namespace o2 { -namespace calibration +namespace tpc { class TPCCalibPedestalDevice : public o2::framework::Task { public: - TPCCalibPedestalDevice(bool skipCalib) : mSkipCalib(skipCalib) {} + TPCCalibPedestalDevice(int lane, const std::vector& sectors) : mLane{lane}, mSectors(sectors) {} void init(o2::framework::InitContext& ic) final { @@ -74,7 +76,7 @@ class TPCCalibPedestalDevice : public o2::framework::Task } auto& reader = mRawReader.getReaders()[0]; - calib_processing_helper::processRawData(pc.inputs(), reader, mUseOldSubspec); + calib_processing_helper::processRawData(pc.inputs(), reader, mUseOldSubspec, mSectors); mCalibPedestal.incrementNEvents(); LOGP(info, "Number of processed events: {} ({})", mCalibPedestal.getNumberOfProcessedEvents(), mMaxEvents); @@ -96,51 +98,37 @@ class TPCCalibPedestalDevice : public o2::framework::Task { LOGP(info, "endOfStream"); dumpCalibData(); - if (!mSkipCalib) { - sendOutput(ec.outputs()); - } + sendOutput(ec.outputs()); ec.services().get().readyToQuit(QuitRequest::Me); } private: CalibPedestal mCalibPedestal; rawreader::RawReaderCRUManager mRawReader; - uint32_t mMaxEvents{100}; - bool mReadyToQuit{false}; - bool mCalibDumped{false}; - bool mUseOldSubspec{false}; - bool mForceQuit{false}; - bool mDirectFileDump{false}; - bool mSkipCalib{false}; + uint32_t mMaxEvents{100}; ///< maximum number of events to process + int mLane{0}; ///< lane number of processor + std::vector mSectors{}; ///< sectors to process in this instance + bool mReadyToQuit{false}; ///< if processor is ready to quit + bool mCalibDumped{false}; ///< if calibration object already dumped + bool mUseOldSubspec{false}; ///< use the old subspec definition + bool mForceQuit{false}; ///< for quit after processing finished + bool mDirectFileDump{false}; ///< directly dump the calibration data to file //____________________________________________________________________________ void sendOutput(DataAllocator& output) { - CDBStorage::MetaData_t md; - - // perhaps should be changed to time of the run - const auto now = std::chrono::system_clock::now(); - long timeStart = std::chrono::duration_cast(now.time_since_epoch()).count(); - long timeEnd = 99999999999999; std::array*, 2> data = {&mCalibPedestal.getPedestal(), &mCalibPedestal.getNoise()}; std::array dataType = {CDBType::CalPedestal, CDBType::CalNoise}; for (size_t i = 0; i < data.size(); ++i) { auto cal = data[i]; - o2::ccdb::CcdbObjectInfo w; - auto image = o2::ccdb::CcdbApi::createObjectImage(cal, &w); - - w.setPath(CDBTypeMap.at(dataType[i])); - w.setStartValidityTimestamp(timeStart); - w.setEndValidityTimestamp(timeEnd); - - LOG(INFO) << "Sending object " << w.getPath() << "/" << w.getFileName() << " of size " << image->size() - << " bytes, valid for " << w.getStartValidityTimestamp() << " : " << w.getEndValidityTimestamp(); + auto image = o2::utils::MemFileHelper::createFileImage(cal, typeid(*cal), cal->getName(), "data"); + int type = int(dataType[i]); header::DataHeader::SubSpecificationType subSpec{(header::DataHeader::SubSpecificationType)i}; - output.snapshot(Output{clbUtils::gDataOriginCLB, clbUtils::gDataDescriptionCLBPayload, subSpec}, *image.get()); - output.snapshot(Output{clbUtils::gDataOriginCLB, clbUtils::gDataDescriptionCLBInfo, subSpec}, w); + output.snapshot(Output{clbUtils::gDataOriginCLB, "TPCCLBPART", subSpec}, *image.get()); + output.snapshot(Output{clbUtils::gDataOriginCLB, "TPCCLBPARTINFO", subSpec}, type); } } @@ -150,32 +138,24 @@ class TPCCalibPedestalDevice : public o2::framework::Task if (mDirectFileDump && !mCalibDumped) { LOGP(info, "Dumping output"); mCalibPedestal.analyse(); - mCalibPedestal.dumpToFile("pedestals.root"); + mCalibPedestal.dumpToFile(fmt::format("pedestals_{:02}.root", mLane)); mCalibDumped = true; } } }; -} // namespace calibration - -namespace framework +DataProcessorSpec getTPCCalibPedestalSpec(const std::string inputSpec, int ilane = 0, std::vector sectors = {}) { + std::vector outputs; + outputs.emplace_back(ConcreteDataTypeMatcher{clbUtils::gDataOriginCLB, "TPCCLBPART"}); + outputs.emplace_back(ConcreteDataTypeMatcher{clbUtils::gDataOriginCLB, "TPCCLBPARTINFO"}); -DataProcessorSpec getTPCCalibPedestalSpec(const std::string inputSpec, bool skipCalib) -{ - using device = o2::calibration::TPCCalibPedestalDevice; - - std::vector outputs; - if (!skipCalib) { - outputs.emplace_back(ConcreteDataTypeMatcher{clbUtils::gDataOriginCLB, clbUtils::gDataDescriptionCLBPayload}); - outputs.emplace_back(ConcreteDataTypeMatcher{clbUtils::gDataOriginCLB, clbUtils::gDataDescriptionCLBInfo}); - } - + const auto id = fmt::format("calib-tpc-pedestal-{:02}", ilane); return DataProcessorSpec{ - "calib-tpc-pedestal", + id.data(), select(inputSpec.data()), outputs, - AlgorithmSpec{adaptFromTask(skipCalib)}, + AlgorithmSpec{adaptFromTask(ilane, sectors)}, Options{ {"max-events", VariantType::Int, 100, {"maximum number of events to process"}}, {"use-old-subspec", VariantType::Bool, false, {"use old subsecifiation definition"}}, @@ -185,7 +165,7 @@ DataProcessorSpec getTPCCalibPedestalSpec(const std::string inputSpec, bool skip }; // end DataProcessorSpec } -} // namespace framework +} // namespace tpc } // namespace o2 #endif diff --git a/Detectors/TPC/workflow/src/CalDetMergerPublisherSpec.cxx b/Detectors/TPC/workflow/src/CalDetMergerPublisherSpec.cxx new file mode 100644 index 0000000000000..740ac44896fa8 --- /dev/null +++ b/Detectors/TPC/workflow/src/CalDetMergerPublisherSpec.cxx @@ -0,0 +1,166 @@ +// 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. + +/// @file CalDetMergerPublisherSpec.cxx +/// @brief TPC CalDet merger and CCDB publisher +/// @author Jens Wiechula, Jens.Wiechula@ikf.uni-frankfurt.de + +#include +#include +#include +#include + +#include + +#include "TMemFile.h" +#include "TFile.h" + +#include "Framework/Task.h" +#include "Framework/ControlService.h" +#include "Framework/Logger.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/DataProcessorSpec.h" + +#include "Headers/DataHeader.h" +#include "DetectorsCalibration/Utils.h" +#include "CCDB/CcdbApi.h" +#include "CCDB/CcdbObjectInfo.h" +#include "TPCBase/CDBInterface.h" +#include "TPCBase/CalDet.h" +#include "TPCWorkflow/CalDetMergerPublisherSpec.h" + +using namespace o2::framework; +using namespace o2::tpc; +using clbUtils = o2::calibration::Utils; + +class CalDetMergerPublisherSpec : public o2::framework::Task +{ + using CcdbObjectInfo = o2::ccdb::CcdbObjectInfo; + + public: + CalDetMergerPublisherSpec(bool skipCCDB) : mSkipCCDB(skipCCDB) {} + + void init(o2::framework::InitContext& ic) final + { + mForceQuit = ic.options().get("force-quit"); + mDirectFileDump = ic.options().get("direct-file-dump"); + } + + void run(o2::framework::ProcessingContext& pc) final + { + int nSlots = pc.inputs().getNofParts(0); + assert(pc.inputs().getNofParts(1) == nSlots); + + LOGP(info, "CalDetMergerPublisherSpec run"); + for (int isl = 0; isl < nSlots; isl++) { + const auto type = pc.inputs().get("clbInfo", isl); + const auto pld = pc.inputs().get>("clbPayload", isl); // this is actually an image of TMemFile + + //const auto& path = wrp->getPath(); + TMemFile f("file", (char*)&pld[0], pld.size(), "READ"); + if (!f.IsZombie()) { + auto calDet = f.Get>("data"); + if (calDet) { + if (mMergedCalDets.find(type) == mMergedCalDets.end()) { + mMergedCalDets[type] = *calDet; + } else { + mMergedCalDets[type] += *calDet; + } + } + } + f.Close(); + + LOGP(info, "getting slot {}", isl); + } + } + + void endOfStream(o2::framework::EndOfStreamContext& ec) final + { + LOGP(info, "CalDetMergerPublisherSpec endOfStream"); + + dumpCalibData(); + sendOutput(ec.outputs()); + ec.services().get().readyToQuit(QuitRequest::Me); + } + + private: + using dataType = o2::tpc::CalDet; + std::unordered_map mMergedCalDets; ///< calibration data to merge + bool mForceQuit{false}; ///< for quit after processing finished + bool mDirectFileDump{false}; ///< directly dump the calibration data to file + bool mCalibDumped{false}; ///< if calibration object already dumped + bool mSkipCCDB{false}; ///< skip sending of calibration data + + //____________________________________________________________________________ + void sendOutput(DataAllocator& output) + { + //CDBStorage::MetaData_t md; + + // perhaps should be changed to time of the run + const auto now = std::chrono::system_clock::now(); + const long timeStart = std::chrono::duration_cast(now.time_since_epoch()).count(); + const long timeEnd = 99999999999999; + + for (auto& [type, object] : mMergedCalDets) { + o2::ccdb::CcdbObjectInfo w; + auto image = o2::ccdb::CcdbApi::createObjectImage(&object, &w); + + w.setPath(CDBTypeMap.at(CDBType(type))); + w.setStartValidityTimestamp(timeStart); + w.setEndValidityTimestamp(timeEnd); + + LOG(INFO) << "Sending object " << w.getPath() << "/" << w.getFileName() << " of size " << image->size() + << " bytes, valid for " << w.getStartValidityTimestamp() << " : " << w.getEndValidityTimestamp(); + + o2::header::DataHeader::SubSpecificationType subSpec{(o2::header::DataHeader::SubSpecificationType)type}; + output.snapshot(Output{clbUtils::gDataOriginCLB, clbUtils::gDataDescriptionCLBPayload, subSpec}, *image.get()); + output.snapshot(Output{clbUtils::gDataOriginCLB, clbUtils::gDataDescriptionCLBInfo, subSpec}, w); + } + } + + //____________________________________________________________________________ + void dumpCalibData() + { + if (mDirectFileDump && !mCalibDumped) { + LOGP(info, "CalDetMergerPublisherSpec Dumping output"); + TFile f("merged_CalDet.root", "recreate"); + for (auto& [type, object] : mMergedCalDets) { + f.WriteObject(&object, object.getName().data()); + } + mCalibDumped = true; + } + } +}; + +o2::framework::DataProcessorSpec o2::tpc::getCalDetMergerPublisherSpec(bool skipCCDB) +{ + std::vector outputs; + if (!skipCCDB) { + outputs.emplace_back(ConcreteDataTypeMatcher{clbUtils::gDataOriginCLB, clbUtils::gDataDescriptionCLBPayload}); + outputs.emplace_back(ConcreteDataTypeMatcher{clbUtils::gDataOriginCLB, clbUtils::gDataDescriptionCLBInfo}); + } + + std::vector inputs; + inputs.emplace_back("clbPayload", ConcreteDataTypeMatcher{clbUtils::gDataOriginCLB, "TPCCLBPART"}); + inputs.emplace_back("clbInfo", ConcreteDataTypeMatcher{clbUtils::gDataOriginCLB, "TPCCLBPARTINFO"}); + + const std::string id = "calib-tpc-caldet-merger-publisher"; + + return DataProcessorSpec{ + id.data(), + inputs, + outputs, + AlgorithmSpec{adaptFromTask(skipCCDB)}, + Options{ + {"force-quit", VariantType::Bool, false, {"force quit after max-events have been reached"}}, + {"direct-file-dump", VariantType::Bool, false, {"directly dump calibration to file"}}, + } // end Options + }; // end DataProcessorSpec +} diff --git a/Detectors/TPC/workflow/src/CalibProcessingHelper.cxx b/Detectors/TPC/workflow/src/CalibProcessingHelper.cxx index 6f42bfa033dcf..bf705b33a9a12 100644 --- a/Detectors/TPC/workflow/src/CalibProcessingHelper.cxx +++ b/Detectors/TPC/workflow/src/CalibProcessingHelper.cxx @@ -8,6 +8,9 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +#include +#include + #include "Framework/ConcreteDataMatcher.h" #include "Framework/InputRecordWalker.h" #include "Framework/Logger.h" @@ -21,7 +24,7 @@ using namespace o2::tpc; using namespace o2::framework; -uint64_t calib_processing_helper::processRawData(o2::framework::InputRecord& inputs, std::unique_ptr& reader, bool useOldSubspec) +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}}; @@ -45,7 +48,13 @@ uint64_t calib_processing_helper::processRawData(o2::framework::InputRecord& inp rdh_utils::getMapping(feeID, cruID, endPoint, linkID); } - uint64_t sector = cruID / 10; + const uint64_t sector = cruID / 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())) { + continue; + } + activeSectors |= (0x1 << sector); const auto globalLinkID = linkID + endPoint * 12; diff --git a/Detectors/TPC/workflow/src/tpc-calib-pedestal.cxx b/Detectors/TPC/workflow/src/tpc-calib-pedestal.cxx index ba58c351beaab..3056e70cd902a 100644 --- a/Detectors/TPC/workflow/src/tpc-calib-pedestal.cxx +++ b/Detectors/TPC/workflow/src/tpc-calib-pedestal.cxx @@ -9,6 +9,7 @@ // or submit itself to any jurisdiction. #include +#include "Algorithm/RangeTokenizer.h" #include "Framework/WorkflowSpec.h" #include "Framework/DataProcessorSpec.h" #include "Framework/DataSpecUtils.h" @@ -28,6 +29,7 @@ #include "DetectorsRaw/RDHUtils.h" #include "TPCBase/RDHUtils.h" #include "TPCWorkflow/TPCCalibPedestalSpec.h" +#include "TPCWorkflow/CalDetMergerPublisherSpec.h" using namespace o2::framework; using RDHUtils = o2::raw::RDHUtils; @@ -36,17 +38,23 @@ using RDHUtils = o2::raw::RDHUtils; void customize(std::vector& policies) { using o2::framework::CompletionPolicy; - policies.push_back(CompletionPolicyHelpers::defineByName("calib-tpc-pedestal", CompletionPolicy::CompletionOp::Consume)); + policies.push_back(CompletionPolicyHelpers::defineByName("calib-tpc-pedestal.*", CompletionPolicy::CompletionOp::Consume)); + policies.push_back(CompletionPolicyHelpers::defineByName("calib-tpc-caldet-merger-publisher", CompletionPolicy::CompletionOp::Consume)); } // we need to add workflow options before including Framework/runDataProcessing void customize(std::vector& workflowOptions) { + std::string sectorDefault = "0-" + std::to_string(o2::tpc::Sector::MAXSECTOR - 1); + int defaultlanes = 1; //std::max(1u, std::thread::hardware_concurrency() / 2); + std::vector options{ {"input-spec", VariantType::String, "A:TPC/RAWDATA", {"selection string input specs"}}, {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings (e.g.: 'TPCCalibPedestal.FirstTimeBin=10;...')"}}, {"configFile", VariantType::String, "", {"configuration file for configurable parameters"}}, - {"no-calib-output", VariantType::Bool, false, {"skip sending the calibration output"}}, + {"no-write-ccdb", VariantType::Bool, false, {"skip sending the calibration output to CCDB"}}, + {"lanes", VariantType::Int, defaultlanes, {"Number of parallel processing lanes."}}, + {"sectors", VariantType::String, sectorDefault.c_str(), {"List of TPC sectors, comma separated ranges, e.g. 0-3,7,9-15"}}, }; std::swap(workflowOptions, options); @@ -66,10 +74,30 @@ WorkflowSpec defineDataProcessing(ConfigContext const& config) o2::conf::ConfigurableParam::writeINI("o2tpccalibration_configuration.ini"); const std::string inputSpec = config.options().get("input-spec"); - const auto skipCalib = config.options().get("no-calib-output"); + const auto skipCCDB = config.options().get("no-write-ccdb"); + + const auto tpcsectors = o2::RangeTokenizer::tokenize(config.options().get("sectors")); + const auto nSectors = (int)tpcsectors.size(); + const auto nLanes = std::min(config.options().get("lanes"), nSectors); + const auto sectorsPerLane = nSectors / nLanes + ((nSectors % nLanes) != 0); WorkflowSpec workflow; - workflow.emplace_back(getTPCCalibPedestalSpec(inputSpec, skipCalib)); + + if (nLanes <= 0) { + return workflow; + } + + for (int ilane = 0; ilane < nLanes; ++ilane) { + auto first = tpcsectors.begin() + ilane * sectorsPerLane; + if (first >= tpcsectors.end()) { + break; + } + auto last = std::min(tpcsectors.end(), first + sectorsPerLane); + std::vector range(first, last); + workflow.emplace_back(getTPCCalibPedestalSpec(inputSpec, ilane, range)); + } + + workflow.emplace_back(getCalDetMergerPublisherSpec(skipCCDB)); return workflow; }