Skip to content

Commit

Permalink
[Common] improvements to the ReferenceComparatorCheck
Browse files Browse the repository at this point in the history
* comparators are now plot-specific, allowing to have configuration parameters
that are specific to some plots
* for 1-D histograms, if specified the X range is shown on the ratio plot
with a double-arrow horizontal line
  • Loading branch information
aferrero2707 committed Sep 22, 2024
1 parent da4b56f commit ddb350d
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 25 deletions.
11 changes: 9 additions & 2 deletions Modules/Common/include/Common/ReferenceComparatorCheck.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <unordered_map>

class TPaveText;
class TCanvas;

namespace o2::quality_control_modules::common
{
Expand All @@ -50,16 +51,22 @@ class ReferenceComparatorCheck : public o2::quality_control::checker::CheckInter
void endOfActivity(const Activity& activity) override;

private:
Quality getSinglePlotQuality(std::shared_ptr<MonitorObject> mo, std::string& message);
Quality getSinglePlotQuality(std::shared_ptr<MonitorObject> mo, ObjectComparatorInterface* comparator, std::string& message);
void drawHorizontalRange(const std::string& moName, TCanvas* canvas, const Quality& quality);

std::unique_ptr<ObjectComparatorInterface> mComparator;
std::map<std::string, Quality> mQualityFlags;
std::map<std::string, std::shared_ptr<TPaveText>> 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<std::string, std::shared_ptr<MonitorObject>> mReferencePlots;
/// collection of object comparators with plot-specific settings
std::unordered_map<std::string, std::unique_ptr<ObjectComparatorInterface>> mComparators;
};

} // namespace o2::quality_control_modules::common
Expand Down
126 changes: 103 additions & 23 deletions Modules/Common/src/ReferenceComparatorCheck.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include <TCanvas.h>
#include <TPaveText.h>
#include <TColor.h>
#include <TArrow.h>

using namespace o2::quality_control;

Expand All @@ -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<ObjectComparatorInterface>(moduleName, comparatorName));
}

if (mComparator) {
mComparator->setThreshold(threshold);
}
mActivity = activity;

mReferenceActivity = activity;
mReferenceActivity.mId = mReferenceRun;
Expand All @@ -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();
}

Expand All @@ -92,7 +86,7 @@ static std::pair<TH1*, TH1*> 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()));

Expand Down Expand Up @@ -126,6 +120,27 @@ static std::pair<TH1*, TH1*> 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<TH1*>(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)
{
Expand All @@ -148,14 +163,18 @@ static Quality compare(TCanvas* canvas, ObjectComparatorInterface* comparator, s
return comparator->compare(plots.first, plots.second, message);
}

Quality ReferenceComparatorCheck::getSinglePlotQuality(std::shared_ptr<MonitorObject> mo, std::string& message)
Quality ReferenceComparatorCheck::getSinglePlotQuality(std::shared_ptr<MonitorObject> mo, ObjectComparatorInterface* comparator, std::string& message)
{
// retrieve the reference plot and compare
auto* th1 = dynamic_cast<TH1*>(mo->getObject());
if (th1 == nullptr) {
message = "The MonitorObject is not a TH1";
return Quality::Null;
}
if (!comparator) {
message = "missing comparator";
return Quality::Null;
}

// get path of mo and ref (we have to remove the provenance)
std::string path = RepoPathUtils::getPathNoProvenance(mo);
Expand All @@ -180,7 +199,13 @@ Quality ReferenceComparatorCheck::getSinglePlotQuality(std::shared_ptr<MonitorOb
message = "The reference plot is not a TH1";
return Quality::Null;
}
return mComparator.get()->compare(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);
}

//_________________________________________________________________________________________
Expand All @@ -194,17 +219,29 @@ Quality ReferenceComparatorCheck::check(std::map<std::string, std::shared_ptr<Mo

for (auto& [key, mo] : *moMap) {
auto moName = mo->getName();
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<ObjectComparatorInterface>(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<TCanvas>()) {
// We got a canvas. It contains the plot and its reference.
auto* canvas = dynamic_cast<TCanvas*>(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;
Expand Down Expand Up @@ -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<MonitorObject> mo, Quality checkResult)
{
// get the quality associated to the current MO
Expand All @@ -307,12 +382,17 @@ void ReferenceComparatorCheck::beautify(std::shared_ptr<MonitorObject> mo, Quali

// draw the quality label on the plot
setQualityLabel(canvas, quality);
}
auto* th1 = dynamic_cast<TH1*>(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<TH1*>(mo->getObject());
if (th1) {
auto* qualityLabel = new TPaveText(0.75, 0.65, 0.98, 0.75, "brNDC");
updateQualityLabel(qualityLabel, quality);
th1->GetListOfFunctions()->Add(qualityLabel);
}
}
}

Expand Down

0 comments on commit ddb350d

Please sign in to comment.