diff --git a/Modules/TOF/CMakeLists.txt b/Modules/TOF/CMakeLists.txt index ed8b787631..3aa4cb4cff 100644 --- a/Modules/TOF/CMakeLists.txt +++ b/Modules/TOF/CMakeLists.txt @@ -23,6 +23,7 @@ target_sources(O2QcTOF src/PostProcessDiagnosticPerCrate.cxx src/PostProcessHitMap.cxx src/PostProcessingLostOrbits.cxx + src/PostProcessingLuminometer.cxx # Trending src/TrendingHits.cxx src/TrendingRate.cxx @@ -80,6 +81,7 @@ add_root_dictionary(O2QcTOF include/TOF/PostProcessDiagnosticPerCrate.h include/TOF/PostProcessHitMap.h include/TOF/PostProcessingLostOrbits.h + include/TOF/PostProcessingLuminometer.h # Trending include/TOF/TrendingHits.h include/TOF/TrendingRate.h diff --git a/Modules/TOF/include/TOF/LinkDef.h b/Modules/TOF/include/TOF/LinkDef.h index 1a83fdc207..495a8d2e71 100644 --- a/Modules/TOF/include/TOF/LinkDef.h +++ b/Modules/TOF/include/TOF/LinkDef.h @@ -23,6 +23,7 @@ #pragma link C++ class o2::quality_control_modules::tof::PostProcessDiagnosticPerCrate + ; #pragma link C++ class o2::quality_control_modules::tof::PostProcessHitMap + ; #pragma link C++ class o2::quality_control_modules::tof::PostProcessingLostOrbits + ; +#pragma link C++ class o2::quality_control_modules::tof::PostProcessingLuminometer + ; // Trending #pragma link C++ class o2::quality_control_modules::tof::TrendingHits + ; #pragma link C++ class o2::quality_control_modules::tof::TrendingRate + ; diff --git a/Modules/TOF/include/TOF/PostProcessingLuminometer.h b/Modules/TOF/include/TOF/PostProcessingLuminometer.h new file mode 100644 index 0000000000..02b043394e --- /dev/null +++ b/Modules/TOF/include/TOF/PostProcessingLuminometer.h @@ -0,0 +1,76 @@ +// 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 PostProcessingLuminometer.h +/// \author Francesca Ercolessi francesca.ercolessi@cern.ch +/// + +#ifndef QUALITYCONTROL_POSTPROCESSINGLUMINOMETER_H +#define QUALITYCONTROL_POSTPROCESSINGLUMINOMETER_H + +#include "QualityControl/PostProcessingInterface.h" +#include "QualityControl/DatabaseInterface.h" + +class TH1F; + +namespace o2::quality_control_modules::tof +{ + +/// \brief Post processing to monitor lost orbits in TimeFrame +/// \author Francesca Ercolessi francesca.ercolessi@cern.ch +class PostProcessingLuminometer final : public quality_control::postprocessing::PostProcessingInterface +{ + public: + /// \brief Constructor + PostProcessingLuminometer() = default; + /// \brief Destructor + ~PostProcessingLuminometer() override; + + /// \brief Configuration of a post-processing task. + /// Configuration of a post-processing task. Can be overridden if user wants to retrieve the configuration of the task. + /// \param config ConfigurationInterface with prefix set to "" + virtual void configure(const boost::property_tree::ptree& config) override; + /// \brief Initialization of a post-processing task. + /// Initialization of a post-processing task. User receives a Trigger which caused the initialization and a service + /// registry with singleton interfaces. + /// \param trigger Trigger which caused the initialization, for example Trigger::SOR + /// \param services Interface containing optional interfaces, for example DatabaseInterface + void initialize(quality_control::postprocessing::Trigger, framework::ServiceRegistryRef) override; + /// \brief Update of a post-processing task. + /// Update of a post-processing task. User receives a Trigger which caused the update and a service + /// registry with singleton interfaces. + /// \param trigger Trigger which caused the initialization, for example Trigger::Period + /// \param services Interface containing optional interfaces, for example DatabaseInterface + void update(quality_control::postprocessing::Trigger, framework::ServiceRegistryRef) override; + /// \brief Finalization of a post-processing task. + /// Finalization of a post-processing task. User receives a Trigger which caused the finalization and a service + /// registry with singleton interfaces. + /// \param trigger Trigger which caused the initialization, for example Trigger::EOR + /// \param services Interface containing optional interfaces, for example DatabaseInterface + void finalize(quality_control::postprocessing::Trigger, framework::ServiceRegistryRef) override; + + private: + o2::quality_control::repository::DatabaseInterface* mDatabase = nullptr; + std::string mCCDBPath = "TOF/MO/TaskDigits/"; + std::string mMOEfficiency = "OrbitVsCrate"; + std::string mMOActiveChannels = "HitMap"; + std::string mMOMultiplicity = "Multiplicity/Integrated"; + std::shared_ptr mHistoOrbitsInTFEfficiency = nullptr; + std::shared_ptr mHistoLuminometer = nullptr; + int mBins = 1100; + float mMaxRange = 1.1; + float mActiveThr = 1; +}; + +} // namespace o2::quality_control_modules::tof + +#endif // QUALITYCONTROL_POSTPROCESSINGLuminometer_H \ No newline at end of file diff --git a/Modules/TOF/src/PostProcessingLuminometer.cxx b/Modules/TOF/src/PostProcessingLuminometer.cxx new file mode 100644 index 0000000000..bc83856f42 --- /dev/null +++ b/Modules/TOF/src/PostProcessingLuminometer.cxx @@ -0,0 +1,154 @@ +// 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 PostProcessingLuminometer.cxx +/// \author Francesca Ercolessi francesca.ercolessi@cern.ch +/// + +#include "TOF/PostProcessingLuminometer.h" +#include "QualityControl/QcInfoLogger.h" +#include "QualityControl/DatabaseInterface.h" + +#include "TOF/Utils.h" + +#include +#include +#include + +using namespace o2::quality_control::postprocessing; + +namespace o2::quality_control_modules::tof +{ + +PostProcessingLuminometer::~PostProcessingLuminometer() +{ +} + +void PostProcessingLuminometer::configure(const boost::property_tree::ptree& config) +{ + if (const auto& customConfigs = config.get_child_optional("qc.postprocessing." + getID() + ".customization"); customConfigs.has_value()) { + for (const auto& customConfig : customConfigs.value()) { // Plot configuration + if (const auto& customNames = customConfig.second.get_child_optional("name"); customNames.has_value()) { + if (customConfig.second.get("name") == "Nbins") { + mBins = customConfig.second.get("value"); + ILOG(Info, Support) << "Setting Nbins to " << mBins << ENDM; + } else if (customConfig.second.get("name") == "MaxValue") { + mMaxRange = customConfig.second.get("value"); + ILOG(Info, Support) << "Setting Nbins to " << mMaxRange << ENDM; + } else if (customConfig.second.get("name") == "CCDBPath") { + mCCDBPath = customConfig.second.get("value"); + ILOG(Info, Support) << "Setting CCDBPath to " << mCCDBPath << ENDM; + } else if (customConfig.second.get("name") == "ActiveThr") { + mActiveThr = customConfig.second.get("value"); + ILOG(Info, Support) << "Setting mActiveThr to " << mActiveThr << ENDM; + } + } + } + } +} + +void PostProcessingLuminometer::initialize(Trigger, framework::ServiceRegistryRef services) +{ + float bin_width = mMaxRange / mBins; + mHistoOrbitsInTFEfficiency.reset(); + mHistoOrbitsInTFEfficiency = std::make_shared("OrbitsInTFEfficiency", "Fraction of orbits in TF;Fraction of orbits in TF; Counts x n_{crates} ", mBins, bin_width / 2, mMaxRange + bin_width / 2); + getObjectsManager()->startPublishing(mHistoOrbitsInTFEfficiency.get()); + + mHistoLuminometer.reset(); + mHistoLuminometer = std::make_shared("Luminometer", "Luminometer; ; hit_{TOF}/(eff_{RO}f_{active}) ", 1000, 0., 10000); + getObjectsManager()->startPublishing(mHistoLuminometer.get()); + + mDatabase = &services.get(); +} + +void PostProcessingLuminometer::update(Trigger t, framework::ServiceRegistryRef) +{ + ILOG(Info, Support) << "Trigger type is: " << t.triggerType << ", the timestamp is " << t.timestamp << ENDM; + + if (mHistoOrbitsInTFEfficiency) { + mHistoOrbitsInTFEfficiency->Reset(); + } + if (mHistoLuminometer) { + mHistoLuminometer->Reset(); + } + + TH1F* tempPerCrateHisto[72]; // 72 crates + for (int i = 0; i < 72; i++) { // loop over crates + tempPerCrateHisto[i] = nullptr; + } + + auto moEfficiency = mDatabase->retrieveMO(mCCDBPath, mMOEfficiency, t.timestamp, t.activity); + auto moActiveChannels = mDatabase->retrieveMO(mCCDBPath, mMOActiveChannels, t.timestamp, t.activity); + auto moMultiplicity = mDatabase->retrieveMO(mCCDBPath, mMOMultiplicity, t.timestamp, t.activity); + + float ROeff = 1.; + float hitMult = 0.; + float activeCh = 1.; + + // Readout efficiency + TH2F* moHEfficiency = static_cast(moEfficiency ? moEfficiency->getObject() : nullptr); + if (moHEfficiency) { + ILOG(Info, Support) << "Found MO " << mMOEfficiency << " in path " << mCCDBPath << ENDM; + for (int i = 0; i < 72; i++) { // loop over crates + tempPerCrateHisto[i] = (TH1F*)moHEfficiency->ProjectionY(Form("hPerCrate%i", i), i + 1, i + 1); + mHistoOrbitsInTFEfficiency->Fill(tempPerCrateHisto[i]->Integral() / (32.f * 3.f)); // 32 orbits in Time Frame, 3 readout windows per orbit + } + } else { + ILOG(Warning) << "Did not find MO " << mMOEfficiency << " in path " << mCCDBPath << ENDM; + } + + if (mHistoOrbitsInTFEfficiency) { + ROeff = mHistoOrbitsInTFEfficiency->GetMean(); + } + + // Active channels + TH2F* moHActiveChannels = static_cast(moActiveChannels ? moActiveChannels->getObject() : nullptr); + if (moHActiveChannels) { + ILOG(Info, Support) << "Found MO " << mMOActiveChannels << " in path " << mCCDBPath << ENDM; + + int counterAll = 0; + int counterActive = 0; + + for (int i = 1; i <= moHActiveChannels->GetNbinsX(); i++) { + for (int j = 1; j <= moHActiveChannels->GetNbinsY(); j++) { + counterAll++; + + if (moHActiveChannels->GetBinContent(i, j) > mActiveThr) { + counterActive++; + } + } + } + + activeCh = (float)counterActive / counterAll; + } else { + ILOG(Warning) << "Did not find MO " << mMOActiveChannels << " in path " << mCCDBPath << ENDM; + } + + // Multiplicity + TH1F* moHMultiplicity = static_cast(moMultiplicity ? moMultiplicity->getObject() : nullptr); + if (moHMultiplicity) { + ILOG(Info, Support) << "Found MO " << mMOMultiplicity << " in path " << mCCDBPath << ENDM; + hitMult = moHMultiplicity->GetMean(); + } else { + ILOG(Warning) << "Did not find MO " << mMOMultiplicity << " in path " << mCCDBPath << ENDM; + } + + mHistoLuminometer->Fill(hitMult / (activeCh * ROeff)); +} + +void PostProcessingLuminometer::finalize(Trigger, framework::ServiceRegistryRef) +{ + // Only if you don't want it to be published after finalisation. + getObjectsManager()->stopPublishing(mHistoLuminometer.get()); +} + +} // namespace o2::quality_control_modules::tof