CMS 3D CMS Logo

NanoAODRNTupleOutputModule.cc
Go to the documentation of this file.
1 // -*- C++ -*-
2 //
3 // Package: PhysicsTools/NanoAODOutput
4 // Class : NanoAODRNTupleOutputModule
5 //
6 // Implementation:
7 // [Notes on implementation]
8 //
9 // Original Author: Max Orok
10 // Created: Wed, 13 Jan 2021 14:21:41 GMT
11 //
12 
13 #include <cstdint>
14 #include <string>
15 
16 #include <ROOT/RNTuple.hxx>
17 #include <ROOT/RNTupleModel.hxx>
18 #include <ROOT/RPageStorageFile.hxx>
19 using ROOT::Experimental::RNTupleModel;
20 #if ROOT_VERSION_CODE < ROOT_VERSION(6, 31, 0)
21 using ROOT::Experimental::RNTupleWriter;
22 using ROOT::Experimental::Detail::RPageSinkFile;
23 #define MakeRNTupleWriter std::make_unique<RNTupleWriter>
24 #include <ROOT/RNTupleOptions.hxx>
25 #else
26 using ROOT::Experimental::Internal::RPageSinkFile;
27 #define MakeRNTupleWriter ROOT::Experimental::Internal::CreateRNTupleWriter
28 #include <ROOT/RNTupleWriteOptions.hxx>
29 #endif
30 using ROOT::Experimental::RNTupleWriteOptions;
31 
32 #include "TObjString.h"
33 
46 
47 #include "NanoAODRNTuples.h"
48 
50 public:
52  ~NanoAODRNTupleOutputModule() override;
53 
54  static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
55 
56 private:
57  void openFile(edm::FileBlock const&) override;
58  bool isFileOpen() const override;
59  void write(edm::EventForOutput const& e) override;
61  void writeRun(edm::RunForOutput const&) override;
62  void reallyCloseFile() override;
63  void writeProvenance();
64 
66 
74 
75  std::unique_ptr<TFile> m_file;
76  std::unique_ptr<RNTupleWriter> m_ntuple;
78  std::vector<TriggerOutputFields> m_triggers;
80 
82  public:
83  void createFields(RNTupleModel& model) {
84  m_run = model.MakeField<UInt_t>("run");
85  m_luminosityBlock = model.MakeField<UInt_t>("luminosityBlock");
86  m_event = model.MakeField<std::uint64_t>("event");
87  }
88  void fill(const edm::EventID& id) {
89  *m_run = id.run();
90  *m_luminosityBlock = id.luminosityBlock();
91  *m_event = id.event();
92  }
93 
94  private:
95  std::shared_ptr<UInt_t> m_run;
96  std::shared_ptr<UInt_t> m_luminosityBlock;
97  std::shared_ptr<std::uint64_t> m_event;
99 
102 
103  std::vector<std::pair<std::string, edm::EDGetToken>> m_nanoMetadata;
104 };
105 
108  edm::one::OutputModule<>(pset),
109  m_fileName(pset.getUntrackedParameter<std::string>("fileName")),
110  m_logicalFileName(pset.getUntrackedParameter<std::string>("logicalFileName")),
111  m_compressionAlgorithm(pset.getUntrackedParameter<std::string>("compressionAlgorithm")),
112  m_compressionLevel(pset.getUntrackedParameter<int>("compressionLevel")),
113  m_writeProvenance(pset.getUntrackedParameter<bool>("saveProvenance", true)),
114  m_processHistoryRegistry() {}
115 
117 
120  jr->reportLumiSection(m_jrToken, iLumi.id().run(), iLumi.id().value());
121  m_lumi.fill(iLumi.id(), *m_file);
123 }
124 
127  jr->reportRunNumber(m_jrToken, iRun.id().run());
128 
129  m_run.fill(iRun, *m_file);
130 
132  for (const auto& p : m_nanoMetadata) {
133  iRun.getByToken(p.second, hstring);
134  TObjString* tos = dynamic_cast<TObjString*>(m_file->Get(p.first.c_str()));
135  if (tos && hstring->str() != tos->GetString()) {
136  throw cms::Exception("LogicError", "Inconsistent nanoMetadata " + p.first + " (" + hstring->str() + ")");
137  } else {
138  auto ostr = std::make_unique<TObjString>(hstring->str().c_str());
139  m_file->WriteTObject(ostr.release(), p.first.c_str());
140  }
141  }
143 }
144 
145 bool NanoAODRNTupleOutputModule::isFileOpen() const { return nullptr != m_ntuple.get(); }
146 
148  m_file = std::make_unique<TFile>(m_fileName.c_str(), "RECREATE", "", m_compressionLevel);
150  cms::Digest branchHash;
151  m_jrToken = jr->outputFileOpened(m_fileName,
153  std::string(),
154  // TODO check if needed
155  //m_fakeName ? "PoolOutputModule" : "NanoAODOutputModule",
156  "NanoAODRNTupleOutputModule",
159  std::string(),
160  branchHash.digest().toString(),
161  std::vector<std::string>());
162 
163  if (m_compressionAlgorithm == "ZLIB") {
164  m_file->SetCompressionAlgorithm(ROOT::kZLIB);
165  } else if (m_compressionAlgorithm == "LZMA") {
166  m_file->SetCompressionAlgorithm(ROOT::kLZMA);
167  } else {
168  throw cms::Exception("Configuration")
169  << "NanoAODOutputModule configured with unknown compression algorithm '" << m_compressionAlgorithm << "'\n"
170  << "Allowed compression algorithms are ZLIB and LZMA\n";
171  }
172 
173  const auto& keeps = keptProducts();
174  for (const auto& keep : keeps[edm::InRun]) {
175  if (keep.first->className() == "nanoaod::MergeableCounterTable") {
176  m_run.registerToken(keep.second);
177  } else if (keep.first->className() == "nanoaod::UniqueString" && keep.first->moduleLabel() == "nanoMetadata") {
178  m_nanoMetadata.emplace_back(keep.first->productInstanceName(), keep.second);
179  } else {
180  throw cms::Exception(
181  "Configuration",
182  "NanoAODRNTupleOutputModule cannot handle class " + keep.first->className() + " in Run branch");
183  }
184  }
185 }
186 
188  // set up RNTuple schema
189  auto model = RNTupleModel::Create();
191 
192  const auto& keeps = keptProducts();
193  for (const auto& keep : keeps[edm::InEvent]) {
194  if (keep.first->className() == "nanoaod::FlatTable") {
196  const auto& token = keep.second;
197  iEvent.getByToken(token, handle);
199  } else if (keep.first->className() == "edm::TriggerResults") {
200  m_triggers.emplace_back(TriggerOutputFields(keep.first->processName(), keep.second));
201  } else if (keep.first->className() == "std::basic_string<char,std::char_traits<char> >" &&
202  keep.first->productInstanceName() == "genModel") {
204  } else {
205  throw cms::Exception("Configuration", "NanoAODOutputModule cannot handle class " + keep.first->className());
206  }
207  }
209  for (auto& trigger : m_triggers) {
210  trigger.createFields(iEvent, *model);
211  }
213  // TODO use Append
214  RNTupleWriteOptions options;
215  options.SetCompression(m_file->GetCompressionSettings());
216  m_ntuple = MakeRNTupleWriter(std::move(model), std::make_unique<RPageSinkFile>("Events", *m_file, options));
217 }
218 
220  if (!m_ntuple) {
222  }
223 
225  jr->eventWrittenToFile(m_jrToken, iEvent.id().run(), iEvent.id().event());
226 
227  m_commonFields.fill(iEvent.id());
229  for (auto& trigger : m_triggers) {
230  trigger.fill(iEvent);
231  }
233  m_ntuple->Fill();
235 }
236 
238  if (m_writeProvenance) {
239  writeProvenance();
240  }
241  // write ntuple to disk by calling the RNTupleWriter destructor
242  m_ntuple.reset();
245  m_file->Write();
246  m_file->Close();
247 
250 }
251 
253  PSetNTuple pntuple;
255  pntuple.finalizeWrite();
256 
257  MetadataNTuple mdntuple;
259  mdntuple.finalizeWrite();
260 }
261 
264 
265  desc.addUntracked<std::string>("fileName");
266  desc.addUntracked<std::string>("logicalFileName", "");
267  desc.addUntracked<int>("compressionLevel", 9)->setComment("ROOT compression level of output file.");
268  desc.addUntracked<std::string>("compressionAlgorithm", "ZLIB")
269  ->setComment(
270  "Algorithm used to "
271  "compress data in the ROOT output file, allowed values are ZLIB and LZMA");
272  desc.addUntracked<bool>("saveProvenance", true)
273  ->setComment("Save process provenance information, e.g. for edmProvDump");
274  const std::vector<std::string> keep = {"drop *",
275  "keep nanoaodFlatTable_*Table_*_*",
276  "keep edmTriggerResults_*_*_*",
277  "keep String_*_genModel_*",
278  "keep nanoaodMergeableCounterTable_*Table_*_*",
279  "keep nanoaodUniqueString_nanoMetadata_*_*"};
281 
282  //Used by Workflow management for their own meta data
284  dataSet.setAllowAnything();
285  desc.addUntracked<edm::ParameterSetDescription>("dataset", dataSet)
286  ->setComment("PSet is only used by Data Operations and not by this module.");
287 
289  branchSet.setAllowAnything();
290  desc.add<edm::ParameterSetDescription>("branches", branchSet);
291 
292  descriptions.addDefault(desc);
293 }
294 
void finalizeWrite()
void fill(const edm::LuminosityBlockID &id, TFile &file)
void setAllowAnything()
allow any parameter label/value pairs
bool registerProcessHistory(ProcessHistory const &processHistory)
#define MakeRNTupleWriter
void initializeNTuple(edm::EventForOutput const &e)
std::vector< std::pair< std::string, edm::EDGetToken > > m_nanoMetadata
void registerToken(const edm::EDGetToken &token)
void reportRunNumber(JobReport::Token token, unsigned int run)
Definition: JobReport.cc:505
BasicHandle getByToken(EDGetToken token, TypeID const &typeID) const
ModuleDescription const & description() const
int iEvent
Definition: GenABIO.cc:224
NanoAODRNTupleOutputModule(edm::ParameterSet const &pset)
void addDefault(ParameterSetDescription const &psetDescription)
MD5Result digest()
Definition: Digest.cc:171
void finalizeWrite()
class NanoAODRNTupleOutputModule::CommonEventFields m_commonFields
void fill(const edm::ProcessHistoryRegistry &procHist, TFile &file)
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:16
void fill(const edm::EventForOutput &event)
void writeRun(edm::RunForOutput const &) override
void fill(edm::pset::Registry *pset, TFile &file)
RunNumber_t run() const
std::size_t Token
Definition: JobReport.h:106
void openFile(edm::FileBlock const &) override
std::string createGlobalIdentifier(bool binary=false)
SelectedProductsForBranchType const & keptProducts() const
unsigned long long uint64_t
Definition: Time.h:13
std::unique_ptr< RNTupleWriter > m_ntuple
void eventWrittenToFile(Token fileToken, RunNumber_t run, EventNumber_t event)
Definition: JobReport.cc:462
std::vector< TriggerOutputFields > m_triggers
void createFields(RNTupleModel &model)
LuminosityBlockID const & id() const
const std::string & str() const
Definition: UniqueString.h:12
void finalizeWrite()
void add(const edm::EDGetToken &table_token, const nanoaod::FlatTable &table)
virtual ProcessHistory const & processHistory() const
void writeLuminosityBlock(edm::LuminosityBlockForOutput const &) override
RunID const & id() const
Definition: RunForOutput.h:55
HLT enums.
void outputFileClosed(Token fileToken)
Definition: JobReport.cc:467
edm::ProcessHistoryRegistry m_processHistoryRegistry
void fill(const edm::EventForOutput &iEvent)
void registerToken(const edm::EDGetToken &token)
void fill(const edm::RunForOutput &iRun, TFile &file)
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
static void fillDescription(ParameterSetDescription &desc, std::vector< std::string > const &iDefaultOutputCommands=ProductSelectorRules::defaultSelectionStrings())
std::string toString() const
Definition: Digest.cc:95
void createFields(const edm::EventForOutput &event, RNTupleModel &eventModel)
def move(src, dest)
Definition: eostools.py:511
static Registry * instance()
Definition: Registry.cc:12
RunNumber_t run() const
Definition: RunID.h:26
void write(edm::EventForOutput const &e) override
void reportLumiSection(JobReport::Token token, unsigned int run, unsigned int lumiSectId, unsigned long nEvents=0)
Definition: JobReport.cc:494