Skip to content

Commit c77cc97

Browse files
author
Michal Tichák
committed
[QC-1298] first version of Data
1 parent 891a040 commit c77cc97

File tree

8 files changed

+254
-29
lines changed

8 files changed

+254
-29
lines changed

Framework/CMakeLists.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,9 @@ add_library(O2QualityControl
136136
src/ReductorHelpers.cxx
137137
src/KafkaPoller.cxx
138138
src/FlagHelpers.cxx
139-
src/ObjectMetadataHelpers.cxx)
139+
src/ObjectMetadataHelpers.cxx
140+
src/Data.cxx
141+
)
140142

141143
target_include_directories(
142144
O2QualityControl
@@ -289,6 +291,7 @@ add_executable(o2-qc-test-core
289291
test/testKafkaTests.cxx
290292
test/testFlagHelpers.cxx
291293
test/testQualitiesToFlagCollectionConverter.cxx
294+
test/testData.cxx
292295
)
293296
set_property(TARGET o2-qc-test-core
294297
PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/tests)

Framework/include/QualityControl/CheckInterface.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ namespace o2::quality_control::core
2626
{
2727
class Activity;
2828
class MonitorObject;
29-
}
29+
class Data;
30+
31+
} // namespace o2::quality_control::core
3032

3133
using namespace o2::quality_control::core;
3234

@@ -48,7 +50,13 @@ class CheckInterface : public core::UserCodeInterface
4850
///
4951
/// @param moMap A map of the the MonitorObjects to check and their full names (i.e. <task_name>/<mo name>) as keys.
5052
/// @return The quality associated with these objects.
51-
virtual core::Quality check(std::map<std::string, std::shared_ptr<core::MonitorObject>>* moMap) = 0;
53+
virtual core::Quality check(std::map<std::string, std::shared_ptr<core::MonitorObject>>* moMap);
54+
55+
/// \brief Returns the quality associated with these objects.
56+
///
57+
/// @param data An object with any type of data possible accesible via full names (i.e. <task_name>/<mo name> in case of MOs) as keys.
58+
/// @return The quality associated with these objects.
59+
virtual core::Quality check(const core::Data& data);
5260

5361
/// \brief Modify the aspect of the plot.
5462
///
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// Copyright 2025 CERN and copyright holders of ALICE O2.
2+
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3+
// All rights not expressly granted are reserved.
4+
//
5+
// This software is distributed under the terms of the GNU General Public
6+
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7+
//
8+
// In applying this license CERN does not waive the privileges and immunities
9+
// granted to it by virtue of its status as an Intergovernmental Organization
10+
// or submit itself to any jurisdiction.
11+
12+
///
13+
/// \file Data.h
14+
/// \author Michal Tichak
15+
///
16+
17+
#include <any>
18+
#include <concepts>
19+
#include <iostream>
20+
#include <map>
21+
#include <memory>
22+
#include <optional>
23+
#include <string>
24+
#include <vector>
25+
#include <typeinfo>
26+
27+
namespace o2::quality_control::core
28+
{
29+
30+
class MonitorObject;
31+
32+
class Data
33+
{
34+
public:
35+
Data() = default;
36+
Data(const std::map<std::string, std::shared_ptr<MonitorObject>>& moMap);
37+
38+
template <typename Result>
39+
std::optional<Result> get(std::string_view key)
40+
{
41+
if (const auto foundIt = mObjects.find(key); foundIt != mObjects.end()) {
42+
if (auto* casted = std::any_cast<Result>(&foundIt->second); casted != nullptr) {
43+
return { *casted };
44+
}
45+
}
46+
return std::nullopt;
47+
}
48+
49+
template <typename StoreType>
50+
void insert(std::string_view key, const StoreType& value)
51+
{
52+
// std::cout << "inserting value: " << value << ", of type: " << typeid(StoreType).name() << "\n";
53+
mObjects.insert({ std::string{ key }, value });
54+
}
55+
56+
template <typename Type>
57+
std::vector<Type> getAllOfType() const
58+
{
59+
std::vector<Type> result;
60+
for (const auto& [_, object] : mObjects) {
61+
if (auto* casted = std::any_cast<Type>(&object); casted != nullptr) {
62+
result.push_back(*casted);
63+
}
64+
}
65+
return result;
66+
}
67+
68+
template <typename Type, std::predicate<Type> Pred>
69+
std::vector<Type> getAllOfTypeIf(Pred filter) const
70+
{
71+
std::vector<Type> result;
72+
for (const auto& [_, object] : mObjects) {
73+
if (auto* casted = std::any_cast<Type>(&object); casted != nullptr) {
74+
if (filter(*casted)) {
75+
result.push_back(*casted);
76+
}
77+
}
78+
}
79+
return result;
80+
}
81+
82+
private:
83+
std::map<std::string, std::any, std::less<>> mObjects;
84+
};
85+
86+
} // namespace o2::quality_control::core

Framework/src/CheckInterface.cxx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "QualityControl/CheckInterface.h"
1818
#include "QualityControl/ReferenceUtils.h"
1919
#include "QualityControl/MonitorObject.h"
20+
#include "QualityControl/Data.h"
2021

