diff --git a/PhysicsTools/NanoAOD/plugins/BuildFile.xml b/PhysicsTools/NanoAOD/plugins/BuildFile.xml index bbe8818cfa63a..405928ffd7c53 100644 --- a/PhysicsTools/NanoAOD/plugins/BuildFile.xml +++ b/PhysicsTools/NanoAOD/plugins/BuildFile.xml @@ -38,9 +38,7 @@ - diff --git a/PhysicsTools/NanoAOD/plugins/rntuple/EventStringOutputFields.h b/PhysicsTools/NanoAOD/plugins/rntuple/EventStringOutputFields.h index 71e502bdd5058..5e86e89582101 100644 --- a/PhysicsTools/NanoAOD/plugins/rntuple/EventStringOutputFields.h +++ b/PhysicsTools/NanoAOD/plugins/rntuple/EventStringOutputFields.h @@ -6,7 +6,7 @@ #include "FWCore/Utilities/interface/EDGetToken.h" #include -using ROOT::Experimental::RNTupleModel; +using ROOT::RNTupleModel; #include "RNTupleFieldPtr.h" diff --git a/PhysicsTools/NanoAOD/plugins/rntuple/NanoAODRNTupleOutputModule.cc b/PhysicsTools/NanoAOD/plugins/rntuple/NanoAODRNTupleOutputModule.cc index ca293cbe9e552..26f8aca1ee25e 100644 --- a/PhysicsTools/NanoAOD/plugins/rntuple/NanoAODRNTupleOutputModule.cc +++ b/PhysicsTools/NanoAOD/plugins/rntuple/NanoAODRNTupleOutputModule.cc @@ -15,19 +15,9 @@ #include #include -#include -using ROOT::Experimental::RNTupleModel; -#if ROOT_VERSION_CODE < ROOT_VERSION(6, 31, 0) -using ROOT::Experimental::RNTupleWriter; -using ROOT::Experimental::Detail::RPageSinkFile; -#define MakeRNTupleWriter std::make_unique -#include -#else -using ROOT::Experimental::Internal::RPageSinkFile; -#define MakeRNTupleWriter ROOT::Experimental::Internal::CreateRNTupleWriter +using ROOT::RNTupleModel; #include -#endif -using ROOT::Experimental::RNTupleWriteOptions; +using ROOT::RNTupleWriteOptions; #include "TObjString.h" @@ -173,13 +163,15 @@ void NanoAODRNTupleOutputModule::openFile(edm::FileBlock const&) { const auto& keeps = keptProducts(); for (const auto& keep : keeps[edm::InRun]) { if (keep.first->className() == "nanoaod::MergeableCounterTable") { - m_run.registerToken(keep.second); + m_run.registerCounterTableToken(keep.second); } else if (keep.first->className() == "nanoaod::UniqueString" && keep.first->moduleLabel() == "nanoMetadata") { m_nanoMetadata.emplace_back(keep.first->productInstanceName(), keep.second); + } else if (keep.first->className() == "nanoaod::FlatTable") { + m_run.registerFlatTableToken(keep.second); } else { throw cms::Exception( "Configuration", - "NanoAODRNTupleOutputModule cannot handle class " + keep.first->className() + " in Run branch"); + "NanoAODRNTupleOutputModule cannot handle class " + keep.first->className() + " in Run RNTuple"); } } } @@ -210,10 +202,15 @@ void NanoAODRNTupleOutputModule::initializeNTuple(edm::EventForOutput const& iEv trigger.createFields(iEvent, *model); } m_evstrings.createFields(*model); - // TODO use Append + + // Model needs to be frozen before we bind buffers + model->Freeze(); + + m_tables.bindBuffers(*model); + RNTupleWriteOptions options; options.SetCompression(m_file->GetCompressionSettings()); - m_ntuple = MakeRNTupleWriter(std::move(model), std::make_unique("Events", *m_file, options)); + m_ntuple = RNTupleWriter::Append(std::move(model), "Events", *m_file, options); } void NanoAODRNTupleOutputModule::write(edm::EventForOutput const& iEvent) { diff --git a/PhysicsTools/NanoAOD/plugins/rntuple/NanoAODRNTuples.cc b/PhysicsTools/NanoAOD/plugins/rntuple/NanoAODRNTuples.cc index 86c367bb95898..707cee0be4215 100644 --- a/PhysicsTools/NanoAOD/plugins/rntuple/NanoAODRNTuples.cc +++ b/PhysicsTools/NanoAOD/plugins/rntuple/NanoAODRNTuples.cc @@ -3,21 +3,10 @@ #include "DataFormats/NanoAOD/interface/MergeableCounterTable.h" #include "FWCore/Framework/interface/RunForOutput.h" -#include #include -#include -using ROOT::Experimental::RNTupleModel; -#if ROOT_VERSION_CODE < ROOT_VERSION(6, 31, 0) -using ROOT::Experimental::RNTupleWriter; -using ROOT::Experimental::Detail::RPageSinkFile; -#define MakeRNTupleWriter std::make_unique -#include -#else -using ROOT::Experimental::Internal::RPageSinkFile; -#define MakeRNTupleWriter ROOT::Experimental::Internal::CreateRNTupleWriter +using ROOT::RNTupleModel; #include -#endif -using ROOT::Experimental::RNTupleWriteOptions; +using ROOT::RNTupleWriteOptions; #include "RNTupleFieldPtr.h" #include "SummaryTableOutputFields.h" @@ -26,11 +15,9 @@ void LumiNTuple::createFields(const edm::LuminosityBlockID& id, TFile& file) { auto model = RNTupleModel::Create(); m_run = RNTupleFieldPtr("run", "", *model); m_luminosityBlock = RNTupleFieldPtr("luminosityBlock", "", *model); - // TODO use Append when we bump our RNTuple version: - // m_ntuple = RNTupleWriter::Append(std::move(model), "LuminosityBlocks", file); RNTupleWriteOptions options; options.SetCompression(file.GetCompressionSettings()); - m_ntuple = MakeRNTupleWriter(std::move(model), std::make_unique("LuminosityBlocks", file, options)); + m_ntuple = RNTupleWriter::Append(std::move(model), "LuminosityBlocks", file, options); } void LumiNTuple::fill(const edm::LuminosityBlockID& id, TFile& file) { @@ -44,23 +31,31 @@ void LumiNTuple::fill(const edm::LuminosityBlockID& id, TFile& file) { void LumiNTuple::finalizeWrite() { m_ntuple.reset(); } -void RunNTuple::registerToken(const edm::EDGetToken& token) { m_tokens.push_back(token); } +void RunNTuple::registerCounterTableToken(const edm::EDGetToken& token) { m_counterTableTokens.push_back(token); } + +void RunNTuple::registerFlatTableToken(const edm::EDGetToken& token) { m_flatTableTokens.push_back(token); } void RunNTuple::createFields(const edm::RunForOutput& iRun, TFile& file) { auto model = RNTupleModel::Create(); m_run = RNTupleFieldPtr("run", "", *model); - edm::Handle handle; - for (const auto& token : m_tokens) { - iRun.getByToken(token, handle); - const nanoaod::MergeableCounterTable& tab = *handle; - m_tables.push_back(SummaryTableOutputFields(tab, *model)); + edm::Handle counterTableHandle; + for (const auto& token : m_counterTableTokens) { + iRun.getByToken(token, counterTableHandle); + const nanoaod::MergeableCounterTable& tab = *counterTableHandle; + m_counterTables.push_back(SummaryTableOutputFields(tab, *model)); + } + + edm::Handle flatTableHandle; + for (const auto& token : m_flatTableTokens) { + iRun.getByToken(token, flatTableHandle); + m_flatTables.add(token, *flatTableHandle); } + m_flatTables.createFields(iRun, *model); - // TODO use Append when we bump our RNTuple version RNTupleWriteOptions options; options.SetCompression(file.GetCompressionSettings()); - m_ntuple = MakeRNTupleWriter(std::move(model), std::make_unique("Runs", file, options)); + m_ntuple = RNTupleWriter::Append(std::move(model), "Runs", file, options); } void RunNTuple::fill(const edm::RunForOutput& iRun, TFile& file) { @@ -68,29 +63,28 @@ void RunNTuple::fill(const edm::RunForOutput& iRun, TFile& file) { createFields(iRun, file); } m_run.fill(iRun.id().run()); - edm::Handle handle; - for (std::size_t i = 0; i < m_tokens.size(); i++) { - iRun.getByToken(m_tokens.at(i), handle); - const nanoaod::MergeableCounterTable& tab = *handle; - m_tables.at(i).fill(tab); + + edm::Handle counterTableHandle; + for (std::size_t i = 0; i < m_counterTableTokens.size(); i++) { + iRun.getByToken(m_counterTableTokens.at(i), counterTableHandle); + const nanoaod::MergeableCounterTable& tab = *counterTableHandle; + m_counterTables.at(i).fill(tab); } + + m_flatTables.fill(iRun); + m_ntuple->Fill(); } void RunNTuple::finalizeWrite() { m_ntuple.reset(); } void PSetNTuple::createFields(TFile& file) { - // use a collection to emulate std::pair - auto pairModel = RNTupleModel::Create(); - m_psetId = RNTupleFieldPtr("first", "", *pairModel); - m_psetBlob = RNTupleFieldPtr("second", "", *pairModel); auto model = RNTupleModel::Create(); - m_collection = model->MakeCollection(edm::poolNames::idToParameterSetBlobsBranchName(), std::move(pairModel)); - // TODO use Append when we bump our RNTuple version + m_pset = RNTupleFieldPtr(edm::poolNames::idToParameterSetBlobsBranchName(), "", *model); + RNTupleWriteOptions options; options.SetCompression(file.GetCompressionSettings()); - m_ntuple = MakeRNTupleWriter(std::move(model), - std::make_unique(edm::poolNames::parameterSetsTreeName(), file, options)); + m_ntuple = RNTupleWriter::Append(std::move(model), edm::poolNames::parameterSetsTreeName(), file, options); } void PSetNTuple::fill(edm::pset::Registry* pset, TFile& file) { @@ -101,28 +95,22 @@ void PSetNTuple::fill(edm::pset::Registry* pset, TFile& file) { createFields(file); } for (const auto& ps : *pset) { - std::ostringstream oss; - oss << ps.first; - m_psetId.fill(oss.str()); - m_psetBlob.fill(ps.second.toString()); - m_collection->Fill(); + std::string psString; + ps.second.toString(psString); + edm::ParameterSetBlob psBlob(psString); + m_pset.fill(std::make_pair(ps.first, psBlob)); m_ntuple->Fill(); } } void PSetNTuple::finalizeWrite() { m_ntuple.reset(); } -// TODO blocked on RNTuple typedef member field support void MetadataNTuple::createFields(TFile& file) { - auto procHistModel = RNTupleModel::Create(); - // ProcessHistory.transients_.phid_ replacement - m_phId = RNTupleFieldPtr("transients_phid_", "", *procHistModel); auto model = RNTupleModel::Create(); - m_procHist = model->MakeCollection(edm::poolNames::processHistoryBranchName(), std::move(procHistModel)); + m_procHist = RNTupleFieldPtr(edm::poolNames::processHistoryBranchName(), "", *model); RNTupleWriteOptions options; options.SetCompression(file.GetCompressionSettings()); - m_ntuple = MakeRNTupleWriter(std::move(model), - std::make_unique(edm::poolNames::metaDataTreeName(), file, options)); + m_ntuple = RNTupleWriter::Append(std::move(model), edm::poolNames::metaDataTreeName(), file, options); } void MetadataNTuple::fill(const edm::ProcessHistoryRegistry& procHist, TFile& file) { @@ -130,12 +118,9 @@ void MetadataNTuple::fill(const edm::ProcessHistoryRegistry& procHist, TFile& fi createFields(file); } for (const auto& ph : procHist) { - std::string phid; - ph.second.id().toString(phid); - m_phId.fill(phid); - m_procHist->Fill(); + m_procHist.fill(ph.second); + m_ntuple->Fill(); } - m_ntuple->Fill(); } void MetadataNTuple::finalizeWrite() { m_ntuple.reset(); } diff --git a/PhysicsTools/NanoAOD/plugins/rntuple/NanoAODRNTuples.h b/PhysicsTools/NanoAOD/plugins/rntuple/NanoAODRNTuples.h index 65843adafe94c..80f8251c26cb6 100644 --- a/PhysicsTools/NanoAOD/plugins/rntuple/NanoAODRNTuples.h +++ b/PhysicsTools/NanoAOD/plugins/rntuple/NanoAODRNTuples.h @@ -12,14 +12,8 @@ #include "TFile.h" #include -#if ROOT_VERSION_CODE < ROOT_VERSION(6, 31, 0) -using ROOT::Experimental::RCollectionNTupleWriter; -#else #include -#include -using ROOT::Experimental::RNTupleCollectionWriter; -#endif -using ROOT::Experimental::RNTupleWriter; +using ROOT::RNTupleWriter; #include "EventStringOutputFields.h" #include "RNTupleFieldPtr.h" @@ -43,16 +37,19 @@ class LumiNTuple { class RunNTuple { public: RunNTuple() = default; - void registerToken(const edm::EDGetToken& token); + void registerCounterTableToken(const edm::EDGetToken& token); + void registerFlatTableToken(const edm::EDGetToken& token); void fill(const edm::RunForOutput& iRun, TFile& file); void finalizeWrite(); private: void createFields(const edm::RunForOutput& iRun, TFile& file); - std::vector m_tokens; + std::vector m_counterTableTokens; + std::vector m_flatTableTokens; std::unique_ptr m_ntuple; RNTupleFieldPtr m_run; - std::vector m_tables; + std::vector m_counterTables; + TableCollectionSet m_flatTables; }; class PSetNTuple { @@ -62,21 +59,9 @@ class PSetNTuple { void finalizeWrite(); private: - // TODO blocked on RNTuple std::pair support - // using PSetType = std::pair; - // RNTupleFieldPtr m_pset; + using PSetType = std::pair; + RNTupleFieldPtr m_pset; void createFields(TFile& file); - // TODO blocked on RNTuple typedef member field support: - // https://github.com/root-project/root/issues/7861 - // RNTupleFieldPtr m_psetId; - // RNTupleFieldPtr m_psetBlob; -#if ROOT_VERSION_CODE < ROOT_VERSION(6, 31, 0) - std::shared_ptr m_collection; -#else - std::shared_ptr m_collection; -#endif - RNTupleFieldPtr m_psetId; - RNTupleFieldPtr m_psetBlob; std::unique_ptr m_ntuple; }; @@ -88,13 +73,7 @@ class MetadataNTuple { private: void createFields(TFile& file); -#if ROOT_VERSION_CODE < ROOT_VERSION(6, 31, 0) - std::shared_ptr m_procHist; -#else - std::shared_ptr m_procHist; -#endif - - RNTupleFieldPtr m_phId; + RNTupleFieldPtr m_procHist; std::unique_ptr m_ntuple; }; diff --git a/PhysicsTools/NanoAOD/plugins/rntuple/RNTupleCollection.cc b/PhysicsTools/NanoAOD/plugins/rntuple/RNTupleCollection.cc new file mode 100644 index 0000000000000..d9e8ca6ad968d --- /dev/null +++ b/PhysicsTools/NanoAOD/plugins/rntuple/RNTupleCollection.cc @@ -0,0 +1,128 @@ +#include "RNTupleCollection.h" + +#include +#include +#include + +using ROOT::REntry; +using ROOT::RFieldBase; +using ROOT::RNTupleModel; +using ROOT::RRecordField; +using ROOT::RVectorField; + +std::string flatTableColumnTypeToString(nanoaod::FlatTable::ColumnType type) { + switch (type) { + case nanoaod::FlatTable::ColumnType::UInt8: + return "std::uint8_t"; + case nanoaod::FlatTable::ColumnType::Int16: + return "std::int16_t"; + case nanoaod::FlatTable::ColumnType::UInt16: + return "std::uint16_t"; + case nanoaod::FlatTable::ColumnType::Int32: + return "std::int32_t"; + case nanoaod::FlatTable::ColumnType::UInt32: + return "std::uint32_t"; + case nanoaod::FlatTable::ColumnType::Int64: + return "std::int64_t"; + case nanoaod::FlatTable::ColumnType::UInt64: + return "std::uint64_t"; + case nanoaod::FlatTable::ColumnType::Bool: + return "bool"; + case nanoaod::FlatTable::ColumnType::Float: + return "float"; + case nanoaod::FlatTable::ColumnType::Double: + return "double"; + default: + throw cms::Exception("LogicError", "Unsupported type"); + } +} + +std::tuple getColStartAndTypeSize(edm::Handle& table, + unsigned int colIdx) { + const unsigned char* col_start; + switch (table->columnType(colIdx)) { + case nanoaod::FlatTable::ColumnType::UInt8: + col_start = reinterpret_cast(table->columnData(colIdx).data()); + return std::make_tuple(col_start, 1); + case nanoaod::FlatTable::ColumnType::Int16: + col_start = reinterpret_cast(table->columnData(colIdx).data()); + return std::make_tuple(col_start, 2); + case nanoaod::FlatTable::ColumnType::UInt16: + col_start = reinterpret_cast(table->columnData(colIdx).data()); + return std::make_tuple(col_start, 2); + case nanoaod::FlatTable::ColumnType::Int32: + col_start = reinterpret_cast(table->columnData(colIdx).data()); + return std::make_tuple(col_start, 4); + case nanoaod::FlatTable::ColumnType::UInt32: + col_start = reinterpret_cast(table->columnData(colIdx).data()); + return std::make_tuple(col_start, 4); + case nanoaod::FlatTable::ColumnType::Int64: + col_start = reinterpret_cast(table->columnData(colIdx).data()); + return std::make_tuple(col_start, 8); + case nanoaod::FlatTable::ColumnType::UInt64: + col_start = reinterpret_cast(table->columnData(colIdx).data()); + return std::make_tuple(col_start, 8); + case nanoaod::FlatTable::ColumnType::Bool: + col_start = reinterpret_cast(table->columnData(colIdx).data()); + return std::make_tuple(col_start, 1); + case nanoaod::FlatTable::ColumnType::Float: + col_start = reinterpret_cast(table->columnData(colIdx).data()); + return std::make_tuple(col_start, 4); + case nanoaod::FlatTable::ColumnType::Double: + col_start = reinterpret_cast(table->columnData(colIdx).data()); + return std::make_tuple(col_start, 8); + default: + throw cms::Exception("LogicError", "Unsupported type"); + } +} + +RNTupleCollection::RNTupleCollection(const std::string& name, + const std::string& desc, + std::vector>& tables, + RNTupleModel& model) + : m_name(name) { + std::vector> subfields; + for (auto& table : tables) { + for (unsigned int i = 0; i < table->nColumns(); i++) { + std::string type = flatTableColumnTypeToString(table->columnType(i)); + auto field = RFieldBase::Create(table->columnName(i), type).Unwrap(); + field->SetDescription(table->columnDoc(i)); + subfields.push_back(std::move(field)); + } + } + auto record_field = std::make_unique("_0", std::move(subfields)); + m_record_size = record_field->GetValueSize(); + m_record_offsets = record_field->GetOffsets(); + auto collection_field = RVectorField::CreateUntyped(name, std::move(record_field)); + collection_field->SetDescription(desc); + model.AddField(std::move(collection_field)); +} + +void RNTupleCollection::bindBuffer(RNTupleModel& model) { + auto& default_entry = model.GetDefaultEntry(); + default_entry.BindRawPtr(m_name, &m_buffer); +} + +void RNTupleCollection::fill(std::vector>& tables) { + unsigned int col_idx = 0; + size_t col_size = tables.empty() ? 0 : tables[0]->size(); + + m_buffer.resize(m_record_size * col_size); + + for (auto& table : tables) { + if (table->size() != col_size) { + throw cms::Exception("LogicError", + "Mismatch in number of entries between extension and main table for " + m_name); + } + for (unsigned int i = 0; i < table->nColumns(); i++) { + auto [col_start, type_size] = getColStartAndTypeSize(table, i); + size_t col_offset = m_record_offsets[col_idx]; + + for (unsigned int j = 0; j < col_size; j++) { + std::memcpy(m_buffer.data() + (j * m_record_size) + col_offset, col_start + (j * type_size), type_size); + } + + col_idx++; + } + } +} diff --git a/PhysicsTools/NanoAOD/plugins/rntuple/RNTupleCollection.h b/PhysicsTools/NanoAOD/plugins/rntuple/RNTupleCollection.h new file mode 100644 index 0000000000000..e566fa8fa43be --- /dev/null +++ b/PhysicsTools/NanoAOD/plugins/rntuple/RNTupleCollection.h @@ -0,0 +1,30 @@ +#ifndef PhysicsTools_NanoAOD_RNTupleCollection_h +#define PhysicsTools_NanoAOD_RNTupleCollection_h + +#include "DataFormats/NanoAOD/interface/FlatTable.h" +#include "DataFormats/Common/interface/Handle.h" + +#include +#include + +class RNTupleCollection { +public: + RNTupleCollection() = delete; + RNTupleCollection(const std::string& name, + const std::string& desc, + std::vector>& tables, + ROOT::RNTupleModel& model); + + const std::string& getFieldName() const { return m_name; } + + void bindBuffer(ROOT::RNTupleModel& model); + void fill(std::vector>& tables); + +private: + std::string m_name; + std::size_t m_record_size; + std::vector m_record_offsets; + std::vector m_buffer; +}; + +#endif diff --git a/PhysicsTools/NanoAOD/plugins/rntuple/RNTupleFieldPtr.h b/PhysicsTools/NanoAOD/plugins/rntuple/RNTupleFieldPtr.h index ecb303a52c729..a49644e2419b0 100644 --- a/PhysicsTools/NanoAOD/plugins/rntuple/RNTupleFieldPtr.h +++ b/PhysicsTools/NanoAOD/plugins/rntuple/RNTupleFieldPtr.h @@ -2,14 +2,14 @@ #define PhysicsTools_NanoAOD_RNTupleFieldPtr_h #include -using ROOT::Experimental::RNTupleModel; +#include template class RNTupleFieldPtr { public: RNTupleFieldPtr() = default; - explicit RNTupleFieldPtr(const std::string& name, const std::string& desc, RNTupleModel& model) : m_name(name) { - m_field = model.MakeField({m_name, desc}); + explicit RNTupleFieldPtr(const std::string& name, const std::string& desc, ROOT::RNTupleModel& model) : m_name(name) { + m_field = model.MakeField(m_name, desc); } void fill(const T& value) { *m_field = value; } const std::string& getFieldName() const { return m_name; } diff --git a/PhysicsTools/NanoAOD/plugins/rntuple/SummaryTableOutputFields.cc b/PhysicsTools/NanoAOD/plugins/rntuple/SummaryTableOutputFields.cc index 878bf039c3597..6f2b57b5c38db 100644 --- a/PhysicsTools/NanoAOD/plugins/rntuple/SummaryTableOutputFields.cc +++ b/PhysicsTools/NanoAOD/plugins/rntuple/SummaryTableOutputFields.cc @@ -1,12 +1,13 @@ #include "SummaryTableOutputFields.h" +using ROOT::RNTupleModel; + template std::vector> SummaryTableOutputFields::makeFields(const std::vector &tabcols, RNTupleModel &model) { std::vector> fields; fields.reserve(tabcols.size()); for (const auto &col : tabcols) { - // TODO field description fields.emplace_back(RNTupleFieldPtr(col.name, col.doc, model)); } return fields; @@ -26,6 +27,7 @@ void SummaryTableOutputFields::fillScalarFields(const std::vector &tabcols, } } +// TODO: maybe we can unify with the function above since now it's the same template void SummaryTableOutputFields::fillVectorFields(const std::vector &tabcols, std::vector> fields) { @@ -36,22 +38,17 @@ void SummaryTableOutputFields::fillVectorFields(const std::vector &tabcols, if (tabcols[i].name != fields[i].getFieldName()) { throw cms::Exception("LogicError", "Mismatch in table columns"); } - auto data = tabcols[i].values; - // TODO remove this awful hack when std::int64_t is supported - // -- turns std::vector into std::vector - T casted_data(data.begin(), data.end()); - fields[i].fill(casted_data); + fields[i].fill(tabcols[i].values); } } SummaryTableOutputFields::SummaryTableOutputFields(const nanoaod::MergeableCounterTable &tab, RNTupleModel &model) { - // TODO use std::int64_t when supported - m_intFields = makeFields(tab.intCols(), model); - m_floatFields = makeFields(tab.floatCols(), model); - m_floatWithNormFields = makeFields(tab.floatWithNormCols(), model); - m_vintFields = makeFields>(tab.vintCols(), model); - m_vfloatFields = makeFields>(tab.vfloatCols(), model); - m_vfloatWithNormFields = makeFields>(tab.vfloatWithNormCols(), model); + m_intFields = makeFields(tab.intCols(), model); + m_floatFields = makeFields(tab.floatCols(), model); + m_floatWithNormFields = makeFields(tab.floatWithNormCols(), model); + m_vintFields = makeFields>(tab.vintCols(), model); + m_vfloatFields = makeFields>(tab.vfloatCols(), model); + m_vfloatWithNormFields = makeFields>(tab.vfloatWithNormCols(), model); } void SummaryTableOutputFields::fill(const nanoaod::MergeableCounterTable &tab) { diff --git a/PhysicsTools/NanoAOD/plugins/rntuple/SummaryTableOutputFields.h b/PhysicsTools/NanoAOD/plugins/rntuple/SummaryTableOutputFields.h index 51e6fd52d45c5..8c267b7aa460e 100644 --- a/PhysicsTools/NanoAOD/plugins/rntuple/SummaryTableOutputFields.h +++ b/PhysicsTools/NanoAOD/plugins/rntuple/SummaryTableOutputFields.h @@ -8,23 +8,26 @@ class SummaryTableOutputFields { public: SummaryTableOutputFields() = default; - SummaryTableOutputFields(const nanoaod::MergeableCounterTable &tab, RNTupleModel &model); + SummaryTableOutputFields(const nanoaod::MergeableCounterTable &tab, ROOT::RNTupleModel &model); void fill(const nanoaod::MergeableCounterTable &tab); private: template - std::vector> makeFields(const std::vector &tabcols, RNTupleModel &model); + std::vector> makeFields(const std::vector &tabcols, ROOT::RNTupleModel &model); template static void fillScalarFields(const std::vector &tabcols, std::vector> fields); template static void fillVectorFields(const std::vector &tabcols, std::vector> fields); - std::vector> m_intFields; - std::vector> m_floatFields; - std::vector> m_floatWithNormFields; - std::vector>> m_vfloatFields; - std::vector>> m_vfloatWithNormFields; - std::vector>> m_vintFields; + using int_accumulator = nanoaod::MergeableCounterTable::int_accumulator; + using float_accumulator = nanoaod::MergeableCounterTable::float_accumulator; + + std::vector> m_intFields; + std::vector> m_floatFields; + std::vector> m_floatWithNormFields; + std::vector>> m_vfloatFields; + std::vector>> m_vfloatWithNormFields; + std::vector>> m_vintFields; }; #endif diff --git a/PhysicsTools/NanoAOD/plugins/rntuple/TableOutputFields.cc b/PhysicsTools/NanoAOD/plugins/rntuple/TableOutputFields.cc index eef3bf0f99a96..27ddded769bb4 100644 --- a/PhysicsTools/NanoAOD/plugins/rntuple/TableOutputFields.cc +++ b/PhysicsTools/NanoAOD/plugins/rntuple/TableOutputFields.cc @@ -24,7 +24,9 @@ namespace { std::cout << "bool,"; break; default: - throw cms::Exception("LogicError", "Unsupported type"); + std::cout << "other,"; + break; + //throw cms::Exception("LogicError", "Unsupported type"); } std::cout << "\n"; } @@ -47,7 +49,7 @@ void TableOutputFields::print() const { } } -void TableOutputFields::createFields(const edm::EventForOutput& event, RNTupleModel& model) { +void TableOutputFields::createFields(const edm::OccurrenceForOutput& event, RNTupleModel& model) { edm::Handle handle; event.getByToken(m_token, handle); const nanoaod::FlatTable& table = *handle; @@ -66,7 +68,9 @@ void TableOutputFields::createFields(const edm::EventForOutput& event, RNTupleMo m_boolFields.emplace_back(FlatTableField(table, i, model)); break; default: - throw cms::Exception("LogicError", "Unsupported type"); + std::cout << "Unsupported type in TableOutputFields" + << "\n"; + //throw cms::Exception("LogicError", "Unsupported type"); } } } @@ -88,9 +92,15 @@ void TableOutputFields::fillEntry(const nanoaod::FlatTable& table, std::size_t i const edm::EDGetToken& TableOutputFields::getToken() const { return m_token; } +const edm::Handle TableOutputFields::getTable(const edm::OccurrenceForOutput& event) const { + edm::Handle handle; + event.getByToken(m_token, handle); + return handle; +} + /////////////////////////////////////////////////////////////////////////////// -void TableOutputVectorFields::createFields(const edm::EventForOutput& event, RNTupleModel& model) { +void TableOutputVectorFields::createFields(const edm::OccurrenceForOutput& event, RNTupleModel& model) { edm::Handle handle; event.getByToken(m_token, handle); const nanoaod::FlatTable& table = *handle; @@ -109,11 +119,13 @@ void TableOutputVectorFields::createFields(const edm::EventForOutput& event, RNT m_vboolFields.emplace_back(FlatTableField>(table, i, model)); break; default: - throw cms::Exception("LogicError", "Unsupported type"); + std::cout << "Unsupported type in TableOutputVectorFields" + << "\n"; + //throw cms::Exception("LogicError", "Unsupported type"); } } } -void TableOutputVectorFields::fill(const edm::EventForOutput& event) { +void TableOutputVectorFields::fill(const edm::OccurrenceForOutput& event) { edm::Handle handle; event.getByToken(m_token, handle); const auto& table = *handle; @@ -147,38 +159,37 @@ void TableCollection::add(const edm::EDGetToken& table_token, const nanoaod::Fla m_main = TableOutputFields(table_token); } -void TableCollection::createFields(const edm::EventForOutput& event, RNTupleModel& eventModel) { - auto collectionModel = RNTupleModel::Create(); - m_main.createFields(event, *collectionModel); +void TableCollection::createFields(const edm::OccurrenceForOutput& event, RNTupleModel& eventModel) { + std::vector> tables; + + auto main_table = m_main.getTable(event); + std::string field_desc = main_table->doc(); + + tables.emplace_back(main_table); + for (auto& extension : m_extensions) { - extension.createFields(event, *collectionModel); + auto ext_table = extension.getTable(event); + tables.emplace_back(ext_table); } - edm::Handle handle; - event.getByToken(m_main.getToken(), handle); - const nanoaod::FlatTable& table = *handle; - collectionModel->SetDescription(table.doc()); - m_collection = eventModel.MakeCollection(m_collectionName, std::move(collectionModel)); + m_collection = std::make_unique(m_collectionName, field_desc, tables, eventModel); } -void TableCollection::fill(const edm::EventForOutput& event) { - edm::Handle handle; - event.getByToken(m_main.getToken(), handle); - const auto& main_table = *handle; - auto table_size = main_table.size(); - for (std::size_t i = 0; i < table_size; i++) { - m_main.fillEntry(main_table, i); - for (auto& ext : m_extensions) { - edm::Handle handle; - event.getByToken(ext.getToken(), handle); - const auto& ext_table = *handle; - if (ext_table.size() != table_size) { - throw cms::Exception("LogicError", - "Mismatch in number of entries between extension and main table for " + m_collectionName); - } - ext.fillEntry(ext_table, i); - } - m_collection->Fill(); +void TableCollection::bindBuffer(RNTupleModel& eventModel) { m_collection->bindBuffer(eventModel); } + +void TableCollection::fill(const edm::OccurrenceForOutput& event) { + std::vector> tables; + + auto main_table = m_main.getTable(event); + std::string field_desc = main_table->doc(); + + tables.emplace_back(main_table); + + for (auto& extension : m_extensions) { + auto ext_table = extension.getTable(event); + tables.emplace_back(ext_table); } + + m_collection->fill(tables); } void TableCollection::print() const { @@ -237,7 +248,7 @@ void TableCollectionSet::print() const { } } -void TableCollectionSet::createFields(const edm::EventForOutput& event, RNTupleModel& eventModel) { +void TableCollectionSet::createFields(const edm::OccurrenceForOutput& event, RNTupleModel& eventModel) { for (auto& collection : m_collections) { if (!collection.hasMainTable()) { throw cms::Exception("LogicError", @@ -254,7 +265,13 @@ void TableCollectionSet::createFields(const edm::EventForOutput& event, RNTupleM } } -void TableCollectionSet::fill(const edm::EventForOutput& event) { +void TableCollectionSet::bindBuffers(RNTupleModel& eventModel) { + for (auto& collection : m_collections) { + collection.bindBuffer(eventModel); + } +} + +void TableCollectionSet::fill(const edm::OccurrenceForOutput& event) { for (auto& collection : m_collections) { collection.fill(event); } diff --git a/PhysicsTools/NanoAOD/plugins/rntuple/TableOutputFields.h b/PhysicsTools/NanoAOD/plugins/rntuple/TableOutputFields.h index 457e00991ff2d..00e9be2e833e3 100644 --- a/PhysicsTools/NanoAOD/plugins/rntuple/TableOutputFields.h +++ b/PhysicsTools/NanoAOD/plugins/rntuple/TableOutputFields.h @@ -2,8 +2,9 @@ #define PhysicsTools_NanoAOD_TableOutputFields_h #include "RNTupleFieldPtr.h" +#include "RNTupleCollection.h" -#include "FWCore/Framework/interface/EventForOutput.h" +#include "FWCore/Framework/interface/OccurrenceForOutput.h" #include "DataFormats/NanoAOD/interface/FlatTable.h" #include "FWCore/Utilities/interface/EDGetToken.h" @@ -11,14 +12,8 @@ #include #include -#if ROOT_VERSION_CODE < ROOT_VERSION(6, 31, 0) -using ROOT::Experimental::RCollectionNTupleWriter; -#else -#include -using ROOT::Experimental::RNTupleCollectionWriter; -#endif -using ROOT::Experimental::RNTupleModel; -using ROOT::Experimental::RNTupleWriter; +using ROOT::RNTupleModel; +using ROOT::RNTupleWriter; template class FlatTableField { @@ -70,9 +65,10 @@ class TableOutputFields { TableOutputFields() = default; explicit TableOutputFields(const edm::EDGetToken& token) : m_token(token) {} void print() const; - void createFields(const edm::EventForOutput& event, RNTupleModel& model); + void createFields(const edm::OccurrenceForOutput& event, RNTupleModel& model); void fillEntry(const nanoaod::FlatTable& table, std::size_t i); const edm::EDGetToken& getToken() const; + const edm::Handle getTable(const edm::OccurrenceForOutput& event) const; private: edm::EDGetToken m_token; @@ -86,8 +82,8 @@ class TableOutputVectorFields { public: TableOutputVectorFields() = default; explicit TableOutputVectorFields(const edm::EDGetToken& token) : m_token(token) {} - void createFields(const edm::EventForOutput& event, RNTupleModel& model); - void fill(const edm::EventForOutput& event); + void createFields(const edm::OccurrenceForOutput& event, RNTupleModel& model); + void fill(const edm::OccurrenceForOutput& event); private: edm::EDGetToken m_token; @@ -107,19 +103,16 @@ class TableCollection { // Invariants: // * m_main not null // * m_collectionName not empty - void createFields(const edm::EventForOutput& event, RNTupleModel& eventModel); - void fill(const edm::EventForOutput& event); + void createFields(const edm::OccurrenceForOutput& event, RNTupleModel& eventModel); + void bindBuffer(RNTupleModel& eventModel); + void fill(const edm::OccurrenceForOutput& event); void print() const; bool hasMainTable(); const std::string& getCollectionName() const; private: std::string m_collectionName; -#if ROOT_VERSION_CODE < ROOT_VERSION(6, 31, 0) - std::shared_ptr m_collection; -#else - std::shared_ptr m_collection; -#endif + std::unique_ptr m_collection; TableOutputFields m_main; std::vector m_extensions; }; @@ -127,8 +120,9 @@ class TableCollection { class TableCollectionSet { public: void add(const edm::EDGetToken& table_token, const nanoaod::FlatTable& table); - void createFields(const edm::EventForOutput& event, RNTupleModel& eventModel); - void fill(const edm::EventForOutput& event); + void createFields(const edm::OccurrenceForOutput& event, RNTupleModel& eventModel); + void bindBuffers(RNTupleModel& eventModel); + void fill(const edm::OccurrenceForOutput& event); void print() const; private: diff --git a/PhysicsTools/NanoAOD/plugins/rntuple/TriggerOutputFields.cc b/PhysicsTools/NanoAOD/plugins/rntuple/TriggerOutputFields.cc index e1fa1161bf8be..db752038c07e2 100644 --- a/PhysicsTools/NanoAOD/plugins/rntuple/TriggerOutputFields.cc +++ b/PhysicsTools/NanoAOD/plugins/rntuple/TriggerOutputFields.cc @@ -13,6 +13,8 @@ #include +using ROOT::RNTupleModel; + namespace { void trimVersionSuffix(std::string& trigger_name) { @@ -121,19 +123,14 @@ void TriggerOutputFields::updateTriggerFields(const edm::TriggerResults& trigger } } -void TriggerOutputFields::makeUniqueFieldName(RNTupleModel& model, std::string& name) { - // Could also use a cache of names in a higher-level object, don't ask the RNTupleModel each time -#if ROOT_VERSION_CODE < ROOT_VERSION(6, 31, 0) - auto existing_field = model.Get(name); -#else - auto existing_field = model.GetDefaultEntry().GetPtr(name); -#endif - if (!existing_field) { +void TriggerOutputFields::makeUniqueFieldName(const RNTupleModel& model, std::string& name) { + bool already_exists = model.GetFieldNames().contains(name); + + if (!already_exists) { return; } - edm::LogWarning("TriggerOutputFields") << "Found a branch with name " << name - << " already present. Will add suffix _p" << m_processName - << " to the new branch.\n"; + edm::LogWarning("TriggerOutputFields") << "Found a field with name " << name << " already present. Will add suffix _p" + << m_processName << " to the new field.\n"; name += std::string("_p") + m_processName; } diff --git a/PhysicsTools/NanoAOD/plugins/rntuple/TriggerOutputFields.h b/PhysicsTools/NanoAOD/plugins/rntuple/TriggerOutputFields.h index 592cc51caceb2..3ff026de54d9d 100644 --- a/PhysicsTools/NanoAOD/plugins/rntuple/TriggerOutputFields.h +++ b/PhysicsTools/NanoAOD/plugins/rntuple/TriggerOutputFields.h @@ -13,7 +13,7 @@ namespace edm { class TriggerFieldPtr { public: TriggerFieldPtr() = default; - TriggerFieldPtr(std::string name, int index, std::string fieldName, std::string fieldDesc, RNTupleModel& model); + TriggerFieldPtr(std::string name, int index, std::string fieldName, std::string fieldDesc, ROOT::RNTupleModel& model); void fill(const edm::TriggerResults& triggers); const std::string& getTriggerName() const { return m_triggerName; } void setIndex(int newIndex) { m_triggerIndex = newIndex; } @@ -30,14 +30,14 @@ class TriggerOutputFields { TriggerOutputFields() = default; explicit TriggerOutputFields(const std::string& processName, const edm::EDGetToken& token) : m_token(token), m_lastRun(-1), m_processName(processName) {} - void createFields(const edm::EventForOutput& event, RNTupleModel& model); + void createFields(const edm::EventForOutput& event, ROOT::RNTupleModel& model); void fill(const edm::EventForOutput& event); private: static std::vector getTriggerNames(const edm::TriggerResults& triggerResults); // Update trigger field information on run boundaries void updateTriggerFields(const edm::TriggerResults& triggerResults); - void makeUniqueFieldName(/*const*/ RNTupleModel& model, std::string& name); + void makeUniqueFieldName(const ROOT::RNTupleModel& model, std::string& name); edm::EDGetToken m_token; long m_lastRun;