diff --git a/Modules/TPC/include/TPC/ClusterVisualizer.h b/Modules/TPC/include/TPC/ClusterVisualizer.h index 1d08cf4abe..7fd9340af1 100644 --- a/Modules/TPC/include/TPC/ClusterVisualizer.h +++ b/Modules/TPC/include/TPC/ClusterVisualizer.h @@ -65,7 +65,14 @@ class ClusterVisualizer final : public quality_control::postprocessing::PostProc /// \param services Interface containing optional interfaces, for example DatabaseInterface void finalize(quality_control::postprocessing::Trigger, framework::ServiceRegistryRef) override; + template + void makeRadialProfile(o2::tpc::CalDet& calDet, TCanvas* canv, int nbinsY, float yMin, float yMax); + + template + void fillRadialHisto(TH2D& h2D, const o2::tpc::CalDet& calDet, const o2::tpc::Side side); + private: + int mNHBFPerTF = 32; o2::ccdb::CcdbApi mCdbApi; std::string mHost; std::vector>> mCalDetCanvasVec{}; ///< vector containing a vector of summary canvases for every CalDet object diff --git a/Modules/TPC/include/TPC/Clusters.h b/Modules/TPC/include/TPC/Clusters.h index 3c0eb3bb53..97741af41b 100644 --- a/Modules/TPC/include/TPC/Clusters.h +++ b/Modules/TPC/include/TPC/Clusters.h @@ -55,6 +55,7 @@ class Clusters /*final*/ : public TaskInterface // todo add back the "final" whe private: bool mIsMergeable = true; + int mNHBFPerTF = 32; ClustersData mQCClusters{}; ///< O2 Cluster task to perform actions on cluster objects std::vector mWrapperVector{}; ///< vector holding CalPad objects wrapped as TObjects; published on QCG; will be non-wrapped CalPad objects in the future std::vector> mNClustersCanvasVec{}; ///< summary canvases of the NClusters object @@ -63,6 +64,7 @@ class Clusters /*final*/ : public TaskInterface // todo add back the "final" whe std::vector> mSigmaTimeCanvasVec{}; ///< summary canvases of the SigmaTime object std::vector> mSigmaPadCanvasVec{}; ///< summary canvases of the SigmaPad object std::vector> mTimeBinCanvasVec{}; ///< summary canvases of the TimeBin object + std::vector> mOccupancyCanvasVec{}; ///< summary canvases of the Occupancy object void processClusterNative(o2::framework::InputRecord& inputs); void processKrClusters(o2::framework::InputRecord& inputs); diff --git a/Modules/TPC/run/tpcQCClusterVisualizer.json b/Modules/TPC/run/tpcQCClusterVisualizer.json index 95015deab8..fa11f30494 100644 --- a/Modules/TPC/run/tpcQCClusterVisualizer.json +++ b/Modules/TPC/run/tpcQCClusterVisualizer.json @@ -60,10 +60,11 @@ { "Q_Tot" : [ "600", "0", "600" ] }, { "Sigma_Time" : [ "200", "0", "2" ] }, { "Sigma_Pad" : [ "200", "0", "2" ] }, - { "Time_Bin" : [ "1000", "0", "100000" ] } + { "Time_Bin" : [ "1000", "0", "100000" ] }, + { "Occupancy" : [ "100", "0", "0.001" ] } ], "path_comment": "This is the path of the ClustersData object that shall be visualized.", - "path": "TPC/MO/Clusters/ClusterData", + "path": "qc/TPC/MO/Clusters/ClusterData", "dataType_comment": "This is the switch for 'RawDigits' or 'Clusters' task. Choose 'raw' or 'clusters'.", "dataType": "clusters", "initTrigger": [ @@ -71,7 +72,7 @@ ], "updateTrigger_comment": "To trigger on a specific file being updated, use e.g. 'newobject:qcdb:TPC/Calib/Noise'", "updateTrigger": [ - "newobject:qcdb:TPC/MO/Clusters/ClusterData" + "newobject:ccdb:qc/TPC/MO/Clusters/ClusterData" ], "stopTrigger": [ "userorcontrol" diff --git a/Modules/TPC/run/tpcQCClusters_direct.json b/Modules/TPC/run/tpcQCClusters_direct.json index 37509e8539..a30dd1ade1 100644 --- a/Modules/TPC/run/tpcQCClusters_direct.json +++ b/Modules/TPC/run/tpcQCClusters_direct.json @@ -28,7 +28,8 @@ "className": "o2::quality_control_modules::tpc::Clusters", "moduleName": "QcTPC", "detectorName": "TPC", - "cycleDurationSeconds": "10", + "cycleDurationSeconds": "60", + "maxNumberCycles": "-1", "resetAfterCycles": "5", "dataSource": { "type": "direct", @@ -41,7 +42,8 @@ "QtotNBins": "600", "QtotXMin": "0", "QtotXMax": "600", "SigmaPadNBins": "200", "SigmaPadXMin": "0", "SigmaPadXMax": "2", "SigmaTimeNBins": "200", "SigmaTimeXMin": "0", "SigmaTimeXMax": "2", - "TimeBinNBins": "1000", "TimeBinXMin": "0", "TimeBinXMax": "100000" + "TimeBinNBins": "1000", "TimeBinXMin": "0", "TimeBinXMax": "100000", + "OccupancyNBins": "1000", "OccupancyXMin": "0", "OccupancyXMax": "0.00001" }, "location": "local", "localMachines": [ diff --git a/Modules/TPC/src/ClusterVisualizer.cxx b/Modules/TPC/src/ClusterVisualizer.cxx index 8a8fe23680..31d527034a 100644 --- a/Modules/TPC/src/ClusterVisualizer.cxx +++ b/Modules/TPC/src/ClusterVisualizer.cxx @@ -18,6 +18,7 @@ #include "TPCBase/Painter.h" #include "TPCBase/CDBInterface.h" #include "TPCQC/Helpers.h" +#include "DetectorsBase/GRPGeomHelper.h" // QC includes #include "QualityControl/QcInfoLogger.h" @@ -120,14 +121,16 @@ void ClusterVisualizer::configure(const boost::property_tree::ptree& config) "Q_Tot", "Sigma_Pad", "Sigma_Time", - "Time_Bin" + "Time_Bin", + "Occupancy" }; } else if (type == "raw") { mIsClusters = false; mObservables = { "N_RawDigits", "Q_Max", - "Time_Bin" + "Time_Bin", + "Occupancy" }; } else { ILOG(Error, Support) << "No valid data type given. 'dataType' has to be either 'clusters' or 'raw'." << ENDM; @@ -138,6 +141,8 @@ void ClusterVisualizer::initialize(Trigger, framework::ServiceRegistryRef) { mCdbApi.init(mHost); + mNHBFPerTF = o2::base::GRPGeomHelper::instance().getNHBFPerTF(); + if (mCalDetCanvasVec.size() > 0) { mCalDetCanvasVec.clear(); } @@ -153,12 +158,25 @@ void ClusterVisualizer::initialize(Trigger, framework::ServiceRegistryRef) mStoreMaps.size() > 1 ? mStoreMaps.at(calDetIter) : mStoreMaps.at(0)); calDetIter++; } + if (mIsClusters) { + mCalDetCanvasVec.emplace_back(std::vector>()); + addAndPublish(getObjectsManager(), + mCalDetCanvasVec.back(), + { "c_radial_profile_Occupancy" }, + mStoreMaps.size() > 1 ? mStoreMaps.at(calDetIter) : mStoreMaps.at(0)); + } } void ClusterVisualizer::update(Trigger t, framework::ServiceRegistryRef) { ILOG(Info, Support) << "Trigger type is: " << t.triggerType << ", the timestamp is " << t.timestamp << ENDM; + for (auto& vec : mCalDetCanvasVec) { + for (auto& canvas : vec) { + canvas.get()->Clear(); + } + } + auto calDetIter = 0; std::unique_ptr clusterData(mCdbApi.retrieveFromTFileAny(mPath, @@ -199,6 +217,14 @@ void ClusterVisualizer::update(Trigger t, framework::ServiceRegistryRef) vecPtr = toVector(mCalDetCanvasVec.at(calDetIter)); o2::tpc::painter::makeSummaryCanvases(calDet, int(mRanges[calDet.getName()].at(0)), mRanges[calDet.getName()].at(1), mRanges[calDet.getName()].at(2), false, &vecPtr); calDetIter++; + + auto occupancy = clusters.getOccupancy(mNHBFPerTF); + vecPtr = toVector(mCalDetCanvasVec.at(calDetIter)); + o2::tpc::painter::makeSummaryCanvases(occupancy, int(mRanges[occupancy.getName()].at(0)), mRanges[occupancy.getName()].at(1), mRanges[occupancy.getName()].at(2), false, &vecPtr); + calDetIter++; + vecPtr = toVector(mCalDetCanvasVec.at(calDetIter)); + makeRadialProfile(occupancy, vecPtr.at(0), int(mRanges[occupancy.getName()].at(0)), mRanges[occupancy.getName()].at(1), mRanges[occupancy.getName()].at(2)); + calDetIter++; } void ClusterVisualizer::finalize(Trigger t, framework::ServiceRegistryRef) @@ -214,4 +240,64 @@ void ClusterVisualizer::finalize(Trigger t, framework::ServiceRegistryRef) } } +template +void ClusterVisualizer::makeRadialProfile(o2::tpc::CalDet& calDet, TCanvas* canv, int nbinsY, float yMin, float yMax) +{ + const std::string_view calName = calDet.getName(); + const auto radialBinning = o2::tpc::painter::getRowBinningCM(); + + auto hAside2D = new TH2D(fmt::format("h_{}_radialProfile_Aside", calName).data(), fmt::format("{}: Radial profile (A-Side)", calName).data(), radialBinning.size() - 1, radialBinning.data(), nbinsY, yMin, yMax); + hAside2D->GetXaxis()->SetTitle("x (cm)"); + hAside2D->GetYaxis()->SetTitle(fmt::format("{}", calName).data()); + hAside2D->SetTitleOffset(1.05, "XY"); + hAside2D->SetTitleSize(0.05, "XY"); + hAside2D->SetStats(0); + + auto hCside2D = new TH2D(fmt::format("h_{}_radialProfile_Cside", calName).data(), fmt::format("{}: Radial profile (C-Side)", calName).data(), radialBinning.size() - 1, radialBinning.data(), nbinsY, yMin, yMax); + hCside2D->GetXaxis()->SetTitle("x (cm)"); + hCside2D->GetYaxis()->SetTitle(fmt::format("{}", calName).data()); + hCside2D->SetTitleOffset(1.05, "XY"); + hCside2D->SetTitleSize(0.05, "XY"); + hCside2D->SetStats(0); + + fillRadialHisto(*hAside2D, calDet, o2::tpc::Side::A); + fillRadialHisto(*hCside2D, calDet, o2::tpc::Side::C); + + canv->Divide(1, 2); + canv->cd(1); + hAside2D->Draw("colz"); + hAside2D->SetStats(0); + hAside2D->ProfileX("profile_ASide", 1, -1, "d,same"); + + canv->cd(2); + hCside2D->Draw("colz"); + hCside2D->ProfileX("profile_CSide", 1, -1, "d,same"); + hAside2D->SetStats(0); + + hAside2D->SetBit(TObject::kCanDelete); + hCside2D->SetBit(TObject::kCanDelete); +} + +template +void ClusterVisualizer::fillRadialHisto(TH2D& h2D, const o2::tpc::CalDet& calDet, const o2::tpc::Side side) +{ + const o2::tpc::Mapper& mapper = o2::tpc::Mapper::instance(); + + for (o2::tpc::ROC roc; !roc.looped(); ++roc) { + if (roc.side() != side) { + continue; + } + const int nrows = mapper.getNumberOfRowsROC(roc); + for (int irow = 0; irow < nrows; ++irow) { + const int npads = mapper.getNumberOfPadsInRowROC(roc, irow); + const int globalRow = irow + (roc >= o2::tpc::Mapper::getNumberOfIROCs()) * o2::tpc::Mapper::getNumberOfRowsInIROC(); + for (int ipad = 0; ipad < npads; ++ipad) { + const auto val = calDet.getValue(roc, irow, ipad); + const o2::tpc::LocalPosition2D pos = mapper.getPadCentre(o2::tpc::PadPos(globalRow, ipad)); + h2D.Fill(pos.X(), val); + } + } + } +} + } // namespace o2::quality_control_modules::tpc diff --git a/Modules/TPC/src/Clusters.cxx b/Modules/TPC/src/Clusters.cxx index 065ac17a10..ad70f2d220 100644 --- a/Modules/TPC/src/Clusters.cxx +++ b/Modules/TPC/src/Clusters.cxx @@ -20,6 +20,7 @@ #include "DataFormatsTPC/ClusterNative.h" #include "TPCBase/Painter.h" #include "Framework/InputRecordWalker.h" +#include "DetectorsBase/GRPGeomHelper.h" // QC includes #include "QualityControl/QcInfoLogger.h" @@ -42,6 +43,8 @@ void Clusters::initialize(InitContext& /*ctx*/) mQCClusters.setName("ClusterData"); + mNHBFPerTF = o2::base::GRPGeomHelper::instance().getNHBFPerTF(); + const auto last = mCustomParameters.end(); const auto itMergeable = mCustomParameters.find("mergeableOutput"); std::string mergeable; @@ -73,6 +76,8 @@ void Clusters::initialize(InitContext& /*ctx*/) mWrapperVector.emplace_back(&mQCClusters.getClusters().getSigmaTime()); mWrapperVector.emplace_back(&mQCClusters.getClusters().getSigmaPad()); mWrapperVector.emplace_back(&mQCClusters.getClusters().getTimeBin()); + auto occupancy = mQCClusters.getClusters().getOccupancy(mNHBFPerTF); + mWrapperVector.emplace_back(&occupancy); addAndPublish(getObjectsManager(), mNClustersCanvasVec, { "c_Sides_N_Clusters", "c_ROCs_N_Clusters_1D", "c_ROCs_N_Clusters_2D" }); addAndPublish(getObjectsManager(), mQMaxCanvasVec, { "c_Sides_Q_Max", "c_ROCs_Q_Max_1D", "c_ROCs_Q_Max_2D" }); @@ -80,6 +85,7 @@ void Clusters::initialize(InitContext& /*ctx*/) addAndPublish(getObjectsManager(), mSigmaTimeCanvasVec, { "c_Sides_Sigma_Time", "c_ROCs_Sigma_Time_1D", "c_ROCs_Sigma_Time_2D" }); addAndPublish(getObjectsManager(), mSigmaPadCanvasVec, { "c_Sides_Sigma_Pad", "c_ROCs_Sigma_Pad_1D", "c_ROCs_Sigma_Pad_2D" }); addAndPublish(getObjectsManager(), mTimeBinCanvasVec, { "c_Sides_Time_Bin", "c_ROCs_Time_Bin_1D", "c_ROCs_Time_Bin_2D" }); + addAndPublish(getObjectsManager(), mOccupancyCanvasVec, { "c_Sides_Occupancy", "c_ROCs_Occupancy_1D", "c_ROCs_Occupancy_2D" }); for (auto& wrapper : mWrapperVector) { getObjectsManager()->startPublishing(&wrapper); @@ -123,6 +129,7 @@ void Clusters::processClusterNative(InputRecord& inputs) } } } + mQCClusters.getClusters().endTF(); } void Clusters::processKrClusters(InputRecord& inputs) @@ -138,6 +145,7 @@ void Clusters::processKrClusters(InputRecord& inputs) mQCClusters.getClusters().processCluster(cl, Sector(cl.sector), int(cl.meanRow)); } } + mQCClusters.getClusters().endTF(); } void Clusters::monitorData(ProcessingContext& ctx) @@ -156,12 +164,14 @@ void Clusters::monitorData(ProcessingContext& ctx) fillCanvases(mQCClusters.getClusters().getSigmaTime(), mSigmaTimeCanvasVec, mCustomParameters, "SigmaPad"); fillCanvases(mQCClusters.getClusters().getSigmaPad(), mSigmaPadCanvasVec, mCustomParameters, "SigmaTime"); fillCanvases(mQCClusters.getClusters().getTimeBin(), mTimeBinCanvasVec, mCustomParameters, "TimeBin"); + fillCanvases(mQCClusters.getClusters().getTimeBin(), mOccupancyCanvasVec, mCustomParameters, "Occupancy"); } } void Clusters::endOfCycle() { - ILOG(Debug, Devel) << "endOfCycle" << ENDM; + ILOG(Info, Support) << "endOfCycle" << ENDM; + ILOG(Info, Support) << "Processed TFs: " << mQCClusters.getClusters().getProcessedTFs() << ENDM; if (mIsMergeable) { mQCClusters.getClusters().normalize(); @@ -188,6 +198,7 @@ void Clusters::reset() clearCanvases(mSigmaTimeCanvasVec); clearCanvases(mSigmaPadCanvasVec); clearCanvases(mTimeBinCanvasVec); + clearCanvases(mOccupancyCanvasVec); } }