Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Framework/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ add_library(O2QualityControl
src/MonitorObjectCollection.cxx
src/UpdatePolicyManager.cxx
src/AdvancedWorkflow.cxx
src/QualitiesToTRFCollectionConverter.cxx
src/Calculators.cxx)

target_include_directories(
Expand Down Expand Up @@ -99,6 +100,7 @@ target_link_libraries(O2QualityControl
O2QualityControlTypes
O2::Mergers
O2::DataSampling
O2::DataFormatsQualityControl
PRIVATE Boost::system
ROOT::Gui
CURL::libcurl)
Expand Down Expand Up @@ -235,6 +237,7 @@ set(TEST_SRCS
test/testVersion.cxx
test/testRepoPathUtils.cxx
test/testPolicyManager.cxx
test/testQualitiesToTRFCollectionConverter.cxx
)

set(TEST_ARGS
Expand Down Expand Up @@ -267,6 +270,7 @@ set(TEST_ARGS
""
""
""
""
)

list(LENGTH TEST_SRCS count)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright CERN and copyright holders of ALICE O2. This software is
// distributed under the terms of the GNU General Public License v3 (GPL
// Version 3), copied verbatim in the file "COPYING".
//
// See http://alice-o2.web.cern.ch/license for full licensing information.
//
// In applying this license CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.

///
/// \file QualitiesToTRFCollectionConverter.h
/// \author Piotr Konopka
///

#ifndef QUALITYCONTROL_QUALITIESTOTRFCOLLECTIONCONVERTER_H
#define QUALITYCONTROL_QUALITIESTOTRFCOLLECTIONCONVERTER_H

#include <DataFormatsQualityControl/TimeRangeFlag.h>
#include <memory>
#include <optional>

namespace o2::quality_control
{
class TimeRangeFlagCollection;
}

namespace o2::quality_control::core
{

class QualityObject;

/// \brief Converts a set of chronologically provided Qualities from the same path into a TRFCollection.
class QualitiesToTRFCollectionConverter
{
public:
QualitiesToTRFCollectionConverter(std::string trfcName, std::string detectorCode, uint64_t startTimeLimit, uint64_t endTimeLimit, std::string qoPath);
~QualitiesToTRFCollectionConverter() = default;

/// \brief Converts a Quality into TRFCollection. The converter should get Qualities in chronological order.
void operator()(const QualityObject&);

/// \brief Moves the final TRFCollection out and resets the converter.
std::unique_ptr<TimeRangeFlagCollection> getResult();

size_t getQOsIncluded() const;
size_t getWorseThanGoodQOs() const;

private:
uint64_t mStartTimeLimit;
uint64_t mEndTimeLimit;
std::string mQOPath; // this is only to indicate what is the missing Quality in TRF

std::unique_ptr<TimeRangeFlagCollection> mConverted;

uint64_t mCurrentStartTime;
uint64_t mCurrentEndTime;
std::optional<TimeRangeFlag> mCurrentTRF;
size_t mQOsIncluded;
size_t mWorseThanGoodQOs;
};

} // namespace o2::quality_control::core

#endif //QUALITYCONTROL_QUALITIESTOTRFCOLLECTIONCONVERTER_H
137 changes: 137 additions & 0 deletions Framework/src/QualitiesToTRFCollectionConverter.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
// Copyright CERN and copyright holders of ALICE O2. This software is
// distributed under the terms of the GNU General Public License v3 (GPL
// Version 3), copied verbatim in the file "COPYING".
//
// See http://alice-o2.web.cern.ch/license for full licensing information.
//
// In applying this license CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.

///
/// \file QualitiesToTRFCollectionConverter.cxx
/// \author Piotr Konopka
///

#include "QualityControl/QualitiesToTRFCollectionConverter.h"

#include <DataFormatsQualityControl/TimeRangeFlagCollection.h>
#include "QualityControl/QualityObject.h"

namespace o2::quality_control::core
{

const char* noQualityObjectsComment = "No Quality Objects found within the specified time range";

QualitiesToTRFCollectionConverter::QualitiesToTRFCollectionConverter(std::string trfcName, std::string detectorCode, uint64_t startTimeLimit, uint64_t endTimeLimit, std::string qoPath)
: mStartTimeLimit(startTimeLimit),
mEndTimeLimit(endTimeLimit),
mQOPath(qoPath),
mConverted(new TimeRangeFlagCollection(trfcName, detectorCode)),
mCurrentStartTime(0),
mCurrentEndTime(startTimeLimit), // this is to correctly set the missing QO time range if none were given
mQOsIncluded(0),
mWorseThanGoodQOs(0)
{
}

void QualitiesToTRFCollectionConverter::operator()(const QualityObject& newQO)
{
if (mConverted->getDetector() != newQO.getDetectorName()) {
throw std::runtime_error("The TRFCollection '" + mConverted->getName() +
"' expects QOs from detector '" + mConverted->getDetector() +
"' but received a QO for '" + newQO.getDetectorName() + "'");
}

mQOsIncluded++;
if (newQO.getQuality().isWorseThan(Quality::Good)) {
mWorseThanGoodQOs++;
}

uint64_t validFrom = strtoull(newQO.getMetadata("Valid-From").c_str(), nullptr, 10);
uint64_t validUntil = strtoull(newQO.getMetadata("Valid-Until").c_str(), nullptr, 10);
if (validFrom < mCurrentStartTime) {
throw std::runtime_error("The currently provided QO is dated as earlier than the one before (" //
+ std::to_string(validFrom) + " vs. " + std::to_string(mCurrentStartTime) +
"). QOs should be provided to the QualitiesToTRFCollectionConverter in the chronological order");
}

// Is the beginning of time range covered by the first QO provided?
if (mCurrentStartTime < mStartTimeLimit && validFrom > mStartTimeLimit) {
mConverted->insert({ mStartTimeLimit, validFrom - 1, FlagReasonFactory::MissingQualityObject(), noQualityObjectsComment, mQOPath });
}

mCurrentStartTime = validFrom < mStartTimeLimit ? mStartTimeLimit : validFrom;
mCurrentEndTime = validUntil > mEndTimeLimit ? mEndTimeLimit : validUntil;

if (!mCurrentTRF.has_value() && newQO.getQuality().isWorseThan(Quality::Good)) {
// There was no TRF in the previous step and the data quality is bad now.
// We create a new TRF and we will work on it in next loop iterations.
mCurrentTRF.emplace(mCurrentStartTime, mCurrentEndTime, FlagReasonFactory::Unknown(), newQO.getMetadata("comment", ""), newQO.getPath());

} else if (mCurrentTRF.has_value()) {
// There is already a TRF. We will check if it can be merged with the new QO.
auto newFlag = FlagReasonFactory::Unknown(); // todo: use reasons from QOs
auto newComment = newQO.getMetadata("comment", "");

if (newQO.getQuality() == Quality::Good) {
// The data quality is not bad anymore.
// We trim the current TRF's time range if necessary and deposit it to the collection.
if (mCurrentTRF->getEnd() > validFrom) {
mCurrentTRF->setEnd(validFrom);
}
mConverted->insert(mCurrentTRF.value());
mCurrentTRF.reset();
} else if (mCurrentTRF->getFlag() != newFlag || mCurrentTRF->getComment() != newComment) {
// The data quality is still bad, but in a different way.
// We trim the current TRF's time range if necessary and deposit it to the collection.
// Then, we create a new TRF.
if (mCurrentTRF->getEnd() > validFrom) {
mCurrentTRF->setEnd(validFrom);
}
mConverted->insert(mCurrentTRF.value());

mCurrentTRF.emplace(validFrom, mCurrentEndTime, newFlag, newComment, newQO.getName());
} else if (mCurrentTRF->getEnd() < mCurrentEndTime) {
// The data quality is still bad and in the same way.
// We extend the duration of the current TRF.
mCurrentTRF->setEnd(mCurrentEndTime);
}
// If none of the above conditions was fulfilled,
// then mCurrentTRF covers larger time range than the new one, keep the old one.
}
}

std::unique_ptr<TimeRangeFlagCollection> QualitiesToTRFCollectionConverter::getResult()
{
// handling the end of the time range
if (mCurrentTRF.has_value()) {
mConverted->insert(mCurrentTRF.value());
mCurrentEndTime = mCurrentTRF->getEnd();
}
if (mCurrentEndTime < mEndTimeLimit) {
mConverted->insert({ mCurrentEndTime, mEndTimeLimit, FlagReasonFactory::MissingQualityObject(), noQualityObjectsComment, mQOPath });
}

auto result = std::make_unique<TimeRangeFlagCollection>(mConverted->getName(), mConverted->getDetector());
result.swap(mConverted);

mCurrentStartTime = 0;
mCurrentEndTime = mStartTimeLimit;
mCurrentTRF.reset();
mQOsIncluded = 0;
mWorseThanGoodQOs = 0;

return result;
}

size_t QualitiesToTRFCollectionConverter::getQOsIncluded() const
{
return mQOsIncluded;
}
size_t QualitiesToTRFCollectionConverter::getWorseThanGoodQOs() const
{
return mWorseThanGoodQOs;
}

} // namespace o2::quality_control::core
Loading