2122
#include <TClass.h>
2223

@@ -26,6 +27,17 @@ using namespace o2::quality_control::core;
2627
namespace o2::quality_control::checker
2728
{
2829

30+
core::Quality CheckInterface::check(std::map<std::string, std::shared_ptr<core::MonitorObject>>* moMap)
31+
{
32+
Data data(*moMap);
33+
return check(data);
34+
};
35+
36+
core::Quality CheckInterface::check(const core::Data& data)
37+
{
38+
return core::Quality{};
39+
};
40+
2941
std::string CheckInterface::getAcceptedType() { return "TObject"; }
3042

3143
bool CheckInterface::isObjectCheckable(const std::shared_ptr<MonitorObject> mo)

Framework/src/Data.cxx

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright 2025 CERN and copyright holders of ALICE O2.
2+
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3+
// All rights not expressly granted are reserved.
4+
//
5+
// This software is distributed under the terms of the GNU General Public
6+
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7+
//
8+
// In applying this license CERN does not waive the privileges and immunities
9+
// granted to it by virtue of its status as an Intergovernmental Organization
10+
// or submit itself to any jurisdiction.
11+
12+
///
13+
/// \file Data.h
14+
/// \author Michal Tichak
15+
///
16+
17+
#include "QualityControl/Data.h"
18+
19+
namespace o2::quality_control::core
20+
{
21+
Data::Data(const std::map<std::string, std::shared_ptr<MonitorObject>>& moMap)
22+
{
23+
for (const auto& [key, mo] : moMap) {
24+
insert(key, mo);
25+
}
26+
}
27+
} // namespace o2::quality_control::core

Framework/test/testData.cxx

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Copyright 2025 CERN and copyright holders of ALICE O2.
2+
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3+
// All rights not expressly granted are reserved.
4+
//
5+
// This software is distributed under the terms of the GNU General Public
6+
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7+
//
8+
// In applying this license CERN does not waive the privileges and immunities
9+
// granted to it by virtue of its status as an Intergovernmental Organization
10+
// or submit itself to any jurisdiction.
11+
12+
///
13+
/// \file testData.cxx
14+
/// \author Michal Tichak
15+
///
16+
17+
#include <catch_amalgamated.hpp>
18+
#include "QualityControl/Data.h"
19+
20+
using namespace o2::quality_control::core;
21+
22+
TEST_CASE("Data constructor", "[Data]")
23+
{
24+
REQUIRE_NOTHROW([]() { Data data{}; });
25+
}
26+
27+
TEST_CASE("Data insert and get", "[Data]")
28+
{
29+
Data data;
30+
data.insert("test", 1);
31+
auto valueStr = data.get<std::string>("test");
32+
REQUIRE(!valueStr.has_value());
33+
auto valueInt = data.get<int>("test");
34+
REQUIRE(valueInt.has_value());
35+
REQUIRE(valueInt.value() == 1);
36+
}
37+
38+
TEST_CASE("Data getAllOfType", "[Data]")
39+
{
40+
Data data;
41+
data.insert("int1", 1);
42+
data.insert("string", std::string{ "1" });
43+
data.insert("int2", 1);
44+
data.insert("long", 1l);
45+
46+
const auto ints = data.getAllOfType<int>();
47+
REQUIRE(ints.size() == 2);
48+
REQUIRE(ints[0] == 1);
49+
REQUIRE(ints[1] == 1);
50+
51+
const auto strings = data.getAllOfType<std::string>();
52+
REQUIRE(strings.size() == 1);
53+
REQUIRE(strings[0] == "1");
54+
55+
const auto longs = data.getAllOfType<long>();
56+
REQUIRE(longs.size() == 1);
57+
REQUIRE(longs[0] == 1u);
58+
59+
struct nonexistent {
60+
};
61+
62+
const auto nonexistens = data.getAllOfType<nonexistent>();
63+
REQUIRE(nonexistens.empty());
64+
}
65+
66+
template <typename T>
67+
struct named {
68+
std::string name;
69+
T val;
70+
};
71+
72+
TEST_CASE("Data getAllOfTypeIf", "[Data]")
73+
{
74+
Data data;
75+
data.insert("1", named{ "1", 4 });
76+
data.insert("1", named{ "1", 4l });
77+
auto filtered = data.getAllOfTypeIf<named<int>>([](const auto& val) { return val.name == "1"; });
78+
REQUIRE(filtered.size() == 1);
79+
}

Modules/Skeleton/include/Skeleton/SkeletonCheck.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class SkeletonCheck : public o2::quality_control::checker::CheckInterface
3535
// Override interface
3636
void configure() override;
3737
Quality check(std::map<std::string, std::shared_ptr<MonitorObject>>* moMap) override;
38+
Quality check(const quality_control::core::Data& data) override;
3839
void beautify(std::shared_ptr<MonitorObject> mo, Quality checkResult = Quality::Null) override;
3940
std::string getAcceptedType() override;
4041
void reset() override;

Modules/Skeleton/src/SkeletonCheck.cxx

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,14 @@
1818
#include "QualityControl/MonitorObject.h"
1919
#include "QualityControl/Quality.h"
2020
#include "QualityControl/QcInfoLogger.h"
21+
#include "Skeleton/SkeletonTask.h"
22+
#include "QualityControl/Data.h"
2123
// ROOT
2224
#include <TH1.h>
2325

2426
#include <DataFormatsQualityControl/FlagType.h>
2527
#include <DataFormatsQualityControl/FlagTypeFactory.h>
28+
#include <memory>
2629

2730
using namespace std;
2831
using namespace o2::quality_control;
@@ -40,6 +43,12 @@ void SkeletonCheck::configure()
4043
}
4144

