Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2025-04-22 06:27:33

0001 #include "IOPool/Output/interface/PoolOutputModule.h"
0002 
0003 #include "IOPool/Output/src/RootOutputFile.h"
0004 
0005 #include "FWCore/Framework/interface/EventForOutput.h"
0006 #include "FWCore/Framework/interface/LuminosityBlockForOutput.h"
0007 #include "FWCore/Framework/interface/RunForOutput.h"
0008 #include "FWCore/Framework/interface/FileBlock.h"
0009 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0010 #include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
0011 #include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
0012 #include "FWCore/ServiceRegistry/interface/Service.h"
0013 #include "DataFormats/Provenance/interface/ProductDescription.h"
0014 #include "DataFormats/Provenance/interface/Parentage.h"
0015 #include "DataFormats/Provenance/interface/ParentageRegistry.h"
0016 #include "DataFormats/Provenance/interface/ProductProvenance.h"
0017 #include "FWCore/Framework/interface/ProductProvenanceRetriever.h"
0018 #include "FWCore/Utilities/interface/Algorithms.h"
0019 #include "FWCore/Utilities/interface/EDMException.h"
0020 #include "FWCore/Utilities/interface/TimeOfDay.h"
0021 #include "FWCore/Utilities/interface/WrappedClassName.h"
0022 
0023 #include "TTree.h"
0024 #include "TBranchElement.h"
0025 #include "TObjArray.h"
0026 #include "RVersion.h"
0027 #include "TDictAttributeMap.h"
0028 
0029 #include <fstream>
0030 #include <iomanip>
0031 #include <sstream>
0032 #include "boost/algorithm/string.hpp"
0033 
0034 namespace edm {
0035   PoolOutputModule::PoolOutputModule(ParameterSet const& pset)
0036       : edm::one::OutputModuleBase::OutputModuleBase(pset),
0037         one::OutputModule<WatchInputFiles>(pset),
0038         rootServiceChecker_(),
0039         auxItems_(),
0040         selectedOutputItemList_(),
0041         fileName_(pset.getUntrackedParameter<std::string>("fileName")),
0042         logicalFileName_(pset.getUntrackedParameter<std::string>("logicalFileName")),
0043         catalog_(pset.getUntrackedParameter<std::string>("catalog")),
0044         maxFileSize_(pset.getUntrackedParameter<int>("maxSize")),
0045         compressionLevel_(pset.getUntrackedParameter<int>("compressionLevel")),
0046         compressionAlgorithm_(pset.getUntrackedParameter<std::string>("compressionAlgorithm")),
0047         basketSize_(pset.getUntrackedParameter<int>("basketSize")),
0048         eventAuxBasketSize_(pset.getUntrackedParameter<int>("eventAuxiliaryBasketSize")),
0049         eventAutoFlushSize_(pset.getUntrackedParameter<int>("eventAutoFlushCompressedSize")),
0050         splitLevel_(std::min<int>(pset.getUntrackedParameter<int>("splitLevel") + 1, 99)),
0051         basketOrder_(pset.getUntrackedParameter<std::string>("sortBaskets")),
0052         treeMaxVirtualSize_(pset.getUntrackedParameter<int>("treeMaxVirtualSize")),
0053         whyNotFastClonable_(pset.getUntrackedParameter<bool>("fastCloning") ? FileBlock::CanFastClone
0054                                                                             : FileBlock::DisabledInConfigFile),
0055         dropMetaData_(DropNone),
0056         moduleLabel_(pset.getParameter<std::string>("@module_label")),
0057         initializedFromInput_(false),
0058         outputFileCount_(0),
0059         inputFileCount_(0),
0060         branchParents_(),
0061         productDependencies_(),
0062         overrideInputFileSplitLevels_(pset.getUntrackedParameter<bool>("overrideInputFileSplitLevels")),
0063         compactEventAuxiliary_(pset.getUntrackedParameter<bool>("compactEventAuxiliary")),
0064         mergeJob_(pset.getUntrackedParameter<bool>("mergeJob")),
0065         rootOutputFile_(),
0066         statusFileName_(),
0067         overrideGUID_(pset.getUntrackedParameter<std::string>("overrideGUID")) {
0068     if (pset.getUntrackedParameter<bool>("writeStatusFile")) {
0069       std::ostringstream statusfilename;
0070       statusfilename << moduleLabel_ << '_' << getpid();
0071       statusFileName_ = statusfilename.str();
0072     }
0073 
0074     std::string dropMetaData(pset.getUntrackedParameter<std::string>("dropMetaData"));
0075     if (dropMetaData.empty())
0076       dropMetaData_ = DropNone;
0077     else if (dropMetaData == std::string("NONE"))
0078       dropMetaData_ = DropNone;
0079     else if (dropMetaData == std::string("DROPPED"))
0080       dropMetaData_ = DropDroppedPrior;
0081     else if (dropMetaData == std::string("PRIOR"))
0082       dropMetaData_ = DropPrior;
0083     else if (dropMetaData == std::string("ALL"))
0084       dropMetaData_ = DropAll;
0085     else {
0086       throw edm::Exception(errors::Configuration, "Illegal dropMetaData parameter value: ")
0087           << dropMetaData << ".\n"
0088           << "Legal values are 'NONE', 'DROPPED', 'PRIOR', and 'ALL'.\n";
0089     }
0090 
0091     if (!wantAllEvents()) {
0092       whyNotFastClonable_ += FileBlock::EventSelectionUsed;
0093     }
0094 
0095     auto const& specialSplit{pset.getUntrackedParameterSetVector("overrideBranchesSplitLevel")};
0096 
0097     specialSplitLevelForBranches_.reserve(specialSplit.size());
0098     for (auto const& s : specialSplit) {
0099       specialSplitLevelForBranches_.emplace_back(s.getUntrackedParameter<std::string>("branch"),
0100                                                  s.getUntrackedParameter<int>("splitLevel"));
0101     }
0102 
0103     auto const& branchAliases{pset.getUntrackedParameterSetVector("branchAliases")};
0104     aliasForBranches_.reserve(branchAliases.size());
0105     for (auto const& a : branchAliases) {
0106       aliasForBranches_.emplace_back(a.getUntrackedParameter<std::string>("branch"),
0107                                      a.getUntrackedParameter<std::string>("alias"));
0108     }
0109     // We don't use this next parameter, but we read it anyway because it is part
0110     // of the configuration of this module.  An external parser creates the
0111     // configuration by reading this source code.
0112     pset.getUntrackedParameterSet("dataset");
0113   }
0114 
0115   void PoolOutputModule::beginJob() {}
0116 
0117   void PoolOutputModule::initialRegistry(edm::ProductRegistry const& iReg) {
0118     reg_ = std::make_unique<ProductRegistry>(iReg.productList());
0119   }
0120 
0121   std::string const& PoolOutputModule::currentFileName() const { return rootOutputFile_->fileName(); }
0122 
0123   PoolOutputModule::AuxItem::AuxItem() : basketSize_(ProductDescription::invalidBasketSize) {}
0124 
0125   PoolOutputModule::OutputItem::OutputItem(ProductDescription const* bd,
0126                                            EDGetToken const& token,
0127                                            int splitLevel,
0128                                            int basketSize)
0129       : productDescription_(bd), token_(token), product_(nullptr), splitLevel_(splitLevel), basketSize_(basketSize) {}
0130 
0131   PoolOutputModule::OutputItem::Sorter::Sorter(TTree* tree) : treeMap_(new std::map<std::string, int>) {
0132     // Fill a map mapping branch names to an index specifying the order in the tree.
0133     if (tree != nullptr) {
0134       TObjArray* branches = tree->GetListOfBranches();
0135       for (int i = 0; i < branches->GetEntries(); ++i) {
0136         TBranchElement* br = (TBranchElement*)branches->At(i);
0137         treeMap_->insert(std::make_pair(std::string(br->GetName()), i));
0138       }
0139     }
0140   }
0141 
0142   bool PoolOutputModule::OutputItem::Sorter::operator()(OutputItem const& lh, OutputItem const& rh) const {
0143     // Provides a comparison for sorting branches according to the index values in treeMap_.
0144     // Branches not found are always put at the end (i.e. not found > found).
0145     if (treeMap_->empty())
0146       return lh < rh;
0147     std::string const& lstring = lh.productDescription_->branchName();
0148     std::string const& rstring = rh.productDescription_->branchName();
0149     std::map<std::string, int>::const_iterator lit = treeMap_->find(lstring);
0150     std::map<std::string, int>::const_iterator rit = treeMap_->find(rstring);
0151     bool lfound = (lit != treeMap_->end());
0152     bool rfound = (rit != treeMap_->end());
0153     if (lfound && rfound) {
0154       return lit->second < rit->second;
0155     } else if (lfound) {
0156       return true;
0157     } else if (rfound) {
0158       return false;
0159     }
0160     return lh < rh;
0161   }
0162 
0163   namespace {
0164     std::regex convertBranchExpression(std::string const& iGlobBranchExpression) {
0165       std::string tmp(iGlobBranchExpression);
0166       boost::replace_all(tmp, "*", ".*");
0167       boost::replace_all(tmp, "?", ".");
0168       return std::regex(tmp);
0169     }
0170   }  // namespace
0171 
0172   inline bool PoolOutputModule::SpecialSplitLevelForBranch::match(std::string const& iBranchName) const {
0173     return std::regex_match(iBranchName, branch_);
0174   }
0175 
0176   std::regex PoolOutputModule::SpecialSplitLevelForBranch::convert(std::string const& iGlobBranchExpression) const {
0177     return convertBranchExpression(iGlobBranchExpression);
0178   }
0179 
0180   bool PoolOutputModule::AliasForBranch::match(std::string const& iBranchName) const {
0181     return std::regex_match(iBranchName, branch_);
0182   }
0183 
0184   std::regex PoolOutputModule::AliasForBranch::convert(std::string const& iGlobBranchExpression) const {
0185     return convertBranchExpression(iGlobBranchExpression);
0186   }
0187 
0188   void PoolOutputModule::fillSelectedItemList(BranchType branchType,
0189                                               std::string const& processName,
0190                                               TTree* theInputTree,
0191                                               OutputItemList& outputItemList) {
0192     SelectedProducts const& keptVector = keptProducts()[branchType];
0193 
0194     if (branchType != InProcess) {
0195       AuxItem& auxItem = auxItems_[branchType];
0196 
0197       auto basketSize = (InEvent == branchType) ? eventAuxBasketSize_ : basketSize_;
0198 
0199       // Fill AuxItem
0200       if (theInputTree != nullptr && !overrideInputFileSplitLevels_) {
0201         TBranch* auxBranch = theInputTree->GetBranch(BranchTypeToAuxiliaryBranchName(branchType).c_str());
0202         if (auxBranch) {
0203           auxItem.basketSize_ = auxBranch->GetBasketSize();
0204         } else {
0205           auxItem.basketSize_ = basketSize;
0206         }
0207       } else {
0208         auxItem.basketSize_ = basketSize;
0209       }
0210     }
0211 
0212     // Fill outputItemList with an entry for each branch.
0213     for (auto const& kept : keptVector) {
0214       int splitLevel = ProductDescription::invalidSplitLevel;
0215       int basketSize = ProductDescription::invalidBasketSize;
0216 
0217       ProductDescription const& prod = *kept.first;
0218       if (branchType == InProcess && processName != prod.processName()) {
0219         continue;
0220       }
0221       TBranch* theBranch = ((!prod.produced() && theInputTree != nullptr && !overrideInputFileSplitLevels_)
0222                                 ? theInputTree->GetBranch(prod.branchName().c_str())
0223                                 : nullptr);
0224 
0225       if (theBranch != nullptr) {
0226         splitLevel = theBranch->GetSplitLevel();
0227         basketSize = theBranch->GetBasketSize();
0228       } else {
0229         auto wp = prod.wrappedType().getClass()->GetAttributeMap();
0230         auto wpSplitLevel = ProductDescription::invalidSplitLevel;
0231         if (wp && wp->HasKey("splitLevel")) {
0232           wpSplitLevel = strtol(wp->GetPropertyAsString("splitLevel"), nullptr, 0);
0233           if (wpSplitLevel < 0) {
0234             throw cms::Exception("IllegalSplitLevel") << "' An illegal ROOT split level of " << wpSplitLevel
0235                                                       << " is specified for class " << prod.wrappedName() << ".'\n";
0236           }
0237           wpSplitLevel += 1;  //Compensate for wrapper
0238         }
0239         splitLevel = (wpSplitLevel == ProductDescription::invalidSplitLevel ? splitLevel_ : wpSplitLevel);
0240         for (auto const& b : specialSplitLevelForBranches_) {
0241           if (b.match(prod.branchName())) {
0242             splitLevel = b.splitLevel_;
0243           }
0244         }
0245         auto wpBasketSize = ProductDescription::invalidBasketSize;
0246         if (wp && wp->HasKey("basketSize")) {
0247           wpBasketSize = strtol(wp->GetPropertyAsString("basketSize"), nullptr, 0);
0248           if (wpBasketSize <= 0) {
0249             throw cms::Exception("IllegalBasketSize") << "' An illegal ROOT basket size of " << wpBasketSize
0250                                                       << " is specified for class " << prod.wrappedName() << "'.\n";
0251           }
0252         }
0253         basketSize = (wpBasketSize == ProductDescription::invalidBasketSize ? basketSize_ : wpBasketSize);
0254       }
0255       outputItemList.emplace_back(&prod, kept.second, splitLevel, basketSize);
0256     }
0257 
0258     // Sort outputItemList to allow fast copying.
0259     // The branches in outputItemList must be in the same order as in the input tree, with all new branches at the end.
0260     sort_all(outputItemList, OutputItem::Sorter(theInputTree));
0261   }
0262 
0263   void PoolOutputModule::beginInputFile(FileBlock const& fb) {
0264     if (isFileOpen()) {
0265       //Faster to read ChildrenBranches directly from input
0266       // file than to build it every event
0267       auto const& branchToChildMap = fb.productDependencies().childLookup();
0268       for (auto const& parentToChildren : branchToChildMap) {
0269         for (auto const& child : parentToChildren.second) {
0270           productDependencies_.insertChild(parentToChildren.first, child);
0271         }
0272       }
0273       rootOutputFile_->beginInputFile(fb, remainingEvents());
0274     }
0275   }
0276 
0277   void PoolOutputModule::openFile(FileBlock const& fb) {
0278     if (!isFileOpen()) {
0279       reallyOpenFile();
0280       beginInputFile(fb);
0281     }
0282   }
0283 
0284   void PoolOutputModule::respondToOpenInputFile(FileBlock const& fb) {
0285     if (!initializedFromInput_) {
0286       std::vector<std::string> const& processesWithProcessBlockProducts =
0287           outputProcessBlockHelper().processesWithProcessBlockProducts();
0288       unsigned int numberOfProcessesWithProcessBlockProducts = processesWithProcessBlockProducts.size();
0289       unsigned int numberOfTTrees = numberOfRunLumiEventProductTrees + numberOfProcessesWithProcessBlockProducts;
0290       selectedOutputItemList_.resize(numberOfTTrees);
0291 
0292       for (unsigned int i = InEvent; i < NumBranchTypes; ++i) {
0293         BranchType branchType = static_cast<BranchType>(i);
0294         if (branchType != InProcess) {
0295           std::string processName;
0296           TTree* theInputTree =
0297               (branchType == InEvent ? fb.tree() : (branchType == InLumi ? fb.lumiTree() : fb.runTree()));
0298           OutputItemList& outputItemList = selectedOutputItemList_[branchType];
0299           fillSelectedItemList(branchType, processName, theInputTree, outputItemList);
0300         } else {
0301           // Handle output items in ProcessBlocks
0302           for (unsigned int k = InProcess; k < numberOfTTrees; ++k) {
0303             OutputItemList& outputItemList = selectedOutputItemList_[k];
0304             std::string const& processName = processesWithProcessBlockProducts[k - InProcess];
0305             TTree* theInputTree = fb.processBlockTree(processName);
0306             fillSelectedItemList(branchType, processName, theInputTree, outputItemList);
0307           }
0308         }
0309       }
0310       initializedFromInput_ = true;
0311     }
0312     ++inputFileCount_;
0313     beginInputFile(fb);
0314   }
0315 
0316   void PoolOutputModule::respondToCloseInputFile(FileBlock const& fb) {
0317     if (rootOutputFile_)
0318       rootOutputFile_->respondToCloseInputFile(fb);
0319   }
0320 
0321   void PoolOutputModule::setProcessesWithSelectedMergeableRunProducts(std::set<std::string> const& processes) {
0322     processesWithSelectedMergeableRunProducts_.assign(processes.begin(), processes.end());
0323   }
0324 
0325   PoolOutputModule::~PoolOutputModule() {}
0326 
0327   void PoolOutputModule::write(EventForOutput const& e) {
0328     updateBranchParents(e);
0329     rootOutputFile_->writeOne(e);
0330     if (!statusFileName_.empty()) {
0331       std::ofstream statusFile(statusFileName_.c_str());
0332       statusFile << e.id() << " time: " << std::setprecision(3) << TimeOfDay() << '\n';
0333       statusFile.close();
0334     }
0335   }
0336 
0337   void PoolOutputModule::writeLuminosityBlock(LuminosityBlockForOutput const& lb) {
0338     rootOutputFile_->writeLuminosityBlock(lb);
0339   }
0340 
0341   void PoolOutputModule::writeRun(RunForOutput const& r) {
0342     if (!reg_ or (reg_->size() < r.productRegistry().size())) {
0343       reg_ = std::make_unique<ProductRegistry>(r.productRegistry().productList());
0344     }
0345     rootOutputFile_->writeRun(r);
0346   }
0347 
0348   void PoolOutputModule::writeProcessBlock(ProcessBlockForOutput const& pb) { rootOutputFile_->writeProcessBlock(pb); }
0349 
0350   void PoolOutputModule::reallyCloseFile() {
0351     writeEventAuxiliary();
0352     fillDependencyGraph();
0353     branchParents_.clear();
0354     startEndFile();
0355     writeFileFormatVersion();
0356     writeFileIdentifier();
0357     writeIndexIntoFile();
0358     writeStoredMergeableRunProductMetadata();
0359     writeProcessHistoryRegistry();
0360     writeParameterSetRegistry();
0361     writeProductDescriptionRegistry();
0362     writeParentageRegistry();
0363     writeBranchIDListRegistry();
0364     writeThinnedAssociationsHelper();
0365     writeProductDependencies();  //productDependencies used here
0366     writeProcessBlockHelper();
0367     productDependencies_.clear();
0368     finishEndFile();
0369 
0370     doExtrasAfterCloseFile();
0371   }
0372 
0373   // At some later date, we may move functionality from finishEndFile() to here.
0374   void PoolOutputModule::startEndFile() {}
0375 
0376   void PoolOutputModule::writeFileFormatVersion() { rootOutputFile_->writeFileFormatVersion(); }
0377   void PoolOutputModule::writeFileIdentifier() { rootOutputFile_->writeFileIdentifier(); }
0378   void PoolOutputModule::writeIndexIntoFile() { rootOutputFile_->writeIndexIntoFile(); }
0379   void PoolOutputModule::writeStoredMergeableRunProductMetadata() {
0380     rootOutputFile_->writeStoredMergeableRunProductMetadata();
0381   }
0382   void PoolOutputModule::writeProcessHistoryRegistry() { rootOutputFile_->writeProcessHistoryRegistry(); }
0383   void PoolOutputModule::writeParameterSetRegistry() { rootOutputFile_->writeParameterSetRegistry(); }
0384   void PoolOutputModule::writeProductDescriptionRegistry() {
0385     assert(reg_);
0386     rootOutputFile_->writeProductDescriptionRegistry(*reg_);
0387   }
0388   void PoolOutputModule::writeParentageRegistry() { rootOutputFile_->writeParentageRegistry(); }
0389   void PoolOutputModule::writeBranchIDListRegistry() { rootOutputFile_->writeBranchIDListRegistry(); }
0390   void PoolOutputModule::writeThinnedAssociationsHelper() { rootOutputFile_->writeThinnedAssociationsHelper(); }
0391   void PoolOutputModule::writeProductDependencies() { rootOutputFile_->writeProductDependencies(); }
0392   void PoolOutputModule::writeEventAuxiliary() { rootOutputFile_->writeEventAuxiliary(); }
0393   void PoolOutputModule::writeProcessBlockHelper() { rootOutputFile_->writeProcessBlockHelper(); }
0394   void PoolOutputModule::finishEndFile() {
0395     rootOutputFile_->finishEndFile();
0396     rootOutputFile_ = nullptr;
0397   }  // propagate_const<T> has no reset() function
0398   void PoolOutputModule::doExtrasAfterCloseFile() {}
0399   bool PoolOutputModule::isFileOpen() const { return rootOutputFile_.get() != nullptr; }
0400   bool PoolOutputModule::shouldWeCloseFile() const { return rootOutputFile_->shouldWeCloseFile(); }
0401 
0402   std::pair<std::string, std::string> PoolOutputModule::physicalAndLogicalNameForNewFile() {
0403     if (inputFileCount_ == 0) {
0404       throw edm::Exception(errors::LogicError) << "Attempt to open output file before input file. "
0405                                                << "Please report this to the core framework developers.\n";
0406     }
0407     std::string suffix(".root");
0408     std::string::size_type offset = fileName().rfind(suffix);
0409     bool ext = (offset == fileName().size() - suffix.size());
0410     if (!ext)
0411       suffix.clear();
0412     std::string fileBase(ext ? fileName().substr(0, offset) : fileName());
0413     std::ostringstream ofilename;
0414     std::ostringstream lfilename;
0415     ofilename << fileBase;
0416     lfilename << logicalFileName();
0417     if (outputFileCount_) {
0418       ofilename << std::setw(3) << std::setfill('0') << outputFileCount_;
0419       if (!logicalFileName().empty()) {
0420         lfilename << std::setw(3) << std::setfill('0') << outputFileCount_;
0421       }
0422     }
0423     ofilename << suffix;
0424     ++outputFileCount_;
0425 
0426     return std::make_pair(ofilename.str(), lfilename.str());
0427   }
0428 
0429   void PoolOutputModule::reallyOpenFile() {
0430     auto names = physicalAndLogicalNameForNewFile();
0431     rootOutputFile_ = std::make_unique<RootOutputFile>(this,
0432                                                        names.first,
0433                                                        names.second,
0434                                                        processesWithSelectedMergeableRunProducts_,
0435                                                        overrideGUID_);  // propagate_const<T> has no reset() function
0436     // Override the GUID of the first file only, in order to avoid two
0437     // output files from one Output Module to have identical GUID.
0438     overrideGUID_.clear();
0439   }
0440 
0441   void PoolOutputModule::updateBranchParentsForOneBranch(ProductProvenanceRetriever const* provRetriever,
0442                                                          BranchID const& branchID) {
0443     ProductProvenance const* provenance = provRetriever->branchIDToProvenanceForProducedOnly(branchID);
0444     if (provenance != nullptr) {
0445       BranchParents::iterator it = branchParents_.find(branchID);
0446       if (it == branchParents_.end()) {
0447         it = branchParents_.insert(std::make_pair(branchID, std::set<ParentageID>())).first;
0448       }
0449       it->second.insert(provenance->parentageID());
0450     }
0451   }
0452 
0453   void PoolOutputModule::updateBranchParents(EventForOutput const& e) {
0454     ProductProvenanceRetriever const* provRetriever = e.productProvenanceRetrieverPtr();
0455     if (producedBranches_.empty()) {
0456       for (auto const& prod : e.productRegistry().productList()) {
0457         ProductDescription const& desc = prod.second;
0458         if (desc.produced() && desc.branchType() == InEvent && !desc.isAlias()) {
0459           producedBranches_.emplace_back(desc.branchID());
0460         }
0461       }
0462     }
0463     for (auto const& bid : producedBranches_) {
0464       updateBranchParentsForOneBranch(provRetriever, bid);
0465     }
0466   }
0467 
0468   void PoolOutputModule::preActionBeforeRunEventAsync(WaitingTaskHolder iTask,
0469                                                       ModuleCallingContext const& iModuleCallingContext,
0470                                                       Principal const& iPrincipal) const noexcept {
0471     if (DropAll != dropMetaData_) {
0472       auto const* ep = dynamic_cast<EventPrincipal const*>(&iPrincipal);
0473       if (ep) {
0474         auto pr = ep->productProvenanceRetrieverPtr();
0475         if (pr) {
0476           pr->readProvenanceAsync(iTask, &iModuleCallingContext);
0477         }
0478       }
0479     }
0480   }
0481 
0482   void PoolOutputModule::fillDependencyGraph() {
0483     for (auto const& branchParent : branchParents_) {
0484       BranchID const& child = branchParent.first;
0485       std::set<ParentageID> const& eIds = branchParent.second;
0486       for (auto const& eId : eIds) {
0487         Parentage entryDesc;
0488         ParentageRegistry::instance()->getMapped(eId, entryDesc);
0489         std::vector<BranchID> const& parents = entryDesc.parents();
0490         for (auto const& parent : parents) {
0491           productDependencies_.insertChild(parent, child);
0492         }
0493       }
0494     }
0495   }
0496 
0497   void PoolOutputModule::fillDescription(ParameterSetDescription& desc) {
0498     std::string defaultString;
0499 
0500     desc.setComment("Writes runs, lumis, and events into EDM/ROOT files.");
0501     desc.addUntracked<std::string>("fileName")->setComment("Name of output file.");
0502     desc.addUntracked<std::string>("logicalFileName", defaultString)
0503         ->setComment("Passed to job report. Otherwise unused by module.");
0504     desc.addUntracked<std::string>("catalog", defaultString)
0505         ->setComment("Passed to job report. Otherwise unused by module.");
0506     desc.addUntracked<int>("maxSize", 0x7f000000)
0507         ->setComment(
0508             "Maximum output file size, in kB.\n"
0509             "If over maximum, new output file will be started at next input file transition.");
0510     desc.addUntracked<int>("compressionLevel", 4)->setComment("ROOT compression level of output file.");
0511     desc.addUntracked<std::string>("compressionAlgorithm", "ZSTD")
0512         ->setComment(
0513             "Algorithm used to compress data in the ROOT output file, allowed values are ZLIB, LZMA, LZ4, and ZSTD");
0514     desc.addUntracked<int>("basketSize", 16384)->setComment("Default ROOT basket size in output file.");
0515     desc.addUntracked<int>("eventAuxiliaryBasketSize", 16384)
0516         ->setComment("Default ROOT basket size in output file for EventAuxiliary branch.");
0517     desc.addUntracked<int>("eventAutoFlushCompressedSize", 20 * 1024 * 1024)
0518         ->setComment(
0519             "Set ROOT auto flush stored data size (in bytes) for event TTree. The value sets how large the compressed "
0520             "buffer is allowed to get. The uncompressed buffer can be quite a bit larger than this depending on the "
0521             "average compression ratio. The value of -1 just uses ROOT's default value. The value of 0 turns off this "
0522             "feature. A value of -N changes the behavior to flush after every Nth event.");
0523     desc.addUntracked<int>("splitLevel", 99)->setComment("Default ROOT branch split level in output file.");
0524     desc.addUntracked<std::string>("sortBaskets", std::string("sortbasketsbyoffset"))
0525         ->setComment(
0526             "Legal values: 'sortbasketsbyoffset', 'sortbasketsbybranch', 'sortbasketsbyentry'.\n"
0527             "Used by ROOT when fast copying. Affects performance.");
0528     desc.addUntracked<int>("treeMaxVirtualSize", -1)
0529         ->setComment("Size of ROOT TTree TBasket cache.  Affects performance.");
0530     desc.addUntracked<bool>("fastCloning", true)
0531         ->setComment(
0532             "True:  Allow fast copying, if possible.\n"
0533             "False: Disable fast copying.");
0534     desc.addUntracked("mergeJob", false)
0535         ->setComment(
0536             "If set to true and fast copying is disabled, copy input file compression and basket sizes to the output "
0537             "file.");
0538     desc.addUntracked<bool>("compactEventAuxiliary", false)
0539         ->setComment(
0540             "False: Write EventAuxiliary as we go like any other event metadata branch.\n"
0541             "True:  Optimize the file layout by deferring writing the EventAuxiliary branch until the output file is "
0542             "closed.");
0543     desc.addUntracked<bool>("overrideInputFileSplitLevels", false)
0544         ->setComment(
0545             "False: Use branch split levels and basket sizes from input file, if possible.\n"
0546             "True:  Always use specified or default split levels and basket sizes.");
0547     desc.addUntracked<bool>("writeStatusFile", false)
0548         ->setComment("Write a status file. Intended for use by workflow management.");
0549     desc.addUntracked<std::string>("dropMetaData", defaultString)
0550         ->setComment(
0551             "Determines handling of per product per event metadata.  Options are:\n"
0552             "'NONE':    Keep all of it.\n"
0553             "'DROPPED': Keep it for products produced in current process and all kept products. Drop it for dropped "
0554             "products produced in prior processes.\n"
0555             "'PRIOR':   Keep it for products produced in current process. Drop it for products produced in prior "
0556             "processes.\n"
0557             "'ALL':     Drop all of it.");
0558     desc.addUntracked<std::string>("overrideGUID", defaultString)
0559         ->setComment(
0560             "Allows to override the GUID of the file. Intended to be used only in Tier0 for re-creating files.\n"
0561             "The GUID needs to be of the proper format. If a new output file is started (see maxSize), the GUID of\n"
0562             "the first file only is overridden, i.e. the subsequent output files have different, generated GUID.");
0563     {
0564       ParameterSetDescription dataSet;
0565       dataSet.setAllowAnything();
0566       desc.addUntracked<ParameterSetDescription>("dataset", dataSet)
0567           ->setComment("PSet is only used by Data Operations and not by this module.");
0568     }
0569     {
0570       ParameterSetDescription specialSplit;
0571       specialSplit.addUntracked<std::string>("branch")->setComment(
0572           "Name of branch needing a special split level. The name can contain wildcards '*' and '?'");
0573       specialSplit.addUntracked<int>("splitLevel")->setComment("The special split level for the branch");
0574       desc.addVPSetUntracked("overrideBranchesSplitLevel", specialSplit, std::vector<ParameterSet>());
0575     }
0576     {
0577       ParameterSetDescription alias;
0578       alias.addUntracked<std::string>("branch")->setComment(
0579           "Name of branch which will get alias. The name can contain wildcards '*' and '?'");
0580       alias.addUntracked<std::string>("alias")->setComment("The alias to give to the TBranch");
0581       desc.addVPSetUntracked("branchAliases", alias, std::vector<ParameterSet>());
0582     }
0583     OutputModule::fillDescription(desc);
0584   }
0585 
0586   void PoolOutputModule::fillDescriptions(ConfigurationDescriptions& descriptions) {
0587     ParameterSetDescription desc;
0588     PoolOutputModule::fillDescription(desc);
0589     descriptions.add("edmOutput", desc);
0590   }
0591 }  // namespace edm