diff --git a/DataFormats/Detectors/FIT/FDD/CMakeLists.txt b/DataFormats/Detectors/FIT/FDD/CMakeLists.txt index 140ba1165bff8..8e8f3f0588a0c 100644 --- a/DataFormats/Detectors/FIT/FDD/CMakeLists.txt +++ b/DataFormats/Detectors/FIT/FDD/CMakeLists.txt @@ -29,5 +29,7 @@ o2_target_root_dictionary(DataFormatsFDD include/DataFormatsFDD/RecPoint.h include/DataFormatsFDD/RawEventData.h include/DataFormatsFDD/LookUpTable.h - include/DataFormatsFDD/CTF.h) + include/DataFormatsFDD/CTF.h + include/DataFormatsFDD/FeeConfiguration.h + include/DataFormatsFDD/HvConfiguration.h) diff --git a/DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/FeeConfiguration.h b/DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/FeeConfiguration.h new file mode 100644 index 0000000000000..f9b365eea6114 --- /dev/null +++ b/DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/FeeConfiguration.h @@ -0,0 +1,42 @@ +// 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. + +#ifndef O2_FDD_FEE_CONFIGURATION +#define O2_FDD_FEE_CONFIGURATION + +#include "DataFormatsFIT/Configuration.h" + +namespace o2::fdd +{ +struct TriggersConfig { + float vertexTimeLowThreshold{o2::fit::config_helpers::DefaultValue}; + float vertexTimeHighThreshold{o2::fit::config_helpers::DefaultValue}; + uint16_t semicentralA{o2::fit::config_helpers::DefaultValue}; + uint16_t semicentralC{o2::fit::config_helpers::DefaultValue}; + uint16_t centralA{o2::fit::config_helpers::DefaultValue}; + uint16_t centralC{o2::fit::config_helpers::DefaultValue}; + uint8_t sidesCombinationMode{o2::fit::config_helpers::DefaultValue}; + + ClassDefNV(TriggersConfig, 1); +}; + +struct FddFeeConfiguration { + static constexpr int NChannels = 16; + TriggersConfig triggers; + o2::fit::ChannelsConfig channels; + o2::fit::TcmConfig tcm; + o2::fit::PmConfig pmA[10]; + o2::fit::PmConfig pmC[10]; + + ClassDefNV(FddFeeConfiguration, 1); +}; +} // namespace o2::fdd +#endif \ No newline at end of file diff --git a/DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/HvConfiguration.h b/DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/HvConfiguration.h new file mode 100644 index 0000000000000..abaaa4a355b64 --- /dev/null +++ b/DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/HvConfiguration.h @@ -0,0 +1,26 @@ +// 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. + +#ifndef O2_FDD_HV_CONFIGURATION +#define O2_FDD_HV_CONFIGURATION + +#include "DataFormatsFIT/Configuration.h" +#include + +namespace o2::fdd +{ +struct FddHvConfiguration { + static constexpr int NChannels = 16; + o2::fit::HvChannelsConfig channels; + ClassDefNV(FddHvConfiguration, 1); +}; +} // namespace o2::fdd +#endif \ No newline at end of file diff --git a/DataFormats/Detectors/FIT/FDD/src/DataFormatsFDDLinkDef.h b/DataFormats/Detectors/FIT/FDD/src/DataFormatsFDDLinkDef.h index daf1fb4027dc9..14d670882eacb 100644 --- a/DataFormats/Detectors/FIT/FDD/src/DataFormatsFDDLinkDef.h +++ b/DataFormats/Detectors/FIT/FDD/src/DataFormatsFDDLinkDef.h @@ -37,4 +37,9 @@ #pragma link C++ class o2::fdd::CTF + ; #pragma link C++ class o2::ctf::EncodedBlocks < o2::fdd::CTFHeader, 8, uint32_t> + ; +#pragma link C++ struct o2::fdd::FddFeeConfiguration + ; +#pragma link C++ struct o2::fit::ChannelsConfig < 16> + ; +#pragma link C++ struct o2::fdd::TriggersConfig + ; +#pragma link C++ struct o2::fdd::FddHvConfiguration + ; +#pragma link C++ struct o2::fit::HvChannelsConfig < 16> + ; #endif diff --git a/DataFormats/Detectors/FIT/FT0/CMakeLists.txt b/DataFormats/Detectors/FIT/FT0/CMakeLists.txt index f7d6a111f4348..05e51615b223f 100644 --- a/DataFormats/Detectors/FIT/FT0/CMakeLists.txt +++ b/DataFormats/Detectors/FIT/FT0/CMakeLists.txt @@ -48,4 +48,6 @@ o2_target_root_dictionary(DataFormatsFT0 include/DataFormatsFT0/SpectraInfoObject.h include/DataFormatsFT0/SlewingCoef.h include/DataFormatsFT0/EventsPerBc.h + include/DataFormatsFT0/FeeConfiguration.h + include/DataFormatsFT0/HvConfiguration.h ) diff --git a/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/FeeConfiguration.h b/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/FeeConfiguration.h new file mode 100644 index 0000000000000..2d5f9a656c255 --- /dev/null +++ b/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/FeeConfiguration.h @@ -0,0 +1,42 @@ +// 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. + +#ifndef O2_FT0_FEE_CONFIGURATION +#define O2_FT0_FEE_CONFIGURATION + +#include "CommonUtils/ConfigurableParamHelper.h" +#include "DataFormatsFIT/Configuration.h" +#include + +namespace o2::ft0 +{ +struct TriggersConfig { + int16_t vertexTimeLowThreshold{o2::fit::config_helpers::DefaultValue}; + int16_t vertexTimeHighThreshold{o2::fit::config_helpers::DefaultValue}; + uint16_t semicentralA{o2::fit::config_helpers::DefaultValue}; + uint16_t semicentralC{o2::fit::config_helpers::DefaultValue}; + uint16_t centralA{o2::fit::config_helpers::DefaultValue}; + uint16_t centralC{o2::fit::config_helpers::DefaultValue}; + uint8_t sidesCombinationMode{o2::fit::config_helpers::DefaultValue}; + ClassDefNV(TriggersConfig, 1); +}; + +struct Ft0FeeConfiguration { + static constexpr int NChannels = 208; + TriggersConfig triggers; + o2::fit::ChannelsConfig channels; + o2::fit::TcmConfig tcm; + o2::fit::PmConfig pmA[10]; + o2::fit::PmConfig pmC[10]; + ClassDefNV(Ft0FeeConfiguration, 1); +}; +} // namespace o2::ft0 +#endif \ No newline at end of file diff --git a/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/HvConfiguration.h b/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/HvConfiguration.h new file mode 100644 index 0000000000000..55075a185056f --- /dev/null +++ b/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/HvConfiguration.h @@ -0,0 +1,27 @@ +// 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. + +#ifndef O2_FT0_HV_CONFIGURATION +#define O2_FT0_HV_CONFIGURATION + +#include "CommonUtils/ConfigurableParamHelper.h" +#include "DataFormatsFIT/Configuration.h" +#include + +namespace o2::ft0 +{ +struct Ft0HvConfiguration { + static constexpr int NChannels = 208; + o2::fit::HvChannelsConfig channels; + ClassDefNV(Ft0HvConfiguration, 1); +}; +} // namespace o2::ft0 +#endif \ No newline at end of file diff --git a/DataFormats/Detectors/FIT/FT0/src/DataFormatsFT0LinkDef.h b/DataFormats/Detectors/FIT/FT0/src/DataFormatsFT0LinkDef.h index 7f8c17a0cd191..b207d3c9d6003 100644 --- a/DataFormats/Detectors/FIT/FT0/src/DataFormatsFT0LinkDef.h +++ b/DataFormats/Detectors/FIT/FT0/src/DataFormatsFT0LinkDef.h @@ -57,5 +57,9 @@ #pragma link C++ class o2::ft0::SlewingCoef + ; #pragma link C++ class o2::ft0::EventsPerBc + ; - +#pragma link C++ struct o2::ft0::Ft0FeeConfiguration + ; +#pragma link C++ struct o2::ft0::TriggersConfig + ; +#pragma link C++ struct o2::fit::ChannelsConfig < 208> + ; +#pragma link C++ struct o2::ft0::Ft0HvConfiguration + ; +#pragma link C++ struct o2::fit::HvChannelsConfig < 208> + ; #endif diff --git a/DataFormats/Detectors/FIT/FV0/CMakeLists.txt b/DataFormats/Detectors/FIT/FV0/CMakeLists.txt index 35bc653a8234e..cf1df963c6791 100644 --- a/DataFormats/Detectors/FIT/FV0/CMakeLists.txt +++ b/DataFormats/Detectors/FIT/FV0/CMakeLists.txt @@ -35,4 +35,6 @@ o2_target_root_dictionary(DataFormatsFV0 include/DataFormatsFV0/RecPoints.h include/DataFormatsFV0/RawEventData.h include/DataFormatsFV0/LookUpTable.h - include/DataFormatsFV0/CTF.h) + include/DataFormatsFV0/CTF.h + include/DataFormatsFV0/FeeConfiguration.h + include/DataFormatsFV0/HvConfiguration.h) diff --git a/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/FeeConfiguration.h b/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/FeeConfiguration.h new file mode 100644 index 0000000000000..17646acbbfe79 --- /dev/null +++ b/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/FeeConfiguration.h @@ -0,0 +1,39 @@ +// 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. + +#ifndef O2_FV0_FEE_CONFIGURATION +#define O2_FV0_FEE_CONFIGURATION + +#include "DataFormatsFIT/Configuration.h" + +namespace o2::fv0 +{ +struct TriggersConfig { + uint16_t nChannels{o2::fit::config_helpers::DefaultValue}; + uint16_t innerRings{o2::fit::config_helpers::DefaultValue}; + uint16_t charge{o2::fit::config_helpers::DefaultValue}; + uint16_t outerRings{o2::fit::config_helpers::DefaultValue}; + uint8_t sidesCombinationMode{o2::fit::config_helpers::DefaultValue}; + + ClassDefNV(TriggersConfig, 1); +}; + +struct Fv0FeeConfiguration { + static constexpr int NChannels = 48; + TriggersConfig triggers; + o2::fit::ChannelsConfig channels; + o2::fit::TcmConfig tcm; + o2::fit::PmConfig pmA[10]; + + ClassDefNV(Fv0FeeConfiguration, 1); +}; +} // namespace o2::fv0 +#endif \ No newline at end of file diff --git a/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/HvConfiguration.h b/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/HvConfiguration.h new file mode 100644 index 0000000000000..207c83ba20d55 --- /dev/null +++ b/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/HvConfiguration.h @@ -0,0 +1,26 @@ +// 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. + +#ifndef O2_FV0_HV_CONFIGURATION +#define O2_FV0_HV_CONFIGURATION + +#include "DataFormatsFIT/Configuration.h" +#include + +namespace o2::fv0 +{ +struct Fv0HvConfiguration { + static constexpr int NChannels = 48; + o2::fit::HvChannelsConfig channels; + ClassDefNV(Fv0HvConfiguration, 1); +}; +} // namespace o2::fv0 +#endif \ No newline at end of file diff --git a/DataFormats/Detectors/FIT/FV0/src/DataFormatsFV0LinkDef.h b/DataFormats/Detectors/FIT/FV0/src/DataFormatsFV0LinkDef.h index ab23b4aa727bc..10962ebe67383 100644 --- a/DataFormats/Detectors/FIT/FV0/src/DataFormatsFV0LinkDef.h +++ b/DataFormats/Detectors/FIT/FV0/src/DataFormatsFV0LinkDef.h @@ -40,4 +40,8 @@ #pragma link C++ class o2::fv0::FV0CalibrationInfoObject + ; #pragma link C++ class o2::fv0::FV0ChannelTimeCalibrationObject + ; +#pragma link C++ struct o2::fv0::Fv0FeeConfiguration + ; +#pragma link C++ struct o2::fit::ChannelsConfig < 48> + ; +#pragma link C++ struct o2::fv0::Fv0HvConfiguration + ; +#pragma link C++ struct o2::fit::HvChannelsConfig < 48> + ; #endif diff --git a/DataFormats/Detectors/FIT/common/CMakeLists.txt b/DataFormats/Detectors/FIT/common/CMakeLists.txt index 61dbcabc7f087..4bdd9a1e00fa5 100644 --- a/DataFormats/Detectors/FIT/common/CMakeLists.txt +++ b/DataFormats/Detectors/FIT/common/CMakeLists.txt @@ -23,4 +23,6 @@ o2_target_root_dictionary(DataFormatsFIT include/DataFormatsFIT/LookUpTable.h include/DataFormatsFIT/Triggers.h include/DataFormatsFIT/ChannelData.h - include/DataFormatsFIT/Digit.h) + include/DataFormatsFIT/Digit.h + include/DataFormatsFIT/Configuration.h + include/DataFormatsFIT/DeadChannelMap.h) diff --git a/DataFormats/Detectors/FIT/common/include/DataFormatsFIT/Configuration.h b/DataFormats/Detectors/FIT/common/include/DataFormatsFIT/Configuration.h new file mode 100644 index 0000000000000..72eae33c3d862 --- /dev/null +++ b/DataFormats/Detectors/FIT/common/include/DataFormatsFIT/Configuration.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 FeeConfiguration.h +/// \brief Utilities to describe FEE configuration +/// \author wiktor.pierozak@cern.ch + +#ifndef O2_FIT_FEE_CONFIGURATION +#define O2_FIT_FEE_CONFIGURATION + +#include +#include +#include +#include +#include +#include +#include + +namespace o2::fit +{ +namespace config_helpers +{ +struct DefaultValueType { + template + requires std::is_arithmetic_v + constexpr operator T() const noexcept + { + if constexpr (std::is_same_v) { + return false; + } else { + return std::numeric_limits::max(); + } + } +}; + +inline constexpr DefaultValueType DefaultValue{}; + +template +constexpr void fillDefaultArray(T (&array)[N]) +{ + for (auto& element : array) { + element = DefaultValue; + } +} +} // namespace config_helpers + +struct TcmConfig { + float phaseDelayA{config_helpers::DefaultValue}; + float phaseDelayC{config_helpers::DefaultValue}; + + bool operator==(const TcmConfig&) const = default; + ClassDefNV(TcmConfig, 1); +}; + +struct PmConfig { + uint8_t orGate{config_helpers::DefaultValue}; + uint16_t trgChargeHighLevel{config_helpers::DefaultValue}; + uint16_t trgChargeLowLevel{config_helpers::DefaultValue}; + bool fddCoincidenceMode{config_helpers::DefaultValue}; + bool operator==(const PmConfig&) const = default; + ClassDefNV(PmConfig, 1); +}; + +template +struct ChannelsConfig { + int16_t timeAligments[NChannels]; + uint16_t cfdThresholds[NChannels]; + int16_t cfdZeros[NChannels]; + int16_t adcZeros[NChannels]; + uint16_t adcDelays[NChannels]; + uint16_t rangeCorrectionAdc0[NChannels]; + uint16_t rangeCorrectionAdc1[NChannels]; + uint16_t thresholdCalibration[NChannels]; + bool channelMaskData[NChannels]; + bool channelMaskTriggers[NChannels]; + + constexpr ChannelsConfig() + { + config_helpers::fillDefaultArray(timeAligments); + config_helpers::fillDefaultArray(cfdThresholds); + config_helpers::fillDefaultArray(cfdZeros); + config_helpers::fillDefaultArray(adcZeros); + config_helpers::fillDefaultArray(adcDelays); + config_helpers::fillDefaultArray(rangeCorrectionAdc0); + config_helpers::fillDefaultArray(rangeCorrectionAdc1); + config_helpers::fillDefaultArray(channelMaskData); + config_helpers::fillDefaultArray(channelMaskTriggers); + config_helpers::fillDefaultArray(thresholdCalibration); + } + + template + [[nodiscard]] static constexpr bool isDefault(const T& value) + { + return value == static_cast(config_helpers::DefaultValue); + } + + gsl::span getTimeAligments() const { return timeAligments; } + gsl::span getCfdThresholds() const { return cfdThresholds; } + gsl::span getCfdZeros() const { return cfdZeros; } + gsl::span getAdcZeros() const { return adcZeros; } + gsl::span getAdcDelays() const { return adcDelays; } + gsl::span getRangeCorrectionAdc0() const { return rangeCorrectionAdc0; } + gsl::span getRangeCorrectionAdc1() const { return rangeCorrectionAdc1; } + gsl::span getChannelMaskTriggers() const { return channelMaskTriggers; } + gsl::span getChannelMaskData() const { return channelMaskData; } + + bool operator==(const ChannelsConfig& other) const + { + return std::equal(std::begin(timeAligments), std::end(timeAligments), std::begin(other.timeAligments)) && + std::equal(std::begin(cfdThresholds), std::end(cfdThresholds), std::begin(other.cfdThresholds)) && + std::equal(std::begin(cfdZeros), std::end(cfdZeros), std::begin(other.cfdZeros)) && + std::equal(std::begin(adcZeros), std::end(adcZeros), std::begin(other.adcZeros)) && + std::equal(std::begin(adcDelays), std::end(adcDelays), std::begin(other.adcDelays)) && + std::equal(std::begin(rangeCorrectionAdc0), std::end(rangeCorrectionAdc0), std::begin(other.rangeCorrectionAdc0)) && + std::equal(std::begin(rangeCorrectionAdc1), std::end(rangeCorrectionAdc1), std::begin(other.rangeCorrectionAdc1)) && + std::equal(std::begin(channelMaskData), std::end(channelMaskData), std::begin(other.channelMaskData)) && + std::equal(std::begin(channelMaskTriggers), std::end(channelMaskTriggers), std::begin(other.channelMaskTriggers)); + } + + ClassDefNV(ChannelsConfig, 1); +}; + +template +struct HvChannelsConfig { + float gain[NChannels]; + + constexpr HvChannelsConfig() + { + config_helpers::fillDefaultArray(gain); + } + bool operator==(const HvChannelsConfig& other) const + { + return std::equal(std::begin(gain), std::end(gain), std::begin(other.gain)); + } + ClassDefNV(HvChannelsConfig, 1); +}; +} // namespace o2::fit +#endif \ No newline at end of file diff --git a/DataFormats/Detectors/FIT/common/src/DataFormatsFITLinkDef.h b/DataFormats/Detectors/FIT/common/src/DataFormatsFITLinkDef.h index e005315e2d6a0..d017599cb8998 100644 --- a/DataFormats/Detectors/FIT/common/src/DataFormatsFITLinkDef.h +++ b/DataFormats/Detectors/FIT/common/src/DataFormatsFITLinkDef.h @@ -25,6 +25,10 @@ #pragma link C++ std::vector < std::pair < uint64_t, int>> + ; #pragma link C++ struct o2::fit::DCSDPValues + ; + +#pragma link C++ struct o2::fit::TcmConfig + ; +#pragma link C++ struct o2::fit::PmConfig + ; +#pragma link C++ struct o2::fit::DeadChannelMap + ; /* #include "DetectorsCommonDataFormats/DetID.h" #pragma link C++ struct o2::fit::ChannelData + ; diff --git a/Detectors/FIT/FDD/dcsmonitoring/CMakeLists.txt b/Detectors/FIT/FDD/dcsmonitoring/CMakeLists.txt index a13227dc90605..7b6566f8fbb97 100644 --- a/Detectors/FIT/FDD/dcsmonitoring/CMakeLists.txt +++ b/Detectors/FIT/FDD/dcsmonitoring/CMakeLists.txt @@ -10,8 +10,8 @@ # or submit itself to any jurisdiction. o2_add_library(FDDDCSMonitoring - SOURCES src/FDDDCSDataProcessor.cxx - PUBLIC_LINK_LIBRARIES O2::FITDCSMonitoring) + SOURCES src/FDDDCSDataProcessor.cxx src/FDDDCSConfigProcessor.cxx src/FDDFEEConfigurationReader.cxx + PUBLIC_LINK_LIBRARIES O2::FITDCSMonitoring O2::DataFormatsFDD) o2_add_executable(dcs-sim-workflow COMPONENT_NAME fdd @@ -30,4 +30,5 @@ o2_add_executable(dcs-config-workflow SOURCES workflow/fdd-dcs-config-workflow.cxx PUBLIC_LINK_LIBRARIES O2::DetectorsCalibration O2::FITDCSMonitoring - O2::Framework) + O2::Framework + O2::FDDDCSMonitoring) diff --git a/Detectors/FIT/FDD/dcsmonitoring/include/FDDDCSMonitoring/FDDDCSConfigProcessor.h b/Detectors/FIT/FDD/dcsmonitoring/include/FDDDCSMonitoring/FDDDCSConfigProcessor.h new file mode 100644 index 0000000000000..451725cb14bbd --- /dev/null +++ b/Detectors/FIT/FDD/dcsmonitoring/include/FDDDCSMonitoring/FDDDCSConfigProcessor.h @@ -0,0 +1,38 @@ +// 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. + +/// \author Wiktor Pierożak , AGH University of Krakow, Poland + +#ifndef O2_FDD_DCS_CONFIG_PROCESSOR_H +#define O2_FDD_DCS_CONFIG_PROCESSOR_H + +#include "FITDCSMonitoring/FITDCSConfigProcessor.h" +#include "FDDDCSMonitoring/FDDFEEConfigurationReader.h" +#include "FITDCSMonitoring/FITHvConfigurationReader.h" + +namespace o2::fdd +{ +class FDDDCSConfigProcessor : public o2::fit::FITDCSConfigProcessor +{ + public: + FDDDCSConfigProcessor(const std::string& detectorName, const o2::header::DataDescription& dataDescriptionDChM, const o2::header::DataDescription& dataDescriptionFeeConfig, const o2::header::DataDescription& dataDescriptionHvConfig) + : o2::fit::FITDCSConfigProcessor(detectorName, dataDescriptionDChM, dataDescriptionFeeConfig, dataDescriptionHvConfig) {} + + void init(o2::framework::InitContext& ic) final; + void run(o2::framework::ProcessingContext& pc) final; + void endOfStream(o2::framework::EndOfStreamContext& ec) final; + + private: + FDDFEEConfigurationReader mFeeConfigurationReader; + o2::fit::FITHvConfigurationReader mHvConfigurationReader; +}; +} // namespace o2::fdd +#endif \ No newline at end of file diff --git a/Detectors/FIT/FDD/dcsmonitoring/include/FDDDCSMonitoring/FDDFEEConfigurationReader.h b/Detectors/FIT/FDD/dcsmonitoring/include/FDDDCSMonitoring/FDDFEEConfigurationReader.h new file mode 100644 index 0000000000000..a604afb391513 --- /dev/null +++ b/Detectors/FIT/FDD/dcsmonitoring/include/FDDDCSMonitoring/FDDFEEConfigurationReader.h @@ -0,0 +1,29 @@ +// 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. + +#ifndef O2_FDD_DCSCONFIGREADER_H +#define O2_FDD_DCSCONFIGREADER_H + +#include "FITDCSMonitoring/FITFEEConfigurationReader.h" +#include "DataFormatsFDD/FeeConfiguration.h" + +namespace o2::fdd +{ +class FDDFEEConfigurationReader : public o2::fit::FITFEEConfigurationReader +{ + public: + FddFeeConfiguration parseFeeConfiguration(gsl::span configBuf); + void parseTriggers(const rapidjson::Value& root, const char* triggersNodeName, TriggersConfig& config); +}; + +} // namespace o2::fdd + +#endif // O2_FV0_DCSCONFIGREADER_H \ No newline at end of file diff --git a/Detectors/FIT/FDD/dcsmonitoring/macros/CMakeLists.txt b/Detectors/FIT/FDD/dcsmonitoring/macros/CMakeLists.txt index 63571c1001d3f..1fc63e6c61d01 100644 --- a/Detectors/FIT/FDD/dcsmonitoring/macros/CMakeLists.txt +++ b/Detectors/FIT/FDD/dcsmonitoring/macros/CMakeLists.txt @@ -13,3 +13,9 @@ o2_add_test_root_macro(makeFDDCCDBEntryForDCS.C PUBLIC_LINK_LIBRARIES O2::CCDB O2::DetectorsDCS LABELS fdd) + +o2_add_test_root_macro(fetchFddFeeConfig.C + PUBLIC_LINK_LIBRARIES + O2::CCDB + O2::DataFormatsFDD + LABELS fdd) \ No newline at end of file diff --git a/Detectors/FIT/FDD/dcsmonitoring/macros/fetchFddFeeConfig.C b/Detectors/FIT/FDD/dcsmonitoring/macros/fetchFddFeeConfig.C new file mode 100644 index 0000000000000..e205b7e5d56d4 --- /dev/null +++ b/Detectors/FIT/FDD/dcsmonitoring/macros/fetchFddFeeConfig.C @@ -0,0 +1,139 @@ +// 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. + +#if !defined(__CLING__) || defined(__ROOTCLING__) + +#include "CCDB/CcdbApi.h" +#include "DataFormatsFDD/FeeConfiguration.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#endif + +void fetchFddFeeConfig(const std::string ccdbUrl = "http://alice-ccdb.cern.ch", long timestamp = -1, const std::string fileName = "fdd-fee-config.json", const std::string ccdbPath = "FDD/Config/FeeConfiguration") +{ + o2::ccdb::CcdbApi ccdbApi; + ccdbApi.init(ccdbUrl); + + std::map metadata; + std::unique_ptr config(ccdbApi.retrieveFromTFileAny(ccdbPath, metadata, timestamp)); + + if (!config) { + throw std::runtime_error("Cannot retrieve FddFeeConfiguration from CCDB path " + ccdbPath); + } + + rapidjson::Document doc; + doc.SetObject(); + auto& allocator = doc.GetAllocator(); + + rapidjson::Value channels(rapidjson::kObjectType); + rapidjson::Value timeAligments(rapidjson::kArrayType); + rapidjson::Value cfdThresholds(rapidjson::kArrayType); + rapidjson::Value cfdZeros(rapidjson::kArrayType); + rapidjson::Value adcZeros(rapidjson::kArrayType); + rapidjson::Value adcDelays(rapidjson::kArrayType); + rapidjson::Value rangeCorrectionAdc0(rapidjson::kArrayType); + rapidjson::Value rangeCorrectionAdc1(rapidjson::kArrayType); + rapidjson::Value channelMaskData(rapidjson::kArrayType); + rapidjson::Value channelMaskTriggers(rapidjson::kArrayType); + rapidjson::Value thresholdCalibration(rapidjson::kArrayType); + + for (int i = 0; i < o2::fdd::FddFeeConfiguration::NChannels; ++i) { + timeAligments.PushBack(config->channels.timeAligments[i], allocator); + cfdThresholds.PushBack(config->channels.cfdThresholds[i], allocator); + cfdZeros.PushBack(config->channels.cfdZeros[i], allocator); + adcZeros.PushBack(config->channels.adcZeros[i], allocator); + adcDelays.PushBack(config->channels.adcDelays[i], allocator); + rangeCorrectionAdc0.PushBack(config->channels.rangeCorrectionAdc0[i], allocator); + rangeCorrectionAdc1.PushBack(config->channels.rangeCorrectionAdc1[i], allocator); + channelMaskData.PushBack(config->channels.channelMaskData[i], allocator); + channelMaskTriggers.PushBack(config->channels.channelMaskTriggers[i], allocator); + thresholdCalibration.PushBack(config->channels.thresholdCalibration[i], allocator); + } + + channels.AddMember("time_aligments", timeAligments, allocator); + channels.AddMember("cfd_thresholds", cfdThresholds, allocator); + channels.AddMember("cfd_zeros", cfdZeros, allocator); + channels.AddMember("adc_zeros", adcZeros, allocator); + channels.AddMember("adc_delays", adcDelays, allocator); + channels.AddMember("range_correction_adc0", rangeCorrectionAdc0, allocator); + channels.AddMember("range_correction_adc1", rangeCorrectionAdc1, allocator); + channels.AddMember("channel_mask_data", channelMaskData, allocator); + channels.AddMember("channel_mask_triggers", channelMaskTriggers, allocator); + channels.AddMember("threshold_calibration", thresholdCalibration, allocator); + doc.AddMember("channels", channels, allocator); + + rapidjson::Value tcm(rapidjson::kObjectType); + tcm.AddMember("phase_delay_a", config->tcm.phaseDelayA, allocator); + tcm.AddMember("phase_delay_c", config->tcm.phaseDelayC, allocator); + doc.AddMember("tcm", tcm, allocator); + + rapidjson::Value pmA(rapidjson::kArrayType); + + for (int i = 0; i < 10; ++i) { + rapidjson::Value pm(rapidjson::kObjectType); + pm.AddMember("or_gate", config->pmA[i].orGate, allocator); + pm.AddMember("trg_charge_low_level", config->pmA[i].trgChargeLowLevel, allocator); + pm.AddMember("trg_charge_high_level", config->pmA[i].trgChargeHighLevel, allocator); + pmA.PushBack(pm, allocator); + } + doc.AddMember("pm_a", pmA, allocator); + + rapidjson::Value pmC(rapidjson::kArrayType); + for (int i = 0; i < 10; ++i) { + rapidjson::Value pm(rapidjson::kObjectType); + pm.AddMember("or_gate", config->pmC[i].orGate, allocator); + pm.AddMember("trg_charge_low_level", config->pmC[i].trgChargeLowLevel, allocator); + pm.AddMember("trg_charge_high_level", config->pmC[i].trgChargeHighLevel, allocator); + pmC.PushBack(pm, allocator); + } + doc.AddMember("pm_c", pmC, allocator); + + rapidjson::Value triggers(rapidjson::kObjectType); + triggers.AddMember("vertex_time_low_threshold", config->triggers.vertexTimeLowThreshold, allocator); + + triggers.AddMember("vertex_time_high_threshold", config->triggers.vertexTimeHighThreshold, allocator); + triggers.AddMember("semicentral_a", config->triggers.semicentralA, allocator); + triggers.AddMember("semicentral_c", config->triggers.semicentralC, allocator); + triggers.AddMember("central_a", config->triggers.centralA, allocator); + triggers.AddMember("central_c", config->triggers.centralC, allocator); + doc.AddMember("triggers", triggers, allocator); + + rapidjson::StringBuffer buffer; + rapidjson::PrettyWriter writer(buffer); + + doc.Accept(writer); + + if (fileName.empty()) { + std::cout << buffer.GetString() << '\n'; + return; + } + + std::ofstream output(fileName); + + if (!output) { + throw std::runtime_error( + "Cannot open output file " + fileName); + } + + output << buffer.GetString() << '\n'; + + std::cout << "FT0 FEE configuration written to " << fileName << '\n'; +} diff --git a/Detectors/FIT/FDD/dcsmonitoring/src/FDDDCSConfigProcessor.cxx b/Detectors/FIT/FDD/dcsmonitoring/src/FDDDCSConfigProcessor.cxx new file mode 100644 index 0000000000000..dc271433f1994 --- /dev/null +++ b/Detectors/FIT/FDD/dcsmonitoring/src/FDDDCSConfigProcessor.cxx @@ -0,0 +1,55 @@ +// 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 "FDDDCSMonitoring/FDDDCSConfigProcessor.h" +#include "DataFormatsFDD/HvConfiguration.h" + +namespace o2::fdd +{ +void FDDDCSConfigProcessor::init(o2::framework::InitContext& ic) +{ + initDeadChannelMapReader(); + setupDeadChannelMapReader(ic); + setupFeeConfigurationReader(ic, mFeeConfigurationReader); + setupHvConfigurationReader(ic, mHvConfigurationReader); +} + +void FDDDCSConfigProcessor::run(o2::framework::ProcessingContext& pc) +{ + try { + long dataTime = getValidityTime(pc); + + gsl::span dataBuffer = pc.inputs().get>("inputConfig"); + std::string configFileName = pc.inputs().get("inputConfigFileName"); + LOG(info) << "Got input file " << configFileName << " of size " << dataBuffer.size(); + + if (!configFileName.compare(mDeadChannelMapReader->getFileNameDChM())) { + handleDeadChannelMapUpdate(pc, dataTime, dataBuffer); + } else if (mFeeConfigurationReader.matchFilename(configFileName)) { + FddFeeConfiguration feeConfiguration = mFeeConfigurationReader.parseFeeConfiguration(dataBuffer); + o2::ccdb::CcdbObjectInfo objectInfo = mFeeConfigCcdbInfo.createObjectInfo(feeConfiguration, dataTime, {}); + sendObject(pc.outputs(), feeConfiguration, objectInfo, getFeeConfigDescription()); + } else if (mHvConfigurationReader.matchFilename(configFileName)) { + FddHvConfiguration hvConfig = mHvConfigurationReader.parseHvConfiguration(dataBuffer); + o2::ccdb::CcdbObjectInfo objectInfo = mHvConfigCcdbInfo.createObjectInfo(hvConfig, dataTime, {}); + sendObject(pc.outputs(), hvConfig, objectInfo, getHvConfigDescription()); + } else { + LOG(error) << "Unknown input file: " << configFileName; + } + } catch (std::exception& e) { + LOG(error) << "Exception: " << e.what(); + } +} + +void FDDDCSConfigProcessor::endOfStream(o2::framework::EndOfStreamContext& ec) +{ +} +} // namespace o2::fdd \ No newline at end of file diff --git a/Detectors/FIT/FDD/dcsmonitoring/src/FDDFEEConfigurationReader.cxx b/Detectors/FIT/FDD/dcsmonitoring/src/FDDFEEConfigurationReader.cxx new file mode 100644 index 0000000000000..224cfb0051e2a --- /dev/null +++ b/Detectors/FIT/FDD/dcsmonitoring/src/FDDFEEConfigurationReader.cxx @@ -0,0 +1,70 @@ +// 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 "FDDDCSMonitoring/FDDFEEConfigurationReader.h" +#include +#include + +namespace o2::fdd +{ +FddFeeConfiguration FDDFEEConfigurationReader::parseFeeConfiguration(gsl::span buffer) +{ + return FITFEEConfigurationReader::parseFeeConfiguration(buffer); +} + +void FDDFEEConfigurationReader::parseTriggers(const rapidjson::Value& root, const char* triggersNodeName, TriggersConfig& config) +{ + const auto& triggersNode = root["triggers"]; + + if (triggersNode.HasMember("vertex_time_low_threshold") == false) { + throw std::runtime_error("Missing vertex_time_low_threshold trigger node!"); + } + const auto& vertexTimeLowThresholdNode = triggersNode["vertex_time_low_threshold"]; + + if (triggersNode.HasMember("vertex_time_high_threshold") == false) { + throw std::runtime_error("Missing vertex_time_high_threshold trigger node!"); + } + const auto& vertexTimeHighThresholdNode = triggersNode["vertex_time_high_threshold"]; + + if (triggersNode.HasMember("semi_central_a") == false) { + throw std::runtime_error("Missing semi_central_a trigger node!"); + } + const auto& semicentralANode = triggersNode["semi_central_a"]; + + if (triggersNode.HasMember("semi_central_c") == false) { + throw std::runtime_error("Missing semi_central_c trigger node!"); + } + const auto& semicentralCNode = triggersNode["semi_central_c"]; + + if (triggersNode.HasMember("central_a") == false) { + throw std::runtime_error("Missing central_a trigger node!"); + } + const auto& centralANode = triggersNode["central_a"]; + + if (triggersNode.HasMember("central_c") == false) { + throw std::runtime_error("Missing central_c trigger node!"); + } + const auto& centralCNode = triggersNode["central_c"]; + + if (triggersNode.HasMember("sides_combination_mode") == false) { + throw std::runtime_error("Missing sides_combination_mode node!"); + } + const auto& sidesCombinationMode = triggersNode["sides_combination_mode"]; + + config.vertexTimeLowThreshold = vertexTimeLowThresholdNode.GetInt(); + config.vertexTimeHighThreshold = vertexTimeHighThresholdNode.GetInt(); + config.semicentralA = semicentralANode.GetUint(); + config.semicentralC = semicentralCNode.GetUint(); + config.centralA = centralANode.GetUint(); + config.centralC = centralCNode.GetUint(); + config.sidesCombinationMode = sidesCombinationMode.GetUint(); +} +} // namespace o2::fdd \ No newline at end of file diff --git a/Detectors/FIT/FDD/dcsmonitoring/workflow/FDDDCSConfigProcessorSpec.h b/Detectors/FIT/FDD/dcsmonitoring/workflow/FDDDCSConfigProcessorSpec.h index b2844fc0ac95a..0b23e729415fc 100644 --- a/Detectors/FIT/FDD/dcsmonitoring/workflow/FDDDCSConfigProcessorSpec.h +++ b/Detectors/FIT/FDD/dcsmonitoring/workflow/FDDDCSConfigProcessorSpec.h @@ -17,7 +17,7 @@ #ifndef O2_FDD_DCSCONFIGPROCESSOR_H #define O2_FDD_DCSCONFIGPROCESSOR_H -#include "FITDCSMonitoring/FITDCSConfigProcessorSpec.h" +#include "FDDDCSMonitoring/FDDDCSConfigProcessor.h" #include "DetectorsCalibration/Utils.h" #include "Framework/WorkflowSpec.h" #include "Headers/DataHeader.h" @@ -30,7 +30,6 @@ namespace o2 namespace framework { - DataProcessorSpec getFDDDCSConfigProcessorSpec() { o2::header::DataDescription ddDChM = "FDD_DCHM"; @@ -38,16 +37,28 @@ DataProcessorSpec getFDDDCSConfigProcessorSpec() outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, ddDChM}, Lifetime::Sporadic); outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, ddDChM}, Lifetime::Sporadic); + o2::header::DataDescription ddFeeConfig = "FDD_FEE_CONFIG"; + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, ddFeeConfig}, Lifetime::Sporadic); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, ddFeeConfig}, Lifetime::Sporadic); + + o2::header::DataDescription ddHvConfig = "FDD_HV_CONFIG"; + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, ddHvConfig}, Lifetime::Sporadic); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, ddHvConfig}, Lifetime::Sporadic); + return DataProcessorSpec{ "fdd-dcs-config-processor", Inputs{{"inputConfig", o2::header::gDataOriginFDD, "DCS_CONFIG_FILE", Lifetime::Sporadic}, {"inputConfigFileName", o2::header::gDataOriginFDD, "DCS_CONFIG_NAME", Lifetime::Sporadic}}, outputs, - AlgorithmSpec{adaptFromTask("FDD", ddDChM)}, + AlgorithmSpec{adaptFromTask("FDD", ddDChM, ddFeeConfig, ddHvConfig)}, Options{{"use-verbose-mode", VariantType::Bool, false, {"Use verbose mode"}}, {"filename-dchm", VariantType::String, "FDD-deadchannels.txt", {"Dead channel map file name"}}, {"valid-days-dchm", VariantType::UInt32, 180u, {"Dead channel map validity in days"}}, - {"no-validate", VariantType::Bool, false, {"Don't validate the CCDB uploads"}}}}; + {"no-validate", VariantType::Bool, false, {"Don't validate the CCDB uploads"}}, + {"filename-fee-config", VariantType::String, "FDD-fee-config.json", {"FEE configuration file name"}}, + {"valid-days-fee-config", VariantType::UInt32, 180u, {"FEE configuration validity in days"}}, + {"filename-hv-config", VariantType::String, "FDD-hv-config.json", {"HV configuration file name"}}, + {"valid-days-hv-config", VariantType::UInt32, 180u, {"HV configuration validity in days"}}}}; } } // namespace framework diff --git a/Detectors/FIT/FT0/dcsmonitoring/CMakeLists.txt b/Detectors/FIT/FT0/dcsmonitoring/CMakeLists.txt index 3c8abdad32e6c..287fc5d5fee7a 100644 --- a/Detectors/FIT/FT0/dcsmonitoring/CMakeLists.txt +++ b/Detectors/FIT/FT0/dcsmonitoring/CMakeLists.txt @@ -10,11 +10,8 @@ # or submit itself to any jurisdiction. o2_add_library(FT0DCSMonitoring - SOURCES src/FT0DCSDataProcessor.cxx - PUBLIC_LINK_LIBRARIES O2::FITDCSMonitoring) - -o2_target_root_dictionary(FT0DCSMonitoring - HEADERS include/FT0DCSMonitoring/FT0DCSConfigReader.h) + SOURCES src/FT0DCSDataProcessor.cxx src/FT0DCSConfigProcessor.cxx src/FT0FEEConfigurationReader.cxx + PUBLIC_LINK_LIBRARIES O2::FITDCSMonitoring O2::DataFormatsFT0) o2_add_executable(dcs-sim-workflow COMPONENT_NAME ft0 diff --git a/Detectors/FIT/FT0/dcsmonitoring/include/FT0DCSMonitoring/FT0DCSConfigProcessor.h b/Detectors/FIT/FT0/dcsmonitoring/include/FT0DCSMonitoring/FT0DCSConfigProcessor.h new file mode 100644 index 0000000000000..589acaad5318e --- /dev/null +++ b/Detectors/FIT/FT0/dcsmonitoring/include/FT0DCSMonitoring/FT0DCSConfigProcessor.h @@ -0,0 +1,42 @@ +// 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. + +#ifndef O2_FT0_DCSCONFIGPROCESSOR_H +#define O2_FT0_DCSCONFIGPROCESSOR_H + +#include "FITDCSMonitoring/FITDCSConfigProcessor.h" +#include "FT0DCSMonitoring/FT0FEEConfigurationReader.h" +#include "FITDCSMonitoring/FITHvConfigurationReader.h" +#include "DetectorsCalibration/Utils.h" +#include "Framework/WorkflowSpec.h" +#include "Headers/DataHeader.h" + +#include +#include + +namespace o2::ft0 +{ +class FT0DCSConfigProcessor : public o2::fit::FITDCSConfigProcessor +{ + public: + FT0DCSConfigProcessor(const std::string& detectorName, const o2::header::DataDescription& dataDescriptionDChM, const o2::header::DataDescription& dataDescriptionFeeConfig, const o2::header::DataDescription& dataDescriptionHvConfig) + : o2::fit::FITDCSConfigProcessor(detectorName, dataDescriptionDChM, dataDescriptionFeeConfig, dataDescriptionHvConfig) {} + + void init(o2::framework::InitContext& ic) final; + void run(o2::framework::ProcessingContext& pc) final; + void endOfStream(o2::framework::EndOfStreamContext& ec) final; + + private: + FT0FEEConfigurationReader mFeeConfigurationReader; + o2::fit::FITHvConfigurationReader mHvConfigurationReader; +}; +} // namespace o2::ft0 +#endif // O2_FT0_DCSCONFIGPROCESSOR_H \ No newline at end of file diff --git a/Detectors/FIT/FT0/dcsmonitoring/include/FT0DCSMonitoring/FT0FEEConfigurationReader.h b/Detectors/FIT/FT0/dcsmonitoring/include/FT0DCSMonitoring/FT0FEEConfigurationReader.h new file mode 100644 index 0000000000000..e8955c616e5b3 --- /dev/null +++ b/Detectors/FIT/FT0/dcsmonitoring/include/FT0DCSMonitoring/FT0FEEConfigurationReader.h @@ -0,0 +1,29 @@ +// 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. + +#ifndef O2_FT0_DCSCONFIGREADER_H +#define O2_FT0_DCSCONFIGREADER_H + +#include "FITDCSMonitoring/FITFEEConfigurationReader.h" +#include "DataFormatsFT0/FeeConfiguration.h" + +namespace o2::ft0 +{ +class FT0FEEConfigurationReader : public o2::fit::FITFEEConfigurationReader +{ + public: + Ft0FeeConfiguration parseFeeConfiguration(gsl::span configBuf); + void parseTriggers(const rapidjson::Value& root, const char* triggersNodeName, TriggersConfig& config); +}; + +} // namespace o2::ft0 + +#endif // O2_FT0_DCSCONFIGREADER_H \ No newline at end of file diff --git a/Detectors/FIT/FT0/dcsmonitoring/macros/CMakeLists.txt b/Detectors/FIT/FT0/dcsmonitoring/macros/CMakeLists.txt index 9d4391d8f4084..3ee7472fcb04d 100644 --- a/Detectors/FIT/FT0/dcsmonitoring/macros/CMakeLists.txt +++ b/Detectors/FIT/FT0/dcsmonitoring/macros/CMakeLists.txt @@ -13,3 +13,9 @@ o2_add_test_root_macro(makeFT0CCDBEntryForDCS.C PUBLIC_LINK_LIBRARIES O2::CCDB O2::DetectorsDCS LABELS ft0) + +o2_add_test_root_macro(fetchFt0FeeConfig.C + PUBLIC_LINK_LIBRARIES + O2::CCDB + O2::DataFormatsFT0 + LABELS ft0) \ No newline at end of file diff --git a/Detectors/FIT/FT0/dcsmonitoring/macros/fetchFt0FeeConfig.C b/Detectors/FIT/FT0/dcsmonitoring/macros/fetchFt0FeeConfig.C new file mode 100644 index 0000000000000..8109dcb264d5c --- /dev/null +++ b/Detectors/FIT/FT0/dcsmonitoring/macros/fetchFt0FeeConfig.C @@ -0,0 +1,140 @@ +// 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. + +#if !defined(__CLING__) || defined(__ROOTCLING__) + +#include "CCDB/CcdbApi.h" +#include "DataFormatsFT0/FeeConfiguration.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#endif + +void fetchFt0FeeConfig(const std::string ccdbUrl = "http://alice-ccdb.cern.ch", long timestamp = -1, const std::string fileName = "ft0-fee-config.json", const std::string ccdbPath = "FT0/Config/FeeConfiguration") +{ + o2::ccdb::CcdbApi ccdbApi; + ccdbApi.init(ccdbUrl); + + std::map metadata; + std::unique_ptr config(ccdbApi.retrieveFromTFileAny(ccdbPath, metadata, timestamp)); + + if (!config) { + throw std::runtime_error("Cannot retrieve Ft0FeeConfiguration from CCDB path " + ccdbPath); + } + + rapidjson::Document doc; + doc.SetObject(); + auto& allocator = doc.GetAllocator(); + + rapidjson::Value channels(rapidjson::kObjectType); + rapidjson::Value timeAligments(rapidjson::kArrayType); + rapidjson::Value cfdThresholds(rapidjson::kArrayType); + rapidjson::Value cfdZeros(rapidjson::kArrayType); + rapidjson::Value adcZeros(rapidjson::kArrayType); + rapidjson::Value adcDelays(rapidjson::kArrayType); + rapidjson::Value rangeCorrectionAdc0(rapidjson::kArrayType); + rapidjson::Value rangeCorrectionAdc1(rapidjson::kArrayType); + rapidjson::Value channelMaskData(rapidjson::kArrayType); + rapidjson::Value channelMaskTriggers(rapidjson::kArrayType); + rapidjson::Value thresholdCalibration(rapidjson::kArrayType); + + for (int i = 0; i < o2::ft0::Ft0FeeConfiguration::NChannels; ++i) { + timeAligments.PushBack(config->channels.timeAligments[i], allocator); + cfdThresholds.PushBack(config->channels.cfdThresholds[i], allocator); + cfdZeros.PushBack(config->channels.cfdZeros[i], allocator); + adcZeros.PushBack(config->channels.adcZeros[i], allocator); + adcDelays.PushBack(config->channels.adcDelays[i], allocator); + rangeCorrectionAdc0.PushBack(config->channels.rangeCorrectionAdc0[i], allocator); + rangeCorrectionAdc1.PushBack(config->channels.rangeCorrectionAdc1[i], allocator); + channelMaskData.PushBack(config->channels.channelMaskData[i], allocator); + channelMaskTriggers.PushBack(config->channels.channelMaskTriggers[i], allocator); + thresholdCalibration.PushBack(config->channels.thresholdCalibration[i], allocator); + } + + channels.AddMember("time_aligments", timeAligments, allocator); + channels.AddMember("cfd_thresholds", cfdThresholds, allocator); + channels.AddMember("cfd_zeros", cfdZeros, allocator); + channels.AddMember("adc_zeros", adcZeros, allocator); + channels.AddMember("adc_delays", adcDelays, allocator); + channels.AddMember("range_correction_adc0", rangeCorrectionAdc0, allocator); + channels.AddMember("range_correction_adc1", rangeCorrectionAdc1, allocator); + channels.AddMember("channel_mask_data", channelMaskData, allocator); + channels.AddMember("channel_mask_triggers", channelMaskTriggers, allocator); + channels.AddMember("threshold_calibration", thresholdCalibration, allocator); + doc.AddMember("channels", channels, allocator); + + rapidjson::Value tcm(rapidjson::kObjectType); + tcm.AddMember("phase_delay_a", config->tcm.phaseDelayA, allocator); + tcm.AddMember("phase_delay_c", config->tcm.phaseDelayC, allocator); + doc.AddMember("tcm", tcm, allocator); + + rapidjson::Value pmA(rapidjson::kArrayType); + + for (int i = 0; i < 10; ++i) { + rapidjson::Value pm(rapidjson::kObjectType); + pm.AddMember("or_gate", config->pmA[i].orGate, allocator); + pm.AddMember("trg_charge_low_level", config->pmA[i].trgChargeLowLevel, allocator); + pm.AddMember("trg_charge_high_level", config->pmA[i].trgChargeHighLevel, allocator); + pmA.PushBack(pm, allocator); + } + doc.AddMember("pm_a", pmA, allocator); + + rapidjson::Value pmC(rapidjson::kArrayType); + for (int i = 0; i < 10; ++i) { + rapidjson::Value pm(rapidjson::kObjectType); + pm.AddMember("or_gate", config->pmC[i].orGate, allocator); + pm.AddMember("trg_charge_low_level", config->pmC[i].trgChargeLowLevel, allocator); + pm.AddMember("trg_charge_high_level", config->pmC[i].trgChargeHighLevel, allocator); + pmC.PushBack(pm, allocator); + } + doc.AddMember("pm_c", pmC, allocator); + + rapidjson::Value triggers(rapidjson::kObjectType); + triggers.AddMember("vertex_time_low_threshold", config->triggers.vertexTimeLowThreshold, allocator); + + triggers.AddMember("vertex_time_high_threshold", config->triggers.vertexTimeHighThreshold, allocator); + triggers.AddMember("semicentral_a", config->triggers.semicentralA, allocator); + triggers.AddMember("semicentral_c", config->triggers.semicentralC, allocator); + triggers.AddMember("central_a", config->triggers.centralA, allocator); + triggers.AddMember("central_c", config->triggers.centralC, allocator); + triggers.AddMember("sides_combination_mode", config->triggers.sidesCombinationMode, allocator); + doc.AddMember("triggers", triggers, allocator); + + rapidjson::StringBuffer buffer; + rapidjson::PrettyWriter writer(buffer); + + doc.Accept(writer); + + if (fileName.empty()) { + std::cout << buffer.GetString() << '\n'; + return; + } + + std::ofstream output(fileName); + + if (!output) { + throw std::runtime_error( + "Cannot open output file " + fileName); + } + + output << buffer.GetString() << '\n'; + + std::cout << "FT0 FEE configuration written to " << fileName << '\n'; +} diff --git a/Detectors/FIT/FT0/dcsmonitoring/src/FT0DCSConfigProcessor.cxx b/Detectors/FIT/FT0/dcsmonitoring/src/FT0DCSConfigProcessor.cxx new file mode 100644 index 0000000000000..f5000ae4cc638 --- /dev/null +++ b/Detectors/FIT/FT0/dcsmonitoring/src/FT0DCSConfigProcessor.cxx @@ -0,0 +1,54 @@ +// 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 "FT0DCSMonitoring/FT0DCSConfigProcessor.h" +#include "DataFormatsFT0/HvConfiguration.h" + +namespace o2::ft0 +{ +void FT0DCSConfigProcessor::init(o2::framework::InitContext& ic) +{ + initDeadChannelMapReader(); + setupDeadChannelMapReader(ic); + setupFeeConfigurationReader(ic, mFeeConfigurationReader); + setupHvConfigurationReader(ic, mHvConfigurationReader); +} + +void FT0DCSConfigProcessor::run(o2::framework::ProcessingContext& pc) +{ + try { + long dataTime = getValidityTime(pc); + + gsl::span dataBuffer = pc.inputs().get>("inputConfig"); + std::string configFileName = pc.inputs().get("inputConfigFileName"); + LOG(info) << "Got input file " << configFileName << " of size " << dataBuffer.size(); + if (!configFileName.compare(mDeadChannelMapReader->getFileNameDChM())) { + handleDeadChannelMapUpdate(pc, dataTime, dataBuffer); + } else if (mFeeConfigurationReader.matchFilename(configFileName)) { + Ft0FeeConfiguration feeConfiguration = mFeeConfigurationReader.parseFeeConfiguration(dataBuffer); + o2::ccdb::CcdbObjectInfo objectInfo = mFeeConfigCcdbInfo.createObjectInfo(feeConfiguration, dataTime, {}); + sendObject(pc.outputs(), feeConfiguration, objectInfo, getFeeConfigDescription()); + } else if (mHvConfigurationReader.matchFilename(configFileName)) { + Ft0HvConfiguration hvConfig = mHvConfigurationReader.parseHvConfiguration(dataBuffer); + o2::ccdb::CcdbObjectInfo objectInfo = mHvConfigCcdbInfo.createObjectInfo(hvConfig, dataTime, {}); + sendObject(pc.outputs(), hvConfig, objectInfo, getHvConfigDescription()); + } else { + LOG(error) << "Unknown input file: " << configFileName; + } + } catch (std::exception& e) { + LOG(error) << "Exception: " << e.what(); + } +} + +void FT0DCSConfigProcessor::endOfStream(o2::framework::EndOfStreamContext& ec) +{ +} +} // namespace o2::ft0 \ No newline at end of file diff --git a/Detectors/FIT/FT0/dcsmonitoring/src/FT0DCSMonitoringLinkDef.h b/Detectors/FIT/FT0/dcsmonitoring/src/FT0DCSMonitoringLinkDef.h index 50a9e7f35e25f..c85dd2d378ccb 100644 --- a/Detectors/FIT/FT0/dcsmonitoring/src/FT0DCSMonitoringLinkDef.h +++ b/Detectors/FIT/FT0/dcsmonitoring/src/FT0DCSMonitoringLinkDef.h @@ -15,6 +15,4 @@ #pragma link off all classes; #pragma link off all functions; -#pragma link C++ class o2::ft0::FT0DCSConfigReader + ; - #endif diff --git a/Detectors/FIT/FT0/dcsmonitoring/src/FT0FEEConfigurationReader.cxx b/Detectors/FIT/FT0/dcsmonitoring/src/FT0FEEConfigurationReader.cxx new file mode 100644 index 0000000000000..5303dc7d45991 --- /dev/null +++ b/Detectors/FIT/FT0/dcsmonitoring/src/FT0FEEConfigurationReader.cxx @@ -0,0 +1,70 @@ +// 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 "FT0DCSMonitoring/FT0FEEConfigurationReader.h" +#include +#include + +namespace o2::ft0 +{ +Ft0FeeConfiguration FT0FEEConfigurationReader::parseFeeConfiguration(gsl::span buffer) +{ + return FITFEEConfigurationReader::parseFeeConfiguration(buffer); +} + +void FT0FEEConfigurationReader::parseTriggers(const rapidjson::Value& root, const char* triggersNodeName, TriggersConfig& config) +{ + const auto& triggersNode = root["triggers"]; + + if (triggersNode.HasMember("vertex_time_low_threshold") == false) { + throw std::runtime_error("Missing vertex_time_low_threshold trigger node!"); + } + const auto& vertexTimeLowThresholdNode = triggersNode["vertex_time_low_threshold"]; + + if (triggersNode.HasMember("vertex_time_high_threshold") == false) { + throw std::runtime_error("Missing vertex_time_high_threshold trigger node!"); + } + const auto& vertexTimeHighThresholdNode = triggersNode["vertex_time_high_threshold"]; + + if (triggersNode.HasMember("semi_central_a") == false) { + throw std::runtime_error("Missing semi_central_a trigger node!"); + } + const auto& semicentralANode = triggersNode["semi_central_a"]; + + if (triggersNode.HasMember("semi_central_c") == false) { + throw std::runtime_error("Missing semi_central_c trigger node!"); + } + const auto& semicentralCNode = triggersNode["semi_central_c"]; + + if (triggersNode.HasMember("central_a") == false) { + throw std::runtime_error("Missing central_a trigger node!"); + } + const auto& centralANode = triggersNode["central_a"]; + + if (triggersNode.HasMember("central_c") == false) { + throw std::runtime_error("Missing central_c trigger node!"); + } + const auto& centralCNode = triggersNode["central_c"]; + + if (triggersNode.HasMember("sides_combination_mode") == false) { + throw std::runtime_error("Missing sides_combination_mode node!"); + } + const auto& sidesCombinationMode = triggersNode["sides_combination_mode"]; + + config.vertexTimeLowThreshold = vertexTimeLowThresholdNode.GetInt(); + config.vertexTimeHighThreshold = vertexTimeHighThresholdNode.GetInt(); + config.semicentralA = semicentralANode.GetUint(); + config.semicentralC = semicentralCNode.GetUint(); + config.centralA = centralANode.GetUint(); + config.centralC = centralCNode.GetUint(); + config.sidesCombinationMode = sidesCombinationMode.GetUint(); +} +} // namespace o2::ft0 \ No newline at end of file diff --git a/Detectors/FIT/FT0/dcsmonitoring/workflow/FT0DCSConfigProcessorSpec.h b/Detectors/FIT/FT0/dcsmonitoring/workflow/FT0DCSConfigProcessorSpec.h index fe6701344530b..fdd8ebc92b542 100644 --- a/Detectors/FIT/FT0/dcsmonitoring/workflow/FT0DCSConfigProcessorSpec.h +++ b/Detectors/FIT/FT0/dcsmonitoring/workflow/FT0DCSConfigProcessorSpec.h @@ -14,11 +14,10 @@ /// /// \author Andreas Molander , University of Jyvaskyla, Finland -#ifndef O2_FT0_DCSCONFIGPROCESSOR_H -#define O2_FT0_DCSCONFIGPROCESSOR_H +#ifndef O2_FT0_DCSCONFIGPROCESSOR_SPEC_H +#define O2_FT0_DCSCONFIGPROCESSOR_SPEC_H -#include "FITDCSMonitoring/FITDCSConfigProcessorSpec.h" -#include "FT0DCSMonitoring/FT0DCSConfigReader.h" +#include "FT0DCSMonitoring/FT0DCSConfigProcessor.h" #include "DetectorsCalibration/Utils.h" #include "Framework/WorkflowSpec.h" #include "Headers/DataHeader.h" @@ -26,30 +25,8 @@ #include #include -namespace o2 +namespace o2::framework { -namespace ft0 -{ - -class FT0DCSConfigProcessor : public o2::fit::FITDCSConfigProcessor -{ - // Example of how to use another DCS config reader (subclass of o2::fit::FITDCSConfigReader) - public: - FT0DCSConfigProcessor(const std::string& detectorName, const o2::header::DataDescription& dataDescriptionDChM) - : o2::fit::FITDCSConfigProcessor(detectorName, dataDescriptionDChM) {} - - protected: - void initDCSConfigReader() override - { - mDCSConfigReader = std::make_unique(FT0DCSConfigReader()); - } -}; - -} // namespace ft0 - -namespace framework -{ - DataProcessorSpec getFT0DCSConfigProcessorSpec() { o2::header::DataDescription ddDChM = "FT0_DCHM"; @@ -57,19 +34,30 @@ DataProcessorSpec getFT0DCSConfigProcessorSpec() outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, ddDChM}, Lifetime::Sporadic); outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, ddDChM}, Lifetime::Sporadic); + o2::header::DataDescription ddFeeConfig = "FT0_FEE_CONFIG"; + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, ddFeeConfig}, Lifetime::Sporadic); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, ddFeeConfig}, Lifetime::Sporadic); + + o2::header::DataDescription ddHvConfig = "FT0_HV_CONFIG"; + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, ddHvConfig}, Lifetime::Sporadic); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, ddHvConfig}, Lifetime::Sporadic); + return DataProcessorSpec{ "ft0-dcs-config-processor", Inputs{{"inputConfig", o2::header::gDataOriginFT0, "DCS_CONFIG_FILE", Lifetime::Sporadic}, {"inputConfigFileName", o2::header::gDataOriginFT0, "DCS_CONFIG_NAME", Lifetime::Sporadic}}, outputs, - AlgorithmSpec{adaptFromTask("FT0", ddDChM)}, + AlgorithmSpec{adaptFromTask("FT0", ddDChM, ddFeeConfig, ddHvConfig)}, Options{{"use-verbose-mode", VariantType::Bool, false, {"Use verbose mode"}}, {"filename-dchm", VariantType::String, "FT0-deadchannels.txt", {"Dead channel map file name"}}, {"valid-days-dchm", VariantType::UInt32, 180u, {"Dead channel map validity in days"}}, - {"no-validate", VariantType::Bool, false, {"Don't validate the CCDB uploads"}}}}; + {"no-validate", VariantType::Bool, false, {"Don't validate the CCDB uploads"}}, + {"filename-fee-config", VariantType::String, "FT0-fee-config.json", {"FEE configuration file name"}}, + {"valid-days-fee-config", VariantType::UInt32, 180u, {"FEE configuration validity in days"}}, + {"filename-hv-config", VariantType::String, "FT0-hv-config.json", {"HV configuration file name"}}, + {"valid-days-hv-config", VariantType::UInt32, 180u, {"HV configuration validity in days"}}}}; } -} // namespace framework -} // namespace o2 +} // namespace o2::framework -#endif // O2_FT0_DCSCONFIGPROCESSOR_H +#endif // O2_FT0_DCSCONFIGPROCESSOR_SPEC_H diff --git a/Detectors/FIT/FT0/macros/CMakeLists.txt b/Detectors/FIT/FT0/macros/CMakeLists.txt index 17491ca4962c1..27c5891e864f2 100644 --- a/Detectors/FIT/FT0/macros/CMakeLists.txt +++ b/Detectors/FIT/FT0/macros/CMakeLists.txt @@ -18,4 +18,4 @@ o2_add_test_root_macro(FT0readEventsPerBc.C PUBLIC_LINK_LIBRARIES O2::CCDB O2::DataFormatsFT0 - LABELS ft0) + LABELS ft0) \ No newline at end of file diff --git a/Detectors/FIT/FV0/dcsmonitoring/CMakeLists.txt b/Detectors/FIT/FV0/dcsmonitoring/CMakeLists.txt index 7508e24fc069c..a036cdb4296a1 100644 --- a/Detectors/FIT/FV0/dcsmonitoring/CMakeLists.txt +++ b/Detectors/FIT/FV0/dcsmonitoring/CMakeLists.txt @@ -10,8 +10,8 @@ # or submit itself to any jurisdiction. o2_add_library(FV0DCSMonitoring - SOURCES src/FV0DCSDataProcessor.cxx - PUBLIC_LINK_LIBRARIES O2::FITDCSMonitoring) + SOURCES src/FV0DCSDataProcessor.cxx src/FV0DCSConfigProcessor.cxx src/FV0FEEConfigurationReader.cxx + PUBLIC_LINK_LIBRARIES O2::FITDCSMonitoring O2::DataFormatsFV0) o2_add_executable(dcs-sim-workflow COMPONENT_NAME fv0 @@ -30,4 +30,5 @@ o2_add_executable(dcs-config-workflow SOURCES workflow/fv0-dcs-config-workflow.cxx PUBLIC_LINK_LIBRARIES O2::DetectorsCalibration O2::FITDCSMonitoring - O2::Framework) + O2::Framework + O2::FV0DCSMonitoring) diff --git a/Detectors/FIT/FV0/dcsmonitoring/include/FV0DCSMonitoring/FV0DCSConfigProcessor.h b/Detectors/FIT/FV0/dcsmonitoring/include/FV0DCSMonitoring/FV0DCSConfigProcessor.h new file mode 100644 index 0000000000000..e69190e327ce1 --- /dev/null +++ b/Detectors/FIT/FV0/dcsmonitoring/include/FV0DCSMonitoring/FV0DCSConfigProcessor.h @@ -0,0 +1,37 @@ +// 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. + +/// \author Wiktor Pierożak , AGH University of Krakow, Poland + +#ifndef O2_FV0_DCS_CONFIG_PROCESSOR_H +#define O2_FV0_DCS_CONFIG_PROCESSOR_H +#include "FITDCSMonitoring/FITDCSConfigProcessor.h" +#include "FV0DCSMonitoring/FV0FEEConfigurationReader.h" +#include "FITDCSMonitoring/FITHvConfigurationReader.h" + +namespace o2::fv0 +{ +class FV0DCSConfigProcessor : public o2::fit::FITDCSConfigProcessor +{ + public: + FV0DCSConfigProcessor(const std::string& detectorName, const o2::header::DataDescription& dataDescriptionDChM, const o2::header::DataDescription& dataDescriptionFeeConfig, const o2::header::DataDescription& dataDescriptionHvConfig) + : o2::fit::FITDCSConfigProcessor(detectorName, dataDescriptionDChM, dataDescriptionFeeConfig, dataDescriptionHvConfig) {} + + void init(o2::framework::InitContext& ic) final; + void run(o2::framework::ProcessingContext& pc) final; + void endOfStream(o2::framework::EndOfStreamContext& ec) final; + + private: + FV0FEEConfigurationReader mFeeConfigurationReader; + o2::fit::FITHvConfigurationReader mHvConfigurationReader; +}; +} // namespace o2::fv0 +#endif \ No newline at end of file diff --git a/Detectors/FIT/FT0/dcsmonitoring/include/FT0DCSMonitoring/FT0DCSConfigReader.h b/Detectors/FIT/FV0/dcsmonitoring/include/FV0DCSMonitoring/FV0FEEConfigurationReader.h similarity index 51% rename from Detectors/FIT/FT0/dcsmonitoring/include/FT0DCSMonitoring/FT0DCSConfigReader.h rename to Detectors/FIT/FV0/dcsmonitoring/include/FV0DCSMonitoring/FV0FEEConfigurationReader.h index 8c8a216ac65b0..8f0e110741dc9 100644 --- a/Detectors/FIT/FT0/dcsmonitoring/include/FT0DCSMonitoring/FT0DCSConfigReader.h +++ b/Detectors/FIT/FV0/dcsmonitoring/include/FV0DCSMonitoring/FV0FEEConfigurationReader.h @@ -14,30 +14,21 @@ /// /// \author Andreas Molander , University of Jyvaskyla, Finland -#ifndef O2_FT0_DCSCONFIGREADER_H -#define O2_FT0_DCSCONFIGREADER_H +#ifndef O2_FV0_DCSCONFIGREADER_H +#define O2_FV0_DCSCONFIGREADER_H -#include "FITDCSMonitoring/FITDCSConfigReader.h" -#include "Rtypes.h" +#include "FITDCSMonitoring/FITFEEConfigurationReader.h" +#include "DataFormatsFV0/FeeConfiguration.h" -namespace o2 +namespace o2::fv0 { -namespace ft0 +class FV0FEEConfigurationReader : public o2::fit::FITFEEConfigurationReader { - -/// DCS configuration reader for FT0 -/// -/// At the moment this class doesn't differ from the base class o2::fit::FITDCSConfigReader, -/// which makes it obsolete. It exists only as an example for how to create detector specific -/// DCS configuration readers later. -class FT0DCSConfigReader : public o2::fit::FITDCSConfigReader -{ - // For FT0 specific processing of DCS configurations, override base class methods here. - - ClassDefNV(FT0DCSConfigReader, 0); + public: + Fv0FeeConfiguration parseFeeConfiguration(gsl::span configBuf); + void parseTriggers(const rapidjson::Value& root, const char* triggersNodeName, TriggersConfig& config); }; -} // namespace ft0 -} // namespace o2 +} // namespace o2::fv0 -#endif // O2_FT0_DCSCONFIGREADER_H \ No newline at end of file +#endif // O2_FV0_DCSCONFIGREADER_H \ No newline at end of file diff --git a/Detectors/FIT/FV0/dcsmonitoring/macros/CMakeLists.txt b/Detectors/FIT/FV0/dcsmonitoring/macros/CMakeLists.txt index 446f01dde8ffe..bfa2ed0e72b8d 100644 --- a/Detectors/FIT/FV0/dcsmonitoring/macros/CMakeLists.txt +++ b/Detectors/FIT/FV0/dcsmonitoring/macros/CMakeLists.txt @@ -13,3 +13,9 @@ o2_add_test_root_macro(makeFV0CCDBEntryForDCS.C PUBLIC_LINK_LIBRARIES O2::CCDB O2::DetectorsDCS LABELS fv0) + +o2_add_test_root_macro(fetchFv0FeeConfig.C + PUBLIC_LINK_LIBRARIES + O2::CCDB + O2::DataFormatsFV0 + LABELS fv0) \ No newline at end of file diff --git a/Detectors/FIT/FV0/dcsmonitoring/macros/fetchFv0FeeConfig.C b/Detectors/FIT/FV0/dcsmonitoring/macros/fetchFv0FeeConfig.C new file mode 100644 index 0000000000000..fcf1f5558855f --- /dev/null +++ b/Detectors/FIT/FV0/dcsmonitoring/macros/fetchFv0FeeConfig.C @@ -0,0 +1,125 @@ +// 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. + +#if !defined(__CLING__) || defined(__ROOTCLING__) + +#include "CCDB/CcdbApi.h" +#include "DataFormatsFV0/FeeConfiguration.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#endif + +void fetchFv0FeeConfig(const std::string ccdbUrl = "http://alice-ccdb.cern.ch", long timestamp = -1, const std::string fileName = "fv0-fee-config.json", const std::string ccdbPath = "FV0/Config/FeeConfiguration") +{ + o2::ccdb::CcdbApi ccdbApi; + ccdbApi.init(ccdbUrl); + + std::map metadata; + std::unique_ptr config(ccdbApi.retrieveFromTFileAny(ccdbPath, metadata, timestamp)); + + if (!config) { + throw std::runtime_error("Cannot retrieve Fv0FeeConfiguration from CCDB path " + ccdbPath); + } + + rapidjson::Document doc; + doc.SetObject(); + auto& allocator = doc.GetAllocator(); + + rapidjson::Value channels(rapidjson::kObjectType); + rapidjson::Value timeAligments(rapidjson::kArrayType); + rapidjson::Value cfdThresholds(rapidjson::kArrayType); + rapidjson::Value cfdZeros(rapidjson::kArrayType); + rapidjson::Value adcZeros(rapidjson::kArrayType); + rapidjson::Value adcDelays(rapidjson::kArrayType); + rapidjson::Value rangeCorrectionAdc0(rapidjson::kArrayType); + rapidjson::Value rangeCorrectionAdc1(rapidjson::kArrayType); + rapidjson::Value channelMaskData(rapidjson::kArrayType); + rapidjson::Value channelMaskTriggers(rapidjson::kArrayType); + rapidjson::Value thresholdCalibration(rapidjson::kArrayType); + + for (int i = 0; i < o2::fv0::Fv0FeeConfiguration::NChannels; ++i) { + timeAligments.PushBack(config->channels.timeAligments[i], allocator); + cfdThresholds.PushBack(config->channels.cfdThresholds[i], allocator); + cfdZeros.PushBack(config->channels.cfdZeros[i], allocator); + adcZeros.PushBack(config->channels.adcZeros[i], allocator); + adcDelays.PushBack(config->channels.adcDelays[i], allocator); + rangeCorrectionAdc0.PushBack(config->channels.rangeCorrectionAdc0[i], allocator); + rangeCorrectionAdc1.PushBack(config->channels.rangeCorrectionAdc1[i], allocator); + channelMaskData.PushBack(config->channels.channelMaskData[i], allocator); + channelMaskTriggers.PushBack(config->channels.channelMaskTriggers[i], allocator); + thresholdCalibration.PushBack(config->channels.thresholdCalibration[i], allocator); + } + + channels.AddMember("time_aligments", timeAligments, allocator); + channels.AddMember("cfd_thresholds", cfdThresholds, allocator); + channels.AddMember("cfd_zeros", cfdZeros, allocator); + channels.AddMember("adc_zeros", adcZeros, allocator); + channels.AddMember("adc_delays", adcDelays, allocator); + channels.AddMember("range_correction_adc0", rangeCorrectionAdc0, allocator); + channels.AddMember("range_correction_adc1", rangeCorrectionAdc1, allocator); + channels.AddMember("channel_mask_data", channelMaskData, allocator); + channels.AddMember("channel_mask_triggers", channelMaskTriggers, allocator); + channels.AddMember("threshold_calibration", thresholdCalibration, allocator); + doc.AddMember("channels", channels, allocator); + + rapidjson::Value tcm(rapidjson::kObjectType); + tcm.AddMember("phase_delay_a", config->tcm.phaseDelayA, allocator); + tcm.AddMember("phase_delay_c", config->tcm.phaseDelayC, allocator); + doc.AddMember("tcm", tcm, allocator); + + rapidjson::Value pmA(rapidjson::kArrayType); + + for (int i = 0; i < 10; ++i) { + rapidjson::Value pm(rapidjson::kObjectType); + pm.AddMember("or_gate", config->pmA[i].orGate, allocator); + pm.AddMember("trg_charge_low_level", config->pmA[i].trgChargeLowLevel, allocator); + pm.AddMember("trg_charge_high_level", config->pmA[i].trgChargeHighLevel, allocator); + pmA.PushBack(pm, allocator); + } + doc.AddMember("pm_a", pmA, allocator); + + rapidjson::Value triggers(rapidjson::kObjectType); + triggers.AddMember("n_channels_level", config->triggers.nChannels, allocator); + triggers.AddMember("inner_rings_level", config->triggers.innerRings, allocator); + triggers.AddMember("charge_level", config->triggers.charge, allocator); + triggers.AddMember("outer_rings_level", config->triggers.outerRings, allocator); + doc.AddMember("triggers", triggers, allocator); + + rapidjson::StringBuffer buffer; + rapidjson::PrettyWriter writer(buffer); + + doc.Accept(writer); + + if (fileName.empty()) { + std::cout << buffer.GetString() << '\n'; + return; + } + + std::ofstream output(fileName); + + if (!output) { + throw std::runtime_error( + "Cannot open output file " + fileName); + } + + output << buffer.GetString() << '\n'; + std::cout << "FV0 FEE configuration written to " << fileName << '\n'; +} diff --git a/Detectors/FIT/FV0/dcsmonitoring/src/FV0DCSConfigProcessor.cxx b/Detectors/FIT/FV0/dcsmonitoring/src/FV0DCSConfigProcessor.cxx new file mode 100644 index 0000000000000..4eaf335917629 --- /dev/null +++ b/Detectors/FIT/FV0/dcsmonitoring/src/FV0DCSConfigProcessor.cxx @@ -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. + +#include "FV0DCSMonitoring/FV0DCSConfigProcessor.h" +#include "DataFormatsFV0/HvConfiguration.h" +#include "DataFormatsFV0/FeeConfiguration.h" + +namespace o2::fv0 +{ +void FV0DCSConfigProcessor::init(o2::framework::InitContext& ic) +{ + initDeadChannelMapReader(); + setupDeadChannelMapReader(ic); + setupFeeConfigurationReader(ic, mFeeConfigurationReader); + setupHvConfigurationReader(ic, mHvConfigurationReader); +} + +void FV0DCSConfigProcessor::run(o2::framework::ProcessingContext& pc) +{ + try { + long dataTime = getValidityTime(pc); + + gsl::span dataBuffer = pc.inputs().get>("inputConfig"); + std::string configFileName = pc.inputs().get("inputConfigFileName"); + LOG(info) << "Got input file " << configFileName << " of size " << dataBuffer.size(); + + if (!configFileName.compare(mDeadChannelMapReader->getFileNameDChM())) { + handleDeadChannelMapUpdate(pc, dataTime, dataBuffer); + } else if (mFeeConfigurationReader.matchFilename(configFileName)) { + Fv0FeeConfiguration feeConfiguration = mFeeConfigurationReader.parseFeeConfiguration(dataBuffer); + o2::ccdb::CcdbObjectInfo objectInfo = mFeeConfigCcdbInfo.createObjectInfo(feeConfiguration, dataTime, {}); + sendObject(pc.outputs(), feeConfiguration, objectInfo, getFeeConfigDescription()); + } else if (mHvConfigurationReader.matchFilename(configFileName)) { + Fv0HvConfiguration hvConfig = mHvConfigurationReader.parseHvConfiguration(dataBuffer); + o2::ccdb::CcdbObjectInfo objectInfo = mHvConfigCcdbInfo.createObjectInfo(hvConfig, dataTime, {}); + sendObject(pc.outputs(), hvConfig, objectInfo, getHvConfigDescription()); + } else { + LOG(error) << "Unknown input file: " << configFileName; + } + } catch (std::exception& e) { + LOG(error) << "Exception: " << e.what(); + } +} + +void FV0DCSConfigProcessor::endOfStream(o2::framework::EndOfStreamContext& ec) +{ +} +} // namespace o2::fv0 \ No newline at end of file diff --git a/Detectors/FIT/FV0/dcsmonitoring/src/FV0FEEConfigurationReader.cxx b/Detectors/FIT/FV0/dcsmonitoring/src/FV0FEEConfigurationReader.cxx new file mode 100644 index 0000000000000..459d9a8a5ed86 --- /dev/null +++ b/Detectors/FIT/FV0/dcsmonitoring/src/FV0FEEConfigurationReader.cxx @@ -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. + +#include "FV0DCSMonitoring/FV0FEEConfigurationReader.h" + +namespace o2::fv0 +{ +Fv0FeeConfiguration FV0FEEConfigurationReader::parseFeeConfiguration(gsl::span configBuf) +{ + return FITFEEConfigurationReader::parseFeeConfiguration(configBuf); +} + +void FV0FEEConfigurationReader::parseTriggers(const rapidjson::Value& root, const char* triggersNodeName, TriggersConfig& config) +{ + const auto& triggersNode = root["triggers"]; + + if (triggersNode.HasMember("n_channels_level") == false) { + throw std::runtime_error("Missing n_channels_level trigger node!"); + } + const auto& nChannelsLevelNode = triggersNode["n_channels_level"]; + + if (triggersNode.HasMember("inner_rings_level") == false) { + throw std::runtime_error("Missing inner_rings_level trigger node!"); + } + const auto& innerRingsLevelNode = triggersNode["inner_rings_level"]; + + if (triggersNode.HasMember("charge_level") == false) { + throw std::runtime_error("Missing charge_level trigger node!"); + } + const auto& chargeLevelNode = triggersNode["charge_level"]; + + if (triggersNode.HasMember("outer_rings_level") == false) { + throw std::runtime_error("Missing outer_rings_level trigger node!"); + } + const auto& outerRingsLevelNode = triggersNode["outer_rings_level"]; + + if (triggersNode.HasMember("sides_combination_mode") == false) { + throw std::runtime_error("Missing sides_combination_mode node!"); + } + const auto& sidesCombinationMode = triggersNode["sides_combination_mode"]; + + config.innerRings = innerRingsLevelNode.GetInt(); + config.nChannels = nChannelsLevelNode.GetInt(); + config.charge = chargeLevelNode.GetInt(); + config.outerRings = chargeLevelNode.GetInt(); + config.sidesCombinationMode = sidesCombinationMode.GetUint(); +} +} // namespace o2::fv0 \ No newline at end of file diff --git a/Detectors/FIT/FV0/dcsmonitoring/workflow/FV0DCSConfigProcessorSpec.h b/Detectors/FIT/FV0/dcsmonitoring/workflow/FV0DCSConfigProcessorSpec.h index 7c5a888312713..c178c7c1e8d64 100644 --- a/Detectors/FIT/FV0/dcsmonitoring/workflow/FV0DCSConfigProcessorSpec.h +++ b/Detectors/FIT/FV0/dcsmonitoring/workflow/FV0DCSConfigProcessorSpec.h @@ -17,7 +17,7 @@ #ifndef O2_FV0_DCSCONFIGPROCESSOR_H #define O2_FV0_DCSCONFIGPROCESSOR_H -#include "FITDCSMonitoring/FITDCSConfigProcessorSpec.h" +#include "FV0DCSMonitoring/FV0DCSConfigProcessor.h" #include "DetectorsCalibration/Utils.h" #include "Framework/WorkflowSpec.h" #include "Headers/DataHeader.h" @@ -30,7 +30,6 @@ namespace o2 namespace framework { - DataProcessorSpec getFV0DCSConfigProcessorSpec() { o2::header::DataDescription ddDChM = "FV0_DCHM"; @@ -38,16 +37,28 @@ DataProcessorSpec getFV0DCSConfigProcessorSpec() outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, ddDChM}, Lifetime::Sporadic); outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, ddDChM}, Lifetime::Sporadic); + o2::header::DataDescription ddFeeConfig = "FV0_FEE_CONFIG"; + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, ddFeeConfig}, Lifetime::Sporadic); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, ddFeeConfig}, Lifetime::Sporadic); + + o2::header::DataDescription ddHvConfig = "FV0_HV_CONFIG"; + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, ddHvConfig}, Lifetime::Sporadic); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, ddHvConfig}, Lifetime::Sporadic); + return DataProcessorSpec{ "fv0-dcs-config-processor", Inputs{{"inputConfig", o2::header::gDataOriginFV0, "DCS_CONFIG_FILE", Lifetime::Sporadic}, {"inputConfigFileName", o2::header::gDataOriginFV0, "DCS_CONFIG_NAME", Lifetime::Sporadic}}, outputs, - AlgorithmSpec{adaptFromTask("FV0", ddDChM)}, + AlgorithmSpec{adaptFromTask("FV0", ddDChM, ddFeeConfig, ddHvConfig)}, Options{{"use-verbose-mode", VariantType::Bool, false, {"Use verbose mode"}}, {"filename-dchm", VariantType::String, "FV0-deadchannels.txt", {"Dead channel map file name"}}, {"valid-days-dchm", VariantType::UInt32, 180u, {"Dead channel map validity in days"}}, - {"no-validate", VariantType::Bool, false, {"Don't validate the CCDB uploads"}}}}; + {"no-validate", VariantType::Bool, false, {"Don't validate the CCDB uploads"}}, + {"filename-fee-config", VariantType::String, "FV0-fee-config.json", {"FEE configuration file name"}}, + {"valid-days-fee-config", VariantType::UInt32, 180u, {"FEE configuration validity in days"}}, + {"filename-hv-config", VariantType::String, "FV0-hv-config.json", {"HV configuration file name"}}, + {"valid-days-hv-config", VariantType::UInt32, 180u, {"HV configuration validity in days"}}}}; } } // namespace framework diff --git a/Detectors/FIT/common/CMakeLists.txt b/Detectors/FIT/common/CMakeLists.txt index 1066814a6cbaa..3a3949f3df442 100644 --- a/Detectors/FIT/common/CMakeLists.txt +++ b/Detectors/FIT/common/CMakeLists.txt @@ -13,4 +13,5 @@ add_subdirectory(calibration) add_subdirectory(dcsmonitoring) if(BUILD_TESTING) add_subdirectory(dcsmonitoring/macros) + add_subdirectory(tests) endif() diff --git a/Detectors/FIT/common/dcsmonitoring/CMakeLists.txt b/Detectors/FIT/common/dcsmonitoring/CMakeLists.txt index 7bc0820e77a00..248c52a810b30 100644 --- a/Detectors/FIT/common/dcsmonitoring/CMakeLists.txt +++ b/Detectors/FIT/common/dcsmonitoring/CMakeLists.txt @@ -10,14 +10,15 @@ # or submit itself to any jurisdiction. o2_add_library(FITDCSMonitoring - SOURCES src/FITDCSConfigReader.cxx - src/FITDCSDataProcessor.cxx + SOURCES src/FITDCSDataProcessor.cxx src/FITDCSDataReader.cxx + src/FITDeadChannelMapReader.cxx + src/FITDCSConfigProcessor.cxx + src/FITDCSBaseConfigReader.cxx PUBLIC_LINK_LIBRARIES O2::DataFormatsFIT O2::DetectorsCalibration O2::DetectorsDCS) # TODO AM: remove include/FITDCSMonitoring/FITDCSDataReader.h when dictionaries are created in DataFormatsFIT instead o2_target_root_dictionary(FITDCSMonitoring - HEADERS include/FITDCSMonitoring/FITDCSConfigReader.h - include/FITDCSMonitoring/FITDCSDataReader.h) + HEADERS include/FITDCSMonitoring/FITDCSDataReader.h) diff --git a/Detectors/FIT/common/dcsmonitoring/include/FITDCSMonitoring/DcsCcdbInfo.h b/Detectors/FIT/common/dcsmonitoring/include/FITDCSMonitoring/DcsCcdbInfo.h new file mode 100644 index 0000000000000..4cde419046d83 --- /dev/null +++ b/Detectors/FIT/common/dcsmonitoring/include/FITDCSMonitoring/DcsCcdbInfo.h @@ -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. + +#ifndef O2_FIT_DCS_VALIDITY_H +#define O2_FIT_DCS_VALIDITY_H + +#include "CCDB/CcdbApi.h" + +namespace o2::fit +{ +class DcsCcdbInfo +{ + public: + DcsCcdbInfo(long validityInDays) : mValidityDays(validityInDays) {} + + long getValidityTimestamp(long startTimestamp) const + { + return startTimestamp + mValidityDays * o2::ccdb::CcdbObjectInfo::DAY; + } + + void setValidityPeriodInDays(long days) + { + mValidityDays = days; + } + + long getValidityPeriodInDays() const + { + return mValidityDays; + } + + void setValidateUpload(bool validate) + { + mValidateUpload = validate; + } + + bool getValidateUpload() const + { + return mValidateUpload; + } + + void setCcdbPath(const std::string path) + { + mCcdbPath = path; + } + + const std::string& getCcdbPath() const + { + return mCcdbPath; + } + + template + o2::ccdb::CcdbObjectInfo createObjectInfo(const DcsConfigType& configObject, long startValidityTimestamp, const std::map& metadata) + { + o2::ccdb::CcdbObjectInfo objectInfo; + o2::calibration::Utils::prepareCCDBobjectInfo(configObject, objectInfo, mCcdbPath, metadata, startValidityTimestamp, getValidityTimestamp(startValidityTimestamp)); + objectInfo.setValidateUpload(mValidateUpload); + return objectInfo; + } + + private: + long mValidityDays; + bool mValidateUpload; + std::string mCcdbPath; +}; +} // namespace o2::fit +#endif \ No newline at end of file diff --git a/Detectors/FIT/common/dcsmonitoring/include/FITDCSMonitoring/FITDCSBaseConfigReader.h b/Detectors/FIT/common/dcsmonitoring/include/FITDCSMonitoring/FITDCSBaseConfigReader.h new file mode 100644 index 0000000000000..045a1eb4ee6b6 --- /dev/null +++ b/Detectors/FIT/common/dcsmonitoring/include/FITDCSMonitoring/FITDCSBaseConfigReader.h @@ -0,0 +1,94 @@ +// 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. + +#ifndef O2_FIT_DCS_BASE_CONFIG_READER_H +#define O2_FIT_DCS_BASE_CONFIG_READER_H + +#include +#include +#include +#include "DetectorsCalibration/Utils.h" + +namespace o2::fit +{ +class FITDCSBaseConfigReader +{ + public: + virtual ~FITDCSBaseConfigReader() = default; + template + void parseJsonArray(const rapidjson::Value& node, const char* childName, T (&array)[Size]) + { + if (node.HasMember(childName) == false) { + throw std::runtime_error(std::string("Failed to find node of name ") + childName); + } + const auto& childNode = node[childName]; + if (childNode.IsArray() == false) { + throw std::runtime_error(std::format("Node {} is not an array!", childName)); + } + auto jsonArray = childNode.GetArray(); + if (jsonArray.Size() != Size) { + throw std::runtime_error(std::format("Array {}. Expected array of size {}, parsed array of size {}", childName, Size, jsonArray.Size())); + } + for (int idx = 0; idx < Size; idx++) { + const auto& node = jsonArray[idx]; + if constexpr (std::is_same_v) { + if (!node.IsBool()) { + throw std::runtime_error(std::format("{} is not a bool array", childName)); + } + array[idx] = node.GetBool(); + } else if constexpr (std::is_floating_point_v) { + if (!node.IsNumber()) { + throw std::runtime_error(std::format("{} is not an floating point array", childName)); + } + array[idx] = node.GetFloat(); + } else if constexpr (std::is_integral_v && std::is_unsigned_v) { + if (!node.IsUint()) { + throw std::runtime_error(std::format("{} is not an unsigned integer array", childName)); + } + array[idx] = static_cast(node.GetUint()); + } else if constexpr (std::is_integral_v) { + if (!node.IsInt()) { + throw std::runtime_error(std::format("{} is not an integer array", childName)); + } + array[idx] = static_cast(node.GetInt()); + } else { + static_assert(std::is_same_v, "Unsupported type"); + } + } + } + + void setFilename(const std::string& filename) + { + mFilename = filename; + } + + const std::string& getFilename() const + { + return mFilename; + } + + bool matchFilename(const std::string& filename) + { + return mFilename == filename; + } + + bool validateSchema(const rapidjson::Document& docs, std::string& errorMessage); + + protected: + void loadSchema(std::string_view schema); + rapidjson::Document parseJsonBuffer(gsl::span buffer, bool throwOnInvalidSchema = true); + + private: + std::string mFilename; + std::unique_ptr mSchema; +}; +} // namespace o2::fit +#endif \ No newline at end of file diff --git a/Detectors/FIT/common/dcsmonitoring/include/FITDCSMonitoring/FITDCSConfigProcessor.h b/Detectors/FIT/common/dcsmonitoring/include/FITDCSMonitoring/FITDCSConfigProcessor.h new file mode 100644 index 0000000000000..3031076fc3ec1 --- /dev/null +++ b/Detectors/FIT/common/dcsmonitoring/include/FITDCSMonitoring/FITDCSConfigProcessor.h @@ -0,0 +1,114 @@ +// 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 FITDCSConfigProcessorSpec.cxx +/// \brief FIT processor spec for DCS configurations +/// +/// \author Andreas Molander , University of Jyvaskyla, Finland + +#ifndef O2_FIT_DCSCONFIGPROCESSORSPEC_H +#define O2_FIT_DCSCONFIGPROCESSORSPEC_H + +#include "CCDB/CcdbApi.h" +#include "DetectorsCalibration/Utils.h" +#include "FITDCSMonitoring/FITDeadChannelMapReader.h" +#include "FITDCSMonitoring/FITFEEConfigurationReader.h" +#include "FITDCSMonitoring/FITHvConfigurationReader.h" +#include "FITDCSMonitoring/DcsCcdbInfo.h" + +#include "Framework/ConfigParamRegistry.h" +#include "Framework/Task.h" +#include "Framework/WorkflowSpec.h" + +#include +#include +#include +#include +#include + +namespace o2 +{ +namespace fit +{ + +class FITDCSConfigProcessor : public o2::framework::Task +{ + public: + FITDCSConfigProcessor(const std::string& detectorName, const o2::header::DataDescription& dataDescriptionDChM, const o2::header::DataDescription& dataDescriptionFeeConfig, const o2::header::DataDescription& dataDescriptionHvConfig) + : mDetectorName(detectorName), + mDataDescriptionDChM(dataDescriptionDChM), + mDataDescriptionFeeConfig(dataDescriptionFeeConfig), + mDataDescriptionHvConfig(dataDescriptionHvConfig) {} // TODO AM: how to pass dd + + protected: + /// Initializes the DCS config reader. + /// Can be overriden in case another reader (subclass of o2::fit::FITDeadChannelMapReader) is needed. + virtual void initDeadChannelMapReader(); + + long getValidityTime(o2::framework::ProcessingContext& pc); + + void setupDeadChannelMapReader(o2::framework::InitContext& ic); + + template + void setupFeeConfigurationReader(o2::framework::InitContext& ic, FITFEEConfigurationReader& feeConfig) + { + feeConfig.setFilename(ic.options().get("filename-fee-config")); + mFeeConfigCcdbInfo.setCcdbPath(mDetectorName + "/Config/FeeConfiguration"); + mFeeConfigCcdbInfo.setValidityPeriodInDays(ic.options().get("valid-days-fee-config")); + } + + void setupHvConfigurationReader(o2::framework::InitContext& ic, FITHvConfigurationReader& hvReader); + + void handleDeadChannelMapUpdate(o2::framework::ProcessingContext& pc, long dataTime, gsl::span dataBuffer); + void processDeadChannelMap(const long& dataTime, gsl::span dataBuffer); + + template + void sendObject(o2::framework::DataAllocator& output, const ConfigObjectType& object, o2::ccdb::CcdbObjectInfo& info, const o2::header::DataDescription& descriptor) + { + auto image = o2::ccdb::CcdbApi::createObjectImage(&object, &info); + LOG(info) << "Sending object " << info.getPath() << "/" << info.getFileName() << " of size " << image->size() + << " bytes, valid for " << info.getStartValidityTimestamp() << " : " << info.getEndValidityTimestamp(); + output.snapshot(o2::framework::Output{o2::calibration::Utils::gDataOriginCDBPayload, descriptor, 0}, *image.get()); + output.snapshot(o2::framework::Output{o2::calibration::Utils::gDataOriginCDBWrapper, descriptor, 0}, info); + } + + std::unique_ptr mDeadChannelMapReader; + + const o2::header::DataDescription& getFeeConfigDescription() const + { + return mDataDescriptionFeeConfig; + } + + const o2::header::DataDescription& getHvConfigDescription() const + { + return mDataDescriptionHvConfig; + } + + const o2::header::DataDescription& getDeadChannelMapDescription() const + { + return mDataDescriptionDChM; + } + + protected: + DcsCcdbInfo mFeeConfigCcdbInfo{180u}; + DcsCcdbInfo mHvConfigCcdbInfo{180u}; + + private: + std::string mDetectorName; ///< Detector name + o2::header::DataDescription mDataDescriptionDChM; ///< DataDescription for the dead channel map + o2::header::DataDescription mDataDescriptionFeeConfig; + o2::header::DataDescription mDataDescriptionHvConfig; +}; + +} // namespace fit +} // namespace o2 + +#endif // O2_FIT_DCSCONFIGPROCESSORSPEC_H diff --git a/Detectors/FIT/common/dcsmonitoring/include/FITDCSMonitoring/FITDCSConfigProcessorSpec.h b/Detectors/FIT/common/dcsmonitoring/include/FITDCSMonitoring/FITDCSConfigProcessorSpec.h deleted file mode 100644 index 18c0b593b0a02..0000000000000 --- a/Detectors/FIT/common/dcsmonitoring/include/FITDCSMonitoring/FITDCSConfigProcessorSpec.h +++ /dev/null @@ -1,138 +0,0 @@ -// 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 FITDCSConfigProcessorSpec.cxx -/// \brief FIT processor spec for DCS configurations -/// -/// \author Andreas Molander , University of Jyvaskyla, Finland - -#ifndef O2_FIT_DCSCONFIGPROCESSORSPEC_H -#define O2_FIT_DCSCONFIGPROCESSORSPEC_H - -#include "CCDB/CcdbApi.h" -#include "DetectorsCalibration/Utils.h" -#include "FITDCSMonitoring/FITDCSConfigReader.h" -#include "Framework/ConfigParamRegistry.h" -#include "Framework/Task.h" -#include "Framework/WorkflowSpec.h" - -#include -#include -#include -#include -#include - -using namespace o2::framework; - -namespace o2 -{ -namespace fit -{ - -class FITDCSConfigProcessor : public o2::framework::Task -{ - public: - FITDCSConfigProcessor(const std::string& detectorName, const o2::header::DataDescription& dataDescriptionDChM) - : mDetectorName(detectorName), - mDataDescriptionDChM(dataDescriptionDChM) {} // TODO AM: how to pass dd - - void init(o2::framework::InitContext& ic) final - { - initDCSConfigReader(); - mDCSConfigReader->setFileNameDChM(ic.options().get("filename-dchm")); - mDCSConfigReader->setValidDaysDChM(ic.options().get("valid-days-dchm")); - mDCSConfigReader->setCcdbPathDChM(mDetectorName + "/Calib/DeadChannelMap"); - mVerbose = ic.options().get("use-verbose-mode"); - mDCSConfigReader->setVerboseMode(mVerbose); - mValidateUpload = !ic.options().get("no-validate"); - mDCSConfigReader->setValidateUploadMode(mValidateUpload); - - LOG(info) << "Verbose mode: " << mVerbose; - LOG(info) << "Validate upload: " << mValidateUpload; - LOG(info) << "Expected dead channel map file name: " << mDCSConfigReader->getFileNameDChM(); - LOG(info) << "Dead channel maps will be valid for " << mDCSConfigReader->getValidDaysDChM() << " days"; - } - - void run(o2::framework::ProcessingContext& pc) final - { - // Get the time of the data - auto timeNow = std::chrono::high_resolution_clock::now(); - long dataTime = (long)(pc.services().get().creation); - if (dataTime == 0xffffffffffffffff) { // means it is not set - dataTime = std::chrono::duration_cast(timeNow.time_since_epoch()).count(); // in ms - } - - // Get the input file - gsl::span configBuf = pc.inputs().get>("inputConfig"); - std::string configFileName = pc.inputs().get("inputConfigFileName"); - LOG(info) << "Got input file " << configFileName << " of size " << configBuf.size(); - - if (!configFileName.compare(mDCSConfigReader->getFileNameDChM())) { - // Got dead channel map - processDChM(dataTime, configBuf); - sendDChMOutput(pc.outputs()); - mDCSConfigReader->resetStartValidityDChM(); - mDCSConfigReader->resetDChM(); - } else { - LOG(error) << "Unknown input file: " << configFileName; - } - } - - void endOfStream(o2::framework::EndOfStreamContext& ec) final - { - } - - protected: - /// Initializes the DCS config reader. - /// Can be overriden in case another reader (subclass of o2::fit::FITDCSConfigReader) is needed. - virtual void initDCSConfigReader() - { - mDCSConfigReader = std::make_unique(FITDCSConfigReader()); - } - - std::unique_ptr mDCSConfigReader; ///< Reader for the DCS configurations - - private: - /// Processing the dead channel map - void processDChM(const long& dataTime, gsl::span configBuf) - { - if (!mDCSConfigReader->isStartValidityDChMSet()) { - if (mVerbose) { - LOG(info) << "Start validity for DCS data set to = " << dataTime; - } - mDCSConfigReader->setStartValidityDChM(dataTime); - } - mDCSConfigReader->processDChM(configBuf); - mDCSConfigReader->updateDChMCcdbObjectInfo(); - } - - /// Sending the dead channeel map output to CCDB - void sendDChMOutput(o2::framework::DataAllocator& output) - { - const auto& payload = mDCSConfigReader->getDChM(); - auto& info = mDCSConfigReader->getObjectInfoDChM(); - auto image = o2::ccdb::CcdbApi::createObjectImage(&payload, &info); - LOG(info) << "Sending object " << info.getPath() << "/" << info.getFileName() << " of size " << image->size() - << " bytes, valid for " << info.getStartValidityTimestamp() << " : " << info.getEndValidityTimestamp(); - output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, mDataDescriptionDChM, 0}, *image.get()); - output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, mDataDescriptionDChM, 0}, info); - } - - std::string mDetectorName; ///< Detector name - o2::header::DataDescription mDataDescriptionDChM; ///< DataDescription for the dead channel map - bool mVerbose = false; ///< Verbose mode - bool mValidateUpload = true; ///< Validate upload -}; - -} // namespace fit -} // namespace o2 - -#endif // O2_FIT_DCSCONFIGPROCESSORSPEC_H diff --git a/Detectors/FIT/common/dcsmonitoring/include/FITDCSMonitoring/FITDCSConfigurationDataParser.h b/Detectors/FIT/common/dcsmonitoring/include/FITDCSMonitoring/FITDCSConfigurationDataParser.h new file mode 100644 index 0000000000000..5aea8d1fed570 --- /dev/null +++ b/Detectors/FIT/common/dcsmonitoring/include/FITDCSMonitoring/FITDCSConfigurationDataParser.h @@ -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. + +/// \file FITDCSConfigurationDataParser.h +/// \brief DCS configuration reader for FIT +/// +/// \author Andreas Molander , University of Jyvaskyla, Finland + +#ifndef O2_FIT_DCS_CONFIGURATION_DATA_PARSER_H +#define O2_FIT_DCS_CONFIGURATION_DATA_PARSER_H + +#endif \ No newline at end of file diff --git a/Detectors/FIT/common/dcsmonitoring/include/FITDCSMonitoring/FITDCSConfigReader.h b/Detectors/FIT/common/dcsmonitoring/include/FITDCSMonitoring/FITDeadChannelMapReader.h similarity index 89% rename from Detectors/FIT/common/dcsmonitoring/include/FITDCSMonitoring/FITDCSConfigReader.h rename to Detectors/FIT/common/dcsmonitoring/include/FITDCSMonitoring/FITDeadChannelMapReader.h index c43607e091493..7d3ffb7b583bb 100644 --- a/Detectors/FIT/common/dcsmonitoring/include/FITDCSMonitoring/FITDCSConfigReader.h +++ b/Detectors/FIT/common/dcsmonitoring/include/FITDCSMonitoring/FITDeadChannelMapReader.h @@ -9,13 +9,13 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file FITDCSConfigReader.h +/// \file FITDeadChannelMapReader.h /// \brief DCS configuration reader for FIT /// /// \author Andreas Molander , University of Jyvaskyla, Finland -#ifndef O2_FIT_DCSCONFIGREADER_H -#define O2_FIT_DCSCONFIGREADER_H +#ifndef O2_FIT_DEAD_CHANNEL_MAP_READER_H +#define O2_FIT_DEAD_CHANNEL_MAP_READER_H #include "CCDB/CcdbObjectInfo.h" #include "DataFormatsFIT/DeadChannelMap.h" @@ -28,11 +28,11 @@ namespace o2 namespace fit { -class FITDCSConfigReader +class FITDeadChannelMapReader { public: - FITDCSConfigReader() = default; - ~FITDCSConfigReader() = default; + FITDeadChannelMapReader() = default; + ~FITDeadChannelMapReader() = default; virtual void processDChM(gsl::span configBuf); void updateDChMCcdbObjectInfo(); @@ -73,10 +73,10 @@ class FITDCSConfigReader o2::ccdb::CcdbObjectInfo mCcdbObjectInfoDChM; ///< CCDB object info for the dead channel map bool mValidateUpload = true; ///< Validate upload mode - ClassDefNV(FITDCSConfigReader, 1); + std::string mFilenameFeeConfig; }; } // namespace fit } // namespace o2 -#endif // O2_FIT_DCSCONFIGREADER_H \ No newline at end of file +#endif // O2_FIT_DEAD_CHANNEL_MAP_READER_H \ No newline at end of file diff --git a/Detectors/FIT/common/dcsmonitoring/include/FITDCSMonitoring/FITFEEConfigurationReader.h b/Detectors/FIT/common/dcsmonitoring/include/FITDCSMonitoring/FITFEEConfigurationReader.h new file mode 100644 index 0000000000000..a74f6668c55de --- /dev/null +++ b/Detectors/FIT/common/dcsmonitoring/include/FITDCSMonitoring/FITFEEConfigurationReader.h @@ -0,0 +1,230 @@ +// 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. + +#ifndef O2_FIT_DCS_CONFIGURATION_DATA_READER_H +#define O2_FIT_DCS_CONFIGURATION_DATA_READER_H + +#include +#include +#include "DataFormatsFIT/Configuration.h" +#include "DetectorsCalibration/Utils.h" +#include "FITDCSMonitoring/FITDCSBaseConfigReader.h" + +namespace o2::fit +{ +template +class FITFEEConfigurationReader : public FITDCSBaseConfigReader +{ + public: + FITFEEConfigurationReader() + { + loadSchema(configurationSchema); + } + + virtual ~FITFEEConfigurationReader() = default; + + protected: + template + ConfigType parseFeeConfiguration(gsl::span buffer) + { + rapidjson::Document document = parseJsonBuffer(buffer); + ConfigType configuration; + + parseChannelData(document, "channels", configuration.channels); + parseTcmConfig(document, "tcm", configuration.tcm); + if constexpr (requires { configuration.pmA; }) { + parsePmsArray(document, "pm_a", configuration.pmA); + } + if constexpr (requires { configuration.pmC; }) { + parsePmsArray(document, "pm_c", configuration.pmC); + } + static_cast(this)->parseTriggers(document, "triggers", configuration.triggers); + + return configuration; + } + + template + void parseJsonArray(const rapidjson::Value& node, const char* childName, T (&array)[Size]) + { + if (node.HasMember(childName) == false) { + throw std::runtime_error(std::string("Failed to find node of name ") + childName); + } + const auto& childNode = node[childName]; + if (childNode.IsArray() == false) { + throw std::runtime_error(std::format("Node {} is not an array!", childName)); + } + auto jsonArray = childNode.GetArray(); + if (jsonArray.Size() != Size) { + throw std::runtime_error(std::format("Array {}. Expected array of size {}, parsed array of size {}", childName, Size, jsonArray.Size())); + } + for (int idx = 0; idx < Size; idx++) { + const auto& node = jsonArray[idx]; + if constexpr (std::is_same_v) { + if (!node.IsBool()) { + throw std::runtime_error(std::format("{} is not a bool array", childName)); + } + array[idx] = node.GetBool(); + } else if constexpr (std::is_floating_point_v) { + if (!node.IsNumber()) { + throw std::runtime_error(std::format("{} is not an floating point array", childName)); + } + array[idx] = node.GetFloat(); + } else if constexpr (std::is_integral_v && std::is_unsigned_v) { + if (!node.IsUint()) { + throw std::runtime_error(std::format("{} is not an unsigned integer array", childName)); + } + array[idx] = static_cast(node.GetUint()); + } else if constexpr (std::is_integral_v) { + if (!node.IsInt()) { + throw std::runtime_error(std::format("{} is not an integer array", childName)); + } + array[idx] = static_cast(node.GetInt()); + } else { + static_assert(std::is_same_v, "Unsupported type"); + } + } + } + + template + void parseChannelData(const rapidjson::Value& root, const char* channelsNodeName, ChannelsConfig& channelsConfiguration) + { + const auto& channelsNode = root[channelsNodeName]; + parseJsonArray(channelsNode, "time_alignments", channelsConfiguration.timeAligments); + parseJsonArray(channelsNode, "cfd_thresholds", channelsConfiguration.cfdThresholds); + parseJsonArray(channelsNode, "cfd_zeros", channelsConfiguration.cfdZeros); + parseJsonArray(channelsNode, "adc_zeros", channelsConfiguration.adcZeros); + parseJsonArray(channelsNode, "adc_delays", channelsConfiguration.adcDelays); + parseJsonArray(channelsNode, "range_correction_adc0", channelsConfiguration.rangeCorrectionAdc0); + parseJsonArray(channelsNode, "range_correction_adc1", channelsConfiguration.rangeCorrectionAdc1); + parseJsonArray(channelsNode, "channel_mask_data", channelsConfiguration.channelMaskData); + parseJsonArray(channelsNode, "channel_mask_triggers", channelsConfiguration.channelMaskTriggers); + parseJsonArray(channelsNode, "threshold_calibration", channelsConfiguration.thresholdCalibration); + } + + void parseTcmConfig(const rapidjson::Value& root, const char* tcmNodeName, TcmConfig& tcmConfig) + { + const auto& tcmNode = root[tcmNodeName]; + const auto& phaseDelayANode = tcmNode["phase_delay_a"]; + const auto& phaseDelayCNode = tcmNode["phase_delay_c"]; + tcmConfig.phaseDelayA = phaseDelayANode.GetDouble(); + tcmConfig.phaseDelayC = phaseDelayCNode.GetDouble(); + } + + void parsePmConfig(const rapidjson::Value& pmNode, PmConfig& pmConfig) + { + const auto& orGateNode = pmNode["or_gate"]; + const auto& trgChargeHighLevelNode = pmNode["trg_charge_high_level"]; + const auto& trgChargeLowLevelNode = pmNode["trg_charge_low_level"]; + pmConfig.orGate = orGateNode.GetUint(); + pmConfig.trgChargeHighLevel = trgChargeHighLevelNode.GetUint(); + pmConfig.trgChargeLowLevel = trgChargeLowLevelNode.GetUint(); + } + + template + void parsePmsArray(const rapidjson::Value& root, const char* pmArrayNodeName, PmConfig (&pmConfig)[Size]) + { + if (root.HasMember(pmArrayNodeName) == false) { + throw std::runtime_error(std::format("Failed to find {} node", pmArrayNodeName)); + } + const auto& pmArrayNode = root[pmArrayNodeName]; + const auto& pmArray = pmArrayNode.GetArray(); + if (pmArray.Size() != Size) { + throw std::runtime_error(std::format("Received data for {} PMs, but expected {}", pmArray.Size(), Size)); + } + for (int idx = 0; idx < pmArray.Size(); idx++) { + const auto& pm = pmArray[idx]; + if (pm.IsNull()) { + continue; + } + parsePmConfig(pm, pmConfig[idx]); + } + } + + std::string_view getSchemaString() const + { + return configurationSchema; + } + + private: + inline static constexpr std::string_view configurationSchema = R"SCH( + { + "type": "object", + "properties": { + "channels": { + "type": "object", + "properties": { + "time_alignments": {"type": "array", "items": {"type": "integer"}}, + "cfd_thresholds": {"type": "array", "items": {"type": "integer"}}, + "cfd_zeros": {"type": "array", "items": {"type": "integer"}}, + "adc_zeros": {"type": "array", "items": {"type": "integer"}}, + "adc_delays": {"type": "array", "items": {"type": "integer"}}, + "range_correction_adc0": {"type": "array", "items": {"type": "integer"}}, + "range_correction_adc1": {"type": "array", "items": {"type": "integer"}}, + "channel_mask_data": {"type": "array", "items": {"type": "boolean"}}, + "channel_mask_triggers": {"type": "array", "items": {"type": "boolean"}}, + "threshold_calibration": {"type": "array", "items": {"type": "integer"}} + }, + "additionalProperties": false, + "required": [ + "time_alignments", "cfd_thresholds", "cfd_zeros", + "adc_zeros", "adc_delays", "range_correction_adc0", "range_correction_adc1", + "channel_mask_data", "channel_mask_triggers" + ] + }, + "tcm" : { + "type": "object", + "properties": { + "phase_delay_a": {"type": "number"}, + "phase_delay_c": {"type": "number"} + }, + "additionalProperties": false, + "required": ["phase_delay_a", "phase_delay_c"] + }, + "pm_a":{ + "type": "array", + "items": { + "type": ["object", "null"], + "properties": { + "or_gate": {"type": "number"}, + "trg_charge_low_level": {"type": "number"}, + "trg_charge_high_level": {"type": "number"}, + "fdd_coincidence_mode": {"type": "boolean"} + }, + "additionalProperties": false, + "required": ["or_gate", "trg_charge_low_level", "trg_charge_high_level"] + } + }, + "pm_c": { + "type": "array", + "items": { + "type": ["object", "null"], + "properties": { + "or_gate": {"type": "number"}, + "trg_charge_low_level": {"type": "number"}, + "trg_charge_high_level": {"type": "number"}, + "fddCoincidenceMode": {"type": "boolean} + }, + "additionalProperties": false, + "required": ["or_gate", "trg_charge_low_level", "trg_charge_high_level"] + } + }, + "triggers": { + "type": "object", + "additionalProperties" : { "type": "number" } + } + }, + "required": ["channels", "tcm", "triggers"] + } + )SCH"; +}; +} // namespace o2::fit + +#endif \ No newline at end of file diff --git a/Detectors/FIT/common/dcsmonitoring/include/FITDCSMonitoring/FITHvConfigurationReader.h b/Detectors/FIT/common/dcsmonitoring/include/FITDCSMonitoring/FITHvConfigurationReader.h new file mode 100644 index 0000000000000..14ee98a27e05d --- /dev/null +++ b/Detectors/FIT/common/dcsmonitoring/include/FITDCSMonitoring/FITHvConfigurationReader.h @@ -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. + +#ifndef O2_FIT_DCS_HV_CONFIGURATION_DATA_READER_H +#define O2_FIT_DCS_HV_CONFIGURATION_DATA_READER_H + +#include +#include +#include "DataFormatsFIT/Configuration.h" +#include "DetectorsCalibration/Utils.h" +#include "FITDCSMonitoring/FITDCSBaseConfigReader.h" + +namespace o2::fit +{ +class FITHvConfigurationReader : public FITDCSBaseConfigReader +{ + public: + FITHvConfigurationReader() + { + loadSchema(configurationSchema); + } + + template + ConfigType parseHvConfiguration(gsl::span buffer) + { + rapidjson::Document root = parseJsonBuffer(buffer); + ConfigType configuration; + parseHvChannelData(root, "hv_channels", configuration.channels); + return configuration; + } + + template + void parseHvChannelData(rapidjson::Value& root, const char* hvChannelsNode, HvChannelsConfig& config) + { + const auto& hvChannels = root[hvChannelsNode]; + parseJsonArray(hvChannels, "gain", config.gain); + } + + std::string_view getSchemaString() const + { + return configurationSchema; + } + + private: + inline static constexpr std::string_view configurationSchema = R"json( + { + "type": "object", + "properties": { + "hv_channels": { + "type": "object", + "properties": { + "gain": { + "type": "array", + "items": { + "type": "number" + } + } + }, + "additionalProperties": false, + "required": ["gain"] + } + }, + "additionalProperties": false, + "required": ["hv_channels"] + } + )json"; +}; +} // namespace o2::fit +#endif \ No newline at end of file diff --git a/Detectors/FIT/common/dcsmonitoring/src/FITDCSBaseConfigReader.cxx b/Detectors/FIT/common/dcsmonitoring/src/FITDCSBaseConfigReader.cxx new file mode 100644 index 0000000000000..d7700459109b7 --- /dev/null +++ b/Detectors/FIT/common/dcsmonitoring/src/FITDCSBaseConfigReader.cxx @@ -0,0 +1,61 @@ +// 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 "FITDCSMonitoring/FITDCSBaseConfigReader.h" + +namespace o2::fit +{ +rapidjson::Document FITDCSBaseConfigReader::parseJsonBuffer(gsl::span buffer, bool throwOnInvalidSchema) +{ + rapidjson::MemoryStream ms(buffer.data(), buffer.size()); + rapidjson::Document document; + document.ParseStream(ms); + + std::string validationErrorMessage; + if ((!throwOnInvalidSchema || validateSchema(document, validationErrorMessage)) == false) { + std::string_view bufferView(buffer.data(), buffer.size()); + throw std::runtime_error("Received document does not match FEE configuration schema! Error message: " + validationErrorMessage); + } + + return document; +} + +void FITDCSBaseConfigReader::loadSchema(std::string_view schema) +{ + rapidjson::Document schemaDocument; + schemaDocument.Parse(schema.data(), schema.size()); + if (schemaDocument.HasParseError()) { + throw std::runtime_error("Cannot parse JSON schema"); + } + mSchema = std::make_unique(schemaDocument); +} + +bool FITDCSBaseConfigReader::validateSchema(const rapidjson::Document& docs, std::string& errorMessage) +{ + rapidjson::SchemaValidator validator(*mSchema); + if (docs.Accept(validator) == false) { + rapidjson::StringBuffer buffer; + std::ostringstream ss; + validator.GetInvalidSchemaPointer().StringifyUriFragment(buffer); + ss << "Invalid schema: " << buffer.GetString() << '\n'; + ss << "Invalid keyword: " << validator.GetInvalidSchemaKeyword() << '\n'; + + buffer.Clear(); + + validator.GetInvalidDocumentPointer().StringifyUriFragment(buffer); + ss << "Invalid document: " << buffer.GetString() << '\n'; + + errorMessage = ss.str(); + return false; + } + return true; +} +} // namespace o2::fit \ No newline at end of file diff --git a/Detectors/FIT/common/dcsmonitoring/src/FITDCSConfigProcessor.cxx b/Detectors/FIT/common/dcsmonitoring/src/FITDCSConfigProcessor.cxx new file mode 100644 index 0000000000000..de3f66ca08905 --- /dev/null +++ b/Detectors/FIT/common/dcsmonitoring/src/FITDCSConfigProcessor.cxx @@ -0,0 +1,70 @@ +// 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 "FITDCSMonitoring/FITDCSConfigProcessor.h" + +namespace o2::fit +{ +void FITDCSConfigProcessor::initDeadChannelMapReader() +{ + mDeadChannelMapReader = std::make_unique(FITDeadChannelMapReader()); +} + +long FITDCSConfigProcessor::getValidityTime(o2::framework::ProcessingContext& pc) +{ + long dataTime = (long)(pc.services().get().creation); + if (dataTime == 0xffffffffffffffff) { // means it is not set + dataTime = std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()).count(); // in ms + } + return dataTime; +} + +void FITDCSConfigProcessor::setupDeadChannelMapReader(o2::framework::InitContext& ic) +{ + mDeadChannelMapReader->setFileNameDChM(ic.options().get("filename-dchm")); + mDeadChannelMapReader->setValidDaysDChM(ic.options().get("valid-days-dchm")); + mDeadChannelMapReader->setCcdbPathDChM(mDetectorName + "/Calib/DeadChannelMap"); + bool verbose = ic.options().get("use-verbose-mode"); + mDeadChannelMapReader->setVerboseMode(verbose); + bool validateUpload = !ic.options().get("no-validate"); + mDeadChannelMapReader->setValidateUploadMode(validateUpload); + + LOG(info) << "Verbose mode: " << verbose; + LOG(info) << "Validate upload: " << validateUpload; + LOG(info) << "Expected dead channel map file name: " << mDeadChannelMapReader->getFileNameDChM(); + LOG(info) << "Dead channel maps will be valid for " << mDeadChannelMapReader->getValidDaysDChM() << " days"; +} + +void FITDCSConfigProcessor::handleDeadChannelMapUpdate(o2::framework::ProcessingContext& pc, long dataTime, gsl::span dataBuffer) +{ + processDeadChannelMap(dataTime, dataBuffer); + sendObject(pc.outputs(), mDeadChannelMapReader->getDChM(), mDeadChannelMapReader->getObjectInfoDChM(), mDataDescriptionDChM); + mDeadChannelMapReader->resetStartValidityDChM(); + mDeadChannelMapReader->resetDChM(); +} + +/// Processing the dead channel map +void FITDCSConfigProcessor::processDeadChannelMap(const long& dataTime, gsl::span dataBuffer) +{ + if (!mDeadChannelMapReader->isStartValidityDChMSet()) { + mDeadChannelMapReader->setStartValidityDChM(dataTime); + } + mDeadChannelMapReader->processDChM(dataBuffer); + mDeadChannelMapReader->updateDChMCcdbObjectInfo(); +} + +void FITDCSConfigProcessor::setupHvConfigurationReader(o2::framework::InitContext& ic, FITHvConfigurationReader& hvReader) +{ + hvReader.setFilename(ic.options().get("filename-hv-config")); + mHvConfigCcdbInfo.setCcdbPath(mDetectorName + "/Config/HvConfiguration"); + mHvConfigCcdbInfo.setValidityPeriodInDays(ic.options().get("valid-days-hv-config")); +} +} // namespace o2::fit \ No newline at end of file diff --git a/Detectors/FIT/common/dcsmonitoring/src/FITDCSConfigReader.cxx b/Detectors/FIT/common/dcsmonitoring/src/FITDCSConfigReader.cxx deleted file mode 100644 index 3540d3a2f33c0..0000000000000 --- a/Detectors/FIT/common/dcsmonitoring/src/FITDCSConfigReader.cxx +++ /dev/null @@ -1,75 +0,0 @@ -// 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 FITDCSConfigReader.cxx -/// \brief FIT reader for DCS configurations -/// -/// \author Andreas Molander , University of Jyvaskyla, Finland - -#include "FITDCSMonitoring/FITDCSConfigReader.h" - -#include "DetectorsCalibration/Utils.h" - -#include -#include - -using namespace o2::fit; - -void FITDCSConfigReader::processDChM(gsl::span configBuf) -{ - LOG(info) << "Processing dead channel map"; - - // AM: need to specify the size, - // otherwise the configBuf.data() pointer might point to an array that is too long, - // the array sometimes includes "extra memory from previous runs" - std::istringstream iss(std::string(configBuf.data(), configBuf.size())); - uint8_t iLine = 0; // line 0 corresponds to cahnnel id 0 and so on - - for (std::string line; std::getline(iss, line);) { - mDChM.setChannelAlive(iLine, std::stoi(line) == 1); - iLine++; - } - - if (getVerboseMode()) { - LOGP(info, "Processed {} channels", iLine); - } -} - -void FITDCSConfigReader::updateDChMCcdbObjectInfo() -{ - std::map metadata; - o2::calibration::Utils::prepareCCDBobjectInfo(mDChM, mCcdbObjectInfoDChM, mCcdbPathDChM, metadata, getStartValidityDChM(), getEndValidityDChM()); - mCcdbObjectInfoDChM.setValidateUpload(getValidateUploadMode()); -} - -const o2::fit::DeadChannelMap& FITDCSConfigReader::getDChM() const { return mDChM; } -void FITDCSConfigReader::resetDChM() { mDChM.clear(); } -const std::string& FITDCSConfigReader::getCcdbPathDChm() const { return mCcdbPathDChM; } -void FITDCSConfigReader::setCcdbPathDChM(const std::string& ccdbPath) { mCcdbPathDChM = ccdbPath; } -const long FITDCSConfigReader::getStartValidityDChM() const { return mStartValidityDChM; } -const long FITDCSConfigReader::getEndValidityDChM() const { return mStartValidityDChM + getValidDaysDChM() * o2::ccdb::CcdbObjectInfo::DAY; } -void FITDCSConfigReader::setStartValidityDChM(const long startValidity) { mStartValidityDChM = startValidity; } -const bool FITDCSConfigReader::isStartValidityDChMSet() const { return mStartValidityDChM != o2::ccdb::CcdbObjectInfo::INFINITE_TIMESTAMP; } -void FITDCSConfigReader::resetStartValidityDChM() { mStartValidityDChM = o2::ccdb::CcdbObjectInfo::INFINITE_TIMESTAMP; } -const o2::ccdb::CcdbObjectInfo& FITDCSConfigReader::getObjectInfoDChM() const { return mCcdbObjectInfoDChM; } -o2::ccdb::CcdbObjectInfo& FITDCSConfigReader::getObjectInfoDChM() { return mCcdbObjectInfoDChM; } - -const std::string& FITDCSConfigReader::getFileNameDChM() const { return mFileNameDChM; } -void FITDCSConfigReader::setFileNameDChM(const std::string& fileName) { mFileNameDChM = fileName; } - -const uint FITDCSConfigReader::getValidDaysDChM() const { return mValidDaysDChM; } -void FITDCSConfigReader::setValidDaysDChM(const uint validDays) { mValidDaysDChM = validDays; } - -const bool FITDCSConfigReader::getVerboseMode() const { return mVerbose; } -void FITDCSConfigReader::setVerboseMode(const bool verboseMode) { mVerbose = verboseMode; } - -const bool FITDCSConfigReader::getValidateUploadMode() const { return mValidateUpload; } -void FITDCSConfigReader::setValidateUploadMode(const bool validateUpload) { mValidateUpload = validateUpload; }; \ No newline at end of file diff --git a/Detectors/FIT/common/dcsmonitoring/src/FITDCSMonitoringLinkDef.h b/Detectors/FIT/common/dcsmonitoring/src/FITDCSMonitoringLinkDef.h index 521673ad062f3..c6d473429cf86 100644 --- a/Detectors/FIT/common/dcsmonitoring/src/FITDCSMonitoringLinkDef.h +++ b/Detectors/FIT/common/dcsmonitoring/src/FITDCSMonitoringLinkDef.h @@ -16,9 +16,6 @@ #pragma link off all functions; #pragma link C++ std::unordered_map < uint8_t, bool> + ; -#pragma link C++ struct o2::fit::DeadChannelMap + ; - // TODO AM: Move this to DataFormatsFIT when unused class warning is solved. #pragma link C++ class std::unordered_map < o2::dcs::DataPointIdentifier, o2::fit::DCSDPValues> + ; - #endif diff --git a/Detectors/FIT/common/dcsmonitoring/src/FITDeadChannelMapReader.cxx b/Detectors/FIT/common/dcsmonitoring/src/FITDeadChannelMapReader.cxx new file mode 100644 index 0000000000000..a926df10d26ad --- /dev/null +++ b/Detectors/FIT/common/dcsmonitoring/src/FITDeadChannelMapReader.cxx @@ -0,0 +1,75 @@ +// 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 FITDeadChannelMapReader.cxx +/// \brief FIT reader for DCS configurations +/// +/// \author Andreas Molander , University of Jyvaskyla, Finland + +#include "FITDCSMonitoring/FITDeadChannelMapReader.h" + +#include "DetectorsCalibration/Utils.h" + +#include +#include + +using namespace o2::fit; + +void FITDeadChannelMapReader::processDChM(gsl::span configBuf) +{ + LOG(info) << "Processing dead channel map"; + + // AM: need to specify the size, + // otherwise the configBuf.data() pointer might point to an array that is too long, + // the array sometimes includes "extra memory from previous runs" + std::istringstream iss(std::string(configBuf.data(), configBuf.size())); + uint8_t iLine = 0; // line 0 corresponds to cahnnel id 0 and so on + + for (std::string line; std::getline(iss, line);) { + mDChM.setChannelAlive(iLine, std::stoi(line) == 1); + iLine++; + } + + if (getVerboseMode()) { + LOGP(info, "Processed {} channels", iLine); + } +} + +void FITDeadChannelMapReader::updateDChMCcdbObjectInfo() +{ + std::map metadata; + o2::calibration::Utils::prepareCCDBobjectInfo(mDChM, mCcdbObjectInfoDChM, mCcdbPathDChM, metadata, getStartValidityDChM(), getEndValidityDChM()); + mCcdbObjectInfoDChM.setValidateUpload(getValidateUploadMode()); +} + +const o2::fit::DeadChannelMap& FITDeadChannelMapReader::getDChM() const { return mDChM; } +void FITDeadChannelMapReader::resetDChM() { mDChM.clear(); } +const std::string& FITDeadChannelMapReader::getCcdbPathDChm() const { return mCcdbPathDChM; } +void FITDeadChannelMapReader::setCcdbPathDChM(const std::string& ccdbPath) { mCcdbPathDChM = ccdbPath; } +const long FITDeadChannelMapReader::getStartValidityDChM() const { return mStartValidityDChM; } +const long FITDeadChannelMapReader::getEndValidityDChM() const { return mStartValidityDChM + getValidDaysDChM() * o2::ccdb::CcdbObjectInfo::DAY; } +void FITDeadChannelMapReader::setStartValidityDChM(const long startValidity) { mStartValidityDChM = startValidity; } +const bool FITDeadChannelMapReader::isStartValidityDChMSet() const { return mStartValidityDChM != o2::ccdb::CcdbObjectInfo::INFINITE_TIMESTAMP; } +void FITDeadChannelMapReader::resetStartValidityDChM() { mStartValidityDChM = o2::ccdb::CcdbObjectInfo::INFINITE_TIMESTAMP; } +const o2::ccdb::CcdbObjectInfo& FITDeadChannelMapReader::getObjectInfoDChM() const { return mCcdbObjectInfoDChM; } +o2::ccdb::CcdbObjectInfo& FITDeadChannelMapReader::getObjectInfoDChM() { return mCcdbObjectInfoDChM; } + +const std::string& FITDeadChannelMapReader::getFileNameDChM() const { return mFileNameDChM; } +void FITDeadChannelMapReader::setFileNameDChM(const std::string& fileName) { mFileNameDChM = fileName; } + +const uint FITDeadChannelMapReader::getValidDaysDChM() const { return mValidDaysDChM; } +void FITDeadChannelMapReader::setValidDaysDChM(const uint validDays) { mValidDaysDChM = validDays; } + +const bool FITDeadChannelMapReader::getVerboseMode() const { return mVerbose; } +void FITDeadChannelMapReader::setVerboseMode(const bool verboseMode) { mVerbose = verboseMode; } + +const bool FITDeadChannelMapReader::getValidateUploadMode() const { return mValidateUpload; } +void FITDeadChannelMapReader::setValidateUploadMode(const bool validateUpload) { mValidateUpload = validateUpload; }; \ No newline at end of file diff --git a/Detectors/FIT/common/tests/CMakeLists.txt b/Detectors/FIT/common/tests/CMakeLists.txt new file mode 100644 index 0000000000000..937f0e7b18d37 --- /dev/null +++ b/Detectors/FIT/common/tests/CMakeLists.txt @@ -0,0 +1,22 @@ +# 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_test(FITFEEConfigurationReader + COMPONENT_NAME fit_fee_config_reader + LABELS fit + PUBLIC_LINK_LIBRARIES O2::DataFormatsFIT O2::FITDCSMonitoring + SOURCES dcsmonitoring/FITFEEConfigurationReaderTest.cxx) + +o2_add_test(FITHvConfigurationReader + COMPONENT_NAME fit_hv_config_reader + LABELS fit + PUBLIC_LINK_LIBRARIES O2::DataFormatsFIT O2::FITDCSMonitoring + SOURCES dcsmonitoring/FITHvConfigurationReaderTest.cxx) \ No newline at end of file diff --git a/Detectors/FIT/common/tests/dcsmonitoring/FITFEEConfigurationReaderTest.cxx b/Detectors/FIT/common/tests/dcsmonitoring/FITFEEConfigurationReaderTest.cxx new file mode 100644 index 0000000000000..8fb579ee89d47 --- /dev/null +++ b/Detectors/FIT/common/tests/dcsmonitoring/FITFEEConfigurationReaderTest.cxx @@ -0,0 +1,561 @@ +// 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 FITDCSMonitoring FITFEEConfigurationReader +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +#include +#include + +#include "DataFormatsFIT/Configuration.h" +#include "FITDCSMonitoring/FITFEEConfigurationReader.h" + +using namespace o2::fit; + +BOOST_AUTO_TEST_SUITE(o2_fit_dcs_monitoring) + +// Dummy structure for trigger data for complete definition of FEE configuration structure +struct SimpleTriggers { + int32_t triggerA; +}; + +// Test configuration structure +struct SimpleConfiguration { + static constexpr int NChannels = 5; + SimpleTriggers triggers; + o2::fit::ChannelsConfig channels; + o2::fit::TcmConfig tcm; + o2::fit::PmConfig pmA[2]; + o2::fit::PmConfig pmC[2]; +}; + +rapidjson::Document createEmptyPayload() +{ + rapidjson::Document doc; + doc.SetObject(); + return doc; +} + +rapidjson::Document createDocumentFromString(const char* data) +{ + rapidjson::Document doc; + doc.Parse(data); + return doc; +} + +rapidjson::Document createPmConfigNode(uint8_t orGateValue, uint16_t trgChargeLowLevel, uint16_t trgChargeHighLevel) +{ + auto doc = createEmptyPayload(); + auto& allocator = doc.GetAllocator(); + doc.AddMember("or_gate", orGateValue, allocator); + doc.AddMember("trg_charge_low_level", trgChargeLowLevel, allocator); + doc.AddMember("trg_charge_high_level", trgChargeHighLevel, allocator); + return doc; +} + +void addTcmConfigNode(rapidjson::Document& doc, + const char* nodeName, + float phaseDelayA, + float phaseDelayC) +{ + auto& allocator = doc.GetAllocator(); + + rapidjson::Value tcmConfigJson(rapidjson::kObjectType); + tcmConfigJson.AddMember("phase_delay_a", phaseDelayA, allocator); + tcmConfigJson.AddMember("phase_delay_c", phaseDelayC, allocator); + + doc.AddMember(rapidjson::StringRef(nodeName), tcmConfigJson, allocator); +} + +template +void addPmConfigsNode(rapidjson::Document& doc, const char* nodeName, const uint8_t (&orGateValues)[NChannels], const uint16_t (&trgChargeLowLevel)[NChannels], const uint16_t (&trgChargeHighLevel)[NChannels]) +{ + auto& allocator = doc.GetAllocator(); + + rapidjson::Value pmJson(rapidjson::kArrayType); + + for (size_t idx = 0; idx < NChannels; ++idx) { + rapidjson::Value pm(rapidjson::kObjectType); + pm.AddMember("or_gate", orGateValues[idx], allocator); + pm.AddMember("trg_charge_low_level", trgChargeLowLevel[idx], allocator); + pm.AddMember("trg_charge_high_level", trgChargeHighLevel[idx], allocator); + pmJson.PushBack(pm, allocator); + } + + doc.AddMember(rapidjson::StringRef(nodeName), pmJson, allocator); +} + +template +void addArrayMember(rapidjson::Value& node, const char* memberName, const T (&values)[N], rapidjson::Document::AllocatorType& allocator) +{ + rapidjson::Value arrayJson(rapidjson::kArrayType); + + for (size_t idx = 0; idx < N; ++idx) { + arrayJson.PushBack(values[idx], allocator); + } + + node.AddMember(rapidjson::StringRef(memberName), arrayJson, allocator); +} + +template +void addChannelsConfigNode(rapidjson::Document& doc, + const char* nodeName, + const int16_t (&timeAligments)[NChannels], + const uint16_t (&cfdThresholds)[NChannels], + const int16_t (&cfdZeros)[NChannels], + const int16_t (&adcZeros)[NChannels], + const uint16_t (&adcDelays)[NChannels], + const uint16_t (&rangeCorrectionAdc0)[NChannels], + const uint16_t (&rangeCorrectionAdc1)[NChannels], + const bool (&channelMaskData)[NChannels], + const bool (&channelMaskTriggers)[NChannels]) +{ + auto& allocator = doc.GetAllocator(); + + rapidjson::Value channelsJson(rapidjson::kObjectType); + + addArrayMember(channelsJson, "time_alignments", timeAligments, allocator); + addArrayMember(channelsJson, "cfd_thresholds", cfdThresholds, allocator); + addArrayMember(channelsJson, "cfd_zeros", cfdZeros, allocator); + addArrayMember(channelsJson, "adc_zeros", adcZeros, allocator); + addArrayMember(channelsJson, "adc_delays", adcDelays, allocator); + addArrayMember(channelsJson, "range_correction_adc0", rangeCorrectionAdc0, allocator); + addArrayMember(channelsJson, "range_correction_adc1", rangeCorrectionAdc1, allocator); + addArrayMember(channelsJson, "channel_mask_data", channelMaskData, allocator); + addArrayMember(channelsJson, "channel_mask_triggers", channelMaskTriggers, allocator); + + doc.AddMember(rapidjson::StringRef(nodeName), channelsJson, allocator); +} + +class SimpleFITFEEConfigurationReader + : public FITFEEConfigurationReader +{ + public: + // Dummy method to parse dummy triggers payload + SimpleTriggers parseTriggers(const rapidjson::Value&, + const char*, + SimpleTriggers& triggers) + { + triggers.triggerA = 32; + return triggers; + } + + using FITFEEConfigurationReader::parseFeeConfiguration; + using FITFEEConfigurationReader::parseJsonArray; + using FITFEEConfigurationReader::parseChannelData; + using FITFEEConfigurationReader::parseTcmConfig; + using FITFEEConfigurationReader::parsePmConfig; + using FITFEEConfigurationReader::parsePmsArray; + using FITFEEConfigurationReader::validateSchema; +}; + +BOOST_AUTO_TEST_CASE(shouldParseSinglePmConfig) +{ + const uint8_t orGateValue = 20; + const uint16_t rangeCorrectionAdc0 = 1024; + const uint16_t rangeCorrectionAdc1 = 2048; + + rapidjson::Document doc = createPmConfigNode(orGateValue, rangeCorrectionAdc0, rangeCorrectionAdc1); + + PmConfig pmConfig; + SimpleFITFEEConfigurationReader reader; + reader.parsePmConfig(doc, pmConfig); + + BOOST_CHECK_EQUAL(pmConfig.orGate, orGateValue); +} + +BOOST_AUTO_TEST_CASE(shouldParseTcmConfig) +{ + const float phaseDelayAValue = 1.2f; + const float phaseDelayCValue = -1.3f; + + rapidjson::Document doc = createEmptyPayload(); + addTcmConfigNode(doc, "tcm_config", phaseDelayAValue, phaseDelayCValue); + + TcmConfig tcmConfig; + + SimpleFITFEEConfigurationReader reader; + reader.parseTcmConfig(doc, "tcm_config", tcmConfig); + + TcmConfig expectedConfig = { + .phaseDelayA = phaseDelayAValue, + .phaseDelayC = phaseDelayCValue}; + + BOOST_CHECK(tcmConfig == expectedConfig); +} + +BOOST_AUTO_TEST_CASE(shouldParseArrayOfPmConfigs) +{ + const uint8_t pmAOrGate[] = {3, 4}; + const uint16_t pmATrgChargeLowLevel[] = {2047, 2048}; + const uint16_t pmATrgChargeHighLevel[] = {1047, 1048}; + const uint8_t pmCOrGate[] = {5, 6}; + const uint16_t pmCTrgChargeLowLevel[] = {2045, 2046}; + const uint16_t pmCTrgChargeHighLevel[] = {1045, 1046}; + + rapidjson::Document doc = createEmptyPayload(); + addPmConfigsNode(doc, "pm_a", pmAOrGate, pmATrgChargeLowLevel, pmATrgChargeHighLevel); + addPmConfigsNode(doc, "pm_c", pmCOrGate, pmCTrgChargeLowLevel, pmCTrgChargeHighLevel); + + PmConfig pmAParsed[2]; + PmConfig pmCParsed[2]; + + SimpleFITFEEConfigurationReader reader; + reader.parsePmsArray(doc, "pm_a", pmAParsed); + reader.parsePmsArray(doc, "pm_c", pmCParsed); + + for (size_t idx = 0; idx < std::size(pmAParsed); ++idx) { + BOOST_CHECK_EQUAL(pmAParsed[idx].orGate, pmAOrGate[idx]); + } + + for (size_t idx = 0; idx < std::size(pmCParsed); ++idx) { + BOOST_CHECK_EQUAL(pmCParsed[idx].orGate, pmCOrGate[idx]); + } +} + +BOOST_AUTO_TEST_CASE(shouldThrowOnInconsistentPmsArraySize) +{ + const uint8_t pmAOrGate[] = {0, 0}; + const uint16_t pmATrgChargeLowLevel[] = {2047, 2048}; + const uint16_t pmATrgChargeHighLevel[] = {1047, 1048}; + + rapidjson::Document doc = createEmptyPayload(); + addPmConfigsNode(doc, "pm_a", pmAOrGate, pmATrgChargeLowLevel, pmATrgChargeHighLevel); + + PmConfig pmAParsed[3]; + + SimpleFITFEEConfigurationReader reader; + + BOOST_CHECK_THROW(reader.parsePmsArray(doc, "pm_a", pmAParsed), std::runtime_error); +} + +BOOST_AUTO_TEST_CASE(shouldParseChannelsConfig) +{ + constexpr size_t NTestChannels = 4; + + const int16_t timeAligments[NTestChannels] = {1, 2, 3, 4}; + const uint16_t cfdThresholds[NTestChannels] = {10, 20, 30, 40}; + const int16_t cfdZeros[NTestChannels] = {-1, -2, -3, -4}; + const int16_t adcZeros[NTestChannels] = {100, 200, 300, 400}; + const uint16_t adcDelays[NTestChannels] = {5, 6, 7, 8}; + const uint16_t rangeCorrectionAdc0[NTestChannels] = {2045, 2046, 2047, 2048}; + const uint16_t rangeCorrectionAdc1[NTestChannels] = {2048, 2022, 2021, 2022}; + const bool channelMaskData[NTestChannels] = {true, false, true, false}; + const bool channelMaskTriggers[NTestChannels] = {false, true, false, true}; + + rapidjson::Document doc = createEmptyPayload(); + + addChannelsConfigNode( + doc, + "channels", + timeAligments, + cfdThresholds, + cfdZeros, + adcZeros, + adcDelays, + rangeCorrectionAdc0, + rangeCorrectionAdc1, + channelMaskData, + channelMaskTriggers); + + ChannelsConfig parsed{}; + + SimpleFITFEEConfigurationReader reader; + reader.parseChannelData(doc, "channels", parsed); + + for (size_t idx = 0; idx < NTestChannels; ++idx) { + BOOST_CHECK_EQUAL(parsed.timeAligments[idx], timeAligments[idx]); + BOOST_CHECK_EQUAL(parsed.cfdThresholds[idx], cfdThresholds[idx]); + BOOST_CHECK_EQUAL(parsed.cfdZeros[idx], cfdZeros[idx]); + BOOST_CHECK_EQUAL(parsed.adcZeros[idx], adcZeros[idx]); + BOOST_CHECK_EQUAL(parsed.adcDelays[idx], adcDelays[idx]); + BOOST_CHECK_EQUAL(parsed.channelMaskData[idx], channelMaskData[idx]); + BOOST_CHECK_EQUAL(parsed.channelMaskTriggers[idx], channelMaskTriggers[idx]); + } +} + +BOOST_AUTO_TEST_CASE(shouldAcceptValidFeeConfigurationPayload) +{ + const char* jsonPayload = R"json( + { + "channels": { + "time_alignments": [1, 2, 3, 4], + "cfd_thresholds": [10, 20, 30, 40], + "cfd_zeros": [11, 22, 33, 44], + "adc_zeros": [21, 22, 23, 24], + "adc_delays": [31, 32, 33, 34], + "range_correction_adc0": [2048, 2048, 1025, 1024], + "range_correction_adc1": [2048, 2047, 2046, 2045], + "channel_mask_data": [true, false, true, false], + "channel_mask_triggers": [true, true, false, false] + }, + "pm_a": [ + { + "or_gate": 1.21, + "trg_charge_low_level": 2, + "trg_charge_high_level": 5 + }, + { + "or_gate": 1.22, + "trg_charge_low_level": 4, + "trg_charge_high_level": 7 + } + ], + "pm_c": [ + { + "or_gate": 1.22, + "trg_charge_low_level": 4, + "trg_charge_high_level": 7 + }, + { + "or_gate": 1.22, + "trg_charge_low_level": 4, + "trg_charge_high_level": 7 + } + ], + "tcm": { + "phase_delay_a": 3.3, + "phase_delay_c": 4.4 + }, + "triggers": { + "trigger_a": 123 + } + } + )json"; + + rapidjson::Document doc = createDocumentFromString(jsonPayload); + + SimpleFITFEEConfigurationReader reader; + std::string errorMessage; + + BOOST_CHECK_MESSAGE(reader.validateSchema(doc, errorMessage), errorMessage); +} + +BOOST_AUTO_TEST_CASE(shouldAcceptValidFeeConfigurationPayloadWithNullPmData) +{ + const char* jsonPayload = R"json( + { + "channels": { + "time_alignments": [1, 2, 3, 4], + "cfd_thresholds": [10, 20, 30, 40], + "cfd_zeros": [11, 22, 33, 44], + "adc_zeros": [21, 22, 23, 24], + "adc_delays": [31, 32, 33, 34], + "range_correction_adc0": [2048, 2048, 1025, 1024], + "range_correction_adc1": [2048, 2047, 2046, 2045], + "channel_mask_data": [true, false, true, false], + "channel_mask_triggers": [true, true, false, false] + }, + "pm_a": [ + { + "or_gate": 1.21, + "trg_charge_low_level": 2, + "trg_charge_high_level": 5 + }, + null, + { + "or_gate": 1.21, + "trg_charge_low_level": 2, + "trg_charge_high_level": 5 + } + ], + "pm_c": [ + null, + { + "or_gate": 1.21, + "trg_charge_low_level": 2, + "trg_charge_high_level": 5 + }, + { + "or_gate": 1.21, + "trg_charge_low_level": 2, + "trg_charge_high_level": 5 + }, + null, + null + ], + "tcm": { + "phase_delay_a": 3.3, + "phase_delay_c": 4.4 + }, + "triggers": { + "trigger_a": 123 + } + } + )json"; + + rapidjson::Document doc = createDocumentFromString(jsonPayload); + + SimpleFITFEEConfigurationReader reader; + std::string errorMessage; + + BOOST_CHECK_MESSAGE(reader.validateSchema(doc, errorMessage), errorMessage); +} + +BOOST_AUTO_TEST_CASE(shouldDetectInvalidPayload) +{ + SimpleFITFEEConfigurationReader reader; + std::string errorMessage; + + const char* missingChannelData = R"json( + { + "channels": { + "time_alignments": [1, 2, 3, 4], + "cfd_thresholds": [10, 20, 40, 44], + "cfd_zeros": [11, 22, 33, 44], + "adc_delays": [31, 32, 33, 34], + "range_correction_adc0": [2048, 2048, 1025, 1024], + "range_correction_adc1": [2048, 2047, 2046, 2045], + "channel_mask_data": [true, false, true, false], + "channel_mask_triggers": [true, true, false, false] + }, + "pm_a": [ + { + "or_gate": 1.21, + "trg_charge_low_level": 2, + "trg_charge_high_level": 5 + }, + null, + { + "or_gate": 1.21, + "trg_charge_low_level": 2, + "trg_charge_high_level": 5 + } + ], + "pm_c": [ + null, + { + "or_gate": 1.21, + "trg_charge_low_level": 2, + "trg_charge_high_level": 5 + }, + { + "or_gate": 1.21, + "trg_charge_low_level": 2, + "trg_charge_high_level": 5 + }, + null, + null + ], + "tcm": { + "phase_delay_a": 3.3, + "phase_delay_c": 4.4 + }, + "triggers": { + "trigger_a": 123 + } + } + )json"; + + rapidjson::Document doc = createDocumentFromString(missingChannelData); + BOOST_CHECK(reader.validateSchema(doc, errorMessage) == false); + + const char* invalidPmConfig = R"json( + { + "channels": { + "time_alignments": [1, 2, 3, 5, 4], + "cfd_thresholds": [10, 20, 30, 40], + "cfd_zeros": [11, 22, 33, 44], + "adc_zeros": [21, 22, 23, 24], + "range_correction_adc0": [2048, 2048, 1025, 1024], + "range_correction_adc1": [2048, 2047, 2046, 2045], + "channel_mask_data": [true, false, true, false], + "channel_mask_triggers": [true, true, false, false] + }, + "pm_a": [ + { + "or_gate": 1.21, + "trg_charge_low_level": 2, + "trg_charge_high_level": 5 + }, + null, + { + "or_gate": 1.21, + "trg_charge_low_level": 2, + "trg_charge_high_level": 5 + } + ], + "pm_c": [ + { + "or_gate": 1.21, + "trg_charge_low_level": 2, + "trg_charge_high_level": 5 + } + ], + "tcm": { + "phase_delay_a": 3.3, + "phase_delay_c": 4.4 + }, + "triggers": { + "trigger_a": 123 + } + } + )json"; + + doc = createDocumentFromString(invalidPmConfig); + BOOST_CHECK(reader.validateSchema(doc, errorMessage) == false); + + const char* invalidTcmConfig = R"json( + { + "channels": { + "time_alignments": [1, 2, 3, 4], + "cfd_thresholds": [10, 20, 30, 40], + "cfd_zeros": [11, 22, 33, 44], + "adc_zeros": [21, 22, 23, 24], + "adc_delays": [31, 32, 33, 34], + "range_correction_adc0": [2048, 2048, 1025, 1024], + "range_correction_adc1": [2048, 2047, 2046, 2045], + "channel_mask_data": [true, false, true, false], + "channel_mask_triggers": [true, true, false, false] + }, + "pm_a": [ + { + "or_gate": 1.21, + "trg_charge_low_level": 2, + "trg_charge_high_level": 5 + }, + null, + { + "or_gate": 1.21, + "trg_charge_low_level": 2, + "trg_charge_high_level": 5 + } + ], + "pm_c": [ + null, + { + "or_gate": 1.21, + "trg_charge_low_level": 2, + "trg_charge_high_level": 5 + }, + { + "or_gate": 1.21, + "trg_charge_low_level": 2, + "trg_charge_high_level": 5 + }, + null, + null + ], + "tcm": { + "phase_delay_c": 4.4 + }, + "triggers": { + "trigger_a": 123 + } + } + )json"; + + doc = createDocumentFromString(invalidTcmConfig); + BOOST_CHECK(reader.validateSchema(doc, errorMessage) == false); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/Detectors/FIT/common/tests/dcsmonitoring/FITHvConfigurationReaderTest.cxx b/Detectors/FIT/common/tests/dcsmonitoring/FITHvConfigurationReaderTest.cxx new file mode 100644 index 0000000000000..5f97eb37385df --- /dev/null +++ b/Detectors/FIT/common/tests/dcsmonitoring/FITHvConfigurationReaderTest.cxx @@ -0,0 +1,95 @@ +// 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 FITDCSMonitoring FITHvConfigurationReader +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +#include +#include +#include "FITDCSMonitoring/FITHvConfigurationReader.h" +#include "DataFormatsFIT/Configuration.h" + +using namespace o2::fit; + +BOOST_AUTO_TEST_SUITE(o2_fit_dcs_monitoring) + +rapidjson::Document createEmptyPayload() +{ + rapidjson::Document doc; + doc.SetObject(); + return doc; +} + +rapidjson::Document createDocumentFromString(const char* data) +{ + rapidjson::Document doc; + doc.Parse(data); + return doc; +} + +template +void addToPayloadHvChannels(rapidjson::Document& doc, float (&gainValues)[NChannels]) +{ + auto& allocator = doc.GetAllocator(); + + rapidjson::Value gainJson(rapidjson::kArrayType); + for (int idx = 0; idx < NChannels; idx++) { + gainJson.PushBack(gainValues[idx], allocator); + } + rapidjson::Value hvChannelsJson(rapidjson::kObjectType); + hvChannelsJson.AddMember("gain", gainJson, allocator); + doc.AddMember("hv_channels", hvChannelsJson, allocator); +} + +template +HvChannelsConfig createExpectedConfig(float (&gainValues)[NChannels]) +{ + HvChannelsConfig expectedConfig; + std::memcpy(std::begin(expectedConfig.gain), gainValues, sizeof(float) * NChannels); + return expectedConfig; +} + +BOOST_AUTO_TEST_CASE(shouldParseHvChannels) +{ + constexpr size_t NChannels = 5; + float gainValues[NChannels] = {1.0, 2.1, 3.2, 4.3, 5.4}; + + rapidjson::Document doc = createEmptyPayload(); + addToPayloadHvChannels(doc, gainValues); + + HvChannelsConfig channelsConfig; + FITHvConfigurationReader reader; + reader.parseHvChannelData(doc, "hv_channels", channelsConfig); + + HvChannelsConfig expectedConfig = createExpectedConfig(gainValues); + + BOOST_CHECK(expectedConfig == channelsConfig); +} + +BOOST_AUTO_TEST_CASE(shouldAcceptValidJsonPayload) +{ + const char* jsonPayload = R"json( + { + "hv_channels" : { + "gain": [1,2,3,4] + } + } + )json"; + + rapidjson::Document doc = createDocumentFromString(jsonPayload); + + FITHvConfigurationReader reader; + std::string errorMessage; + BOOST_CHECK_MESSAGE(reader.validateSchema(doc, errorMessage), errorMessage); +} + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file