CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
RootOutputFile.cc
Go to the documentation of this file.
1 
3 
5 
43 
44 #include "TTree.h"
45 #include "TFile.h"
46 #include "TClass.h"
47 #include "Rtypes.h"
48 #include "RVersion.h"
49 
50 #include "Compression.h"
51 
52 #include <algorithm>
53 #include <iomanip>
54 #include <sstream>
55 
56 namespace edm {
57 
58  namespace {
59  bool sorterForJobReportHash(BranchDescription const* lh, BranchDescription const* rh) {
60  return lh->fullClassName() < rh->fullClassName() ? true
61  : lh->fullClassName() > rh->fullClassName() ? false
62  : lh->moduleLabel() < rh->moduleLabel() ? true
63  : lh->moduleLabel() > rh->moduleLabel() ? false
64  : lh->productInstanceName() < rh->productInstanceName() ? true
65  : lh->productInstanceName() > rh->productInstanceName() ? false
66  : lh->processName() < rh->processName() ? true
67  : false;
68  }
69 
70  TFile* openTFile(char const* name, int compressionLevel) {
71  TFile* file = TFile::Open(name, "recreate", "", compressionLevel);
72  std::exception_ptr e = edm::threadLocalException::getException();
73  if (e != std::exception_ptr()) {
74  edm::threadLocalException::setException(std::exception_ptr());
75  std::rethrow_exception(e);
76  }
77  return file;
78  }
79  } // namespace
80 
82  std::string const& fileName,
83  std::string const& logicalFileName,
84  std::vector<std::string> const& processesWithSelectedMergeableRunProducts)
85  : file_(fileName),
86  logicalFile_(logicalFileName),
87  reportToken_(0),
88  om_(om),
89  whyNotFastClonable_(om_->whyNotFastClonable()),
90  canFastCloneAux_(false),
91  filePtr_(openTFile(file_.c_str(), om_->compressionLevel())),
92  fid_(),
93  eventEntryNumber_(0LL),
94  lumiEntryNumber_(0LL),
95  runEntryNumber_(0LL),
96  indexIntoFile_(),
97  storedMergeableRunProductMetadata_(processesWithSelectedMergeableRunProducts),
98  nEventsInLumi_(0),
99  metaDataTree_(nullptr),
100  parameterSetsTree_(nullptr),
101  parentageTree_(nullptr),
102  lumiAux_(),
103  runAux_(),
104  pEventAux_(nullptr),
105  pLumiAux_(&lumiAux_),
106  pRunAux_(&runAux_),
107  eventEntryInfoVector_(),
108  pEventEntryInfoVector_(&eventEntryInfoVector_),
109  pBranchListIndexes_(nullptr),
110  pEventSelectionIDs_(nullptr),
111  eventTree_(filePtr(), InEvent, om_->splitLevel(), om_->treeMaxVirtualSize()),
112  lumiTree_(filePtr(), InLumi, om_->splitLevel(), om_->treeMaxVirtualSize()),
113  runTree_(filePtr(), InRun, om_->splitLevel(), om_->treeMaxVirtualSize()),
114  dataTypeReported_(false),
115  processHistoryRegistry_(),
116  parentageIDs_(),
117  branchesWithStoredHistory_(),
118  wrapperBaseTClass_(TClass::GetClass("edm::WrapperBase")) {
119  std::vector<std::string> const& processesWithProcessBlockProducts =
120  om_->outputProcessBlockHelper().processesWithProcessBlockProducts();
121  for (auto const& processName : processesWithProcessBlockProducts) {
122  processBlockTrees_.emplace_back(std::make_unique<RootOutputTree>(
123  filePtr(), InProcess, om_->splitLevel(), om_->treeMaxVirtualSize(), processName));
124  }
125 
126  if (om_->compressionAlgorithm() == std::string("ZLIB")) {
127  filePtr_->SetCompressionAlgorithm(ROOT::kZLIB);
128  } else if (om_->compressionAlgorithm() == std::string("LZMA")) {
129  filePtr_->SetCompressionAlgorithm(ROOT::kLZMA);
130  } else if (om_->compressionAlgorithm() == std::string("ZSTD")) {
131  filePtr_->SetCompressionAlgorithm(ROOT::kZSTD);
132  } else {
134  << "PoolOutputModule configured with unknown compression algorithm '" << om_->compressionAlgorithm() << "'\n"
135  << "Allowed compression algorithms are ZLIB, LZMA, and ZSTD\n";
136  }
137  if (-1 != om->eventAutoFlushSize()) {
139  }
140  if (om_->compactEventAuxiliary()) {
142  BranchTypeToAuxiliaryBranchName(InEvent), pEventAux_, om_->auxItems()[InEvent].basketSize_, false);
143  eventTree_.tree()->SetBranchStatus(BranchTypeToAuxiliaryBranchName(InEvent).c_str(),
144  false); // see writeEventAuxiliary
145  } else {
147  BranchTypeToAuxiliaryBranchName(InEvent), pEventAux_, om_->auxItems()[InEvent].basketSize_);
148  }
149 
152  om_->auxItems()[InEvent].basketSize_);
154  poolNames::eventSelectionsBranchName(), pEventSelectionIDs_, om_->auxItems()[InEvent].basketSize_, false);
157 
158  if (om_->outputProcessBlockHelper().productsFromInputKept()) {
161  om_->auxItems()[InEvent].basketSize_);
162  }
163 
165  BranchTypeToAuxiliaryBranchName(InLumi), pLumiAux_, om_->auxItems()[InLumi].basketSize_);
166 
168  BranchTypeToAuxiliaryBranchName(InRun), pRunAux_, om_->auxItems()[InRun].basketSize_);
169 
170  treePointers_.emplace_back(&eventTree_);
171  treePointers_.emplace_back(&lumiTree_);
172  treePointers_.emplace_back(&runTree_);
173  for (auto& processBlockTree : processBlockTrees_) {
174  treePointers_.emplace_back(processBlockTree.get());
175  }
176 
177  for (unsigned int i = 0; i < treePointers_.size(); ++i) {
178  RootOutputTree* theTree = treePointers_[i];
179  for (auto& item : om_->selectedOutputItemList()[i]) {
180  item.setProduct(nullptr);
181  BranchDescription const& desc = *item.branchDescription();
182  theTree->addBranch(desc.branchName(),
183  desc.wrappedName(),
184  item.product(),
185  item.splitLevel(),
186  item.basketSize(),
187  item.branchDescription()->produced());
188  //make sure we always store product registry info for all branches we create
189  branchesWithStoredHistory_.insert(item.branchID());
190  }
191  }
192  // Don't split metadata tree or event description tree
196 
198 
199  // For the Job Report, get a vector of branch names in the "Events" tree.
200  // Also create a hash of all the branch names in the "Events" tree
201  // in a deterministic order, except use the full class name instead of the friendly class name.
202  // To avoid extra string copies, we create a vector of pointers into the product registry,
203  // and use a custom comparison operator for sorting.
204  std::vector<std::string> branchNames;
205  std::vector<BranchDescription const*> branches;
206  branchNames.reserve(om_->selectedOutputItemList()[InEvent].size());
207  branches.reserve(om->selectedOutputItemList()[InEvent].size());
208  for (auto const& item : om_->selectedOutputItemList()[InEvent]) {
209  branchNames.push_back(item.branchDescription()->branchName());
210  branches.push_back(item.branchDescription());
211  }
212  // Now sort the branches for the hash.
213  sort_all(branches, sorterForJobReportHash);
214  // Now, make a concatenated string.
215  std::ostringstream oss;
216  char const underscore = '_';
217  for (auto const& branch : branches) {
218  BranchDescription const& bd = *branch;
219  oss << bd.fullClassName() << underscore << bd.moduleLabel() << underscore << bd.productInstanceName()
220  << underscore << bd.processName() << underscore;
221  }
222  std::string stringrep = oss.str();
223  cms::Digest md5alg(stringrep);
224 
225  // Register the output file with the JobReport service
226  // and get back the token for it.
227  std::string moduleName = "PoolOutputModule";
228  Service<JobReport> reportSvc;
229  reportToken_ = reportSvc->outputFileOpened(file_,
230  logicalFile_, // PFN and LFN
231  om_->catalog(), // catalog
232  moduleName, // module class name
233  om_->moduleLabel(), // module label
234  fid_.fid(), // file id (guid)
235  std::string(), // data type (not yet known, so string is empty).
236  md5alg.digest().toString(), // branch hash
237  branchNames); // branch names being written
238  }
239 
240  namespace {
241  void maybeIssueWarning(int whyNotFastClonable, std::string const& ifileName, std::string const& ofileName) {
242  // No message if fast cloning was deliberately disabled, or if there are no events to copy anyway.
245  return;
246  }
247 
248  // There will be a message stating every reason that fast cloning was not possible.
249  // If at one or more of the reasons was because of something the user explicitly specified (e.g. event selection, skipping events),
250  // or if the input file was in an old format, the message will be informational. Otherwise, the message will be a warning.
251  bool isWarning = true;
252  std::ostringstream message;
253  message << "Fast copying of file " << ifileName << " to file " << ofileName << " is disabled because:\n";
254  if ((whyNotFastClonable & FileBlock::HasSecondaryFileSequence) != 0) {
255  message << "a SecondaryFileSequence was specified.\n";
256  whyNotFastClonable &= ~(FileBlock::HasSecondaryFileSequence);
257  isWarning = false;
258  }
259  if ((whyNotFastClonable & FileBlock::FileTooOld) != 0) {
260  message << "the input file is in an old format.\n";
261  whyNotFastClonable &= ~(FileBlock::FileTooOld);
262  isWarning = false;
263  }
264  if ((whyNotFastClonable & FileBlock::EventsToBeSorted) != 0) {
265  message << "events need to be sorted.\n";
266  whyNotFastClonable &= ~(FileBlock::EventsToBeSorted);
267  }
268  if ((whyNotFastClonable & FileBlock::RunOrLumiNotContiguous) != 0) {
269  message << "a run or a lumi is not contiguous in the input file.\n";
270  whyNotFastClonable &= ~(FileBlock::RunOrLumiNotContiguous);
271  }
272  if ((whyNotFastClonable & FileBlock::EventsOrLumisSelectedByID) != 0) {
273  message << "events or lumis were selected or skipped by ID.\n";
274  whyNotFastClonable &= ~(FileBlock::EventsOrLumisSelectedByID);
275  isWarning = false;
276  }
277  if ((whyNotFastClonable & FileBlock::InitialEventsSkipped) != 0) {
278  message << "initial events, lumis or runs were skipped.\n";
279  whyNotFastClonable &= ~(FileBlock::InitialEventsSkipped);
280  isWarning = false;
281  }
282  if ((whyNotFastClonable & FileBlock::DuplicateEventsRemoved) != 0) {
283  message << "some events were skipped because of duplicate checking.\n";
284  whyNotFastClonable &= ~(FileBlock::DuplicateEventsRemoved);
285  }
286  if ((whyNotFastClonable & FileBlock::MaxEventsTooSmall) != 0) {
287  message << "some events were not copied because of maxEvents limit.\n";
288  whyNotFastClonable &= ~(FileBlock::MaxEventsTooSmall);
289  isWarning = false;
290  }
291  if ((whyNotFastClonable & FileBlock::MaxLumisTooSmall) != 0) {
292  message << "some events were not copied because of maxLumis limit.\n";
293  whyNotFastClonable &= ~(FileBlock::MaxLumisTooSmall);
294  isWarning = false;
295  }
296  if ((whyNotFastClonable & FileBlock::ParallelProcesses) != 0) {
297  message << "parallel processing was specified.\n";
298  whyNotFastClonable &= ~(FileBlock::ParallelProcesses);
299  isWarning = false;
300  }
301  if ((whyNotFastClonable & FileBlock::EventSelectionUsed) != 0) {
302  message << "an EventSelector was specified.\n";
303  whyNotFastClonable &= ~(FileBlock::EventSelectionUsed);
304  isWarning = false;
305  }
306  if ((whyNotFastClonable & FileBlock::OutputMaxEventsTooSmall) != 0) {
307  message << "some events were not copied because of maxEvents output limit.\n";
308  whyNotFastClonable &= ~(FileBlock::OutputMaxEventsTooSmall);
309  isWarning = false;
310  }
311  if ((whyNotFastClonable & FileBlock::SplitLevelMismatch) != 0) {
312  message << "the split level or basket size of a branch or branches was modified.\n";
313  whyNotFastClonable &= ~(FileBlock::SplitLevelMismatch);
314  }
315  if ((whyNotFastClonable & FileBlock::BranchMismatch) != 0) {
316  message << "The format of a data product has changed.\n";
317  whyNotFastClonable &= ~(FileBlock::BranchMismatch);
318  }
319  assert(whyNotFastClonable == FileBlock::CanFastClone);
320  if (isWarning) {
321  LogWarning("FastCloningDisabled") << message.str();
322  } else {
323  LogInfo("FastCloningDisabled") << message.str();
324  }
325  }
326  } // namespace
327 
328  void RootOutputFile::beginInputFile(FileBlock const& fb, int remainingEvents) {
329  // Reset per input file information
330  whyNotFastClonable_ = om_->whyNotFastClonable();
331  canFastCloneAux_ = false;
332 
333  if (fb.tree() != nullptr) {
335 
336  if (remainingEvents >= 0 && remainingEvents < fb.tree()->GetEntries()) {
338  }
339 
341  if (!match) {
342  if (om_->overrideInputFileSplitLevels()) {
343  // We may be fast copying. We must disable fast copying if the split levels
344  // or basket sizes do not match.
346  } else {
347  // We are using the input split levels and basket sizes from the first input file
348  // for copied output branches. In this case, we throw an exception if any branches
349  // have different split levels or basket sizes in a subsequent input file.
350  // If the mismatch is in the first file, there is a bug somewhere, so we assert.
351  assert(om_->inputFileCount() > 1);
352  throw Exception(errors::MismatchedInputFiles, "RootOutputFile::beginInputFile()")
353  << "Merge failure because input file " << file_ << " has different ROOT split levels or basket sizes\n"
354  << "than previous files. To allow merging in splite of this, use the configuration parameter\n"
355  << "overrideInputFileSplitLevels=cms.untracked.bool(True)\n"
356  << "in every PoolOutputModule.\n";
357  }
358  }
359 
360  // Since this check can be time consuming, we do it only if we would otherwise fast clone.
362  if (!eventTree_.checkIfFastClonable(fb.tree())) {
364  }
365  }
366  // We now check if we can fast copy the auxiliary branches.
367  // We can do so only if we can otherwise fast copy,
368  // the input file has the current format (these branches are in the Events Tree),
369  // there are no newly dropped or produced products,
370  // no metadata has been dropped,
371  // ID's have not been modified,
372  // and the branch list indexes do not need modification.
373 
374  // Note: Fast copy of the EventProductProvenance branch is unsafe
375  // unless we can enforce that the parentage information for a fully copied
376  // output file will be the same as for the input file, with nothing dropped.
377  // This has never been enforced, and, withthe EDAlias feature, it may no longer
378  // work by accident.
379  // So, for now, we do not enable fast cloning of the non-product branches.
380  /*
381  Service<ConstProductRegistry> reg;
382  canFastCloneAux_ = (whyNotFastClonable_ == FileBlock::CanFastClone) &&
383  fb.fileFormatVersion().noMetaDataTrees() &&
384  !om_->hasNewlyDroppedBranch()[InEvent] &&
385  !fb.hasNewlyDroppedBranch()[InEvent] &&
386  om_->dropMetaData() == PoolOutputModule::DropNone &&
387  !reg->anyProductProduced() &&
388  !fb.modifiedIDs() &&
389  fb.branchListIndexesUnchanged();
390 */
391 
392  // Report the fast copying status.
393  Service<JobReport> reportSvc;
394  reportSvc->reportFastCopyingStatus(reportToken_, fb.fileName(), whyNotFastClonable_ == FileBlock::CanFastClone);
395  } else {
397  }
398 
401 
402  // Possibly issue warning or informational message if we haven't fast cloned.
403  if (fb.tree() != nullptr && whyNotFastClonable_ != FileBlock::CanFastClone) {
404  maybeIssueWarning(whyNotFastClonable_, fb.fileName(), file_);
405  }
406 
407  if (om_->compactEventAuxiliary() &&
408  (whyNotFastClonable_ & (FileBlock::EventsOrLumisSelectedByID | FileBlock::InitialEventsSkipped |
410  long long int reserve = remainingEvents;
411  if (fb.tree() != nullptr) {
412  reserve = reserve > 0 ? std::min(fb.tree()->GetEntries(), reserve) : fb.tree()->GetEntries();
413  }
414  if (reserve > 0) {
416  }
417  }
418  }
419 
421  // We can't do setEntries() on the event tree if the EventAuxiliary branch is empty & disabled
422  if (not om_->compactEventAuxiliary()) {
424  }
427  }
428 
430  unsigned int const oneK = 1024;
431  Long64_t size = filePtr_->GetSize() / oneK;
432  return (size >= om_->maxFileSize());
433  }
434 
436  // Auxiliary branch
437  pEventAux_ = &e.eventAuxiliary();
438 
439  // Because getting the data may cause an exception to be thrown we want to do that
440  // first before writing anything to the file about this event
441  // NOTE: pEventAux_, pBranchListIndexes_, pEventSelectionIDs_, and pEventEntryInfoVector_
442  // must be set before calling fillBranches since they get written out in that routine.
446 
447  // Note: The EventSelectionIDVector should have a one to one correspondence with the processes in the process history.
448  // Therefore, a new entry should be added if and only if the current process has been added to the process history,
449  // which is done if and only if there is a produced product.
452  if (reg->anyProductProduced() || !om_->wantAllEvents()) {
453  esids.push_back(om_->selectorConfig());
454  }
455  pEventSelectionIDs_ = &esids;
457  assert(provRetriever);
458  unsigned int ttreeIndex = InEvent;
459  fillBranches(InEvent, e, ttreeIndex, pEventEntryInfoVector_, provRetriever);
460 
461  // Add the dataType to the job report if it hasn't already been done
462  if (!dataTypeReported_) {
463  Service<JobReport> reportSvc;
464  std::string dataType("MC");
465  if (pEventAux_->isRealData())
466  dataType = "Data";
467  reportSvc->reportDataType(reportToken_, dataType);
468  dataTypeReported_ = true;
469  }
470 
471  // Store the process history.
473  // Store the reduced ID in the IndexIntoFile
475  // Add event to index
479 
480  if (om_->compactEventAuxiliary()) {
482  }
483 
484  // Report event written
485  Service<JobReport> reportSvc;
486  reportSvc->eventWrittenToFile(reportToken_, e.id().run(), e.id().event());
487  ++nEventsInLumi_;
488  }
489 
491  // Auxiliary branch
492  // NOTE: lumiAux_ must be filled before calling fillBranches since it gets written out in that routine.
494  // Use the updated process historyID
496  // Store the process history.
498  // Store the reduced ID in the IndexIntoFile
500  // Add lumi to index.
503  unsigned int ttreeIndex = InLumi;
504  fillBranches(InLumi, lb, ttreeIndex);
505  lumiTree_.optimizeBaskets(10ULL * 1024 * 1024);
506 
507  Service<JobReport> reportSvc;
508  reportSvc->reportLumiSection(reportToken_, lb.id().run(), lb.id().luminosityBlock(), nEventsInLumi_);
509  nEventsInLumi_ = 0;
510  }
511 
513  // Auxiliary branch
514  // NOTE: runAux_ must be filled before calling fillBranches since it gets written out in that routine.
515  runAux_ = r.runAuxiliary();
516  // Use the updated process historyID
518  // Store the process history.
520  // Store the reduced ID in the IndexIntoFile
522  // Add run to index.
523  indexIntoFile_.addEntry(reducedPHID, runAux_.run(), 0U, 0U, runEntryNumber_);
525  ++runEntryNumber_;
526  unsigned int ttreeIndex = InRun;
527  fillBranches(InRun, r, ttreeIndex);
528  runTree_.optimizeBaskets(10ULL * 1024 * 1024);
529 
530  Service<JobReport> reportSvc;
531  reportSvc->reportRunNumber(reportToken_, r.run());
532  }
533 
535  std::string const& processName = pb.processName();
536  std::vector<std::string> const& processesWithProcessBlockProducts =
537  om_->outputProcessBlockHelper().processesWithProcessBlockProducts();
538  std::vector<std::string>::const_iterator it =
539  std::find(processesWithProcessBlockProducts.cbegin(), processesWithProcessBlockProducts.cend(), processName);
540  if (it == processesWithProcessBlockProducts.cend()) {
541  return;
542  }
543  unsigned int ttreeIndex = InProcess + std::distance(processesWithProcessBlockProducts.cbegin(), it);
544  fillBranches(InProcess, pb, ttreeIndex);
545  treePointers_[ttreeIndex]->optimizeBaskets(10ULL * 1024 * 1024);
546  }
547 
549  Parentage const* desc(nullptr);
550 
551  if (!parentageTree_->Branch(poolNames::parentageBranchName().c_str(), &desc, om_->basketSize(), 0))
552  throw Exception(errors::FatalRootError) << "Failed to create a branch for Parentages in the output file";
553 
555 
556  std::vector<ParentageID> orderedIDs(parentageIDs_.size());
557  for (auto const& parentageID : parentageIDs_) {
558  orderedIDs[parentageID.second] = parentageID.first;
559  }
560  //now put them into the TTree in the correct order
561  for (auto const& orderedID : orderedIDs) {
562  desc = ptReg.getMapped(orderedID);
563  //NOTE: some old format files have missing Parentage info
564  // so a null value of desc can't be fatal.
565  // Root will default construct an object in that case.
566  parentageTree_->Fill();
567  }
568  }
569 
571  FileFormatVersion fileFormatVersion(getFileFormatVersion());
572  FileFormatVersion* pFileFmtVsn = &fileFormatVersion;
573  TBranch* b =
574  metaDataTree_->Branch(poolNames::fileFormatVersionBranchName().c_str(), &pFileFmtVsn, om_->basketSize(), 0);
575  assert(b);
576  b->Fill();
577  }
578 
580  FileID* fidPtr = &fid_;
581  TBranch* b = metaDataTree_->Branch(poolNames::fileIdentifierBranchName().c_str(), &fidPtr, om_->basketSize(), 0);
582  assert(b);
583  b->Fill();
584  }
585 
589  ex << "The number of entries in at least one output TBranch whose entries\n"
590  "were copied from the input does not match the number of events\n"
591  "recorded in IndexIntoFile. This might (or might not) indicate a\n"
592  "problem related to fast copy.";
593  ex.addContext("Calling RootOutputFile::writeIndexIntoFile");
594  throw ex;
595  }
597  IndexIntoFile* iifPtr = &indexIntoFile_;
598  TBranch* b = metaDataTree_->Branch(poolNames::indexIntoFileBranchName().c_str(), &iifPtr, om_->basketSize(), 0);
599  assert(b);
600  b->Fill();
601  }
602 
606  TBranch* b =
607  metaDataTree_->Branch(poolNames::mergeableRunProductMetadataBranchName().c_str(), &ptr, om_->basketSize(), 0);
608  assert(b);
609  b->Fill();
610  }
611 
614  }
615 
617  BranchIDLists const* p = om_->branchIDLists();
618  TBranch* b = metaDataTree_->Branch(poolNames::branchIDListBranchName().c_str(), &p, om_->basketSize(), 0);
619  assert(b);
620  b->Fill();
621  }
622 
624  ThinnedAssociationsHelper const* p = om_->thinnedAssociationsHelper();
625  TBranch* b =
626  metaDataTree_->Branch(poolNames::thinnedAssociationsHelperBranchName().c_str(), &p, om_->basketSize(), 0);
627  assert(b);
628  b->Fill();
629  }
630 
633  }
634 
636  // Make a local copy of the ProductRegistry, removing any transient or pruned products.
637  using ProductList = ProductRegistry::ProductList;
639  ProductRegistry pReg(reg->productList());
640  ProductList& pList = const_cast<ProductList&>(pReg.productList());
641  for (auto const& prod : pList) {
642  if (prod.second.branchID() != prod.second.originalBranchID()) {
643  if (branchesWithStoredHistory_.find(prod.second.branchID()) != branchesWithStoredHistory_.end()) {
644  branchesWithStoredHistory_.insert(prod.second.originalBranchID());
645  }
646  }
647  }
648  std::set<BranchID>::iterator end = branchesWithStoredHistory_.end();
649  for (ProductList::iterator it = pList.begin(); it != pList.end();) {
650  if (branchesWithStoredHistory_.find(it->second.branchID()) == end) {
651  // avoid invalidating iterator on deletion
652  ProductList::iterator itCopy = it;
653  ++it;
654  pList.erase(itCopy);
655 
656  } else {
657  ++it;
658  }
659  }
660 
661  ProductRegistry* ppReg = &pReg;
662  TBranch* b = metaDataTree_->Branch(poolNames::productDescriptionBranchName().c_str(), &ppReg, om_->basketSize(), 0);
663  assert(b);
664  b->Fill();
665  }
667  BranchChildren& pDeps = const_cast<BranchChildren&>(om_->branchChildren());
668  BranchChildren* ppDeps = &pDeps;
669  TBranch* b =
670  metaDataTree_->Branch(poolNames::productDependenciesBranchName().c_str(), &ppDeps, om_->basketSize(), 0);
671  assert(b);
672  b->Fill();
673  }
674 
675  // For duplicate removal and to determine if fast cloning is possible, the input
676  // module by default reads the entire EventAuxiliary branch when it opens the
677  // input files. If EventAuxiliary is written in the usual way, this results
678  // in many small reads scattered throughout the file, which can have very poor
679  // performance characteristics on some filesystems. As a workaround, we save
680  // EventAuxiliary and write it at the end of the file.
681 
683  constexpr std::size_t maxEaBasketSize = 4 * 1024 * 1024;
684 
685  if (om_->compactEventAuxiliary()) {
686  auto tree = eventTree_.tree();
687  auto const& bname = BranchTypeToAuxiliaryBranchName(InEvent).c_str();
688 
689  tree->SetBranchStatus(bname, true);
690  auto basketsize =
691  std::min(maxEaBasketSize,
692  compactEventAuxiliary_.size() * (sizeof(EventAuxiliary) + 26)); // 26 is an empirical fudge factor
693  tree->SetBasketSize(bname, basketsize);
694  auto b = tree->GetBranch(bname);
695 
696  assert(b);
697 
698  LogDebug("writeEventAuxiliary") << "EventAuxiliary ratio extras/GUIDs/all = "
701 
702  for (auto const& aux : compactEventAuxiliary_) {
703  const auto ea = aux.eventAuxiliary();
704  pEventAux_ = &ea;
705  // Fill EventAuxiliary branch
706  b->Fill();
707  }
709  }
710  }
711 
713  if (!om_->outputProcessBlockHelper().processesWithProcessBlockProducts().empty()) {
714  StoredProcessBlockHelper storedProcessBlockHelper(
715  om_->outputProcessBlockHelper().processesWithProcessBlockProducts());
716  om_->outputProcessBlockHelper().fillCacheIndices(storedProcessBlockHelper);
717 
718  StoredProcessBlockHelper* pStoredProcessBlockHelper = &storedProcessBlockHelper;
719  TBranch* b = metaDataTree_->Branch(
720  poolNames::processBlockHelperBranchName().c_str(), &pStoredProcessBlockHelper, om_->basketSize(), 0);
721  assert(b);
722  b->Fill();
723  }
724  }
725 
727  metaDataTree_->SetEntries(-1);
730 
732 
733  // Create branch aliases for all the branches in the
734  // events/lumis/runs/processblock trees. The loop is over
735  // all types of data products.
736  for (unsigned int i = 0; i < treePointers_.size(); ++i) {
738  BranchType branchType = InProcess;
739  if (i < InProcess) {
740  branchType = static_cast<BranchType>(i);
741  } else {
742  processName = om_->outputProcessBlockHelper().processesWithProcessBlockProducts()[i - InProcess];
743  }
744  setBranchAliases(treePointers_[i]->tree(), om_->keptProducts()[branchType], processName);
745  treePointers_[i]->writeTree();
746  }
747 
748  // close the file -- mfp
749  // Just to play it safe, zero all pointers to objects in the TFile to be closed.
750  metaDataTree_ = parentageTree_ = nullptr;
751  for (auto& treePointer : treePointers_) {
752  treePointer->close();
753  treePointer = nullptr;
754  }
755  filePtr_->Close();
756  filePtr_ = nullptr; // propagate_const<T> has no reset() function
757 
758  // report that file has been closed
759  Service<JobReport> reportSvc;
760  reportSvc->outputFileClosed(reportToken_);
761  }
762 
764  SelectedProducts const& branches,
765  std::string const& processName) const {
766  if (tree && tree->GetNbranches() != 0) {
767  for (auto const& selection : branches) {
768  BranchDescription const& pd = *selection.first;
769  if (pd.branchType() == InProcess && processName != pd.processName()) {
770  continue;
771  }
772  std::string const& full = pd.branchName() + "obj";
773  if (pd.branchAliases().empty()) {
774  std::string const& alias = (pd.productInstanceName().empty() ? pd.moduleLabel() : pd.productInstanceName());
775  tree->SetAlias(alias.c_str(), full.c_str());
776  } else {
777  for (auto const& alias : pd.branchAliases()) {
778  tree->SetAlias(alias.c_str(), full.c_str());
779  }
780  }
781  }
782  }
783  }
784 
786  ProductProvenanceRetriever const* iMapper,
787  bool produced,
788  std::set<BranchID> const& iProducedIDs,
789  std::set<StoredProductProvenance>& oToFill) {
790  assert(om_->dropMetaData() != PoolOutputModule::DropAll);
791  assert(produced || om_->dropMetaData() != PoolOutputModule::DropPrior);
792  if (om_->dropMetaData() == PoolOutputModule::DropDroppedPrior && !produced)
793  return;
794  std::vector<BranchID> const& parentIDs = iGetParents.parentage().parents();
795  for (auto const& parentID : parentIDs) {
796  branchesWithStoredHistory_.insert(parentID);
797  ProductProvenance const* info = iMapper->branchIDToProvenance(parentID);
798  if (info) {
799  if (om_->dropMetaData() == PoolOutputModule::DropNone ||
800  (iProducedIDs.end() != iProducedIDs.find(info->branchID()))) {
801  if (insertProductProvenance(*info, oToFill)) {
802  //haven't seen this one yet
803  insertAncestors(*info, iMapper, produced, iProducedIDs, oToFill);
804  }
805  }
806  }
807  }
808  }
809 
810  void RootOutputFile::fillBranches(BranchType const& branchType,
811  OccurrenceForOutput const& occurrence,
812  unsigned int ttreeIndex,
813  StoredProductProvenanceVector* productProvenanceVecPtr,
814  ProductProvenanceRetriever const* provRetriever) {
815  std::vector<std::unique_ptr<WrapperBase> > dummies;
816 
817  OutputItemList& items = om_->selectedOutputItemList()[ttreeIndex];
818 
819  bool const doProvenance =
820  (productProvenanceVecPtr != nullptr) && (om_->dropMetaData() != PoolOutputModule::DropAll);
821  bool const keepProvenanceForPrior = doProvenance && om_->dropMetaData() != PoolOutputModule::DropPrior;
822 
823  bool const fastCloning = (branchType == InEvent) && (whyNotFastClonable_ == FileBlock::CanFastClone);
824  std::set<StoredProductProvenance> provenanceToKeep;
825  //
826  //If we are dropping some of the meta data we need to know
827  // which BranchIDs were produced in this process because
828  // we may be storing meta data for only those products
829  // We do this only for event products.
830  std::set<BranchID> producedBranches;
831  if (doProvenance && branchType == InEvent && om_->dropMetaData() != PoolOutputModule::DropNone) {
833  for (auto bd : preg->allBranchDescriptions()) {
834  if (bd->produced() && bd->branchType() == InEvent) {
835  producedBranches.insert(bd->branchID());
836  }
837  }
838  }
839 
840  // Loop over EDProduct branches, possibly fill the provenance, and write the branch.
841  for (auto& item : items) {
842  BranchID const& id = item.branchDescription()->branchID();
843  branchesWithStoredHistory_.insert(id);
844 
845  bool produced = item.branchDescription()->produced();
846  bool getProd =
847  (produced || !fastCloning || treePointers_[ttreeIndex]->uncloned(item.branchDescription()->branchName()));
848  bool keepProvenance = doProvenance && (produced || keepProvenanceForPrior);
849 
850  WrapperBase const* product = nullptr;
851  ProductProvenance const* productProvenance = nullptr;
852  if (getProd) {
853  BasicHandle result = occurrence.getByToken(item.token(), item.branchDescription()->unwrappedTypeID());
854  product = result.wrapper();
855  if (result.isValid() && keepProvenance) {
856  productProvenance = result.provenance()->productProvenance();
857  }
858  if (product == nullptr) {
859  // No product with this ID is in the event.
860  // Add a null product.
861  TClass* cp = item.branchDescription()->wrappedType().getClass();
862  assert(cp != nullptr);
863  int offset = cp->GetBaseClassOffset(wrapperBaseTClass_);
864  void* p = cp->New();
865  std::unique_ptr<WrapperBase> dummy = getWrapperBasePtr(p, offset);
866  product = dummy.get();
867  dummies.emplace_back(std::move(dummy));
868  }
869  item.setProduct(product);
870  }
871  if (keepProvenance && productProvenance == nullptr) {
872  productProvenance = provRetriever->branchIDToProvenance(item.branchDescription()->originalBranchID());
873  }
874  if (productProvenance) {
875  insertProductProvenance(*productProvenance, provenanceToKeep);
876  insertAncestors(*productProvenance, provRetriever, produced, producedBranches, provenanceToKeep);
877  }
878  }
879 
880  if (doProvenance)
881  productProvenanceVecPtr->assign(provenanceToKeep.begin(), provenanceToKeep.end());
882  treePointers_[ttreeIndex]->fillTree();
883  if (doProvenance)
884  productProvenanceVecPtr->clear();
885  }
886 
888  std::set<edm::StoredProductProvenance>& oToInsert) {
889  StoredProductProvenance toStore;
890  toStore.branchID_ = iProv.branchID().id();
891  std::set<edm::StoredProductProvenance>::iterator itFound = oToInsert.find(toStore);
892  if (itFound == oToInsert.end()) {
893  //get the index to the ParentageID or insert a new value if not already present
894  std::pair<std::map<edm::ParentageID, unsigned int>::iterator, bool> i =
895  parentageIDs_.insert(std::make_pair(iProv.parentageID(), static_cast<unsigned int>(parentageIDs_.size())));
896  toStore.parentageIDIndex_ = i.first->second;
897  if (toStore.parentageIDIndex_ >= parentageIDs_.size()) {
899  << "RootOutputFile::insertProductProvenance\n"
900  << "The parentage ID index value " << toStore.parentageIDIndex_
901  << " is out of bounds. The maximum value is currently " << parentageIDs_.size() - 1 << ".\n"
902  << "This should never happen.\n"
903  << "Please report this to the framework hypernews forum 'hn-cms-edmFramework@cern.ch'.\n";
904  }
905 
906  oToInsert.insert(toStore);
907  return true;
908  }
909  return false;
910  }
911 } // namespace edm
RunNumber_t run() const
Definition: EventID.h:38
PoolOutputModule::OutputItemList OutputItemList
EventNumber_t event() const
Definition: EventID.h:40
std::string const & branchName() const
bool isRealData() const
void beginInputFile(FileBlock const &fb, int remainingEvents)
BranchID const & branchID() const
LuminosityBlockAuxiliary lumiAux_
std::string const & BranchTypeToAuxiliaryBranchName(BranchType const &branchType)
Definition: BranchType.cc:116
EventID const & id() const
static const TGPicture * info(bool iBackgroundIsBlack)
std::string const & processName() const
BranchType const & branchType() const
std::string const & parentageTreeName()
Definition: BranchType.cc:154
std::vector< BranchIDList > BranchIDLists
Definition: BranchIDList.h:19
int eventAutoFlushSize() const
EventAuxiliary const & eventAuxiliary() const
void writeProcessHistoryRegistry()
void push_back(const EventAuxiliary &ea)
EventToProcessBlockIndexes const & eventToProcessBlockIndexes() const
void addEntryToStoredMetadata(StoredMergeableRunProductMetadata &) const
void insertAncestors(ProductProvenance const &iGetParents, ProductProvenanceRetriever const *iMapper, bool produced, std::set< BranchID > const &producedBranches, std::set< StoredProductProvenance > &oToFill)
void fillParameterSetBranch(TTree *parameterSetsTree, int basketSize)
std::map< BranchKey, BranchDescription > ProductList
bool checkSplitLevelsAndBasketSizes(TTree *inputTree) const
bool registerProcessHistory(ProcessHistory const &processHistory)
selection
main part
Definition: corrVsCorr.py:100
TTree const * tree() const
std::map< ParentageID, unsigned int > parentageIDs_
void fillProcessHistoryBranch(TTree *metaDataTree, int basketSize, ProcessHistoryRegistry const &processHistoryRegistry)
int whyNotFastClonable() const
Definition: FileBlock.h:128
RunNumber_t run() const
std::string const & fileFormatVersionBranchName()
Definition: BranchType.cc:189
edm::propagate_const< TTree * > metaDataTree_
unsigned long nEventsInLumi_
ProcessHistoryRegistry processHistoryRegistry_
ProductProvenance const * branchIDToProvenance(BranchID const &bid) const
std::string const & processName() const
ProductProvenance const * productProvenance() const
Definition: Provenance.cc:24
std::string const & eventSelectionsBranchName()
Definition: BranchType.cc:210
bool int lh
Definition: SIMDVec.h:20
void writeLuminosityBlock(LuminosityBlockForOutput const &lb)
void setAutoFlush(Long64_t size)
void find(edm::Handle< EcalRecHitCollection > &hits, DetId thisDet, std::vector< EcalRecHitCollection::const_iterator > &hit, bool debug=false)
Definition: FindCaloHit.cc:19
assert(be >=bs)
bool shouldWeCloseFile() const
unsigned int id() const
Definition: BranchID.h:21
LuminosityBlockAuxiliary const & luminosityBlockAuxiliary() const
bool checkIfFastClonable(TTree *inputTree) const
BranchType
Definition: BranchType.h:11
std::set< BranchID > branchesWithStoredHistory_
std::vector< edm::propagate_const< RootOutputTree * > > treePointers_
std::vector< EventSelectionID > EventSelectionIDVector
void sortVector_Run_Or_Lumi_Entries()
LuminosityBlockNumber_t luminosityBlock() const
std::string const & parameterSetsTreeName()
Definition: BranchType.cc:216
tuple result
Definition: mps_fire.py:311
RootOutputFile(PoolOutputModule *om, std::string const &fileName, std::string const &logicalFileName, std::vector< std::string > const &processesWithSelectedMergeableRunProducts)
std::vector< std::pair< BranchDescription const *, EDGetToken > > SelectedProducts
std::vector< BranchID > const & parents() const
Definition: Parentage.h:44
void writeThinnedAssociationsHelper()
std::shared_ptr< TFile const > filePtr() const
RootOutputTree eventTree_
std::vector< BranchListIndex > BranchListIndexes
std::vector< OutputItemList > const & selectedOutputItemList() const
bool getMapped(key_type const &k, value_type &result) const
void addBranch(std::string const &branchName, std::string const &className, void const *&pProd, int splitLevel, int basketSize, bool produced)
edm::propagate_const< PoolOutputModule * > om_
virtual ProcessHistory const & processHistory() const
MD5Result digest()
Definition: Digest.cc:171
std::string const & moduleLabel() const
IndexIntoFile::EntryNumber_t eventEntryNumber_
std::string const & productInstanceName() const
std::string const & mergeableRunProductMetadataBranchName()
Definition: BranchType.cc:201
LuminosityBlockAuxiliary const * pLumiAux_
std::string const & indexIntoFileBranchName()
Definition: BranchType.cc:198
edm::propagate_const< std::shared_ptr< TFile > > filePtr_
Definition: GenABIO.cc:168
def move
Definition: eostools.py:511
void writeOne(EventForOutput const &e)
ProductProvenanceRetriever const * productProvenanceRetrieverPtr() const
RunNumber_t run() const
int getFileFormatVersion()
EventSelectionIDVector const & eventSelectionIDs() const
std::string logicalFile_
bool checkEntriesInReadBranches(Long64_t expectedNumberOfEntries) const
void fillBranches(BranchType const &branchType, OccurrenceForOutput const &occurrence, unsigned int ttreeIndex, StoredProductProvenanceVector *productProvenanceVecPtr=nullptr, ProductProvenanceRetriever const *provRetriever=nullptr)
ProcessHistoryID const & reducedProcessHistoryID(ProcessHistoryID const &fullID) const
void setProcessHistoryID(ProcessHistoryID const &phid)
std::string const & metaDataTreeName()
Definition: BranchType.cc:159
T min(T a, T b)
Definition: MathUtil.h:58
CompactEventAuxiliaryVector compactEventAuxiliary_
LuminosityBlockNumber_t luminosityBlock() const
void addEntry(ProcessHistoryID const &processHistoryID, RunNumber_t run, LuminosityBlockNumber_t lumi, EventNumber_t event, EntryNumber_t entry)
edm::propagate_const< TClass * > wrapperBaseTClass_
bool isValid() const noexcept(true)
Definition: BasicHandle.h:69
std::string const & eventToProcessBlockIndexesBranchName()
Definition: BranchType.cc:214
static TTree * makeTTree(TFile *filePtr, std::string const &name, int splitLevel)
ProcessHistoryID const & processHistoryID() const
std::string const & fullClassName() const
EventSelectionIDVector const * pEventSelectionIDs_
std::string createGlobalIdentifier(bool binary=false)
Log< level::Info, false > LogInfo
edm::propagate_const< TTree * > parameterSetsTree_
StoredMergeableRunProductMetadata storedMergeableRunProductMetadata_
void writeStoredMergeableRunProductMetadata()
RunAuxiliary const & runAuxiliary() const
Definition: RunForOutput.h:54
void sort_all(RandomAccessSequence &s)
wrappers for std::sort
Definition: Algorithms.h:92
edm::propagate_const< StoredProductProvenanceVector * > pEventEntryInfoVector_
WrapperBase const * wrapper() const noexcept(true)
Definition: BasicHandle.h:73
RootOutputTree runTree_
std::string toString() const
Definition: Digest.cc:95
std::string const & parentageBranchName()
Definition: BranchType.cc:156
double b
Definition: hdecay.h:118
LuminosityBlockNumber_t luminosityBlock() const
void addContext(std::string const &context)
Definition: Exception.cc:165
edm::propagate_const< TTree * > parentageTree_
std::set< std::string > const & branchAliases() const
bool insertProductProvenance(const ProductProvenance &, std::set< StoredProductProvenance > &oToInsert)
void setException(std::exception_ptr e)
void addAuxiliary(std::string const &branchName, T const *&pAux, int bufSize, bool allowCloning=true)
std::vector< StoredProductProvenance > StoredProductProvenanceVector
void respondToCloseInputFile(FileBlock const &fb)
IndexIntoFile indexIntoFile_
BasicHandle getByToken(EDGetToken token, TypeID const &typeID) const
constexpr element_type const * get() const
std::string const & productDescriptionBranchName()
Definition: BranchType.cc:162
IndexIntoFile::EntryNumber_t runEntryNumber_
ParentageID const & parentageID() const
static void writeTTree(TTree *tree)
ProcessHistoryID const & processHistoryID() const
std::string moduleName(StableProvenance const &provenance, ProcessHistory const &history)
Definition: Provenance.cc:27
EventAuxiliary const * pEventAux_
RunAuxiliary runAux_
std::exception_ptr getException()
string end
Definition: dataset.py:937
void writeProductDescriptionRegistry()
std::string const & BranchTypeToProductProvenanceBranchName(BranchType const &BranchType)
Definition: BranchType.cc:139
std::string const & productDependenciesBranchName()
Definition: BranchType.cc:165
StoredProductProvenanceVector const * pEventEntryInfoVector() const
std::string const & thinnedAssociationsHelperBranchName()
Definition: BranchType.cc:186
BranchListIndexes const & branchListIndexes() const
void writeProcessBlock(ProcessBlockForOutput const &)
std::unique_ptr< WrapperBase > getWrapperBasePtr(void *p, int offset)
std::string const & branchIDListBranchName()
Definition: BranchType.cc:183
void setProcessHistoryID(ProcessHistoryID const &phid)
Definition: RunAuxiliary.h:26
std::string const & branchListIndexesBranchName()
Definition: BranchType.cc:212
Parentage const & parentage() const
BranchListIndexes const * pBranchListIndexes_
Log< level::Warning, false > LogWarning
tuple branchNames
Definition: haddnano.py:54
void maybeFastCloneTree(bool canFastClone, bool canFastCloneAux, TTree *tree, std::string const &option)
LuminosityBlockID const & id() const
preg
Definition: Schedule.cc:687
std::vector< edm::propagate_const< std::unique_ptr< RootOutputTree > > > processBlockTrees_
static ParentageRegistry * instance()
IndexIntoFile::EntryNumber_t lumiEntryNumber_
RootOutputTree lumiTree_
Provenance const * provenance() const noexcept(true)
Definition: BasicHandle.h:75
void optimizeBaskets(ULong64_t size)
void writeRun(RunForOutput const &r)
TTree * tree() const
Definition: FileBlock.h:117
std::string const & fileIdentifierBranchName()
Definition: BranchType.cc:192
MergeableRunProductMetadata const * mergeableRunProductMetadata() const
Definition: RunForOutput.h:59
RunAuxiliary const * pRunAux_
std::string const & processBlockHelperBranchName()
Definition: BranchType.cc:204
std::string const & wrappedName() const
tuple size
Write out results.
EventNumber_t event() const
RunNumber_t run() const
Definition: RunAuxiliary.h:31
void setBranchAliases(TTree *tree, SelectedProducts const &branches, std::string const &processName) const
RunNumber_t run() const
Definition: RunForOutput.h:56
JobReport::Token reportToken_
EventToProcessBlockIndexes const * pEventToProcessBlockIndexes_
std::string const & fileName() const
Definition: FileBlock.h:130
#define LogDebug(id)
std::string match(BranchDescription const &a, BranchDescription const &b, std::string const &fileName)