diff --git a/Framework/CMakeLists.txt b/Framework/CMakeLists.txt index 74c5e7b3a7..34c4f78863 100644 --- a/Framework/CMakeLists.txt +++ b/Framework/CMakeLists.txt @@ -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( @@ -99,6 +100,7 @@ target_link_libraries(O2QualityControl O2QualityControlTypes O2::Mergers O2::DataSampling + O2::DataFormatsQualityControl PRIVATE Boost::system ROOT::Gui CURL::libcurl) @@ -235,6 +237,7 @@ set(TEST_SRCS test/testVersion.cxx test/testRepoPathUtils.cxx test/testPolicyManager.cxx + test/testQualitiesToTRFCollectionConverter.cxx ) set(TEST_ARGS @@ -267,6 +270,7 @@ set(TEST_ARGS "" "" "" + "" ) list(LENGTH TEST_SRCS count) diff --git a/Framework/include/QualityControl/QualitiesToTRFCollectionConverter.h b/Framework/include/QualityControl/QualitiesToTRFCollectionConverter.h new file mode 100644 index 0000000000..5d772ab174 --- /dev/null +++ b/Framework/include/QualityControl/QualitiesToTRFCollectionConverter.h @@ -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 +#include +#include + +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 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 mConverted; + + uint64_t mCurrentStartTime; + uint64_t mCurrentEndTime; + std::optional mCurrentTRF; + size_t mQOsIncluded; + size_t mWorseThanGoodQOs; +}; + +} // namespace o2::quality_control::core + +#endif //QUALITYCONTROL_QUALITIESTOTRFCOLLECTIONCONVERTER_H diff --git a/Framework/src/QualitiesToTRFCollectionConverter.cxx b/Framework/src/QualitiesToTRFCollectionConverter.cxx new file mode 100644 index 0000000000..cf2409da04 --- /dev/null +++ b/Framework/src/QualitiesToTRFCollectionConverter.cxx @@ -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 +#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 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(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 \ No newline at end of file diff --git a/Framework/test/testQualitiesToTRFCollectionConverter.cxx b/Framework/test/testQualitiesToTRFCollectionConverter.cxx new file mode 100644 index 0000000000..58d396f3da --- /dev/null +++ b/Framework/test/testQualitiesToTRFCollectionConverter.cxx @@ -0,0 +1,197 @@ +// 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 testQualitiesToTRFCollectionConverter.cxx +/// \author Piotr Konopka +/// + +#include "QualityControl/QualitiesToTRFCollectionConverter.h" +#include "QualityControl/QualityObject.h" +#include + +#define BOOST_TEST_MODULE QO2TRFCConversion test +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +#include + +using namespace o2::quality_control; +using namespace o2::quality_control::core; + +BOOST_AUTO_TEST_CASE(test_NoQOs) +{ + QualitiesToTRFCollectionConverter converter("test1", "DET", 5, 100, "qc/DET/QO/xyzCheck"); + auto trfc = converter.getResult(); + + BOOST_REQUIRE_EQUAL(trfc->size(), 1); + auto& trf = *trfc->begin(); + BOOST_CHECK_EQUAL(trf.getStart(), 5); + BOOST_CHECK_EQUAL(trf.getEnd(), 100); + BOOST_CHECK_EQUAL(trf.getFlag(), FlagReasonFactory::MissingQualityObject()); + BOOST_CHECK_EQUAL(trf.getSource(), "qc/DET/QO/xyzCheck"); +} + +BOOST_AUTO_TEST_CASE(test_NoBeginning) +{ + std::vector qos{ + { Quality::Bad, "xyzCheck", "DET", {}, {}, {}, { { "Valid-From", "10" }, { "Valid-Until", "50" } } }, + { Quality::Good, "xyzCheck", "DET", {}, {}, {}, { { "Valid-From", "50" }, { "Valid-Until", "120" } } } + }; + QualitiesToTRFCollectionConverter converter("test1", "DET", 5, 100, "qc/DET/QO/xyzCheck"); + for (const auto& qo : qos) { + converter(qo); + } + auto trfc = converter.getResult(); + + BOOST_REQUIRE_EQUAL(trfc->size(), 2); + + auto& trf1 = *trfc->begin(); + BOOST_CHECK_EQUAL(trf1.getStart(), 5); + BOOST_CHECK_EQUAL(trf1.getEnd(), 9); + BOOST_CHECK_EQUAL(trf1.getFlag(), FlagReasonFactory::MissingQualityObject()); + BOOST_CHECK_EQUAL(trf1.getSource(), "qc/DET/QO/xyzCheck"); + + auto& trf2 = *(++trfc->begin()); + BOOST_CHECK_EQUAL(trf2.getStart(), 10); + BOOST_CHECK_EQUAL(trf2.getEnd(), 50); + BOOST_CHECK_EQUAL(trf2.getFlag(), FlagReasonFactory::Unknown()); + BOOST_CHECK_EQUAL(trf2.getSource(), "qc/DET/QO/xyzCheck"); +} + +BOOST_AUTO_TEST_CASE(test_NoEnd) +{ + std::vector qos{ + { Quality::Good, "xyzCheck", "DET", {}, {}, {}, { { "Valid-From", "5" }, { "Valid-Until", "80" } } } + }; + QualitiesToTRFCollectionConverter converter("test1", "DET", 5, 100, "qc/DET/QO/xyzCheck"); + for (const auto& qo : qos) { + converter(qo); + } + auto trfc = converter.getResult(); + + BOOST_REQUIRE_EQUAL(trfc->size(), 1); + auto& trf = *trfc->begin(); + BOOST_CHECK_EQUAL(trf.getStart(), 80); + BOOST_CHECK_EQUAL(trf.getEnd(), 100); + BOOST_CHECK_EQUAL(trf.getFlag(), FlagReasonFactory::MissingQualityObject()); + BOOST_CHECK_EQUAL(trf.getSource(), "qc/DET/QO/xyzCheck"); +} + +BOOST_AUTO_TEST_CASE(test_WrongOrder) +{ + std::vector qos{ + { Quality::Good, "xyzCheck", "DET", {}, {}, {}, { { "Valid-From", "70" }, { "Valid-Until", "90" } } }, + { Quality::Good, "xyzCheck", "DET", {}, {}, {}, { { "Valid-From", "60" }, { "Valid-Until", "90" } } }, + { Quality::Bad, "xyzCheck", "DET", {}, {}, {}, { { "Valid-From", "50" }, { "Valid-Until", "120" } } }, + { Quality::Bad, "xyzCheck", "DET", {}, {}, {}, { { "Valid-From", "40" }, { "Valid-Until", "120" } } }, + { Quality::Good, "xyzCheck", "DET", {}, {}, {}, { { "Valid-From", "30" }, { "Valid-Until", "120" } } } + }; + + { + // good to good + QualitiesToTRFCollectionConverter converter("test1", "DET", 5, 100, "qc/DET/QO/xyzCheck"); + converter(qos[0]); + BOOST_CHECK_THROW(converter(qos[1]), std::runtime_error); + } + { + // good to bad + QualitiesToTRFCollectionConverter converter("test1", "DET", 5, 100, "qc/DET/QO/xyzCheck"); + converter(qos[1]); + BOOST_CHECK_THROW(converter(qos[2]), std::runtime_error); + } + { + // bad to bad + QualitiesToTRFCollectionConverter converter("test1", "DET", 5, 100, "qc/DET/QO/xyzCheck"); + converter(qos[2]); + BOOST_CHECK_THROW(converter(qos[3]), std::runtime_error); + } + { + // bad to good + QualitiesToTRFCollectionConverter converter("test1", "DET", 5, 100, "qc/DET/QO/xyzCheck"); + converter(qos[3]); + BOOST_CHECK_THROW(converter(qos[4]), std::runtime_error); + } +} + +BOOST_AUTO_TEST_CASE(test_MismatchingParameters) +{ + std::vector qos{ + { Quality::Bad, "xyzCheck", "TPC", {}, {}, {}, { { "Valid-From", "10" }, { "Valid-Until", "120" } } }, + { Quality::Bad, "xyzCheck", "DET", {}, {}, {}, { { "Valid-From", "1000" }, { "Valid-Until", "10000" } } }, + { Quality::Bad, "xyzCheck", "DET", {}, {}, {}, { { "Valid-From", "40" }, { "Valid-Until", "30" } } } + }; + + { + // different detector + QualitiesToTRFCollectionConverter converter("test1", "DET", 5, 100, "qc/DET/QO/xyzCheck"); + BOOST_CHECK_THROW(converter(qos[0]), std::runtime_error); + } + { + // QO start after the TRFC end limit + QualitiesToTRFCollectionConverter converter("test1", "DET", 5, 100, "qc/DET/QO/xyzCheck"); + BOOST_CHECK_THROW(converter(qos[1]), std::runtime_error); + } + { + // QO validity starts after it finishes + QualitiesToTRFCollectionConverter converter("test1", "DET", 5, 100, "qc/DET/QO/xyzCheck"); + BOOST_CHECK_THROW(converter(qos[2]), std::runtime_error); + } +} + +BOOST_AUTO_TEST_CASE(test_OverlappingQOs) +{ + std::vector qos{ + { Quality::Good, "xyzCheck", "DET", {}, {}, {}, { { "Valid-From", "5" }, { "Valid-Until", "50" } } }, + { Quality::Good, "xyzCheck", "DET", {}, {}, {}, { { "Valid-From", "10" }, { "Valid-Until", "50" } } }, + { Quality::Good, "xyzCheck", "DET", {}, {}, {}, { { "Valid-From", "15" }, { "Valid-Until", "60" } } }, + { Quality::Bad, "xyzCheck", "DET", {}, {}, {}, { { "Valid-From", "55" }, { "Valid-Until", "120" } } }, + { Quality::Bad, "xyzCheck", "DET", {}, {}, {}, { { "Valid-From", "60" }, { "Valid-Until", "120" } } }, + { Quality::Bad, "xyzCheck", "DET", {}, {}, {}, { { "Valid-From", "70" }, { "Valid-Until", "120" } } } + }; + QualitiesToTRFCollectionConverter converter("test1", "DET", 5, 100, "qc/DET/QO/xyzCheck"); + for (const auto& qo : qos) { + converter(qo); + } + auto trfc = converter.getResult(); + + BOOST_REQUIRE_EQUAL(trfc->size(), 1); + + auto& trf1 = *trfc->begin(); + BOOST_CHECK_EQUAL(trf1.getStart(), 55); + BOOST_CHECK_EQUAL(trf1.getEnd(), 100); + BOOST_CHECK_EQUAL(trf1.getFlag(), FlagReasonFactory::Unknown()); + BOOST_CHECK_EQUAL(trf1.getSource(), "qc/DET/QO/xyzCheck"); +} + +BOOST_AUTO_TEST_CASE(test_AdjacentQOs) +{ + std::vector qos{ + { Quality::Good, "xyzCheck", "DET", {}, {}, {}, { { "Valid-From", "5" }, { "Valid-Until", "10" } } }, + { Quality::Good, "xyzCheck", "DET", {}, {}, {}, { { "Valid-From", "10" }, { "Valid-Until", "14" } } }, + { Quality::Good, "xyzCheck", "DET", {}, {}, {}, { { "Valid-From", "15" }, { "Valid-Until", "49" } } }, + { Quality::Bad, "xyzCheck", "DET", {}, {}, {}, { { "Valid-From", "50" }, { "Valid-Until", "80" } } }, + { Quality::Bad, "xyzCheck", "DET", {}, {}, {}, { { "Valid-From", "80" }, { "Valid-Until", "95" } } }, + { Quality::Bad, "xyzCheck", "DET", {}, {}, {}, { { "Valid-From", "96" }, { "Valid-Until", "120" } } } + }; + QualitiesToTRFCollectionConverter converter("test1", "DET", 5, 100, "qc/DET/QO/xyzCheck"); + for (const auto& qo : qos) { + converter(qo); + } + auto trfc = converter.getResult(); + + BOOST_REQUIRE_EQUAL(trfc->size(), 1); + + auto& trf1 = *trfc->begin(); + BOOST_CHECK_EQUAL(trf1.getStart(), 50); + BOOST_CHECK_EQUAL(trf1.getEnd(), 100); + BOOST_CHECK_EQUAL(trf1.getFlag(), FlagReasonFactory::Unknown()); + BOOST_CHECK_EQUAL(trf1.getSource(), "qc/DET/QO/xyzCheck"); +} \ No newline at end of file diff --git a/Modules/Common/src/TRFCollectionTask.cxx b/Modules/Common/src/TRFCollectionTask.cxx index ee5f2a6dab..be10e24ac1 100644 --- a/Modules/Common/src/TRFCollectionTask.cxx +++ b/Modules/Common/src/TRFCollectionTask.cxx @@ -18,6 +18,7 @@ #include "QualityControl/DatabaseInterface.h" #include "QualityControl/CcdbDatabase.h" #include "QualityControl/RepoPathUtils.h" +#include "QualityControl/QualitiesToTRFCollectionConverter.h" #include #include @@ -59,29 +60,26 @@ TimeRangeFlagCollection TRFCollectionTask::transformQualities(repository::Databa ILOG(Error) << "Could not cast the database interface to CcdbDatabase, this task supports only the CCDB backend" << ENDM } - const char* noQualityObjectsComment = "No Quality Objects found within the specified time range"; - // ------ IMPLEMENTATION ------ // stats size_t totalQOsIncluded = 0; size_t totalWorseThanGoodQOs = 0; - TimeRangeFlagCollection trfCollection{ mConfig.name, mConfig.detector }; + TimeRangeFlagCollection mainTrfCollection{ mConfig.name, mConfig.detector }; for (const auto& qoName : mConfig.qualityObjects) { + std::string qoPath = RepoPathUtils::getQoPath(mConfig.detector, qoName); + QualitiesToTRFCollectionConverter converter(mConfig.name, mConfig.detector, timestampLimitStart, timestampLimitEnd, qoPath); auto availableTimestamps = fetchAvailableTimestamps(qoName); auto firstMatchingTimestamp = std::upper_bound(availableTimestamps.begin(), availableTimestamps.end(), timestampLimitStart); if (firstMatchingTimestamp == availableTimestamps.end()) { ILOG(Warning) << "No object under the path '" << qoPath << "' available after timestamp '" << timestampLimitStart << "'" << ENDM; - trfCollection.insert({ timestampLimitStart, timestampLimitEnd, FlagReasonFactory::MissingQualityObject(), noQualityObjectsComment, qoName }); continue; } - std::optional currentTRF; - auto currentEndTime = *firstMatchingTimestamp; // if available, we move one timestamp back, because 'validUntil' might cover our period. if (firstMatchingTimestamp != availableTimestamps.begin()) { @@ -90,18 +88,7 @@ TimeRangeFlagCollection TRFCollectionTask::transformQualities(repository::Databa if (qo == nullptr) { throw std::runtime_error("Could not retrieve a QO for timestamp '" + std::to_string(*currentObjTimestamp) + "'"); } - uint64_t validUntil = strtoull(qo->getMetadata("Valid-Until").c_str(), nullptr, 10); - currentEndTime = validUntil > timestampLimitEnd ? timestampLimitEnd : validUntil; - - if (currentEndTime > timestampLimitStart && qo->getQuality().isWorseThan(core::Quality::Good)) { - // todo use reasons from QOs when they are available - currentTRF.emplace(timestampLimitStart, currentEndTime, FlagReasonFactory::Unknown(), qo->getMetadata("comment", ""), qo->getName()); - totalQOsIncluded++; - totalWorseThanGoodQOs++; - } - } // otherwise, let's see if we have QO coverage at the beginning of the time range - else if (*firstMatchingTimestamp > timestampLimitStart && !currentTRF.has_value()) { - trfCollection.insert({ timestampLimitStart, *firstMatchingTimestamp, FlagReasonFactory::MissingQualityObject(), noQualityObjectsComment, qoPath }); + converter(*qo); } // the main loop over QOs @@ -113,70 +100,22 @@ TimeRangeFlagCollection TRFCollectionTask::transformQualities(repository::Databa if (newQO == nullptr) { throw std::runtime_error("Could not retrieve a QO for timestamp '" + std::to_string(*currentStartTime) + "'"); } - totalQOsIncluded++; - if (newQO->getQuality().isWorseThan(Quality::Good)) { - totalWorseThanGoodQOs++; - } - uint64_t validUntil = strtoull(newQO->getMetadata("Valid-Until").c_str(), nullptr, 10); - currentEndTime = validUntil > timestampLimitEnd ? timestampLimitEnd : validUntil; - - if (!currentTRF.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. - currentTRF.emplace(*currentStartTime, currentEndTime, FlagReasonFactory::Unknown(), newQO->getMetadata("comment", ""), newQO->getName()); - - } else if (currentTRF.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 (currentTRF->getEnd() > *currentStartTime) { - currentTRF->setEnd(*currentStartTime); - } - trfCollection.insert(currentTRF.value()); - currentTRF.reset(); - } else if (currentTRF->getFlag() != newFlag || currentTRF->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 (currentTRF->getEnd() > *currentStartTime) { - currentTRF->setEnd(*currentStartTime); - } - trfCollection.insert(currentTRF.value()); - - currentTRF.emplace(*currentStartTime, currentEndTime, newFlag, newComment, newQO->getName()); - } else if (currentTRF->getEnd() < currentEndTime) { - // The data quality is still bad and in the same way. - // We extend the duration of the current TRF. - currentTRF->setEnd(currentEndTime); - } - // If none of the above conditions was fulfilled, - // then currentTRF covers larger time range than the new one, keep the old. - } + converter(*newQO); } - // handling the end of the time range - if (currentTRF.has_value()) { - trfCollection.insert(currentTRF.value()); - if (currentTRF->getEnd() < timestampLimitEnd) { - trfCollection.insert({ currentTRF->getEnd(), timestampLimitEnd, FlagReasonFactory::MissingQualityObject(), noQualityObjectsComment, qoPath }); - } - } else if (currentEndTime < timestampLimitEnd) { - trfCollection.insert({ currentEndTime, timestampLimitEnd, FlagReasonFactory::MissingQualityObject(), noQualityObjectsComment, qoPath }); - } + totalQOsIncluded += converter.getQOsIncluded(); + totalWorseThanGoodQOs += converter.getWorseThanGoodQOs(); + mainTrfCollection.merge(*converter.getResult()); } ILOG(Info) << "Total number of QOs included in TRFCollection: " << totalQOsIncluded << ENDM; ILOG(Info) << "Total number of worse than good QOs: " << totalWorseThanGoodQOs << ENDM; - ILOG(Info) << "Number of TRFs: " << trfCollection.size() << ENDM; + ILOG(Info) << "Number of TRFs: " << mainTrfCollection.size() << ENDM; // TODO: now we print it, but it should be stored in the QCDB after we have QC-547. - ILOG(Info) << trfCollection << ENDM; + ILOG(Info) << mainTrfCollection << ENDM; - return trfCollection; + return mainTrfCollection; } void TRFCollectionTask::update(Trigger, framework::ServiceRegistry&)