diff --git a/Framework/include/QualityControl/TrendingTask.h b/Framework/include/QualityControl/TrendingTask.h index 9b37bee237..db1dcb485e 100644 --- a/Framework/include/QualityControl/TrendingTask.h +++ b/Framework/include/QualityControl/TrendingTask.h @@ -73,6 +73,7 @@ class TrendingTask : public PostProcessingInterface static void formatTimeXAxis(TH1* background); static void formatRunNumberXAxis(TH1* background); static std::string deduceGraphLegendOptions(const TrendingTaskConfig::Graph& graphConfig); + static void applyStyleToGraph(TGraph* graph, const TrendingTaskConfig::GraphStyle& style); /// returns true only if all datasources were available to update reductor bool trendValues(const Trigger& t, repository::DatabaseInterface&); diff --git a/Framework/include/QualityControl/TrendingTaskConfig.h b/Framework/include/QualityControl/TrendingTaskConfig.h index 939de60b5d..2d5b33820f 100644 --- a/Framework/include/QualityControl/TrendingTaskConfig.h +++ b/Framework/include/QualityControl/TrendingTaskConfig.h @@ -32,6 +32,25 @@ struct TrendingTaskConfig : PostProcessingConfig { TrendingTaskConfig(std::string name, const boost::property_tree::ptree& config); ~TrendingTaskConfig() = default; + // graph style configuration + // colors as defined by ROOT TColor class: + // https://root.cern/doc/master/classTColor.html + // marker colors and styles are as defined by ROOT TAttMarker class + // https://root.cern/doc/master/classTAttMarker.html + // line styles are as defined by ROOT TAttLine class + // https://root.cern/doc/master/classTAttLine.html + // WARNING: Any parameters in this struct will override colliding parameters in option + struct GraphStyle { + int lineColor = -1; + int lineStyle = -1; + int lineWidth = -1; + int markerColor = -1; + int markerStyle = -1; + float markerSize = -1.f; + int fillColor = -1; + int fillStyle = -1; + }; + // this corresponds to one TTree::Draw() call, i.e. one graph or histogram drawing struct Graph { std::string name; @@ -40,6 +59,13 @@ struct TrendingTaskConfig : PostProcessingConfig { std::string selection; std::string option; // the list of possible options are documented in TGraphPainter and THistPainter std::string errors; + GraphStyle style; + }; + + // legend configuration + struct LegendConfig { + int nColumns{ 1 }; + float x1{ -1.f }, y1{ -1.f }, x2{ -1.f }, y2{ -1.f }; // NDC coords }; // this corresponds to one canvas which can include multiple graphs @@ -49,6 +75,7 @@ struct TrendingTaskConfig : PostProcessingConfig { std::string graphAxisLabel; std::string graphYRange; int colorPalette = 0; + LegendConfig legend; std::vector graphs; }; diff --git a/Framework/src/TrendingTask.cxx b/Framework/src/TrendingTask.cxx index 1f6ed5accf..d92e7baba5 100644 --- a/Framework/src/TrendingTask.cxx +++ b/Framework/src/TrendingTask.cxx @@ -142,6 +142,40 @@ void TrendingTask::initializeTrend(o2::quality_control::repository::DatabaseInte } } +void TrendingTask::applyStyleToGraph(TGraph* graph, const TrendingTaskConfig::GraphStyle& style) +{ + if (!graph) { + return; + } + + if (style.lineColor >= 0) { + graph->SetLineColor(style.lineColor); + } + if (style.lineStyle >= 0) { + graph->SetLineStyle(style.lineStyle); + } + if (style.lineWidth >= 0) { + graph->SetLineWidth(style.lineWidth); + } + + if (style.markerColor >= 0) { + graph->SetMarkerColor(style.markerColor); + } + if (style.markerStyle >= 0) { + graph->SetMarkerStyle(style.markerStyle); + } + if (style.markerSize >= 0.f) { + graph->SetMarkerSize(style.markerSize); + } + + if (style.fillColor >= 0) { + graph->SetFillColor(style.fillColor); + } + if (style.fillStyle >= 0) { + graph->SetFillStyle(style.fillStyle); + } +} + void TrendingTask::initialize(Trigger, framework::ServiceRegistryRef services) { // removing leftovers from any previous runs @@ -310,19 +344,31 @@ std::string TrendingTask::deduceGraphLegendOptions(const TrendingTaskConfig::Gra TCanvas* TrendingTask::drawPlot(const TrendingTaskConfig::Plot& plotConfig) { auto* c = new TCanvas(); - auto* legend = new TLegend(0.3, 0.2); + // Legend + TLegend* legend = nullptr; + if (plotConfig.legend.x1 >= 0 && plotConfig.legend.y1 >= 0 && plotConfig.legend.x2 >= 0 && plotConfig.legend.y2 >= 0) { + legend = new TLegend(plotConfig.legend.x1, plotConfig.legend.y1, + plotConfig.legend.x2, plotConfig.legend.y2, + nullptr, "NDC"); + if (plotConfig.legend.nColumns > 0) { + legend->SetNColumns(plotConfig.legend.nColumns); + } + } else { + legend = new TLegend(0.3, 0.2); + } + legend->SetBorderSize(0); + legend->SetFillStyle(0); + legend->SetTextSize(0.03); + legend->SetMargin(0.15); + + // Keep palette behavior unless user forces explicit colors via per-graph style if (plotConfig.colorPalette != 0) { - // this will work just once until we bump ROOT to a version which contains this commit: - // https://github.com/root-project/root/commit/0acdbd5be80494cec98ff60ba9a73cfe70a9a57a - // and enable the commented out line - // perhaps JSROOT >7.7.1 will allow us to retain the palette as well. gStyle->SetPalette(plotConfig.colorPalette); // This makes ROOT store the selected palette for each generated plot. // TColor::DefinedColors(1); // TODO enable when available } else { - // we set the default palette - gStyle->SetPalette(); + gStyle->SetPalette(); // default } // regardless whether we draw a graph or a histogram, a histogram is always used by TTree::Draw to draw axes and title @@ -337,6 +383,7 @@ TCanvas* TrendingTask::drawPlot(const TrendingTaskConfig::Plot& plotConfig) // having "SAME" at the first TTree::Draw() call will not work, we have to add it only in subsequent Draw calls std::string option = firstGraphInPlot ? graphConfig.option : "SAME " + graphConfig.option; + // Draw main series mTrend->Draw(graphConfig.varexp.c_str(), graphConfig.selection.c_str(), option.c_str()); // For graphs, we allow to draw errors if they are specified. @@ -357,11 +404,23 @@ TCanvas* TrendingTask::drawPlot(const TrendingTaskConfig::Plot& plotConfig) } } + // Legend entry and styling for graphs if (auto graph = dynamic_cast(c->FindObject("Graph"))) { + if (plotOrder >= 2) { + // Style objects after Draw so we override palette/auto styling when requested + applyStyleToGraph(graph, graphConfig.style); + // Keep errors visually consistent with the main series + if (graphErrors) { + applyStyleToGraph(graphErrors, graphConfig.style); + } + } graph->SetName(graphConfig.name.c_str()); graph->SetTitle(graphConfig.title.c_str()); - legend->AddEntry(graph, graphConfig.title.c_str(), deduceGraphLegendOptions(graphConfig).c_str()); + legend->AddEntry(graph, graphConfig.title.c_str(), + deduceGraphLegendOptions(graphConfig).c_str()); } + + // Legend entry and styling for histograms if (auto htemp = dynamic_cast(c->FindObject("htemp"))) { if (plotOrder == 1) { htemp->SetName(graphConfig.name.c_str()); @@ -376,7 +435,7 @@ TCanvas* TrendingTask::drawPlot(const TrendingTaskConfig::Plot& plotConfig) // so we have to do it here. htemp->BufferEmpty(); // we keep the pointer to bg histogram for later postprocessing - if (background == nullptr) { + if (!background) { background = htemp; } } @@ -430,6 +489,7 @@ TCanvas* TrendingTask::drawPlot(const TrendingTaskConfig::Plot& plotConfig) } else { delete legend; } + c->Modified(); c->Update(); diff --git a/Framework/src/TrendingTaskConfig.cxx b/Framework/src/TrendingTaskConfig.cxx index 04de31261b..8b79ced4b6 100644 --- a/Framework/src/TrendingTaskConfig.cxx +++ b/Framework/src/TrendingTaskConfig.cxx @@ -36,14 +36,34 @@ TrendingTaskConfig::TrendingTaskConfig(std::string id, const boost::property_tre for (const auto& [_, graphConfig] : graphsConfig.value()) { // first we use name of the graph, if absent, we use graph title, if absent, we use plot (object) name. const auto& name = graphConfig.get("name", graphConfig.get("title", plotConfig.get("name"))); + GraphStyle style; + style.lineColor = graphConfig.get("style.lineColor", -1); + style.lineStyle = graphConfig.get("style.lineStyle", -1); + style.lineWidth = graphConfig.get("style.lineWidth", -1); + style.markerColor = graphConfig.get("style.markerColor", -1); + style.markerStyle = graphConfig.get("style.markerStyle", -1); + style.markerSize = graphConfig.get("style.markerSize", -1.f); + style.fillColor = graphConfig.get("style.fillColor", -1); + style.fillStyle = graphConfig.get("style.fillStyle", -1); + graphs.push_back({ name, graphConfig.get("title", ""), graphConfig.get("varexp"), graphConfig.get("selection", ""), graphConfig.get("option", ""), - graphConfig.get("graphErrors", "") }); + graphConfig.get("graphErrors", ""), + style }); } } else { + GraphStyle style; + style.lineColor = plotConfig.get("style.lineColor", -1); + style.lineStyle = plotConfig.get("style.lineStyle", -1); + style.lineWidth = plotConfig.get("style.lineWidth", -1); + style.markerColor = plotConfig.get("style.markerColor", -1); + style.markerStyle = plotConfig.get("style.markerStyle", -1); + style.markerSize = plotConfig.get("style.markerSize", -1.f); + style.fillColor = plotConfig.get("style.fillColor", -1); + style.fillStyle = plotConfig.get("style.fillStyle", -1); graphs.push_back({ plotConfig.get("name", ""), plotConfig.get("title", ""), plotConfig.get("varexp"), @@ -51,11 +71,20 @@ TrendingTaskConfig::TrendingTaskConfig(std::string id, const boost::property_tre plotConfig.get("option", ""), plotConfig.get("graphErrors", "") }); } + + LegendConfig leg; + leg.nColumns = plotConfig.get("legend.nColumns", 1); + leg.x1 = plotConfig.get("legend.x1", -1.f); + leg.y1 = plotConfig.get("legend.y1", -1.f); + leg.x2 = plotConfig.get("legend.x2", -1.f); + leg.y2 = plotConfig.get("legend.y2", -1.f); + plots.push_back({ plotConfig.get("name"), plotConfig.get("title", ""), plotConfig.get("graphAxisLabel", ""), plotConfig.get("graphYRange", ""), plotConfig.get("colorPalette", 0), + leg, graphs }); } diff --git a/Modules/FIT/FT0/etc/ft0-post-processing.json b/Modules/FIT/FT0/etc/ft0-post-processing.json index 07546c96e2..57e7a75498 100644 --- a/Modules/FIT/FT0/etc/ft0-post-processing.json +++ b/Modules/FIT/FT0/etc/ft0-post-processing.json @@ -22,6 +22,33 @@ "url": "" } }, + "tasks": { + "Digits": { + "active": "true", + "className": "o2::quality_control_modules::ft0::DigitQcTask", + "moduleName": "QcFT0", + "detectorName": "FT0", + "cycleDurationSeconds": "60", + "resetAfterCycles": "1", + "dataSource": { + "type": "direct", + "query": "digits:FT0/DIGITSBC/0;channels:FT0/DIGITSCH/0" + }, + "taskParameters": { + "#ChannelIDs": "0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215", + "ChannelIDsAmpVsTime": "0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215", + "trgThresholdTimeLow": "-100", + "trgThresholdTimeHigh": "100", + "trgModeSide": "A+C", + "trgModeThresholdVar": "Ampl", + "trgThresholdSCenA": "20", + "trgThresholdCenA": "40", + "trgOrGate": "153", + "trgChargeLevelLow": "0", + "trgChargeLevelHigh": "4095" + } + } + }, "checks": { "ASideInnerMIPCheck": { "active": "true", @@ -416,6 +443,7 @@ "className": "o2::quality_control::postprocessing::TrendingTask", "moduleName": "QcFT0", "detectorName": "FT0", + "resumeTrend": "true", "dataSources": [ { "type": "repository", @@ -431,6 +459,34 @@ } ], "plots": [ + { + "name": "trend_cycle_duration_ntf_corr", + "title": "cycle duration: ns/TF;time;cycle duration [ns/TimeFrames]", + "legend": { "enabled": true, "x1": 0.70, "y1": 0.70, "x2": 0.93, "y2": 0.90, "nColumns": 1 }, + "graphs": [ + { + "title": "cycle duration [ns]", + "varexp": "CycleDuration.entries:time", + "selection": "", + "option": "*LP", + "style": { "lineColor": 38, "markerColor": 4, "markerStyle": 20, "lineWidth": 2 } + }, + { + "title": "cycle duration [TimeFrames]", + "varexp": "CycleDurationNTF.entries:time", + "selection": "", + "option": "*LP", + "style": { "lineColor": 8, "markerColor": 3, "markerStyle": 30, "lineWidth": 2 } + }, + { + "title": "cycle duration: ns/TF;time;cycle duration [ns/TimeFrames]", + "varexp": "CycleDuration.entries/CycleDurationNTF.entries:time", + "selection": "", + "option": "*LP", + "style": { "lineColor": 31, "markerColor": 30, "markerStyle": 23, "lineWidth": 2 } + } + ] + }, { "name": "trend_cycle_duration", "title": "cycle duration [ns]", diff --git a/doc/PostProcessing.md b/doc/PostProcessing.md index 137e48a999..addddec862 100644 --- a/doc/PostProcessing.md +++ b/doc/PostProcessing.md @@ -1,27 +1,31 @@ # Post-processing + + + * [The post-processing framework](#the-post-processing-framework) - * [Post-processing interface](#post-processing-interface) - * [Configuration](#configuration) - * [Running it](#running-it) + * [Post-processing interface](#post-processing-interface) + * [Configuration](#configuration) + * [Running it](#running-it) * [Convenience classes](#convenience-classes) - * [The TrendingTask class](#the-trendingtask-class) - * [The SliceTrendingTask class](#the-slicetrendingtask-class) - * [The ReferenceComparatorTask class](#the-referencecomparatortask-class) - * [The CcdbInspectorTask class](#the-ccdbinspectortask-class) - * [The QualityTask class](#the-qualitytask-class) - * [The BigScreen class](#the-bigscreen-class) + * [The TrendingTask class](#the-trendingtask-class) + * [The SliceTrendingTask class](#the-slicetrendingtask-class) + * [The ReferenceComparatorTask class](#the-referencecomparatortask-class) + * [The CcdbInspectorTask class](#the-ccdbinspectortask-class) + * [The QualityTask class](#the-qualitytask-class) + * [The BigScreen class](#the-bigscreen-class) * [More examples](#more-examples) + ## The post-processing framework This framework is intended for planned post-processing of objects generated by QC Tasks, Checks and correlating them with other data. The most common use-cases include correlation and trending of different properties of the detectors. - The users can write their own Post-processing Tasks or use the ones provided by the framework (see [Convenience classes](#convenience-classes)) which are supposed to cover the usual needs. Post-processing Tasks run asynchronously to data-taking, but can be triggered by a set of selected events. + The users can write their own Post-processing Tasks or use the ones provided by the framework (see [Convenience classes](#convenience-classes)) which are supposed to cover the usual needs. Post-processing Tasks run asynchronously to data-taking, but can be triggered by a set of selected events. ### Post-processing interface @@ -31,7 +35,7 @@ Any Post-processing Task should inherit PostProcessingInterface, which includes * `initialize` - initializes the task and its data, given the event which it was triggered by. * `update` - updates the task and its data, given the event which it was triggered by. * `finalize` - finalizes the processing, given the event which it was triggered by. - + Interfaces to databases and other services are accesible via `ServiceRegistry`, which is an argument to the last three methods. They are invoked when any of the specified triggers is up, which can be: * Start Of Run - triggers when receives SOSOR message from `aliecs.run` kafka topic which has **DIFFERENT** run number **AND** environment id than `Activity` class in config @@ -156,8 +160,8 @@ Each of the three methods can be invoked by one or more triggers. Below are list * `"newobject:[qcdb/ccdb]:"` - New Object - triggers when an object in QCDB or CCDB is updated (applicable for synchronous processing). For example: `"newobject:qcdb:qc/TST/MO/QcTask/Example"` * `"foreachobject:[qcdb/ccdb]:"` - For Each Object - triggers for each object in QCDB or CCDB which matches the activity indicated in the QC config file (applicable for both synchronous and asynchronous processing). This trigger contains monitor cycle of required object in its metadata since v1.178.0 * `"foreachlatest:[qcdb/ccdb]:"` - For Each Latest - triggers for the latest object version in QCDB or CCDB - for each matching activity (applicable for asynchronous processing). It sorts objects in ascending order by period, - pass and run. + for each matching activity (applicable for asynchronous processing). It sorts objects in ascending order by period, + pass and run. * `"once"` - Once - triggers only first time it is checked * `"always"` - Always - triggers each time it is checked * `"userorcontrol"` - triggers when upon corresponding START and STOP state transitions. This is the recommended trigger for `initTrigger` and `stopTrigger`. @@ -300,7 +304,7 @@ Multiple graphs can be drawn on one plot, if needed. As this class is a post-processing task, it inherits also its configuration JSON template. It extends it, though, some additional parameters. -``` json +```json { "qc": { ... @@ -334,7 +338,7 @@ The `"names"` array should point to one or more objects under a common `"path"` Field `"reductorParameters"` is used to configure Reductors (classes inherited from `"o2::quality_control::postprocessing::Reductor"` interface). It uses same format as `"extendedTaskParameters"` field. -``` json +```json { ... "dataSources": [ @@ -380,7 +384,7 @@ Optionally, one can use `"graphError"` to add x and y error bars to a graph, as The `"name"` and `"varexp"` are the only compulsory arguments, others can be omitted to reduce configuration files size. `"graphAxisLabel"` allows the user to set axis labels in the form of `"Label Y axis: Label X axis"`. With `"graphYRange"` numerical values for fixed ranges of the y axis can be provided in the form of `"Min:Max"`. -``` json +```json { ... "plots": [ @@ -420,6 +424,65 @@ The `"name"` and `"varexp"` are the only compulsory arguments, others can be omi } ``` +There is also a possibility to explicitly change the legend, and line, fill and marker styles in case of a need for more customized plots. Example is given below: + +```json +{ + ... + "plots": [ + { + "name": "trend_cycle_duration_ntf_corr", + "title": "cycle duration: ns/TF;time;cycle duration [ns/TimeFrames]", + "legend": { "x1": 0.70, "y1": 0.70, "x2": 0.93, "y2": 0.90, "nColumns": 1 }, + "graphs": [ + { + "title": "cycle duration [ns]", + "varexp": "CycleDuration.entries:time", + "selection": "", + "option": "*LP", + "style": { "lineColor": 38, "markerColor": 4, "markerStyle": 20, "lineWidth": 2 } + }, + { + "title": "cycle duration [TimeFrames]", + "varexp": "CycleDurationNTF.entries:time", + "selection": "", + "option": "*LP", + "style": { "lineColor": 8, "markerColor": 3, "markerStyle": 30, "lineWidth": 2 } + }, + { + "title": "cycle duration: ns/TF;time;cycle duration [ns/TimeFrames]", + "varexp": "CycleDuration.entries/CycleDurationNTF.entries:time", + "selection": "", + "option": "*LP", + "style": { "lineColor": 31, "markerColor": 30, "markerStyle": 23, "lineWidth": 2 } + } + ] + } + ], + ... +} +``` + +The specific options are: + +* `"legend"` ~ allows to specify precise location and shape of legend, as well as disable it completely + * `"x1"`, `"y1"`, `"x2"`, `"y2"` ~ manual coordinates of the legend box, all need to be present for custom legend placement to take account + * `"nColumns"` ~ number of columns in the legend +* `"style"` ~ allows to change the style of the line and marker + * `"lineWidth"` ~ width of the line, integer as defined by ROOT [TAttLine class](https://root.cern.ch/doc/master/classTAttLine.html) + * `"lineStyle"` ~ style of the line, integer as defined by ROOT [TAttLine class](https://root.cern.ch/doc/master/classTAttLine.html) + * `"lineColor"` ~ color of the line, an integer as defined by ROOT [TColor class](https://root.cern.ch/doc/master/classTColor.html) + * `"markerColor"` ~ color of the marker, integer as defined by ROOT [TAttMarker class](https://root.cern.ch/doc/master/classTAttMarker.html) + * `"markerStyle"` ~ style of the marker, integer as defined by ROOT [TAttMarker class](https://root.cern.ch/doc/master/classTAttMarker.html) + * `"markerSize"` ~ size of the marker, float as defined by ROOT [TAttMarker class](https://root.cern.ch/doc/master/classTAttMarker.html) + * `"fillColor"` ~ color of the fill, an integer as defined by ROOT [TColor class](https://root.cern.ch/doc/master/classTColor.html) + * `"fillStyle"` ~ style of the fill, integer as defined by ROOT [TAttFill class](https://root.cern.ch/doc/master/classTAttFill.html) + + +WARNING: Any style parameters specified will override colliding parameters in `"option"`. + +However, lines, fills and markers still have to be enabled in `"option"` to appear (e.g. with `"option" : "LPF"`). + To decide whether plots should be generated during each update or just during finalization, use the boolean flag `"producePlotsOnUpdate"`. @@ -479,7 +542,7 @@ The options for `"TrendingType"` are limited to: The field `"graphErrors"` is set up as `"graphErrors":"Var1:Var2"` where `Var1` is the error along y and `Var2` the error along x. For `Var1(2)` numerical values or the options listed for `Var` above can be set. The original histogram does not need to be provided as the task will take the histogram specified in `"varexp": "Histogram.Var:TrendingType"`. In `"graphYRange"` and `"graphXRange"` numerical values for fixed ranges of the x and y axis can be provided in the form of `"Min:Max"`. If provided, the task will set all x (or y) axis on the canvas to this range. `"graphAxisLabel"` allows the user to set axis labels in the form of `"Label Y axis: Label X axis"`. -``` +``` { ... "plots": [ @@ -551,25 +614,25 @@ The checker extracts the current and reference plots from the stored MO, and com Four comparison modules are provided in the framework: 1. `o2::quality_control_modules::common::ObjectComparatorDeviation`: comparison based on the average relative deviation between the bins of the current and reference histograms; the module accepts the following configuration parameters: - * `threshold`: the maximum allowed average relative deviation between current and reference histograms - * `rangeX`, `rangeY`: if set, the comparison is restricted to the bins in the specified X and Y ranges; bins outside the ranges are ignored + * `threshold`: the maximum allowed average relative deviation between current and reference histograms + * `rangeX`, `rangeY`: if set, the comparison is restricted to the bins in the specified X and Y ranges; bins outside the ranges are ignored 2. `o2::quality_control_modules::common::ObjectComparatorBinByBinDeviation`: comparison based on the relative deviation between each bin of the current and reference histograms; the module accepts the following configuration parameters: - * `threshold`: the maximum allowed relative deviation for each bin between current and reference histograms - * `rangeX`, `rangeY`: if set, the comparison is restricted to the bins in the specified X and Y ranges; bins outside the ranges are ignored - * `maxAllowedBadBins`: the maximum number of bins above threshold for which the quality is still considered Good + * `threshold`: the maximum allowed relative deviation for each bin between current and reference histograms + * `rangeX`, `rangeY`: if set, the comparison is restricted to the bins in the specified X and Y ranges; bins outside the ranges are ignored + * `maxAllowedBadBins`: the maximum number of bins above threshold for which the quality is still considered Good 3. `o2::quality_control_modules::common::ObjectComparatorChi2`: comparison based on a standard chi2 test between the current and reference histograms; the module accepts the following configuration parameters: - * `threshold`: the minimum allowed chi2 probability - * `rangeX`, `rangeY`: if set, the Chi2 test is restricted to the bins in the specified X and Y ranges; bins outside the ranges are ignored + * `threshold`: the minimum allowed chi2 probability + * `rangeX`, `rangeY`: if set, the Chi2 test is restricted to the bins in the specified X and Y ranges; bins outside the ranges are ignored 4. `o2::quality_control_modules::common::ObjectComparatorKolmogorov`: comparison based on a standard Kolmogorov test between the current and reference histograms; the module accepts the following configuration parameters: - * `threshold`: the minimum allowed Kolmogorov probability + * `threshold`: the minimum allowed Kolmogorov probability All the configuration parameters of the comparison modules optionally allow to restrict their validity to specific plots. The following example specifies a threshold value common to all the plots, and then overrides the threshold and X range for all plots named `TrackEta`: ```json "extendedCheckParameters": { - "default": { - "default": { + "default": { + "default": { "moduleName" : "QualityControl", "comparatorName" : "o2::quality_control_modules::common::ObjectComparatorChi2", "threshold" : "0.5", @@ -656,8 +719,8 @@ In the example configuration below, the relationship between the input and outpu "detectorName": "MCH", "policy": "OnAny", "extendedCheckParameters": { - "default": { - "default": { + "default": { + "default": { "moduleName" : "QualityControl", "comparatorName" : "o2::quality_control_modules::common::ObjectComparatorChi2", "threshold" : "0.5", @@ -914,8 +977,8 @@ The task is configured as follows: "moduleName": "QualityControl", "detectorName": "GLO", "extendedTaskParameters": { - "default": { - "default": { + "default": { + "default": { "nRows": "4", "nCols": "5", "borderWidth": "1", @@ -1063,7 +1126,7 @@ Use ForEachObject as the update trigger: ``` Since objects are usually published in collections at the same time, you can use a path for one object to be triggered - for a collection of them (all objects produced by a QC Task). + for a collection of them (all objects produced by a QC Task). Use the Activity which matches the run, and (optionally) period and pass name: