diff --git a/Modules/CMakeLists.txt b/Modules/CMakeLists.txt index 47779d0f27..431cf3b574 100644 --- a/Modules/CMakeLists.txt +++ b/Modules/CMakeLists.txt @@ -19,3 +19,4 @@ add_subdirectory(CPV) add_subdirectory(GLO) add_subdirectory(FV0) add_subdirectory(FDD) +add_subdirectory(CTP) diff --git a/Modules/CTP/CMakeLists.txt b/Modules/CTP/CMakeLists.txt new file mode 100644 index 0000000000..d9875a106b --- /dev/null +++ b/Modules/CTP/CMakeLists.txt @@ -0,0 +1,42 @@ +# ---- Library ---- + +add_library(O2QcCTP) + +target_sources(O2QcCTP PRIVATE src/RawDataQcTask.cxx ) + +target_include_directories( + O2QcCTP + PUBLIC $ + $ + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src) + +target_link_libraries(O2QcCTP PUBLIC O2QualityControl) + +install(TARGETS O2QcCTP + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) + +add_root_dictionary(O2QcCTP + HEADERS +include/CTP/RawDataQcTask.h + LINKDEF include/CTP/LinkDef.h + BASENAME O2QcCTP) + +# ---- Test(s) ---- + +set(TEST_SRCS test/testQcCTP.cxx) + +foreach(test ${TEST_SRCS}) + get_filename_component(test_name ${test} NAME) + string(REGEX REPLACE ".cxx" "" test_name ${test_name}) + + add_executable(${test_name} ${test}) + target_link_libraries(${test_name} + PRIVATE O2QcCTP Boost::unit_test_framework) + add_test(NAME ${test_name} COMMAND ${test_name}) + set_property(TARGET ${test_name} + PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/tests) + set_tests_properties(${test_name} PROPERTIES TIMEOUT 20) +endforeach() + diff --git a/Modules/CTP/basic-ctp.json b/Modules/CTP/basic-ctp.json new file mode 100644 index 0000000000..a6edc4872c --- /dev/null +++ b/Modules/CTP/basic-ctp.json @@ -0,0 +1,61 @@ +{ + "qc": { + "config": { + "database": { + "implementation": "CCDB", + "host": "ccdb-test.cern.ch:8080", + "username": "not_applicable", + "password": "not_applicable", + "name": "not_applicable" + }, + "Activity": { + "number": "42", + "type": "2" + }, + "monitoring": { + "url": "infologger:///debug?qc" + }, + "consul": { + "url": "" + }, + "conditionDB": { + "url": "ccdb-test.cern.ch:8080" + } + }, + "tasks": { + "MyRawDataQcTask": { + "active": "true", + "className": "o2::quality_control_modules::ctp::CTPRawDataReaderTask", + "moduleName": "QcCTP", + "detectorName": "CTP", + "cycleDurationSeconds": "10", + "maxNumberCycles": "-1", + "": "The other type of dataSource is \"direct\", see basic-no-sampling.json.", + "dataSource": { + "type": "dataSamplingPolicy", + "name": "tst-raw" + }, + "taskParameters": { + "myOwnKey": "myOwnValue" + }, + "location": "remote" + } + }, + }, + "dataSamplingPolicies": [ + { + "id": "ctp-raw", + "active": "true", + "machines": [], + "query": "random:CTP/RAWDATA/0", + "samplingConditions": [ + { + "condition": "random", + "fraction": "0.1", + "seed": "1234" + } + ], + "blocking": "false" + } + ] +} diff --git a/Modules/CTP/include/CTP/LinkDef.h b/Modules/CTP/include/CTP/LinkDef.h new file mode 100644 index 0000000000..8ddfd850fe --- /dev/null +++ b/Modules/CTP/include/CTP/LinkDef.h @@ -0,0 +1,8 @@ +#ifdef __CLING__ +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class o2::quality_control_modules::ctp::CTPRawDataReaderTask + ; + +#endif diff --git a/Modules/CTP/include/CTP/RawDataQcTask.h b/Modules/CTP/include/CTP/RawDataQcTask.h new file mode 100644 index 0000000000..8b183ed05f --- /dev/null +++ b/Modules/CTP/include/CTP/RawDataQcTask.h @@ -0,0 +1,56 @@ +// 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 RawDataQcTask.h +/// \author Marek Bombara +/// + +#ifndef QC_MODULE_CTP_CTPRAWDATAQCTASK_H +#define QC_MODULE_CTP_CTPRAWDATAQCTASK_H + +#include "QualityControl/TaskInterface.h" + +class TH1F; + +using namespace o2::quality_control::core; + +namespace o2::quality_control_modules::ctp +{ + +/// \brief Example Quality Control DPL Task +/// \author My Name +class CTPRawDataReaderTask final : public TaskInterface +{ + public: + /// \brief Constructor + CTPRawDataReaderTask() = default; + /// Destructor + ~CTPRawDataReaderTask() override; + + // Definition of the methods for the template method pattern + void initialize(o2::framework::InitContext& ctx) override; + void startOfActivity(Activity& activity) override; + void startOfCycle() override; + void monitorData(o2::framework::ProcessingContext& ctx) override; + void endOfCycle() override; + void endOfActivity(Activity& activity) override; + void reset() override; + + private: + TH1F* mHistoBC = nullptr; + TH1F* mHistoInputs = nullptr; + TH1F* mHistoClasses = nullptr; +}; + +} // namespace o2::quality_control_modules::ctp + +#endif // QC_MODULE_CTP_CTPRAWDATAQCTASK_H diff --git a/Modules/CTP/src/RawDataQcTask.cxx b/Modules/CTP/src/RawDataQcTask.cxx new file mode 100644 index 0000000000..e75eb33d02 --- /dev/null +++ b/Modules/CTP/src/RawDataQcTask.cxx @@ -0,0 +1,207 @@ +// 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 RawDataQcTask.cxx +/// \author Marek Bombara +/// + +#include +#include + +#include "QualityControl/QcInfoLogger.h" +#include "CTP/RawDataQcTask.h" +#include "DetectorsRaw/RDHUtils.h" +#include "Headers/RAWDataHeader.h" +#include "DPLUtils/DPLRawParser.h" +#include "DataFormatsCTP/Digits.h" +#include +#include + +namespace o2::quality_control_modules::ctp +{ + +CTPRawDataReaderTask::~CTPRawDataReaderTask() +{ + delete mHistoBC; + delete mHistoInputs; + delete mHistoClasses; +} + +void CTPRawDataReaderTask::initialize(o2::framework::InitContext& /*ctx*/) +{ + ILOG(Info, Support) << "initialize CTPRawDataReaderTask" << ENDM; // QcInfoLogger is used. FairMQ logs will go to there as well. + + mHistoBC = new TH1F("histobc", "BC distribution", 3564, 0, 3564); + mHistoInputs = new TH1F("inputs", "Inputs distribution", 48, 0, 48); + mHistoClasses = new TH1F("classes", "Classes distribution", 64, 0, 64); + getObjectsManager()->startPublishing(mHistoBC); + getObjectsManager()->startPublishing(mHistoInputs); + getObjectsManager()->startPublishing(mHistoClasses); +} + +void CTPRawDataReaderTask::startOfActivity(Activity& activity) +{ + ILOG(Info, Support) << "startOfActivity " << activity.mId << ENDM; + mHistoBC->Reset(); + mHistoInputs->Reset(); + mHistoClasses->Reset(); +} + +void CTPRawDataReaderTask::startOfCycle() +{ + ILOG(Info, Support) << "startOfCycle" << ENDM; +} + +void CTPRawDataReaderTask::monitorData(o2::framework::ProcessingContext& ctx) +{ + // get the input + o2::framework::DPLRawParser parser(ctx.inputs()); + o2::ctp::gbtword80_t remnant = 0; + uint32_t sizegbt = 0; + uint32_t orbit0 = 0; + bool first = true; + const o2::ctp::gbtword80_t bcidmask = 0xfff; + o2::ctp::gbtword80_t pldmask = 0; + + // loop over input + for (auto it = parser.begin(), end = parser.end(); it != end; ++it) { + // get the header + auto const* rdh = it.get_if(); + auto triggerOrbit = o2::raw::RDHUtils::getTriggerOrbit(rdh); + if (first) { + orbit0 = triggerOrbit; + first = false; + } + + // LOG(info) << "trigger orbit = " << triggerOrbit; + // mHistogram->Fill(triggerOrbit); + // mHistogram2->Fill(triggerBC); + + uint32_t payloadCTP; + auto feeID = o2::raw::RDHUtils::getFEEID(rdh); // 0 = IR, 1 = TCR + auto linkCRU = (feeID & 0xf00) >> 8; + if (linkCRU == o2::ctp::GBTLinkIDIntRec) { + payloadCTP = o2::ctp::NIntRecPayload; + } else if (linkCRU == o2::ctp::GBTLinkIDClassRec) { + payloadCTP = o2::ctp::NClassPayload; + } else { + LOG(error) << "Unxpected CTP CRU link:" << linkCRU; + } + // LOG(info) << "RDH FEEid: " << feeID << " CTP CRU link:" << linkCRU << " Orbit:" << triggerOrbit << " payloadCTP = " << payloadCTP; + pldmask = 0; + for (uint32_t i = 0; i < payloadCTP; i++) { + pldmask[12 + i] = 1; + } + gsl::span payload(it.data(), it.size()); + o2::ctp::gbtword80_t gbtWord = 0; + int wordCount = 0; + std::vector diglets; + + // === according to O2: Detectors/CTP/workflow/src/RawToDigitConverterSpec.cxx ======== + for (auto payloadWord : payload) { + if (wordCount == 15) { + wordCount = 0; + } else if (wordCount > 9) { + wordCount++; + } else if (wordCount == 9) { + for (int i = 0; i < 8; i++) { + gbtWord[wordCount * 8 + i] = bool(int(payloadWord) & (1 << i)); + } + wordCount++; + diglets.clear(); + o2::ctp::gbtword80_t diglet = remnant; + uint32_t k = 0; + const uint32_t nGBT = o2::ctp::NGBT; + while (k < (nGBT - payloadCTP)) { + std::bitset masksize = 0; + for (uint32_t j = 0; j < (payloadCTP - sizegbt); j++) { + masksize[j] = 1; + } + diglet |= (gbtWord & masksize) << (sizegbt); + diglets.push_back(diglet); + diglet = 0; + k += payloadCTP - sizegbt; + gbtWord = gbtWord >> (payloadCTP - sizegbt); + sizegbt = 0; + } + sizegbt = nGBT - k; + remnant = gbtWord; + // ========================================== + // LOG(info) << " gbtword after:" << gbtWord; + for (auto diglet : diglets) { + // LOG(info) << " diglet:" << diglet; + // LOG(info) << " pldmask:" << pldmask; + o2::ctp::gbtword80_t pld = (diglet & pldmask); + if (pld.count() == 0) { + continue; + } + // LOG(info) << " pld:" << pld; + pld >>= 12; + uint32_t bcid = (diglet & bcidmask).to_ulong(); + // LOG(info) << " diglet:" << diglet; + // LOG(info) << " bcid:" << bcid; + mHistoBC->Fill(bcid); + + o2::ctp::gbtword80_t inputMask = 0; + if (linkCRU == o2::ctp::GBTLinkIDIntRec) { + inputMask = pld; + // LOG(info) << " InputMask:" << inputMask; + for (Int_t i = 0; i < payloadCTP; i++) { + if (inputMask[i] != 0) { + mHistoInputs->Fill(i); + } + } + } + + o2::ctp::gbtword80_t classMask = 0; + if (linkCRU == o2::ctp::GBTLinkIDClassRec) { + classMask = pld; + // LOG(info) << " ClassMask:" << classMask; + for (Int_t i = 0; i < payloadCTP; i++) { + if (classMask[i] != 0) { + mHistoClasses->Fill(i); + } + } + } + } + gbtWord = 0; + } else { + for (int i = 0; i < 8; i++) { + gbtWord[wordCount * 8 + i] = bool(int(payloadWord) & (1 << i)); + } + wordCount++; + } + } + } +} + +void CTPRawDataReaderTask::endOfCycle() +{ + ILOG(Info, Support) << "endOfCycle" << ENDM; +} + +void CTPRawDataReaderTask::endOfActivity(Activity& /*activity*/) +{ + ILOG(Info, Support) << "endOfActivity" << ENDM; +} + +void CTPRawDataReaderTask::reset() +{ + // clean all the monitor objects here + + ILOG(Info, Support) << "Resetting the histogram" << ENDM; + mHistoBC->Reset(); + mHistoInputs->Reset(); + mHistoClasses->Reset(); +} + +} // namespace o2::quality_control_modules::ctp diff --git a/Modules/CTP/test/testQcCTP.cxx b/Modules/CTP/test/testQcCTP.cxx new file mode 100644 index 0000000000..98e8021cde --- /dev/null +++ b/Modules/CTP/test/testQcCTP.cxx @@ -0,0 +1,30 @@ +// 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 testCTP.cxx +/// \author My Name +/// + +#include "QualityControl/TaskFactory.h" + +#define BOOST_TEST_MODULE Publisher test +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +#include + +namespace o2::quality_control_modules::ctp +{ + +BOOST_AUTO_TEST_CASE(instantiate_task) { BOOST_CHECK(true); } + +} // namespace o2::quality_control_modules::ctp