diff --git a/include/podio/GenericParameters.h b/include/podio/GenericParameters.h index 60adf8825..4f41aad63 100644 --- a/include/podio/GenericParameters.h +++ b/include/podio/GenericParameters.h @@ -31,6 +31,12 @@ class RNTupleWriter; namespace podio { +#if !defined(__CLING__) +// cling doesn't really deal well (i.e. at all in this case) with the forward +// declaration here and errors out, breaking e.g. python bindings. +class ROOTReader; +#endif + /// The types which are supported in the GenericParameters using SupportedGenericDataTypes = std::tuple; @@ -98,6 +104,10 @@ class GenericParameters { set>(key, std::move(values)); } + /// Load multiple key value pairs simultaneously + template typename VecLike> + void loadFrom(VecLike keys, VecLike> values); + /// Get the number of elements stored under the given key for a type template > size_t getN(const std::string& key) const; @@ -108,7 +118,7 @@ class GenericParameters { /// Get all the available values for a given type template > - std::vector> getValues() const; + std::tuple, std::vector>> getKeysAndValues() const; /// erase all elements void clear() { @@ -134,6 +144,10 @@ class GenericParameters { friend RNTupleWriter; #endif +#if !defined(__CLING__) + friend ROOTReader; +#endif + /// Get a reference to the internal map for a given type template const MapType>& getMap() const { @@ -249,8 +263,9 @@ std::vector GenericParameters::getKeys() const { } template -std::vector> GenericParameters::getValues() const { +std::tuple, std::vector>> GenericParameters::getKeysAndValues() const { std::vector> values; + std::vector keys; auto& mtx = getMutex(); const auto& map = getMap(); { @@ -258,9 +273,26 @@ std::vector> GenericParameters::getValues() const { // values std::lock_guard lock{mtx}; values.reserve(map.size()); - std::transform(map.begin(), map.end(), std::back_inserter(values), [](const auto& pair) { return pair.second; }); + keys.reserve(map.size()); + + for (const auto& [k, v] : map) { + keys.emplace_back(k); + values.emplace_back(v); + } } - return values; + return {keys, values}; } + +template typename VecLike> +void GenericParameters::loadFrom(VecLike keys, VecLike> values) { + auto& map = getMap(); + auto& mtx = getMutex(); + + std::lock_guard lock{mtx}; + for (size_t i = 0; i < keys.size(); ++i) { + map.emplace(std::move(keys[i]), std::move(values[i])); + } +} + } // namespace podio #endif diff --git a/include/podio/ROOTReader.h b/include/podio/ROOTReader.h index bb6a1efdd..e6ecbd0e0 100644 --- a/include/podio/ROOTReader.h +++ b/include/podio/ROOTReader.h @@ -156,6 +156,10 @@ class ROOTReader { /// Read the parameters for the entry specified in the passed CategoryInfo GenericParameters readEntryParameters(CategoryInfo& catInfo, bool reloadBranches, unsigned int localEntry); + template + static void readParams(CategoryInfo& catInfo, podio::GenericParameters& params, bool reloadBranches, + unsigned int localEntry); + /// Read the data entry specified in the passed CategoryInfo, and increase the /// counter afterwards. In case the requested entry is larger than the /// available number of entries, return a nullptr. diff --git a/include/podio/ROOTWriter.h b/include/podio/ROOTWriter.h index 318f0f21f..5ee23835f 100644 --- a/include/podio/ROOTWriter.h +++ b/include/podio/ROOTWriter.h @@ -108,6 +108,13 @@ class ROOTWriter { std::vector collInfo{}; ///< Collection info for this category podio::CollectionIDTable idTable{}; ///< The collection id table for this category std::vector collsToWrite{}; ///< The collections to write for this category + + // Storage for the keys & values of all the parameters of this category + // (resp. at least the current entry) + root_utils::ParamStorage intParams{}; + root_utils::ParamStorage floatParams{}; + root_utils::ParamStorage doubleParams{}; + root_utils::ParamStorage stringParams{}; }; /// Initialize the branches for this category @@ -117,9 +124,10 @@ class ROOTWriter { /// Get the (potentially uninitialized category information for this category) CategoryInfo& getCategoryInfo(const std::string& category); - static void resetBranches(std::vector& branches, - const std::vector& collections, - /*const*/ podio::GenericParameters* parameters); + static void resetBranches(CategoryInfo& categoryInfo, const std::vector& collections); + + /// Fill the parameter keys and values into the CategoryInfo storage + static void fillParams(CategoryInfo& catInfo, const GenericParameters& params); std::unique_ptr m_file{nullptr}; ///< The storage file std::unordered_map m_categories{}; ///< All categories diff --git a/include/podio/utilities/RootHelpers.h b/include/podio/utilities/RootHelpers.h index 55b97a74c..360ef6674 100644 --- a/include/podio/utilities/RootHelpers.h +++ b/include/podio/utilities/RootHelpers.h @@ -1,6 +1,9 @@ #ifndef PODIO_UTILITIES_ROOTHELPERS_H #define PODIO_UTILITIES_ROOTHELPERS_H +#include "podio/GenericParameters.h" + +#include "ROOT/RVec.hxx" #include "TBranch.h" #include @@ -26,6 +29,16 @@ namespace root_utils { /// write a collection. Needed to cache the branch pointers and avoid having to /// get them from a TTree/TChain for every event. struct CollectionBranches { + CollectionBranches() = default; + ~CollectionBranches() = default; + CollectionBranches(const CollectionBranches&) = delete; + CollectionBranches& operator=(const CollectionBranches&) = delete; + CollectionBranches(CollectionBranches&&) = default; + CollectionBranches& operator=(CollectionBranches&&) = default; + + CollectionBranches(TBranch* dataBranch) : data(dataBranch) { + } + TBranch* data{nullptr}; std::vector refs{}; std::vector vecs{}; @@ -36,7 +49,43 @@ namespace root_utils { /// Pair of keys and values for one type of the ones that can be stored in /// GenericParameters template - using ParamStorage = std::tuple, std::vector>>; + struct ParamStorage { + ParamStorage() = default; + ~ParamStorage() = default; + ParamStorage(const ParamStorage&) = delete; + ParamStorage& operator=(const ParamStorage&) = delete; + ParamStorage(ParamStorage&&) = default; + ParamStorage& operator=(ParamStorage&&) = default; + + ParamStorage(std::tuple, std::vector>> keysValues) : + keys(std::move(std::get<0>(keysValues))), values(std::move(std::get<1>(keysValues))) { + } + + /// Get a pointer to the stored keys for binding it to a TBranch + auto keysPtr() { + m_keysPtr = &keys; + return &m_keysPtr; + } + + /// Get a pointer to the stored vectors for binding it to a TBranch + auto valuesPtr() { + m_valuesPtr = &values; + return &m_valuesPtr; + } + + std::vector keys{}; ///< The keys for this type + std::vector> values{}; ///< The values for this type + + private: + std::vector* m_keysPtr{nullptr}; + std::vector>* m_valuesPtr{nullptr}; + }; + + GenericParameters + loadParamsFrom(ROOT::VecOps::RVec intKeys, ROOT::VecOps::RVec> intValues, + ROOT::VecOps::RVec floatKeys, ROOT::VecOps::RVec> floatValues, + ROOT::VecOps::RVec doubleKeys, ROOT::VecOps::RVec> doubleValues, + ROOT::VecOps::RVec stringKeys, ROOT::VecOps::RVec> stringValues); } // namespace root_utils } // namespace podio diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 561e2a9b9..119de39ab 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -81,6 +81,7 @@ SET(root_sources ROOTReader.cc ROOTLegacyReader.cc ROOTFrameData.cc + RootHelpers.cc ) if(ENABLE_RNTUPLE) list(APPEND root_sources @@ -104,7 +105,7 @@ if(ENABLE_RNTUPLE) endif() PODIO_ADD_LIB_AND_DICT(podioRootIO "${root_headers}" "${root_sources}" root_selection.xml) -target_link_libraries(podioRootIO PUBLIC podio::podio ROOT::Core ROOT::RIO ROOT::Tree) +target_link_libraries(podioRootIO PUBLIC podio::podio ROOT::Core ROOT::RIO ROOT::Tree ROOT::ROOTVecOps) if(ENABLE_RNTUPLE) target_link_libraries(podioRootIO PUBLIC ROOT::ROOTNTuple) target_compile_definitions(podioRootIO PUBLIC PODIO_ENABLE_RNTUPLE=1) diff --git a/src/RNTupleReader.cc b/src/RNTupleReader.cc index a372f6c2f..43c8370aa 100644 --- a/src/RNTupleReader.cc +++ b/src/RNTupleReader.cc @@ -18,9 +18,7 @@ void RNTupleReader::readParams(const std::string& name, unsigned entNum, Generic auto keyView = m_readers[name][0]->GetView>(root_utils::getGPKeyName()); auto valueView = m_readers[name][0]->GetView>>(root_utils::getGPValueName()); - for (size_t i = 0; i < keyView(entNum).size(); ++i) { - params.getMap().emplace(std::move(keyView(entNum)[i]), std::move(valueView(entNum)[i])); - } + params.loadFrom(keyView(entNum), valueView(entNum)); } GenericParameters RNTupleReader::readEventMetaData(const std::string& name, unsigned entNum) { diff --git a/src/RNTupleWriter.cc b/src/RNTupleWriter.cc index decdac8e4..b06f0d32e 100644 --- a/src/RNTupleWriter.cc +++ b/src/RNTupleWriter.cc @@ -44,15 +44,14 @@ root_utils::ParamStorage& RNTupleWriter::getParamStorage(CategoryInfo& catInf template void RNTupleWriter::fillParams(const GenericParameters& params, CategoryInfo& catInfo, ROOT::Experimental::REntry* entry) { - auto& [keys, values] = getParamStorage(catInfo); - keys = params.getKeys(); - values = params.getValues(); + auto& paramStorage = getParamStorage(catInfo); + paramStorage = params.getKeysAndValues(); #if ROOT_VERSION_CODE >= ROOT_VERSION(6, 31, 0) - entry->BindRawPtr(root_utils::getGPKeyName(), &keys); - entry->BindRawPtr(root_utils::getGPValueName(), &values); + entry->BindRawPtr(root_utils::getGPKeyName(), ¶mStorage.keys); + entry->BindRawPtr(root_utils::getGPValueName(), ¶mStorage.values); #else - entry->CaptureValueUnsafe(root_utils::getGPKeyName(), &keys); - entry->CaptureValueUnsafe(root_utils::getGPValueName(), &values); + entry->CaptureValueUnsafe(root_utils::getGPKeyName(), ¶mStorage.keys); + entry->CaptureValueUnsafe(root_utils::getGPValueName(), ¶mStorage.values); #endif } diff --git a/src/ROOTLegacyReader.cc b/src/ROOTLegacyReader.cc index 83f160615..494ec4301 100644 --- a/src/ROOTLegacyReader.cc +++ b/src/ROOTLegacyReader.cc @@ -207,7 +207,7 @@ void ROOTLegacyReader::createCollectionBranches(const std::vector @@ -27,22 +26,56 @@ std::tuple, std::vector& collInfo); -GenericParameters ROOTReader::readEntryParameters(ROOTReader::CategoryInfo& catInfo, bool reloadBranches, - unsigned int localEntry) { - // Parameter branch is always the last one - auto& paramBranches = catInfo.branches.back(); +template +void ROOTReader::readParams(ROOTReader::CategoryInfo& catInfo, podio::GenericParameters& params, bool reloadBranches, + unsigned int localEntry) { + const auto collBranchIdx = catInfo.branches.size() - root_utils::nParamBranches - 1; + constexpr auto brOffset = root_utils::getGPBranchOffsets(); - // Make sure to have a valid branch pointer after switching trees in the chain - // as well as on the first event if (reloadBranches) { - paramBranches.data = root_utils::getBranch(catInfo.chain.get(), root_utils::paramBranchName); + auto& keyBranch = catInfo.branches[collBranchIdx + brOffset.keys].data; + keyBranch = root_utils::getBranch(catInfo.chain.get(), root_utils::getGPKeyName()); + auto& valueBranch = catInfo.branches[collBranchIdx + brOffset.values].data; + valueBranch = root_utils::getBranch(catInfo.chain.get(), root_utils::getGPValueName()); } - auto* branch = paramBranches.data; + auto keyBranch = catInfo.branches[collBranchIdx + brOffset.keys].data; + auto valueBranch = catInfo.branches[collBranchIdx + brOffset.values].data; + + root_utils::ParamStorage storage; + keyBranch->SetAddress(storage.keysPtr()); + keyBranch->GetEntry(localEntry); + valueBranch->SetAddress(storage.valuesPtr()); + valueBranch->GetEntry(localEntry); + + params.loadFrom(std::move(storage.keys), std::move(storage.values)); +} + +GenericParameters ROOTReader::readEntryParameters(ROOTReader::CategoryInfo& catInfo, bool reloadBranches, + unsigned int localEntry) { GenericParameters params; - auto* emd = ¶ms; - branch->SetAddress(&emd); - branch->GetEntry(localEntry); + + if (m_fileVersion < podio::version::Version{0, 99, 99}) { + // Parameter branch is always the last one + auto& paramBranches = catInfo.branches.back(); + + // Make sure to have a valid branch pointer after switching trees in the chain + // as well as on the first event + if (reloadBranches) { + paramBranches.data = root_utils::getBranch(catInfo.chain.get(), root_utils::paramBranchName); + } + auto* branch = paramBranches.data; + + auto* emd = ¶ms; + branch->SetAddress(&emd); + branch->GetEntry(localEntry); + } else { + readParams(catInfo, params, reloadBranches, localEntry); + readParams(catInfo, params, reloadBranches, localEntry); + readParams(catInfo, params, reloadBranches, localEntry); + readParams(catInfo, params, reloadBranches, localEntry); + } + return params; } @@ -162,13 +195,25 @@ void ROOTReader::initCategory(CategoryInfo& catInfo, const std::string& category std::tie(catInfo.branches, catInfo.storedClasses) = createCollectionBranches(catInfo.chain.get(), *catInfo.table, *collInfo); } - delete collInfo; // Finally set up the branches for the parameters - root_utils::CollectionBranches paramBranches{}; - paramBranches.data = root_utils::getBranch(catInfo.chain.get(), root_utils::paramBranchName); - catInfo.branches.push_back(paramBranches); + if (m_fileVersion < podio::version::Version{0, 99, 99}) { + root_utils::CollectionBranches paramBranches{}; + catInfo.branches.emplace_back(root_utils::getBranch(catInfo.chain.get(), root_utils::paramBranchName)); + } else { + catInfo.branches.emplace_back(root_utils::getBranch(catInfo.chain.get(), root_utils::intKeyName)); + catInfo.branches.emplace_back(root_utils::getBranch(catInfo.chain.get(), root_utils::intValueName)); + + catInfo.branches.emplace_back(root_utils::getBranch(catInfo.chain.get(), root_utils::floatKeyName)); + catInfo.branches.emplace_back(root_utils::getBranch(catInfo.chain.get(), root_utils::floatValueName)); + + catInfo.branches.emplace_back(root_utils::getBranch(catInfo.chain.get(), root_utils::doubleKeyName)); + catInfo.branches.emplace_back(root_utils::getBranch(catInfo.chain.get(), root_utils::doubleValueName)); + + catInfo.branches.emplace_back(root_utils::getBranch(catInfo.chain.get(), root_utils::stringKeyName)); + catInfo.branches.emplace_back(root_utils::getBranch(catInfo.chain.get(), root_utils::stringValueName)); + } } std::vector getAvailableCategories(TChain* metaChain) { @@ -300,7 +345,7 @@ createCollectionBranchesIndexBased(TChain* chain, const podio::CollectionIDTable collBranches.emplace_back(std::move(branches)); } - return {collBranches, storedClasses}; + return {std::move(collBranches), storedClasses}; } std::tuple, std::vector>> @@ -346,7 +391,7 @@ createCollectionBranches(TChain* chain, const podio::CollectionIDTable& idTable, collBranches.emplace_back(std::move(branches)); } - return {collBranches, storedClasses}; + return {std::move(collBranches), storedClasses}; } } // namespace podio diff --git a/src/ROOTWriter.cc b/src/ROOTWriter.cc index 9e46bf942..b43ac5f92 100644 --- a/src/ROOTWriter.cc +++ b/src/ROOTWriter.cc @@ -8,6 +8,7 @@ #include "rootUtils.h" #include "TTree.h" +#include namespace podio { @@ -61,7 +62,8 @@ void ROOTWriter::writeFrame(const podio::Frame& frame, const std::string& catego throw std::runtime_error("Trying to write category '" + category + "' with inconsistent collection content. " + root_utils::getInconsistentCollsMsg(catInfo.collsToWrite, collsToWrite)); } - resetBranches(catInfo.branches, collections, &const_cast(frame.getParameters())); + fillParams(catInfo, frame.getParameters()); + resetBranches(catInfo, collections); } catInfo.tree->Fill(); @@ -78,7 +80,7 @@ ROOTWriter::CategoryInfo& ROOTWriter::getCategoryInfo(const std::string& categor void ROOTWriter::initBranches(CategoryInfo& catInfo, const std::vector& collections, /*const*/ podio::GenericParameters& parameters) { - catInfo.branches.reserve(collections.size() + 1); // collections + parameters + catInfo.branches.reserve(collections.size() + root_utils::nParamBranches); // collections + parameters // First collections for (auto& [name, coll] : collections) { @@ -117,28 +119,54 @@ void ROOTWriter::initBranches(CategoryInfo& catInfo, const std::vectorgetTypeName()), coll->isSubsetCollection(), coll->getSchemaVersion()); } - // Also make branches for the parameters - root_utils::CollectionBranches branches; - branches.data = catInfo.tree->Branch(root_utils::paramBranchName, ¶meters); - catInfo.branches.push_back(branches); + fillParams(catInfo, parameters); + // NOTE: The order in which these are created is codified for later use in + // root_utils::getGPBranchOffsets + catInfo.branches.emplace_back(catInfo.tree->Branch(root_utils::intKeyName, &catInfo.intParams.keys)); + catInfo.branches.emplace_back(catInfo.tree->Branch(root_utils::intValueName, &catInfo.intParams.values)); + + catInfo.branches.emplace_back(catInfo.tree->Branch(root_utils::floatKeyName, &catInfo.floatParams.keys)); + catInfo.branches.emplace_back(catInfo.tree->Branch(root_utils::floatValueName, &catInfo.floatParams.values)); + + catInfo.branches.emplace_back(catInfo.tree->Branch(root_utils::doubleKeyName, &catInfo.doubleParams.keys)); + catInfo.branches.emplace_back(catInfo.tree->Branch(root_utils::doubleValueName, &catInfo.doubleParams.values)); + + catInfo.branches.emplace_back(catInfo.tree->Branch(root_utils::stringKeyName, &catInfo.stringParams.keys)); + catInfo.branches.emplace_back(catInfo.tree->Branch(root_utils::stringValueName, &catInfo.stringParams.values)); } -void ROOTWriter::resetBranches(std::vector& branches, - const std::vector& collections, - /*const*/ podio::GenericParameters* parameters) { +void ROOTWriter::resetBranches(CategoryInfo& categoryInfo, + const std::vector& collections) { size_t iColl = 0; for (auto& [_, coll] : collections) { - const auto& collBranches = branches[iColl]; + const auto& collBranches = categoryInfo.branches[iColl]; root_utils::setCollectionAddresses(coll->getBuffers(), collBranches); iColl++; } + // Correct index to point to the last branch of collection data for symmetric + // handling of the offsets in reading and writing + iColl--; + + constexpr auto intOffset = root_utils::getGPBranchOffsets(); + categoryInfo.branches[iColl + intOffset.keys].data->SetAddress(categoryInfo.intParams.keysPtr()); + categoryInfo.branches[iColl + intOffset.values].data->SetAddress(categoryInfo.intParams.valuesPtr()); - branches.back().data->SetAddress(¶meters); + constexpr auto floatOffset = root_utils::getGPBranchOffsets(); + categoryInfo.branches[iColl + floatOffset.keys].data->SetAddress(categoryInfo.floatParams.keysPtr()); + categoryInfo.branches[iColl + floatOffset.values].data->SetAddress(categoryInfo.floatParams.valuesPtr()); + + constexpr auto doubleOffset = root_utils::getGPBranchOffsets(); + categoryInfo.branches[iColl + doubleOffset.keys].data->SetAddress(categoryInfo.doubleParams.keysPtr()); + categoryInfo.branches[iColl + doubleOffset.values].data->SetAddress(categoryInfo.doubleParams.valuesPtr()); + + constexpr auto stringOffset = root_utils::getGPBranchOffsets(); + categoryInfo.branches[iColl + stringOffset.keys].data->SetAddress(categoryInfo.stringParams.keysPtr()); + categoryInfo.branches[iColl + stringOffset.values].data->SetAddress(categoryInfo.stringParams.valuesPtr()); } void ROOTWriter::finish() { @@ -175,4 +203,11 @@ ROOTWriter::checkConsistency(const std::vector& collsToWrite, const return {std::vector{}, collsToWrite}; } +void ROOTWriter::fillParams(CategoryInfo& catInfo, const GenericParameters& params) { + catInfo.intParams = params.getKeysAndValues(); + catInfo.floatParams = params.getKeysAndValues(); + catInfo.doubleParams = params.getKeysAndValues(); + catInfo.stringParams = params.getKeysAndValues(); +} + } // namespace podio diff --git a/src/RootHelpers.cc b/src/RootHelpers.cc new file mode 100644 index 000000000..a1a33484c --- /dev/null +++ b/src/RootHelpers.cc @@ -0,0 +1,17 @@ +#include "podio/utilities/RootHelpers.h" + +namespace podio::root_utils { +GenericParameters +loadParamsFrom(ROOT::VecOps::RVec intKeys, ROOT::VecOps::RVec> intValues, + ROOT::VecOps::RVec floatKeys, ROOT::VecOps::RVec> floatValues, + ROOT::VecOps::RVec doubleKeys, ROOT::VecOps::RVec> doubleValues, + ROOT::VecOps::RVec stringKeys, ROOT::VecOps::RVec> stringValues) { + GenericParameters params{}; + params.loadFrom(std::move(intKeys), std::move(intValues)); + params.loadFrom(std::move(floatKeys), std::move(floatValues)); + params.loadFrom(std::move(doubleKeys), std::move(doubleValues)); + params.loadFrom(std::move(stringKeys), std::move(stringValues)); + return params; +} + +} // namespace podio::root_utils diff --git a/src/rootUtils.h b/src/rootUtils.h index c9e7c1238..131e0ef13 100644 --- a/src/rootUtils.h +++ b/src/rootUtils.h @@ -2,6 +2,7 @@ #define PODIO_ROOT_UTILS_H // NOLINT(llvm-header-guard): internal headers confuse clang-tidy #include "podio/CollectionIDTable.h" +#include "podio/GenericParameters.h" #include "podio/utilities/RootHelpers.h" #include "TBranch.h" @@ -80,6 +81,35 @@ constexpr auto getGPValueName() { } } +/// Small helper struct to get info on the offsets of the branches holding +/// GenericParameter keys and values for a given parameter type +struct GPBranchOffsets { + int keys{-1}; + int values{-1}; +}; + +/// The number of branches that we create on top of the collection branches per +/// category +constexpr auto nParamBranches = std::tuple_size_v * 2; + +/// Get the branch offsets for a given parameter type. In this case it is +/// assumed that the integer branches start immediately after the branche for +/// the collections +template +constexpr auto getGPBranchOffsets() { + if constexpr (std::is_same_v) { + return GPBranchOffsets{1, 2}; + } else if constexpr (std::is_same_v) { + return GPBranchOffsets{3, 4}; + } else if constexpr (std::is_same_v) { + return GPBranchOffsets{5, 6}; + } else if constexpr (std::is_same_v) { + return GPBranchOffsets{7, 8}; + } else { + static_assert(sizeof(T) == 0, "Unsupported type for generic parameters"); + } +} + /** * Name of the field with the list of categories for RNTuples */ diff --git a/src/selection.xml b/src/selection.xml index 03686376f..82acdc661 100644 --- a/src/selection.xml +++ b/src/selection.xml @@ -10,6 +10,7 @@ + @@ -17,6 +18,12 @@ + + + + + + @@ -24,6 +31,7 @@ + diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 729248b91..aa417badd 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -59,6 +59,7 @@ set(root_legacy_test_versions v00-16-02 v00-16-05 v00-16-06 + v00-99 ) add_subdirectory(root_io) @@ -66,6 +67,7 @@ if (ENABLE_SIO) set(sio_legacy_test_versions v00-16-05 v00-16-06 + v00-99 ) add_subdirectory(sio_io) diff --git a/tests/CTestCustom.cmake b/tests/CTestCustom.cmake index 3c660068a..802bbed3a 100644 --- a/tests/CTestCustom.cmake +++ b/tests/CTestCustom.cmake @@ -19,6 +19,8 @@ if ((NOT "@FORCE_RUN_ALL_TESTS@" STREQUAL "ON") AND (NOT "@USE_SANITIZER@" STREQ read_python_frame_root read_and_write_frame_root + param_reading_rdataframe + write_frame_root read_frame_root diff --git a/tests/input_files/v00-99-example_frame.root.md5 b/tests/input_files/v00-99-example_frame.root.md5 new file mode 100644 index 000000000..5b52257e6 --- /dev/null +++ b/tests/input_files/v00-99-example_frame.root.md5 @@ -0,0 +1 @@ +dbd91affe295c85c1838c40fb9da5013 diff --git a/tests/input_files/v00-99-example_frame.sio.md5 b/tests/input_files/v00-99-example_frame.sio.md5 new file mode 100644 index 000000000..c57b2a6bb --- /dev/null +++ b/tests/input_files/v00-99-example_frame.sio.md5 @@ -0,0 +1 @@ +ad1945557d6b5e02620294c7edac3f99 diff --git a/tests/root_io/CMakeLists.txt b/tests/root_io/CMakeLists.txt index 6a4069a48..7f79a000b 100644 --- a/tests/root_io/CMakeLists.txt +++ b/tests/root_io/CMakeLists.txt @@ -45,7 +45,9 @@ target_link_libraries(read_frame_legacy_root PRIVATE "${root_libs}") foreach(version IN LISTS root_legacy_test_versions) ADD_PODIO_LEGACY_TEST(${version} read_frame_root ${version}-example_frame.root) - ADD_PODIO_LEGACY_TEST(${version} read_frame_legacy_root ${version}-example.root) + if (version MATCHES "^v00-16") + ADD_PODIO_LEGACY_TEST(${version} read_frame_legacy_root ${version}-example.root) + endif() endforeach() #--- Write via python and the ROOT backend and see if we can read it back in in @@ -60,3 +62,7 @@ if (ENABLE_RNTUPLE) set_property(TEST read_python_frame_rntuple PROPERTY DEPENDS write_python_frame_rntuple) endif() + +add_test(NAME param_reading_rdataframe COMMAND python3 ${CMAKE_CURRENT_SOURCE_DIR}/param_reading_rdataframe.py example_frame.root) +PODIO_SET_TEST_ENV(param_reading_rdataframe) +set_property(TEST param_reading_rdataframe PROPERTY DEPENDS write_frame_root) diff --git a/tests/root_io/param_reading_rdataframe.py b/tests/root_io/param_reading_rdataframe.py new file mode 100644 index 000000000..afc0359ba --- /dev/null +++ b/tests/root_io/param_reading_rdataframe.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3 +"""Small test case for checking that utilities work as expeced in RDataFrame""" + +import sys +import ROOT + + +ROOT.gInterpreter.Declare("#include ") +df = ROOT.RDataFrame("events", sys.argv[1]) + +evtWeights = ( + df.Define( + "params", + "podio::root_utils::loadParamsFrom(GPIntKeys, GPIntValues, GPFloatKeys, GPFloatValues," + "GPDoubleKeys, GPDoubleValues, GPStringKeys, GPStringValues)", + ) + .Define("eventweight", 'params.get("UserEventWeight").value()') + .Histo1D("eventweight") +) + +if evtWeights.GetMean() != 450.0: + print("Parameter values not as expected") + sys.exit(1) diff --git a/tests/sio_io/CMakeLists.txt b/tests/sio_io/CMakeLists.txt index 7102c36c7..7f53917fe 100644 --- a/tests/sio_io/CMakeLists.txt +++ b/tests/sio_io/CMakeLists.txt @@ -33,5 +33,7 @@ target_link_libraries(read_frame_legacy_sio PRIVATE "${sio_libs}" TestDataModel) foreach(version IN LISTS sio_legacy_test_versions) ADD_PODIO_LEGACY_TEST(${version} read_frame_sio ${version}-example_frame.sio) - ADD_PODIO_LEGACY_TEST(${version} read_frame_legacy_sio ${version}-example.sio) + if (version MATCHES "^v00-16") + ADD_PODIO_LEGACY_TEST(${version} read_frame_legacy_sio ${version}-example.sio) + endif() endforeach()