diff --git a/Modules/Common/include/Common/ReferenceComparatorCheck.h b/Modules/Common/include/Common/ReferenceComparatorCheck.h index a611a54128..8fa418c225 100644 --- a/Modules/Common/include/Common/ReferenceComparatorCheck.h +++ b/Modules/Common/include/Common/ReferenceComparatorCheck.h @@ -25,6 +25,7 @@ #include class TPaveText; +class TCanvas; namespace o2::quality_control_modules::common { @@ -50,16 +51,22 @@ class ReferenceComparatorCheck : public o2::quality_control::checker::CheckInter void endOfActivity(const Activity& activity) override; private: - Quality getSinglePlotQuality(std::shared_ptr mo, std::string& message); + Quality getSinglePlotQuality(std::shared_ptr mo, ObjectComparatorInterface* comparator, std::string& message); + void drawHorizontalRange(const std::string& moName, TCanvas* canvas, const Quality& quality); - std::unique_ptr mComparator; std::map mQualityFlags; std::map> mQualityLabels; + quality_control::core::Activity mActivity; quality_control::core::Activity mReferenceActivity; + std::string mComparatorModuleName; /// dynamic module providing the object comparator + std::string mComparatorClassName; /// name of the object comparator class bool mIgnorePeriodForReference{ true }; /// whether to specify the period name in the reference run query bool mIgnorePassForReference{ true }; /// whether to specify the pass name in the reference run query size_t mReferenceRun; + /// cached reference MOs std::unordered_map> mReferencePlots; + /// collection of object comparators with plot-specific settings + std::unordered_map> mComparators; }; } // namespace o2::quality_control_modules::common diff --git a/Modules/Common/src/ReferenceComparatorCheck.cxx b/Modules/Common/src/ReferenceComparatorCheck.cxx index 6fcb102493..84200a5014 100644 --- a/Modules/Common/src/ReferenceComparatorCheck.cxx +++ b/Modules/Common/src/ReferenceComparatorCheck.cxx @@ -34,6 +34,7 @@ #include #include #include +#include using namespace o2::quality_control; @@ -46,21 +47,13 @@ void ReferenceComparatorCheck::configure() void ReferenceComparatorCheck::startOfActivity(const Activity& activity) { - auto moduleName = mCustomParameters.atOptional("moduleName", activity).value_or(""); - auto comparatorName = mCustomParameters.atOptional("comparatorName", activity).value_or(""); - double threshold = std::stof(mCustomParameters.atOptional("threshold", activity).value_or("0")); + mComparatorModuleName = mCustomParameters.atOptional("moduleName", activity).value_or(""); + mComparatorClassName = mCustomParameters.atOptional("comparatorName", activity).value_or(""); mReferenceRun = std::stoi(mCustomParameters.atOptional("referenceRun", activity).value_or("0")); mIgnorePeriodForReference = std::stoi(mCustomParameters.atOptional("ignorePeriodForReference", activity).value_or("1")) != 0; mIgnorePassForReference = std::stoi(mCustomParameters.atOptional("ignorePassForReference", activity).value_or("1")) != 0; - mComparator.reset(); - if (!moduleName.empty() && !comparatorName.empty()) { - mComparator.reset(root_class_factory::create(moduleName, comparatorName)); - } - - if (mComparator) { - mComparator->setThreshold(threshold); - } + mActivity = activity; mReferenceActivity = activity; mReferenceActivity.mId = mReferenceRun; @@ -71,7 +64,8 @@ void ReferenceComparatorCheck::startOfActivity(const Activity& activity) mReferenceActivity.mPassName = ""; } - // clear the cache of reference plots + // clear the cache of comparators and reference plots + mComparators.clear(); mReferencePlots.clear(); } @@ -92,7 +86,7 @@ static std::pair getPlotsFromCanvas(TCanvas* canvas, std::string& me return { nullptr, nullptr }; } // Get the pad containing the reference histogram. - // This pad is only present ofr 2-D histograms. + // This pad is only present for 2-D histograms. // 1-D histograms are drawn superimposed in the same pad TPad* padHistRef = (TPad*)canvas->GetPrimitive(TString::Format("%s_PadHistRef", canvas->GetName())); @@ -126,6 +120,27 @@ static std::pair getPlotsFromCanvas(TCanvas* canvas) return getPlotsFromCanvas(canvas, dummyMessage); } +//_________________________________________________________________________________________ +// +// Get the ratio histograms from the canvas +static TH1* getRatioPlotFromCanvas(TCanvas* canvas) +{ + // Get the pad containing the current histogram, as well as the reference one in the case of 1-D plots + TPad* padHistRatio = (TPad*)canvas->GetPrimitive(TString::Format("%s_PadHistRatio", canvas->GetName())); + if (!padHistRatio) { + return nullptr; + } + + // Get the current histogram + TH1* histRatio = dynamic_cast(padHistRatio->GetPrimitive(TString::Format("%s_hist_ratio", canvas->GetName()))); + if (!histRatio) { + return nullptr; + } + + // return a pair with the two histograms + return histRatio; +} + // Get the current and reference histograms from the canvas, and compare them using the comparator object passed as parameter static Quality compare(TCanvas* canvas, ObjectComparatorInterface* comparator, std::string& message) { @@ -148,7 +163,7 @@ static Quality compare(TCanvas* canvas, ObjectComparatorInterface* comparator, s return comparator->compare(plots.first, plots.second, message); } -Quality ReferenceComparatorCheck::getSinglePlotQuality(std::shared_ptr mo, std::string& message) +Quality ReferenceComparatorCheck::getSinglePlotQuality(std::shared_ptr mo, ObjectComparatorInterface* comparator, std::string& message) { // retrieve the reference plot and compare auto* th1 = dynamic_cast(mo->getObject()); @@ -156,6 +171,10 @@ Quality ReferenceComparatorCheck::getSinglePlotQuality(std::shared_ptrcompare(th1, ref, message); + return comparator->compare(th1, ref, message); +} + +static std::string getBaseName(std::string name) +{ + auto pos = name.rfind("/"); + return ((pos < std::string::npos) ? name.substr(pos + 1) : name); } //_________________________________________________________________________________________ @@ -194,17 +219,29 @@ Quality ReferenceComparatorCheck::check(std::mapgetName(); + auto moKey = getBaseName(moName); Quality quality; std::string message; + if (!mComparatorModuleName.empty() && !mComparatorClassName.empty() && mComparators.count(moKey) == 0) { + mComparators[moKey].reset(root_class_factory::create(mComparatorModuleName, mComparatorClassName)); + if (mComparators[moKey]) { + mComparators[moKey]->configure(mCustomParameters, moKey, mActivity); + } + } + ObjectComparatorInterface* comparator = mComparators[moKey].get(); + if (!comparator) { + continue; + } + // run the comparison algorithm if (mo->getObject()->IsA() == TClass::GetClass()) { // We got a canvas. It contains the plot and its reference. auto* canvas = dynamic_cast(mo->getObject()); - quality = compare(canvas, mComparator.get(), message); + quality = compare(canvas, comparator, message); } else if (mo->getObject()->InheritsFrom(TH1::Class())) { // We got a plot, we have to find the reference before calling the comparator - quality = getSinglePlotQuality(mo, message); + quality = getSinglePlotQuality(mo, comparator, message); } else { ILOG(Warning, Ops) << "Compared Monitor Object '" << mo->getName() << "' is not a TCanvas or a TH1, the detector QC responsible should review the configuration" << ENDM; continue; @@ -291,6 +328,44 @@ static void setQualityLabel(TCanvas* canvas, const Quality& quality) } } +void ReferenceComparatorCheck::drawHorizontalRange(const std::string& moName, TCanvas* canvas, const Quality& quality) +{ + if (!canvas) { + return; + } + + // get the plot with the current/reference ratio from the canvas + auto ratioPlot = getRatioPlotFromCanvas(canvas); + // currently the range indicator is only implemented for 1-D histograms + if (!ratioPlot || ratioPlot->InheritsFrom("TH2")) { + return; + } + + // get the comparator associated to this plot + ObjectComparatorInterface* comparator{ nullptr }; + auto moKey = getBaseName(moName); + if (mComparators.count(moKey) > 0) { + comparator = mComparators[moKey].get(); + } + if (!comparator) { + return; + } + + // get the X-axis range, if defined + auto rangeX = comparator->getXRange(); + if (!rangeX) { + return; + } + + // draw an horizontal double arrow marking the X-axis range + double xMin = ratioPlot->GetXaxis()->GetBinLowEdge(ratioPlot->GetXaxis()->FindBin(rangeX->first)); + double xMax = ratioPlot->GetXaxis()->GetBinUpEdge(ratioPlot->GetXaxis()->FindBin(rangeX->second - 1.0e-6)); + auto arrow = new TArrow(xMin,1.8,xMax,1.8,0.015,"<|>"); + arrow->SetLineColor(getQualityColor(quality)); + arrow->SetFillColor(getQualityColor(quality)); + ratioPlot->GetListOfFunctions()->Add(arrow); +} + void ReferenceComparatorCheck::beautify(std::shared_ptr mo, Quality checkResult) { // get the quality associated to the current MO @@ -307,12 +382,17 @@ void ReferenceComparatorCheck::beautify(std::shared_ptr mo, Quali // draw the quality label on the plot setQualityLabel(canvas, quality); - } - auto* th1 = dynamic_cast(mo->getObject()); - if (th1) { - auto* qualityLabel = new TPaveText(0.75, 0.65, 0.98, 0.75, "brNDC"); - updateQualityLabel(qualityLabel, quality); - th1->GetListOfFunctions()->Add(qualityLabel); + + // draw a double-arrow indicating the horizontal range for the check, if it is set + drawHorizontalRange(moName, canvas, quality); + } else { + // draw the quality label directly on the plot if the MO is an histogram + auto* th1 = dynamic_cast(mo->getObject()); + if (th1) { + auto* qualityLabel = new TPaveText(0.75, 0.65, 0.98, 0.75, "brNDC"); + updateQualityLabel(qualityLabel, quality); + th1->GetListOfFunctions()->Add(qualityLabel); + } } }