diff --git a/Modules/TPC/include/TPC/ClusterVisualizer.h b/Modules/TPC/include/TPC/ClusterVisualizer.h index 1d08cf4abe..1ca259e52f 100644 --- a/Modules/TPC/include/TPC/ClusterVisualizer.h +++ b/Modules/TPC/include/TPC/ClusterVisualizer.h @@ -65,6 +65,12 @@ 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: o2::ccdb::CcdbApi mCdbApi; std::string mHost; diff --git a/Modules/TPC/include/TPC/Clusters.h b/Modules/TPC/include/TPC/Clusters.h index 3c0eb3bb53..f23cd65c76 100644 --- a/Modules/TPC/include/TPC/Clusters.h +++ b/Modules/TPC/include/TPC/Clusters.h @@ -63,6 +63,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 b9d19a0a1b..d51fb1f55f 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 2125743bf0..6a8391c8c2 100644 --- a/Modules/TPC/run/tpcQCClusters_direct.json +++ b/Modules/TPC/run/tpcQCClusters_direct.json @@ -28,12 +28,12 @@ "className": "o2::quality_control_modules::tpc::Clusters", "moduleName": "QcTPC", "detectorName": "TPC", - "cycleDurationSeconds": "10", + "cycleDurationSeconds": "60", "maxNumberCycles": "-1", "resetAfterCycles": "5", "dataSource": { "type": "direct", - "query" : "input:TPC/CLUSTERNATIVE" + "query" : "input:TPC/CLUSTERNATIVE, grpecs:GRP/GRPECS" }, "taskParameters": { "mergeableOutput": "true", @@ -42,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 25edd12e41..a24b9a816e 100644 --- a/Modules/TPC/src/ClusterVisualizer.cxx +++ b/Modules/TPC/src/ClusterVisualizer.cxx @@ -120,14 +120,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; @@ -149,12 +151,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; auto clusterData = mCdbApi.retrieveFromTFileAny(mPath, @@ -194,6 +209,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++; + + calDet = clusters.getOccupancy(); + 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++; + vecPtr = toVector(mCalDetCanvasVec.at(calDetIter)); + makeRadialProfile(calDet, vecPtr.at(0), int(mRanges[calDet.getName()].at(0)), mRanges[calDet.getName()].at(1), mRanges[calDet.getName()].at(2)); + calDetIter++; } void ClusterVisualizer::finalize(Trigger t, framework::ServiceRegistryRef) @@ -205,4 +228,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 fe14ab4f6b..4cb6ed3b03 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 "DataFormatsParameters/GRPECSObject.h" // QC includes #include "QualityControl/QcInfoLogger.h" @@ -73,6 +74,7 @@ void Clusters::initialize(InitContext& /*ctx*/) mWrapperVector.emplace_back(&mQCClusters.getClusters().getSigmaTime()); mWrapperVector.emplace_back(&mQCClusters.getClusters().getSigmaPad()); mWrapperVector.emplace_back(&mQCClusters.getClusters().getTimeBin()); + mWrapperVector.emplace_back(&mQCClusters.getClusters().getOccupancy()); 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 +82,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 +126,7 @@ void Clusters::processClusterNative(InputRecord& inputs) } } } + mQCClusters.getClusters().endTF(); } void Clusters::processKrClusters(InputRecord& inputs) @@ -138,17 +142,21 @@ void Clusters::processKrClusters(InputRecord& inputs) mQCClusters.getClusters().processCluster(cl, Sector(cl.sector), int(cl.meanRow)); } } + mQCClusters.getClusters().endTF(); } void Clusters::monitorData(ProcessingContext& ctx) { mQCClusters.getClusters().denormalize(); + //get grpECS object here + auto const& grpECS = ctx.inputs().get("grpecs"); + mQCClusters.getClusters().setnHBFperTF(grpECS->getNHBFPerTF()); processClusterNative(ctx.inputs()); processKrClusters(ctx.inputs()); if (!mIsMergeable) { - mQCClusters.getClusters().normalize(); + mQCClusters.getClusters().normalize(grpECS->getNHBFPerTF()); fillCanvases(mQCClusters.getClusters().getNClusters(), mNClustersCanvasVec, mCustomParameters, "NClusters"); fillCanvases(mQCClusters.getClusters().getQMax(), mQMaxCanvasVec, mCustomParameters, "Qmax"); @@ -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); } }