diff --git a/DataFormats/Detectors/CTP/CMakeLists.txt b/DataFormats/Detectors/CTP/CMakeLists.txt index c296fdb6da1f6..437766a2397fe 100644 --- a/DataFormats/Detectors/CTP/CMakeLists.txt +++ b/DataFormats/Detectors/CTP/CMakeLists.txt @@ -11,15 +11,16 @@ o2_add_library(DataFormatsCTP SOURCES src/Digits.cxx - SOURCES src/Configuration.cxx - SOURCES src/Scalers.cxx + src/Configuration.cxx + src/Scalers.cxx + src/CTF.cxx PUBLIC_LINK_LIBRARIES O2::CommonDataFormat O2::Headers O2::SimulationDataFormat - O2::CommonConstants - O2::DataFormatsFT0) + O2::CommonConstants) o2_target_root_dictionary(DataFormatsCTP HEADERS include/DataFormatsCTP/Digits.h include/DataFormatsCTP/Configuration.h - include/DataFormatsCTP/Scalers.h) + include/DataFormatsCTP/Scalers.h + include/DataFormatsCTP/CTF.h) diff --git a/DataFormats/Detectors/CTP/include/DataFormatsCTP/CTF.h b/DataFormats/Detectors/CTP/include/DataFormatsCTP/CTF.h new file mode 100644 index 0000000000000..3e42d9fe315ad --- /dev/null +++ b/DataFormats/Detectors/CTP/include/DataFormatsCTP/CTF.h @@ -0,0 +1,52 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// 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 CTF.h +/// \author ruben.shahoyan@cern.ch +/// \brief Definitions for CTP CTF data + +#ifndef O2_CTP_CTF_H +#define O2_CTP_CTF_H + +#include +#include +#include "DetectorsCommonDataFormats/EncodedBlocks.h" + +namespace o2 +{ +namespace ctp +{ + +/// Header for a single CTF +struct CTFHeader : public o2::ctf::CTFDictHeader { + uint32_t nTriggers = 0; /// number of triggers + uint32_t firstOrbit = 0; /// orbit of 1st trigger + uint16_t firstBC = 0; /// bc of 1st trigger + + ClassDefNV(CTFHeader, 1); +}; + +/// wrapper for the Entropy-encoded trigger inputs and classes of the TF +struct CTF : public o2::ctf::EncodedBlocks { + + static constexpr size_t N = getNBlocks(); + enum Slots { BLC_bcIncTrig, + BLC_orbitIncTrig, + BLC_bytesInput, // bytes of the CTPInputMask bitset (6 bytes from lowest to highest) + BLC_bytesClass // bytes of the CTPClassMask bitset (8 bytes from lowest to highest) + }; + ClassDefNV(CTF, 1); +}; + +} // namespace ctp +} // namespace o2 + +#endif diff --git a/DataFormats/Detectors/CTP/include/DataFormatsCTP/Digits.h b/DataFormats/Detectors/CTP/include/DataFormatsCTP/Digits.h index 0ee74801939ee..8c9b851e96b5a 100644 --- a/DataFormats/Detectors/CTP/include/DataFormatsCTP/Digits.h +++ b/DataFormats/Detectors/CTP/include/DataFormatsCTP/Digits.h @@ -17,7 +17,6 @@ #define _CTP_DIGITS_H_ #include "DetectorsCommonDataFormats/DetID.h" #include "CommonDataFormat/InteractionRecord.h" -#include "DataFormatsFT0/Digit.h" #include #include @@ -53,8 +52,16 @@ struct CTPDigit { void printStream(std::ostream& stream) const; void setInputMask(gbtword80_t mask); void setClassMask(gbtword80_t mask); + bool operator==(const CTPDigit& d) const + { + return intRecord == d.intRecord && CTPInputMask == d.CTPInputMask && CTPClassMask == d.CTPClassMask; + } + ClassDefNV(CTPDigit, 2); }; + +std::ostream& operator<<(std::ostream& os, const CTPDigit& d); + struct CTPInputDigit { o2::InteractionRecord intRecord; std::bitset inputsMask; diff --git a/DataFormats/Detectors/CTP/src/CTF.cxx b/DataFormats/Detectors/CTP/src/CTF.cxx new file mode 100644 index 0000000000000..3616f6a387040 --- /dev/null +++ b/DataFormats/Detectors/CTP/src/CTF.cxx @@ -0,0 +1,16 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// 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 +#include "DataFormatsCTP/CTF.h" + +using namespace o2::ctp; diff --git a/DataFormats/Detectors/CTP/src/DataFormatsCTPLinkDef.h b/DataFormats/Detectors/CTP/src/DataFormatsCTPLinkDef.h index 3312517d5628e..47ea52e8f1d91 100644 --- a/DataFormats/Detectors/CTP/src/DataFormatsCTPLinkDef.h +++ b/DataFormats/Detectors/CTP/src/DataFormatsCTPLinkDef.h @@ -40,4 +40,9 @@ #pragma link C++ class o2::ctp::CTPScalerRecordO2 + ; #pragma link C++ class vector < o2::ctp::CTPScalerRecordO2> + ; #pragma link C++ class o2::ctp::CTPRunScalers + ; + +#pragma link C++ struct o2::ctp::CTFHeader + ; +#pragma link C++ struct o2::ctp::CTF + ; +#pragma link C++ class o2::ctf::EncodedBlocks < o2::ctp::CTFHeader, 4, uint32_t> + ; + #endif diff --git a/DataFormats/Detectors/CTP/src/Digits.cxx b/DataFormats/Detectors/CTP/src/Digits.cxx index 96825d2cb9264..aa44216270721 100644 --- a/DataFormats/Detectors/CTP/src/Digits.cxx +++ b/DataFormats/Detectors/CTP/src/Digits.cxx @@ -17,12 +17,17 @@ using namespace o2::ctp; +std::ostream& o2::ctp::operator<<(std::ostream& os, const o2::ctp::CTPDigit& d) +{ + os << "CTP Digit: " << d.intRecord << " Input Mask: " << d.CTPInputMask << " Class Mask: " << d.CTPClassMask; + return os; +} + void CTPDigit::printStream(std::ostream& stream) const { - stream << "CTP Digit: BC " << intRecord.bc << " orbit " << intRecord.orbit << std::endl; - stream << "Input Mask: " << CTPInputMask << std::endl; - stream << "Class Mask: " << CTPClassMask << std::endl; + stream << *this << std::endl; } + void CTPDigit::setInputMask(gbtword80_t mask) { for (int i = 0; i < CTP_NINPUTS; i++) { diff --git a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h index 822ef29801173..b7b726b91ee9d 100644 --- a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h +++ b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h @@ -922,7 +922,7 @@ template std::vector EncodedBlocks::createDictionaryBlocks(const std::vector& vfreq, const std::vector& vmd) { if (vfreq.size() != N) { - throw std::runtime_error("mismatch between the size of frequencies vector and number of blocks"); + throw std::runtime_error(fmt::format("mismatch between the size of frequencies vector {} and number of blocks {}", vfreq.size(), N)); } size_t sz = alignSize(sizeof(EncodedBlocks)); for (int ib = 0; ib < N; ib++) { diff --git a/Detectors/CTF/CMakeLists.txt b/Detectors/CTF/CMakeLists.txt index 46d5aaf5fd8bd..2c459698ac350 100644 --- a/Detectors/CTF/CMakeLists.txt +++ b/Detectors/CTF/CMakeLists.txt @@ -24,21 +24,21 @@ o2_add_test(tpc SOURCES test/test_ctf_io_tpc.cxx COMPONENT_NAME ctf LABELS ctf) - + o2_add_test(ft0 PUBLIC_LINK_LIBRARIES O2::FT0Reconstruction O2::DataFormatsFT0 SOURCES test/test_ctf_io_ft0.cxx COMPONENT_NAME ctf LABELS ctf) - + o2_add_test(fv0 PUBLIC_LINK_LIBRARIES O2::FV0Reconstruction O2::DataFormatsFV0 SOURCES test/test_ctf_io_fv0.cxx COMPONENT_NAME ctf LABELS ctf) - + o2_add_test(fdd PUBLIC_LINK_LIBRARIES O2::FDDReconstruction O2::DataFormatsFDD @@ -73,7 +73,7 @@ o2_add_test(emcal SOURCES test/test_ctf_io_emcal.cxx COMPONENT_NAME ctf LABELS ctf) - + o2_add_test(phos PUBLIC_LINK_LIBRARIES O2::DataFormatsPHOS O2::PHOSReconstruction @@ -87,14 +87,14 @@ o2_add_test(cpv SOURCES test/test_ctf_io_cpv.cxx COMPONENT_NAME ctf LABELS ctf) - + o2_add_test(zdc PUBLIC_LINK_LIBRARIES O2::DataFormatsZDC O2::ZDCReconstruction SOURCES test/test_ctf_io_zdc.cxx COMPONENT_NAME ctf LABELS ctf) - + o2_add_test(trd PUBLIC_LINK_LIBRARIES O2::CTFWorkflow O2::DataFormatsTRD @@ -102,7 +102,7 @@ o2_add_test(trd SOURCES test/test_ctf_io_trd.cxx COMPONENT_NAME ctf LABELS ctf) - + o2_add_test(hmpid PUBLIC_LINK_LIBRARIES O2::CTFWorkflow O2::DataFormatsHMP @@ -110,3 +110,11 @@ o2_add_test(hmpid SOURCES test/test_ctf_io_hmpid.cxx COMPONENT_NAME ctf LABELS ctf) + +o2_add_test(ctp + PUBLIC_LINK_LIBRARIES O2::CTPWorkflow + O2::DataFormatsCTP + O2::CTPReconstruction + SOURCES test/test_ctf_io_ctp.cxx + COMPONENT_NAME ctf + LABELS ctf) diff --git a/Detectors/CTF/test/test_ctf_io_ctp.cxx b/Detectors/CTF/test/test_ctf_io_ctp.cxx new file mode 100644 index 0000000000000..3a8a7adc90745 --- /dev/null +++ b/Detectors/CTF/test/test_ctf_io_ctp.cxx @@ -0,0 +1,96 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// 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. + +#define BOOST_TEST_MODULE Test CTPCTFIO +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK +#include +#include "DetectorsCommonDataFormats/NameConf.h" +#include "CTPReconstruction/CTFCoder.h" +#include "DataFormatsCTP/CTF.h" +#include "DataFormatsCTP/Digits.h" +#include "Framework/Logger.h" +#include +#include +#include +#include +#include + +using namespace o2::ctp; + +BOOST_AUTO_TEST_CASE(CTFTest, *boost::unit_test::enabled()) +{ + std::vector digits; + TStopwatch sw; + sw.Start(); + o2::InteractionRecord ir0(3, 5), ir(ir0); + + std::random_device rd; + std::mt19937_64 eng(rd()); + std::uniform_int_distribution distr; + + for (int itrg = 0; itrg < 1000; itrg++) { + ir += 1 + distr(eng) % 200; + auto& dig = digits.emplace_back(); + dig.intRecord = ir; + dig.CTPInputMask |= distr(eng); + dig.CTPClassMask |= distr(eng); + } + + sw.Start(); + std::vector vec; + { + CTFCoder coder; + coder.encode(vec, digits); // compress + } + sw.Stop(); + LOG(INFO) << "Compressed in " << sw.CpuTime() << " s"; + + // writing + { + sw.Start(); + auto* ctfImage = o2::ctp::CTF::get(vec.data()); + TFile flOut("test_ctf_ctp.root", "recreate"); + TTree ctfTree(std::string(o2::base::NameConf::CTFTREENAME).c_str(), "O2 CTF tree"); + ctfImage->print(); + ctfImage->appendToTree(ctfTree, "CTP"); + ctfTree.Write(); + sw.Stop(); + LOG(INFO) << "Wrote to tree in " << sw.CpuTime() << " s"; + } + + // reading + vec.clear(); + { + sw.Start(); + TFile flIn("test_ctf_ctp.root"); + std::unique_ptr tree((TTree*)flIn.Get(std::string(o2::base::NameConf::CTFTREENAME).c_str())); + BOOST_CHECK(tree); + o2::ctp::CTF::readFromTree(vec, *(tree.get()), "CTP"); + sw.Stop(); + LOG(INFO) << "Read back from tree in " << sw.CpuTime() << " s"; + } + + std::vector digitsD; + + sw.Start(); + const auto ctfImage = o2::ctp::CTF::getImage(vec.data()); + { + CTFCoder coder; + coder.decode(ctfImage, digitsD); // decompress + } + sw.Stop(); + LOG(INFO) << "Decompressed in " << sw.CpuTime() << " s"; + + LOG(INFO) << " BOOST_CHECK(digitsD.size() " << digitsD.size() << " digigits.size()) " << digits.size(); + + BOOST_TEST(digits == digitsD, boost::test_tools::per_element()); +} diff --git a/Detectors/CTF/workflow/CMakeLists.txt b/Detectors/CTF/workflow/CMakeLists.txt index 0462350a3ee21..2b52c9f7dd2c5 100644 --- a/Detectors/CTF/workflow/CMakeLists.txt +++ b/Detectors/CTF/workflow/CMakeLists.txt @@ -26,6 +26,7 @@ o2_add_library(CTFWorkflow O2::DataFormatsCPV O2::DataFormatsZDC O2::DataFormatsHMP + O2::DataFormatsCTP O2::DataFormatsParameters O2::ITSMFTWorkflow O2::TPCWorkflow @@ -40,6 +41,7 @@ o2_add_library(CTFWorkflow O2::CPVWorkflow O2::ZDCWorkflow O2::HMPIDWorkflow + O2::CTPWorkflow O2::Algorithm O2::CommonUtils) diff --git a/Detectors/CTF/workflow/src/CTFReaderSpec.cxx b/Detectors/CTF/workflow/src/CTFReaderSpec.cxx index afe033bc2db22..85220dd37ffee 100644 --- a/Detectors/CTF/workflow/src/CTFReaderSpec.cxx +++ b/Detectors/CTF/workflow/src/CTFReaderSpec.cxx @@ -39,6 +39,7 @@ #include "DataFormatsCPV/CTF.h" #include "DataFormatsZDC/CTF.h" #include "DataFormatsHMP/CTF.h" +#include "DataFormatsCTP/CTF.h" #include "Algorithm/RangeTokenizer.h" #include @@ -312,6 +313,14 @@ void CTFReaderSpec::processTF(ProcessingContext& pc) o2::hmpid::CTF::readFromTree(bufVec, *(mCTFTree.get()), det.getName(), mCurrTreeEntry); setFirstTFOrbit(det.getName()); } + + det = DetID::CTP; + if (detsTF[det]) { + auto& bufVec = pc.outputs().make>({det.getName()}, sizeof(o2::ctp::CTF)); + o2::ctp::CTF::readFromTree(bufVec, *(mCTFTree.get()), det.getName(), mCurrTreeEntry); + setFirstTFOrbit(det.getName()); + } + auto entryStr = fmt::format("({} of {} in {})", mCurrTreeEntry, mCTFTree->GetEntries(), mCTFFile->GetName()); if (++mCurrTreeEntry >= mCTFTree->GetEntries()) { // this file is done, check if there are other files mCTFTree.reset(); diff --git a/Detectors/CTF/workflow/src/CTFWriterSpec.cxx b/Detectors/CTF/workflow/src/CTFWriterSpec.cxx index 47e97bc4cc83c..53cd1afc0d18b 100644 --- a/Detectors/CTF/workflow/src/CTFWriterSpec.cxx +++ b/Detectors/CTF/workflow/src/CTFWriterSpec.cxx @@ -39,6 +39,7 @@ #include "DataFormatsPHOS/CTF.h" #include "DataFormatsCPV/CTF.h" #include "DataFormatsZDC/CTF.h" +#include "DataFormatsCTP/CTF.h" #include "rANS/rans.h" #include #include @@ -368,6 +369,7 @@ void CTFWriterSpec::run(ProcessingContext& pc) szCTF += processDet(pc, DetID::CPV, header, mCTFTreeOut.get()); szCTF += processDet(pc, DetID::ZDC, header, mCTFTreeOut.get()); szCTF += processDet(pc, DetID::HMP, header, mCTFTreeOut.get()); + szCTF += processDet(pc, DetID::CTP, header, mCTFTreeOut.get()); mTimer.Stop(); @@ -548,6 +550,7 @@ void CTFWriterSpec::storeDictionaries() storeDictionary(DetID::CPV, header); storeDictionary(DetID::ZDC, header); storeDictionary(DetID::HMP, header); + storeDictionary(DetID::CTP, header); // close remnants if (mDictTreeOut) { diff --git a/Detectors/CTF/workflow/src/ctf-reader-workflow.cxx b/Detectors/CTF/workflow/src/ctf-reader-workflow.cxx index b7e690e821614..59bc7fe6de1f5 100644 --- a/Detectors/CTF/workflow/src/ctf-reader-workflow.cxx +++ b/Detectors/CTF/workflow/src/ctf-reader-workflow.cxx @@ -36,6 +36,7 @@ #include "PHOSWorkflow/EntropyDecoderSpec.h" #include "CPVWorkflow/EntropyDecoderSpec.h" #include "ZDCWorkflow/EntropyDecoderSpec.h" +#include "CTPWorkflow/EntropyDecoderSpec.h" using namespace o2::framework; using DetID = o2::detectors::DetID; @@ -153,6 +154,9 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) if (ctfInput.detMask[DetID::HMP]) { specs.push_back(o2::hmpid::getEntropyDecoderSpec()); } + if (ctfInput.detMask[DetID::CTP]) { + specs.push_back(o2::ctp::getEntropyDecoderSpec()); + } return std::move(specs); } diff --git a/Detectors/CTP/CMakeLists.txt b/Detectors/CTP/CMakeLists.txt index 6345c1c44c88f..1ef8d5ecf3b92 100644 --- a/Detectors/CTP/CMakeLists.txt +++ b/Detectors/CTP/CMakeLists.txt @@ -10,6 +10,7 @@ # or submit itself to any jurisdiction. add_subdirectory(simulation) +add_subdirectory(reconstruction) add_subdirectory(workflow) add_subdirectory(workflowIO) add_subdirectory(macro) diff --git a/Detectors/CTP/reconstruction/CMakeLists.txt b/Detectors/CTP/reconstruction/CMakeLists.txt new file mode 100644 index 0000000000000..e407a102a48ee --- /dev/null +++ b/Detectors/CTP/reconstruction/CMakeLists.txt @@ -0,0 +1,20 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# 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. + +o2_add_library(CTPReconstruction + SOURCES src/CTFCoder.cxx src/CTFHelper.cxx + PUBLIC_LINK_LIBRARIES O2::DataFormatsCTP + O2::DetectorsBase + O2::CommonDataFormat + O2::DetectorsCommonDataFormats + O2::rANS + Microsoft.GSL::GSL) + diff --git a/Detectors/CTP/reconstruction/include/CTPReconstruction/CTFCoder.h b/Detectors/CTP/reconstruction/include/CTPReconstruction/CTFCoder.h new file mode 100644 index 0000000000000..64323fef315e6 --- /dev/null +++ b/Detectors/CTP/reconstruction/include/CTPReconstruction/CTFCoder.h @@ -0,0 +1,146 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// 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 CTFCoder.h +/// \author ruben.shahoyan@cern.ch +/// \brief class for entropy encoding/decoding of CTP data + +#ifndef O2_CTP_CTFCODER_H +#define O2_CTP_CTFCODER_H + +#include +#include +#include +#include +#include "DataFormatsCTP/CTF.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "DetectorsBase/CTFCoderBase.h" +#include "rANS/rans.h" +#include "CTPReconstruction/CTFHelper.h" + +class TTree; + +namespace o2 +{ +namespace ctp +{ + +class CTFCoder : public o2::ctf::CTFCoderBase +{ + public: + CTFCoder() : o2::ctf::CTFCoderBase(CTF::getNBlocks(), o2::detectors::DetID::CTP) {} + ~CTFCoder() = default; + + /// entropy-encode data to buffer with CTF + template + void encode(VEC& buff, const gsl::span& data); + + /// entropy decode data from buffer with CTF + template + void decode(const CTF::base& ec, VTRG& data); + + void createCoders(const std::string& dictPath, o2::ctf::CTFCoderBase::OpType op); + + private: + void appendToTree(TTree& tree, CTF& ec); + void readFromTree(TTree& tree, int entry, std::vector& data); +}; + +/// entropy-encode clusters to buffer with CTF +template +void CTFCoder::encode(VEC& buff, const gsl::span& data) +{ + using MD = o2::ctf::Metadata::OptStore; + // what to do which each field: see o2::ctd::Metadata explanation + constexpr MD optField[CTF::getNBlocks()] = { + MD::EENCODE, // BLC_bcIncTrig + MD::EENCODE, // BLC_orbitIncTrig + MD::EENCODE, // BLC_bytesInput + MD::EENCODE, // BLC_bytesClass + }; + + CTFHelper helper(data); + + // book output size with some margin + auto szIni = sizeof(CTFHeader) + helper.getSize() * 2. / 3; // will be autoexpanded if needed + buff.resize(szIni); + + auto ec = CTF::create(buff); + using ECB = CTF::base; + + ec->setHeader(helper.createHeader()); + assignDictVersion(static_cast(ec->getHeader())); + ec->getANSHeader().majorVersion = 0; + ec->getANSHeader().minorVersion = 1; + // at every encoding the buffer might be autoexpanded, so we don't work with fixed pointer ec +#define ENCODECTP(beg, end, slot, bits) CTF::get(buff.data())->encode(beg, end, int(slot), bits, optField[int(slot)], &buff, mCoders[int(slot)].get()); + // clang-format off + ENCODECTP(helper.begin_bcIncTrig(), helper.end_bcIncTrig(), CTF::BLC_bcIncTrig, 0); + ENCODECTP(helper.begin_orbitIncTrig(), helper.end_orbitIncTrig(), CTF::BLC_orbitIncTrig, 0); + + ENCODECTP(helper.begin_bytesInput(), helper.end_bytesInput(), CTF::BLC_bytesInput, 0); + ENCODECTP(helper.begin_bytesClass(), helper.end_bytesClass(), CTF::BLC_bytesClass, 0); + + // clang-format on + CTF::get(buff.data())->print(getPrefix()); +} + +/// decode entropy-encoded digits +template +void CTFCoder::decode(const CTF::base& ec, VTRG& data) +{ + auto header = ec.getHeader(); + checkDictVersion(static_cast(header)); + ec.print(getPrefix()); + std::vector bcInc; + std::vector orbitInc; + std::vector bytesInput, bytesClass; + +#define DECODECTP(part, slot) ec.decode(part, int(slot), mCoders[int(slot)].get()) + // clang-format off + DECODECTP(bcInc, CTF::BLC_bcIncTrig); + DECODECTP(orbitInc, CTF::BLC_orbitIncTrig); + DECODECTP(bytesInput, CTF::BLC_bytesInput); + DECODECTP(bytesClass, CTF::BLC_bytesClass); + // clang-format on + // + data.clear(); + + uint32_t firstEntry = 0, digCount = 0; + o2::InteractionRecord ir(header.firstBC, header.firstOrbit); + auto itInp = bytesInput.begin(); + auto itCls = bytesClass.begin(); + + for (uint32_t itrig = 0; itrig < header.nTriggers; itrig++) { + // restore TrigRecord + if (orbitInc[itrig]) { // non-0 increment => new orbit + ir.bc = bcInc[itrig]; // bcInc has absolute meaning + ir.orbit += orbitInc[itrig]; + } else { + ir.bc += bcInc[itrig]; + } + auto& dig = data.emplace_back(); + dig.intRecord = ir; + for (int i = 0; i < CTFHelper::CTPInpNBytes; i++) { + dig.CTPInputMask |= static_cast(*itInp++) << (8 * i); + } + for (int i = 0; i < CTFHelper::CTPClsNBytes; i++) { + dig.CTPClassMask |= static_cast(*itCls++) << (8 * i); + } + } + assert(itInp == bytesInput.end()); + assert(itCls == bytesClass.end()); +} + +} // namespace ctp +} // namespace o2 + +#endif // O2_CTP_CTFCODER_H diff --git a/Detectors/CTP/reconstruction/include/CTPReconstruction/CTFHelper.h b/Detectors/CTP/reconstruction/include/CTPReconstruction/CTFHelper.h new file mode 100644 index 0000000000000..ce7615cbe7bb0 --- /dev/null +++ b/Detectors/CTP/reconstruction/include/CTPReconstruction/CTFHelper.h @@ -0,0 +1,170 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// 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 CTFHelper.h +/// \author ruben.shahoyan@cern.ch +/// \brief Helper for CTP CTF creation + +#ifndef O2_CTP_CTF_HELPER_H +#define O2_CTP_CTF_HELPER_H + +#include "DataFormatsCTP/CTF.h" +#include "DataFormatsCTP/Digits.h" +#include + +namespace o2 +{ +namespace ctp +{ + +class CTFHelper +{ + + public: + CTFHelper(const gsl::span& data) + : mData(data) {} + + static constexpr int CTPInpNBytes = CTP_NINPUTS / 8 + (CTP_NINPUTS % 8 > 0); + static constexpr int CTPClsNBytes = CTP_NCLASSES / 8 + (CTP_NCLASSES % 8 > 0); + + CTFHeader createHeader() + { + CTFHeader h{0, 1, 0, // dummy timestamp, version 1.0 + uint32_t(mData.size()), 0, 0}; + if (mData.size()) { + h.firstOrbit = mData[0].intRecord.orbit; + h.firstBC = mData[0].intRecord.bc; + } + return h; + } + + size_t getSize() const { return mData.size() * sizeof(CTPDigit); } + + //>>> =========================== ITERATORS ======================================== + + template + class _Iter + { + public: + using difference_type = int64_t; + using value_type = T; + using pointer = const T*; + using reference = const T&; + using iterator_category = std::random_access_iterator_tag; + + _Iter(const gsl::span& data, bool end = false) : mData(data), mIndex(end ? M * data.size() : 0){}; + _Iter() = default; + + const I& operator++() + { + ++mIndex; + return (I&)(*this); + } + + const I& operator--() + { + mIndex--; + return (I&)(*this); + } + + difference_type operator-(const I& other) const { return mIndex - other.mIndex; } + + difference_type operator-(size_t idx) const { return mIndex - idx; } + + const I& operator-(size_t idx) + { + mIndex -= idx; + return (I&)(*this); + } + + bool operator!=(const I& other) const { return mIndex != other.mIndex; } + bool operator==(const I& other) const { return mIndex == other.mIndex; } + bool operator>(const I& other) const { return mIndex > other.mIndex; } + bool operator<(const I& other) const { return mIndex < other.mIndex; } + + protected: + gsl::span mData{}; + size_t mIndex = 0; + }; + + //_______________________________________________ + // BC difference wrt previous if in the same orbit, otherwise the abs.value. + // For the very 1st entry return 0 (diff wrt 1st BC in the CTF header) + class Iter_bcIncTrig : public _Iter + { + public: + using _Iter::_Iter; + value_type operator*() const + { + if (mIndex) { + if (mData[mIndex].intRecord.orbit == mData[mIndex - 1].intRecord.orbit) { + return mData[mIndex].intRecord.bc - mData[mIndex - 1].intRecord.bc; + } else { + return mData[mIndex].intRecord.bc; + } + } + return 0; + } + }; + + //_______________________________________________ + // Orbit difference wrt previous. For the very 1st entry return 0 (diff wrt 1st BC in the CTF header) + class Iter_orbitIncTrig : public _Iter + { + public: + using _Iter::_Iter; + value_type operator*() const { return mIndex ? mData[mIndex].intRecord.orbit - mData[mIndex - 1].intRecord.orbit : 0; } + }; + + //_______________________________________________ + class Iter_bytesInput : public _Iter + { + public: + using _Iter::_Iter; + value_type operator*() const + { + return static_cast(((mData[mIndex / CTPInpNBytes].CTPInputMask.to_ullong()) >> (8 * (mIndex % CTPInpNBytes))) & 0xff); + } + }; + + //_______________________________________________ + class Iter_bytesClass : public _Iter + { + public: + using _Iter::_Iter; + value_type operator*() const + { + return static_cast(((mData[mIndex / CTPClsNBytes].CTPClassMask.to_ullong()) >> (8 * (mIndex % CTPClsNBytes))) & 0xff); + } + }; + + //<<< =========================== ITERATORS ======================================== + + Iter_bcIncTrig begin_bcIncTrig() const { return Iter_bcIncTrig(mData, false); } + Iter_bcIncTrig end_bcIncTrig() const { return Iter_bcIncTrig(mData, true); } + + Iter_orbitIncTrig begin_orbitIncTrig() const { return Iter_orbitIncTrig(mData, false); } + Iter_orbitIncTrig end_orbitIncTrig() const { return Iter_orbitIncTrig(mData, true); } + + Iter_bytesInput begin_bytesInput() const { return Iter_bytesInput(mData, false); } + Iter_bytesInput end_bytesInput() const { return Iter_bytesInput(mData, true); } + + Iter_bytesClass begin_bytesClass() const { return Iter_bytesClass(mData, false); } + Iter_bytesClass end_bytesClass() const { return Iter_bytesClass(mData, true); } + + private: + const gsl::span mData; +}; + +} // namespace ctp +} // namespace o2 + +#endif diff --git a/Detectors/CTP/reconstruction/src/CTFCoder.cxx b/Detectors/CTP/reconstruction/src/CTFCoder.cxx new file mode 100644 index 0000000000000..23a138e34b320 --- /dev/null +++ b/Detectors/CTP/reconstruction/src/CTFCoder.cxx @@ -0,0 +1,74 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// 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 CTFCoder.cxx +/// \author ruben.shahoyan@cern.ch +/// \brief class for entropy encoding/decoding of CTP data + +#include "CTPReconstruction/CTFCoder.h" +#include "CommonUtils/StringUtils.h" +#include + +using namespace o2::ctp; + +///___________________________________________________________________________________ +// Register encoded data in the tree (Fill is not called, will be done by caller) +void CTFCoder::appendToTree(TTree& tree, CTF& ec) +{ + ec.appendToTree(tree, mDet.getName()); +} + +///___________________________________________________________________________________ +// extract and decode data from the tree +void CTFCoder::readFromTree(TTree& tree, int entry, std::vector& data) +{ + assert(entry >= 0 && entry < tree.GetEntries()); + CTF ec; + ec.readFromTree(tree, mDet.getName(), entry); + decode(ec, data); +} + +///________________________________ +void CTFCoder::createCoders(const std::string& dictPath, o2::ctf::CTFCoderBase::OpType op) +{ + bool mayFail = true; // RS FIXME if the dictionary file is not there, do not produce exception + auto buff = readDictionaryFromFile(dictPath, mayFail); + if (!buff.size()) { + if (mayFail) { + return; + } + throw std::runtime_error("Failed to create CTF dictionaty"); + } + const auto* ctf = CTF::get(buff.data()); + + auto getFreq = [ctf](CTF::Slots slot) -> o2::rans::FrequencyTable { + o2::rans::FrequencyTable ft; + auto bl = ctf->getBlock(slot); + auto md = ctf->getMetadata(slot); + ft.addFrequencies(bl.getDict(), bl.getDict() + bl.getNDict(), md.min, md.max); + return std::move(ft); + }; + auto getProbBits = [ctf](CTF::Slots slot) -> int { + return ctf->getMetadata(slot).probabilityBits; + }; + + // just to get types + uint16_t bcInc = 0; + uint32_t orbitInc = 0; + uint8_t bytesInput = 0, bytesClass = 0; +#define MAKECODER(part, slot) createCoder(op, getFreq(slot), getProbBits(slot), int(slot)) + // clang-format off + MAKECODER(bcInc, CTF::BLC_bcIncTrig); + MAKECODER(orbitInc, CTF::BLC_orbitIncTrig); + MAKECODER(bytesInput, CTF::BLC_bytesInput); + MAKECODER(bytesClass, CTF::BLC_bytesClass); + // clang-format on +} diff --git a/Detectors/CTP/reconstruction/src/CTFHelper.cxx b/Detectors/CTP/reconstruction/src/CTFHelper.cxx new file mode 100644 index 0000000000000..548eb5251f869 --- /dev/null +++ b/Detectors/CTP/reconstruction/src/CTFHelper.cxx @@ -0,0 +1,16 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// 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 CTFHelper.cxx +/// \author ruben.shahoyan@cern.ch +/// \brief Helper for CTP CTF creation + +#include "CTPReconstruction/CTFHelper.h" diff --git a/Detectors/CTP/workflow/CMakeLists.txt b/Detectors/CTP/workflow/CMakeLists.txt index afbf17ce77f8d..69aef2902e1e4 100644 --- a/Detectors/CTP/workflow/CMakeLists.txt +++ b/Detectors/CTP/workflow/CMakeLists.txt @@ -12,14 +12,22 @@ o2_add_library(CTPWorkflow SOURCES src/RecoWorkflow.cxx src/RawToDigitConverterSpec.cxx + src/EntropyEncoderSpec.cxx + src/EntropyDecoderSpec.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::DataFormatsCTP O2::DPLUtils O2::DetectorsRaw O2::Algorithm + O2::CTPReconstruction O2::CTPWorkflowIO) o2_add_executable(reco-workflow COMPONENT_NAME ctp SOURCES src/ctp-reco-workflow.cxx PUBLIC_LINK_LIBRARIES O2::Algorithm O2::CTPWorkflow) + +o2_add_executable(entropy-encoder-workflow + COMPONENT_NAME ctp + SOURCES src/entropy-encoder-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::CTPWorkflow) \ No newline at end of file diff --git a/Detectors/CTP/workflow/include/CTPWorkflow/EntropyDecoderSpec.h b/Detectors/CTP/workflow/include/CTPWorkflow/EntropyDecoderSpec.h new file mode 100644 index 0000000000000..4a5618e1a90cc --- /dev/null +++ b/Detectors/CTP/workflow/include/CTPWorkflow/EntropyDecoderSpec.h @@ -0,0 +1,48 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// 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 EntropyDecoderSpec.h +/// @brief Convert CTF (EncodedBlocks) to CTP digit stream + +#ifndef O2_CTP_ENTROPYDECODER_SPEC +#define O2_CTP_ENTROPYDECODER_SPEC + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "CTPReconstruction/CTFCoder.h" +#include + +namespace o2 +{ +namespace ctp +{ + +class EntropyDecoderSpec : public o2::framework::Task +{ + public: + EntropyDecoderSpec(); + ~EntropyDecoderSpec() override = default; + void run(o2::framework::ProcessingContext& pc) final; + void init(o2::framework::InitContext& ic) final; + void endOfStream(o2::framework::EndOfStreamContext& ec) final; + + private: + o2::ctp::CTFCoder mCTFCoder; + TStopwatch mTimer; +}; + +/// create a processor spec +framework::DataProcessorSpec getEntropyDecoderSpec(); + +} // namespace ctp +} // namespace o2 + +#endif diff --git a/Detectors/CTP/workflow/include/CTPWorkflow/EntropyEncoderSpec.h b/Detectors/CTP/workflow/include/CTPWorkflow/EntropyEncoderSpec.h new file mode 100644 index 0000000000000..cbc43822f6cff --- /dev/null +++ b/Detectors/CTP/workflow/include/CTPWorkflow/EntropyEncoderSpec.h @@ -0,0 +1,48 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// 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 EntropyEncoderSpec.h +/// @brief Convert CTP data to CTF (EncodedBlocks) + +#ifndef O2_CTP_ENTROPYENCODER_SPEC +#define O2_CTP_ENTROPYENCODER_SPEC + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include +#include "CTPReconstruction/CTFCoder.h" + +namespace o2 +{ +namespace ctp +{ + +class EntropyEncoderSpec : public o2::framework::Task +{ + public: + EntropyEncoderSpec(); + ~EntropyEncoderSpec() override = default; + void run(o2::framework::ProcessingContext& pc) final; + void init(o2::framework::InitContext& ic) final; + void endOfStream(o2::framework::EndOfStreamContext& ec) final; + + private: + o2::ctp::CTFCoder mCTFCoder; + TStopwatch mTimer; +}; + +/// create a processor spec +framework::DataProcessorSpec getEntropyEncoderSpec(); + +} // namespace ctp +} // namespace o2 + +#endif diff --git a/Detectors/CTP/workflow/src/EntropyDecoderSpec.cxx b/Detectors/CTP/workflow/src/EntropyDecoderSpec.cxx new file mode 100644 index 0000000000000..ef0ffb9e24d48 --- /dev/null +++ b/Detectors/CTP/workflow/src/EntropyDecoderSpec.cxx @@ -0,0 +1,77 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// 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 EntropyDecoderSpec.cxx + +#include + +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "CTPWorkflow/EntropyDecoderSpec.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace ctp +{ + +EntropyDecoderSpec::EntropyDecoderSpec() +{ + mTimer.Stop(); + mTimer.Reset(); +} + +void EntropyDecoderSpec::init(o2::framework::InitContext& ic) +{ + std::string dictPath = ic.options().get("ctf-dict"); + if (!dictPath.empty() && dictPath != "none") { + mCTFCoder.createCoders(dictPath, o2::ctf::CTFCoderBase::OpType::Decoder); + } +} + +void EntropyDecoderSpec::run(ProcessingContext& pc) +{ + auto cput = mTimer.CpuTime(); + mTimer.Start(false); + + auto buff = pc.inputs().get>("ctf"); + + auto& digits = pc.outputs().make>(OutputRef{"digits"}); + + // since the buff is const, we cannot use EncodedBlocks::relocate directly, instead we wrap its data to another flat object + const auto ctfImage = o2::ctp::CTF::getImage(buff.data()); + mCTFCoder.decode(ctfImage, digits); + + mTimer.Stop(); + LOG(INFO) << "Decoded " << digits.size() << " CTP digits in " << mTimer.CpuTime() - cput << " s"; +} + +void EntropyDecoderSpec::endOfStream(EndOfStreamContext& ec) +{ + LOGF(INFO, "CTP Entropy Decoding total timing: Cpu: %.3e Real: %.3e s in %d slots", + mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); +} + +DataProcessorSpec getEntropyDecoderSpec() +{ + std::vector outputs{OutputSpec{{"digits"}, "CTP", "DIGITS", 0, Lifetime::Timeframe}}; + + return DataProcessorSpec{ + "ctp-entropy-decoder", + Inputs{InputSpec{"ctf", "CTP", "CTFDATA", 0, Lifetime::Timeframe}}, + outputs, + AlgorithmSpec{adaptFromTask()}, + Options{{"ctf-dict", VariantType::String, o2::base::NameConf::getCTFDictFileName(), {"File of CTF decoding dictionary"}}}}; +} + +} // namespace ctp +} // namespace o2 diff --git a/Detectors/CTP/workflow/src/EntropyEncoderSpec.cxx b/Detectors/CTP/workflow/src/EntropyEncoderSpec.cxx new file mode 100644 index 0000000000000..d631a3a64f257 --- /dev/null +++ b/Detectors/CTP/workflow/src/EntropyEncoderSpec.cxx @@ -0,0 +1,78 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// 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 EntropyEncoderSpec.cxx + +#include + +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "CTPWorkflow/EntropyEncoderSpec.h" +#include "DetectorsCommonDataFormats/DetID.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace ctp +{ + +EntropyEncoderSpec::EntropyEncoderSpec() +{ + mTimer.Stop(); + mTimer.Reset(); +} + +void EntropyEncoderSpec::init(o2::framework::InitContext& ic) +{ + std::string dictPath = ic.options().get("ctf-dict"); + if (!dictPath.empty() && dictPath != "none") { + mCTFCoder.createCoders(dictPath, o2::ctf::CTFCoderBase::OpType::Encoder); + } +} + +void EntropyEncoderSpec::run(ProcessingContext& pc) +{ + auto cput = mTimer.CpuTime(); + mTimer.Start(false); + auto digits = pc.inputs().get>("digits"); + + auto& buffer = pc.outputs().make>(Output{"CTP", "CTFDATA", 0, Lifetime::Timeframe}); + mCTFCoder.encode(buffer, digits); + auto eeb = CTF::get(buffer.data()); // cast to container pointer + eeb->compactify(); // eliminate unnecessary padding + buffer.resize(eeb->size()); // shrink buffer to strictly necessary size + // eeb->print(); + mTimer.Stop(); + LOG(INFO) << "Created encoded data of size " << eeb->size() << " for CTP in " << mTimer.CpuTime() - cput << " s"; +} + +void EntropyEncoderSpec::endOfStream(EndOfStreamContext& ec) +{ + LOGF(INFO, "CTP Entropy Encoding total timing: Cpu: %.3e Real: %.3e s in %d slots", + mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); +} + +DataProcessorSpec getEntropyEncoderSpec() +{ + std::vector inputs; + inputs.emplace_back("digits", "CTP", "DIGITS", 0, Lifetime::Timeframe); + + return DataProcessorSpec{ + "ctp-entropy-encoder", + inputs, + Outputs{{"CTP", "CTFDATA", 0, Lifetime::Timeframe}}, + AlgorithmSpec{adaptFromTask()}, + Options{{"ctf-dict", VariantType::String, o2::base::NameConf::getCTFDictFileName(), {"File of CTF encoding dictionary"}}}}; +} + +} // namespace ctp +} // namespace o2 diff --git a/Detectors/CTP/workflow/src/RawToDigitConverterSpec.cxx b/Detectors/CTP/workflow/src/RawToDigitConverterSpec.cxx index adbfb61cb2d7e..f8d6af766b1fb 100644 --- a/Detectors/CTP/workflow/src/RawToDigitConverterSpec.cxx +++ b/Detectors/CTP/workflow/src/RawToDigitConverterSpec.cxx @@ -74,7 +74,7 @@ void RawToDigitConverterSpec::run(framework::ProcessingContext& ctx) } else { LOG(ERROR) << "Unxpected CTP CRU link:" << linkCRU; } - LOG(INFO) << "RDH FEEid: " << feeID << " CTP CRU link:" << linkCRU << " Orbit:" << triggerOrbit; + LOG(DEBUG) << "RDH FEEid: " << feeID << " CTP CRU link:" << linkCRU << " Orbit:" << triggerOrbit; pldmask = 0; for (uint32_t i = 0; i < payloadCTP; i++) { pldmask[12 + i] = 1; @@ -125,11 +125,11 @@ void RawToDigitConverterSpec::run(framework::ProcessingContext& ctx) if (digits.count(ir) == 0) { digit.setInputMask(pld); digits[ir] = digit; - LOG(INFO) << bcid << " inputs case 0 bcid orbit " << triggerOrbit << " pld:" << pld; + LOG(DEBUG) << bcid << " inputs case 0 bcid orbit " << triggerOrbit << " pld:" << pld; } else if (digits.count(ir) == 1) { if (digits[ir].CTPInputMask.count() == 0) { digits[ir].setInputMask(pld); - LOG(INFO) << bcid << " inputs bcid vase 1 orbit " << triggerOrbit << " pld:" << pld; + LOG(DEBUG) << bcid << " inputs bcid vase 1 orbit " << triggerOrbit << " pld:" << pld; } else { LOG(ERROR) << "Two CTP IRs with the same timestamp."; } @@ -140,11 +140,11 @@ void RawToDigitConverterSpec::run(framework::ProcessingContext& ctx) if (digits.count(ir) == 0) { digit.setClassMask(pld); digits[ir] = digit; - LOG(INFO) << bcid << " class bcid case 0 orbit " << triggerOrbit << " pld:" << pld; + LOG(DEBUG) << bcid << " class bcid case 0 orbit " << triggerOrbit << " pld:" << pld; } else if (digits.count(ir) == 1) { if (digits[ir].CTPClassMask.count() == 0) { digits[ir].setClassMask(pld); - LOG(INFO) << bcid << " class bcid case 1 orbit " << triggerOrbit << " pld:" << pld; + LOG(DEBUG) << bcid << " class bcid case 1 orbit " << triggerOrbit << " pld:" << pld; } else { LOG(ERROR) << "Two CTP Class masks for same timestamp"; } diff --git a/Detectors/CTP/workflow/src/entropy-encoder-workflow.cxx b/Detectors/CTP/workflow/src/entropy-encoder-workflow.cxx new file mode 100644 index 0000000000000..0d25c85462d2b --- /dev/null +++ b/Detectors/CTP/workflow/src/entropy-encoder-workflow.cxx @@ -0,0 +1,40 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// 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 "CTPWorkflow/EntropyEncoderSpec.h" +#include "CommonUtils/ConfigurableParam.h" +#include "Framework/ConfigParamSpec.h" + +using namespace o2::framework; + +// ------------------------------------------------------------------ + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector& workflowOptions) +{ + // option allowing to set parameters + std::vector options{ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}}; + + std::swap(workflowOptions, options); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec wf; + // Update the (declared) parameters if changed from the command line + o2::conf::ConfigurableParam::updateFromString(cfgc.options().get("configKeyValues")); + wf.emplace_back(o2::ctp::getEntropyEncoderSpec()); + return wf; +} diff --git a/prodtests/full-system-test/dpl-workflow.sh b/prodtests/full-system-test/dpl-workflow.sh index 2c84fd0a1053f..7e2a73a29c581 100755 --- a/prodtests/full-system-test/dpl-workflow.sh +++ b/prodtests/full-system-test/dpl-workflow.sh @@ -134,6 +134,7 @@ N_TPCITS=1 N_MFTMCH=1 N_ITSRAWDEC=1 N_MFTRAWDEC=1 +N_CTPRAWDEC=1 N_TPCRAWDEC=$NGPUS N_EMC=1 N_TRDENT=1 @@ -190,6 +191,7 @@ N_ITSRAWDEC=$((6 * 30 / $RECO_NUM_NODES_WORKFLOW_CMP > $N_ITSRAWDEC ? 6 * 30 / $ N_MFTRAWDEC=$((6 * 30 / $RECO_NUM_NODES_WORKFLOW_CMP > $N_MFTRAWDEC ? 6 * 30 / $RECO_NUM_NODES_WORKFLOW_CMP : $N_MFTRAWDEC)) N_ITSTRK=$((2 * 30 / $RECO_NUM_NODES_WORKFLOW_CMP > $N_ITSTRK ? 2 * 30 / $RECO_NUM_NODES_WORKFLOW_CMP : $N_ITSTRK)) N_MFTTRK=$((2 * 30 / $RECO_NUM_NODES_WORKFLOW_CMP > $N_MFTTRK ? 2 * 30 / $RECO_NUM_NODES_WORKFLOW_CMP : $N_MFTTRK)) +N_CTPRAWDEC=$((30 / $RECO_NUM_NODES_WORKFLOW_CMP > N_CTPRAWDEC ? 30 / $RECO_NUM_NODES_WORKFLOW_CMP : $N_CTPRAWDEC)) # Apply external multiplicity factors N_TPCTRK=$((N_TPCTRK * $N_F_REST)) N_TPCITS=$((N_TPCITS * $N_F_REST)) @@ -205,6 +207,7 @@ N_TRDENT=$((N_TRDENT * $N_F_CTF)) N_ITSRAWDEC=$((N_ITSRAWDEC * $N_F_RAW)) N_MFTRAWDEC=$((N_MFTRAWDEC * $N_F_RAW)) N_TPCRAWDEC=$((N_TPCRAWDEC * $N_F_RAW)) +N_CTPRAWDEC=$((N_CTPRAWDEC * $N_F_RAW)) # --------------------------------------------------------------------------------------------------------------------- # Input workflow @@ -251,6 +254,7 @@ if [ $CTFINPUT == 0 ]; then has_detector TRD && WORKFLOW+="o2-trd-datareader $ARGS_ALL --pipeline trd-datareader:$N_F_RAW | " has_detector ZDC && WORKFLOW+="o2-zdc-raw2digits $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG\" --disable-root-output --pipeline zdc-datareader-dpl:$N_F_RAW | " has_detector HMP && WORKFLOW+="o2-hmpid-raw-to-digits-stream-workflow $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG\" --pipeline HMP-RawStreamDecoder:$N_F_RAW | " + has_detector CTP && WORKFLOW+="o2-ctp-reco-workflow $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG\" --disable-root-output --pipeline CTP-RawStreamDecoder:$N_CTPRAWDEC | " fi # --------------------------------------------------------------------------------------------------------------------- @@ -305,6 +309,7 @@ if [ $CTFINPUT == 0 ]; then has_detector ITS && WORKFLOW+="o2-itsmft-entropy-encoder-workflow $ARGS_ALL --ctf-dict \"${CTF_DICT}\" --configKeyValues \"$ARGS_ALL_CONFIG\" --pipeline its-entropy-encoder:$N_F_CTF| " has_detector TRD && WORKFLOW+="o2-trd-entropy-encoder-workflow $ARGS_ALL --ctf-dict \"${CTF_DICT}\" --configKeyValues \"$ARGS_ALL_CONFIG\" --pipeline trd-entropy-encoder:$N_TRDENT | " has_detector TPC && WORKFLOW+="o2-tpc-reco-workflow $ARGS_ALL --ctf-dict \"${CTF_DICT}\" --configKeyValues \"$ARGS_ALL_CONFIG\" --input-type compressed-clusters-flat --output-type encoded-clusters,disable-writer --pipeline tpc-entropy-encoder:$N_TPCENT | " + has_detector CTP && WORKFLOW+="o2-ctp-entropy-encoder-workflow $ARGS_ALL --ctf-dict \"${CTF_DICT}\" --configKeyValues \"$ARGS_ALL_CONFIG\" --pipeline its-entropy-encoder:$N_F_CTF| " # Calibration workflows has_detector_calib TPC && has_detectors TPC ITS TRD TOF && WORKFLOW+="o2-tpc-scdcalib-interpolation-workflow $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG\" --disable-root-output --disable-root-input --pipeline tpc-track-interpolation:$N_F_REST | " diff --git a/prodtests/full_system_test.sh b/prodtests/full_system_test.sh index 1b4ce78c167af..4668849be51b4 100755 --- a/prodtests/full_system_test.sh +++ b/prodtests/full_system_test.sh @@ -118,6 +118,8 @@ taskwrapper cpvraw.log o2-cpv-digi2raw --file-for link -o raw/CPV taskwrapper zdcraw.log o2-zdc-digi2raw --file-for link -o raw/ZDC taskwrapper hmpraw.log o2-hmpid-digits-to-raw-workflow --file-for link --outdir raw/HMP taskwrapper trdraw.log o2-trd-trap2raw -o raw/TRD --fileper halfcru +taskwrapper ctpraw.log o2-ctp-digi2raw -o raw/CTP --file-per-link + cat raw/*/*.cfg > rawAll.cfg if [ "0$DISABLE_PROCESSING" == "01" ]; then