diff --git a/include/podio/CollectionBranches.h b/include/podio/CollectionBranches.h new file mode 100644 index 000000000..3ab3e8129 --- /dev/null +++ b/include/podio/CollectionBranches.h @@ -0,0 +1,23 @@ +#ifndef PODIO_COLLECTIONBRANCHES_H +#define PODIO_COLLECTIONBRANCHES_H + +#include "TBranch.h" + +#include +#include + +namespace podio::root_utils { +/// Small helper struct to collect all branches that are necessary to read or +/// write a collection. Needed to cache the branch pointers and avoid having to +/// get them from a TTree/TChain for every event. +struct CollectionBranches { + TBranch* data{nullptr}; + std::vector refs{}; + std::vector vecs{}; + std::vector refNames{}; ///< The names of the relation branches + std::vector vecNames{}; ///< The names of the vector member branches +}; + +} // namespace podio::root_utils + +#endif diff --git a/include/podio/GenericParameters.h b/include/podio/GenericParameters.h index 88d8953f4..55119a2e8 100644 --- a/include/podio/GenericParameters.h +++ b/include/podio/GenericParameters.h @@ -6,7 +6,6 @@ #include #include -#include #include #include #include @@ -31,12 +30,6 @@ 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; @@ -112,10 +105,6 @@ class GenericParameters { template > std::vector getKeys() const; - /// Get all the available values for a given type - template > - std::vector> getValues() const; - /// erase all elements void clear() { _intMap.clear(); @@ -140,10 +129,6 @@ 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 { @@ -258,17 +243,5 @@ std::vector GenericParameters::getKeys() const { return keys; } -template -std::vector> GenericParameters::getValues() const { - std::vector> values; - { - auto& mtx = getMutex(); - const auto& map = getMap(); - 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; }); - } - return values; -} } // namespace podio #endif diff --git a/include/podio/RNTupleReader.h b/include/podio/RNTupleReader.h index 057b9fcef..1cffa149f 100644 --- a/include/podio/RNTupleReader.h +++ b/include/podio/RNTupleReader.h @@ -1,6 +1,8 @@ #ifndef PODIO_RNTUPLEREADER_H #define PODIO_RNTUPLEREADER_H +#include "podio/CollectionBranches.h" +#include "podio/ICollectionProvider.h" #include "podio/ROOTFrameData.h" #include "podio/SchemaEvolution.h" #include "podio/podioVersion.h" diff --git a/include/podio/RNTupleWriter.h b/include/podio/RNTupleWriter.h index d8a53ba43..ed0f3012c 100644 --- a/include/podio/RNTupleWriter.h +++ b/include/podio/RNTupleWriter.h @@ -1,11 +1,11 @@ #ifndef PODIO_RNTUPLEWRITER_H #define PODIO_RNTUPLEWRITER_H +#include "podio/CollectionBase.h" #include "podio/Frame.h" #include "podio/GenericParameters.h" #include "podio/SchemaEvolution.h" #include "podio/utilities/DatamodelRegistryIOHelpers.h" -#include "podio/utilities/RootHelpers.h" #include "TFile.h" #include @@ -102,42 +102,42 @@ class RNTupleWriter { checkConsistency(const std::vector& collsToWrite, const std::string& category) const; private: - std::unique_ptr - createModels(const std::vector& collections); - - /// Helper struct to group all the necessary information for one category. - struct CategoryInfo { - std::unique_ptr writer{nullptr}; ///< The RNTupleWriter for this category - - // The following are assumed to run in parallel! - std::vector ids{}; ///< The ids of all collections - std::vector names{}; ///< The names of all collections - std::vector types{}; ///< The types of all collections - std::vector subsetCollections{}; ///< The flags identifying the subcollections - std::vector schemaVersions{}; ///< The schema versions of all collections - - // 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{}; - }; - CategoryInfo& getCategoryInfo(const std::string& category); - template - void fillParams(const GenericParameters& params, CategoryInfo& catInfo, ROOT::Experimental::REntry* entry); + void fillParams(GenericParameters& params, ROOT::Experimental::REntry* entry); - template - root_utils::ParamStorage& getParamStorage(CategoryInfo& catInfo); + using StoreCollection = std::pair; + std::unique_ptr createModels(const std::vector& collections); + + std::unique_ptr m_metadata{}; + std::unique_ptr m_metadataWriter{}; std::unique_ptr m_file{}; DatamodelDefinitionCollector m_datamodelCollector{}; - std::unordered_map m_categories{}; + struct CollectionInfo { + std::vector id{}; + std::vector name{}; + std::vector type{}; + std::vector isSubsetCollection{}; + std::vector schemaVersion{}; + std::unique_ptr writer{nullptr}; + }; + CollectionInfo& getCategoryInfo(const std::string& category); + + std::unordered_map m_categories{}; bool m_finished{false}; + + std::vector m_intkeys{}, m_floatkeys{}, m_doublekeys{}, m_stringkeys{}; + + std::vector> m_intvalues{}; + std::vector> m_floatvalues{}; + std::vector> m_doublevalues{}; + std::vector> m_stringvalues{}; + + template + std::pair&, std::vector>&> getKeyValueVectors(); }; } // namespace podio diff --git a/include/podio/ROOTLegacyReader.h b/include/podio/ROOTLegacyReader.h index 9383ca51b..c379eea1c 100644 --- a/include/podio/ROOTLegacyReader.h +++ b/include/podio/ROOTLegacyReader.h @@ -1,12 +1,13 @@ #ifndef PODIO_ROOTLEGACYREADER_H #define PODIO_ROOTLEGACYREADER_H +#include "podio/CollectionBranches.h" #include "podio/ROOTFrameData.h" #include "podio/podioVersion.h" -#include "podio/utilities/RootHelpers.h" #include "TChain.h" +#include #include #include #include @@ -113,7 +114,7 @@ class ROOTLegacyReader { private: std::pair getLocalTreeAndEntry(const std::string& treename); - void createCollectionBranches(const std::vector& collInfo); + void createCollectionBranches(const std::vector>& collInfo); podio::GenericParameters readEventMetaData(); diff --git a/include/podio/ROOTReader.h b/include/podio/ROOTReader.h index e6ecbd0e0..b14a08d17 100644 --- a/include/podio/ROOTReader.h +++ b/include/podio/ROOTReader.h @@ -1,13 +1,14 @@ #ifndef PODIO_ROOTREADER_H #define PODIO_ROOTREADER_H +#include "podio/CollectionBranches.h" #include "podio/ROOTFrameData.h" #include "podio/podioVersion.h" #include "podio/utilities/DatamodelRegistryIOHelpers.h" -#include "podio/utilities/RootHelpers.h" #include "TChain.h" +#include #include #include #include @@ -156,10 +157,6 @@ 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 5ee23835f..06aa61a46 100644 --- a/include/podio/ROOTWriter.h +++ b/include/podio/ROOTWriter.h @@ -1,9 +1,9 @@ #ifndef PODIO_ROOTWRITER_H #define PODIO_ROOTWRITER_H +#include "podio/CollectionBranches.h" #include "podio/CollectionIDTable.h" #include "podio/utilities/DatamodelRegistryIOHelpers.h" -#include "podio/utilities/RootHelpers.h" #include "TFile.h" @@ -100,34 +100,32 @@ class ROOTWriter { checkConsistency(const std::vector& collsToWrite, const std::string& category) const; private: + using StoreCollection = std::pair; + + // collectionID, collectionType, subsetCollection + // @note same as in rootUtils.h private header! + using CollectionInfoT = std::tuple; + /// Helper struct to group together all necessary state to write / process a /// given category. Created during the first writing of a category struct CategoryInfo { - TTree* tree{nullptr}; ///< The TTree to which this category is written - std::vector branches{}; ///< The branches for this category - 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{}; + TTree* tree{nullptr}; ///< The TTree to which this category is written + std::vector branches{}; ///< The branches for this category + 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 }; /// Initialize the branches for this category - void initBranches(CategoryInfo& catInfo, const std::vector& collections, + void initBranches(CategoryInfo& catInfo, const std::vector& collections, /*const*/ podio::GenericParameters& parameters); /// Get the (potentially uninitialized category information for this category) CategoryInfo& getCategoryInfo(const std::string& category); - 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); + static void resetBranches(std::vector& branches, + const std::vector& collections, + /*const*/ podio::GenericParameters* parameters); 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 deleted file mode 100644 index 8e3118b4d..000000000 --- a/include/podio/utilities/RootHelpers.h +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef PODIO_UTILITIES_ROOTHELPERS_H -#define PODIO_UTILITIES_ROOTHELPERS_H - -#include "TBranch.h" - -#include -#include -#include - -namespace podio { -class CollectionBase; - -namespace root_utils { - - // A collection of additional information that describes the collection: the - // collectionID, the collection (data) type, whether it is a subset - // collection, and its schema version - using CollectionWriteInfoT = std::tuple; - // for backwards compatibility - using CollectionInfoWithoutSchemaT = std::tuple; - - /// A collection name and a base pointer grouped together for writing - using StoreCollection = std::tuple; - - /// Small helper struct to collect all branches that are necessary to read or - /// 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{}; - std::vector refNames{}; ///< The names of the relation branches - std::vector vecNames{}; ///< The names of the vector member branches - }; - - /// Pair of keys and values for one type of the ones that can be stored in - /// GenericParameters - template - struct ParamStorage { - ParamStorage() = default; - ~ParamStorage() = default; - ParamStorage(const ParamStorage&) = delete; - ParamStorage& operator=(const ParamStorage&) = delete; - ParamStorage(ParamStorage&&) = default; - ParamStorage& operator=(ParamStorage&&) = default; - - ParamStorage(const std::vector& ks, const std::vector>& vs) : keys(ks), values(vs) { - } - - auto keysPtr() { - m_keysPtr = &keys; - return &m_keysPtr; - } - - auto valuesPtr() { - m_valuesPtr = &values; - return &m_valuesPtr; - } - - std::vector keys{}; - std::vector> values{}; - - private: - std::vector* m_keysPtr{nullptr}; - std::vector>* m_valuesPtr{nullptr}; - }; - -} // namespace root_utils -} // namespace podio - -#endif // PODIO_UTILITIES_ROOTHELPERS_H diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 561e2a9b9..393e93383 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -94,7 +94,6 @@ SET(root_headers ${PROJECT_SOURCE_DIR}/include/podio/ROOTLegacyReader.h ${PROJECT_SOURCE_DIR}/include/podio/ROOTWriter.h ${PROJECT_SOURCE_DIR}/include/podio/ROOTFrameData.h - ${PROJECT_SOURCE_DIR}/include/podio/utilities/RootHelpers.h ) if(ENABLE_RNTUPLE) list(APPEND root_headers diff --git a/src/RNTupleWriter.cc b/src/RNTupleWriter.cc index 55d23167f..38231cc18 100644 --- a/src/RNTupleWriter.cc +++ b/src/RNTupleWriter.cc @@ -17,6 +17,7 @@ namespace podio { RNTupleWriter::RNTupleWriter(const std::string& filename) : + m_metadata(ROOT::Experimental::RNTupleModel::Create()), m_file(new TFile(filename.c_str(), "RECREATE", "data file")) { } @@ -27,35 +28,40 @@ RNTupleWriter::~RNTupleWriter() { } template -root_utils::ParamStorage& RNTupleWriter::getParamStorage(CategoryInfo& catInfo) { +std::pair&, std::vector>&> RNTupleWriter::getKeyValueVectors() { if constexpr (std::is_same_v) { - return catInfo.intParams; + return {m_intkeys, m_intvalues}; } else if constexpr (std::is_same_v) { - return catInfo.floatParams; + return {m_floatkeys, m_floatvalues}; } else if constexpr (std::is_same_v) { - return catInfo.doubleParams; + return {m_doublekeys, m_doublevalues}; } else if constexpr (std::is_same_v) { - return catInfo.stringParams; + return {m_stringkeys, m_stringvalues}; } else { throw std::runtime_error("Unknown type"); } } template -void RNTupleWriter::fillParams(const GenericParameters& params, CategoryInfo& catInfo, - ROOT::Experimental::REntry* entry) { - auto& paramStorage = getParamStorage(catInfo); - auto& keys = paramStorage.keys; - auto& values = paramStorage.values; - keys = params.getKeys(); - values = params.getValues(); +void RNTupleWriter::fillParams(GenericParameters& params, ROOT::Experimental::REntry* entry) { + auto [key, value] = getKeyValueVectors(); #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(), &key); + entry->BindRawPtr(root_utils::getGPValueName(), &value); #else - entry->CaptureValueUnsafe(root_utils::getGPKeyName(), &keys); - entry->CaptureValueUnsafe(root_utils::getGPValueName(), &values); + entry->CaptureValueUnsafe(root_utils::getGPKeyName(), &key); + entry->CaptureValueUnsafe(root_utils::getGPValueName(), &value); #endif + + key.clear(); + key.reserve(params.getMap().size()); + value.clear(); + value.reserve(params.getMap().size()); + + for (auto& [kk, vv] : params.getMap()) { + key.emplace_back(kk); + value.emplace_back(vv); + } } void RNTupleWriter::writeFrame(const podio::Frame& frame, const std::string& category) { @@ -71,14 +77,14 @@ void RNTupleWriter::writeFrame(const podio::Frame& frame, const std::string& cat const bool new_category = (catInfo.writer == nullptr); if (new_category) { // This is the minimal information that we need for now - catInfo.names = root_utils::sortAlphabeticaly(collsToWrite); + catInfo.name = root_utils::sortAlphabeticaly(collsToWrite); } - std::vector collections; - collections.reserve(catInfo.names.size()); + std::vector collections; + collections.reserve(catInfo.name.size()); // Only loop over the collections that were requested in the first Frame of // this category - for (const auto& name : catInfo.names) { + for (const auto& name : catInfo.name) { auto* coll = frame.getCollectionForWrite(name); if (!coll) { // Make sure all collections that we want to write are actually available @@ -95,15 +101,15 @@ void RNTupleWriter::writeFrame(const podio::Frame& frame, const std::string& cat catInfo.writer = ROOT::Experimental::RNTupleWriter::Append(std::move(model), category, *m_file.get(), {}); for (const auto& [name, coll] : collections) { - catInfo.ids.emplace_back(coll->getID()); - catInfo.types.emplace_back(coll->getTypeName()); - catInfo.subsetCollections.emplace_back(coll->isSubsetCollection()); - catInfo.schemaVersions.emplace_back(coll->getSchemaVersion()); + catInfo.id.emplace_back(coll->getID()); + catInfo.type.emplace_back(coll->getTypeName()); + catInfo.isSubsetCollection.emplace_back(coll->isSubsetCollection()); + catInfo.schemaVersion.emplace_back(coll->getSchemaVersion()); } } else { - if (!root_utils::checkConsistentColls(catInfo.names, collsToWrite)) { + if (!root_utils::checkConsistentColls(catInfo.name, collsToWrite)) { throw std::runtime_error("Trying to write category '" + category + "' with inconsistent collection content. " + - root_utils::getInconsistentCollsMsg(catInfo.names, collsToWrite)); + root_utils::getInconsistentCollsMsg(catInfo.name, collsToWrite)); } } @@ -172,17 +178,17 @@ void RNTupleWriter::writeFrame(const podio::Frame& frame, const std::string& cat // &const_cast(frame.getParameters())); } - const auto& params = frame.getParameters(); - fillParams(params, catInfo, entry.get()); - fillParams(params, catInfo, entry.get()); - fillParams(params, catInfo, entry.get()); - fillParams(params, catInfo, entry.get()); + auto params = frame.getParameters(); + fillParams(params, entry.get()); + fillParams(params, entry.get()); + fillParams(params, entry.get()); + fillParams(params, entry.get()); m_categories[category].writer->Fill(*entry); } std::unique_ptr -RNTupleWriter::createModels(const std::vector& collections) { +RNTupleWriter::createModels(const std::vector& collections) { auto model = ROOT::Experimental::RNTupleModel::CreateBare(); #if ROOT_VERSION_CODE >= ROOT_VERSION(6, 31, 0) @@ -254,49 +260,49 @@ RNTupleWriter::createModels(const std::vector& coll return model; } -RNTupleWriter::CategoryInfo& RNTupleWriter::getCategoryInfo(const std::string& category) { +RNTupleWriter::CollectionInfo& RNTupleWriter::getCategoryInfo(const std::string& category) { if (auto it = m_categories.find(category); it != m_categories.end()) { return it->second; } - auto [it, _] = m_categories.try_emplace(category, CategoryInfo{}); + auto [it, _] = m_categories.try_emplace(category, CollectionInfo{}); return it->second; } void RNTupleWriter::finish() { - auto metadata = ROOT::Experimental::RNTupleModel::Create(); auto podioVersion = podio::version::build_version; - auto versionField = metadata->MakeField>(root_utils::versionBranchName); + auto versionField = m_metadata->MakeField>(root_utils::versionBranchName); *versionField = {podioVersion.major, podioVersion.minor, podioVersion.patch}; auto edmDefinitions = m_datamodelCollector.getDatamodelDefinitionsToWrite(); - auto edmField = metadata->MakeField>>(root_utils::edmDefBranchName); + auto edmField = + m_metadata->MakeField>>(root_utils::edmDefBranchName); *edmField = std::move(edmDefinitions); - auto availableCategoriesField = metadata->MakeField>(root_utils::availableCategories); + auto availableCategoriesField = m_metadata->MakeField>(root_utils::availableCategories); for (auto& [c, _] : m_categories) { availableCategoriesField->push_back(c); } for (auto& [category, collInfo] : m_categories) { - auto idField = metadata->MakeField>({root_utils::idTableName(category)}); - *idField = collInfo.ids; - auto collectionNameField = metadata->MakeField>({root_utils::collectionName(category)}); - *collectionNameField = collInfo.names; - auto collectionTypeField = metadata->MakeField>({root_utils::collInfoName(category)}); - *collectionTypeField = collInfo.types; - auto subsetCollectionField = metadata->MakeField>({root_utils::subsetCollection(category)}); - *subsetCollectionField = collInfo.subsetCollections; - auto schemaVersionField = metadata->MakeField>({"schemaVersion_" + category}); - *schemaVersionField = collInfo.schemaVersions; + auto idField = m_metadata->MakeField>({root_utils::idTableName(category)}); + *idField = collInfo.id; + auto collectionNameField = m_metadata->MakeField>({root_utils::collectionName(category)}); + *collectionNameField = collInfo.name; + auto collectionTypeField = m_metadata->MakeField>({root_utils::collInfoName(category)}); + *collectionTypeField = collInfo.type; + auto subsetCollectionField = m_metadata->MakeField>({root_utils::subsetCollection(category)}); + *subsetCollectionField = collInfo.isSubsetCollection; + auto schemaVersionField = m_metadata->MakeField>({"schemaVersion_" + category}); + *schemaVersionField = collInfo.schemaVersion; } - metadata->Freeze(); - auto metadataWriter = - ROOT::Experimental::RNTupleWriter::Append(std::move(metadata), root_utils::metaTreeName, *m_file, {}); + m_metadata->Freeze(); + m_metadataWriter = + ROOT::Experimental::RNTupleWriter::Append(std::move(m_metadata), root_utils::metaTreeName, *m_file, {}); - metadataWriter->Fill(); + m_metadataWriter->Fill(); m_file->Write(); @@ -305,6 +311,7 @@ void RNTupleWriter::finish() { for (auto& [_, catInfo] : m_categories) { catInfo.writer.reset(); } + m_metadataWriter.reset(); m_finished = true; } @@ -312,7 +319,7 @@ void RNTupleWriter::finish() { std::tuple, std::vector> RNTupleWriter::checkConsistency(const std::vector& collsToWrite, const std::string& category) const { if (const auto it = m_categories.find(category); it != m_categories.end()) { - return root_utils::getInconsistentColls(it->second.names, collsToWrite); + return root_utils::getInconsistentColls(it->second.name, collsToWrite); } return {std::vector{}, collsToWrite}; diff --git a/src/ROOTLegacyReader.cc b/src/ROOTLegacyReader.cc index 494ec4301..c5815e4e3 100644 --- a/src/ROOTLegacyReader.cc +++ b/src/ROOTLegacyReader.cc @@ -138,7 +138,7 @@ void ROOTLegacyReader::openFiles(const std::vector& filenames) { // Check if the CollectionTypeInfo branch is there and assume that the file // has been written with with podio pre #197 (<0.13.1) if that is not the case if (auto* collInfoBranch = root_utils::getBranch(metadatatree, "CollectionTypeInfo")) { - auto collectionInfo = new std::vector; + auto collectionInfo = new std::vector; if (m_fileVersion < podio::version::Version{0, 16, 4}) { auto oldCollInfo = new std::vector(); @@ -171,7 +171,7 @@ unsigned ROOTLegacyReader::getEntries(const std::string& name) const { return m_chain->GetEntries(); } -void ROOTLegacyReader::createCollectionBranches(const std::vector& collInfo) { +void ROOTLegacyReader::createCollectionBranches(const std::vector& collInfo) { size_t collectionIndex{0}; for (const auto& [collID, collType, isSubsetColl, collSchemaVersion] : collInfo) { @@ -207,7 +207,7 @@ void ROOTLegacyReader::createCollectionBranches(const std::vector @@ -20,91 +21,28 @@ namespace podio { std::tuple, std::vector>> createCollectionBranches(TChain* chain, const podio::CollectionIDTable& idTable, - const std::vector& collInfo); + const std::vector& collInfo); std::tuple, std::vector>> createCollectionBranchesIndexBased(TChain* chain, const podio::CollectionIDTable& idTable, - const std::vector& collInfo); - -/// Helper struct to get the negative offsets from the end of the branches -/// vector for the different types of generic parameters. -template -struct TypeToBranchIndexOffset; - -template <> -struct TypeToBranchIndexOffset { - constexpr static int keys = 8; - constexpr static int values = 7; -}; - -template <> -struct TypeToBranchIndexOffset { - constexpr static int keys = 6; - constexpr static int values = 5; -}; - -template <> -struct TypeToBranchIndexOffset { - constexpr static int keys = 4; - constexpr static int values = 3; -}; - -template <> -struct TypeToBranchIndexOffset { - constexpr static int keys = 2; - constexpr static int values = 1; -}; - -template -void ROOTReader::readParams(ROOTReader::CategoryInfo& catInfo, podio::GenericParameters& params, bool reloadBranches, - unsigned int localEntry) { - const auto nBranches = catInfo.branches.size(); - if (reloadBranches) { - auto& keyBranch = catInfo.branches[nBranches - TypeToBranchIndexOffset::keys].data; - keyBranch = root_utils::getBranch(catInfo.chain.get(), root_utils::getGPKeyName()); - auto& valueBranch = catInfo.branches[nBranches - TypeToBranchIndexOffset::values].data; - valueBranch = root_utils::getBranch(catInfo.chain.get(), root_utils::getGPValueName()); - } - - auto keyBranch = catInfo.branches[nBranches - TypeToBranchIndexOffset::keys].data; - auto valueBranch = catInfo.branches[nBranches - TypeToBranchIndexOffset::values].data; - - root_utils::ParamStorage storage; - keyBranch->SetAddress(storage.keysPtr()); - keyBranch->GetEntry(localEntry); - valueBranch->SetAddress(storage.valuesPtr()); - valueBranch->GetEntry(localEntry); - - for (size_t i = 0; i < storage.keys.size(); ++i) { - params.getMap().emplace(std::move(storage.keys[i]), std::move(storage.values[i])); - } -} + const std::vector& collInfo); GenericParameters ROOTReader::readEntryParameters(ROOTReader::CategoryInfo& catInfo, bool reloadBranches, unsigned int localEntry) { - GenericParameters params; - - 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; + // Parameter branch is always the last one + auto& paramBranches = catInfo.branches.back(); - 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); + // 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; + GenericParameters params; + auto* emd = ¶ms; + branch->SetAddress(&emd); + branch->GetEntry(localEntry); return params; } @@ -199,7 +137,7 @@ void ROOTReader::initCategory(CategoryInfo& catInfo, const std::string& category auto* collInfoBranch = root_utils::getBranch(m_metaChain.get(), root_utils::collInfoName(category)); - auto collInfo = new std::vector(); + auto collInfo = new std::vector(); if (m_fileVersion < podio::version::Version{0, 16, 4}) { auto oldCollInfo = new std::vector(); collInfoBranch->SetAddress(&oldCollInfo); @@ -224,25 +162,13 @@ 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 - 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)); - } + root_utils::CollectionBranches paramBranches{}; + paramBranches.data = root_utils::getBranch(catInfo.chain.get(), root_utils::paramBranchName); + catInfo.branches.push_back(paramBranches); } std::vector getAvailableCategories(TChain* metaChain) { @@ -327,7 +253,7 @@ std::vector ROOTReader::getAvailableCategories() const { std::tuple, std::vector>> createCollectionBranchesIndexBased(TChain* chain, const podio::CollectionIDTable& idTable, - const std::vector& collInfo) { + const std::vector& collInfo) { size_t collectionIndex{0}; std::vector collBranches; @@ -374,12 +300,12 @@ createCollectionBranchesIndexBased(TChain* chain, const podio::CollectionIDTable collBranches.emplace_back(std::move(branches)); } - return {std::move(collBranches), storedClasses}; + return {collBranches, storedClasses}; } std::tuple, std::vector>> createCollectionBranches(TChain* chain, const podio::CollectionIDTable& idTable, - const std::vector& collInfo) { + const std::vector& collInfo) { size_t collectionIndex{0}; std::vector collBranches; @@ -420,7 +346,7 @@ createCollectionBranches(TChain* chain, const podio::CollectionIDTable& idTable, collBranches.emplace_back(std::move(branches)); } - return {std::move(collBranches), storedClasses}; + return {collBranches, storedClasses}; } } // namespace podio diff --git a/src/ROOTWriter.cc b/src/ROOTWriter.cc index df8e810fd..b38bc145b 100644 --- a/src/ROOTWriter.cc +++ b/src/ROOTWriter.cc @@ -8,7 +8,6 @@ #include "rootUtils.h" #include "TTree.h" -#include namespace podio { @@ -38,7 +37,7 @@ void ROOTWriter::writeFrame(const podio::Frame& frame, const std::string& catego catInfo.tree->SetDirectory(m_file.get()); } - std::vector collections; + std::vector collections; collections.reserve(catInfo.collsToWrite.size()); for (const auto& name : catInfo.collsToWrite) { auto* coll = frame.getCollectionForWrite(name); @@ -62,8 +61,7 @@ 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)); } - fillParams(catInfo, frame.getParameters()); - resetBranches(catInfo, collections); + resetBranches(catInfo.branches, collections, &const_cast(frame.getParameters())); } catInfo.tree->Fill(); @@ -78,10 +76,9 @@ ROOTWriter::CategoryInfo& ROOTWriter::getCategoryInfo(const std::string& categor return it->second; } -void ROOTWriter::initBranches(CategoryInfo& catInfo, const std::vector& collections, +void ROOTWriter::initBranches(CategoryInfo& catInfo, const std::vector& collections, /*const*/ podio::GenericParameters& parameters) { - catInfo.branches.reserve(collections.size() + - std::tuple_size_v * 2); // collections + parameters + catInfo.branches.reserve(collections.size() + 1); // collections + parameters // First collections for (auto& [name, coll] : collections) { @@ -120,45 +117,28 @@ void ROOTWriter::initBranches(CategoryInfo& catInfo, const std::vectorgetTypeName()), + catInfo.branches.push_back(branches); + catInfo.collInfo.emplace_back(catInfo.idTable.collectionID(name).value(), coll->getTypeName(), coll->isSubsetCollection(), coll->getSchemaVersion()); } - fillParams(catInfo, parameters); - 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)); + // Also make branches for the parameters + root_utils::CollectionBranches branches; + branches.data = catInfo.tree->Branch(root_utils::paramBranchName, ¶meters); + catInfo.branches.push_back(branches); } -void ROOTWriter::resetBranches(CategoryInfo& categoryInfo, - const std::vector& collections) { +void ROOTWriter::resetBranches(std::vector& branches, + const std::vector& collections, + /*const*/ podio::GenericParameters* parameters) { size_t iColl = 0; - for (auto& [_, coll] : collections) { - const auto& collBranches = categoryInfo.branches[iColl]; - root_utils::setCollectionAddresses(coll->getBuffers(), collBranches); + for (auto& coll : collections) { + const auto& collBranches = branches[iColl]; + root_utils::setCollectionAddresses(coll.second->getBuffers(), collBranches); iColl++; } - categoryInfo.branches[iColl].data->SetAddress(categoryInfo.intParams.keysPtr()); - categoryInfo.branches[iColl + 1].data->SetAddress(categoryInfo.intParams.valuesPtr()); - - categoryInfo.branches[iColl + 2].data->SetAddress(categoryInfo.floatParams.keysPtr()); - categoryInfo.branches[iColl + 3].data->SetAddress(categoryInfo.floatParams.valuesPtr()); - - categoryInfo.branches[iColl + 4].data->SetAddress(categoryInfo.doubleParams.keysPtr()); - categoryInfo.branches[iColl + 5].data->SetAddress(categoryInfo.doubleParams.valuesPtr()); - - categoryInfo.branches[iColl + 6].data->SetAddress(categoryInfo.stringParams.keysPtr()); - categoryInfo.branches[iColl + 7].data->SetAddress(categoryInfo.stringParams.valuesPtr()); + branches.back().data->SetAddress(¶meters); } void ROOTWriter::finish() { @@ -195,11 +175,4 @@ ROOTWriter::checkConsistency(const std::vector& collsToWrite, const return {std::vector{}, collsToWrite}; } -void ROOTWriter::fillParams(CategoryInfo& catInfo, const GenericParameters& params) { - catInfo.intParams = {params.getKeys(), params.getValues()}; - catInfo.floatParams = {params.getKeys(), params.getValues()}; - catInfo.doubleParams = {params.getKeys(), params.getValues()}; - catInfo.stringParams = {params.getKeys(), params.getValues()}; -} - } // namespace podio diff --git a/src/rootUtils.h b/src/rootUtils.h index c9e7c1238..5fb7aa7d3 100644 --- a/src/rootUtils.h +++ b/src/rootUtils.h @@ -1,10 +1,14 @@ #ifndef PODIO_ROOT_UTILS_H // NOLINT(llvm-header-guard): internal headers confuse clang-tidy #define PODIO_ROOT_UTILS_H // NOLINT(llvm-header-guard): internal headers confuse clang-tidy +#include "podio/CollectionBase.h" +#include "podio/CollectionBranches.h" +#include "podio/CollectionBuffers.h" #include "podio/CollectionIDTable.h" -#include "podio/utilities/RootHelpers.h" #include "TBranch.h" +#include "TChain.h" +#include "TClass.h" #include "TTree.h" #include @@ -199,6 +203,13 @@ inline void setCollectionAddresses(const BufferT& collBuffers, const CollectionB } } +// A collection of additional information that describes the collection: the +// collectionID, the collection (data) type, whether it is a subset +// collection, and its schema version +using CollectionInfoT = std::tuple; +// for backwards compatibility +using CollectionInfoWithoutSchemaT = std::tuple; + inline void readBranchesData(const CollectionBranches& branches, Long64_t entry) { // Read all data if (branches.data) { @@ -222,7 +233,7 @@ inline void readBranchesData(const CollectionBranches& branches, Long64_t entry) * collections */ inline auto reconstructCollectionInfo(TTree* eventTree, podio::CollectionIDTable const& idTable) { - std::vector collInfo; + std::vector collInfo; for (size_t iColl = 0; iColl < idTable.names().size(); ++iColl) { const auto collID = idTable.ids()[iColl]; diff --git a/src/selection.xml b/src/selection.xml index 82acdc661..03686376f 100644 --- a/src/selection.xml +++ b/src/selection.xml @@ -10,7 +10,6 @@ - @@ -18,12 +17,6 @@ - - - - - - @@ -31,7 +24,6 @@ - diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index aa417badd..729248b91 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -59,7 +59,6 @@ set(root_legacy_test_versions v00-16-02 v00-16-05 v00-16-06 - v00-99 ) add_subdirectory(root_io) @@ -67,7 +66,6 @@ if (ENABLE_SIO) set(sio_legacy_test_versions v00-16-05 v00-16-06 - v00-99 ) add_subdirectory(sio_io) diff --git a/tests/input_files/v00-99-example_frame.root.md5 b/tests/input_files/v00-99-example_frame.root.md5 deleted file mode 100644 index 5b52257e6..000000000 --- a/tests/input_files/v00-99-example_frame.root.md5 +++ /dev/null @@ -1 +0,0 @@ -dbd91affe295c85c1838c40fb9da5013 diff --git a/tests/input_files/v00-99-example_frame.sio.md5 b/tests/input_files/v00-99-example_frame.sio.md5 deleted file mode 100644 index c57b2a6bb..000000000 --- a/tests/input_files/v00-99-example_frame.sio.md5 +++ /dev/null @@ -1 +0,0 @@ -ad1945557d6b5e02620294c7edac3f99 diff --git a/tests/root_io/CMakeLists.txt b/tests/root_io/CMakeLists.txt index fd9c5c0e9..6a4069a48 100644 --- a/tests/root_io/CMakeLists.txt +++ b/tests/root_io/CMakeLists.txt @@ -45,9 +45,7 @@ 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) - if (version MATCHES "^v00-16") - ADD_PODIO_LEGACY_TEST(${version} read_frame_legacy_root ${version}-example.root) - endif() + ADD_PODIO_LEGACY_TEST(${version} read_frame_legacy_root ${version}-example.root) endforeach() #--- Write via python and the ROOT backend and see if we can read it back in in diff --git a/tests/sio_io/CMakeLists.txt b/tests/sio_io/CMakeLists.txt index 7f53917fe..7102c36c7 100644 --- a/tests/sio_io/CMakeLists.txt +++ b/tests/sio_io/CMakeLists.txt @@ -33,7 +33,5 @@ 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) - if (version MATCHES "^v00-16") - ADD_PODIO_LEGACY_TEST(${version} read_frame_legacy_sio ${version}-example.sio) - endif() + ADD_PODIO_LEGACY_TEST(${version} read_frame_legacy_sio ${version}-example.sio) endforeach()