4245
Quality SkeletonCheck::check(std::map<std::string, std::shared_ptr<MonitorObject>>* moMap)
46+
{
47+
Data data{ *moMap };
48+
return check(data);
49+
}
50+
51+
Quality SkeletonCheck::check(const quality_control::core::Data& data)
4352
{
4453
// THUS FUNCTION BODY IS AN EXAMPLE. PLEASE REMOVE EVERYTHING YOU DO NOT NEED.
4554
Quality result = Quality::Null;
@@ -49,35 +58,35 @@ Quality SkeletonCheck::check(std::map<std::string, std::shared_ptr<MonitorObject
4958
// and you can get your custom parameters:
5059
ILOG(Debug, Devel) << "custom param physics.pp.myOwnKey1 : " << mCustomParameters.atOrDefaultValue("myOwnKey1", "default_value", "physics", "pp") << ENDM;
5160

52-
// This is an example of accessing the histogram 'example' created by SkeletonTask
53-
for (auto& [moName, mo] : *moMap) {
54-
if (mo->getName() == "example") {
55-
auto* h = dynamic_cast<TH1*>(mo->getObject());
56-
if (h == nullptr) {
57-
ILOG(Error, Support) << "Could not cast `example` to TH1*, skipping" << ENDM;
58-
continue;
59-
}
60-
// unless we find issues, we assume the quality is good
61-
result = Quality::Good;
62-
63-
// an example of a naive quality check: we want bins 1-7 to be non-empty and bins 0 and >7 to be empty.
64-
for (int i = 0; i < h->GetNbinsX(); i++) {
65-
if (i > 0 && i < 8 && h->GetBinContent(i) == 0) {
66-
result = Quality::Bad;
67-
// optionally, we can add flags indicating the effect on data and a comment explaining why it was assigned.
68-
result.addFlag(FlagTypeFactory::BadPID(), "It is bad because there is nothing in bin " + std::to_string(i));
69-
break;
70-
} else if ((i == 0 || i > 7) && h->GetBinContent(i) > 0) {
71-
result = Quality::Medium;
72-
// optionally, we can add flags indicating the effect on data and a comment explaining why it was assigned.
73-
result.addFlag(FlagTypeFactory::Unknown(), "It is medium because bin " + std::to_string(i) + " is not empty");
74-
result.addFlag(FlagTypeFactory::BadTracking(), "We can assign more than one Flag to a Quality");
75-
}
61+
auto MOs = data.getAllOfTypeIf<std::shared_ptr<MonitorObject>>([](const auto& mo) { return mo->getName() == "example"; });
62+
63+
for (const auto& mo : MOs) {
64+
auto* h = dynamic_cast<TH1*>(mo->getObject());
65+
if (h == nullptr) {
66+
ILOG(Error, Support) << "Could not cast `example` to TH1*, skipping" << ENDM;
67+
continue;
68+
}
69+
// unless we find issues, we assume the quality is good
70+
result = Quality::Good;
71+
72+
// an example of a naive quality check: we want bins 1-7 to be non-empty and bins 0 and >7 to be empty.
73+
for (int i = 0; i < h->GetNbinsX(); i++) {
74+
if (i > 0 && i < 8 && h->GetBinContent(i) == 0) {
75+
result = Quality::Bad;
76+
// optionally, we can add flags indicating the effect on data and a comment explaining why it was assigned.
77+
result.addFlag(FlagTypeFactory::BadPID(), "It is bad because there is nothing in bin " + std::to_string(i));
78+
break;
79+
} else if ((i == 0 || i > 7) && h->GetBinContent(i) > 0) {
80+
result = Quality::Medium;
81+
// optionally, we can add flags indicating the effect on data and a comment explaining why it was assigned.
82+
result.addFlag(FlagTypeFactory::Unknown(), "It is medium because bin " + std::to_string(i) + " is not empty");
83+
result.addFlag(FlagTypeFactory::BadTracking(), "We can assign more than one Flag to a Quality");
7684
}
77-
// optionally, we can associate some custom metadata to a Quality
78-
result.addMetadata("mykey", "myvalue");
7985
}
86+
// optionally, we can associate some custom metadata to a Quality
87+
result.addMetadata("mykey", "myvalue");
8088
}
89+
8190
return result;
8291
}
8392

0 commit comments

Comments
 (0)