diff --git a/Modules/FIT/FT0/CMakeLists.txt b/Modules/FIT/FT0/CMakeLists.txt index 35ae4c0e6d..8a7ca510dd 100644 --- a/Modules/FIT/FT0/CMakeLists.txt +++ b/Modules/FIT/FT0/CMakeLists.txt @@ -11,7 +11,8 @@ target_sources(O2QcFT0 PRIVATE src/AgingLaserTask.cxx src/OutOfBunchCollCheck.cxx src/MergedTreeCheck.cxx src/RecPointsQcTask.cxx - src/ChannelGeometry.cxx) + src/ChannelGeometry.cxx + src/AmpTimeDistribution.cxx) target_include_directories( O2QcFT0 @@ -43,6 +44,7 @@ add_root_dictionary(O2QcFT0 include/FT0/MergedTreeCheck.h include/FT0/RecPointsQcTask.h include/FT0/ChannelGeometry.h + include/FT0/AmpTimeDistribution.h LINKDEF include/FT0/LinkDef.h) install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/FT0 diff --git a/Modules/FIT/FT0/include/FT0/AmpTimeDistribution.h b/Modules/FIT/FT0/include/FT0/AmpTimeDistribution.h new file mode 100644 index 0000000000..89c91e798f --- /dev/null +++ b/Modules/FIT/FT0/include/FT0/AmpTimeDistribution.h @@ -0,0 +1,47 @@ +// 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_FITAMPTIMEDISTRIBUTION_H +#define O2_FITAMPTIMEDISTRIBUTION_H + +#include "TH2F.h" + +#include +#include +#include +#include + +#include + +namespace o2::fit +{ + +struct AmpTimeDistribution { + AmpTimeDistribution() = default; + AmpTimeDistribution(const std::string& name, const std::string& title, int nBins, double minRange, double maxRange, int binsInStep = 50, int binMax = 4095, int axis = 0); + AmpTimeDistribution(const AmpTimeDistribution&); + AmpTimeDistribution(AmpTimeDistribution&&) noexcept; + AmpTimeDistribution& operator=(const AmpTimeDistribution&); + AmpTimeDistribution& operator=(AmpTimeDistribution&&) noexcept; + typedef float Content_t; // to template? + typedef TH2F Hist2F_t; + std::unique_ptr mHist = nullptr; + + void initHists(const std::string& name, const std::string& title, int nBins, double minRange, double maxRange, int binsInStep = 50, int binMax = 4095, int axis = 0); + static std::vector makeVaribleBins(const std::vector>& vecParams, int binMax = 4095); + static std::vector makeVaribleBins(int binsInStep = 50, int binMax = 4095); +}; + +template +using AmpTimeDistributionDetector = std::array, NADC>; + +} // namespace o2::fit +#endif \ No newline at end of file diff --git a/Modules/FIT/FT0/include/FT0/RecPointsQcTask.h b/Modules/FIT/FT0/include/FT0/RecPointsQcTask.h index ac57e0929f..95a89ca45a 100644 --- a/Modules/FIT/FT0/include/FT0/RecPointsQcTask.h +++ b/Modules/FIT/FT0/include/FT0/RecPointsQcTask.h @@ -19,7 +19,7 @@ #define QC_MODULE_FT0_FT0RECOQCTASK_H #include - +#include #include "QualityControl/QcInfoLogger.h" #include #include @@ -46,7 +46,7 @@ namespace o2::quality_control_modules::ft0 class RecPointsQcTask final : public TaskInterface { - static constexpr int NCHANNELS = o2::ft0::Geometry::Nchannels; + static constexpr int sNCHANNELS = o2::ft0::Geometry::Nchannels; public: /// \brief Constructor @@ -62,8 +62,10 @@ class RecPointsQcTask final : public TaskInterface void endOfActivity(const Activity& activity) override; void reset() override; using Detector_t = o2::quality_control_modules::fit::detectorFIT::DetectorFT0; + void initHists(); private: + std::array mArrAmpTimeDistribution; TList* mListHistGarbage; std::set mSetAllowedChIDs; unsigned int mTrgPos_minBias; diff --git a/Modules/FIT/FT0/src/AmpTimeDistribution.cxx b/Modules/FIT/FT0/src/AmpTimeDistribution.cxx new file mode 100644 index 0000000000..c415c9bdb6 --- /dev/null +++ b/Modules/FIT/FT0/src/AmpTimeDistribution.cxx @@ -0,0 +1,99 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include +#include + +using namespace o2::fit; + +AmpTimeDistribution::AmpTimeDistribution(const std::string& name, const std::string& title, int nBins, double minRange, double maxRange, int binsInStep, int binMax, int axis) +{ + initHists(name, title, nBins, minRange, maxRange, binsInStep, binMax, axis); +} + +AmpTimeDistribution::AmpTimeDistribution(const AmpTimeDistribution& other) +{ + if (other.mHist) { + const std::string newName = std::string(other.mHist->GetName()) + "_Cloned"; + mHist = std::unique_ptr(dynamic_cast(other.mHist->Clone(newName.c_str()))); + } +} + +AmpTimeDistribution::AmpTimeDistribution(AmpTimeDistribution&& other) noexcept : mHist(std::move(other.mHist)) +{ +} + +AmpTimeDistribution& AmpTimeDistribution::operator=(const AmpTimeDistribution& other) +{ + if (this != &other) { + if (other.mHist) { + const std::string newName = std::string(other.mHist->GetName()) + "_Cloned"; + mHist = std::unique_ptr(dynamic_cast(other.mHist->Clone(newName.c_str()))); + } else { + mHist.reset(); + } + } + return *this; +} +AmpTimeDistribution& AmpTimeDistribution::operator=(AmpTimeDistribution&& other) noexcept +{ + if (this != &other) { + mHist = std::move(other.mHist); + } + return *this; +} + +void AmpTimeDistribution::initHists(const std::string& name, const std::string& title, int nBins, double minRange, double maxRange, int binsInStep, int binMax, int axis) +{ + const auto& varBins = makeVaribleBins(binsInStep, binMax); + const int varNbins = varBins.size() - 1; + if (axis == 0) { + mHist = std::make_unique(name.c_str(), title.c_str(), varNbins, varBins.data(), nBins, minRange, maxRange); + } else if (axis == 1) { + mHist = std::make_unique(name.c_str(), title.c_str(), nBins, minRange, maxRange, varNbins, varBins.data()); + } +} + +std::vector AmpTimeDistribution::makeVaribleBins(const std::vector>& vecParams, int binMax) +{ + std::vector vecLowEdgeBins{}; + int startBin{ 0 }; + auto makeBinRange = [&vec = vecLowEdgeBins, binMax](int startBin, int binWidth, int nBins) { + const int endBin = startBin + binWidth * nBins; + for (int iBin = startBin; iBin < endBin; iBin += binWidth) { + vec.emplace_back(static_cast(iBin)); + if (iBin > binMax) { + break; + } + } + return endBin; + }; + for (const auto& entry : vecParams) { + startBin = makeBinRange(startBin, entry.first, entry.second); + } + return vecLowEdgeBins; +} + +std::vector AmpTimeDistribution::makeVaribleBins(int binsInStep, int binMax) +{ + auto generateParams = [](int binsInStep, int binMax) { + std::vector> vecParams{}; + int endBin{ 0 }; + int binWidth = 1; + while (endBin < binMax) { + vecParams.push_back({ binWidth, binsInStep }); + endBin += (binWidth * binsInStep); + binWidth *= 2; + } + return vecParams; + }; + return makeVaribleBins(generateParams(binsInStep, binMax), binMax); +} diff --git a/Modules/FIT/FT0/src/RecPointsQcTask.cxx b/Modules/FIT/FT0/src/RecPointsQcTask.cxx index 985edad808..40ed1b48c0 100644 --- a/Modules/FIT/FT0/src/RecPointsQcTask.cxx +++ b/Modules/FIT/FT0/src/RecPointsQcTask.cxx @@ -25,10 +25,11 @@ #include #include #include - +#include "DataFormatsParameters/GRPLHCIFData.h" #include "FITCommon/HelperHist.h" #include "FITCommon/HelperCommon.h" - +#include "DetectorsBase/GRPGeomHelper.h" +#include "CommonDataFormat/BunchFilling.h" namespace o2::quality_control_modules::ft0 { @@ -38,14 +39,23 @@ RecPointsQcTask::~RecPointsQcTask() { delete mListHistGarbage; } +void RecPointsQcTask::initHists() +{ + for (int iCh = 0; iCh < sNCHANNELS; iCh++) { + const std::string name = fmt::format("hAmpVsTime_ch{}", iCh); + const std::string title = fmt::format("Amp Vs Time channelID {}; Amp [ADC]; Time [ps]", iCh); + mArrAmpTimeDistribution[iCh] = o2::fit::AmpTimeDistribution(name, title, 200, -2000., 2000., 50, 4095, 0); // in total 315 bins along x-axis + getObjectsManager()->startPublishing(mArrAmpTimeDistribution[iCh].mHist.get()); + } +} void RecPointsQcTask::initialize(o2::framework::InitContext& /*ctx*/) { ILOG(Info, Support) << "@@@@initialize RecoQcTask" << ENDM; // QcInfoLogger is used. FairMQ logs will go to there as well. - mHistTime2Ch = std::make_unique("TimePerChannel", "Time vs Channel;Channel;Time [ps]", NCHANNELS, 0, NCHANNELS, 500, -2050, 2050); + mHistTime2Ch = std::make_unique("TimePerChannel", "Time vs Channel;Channel;Time [ps]", sNCHANNELS, 0, sNCHANNELS, 500, -2050, 2050); mHistTime2Ch->SetOption("colz"); - mHistAmp2Ch = std::make_unique("AmpPerChannel", "Amplitude vs Channel;Channel;Amp [#ADC channels]", NCHANNELS, 0, NCHANNELS, 200, 0, 1000); + mHistAmp2Ch = std::make_unique("AmpPerChannel", "Amplitude vs Channel;Channel;Amp [#ADC channels]", sNCHANNELS, 0, sNCHANNELS, 200, 0, 1000); mHistAmp2Ch->SetOption("colz"); mHistCollTimeAC = std::make_unique("CollTimeAC", "(T0A+T0C)/2;ps", 100, -1000, 1000); mHistCollTimeA = std::make_unique("CollTimeA", "T0A;ps", 100, -1000, 1000); @@ -87,15 +97,16 @@ void RecPointsQcTask::initialize(o2::framework::InitContext& /*ctx*/) mHistTimeA_perTrg = helper::registerHist(getObjectsManager(), PublicationPolicy::Forever, "COLZ", "TimeA_perTrg", "T0A per Trigger;Time [ps]; Trigger", binsTime, mMapTrgBits); mHistTimeC_perTrg = helper::registerHist(getObjectsManager(), PublicationPolicy::Forever, "COLZ", "TimeC_perTrg", "T0C per Trigger;Time [ps]; Trigger", binsTime, mMapTrgBits); mHistBC_perTriggers = helper::registerHist(getObjectsManager(), PublicationPolicy::Forever, "COLZ", "BC_perTriggers", "BC per Triggers;BC; Trigger", binsBC, mMapTrgBits); - - for (const auto& chID : mSetAllowedChIDs) { - auto pairHistAmpVsTime = mMapHistAmpVsTime.insert({ chID, new TH2F(Form("Amp_vs_time_channel%i", chID), Form("Amplitude vs time, channel %i;Amp;Time", chID), 1000, 0, 4000, 100, -1000, 1000) }); - if (pairHistAmpVsTime.second) { - mListHistGarbage->Add(pairHistAmpVsTime.first->second); - getObjectsManager()->startPublishing(pairHistAmpVsTime.first->second); + /* + for (const auto& chID : mSetAllowedChIDs) { + auto pairHistAmpVsTime = mMapHistAmpVsTime.insert({ chID, new TH2F(Form("Amp_vs_time_channel%i", chID), Form("Amplitude vs time, channel %i;Amp;Time", chID), 1000, 0, 4000, 100, -1000, 1000) }); + if (pairHistAmpVsTime.second) { + mListHistGarbage->Add(pairHistAmpVsTime.first->second); + getObjectsManager()->startPublishing(pairHistAmpVsTime.first->second); + } } - } - + */ + initHists(); ILOG(Info, Support) << "@@@ histos created" << ENDM; } @@ -114,9 +125,8 @@ void RecPointsQcTask::startOfActivity(const Activity& activity) mHistTimeA_perTrg->Reset(); mHistTimeC_perTrg->Reset(); mHistBC_perTriggers->Reset(); - - for (auto& entry : mMapHistAmpVsTime) { - entry.second->Reset(); + for (int iCh = 0; iCh < sNCHANNELS; iCh++) { + mArrAmpTimeDistribution[iCh].mHist->Reset(); } } @@ -128,7 +138,9 @@ void RecPointsQcTask::monitorData(o2::framework::ProcessingContext& ctx) { auto chan = ctx.inputs().get>("channels"); auto recpoints = ctx.inputs().get>("recpoints"); - + const auto& grplhcif = o2::base::GRPGeomHelper::instance().getGRPLHCIF(); + const auto& bcSchema = grplhcif ? grplhcif->getBunchFilling().getBCPattern() : o2::BunchFilling::Pattern{}; + const bool isPbPb = grplhcif ? grplhcif->getAtomicNumberB1() == 82 && grplhcif->getAtomicNumberB2() == 82 : false; for (const auto& recpoint : recpoints) { const auto bc = recpoint.getInteractionRecord().bc; int time[o2::ft0::Constants::sNCHANNELS_PM] = { 0 }; @@ -158,13 +170,14 @@ void RecPointsQcTask::monitorData(o2::framework::ProcessingContext& ctx) } } } + const bool isMinBiasEvent = (isPbPb && minBias) || (!isPbPb && triggersignals.getVertex()); // for pp only vertex, for PbPb vrt && (CENT || SCENT) for (const auto& chData : channels) { time[chData.ChId] = chData.CFDTime; amp[chData.ChId] = chData.QTCAmpl; mHistTime2Ch->Fill(static_cast(chData.ChId), static_cast(chData.CFDTime)); mHistAmp2Ch->Fill(static_cast(chData.ChId), static_cast(chData.QTCAmpl)); - if (mSetAllowedChIDs.find(static_cast(chData.ChId)) != mSetAllowedChIDs.end() && minBias) { // ampt-time dependency is needed only for PbPb runs - mMapHistAmpVsTime[chData.ChId]->Fill(chData.QTCAmpl, chData.CFDTime); + if (bcSchema.test(bc) && isMinBiasEvent) { // ampt-time dependency + mArrAmpTimeDistribution[chData.ChId].mHist->Fill(chData.QTCAmpl, chData.CFDTime); } } if (vertexTrigger) { @@ -239,9 +252,8 @@ void RecPointsQcTask::reset() mHistTimeA_perTrg->Reset(); mHistTimeC_perTrg->Reset(); mHistBC_perTriggers->Reset(); - - for (auto& entry : mMapHistAmpVsTime) { - entry.second->Reset(); + for (int iCh = 0; iCh < sNCHANNELS; iCh++) { + mArrAmpTimeDistribution[iCh].mHist->Reset(); } }