Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2023-03-17 11:10:19

0001 #include "DataFormats/Common/interface/setIsMergeable.h"
0002 #include "DataFormats/Provenance/interface/BranchIDListHelper.h"
0003 #include "DataFormats/Provenance/interface/BranchType.h"
0004 #include "DataFormats/Provenance/interface/branchIDToProductID.h"
0005 #include "DataFormats/Provenance/interface/EventSelectionID.h"
0006 #include "DataFormats/Provenance/interface/History.h"
0007 #include "DataFormats/Provenance/interface/ParameterSetBlob.h"
0008 #include "DataFormats/Provenance/interface/ParameterSetID.h"
0009 #include "DataFormats/Provenance/interface/ProcessHistoryRegistry.h"
0010 #include "DataFormats/Provenance/interface/ProductRegistry.h"
0011 #include "DataFormats/Provenance/interface/Parentage.h"
0012 #include "DataFormats/Provenance/interface/ProductProvenance.h"
0013 #include "DataFormats/Provenance/interface/StoredProductProvenance.h"
0014 #include "DataFormats/Provenance/interface/ParentageRegistry.h"
0015 #include "FWCore/Catalog/interface/InputFileCatalog.h"
0016 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0017 #include "FWCore/ParameterSet/interface/Registry.h"
0018 #include "FWCore/Services/interface/setupSiteLocalConfig.h"
0019 
0020 #include "FWCore/Utilities/interface/Algorithms.h"
0021 #include "FWCore/Utilities/interface/Exception.h"
0022 #include "FWCore/Utilities/interface/propagate_const.h"
0023 
0024 #include "TError.h"
0025 #include "TFile.h"
0026 #include "TTree.h"
0027 
0028 #include "boost/program_options.hpp"
0029 
0030 #include <cassert>
0031 #include <iostream>
0032 #include <memory>
0033 #include <map>
0034 #include <optional>
0035 #include <set>
0036 #include <sstream>
0037 #include <vector>
0038 
0039 typedef std::map<std::string, std::vector<edm::BranchDescription>> IdToBranches;
0040 typedef std::map<std::pair<std::string, std::string>, IdToBranches> ModuleToIdBranches;
0041 
0042 static std::ostream& prettyPrint(std::ostream& oStream,
0043                                  edm::ParameterSet const& iPSet,
0044                                  std::string const& iIndent,
0045                                  std::string const& iIndentDelta);
0046 
0047 static std::string const triggerResults = std::string("TriggerResults");
0048 static std::string const triggerPaths = std::string("@trigger_paths");
0049 static std::string const source = std::string("source");
0050 static std::string const input = std::string("@main_input");
0051 
0052 namespace {
0053   typedef std::map<edm::ParameterSetID, edm::ParameterSetBlob> ParameterSetMap;
0054 
0055   class HistoryNode {
0056   public:
0057     HistoryNode() : config_(), simpleId_(0) {}
0058 
0059     HistoryNode(edm::ProcessConfiguration const& iConfig, unsigned int iSimpleId)
0060         : config_(iConfig), simpleId_(iSimpleId) {}
0061 
0062     void addChild(HistoryNode const& child) { children_.push_back(child); }
0063 
0064     edm::ParameterSetID const& parameterSetID() const { return config_.parameterSetID(); }
0065 
0066     std::string const& processName() const { return config_.processName(); }
0067 
0068     std::size_t size() const { return children_.size(); }
0069 
0070     HistoryNode* lastChildAddress() { return &children_.back(); }
0071 
0072     typedef std::vector<HistoryNode>::const_iterator const_iterator;
0073     typedef std::vector<HistoryNode>::iterator iterator;
0074 
0075     iterator begin() { return children_.begin(); }
0076     iterator end() { return children_.end(); }
0077 
0078     const_iterator begin() const { return children_.begin(); }
0079     const_iterator end() const { return children_.end(); }
0080 
0081     void print(std::ostream& os) const {
0082       os << config_.processName() << " '" << config_.passID() << "' '" << config_.releaseVersion() << "' [" << simpleId_
0083          << "]  (" << config_.parameterSetID() << ")" << std::endl;
0084     }
0085 
0086     void printHistory(std::string const& iIndent = std::string("  ")) const;
0087     void printEventSetupHistory(ParameterSetMap const& iPSM,
0088                                 std::vector<std::string> const& iFindMatch,
0089                                 std::ostream& oErrorLog) const;
0090     void printOtherModulesHistory(ParameterSetMap const& iPSM,
0091                                   ModuleToIdBranches const&,
0092                                   std::vector<std::string> const& iFindMatch,
0093                                   std::ostream& oErrorLog) const;
0094     void printTopLevelPSetsHistory(ParameterSetMap const& iPSM,
0095                                    std::vector<std::string> const& iFindMatch,
0096                                    std::ostream& oErrorLog) const;
0097 
0098     edm::ProcessConfigurationID configurationID() const { return config_.id(); }
0099 
0100     static bool sort_;
0101 
0102   private:
0103     edm::ProcessConfiguration config_;
0104     std::vector<HistoryNode> children_;
0105     unsigned int simpleId_;
0106   };
0107 
0108   std::ostream& operator<<(std::ostream& os, HistoryNode const& node) {
0109     node.print(os);
0110     return os;
0111   }
0112   bool HistoryNode::sort_ = false;
0113 }  // namespace
0114 
0115 std::ostream& operator<<(std::ostream& os, edm::ProcessHistory& iHist) {
0116   std::string const indentDelta("  ");
0117   std::string indent = indentDelta;
0118   for (auto const& process : iHist) {
0119     os << indent << process.processName() << " '" << process.passID() << "' '" << process.releaseVersion() << "' ("
0120        << process.parameterSetID() << ")" << std::endl;
0121     indent += indentDelta;
0122   }
0123   return os;
0124 }
0125 
0126 void HistoryNode::printHistory(std::string const& iIndent) const {
0127   std::string const indentDelta("  ");
0128   const std::string& indent = iIndent;
0129   for (auto const& item : *this) {
0130     std::cout << indent << item;
0131     item.printHistory(indent + indentDelta);
0132   }
0133 }
0134 
0135 std::string eventSetupComponent(char const* iType,
0136                                 std::string const& iCompName,
0137                                 edm::ParameterSet const& iProcessConfig,
0138                                 std::string const& iProcessName) {
0139   std::ostringstream result;
0140   edm::ParameterSet const& pset = iProcessConfig.getParameterSet(iCompName);
0141   std::string name(pset.getParameter<std::string>("@module_label"));
0142   if (name.empty()) {
0143     name = pset.getParameter<std::string>("@module_type");
0144   }
0145 
0146   result << iType << ": " << name << " " << iProcessName << "\n"
0147          << " parameters: ";
0148   prettyPrint(result, pset, " ", " ");
0149   return result.str();
0150 }
0151 
0152 void HistoryNode::printEventSetupHistory(ParameterSetMap const& iPSM,
0153                                          std::vector<std::string> const& iFindMatch,
0154                                          std::ostream& oErrorLog) const {
0155   for (auto const& itH : *this) {
0156     //Get ParameterSet for process
0157     ParameterSetMap::const_iterator itFind = iPSM.find(itH.parameterSetID());
0158     if (itFind == iPSM.end()) {
0159       oErrorLog << "No ParameterSetID for " << itH.parameterSetID() << std::endl;
0160     } else {
0161       edm::ParameterSet processConfig(itFind->second.pset());
0162       std::vector<std::string> sourceStrings, moduleStrings;
0163       //get the sources
0164       std::vector<std::string> sources = processConfig.getParameter<std::vector<std::string>>("@all_essources");
0165       for (auto& itM : sources) {
0166         std::string retValue = eventSetupComponent("ESSource", itM, processConfig, itH.processName());
0167         bool foundMatch = true;
0168         if (!iFindMatch.empty()) {
0169           for (auto const& stringToFind : iFindMatch) {
0170             if (retValue.find(stringToFind) == std::string::npos) {
0171               foundMatch = false;
0172               break;
0173             }
0174           }
0175         }
0176         if (foundMatch) {
0177           sourceStrings.push_back(std::move(retValue));
0178         }
0179       }
0180       //get the modules
0181       std::vector<std::string> modules = processConfig.getParameter<std::vector<std::string>>("@all_esmodules");
0182       for (auto& itM : modules) {
0183         std::string retValue = eventSetupComponent("ESModule", itM, processConfig, itH.processName());
0184         bool foundMatch = true;
0185         if (!iFindMatch.empty()) {
0186           for (auto const& stringToFind : iFindMatch) {
0187             if (retValue.find(stringToFind) == std::string::npos) {
0188               foundMatch = false;
0189               break;
0190             }
0191           }
0192         }
0193         if (foundMatch) {
0194           moduleStrings.push_back(std::move(retValue));
0195         }
0196       }
0197       if (sort_) {
0198         std::sort(sourceStrings.begin(), sourceStrings.end());
0199         std::sort(moduleStrings.begin(), moduleStrings.end());
0200       }
0201       std::copy(sourceStrings.begin(), sourceStrings.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
0202       std::copy(moduleStrings.begin(), moduleStrings.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
0203     }
0204     itH.printEventSetupHistory(iPSM, iFindMatch, oErrorLog);
0205   }
0206 }
0207 
0208 std::string nonProducerComponent(std::string const& iCompName,
0209                                  edm::ParameterSet const& iProcessConfig,
0210                                  std::string const& iProcessName) {
0211   std::ostringstream result;
0212   edm::ParameterSet const& pset = iProcessConfig.getParameterSet(iCompName);
0213   std::string label(pset.getParameter<std::string>("@module_label"));
0214 
0215   result << "Module: " << label << " " << iProcessName << "\n"
0216          << " parameters: ";
0217   prettyPrint(result, pset, " ", " ");
0218   return result.str();
0219 }
0220 
0221 void HistoryNode::printOtherModulesHistory(ParameterSetMap const& iPSM,
0222                                            ModuleToIdBranches const& iModules,
0223                                            std::vector<std::string> const& iFindMatch,
0224                                            std::ostream& oErrorLog) const {
0225   for (auto const& itH : *this) {
0226     //Get ParameterSet for process
0227     ParameterSetMap::const_iterator itFind = iPSM.find(itH.parameterSetID());
0228     if (itFind == iPSM.end()) {
0229       oErrorLog << "No ParameterSetID for " << itH.parameterSetID() << std::endl;
0230     } else {
0231       edm::ParameterSet processConfig(itFind->second.pset());
0232       std::vector<std::string> moduleStrings;
0233       //get all modules
0234       std::vector<std::string> modules = processConfig.getParameter<std::vector<std::string>>("@all_modules");
0235       for (auto& itM : modules) {
0236         //if we didn't already handle this from the branches
0237         if (iModules.end() == iModules.find(std::make_pair(itH.processName(), itM))) {
0238           std::string retValue(nonProducerComponent(itM, processConfig, itH.processName()));
0239           bool foundMatch = true;
0240           if (!iFindMatch.empty()) {
0241             for (auto const& stringToFind : iFindMatch) {
0242               if (retValue.find(stringToFind) == std::string::npos) {
0243                 foundMatch = false;
0244                 break;
0245               }
0246             }
0247           }
0248           if (foundMatch) {
0249             moduleStrings.push_back(std::move(retValue));
0250           }
0251         }
0252       }
0253       if (sort_) {
0254         std::sort(moduleStrings.begin(), moduleStrings.end());
0255       }
0256       std::copy(moduleStrings.begin(), moduleStrings.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
0257     }
0258     itH.printOtherModulesHistory(iPSM, iModules, iFindMatch, oErrorLog);
0259   }
0260 }
0261 
0262 static void appendToSet(std::set<std::string>& iSet, std::vector<std::string> const& iFrom) {
0263   for (auto const& n : iFrom) {
0264     iSet.insert(n);
0265   }
0266 }
0267 
0268 static std::string topLevelPSet(std::string const& iName,
0269                                 edm::ParameterSet const& iProcessConfig,
0270                                 std::string const& iProcessName) {
0271   std::ostringstream result;
0272   edm::ParameterSet const& pset = iProcessConfig.getParameterSet(iName);
0273 
0274   result << "PSet: " << iName << " " << iProcessName << "\n"
0275          << " parameters: ";
0276   prettyPrint(result, pset, " ", " ");
0277   return result.str();
0278 }
0279 
0280 void HistoryNode::printTopLevelPSetsHistory(ParameterSetMap const& iPSM,
0281                                             std::vector<std::string> const& iFindMatch,
0282                                             std::ostream& oErrorLog) const {
0283   for (auto const& itH : *this) {
0284     //Get ParameterSet for process
0285     ParameterSetMap::const_iterator itFind = iPSM.find(itH.parameterSetID());
0286     if (itFind == iPSM.end()) {
0287       oErrorLog << "No ParameterSetID for " << itH.parameterSetID() << std::endl;
0288     } else {
0289       edm::ParameterSet processConfig(itFind->second.pset());
0290       //Need to get the names of PSets which are used by the framework (e.g. names of modules)
0291       std::set<std::string> namesToExclude;
0292       appendToSet(namesToExclude, processConfig.getParameter<std::vector<std::string>>("@all_modules"));
0293       appendToSet(namesToExclude, processConfig.getParameter<std::vector<std::string>>("@all_sources"));
0294       appendToSet(namesToExclude, processConfig.getParameter<std::vector<std::string>>("@all_loopers"));
0295       //appendToSet(namesToExclude,processConfig.getParameter<std::vector<std::string> >("@all_subprocesses"));//untracked
0296       appendToSet(namesToExclude, processConfig.getParameter<std::vector<std::string>>("@all_esmodules"));
0297       appendToSet(namesToExclude, processConfig.getParameter<std::vector<std::string>>("@all_essources"));
0298       appendToSet(namesToExclude, processConfig.getParameter<std::vector<std::string>>("@all_esprefers"));
0299       if (processConfig.existsAs<std::vector<std::string>>("all_aliases")) {
0300         appendToSet(namesToExclude, processConfig.getParameter<std::vector<std::string>>("@all_aliases"));
0301       }
0302 
0303       std::vector<std::string> allNames{};
0304       processConfig.getParameterSetNames(allNames);
0305 
0306       std::vector<std::string> results;
0307       for (auto const& name : allNames) {
0308         if (name.empty() || '@' == name[0] || namesToExclude.find(name) != namesToExclude.end()) {
0309           continue;
0310         }
0311         std::string retValue = topLevelPSet(name, processConfig, itH.processName());
0312 
0313         bool foundMatch = true;
0314         if (!iFindMatch.empty()) {
0315           for (auto const& stringToFind : iFindMatch) {
0316             if (retValue.find(stringToFind) == std::string::npos) {
0317               foundMatch = false;
0318               break;
0319             }
0320           }
0321         }
0322         if (foundMatch) {
0323           results.push_back(std::move(retValue));
0324         }
0325       }
0326       if (sort_) {
0327         std::sort(results.begin(), results.end());
0328       }
0329       std::copy(results.begin(), results.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
0330     }
0331     itH.printTopLevelPSetsHistory(iPSM, iFindMatch, oErrorLog);
0332   }
0333 }
0334 
0335 namespace {
0336   std::unique_ptr<TFile> makeTFileWithLookup(std::string const& filename) {
0337     // See if it is a logical file name.
0338     auto operate = edm::setupSiteLocalConfig();
0339     std::string override;
0340     std::vector<std::string> fileNames;
0341     fileNames.push_back(filename);
0342     edm::InputFileCatalog catalog(fileNames, override, true);
0343     if (catalog.fileNames(0)[0] == filename) {
0344       throw cms::Exception("FileNotFound", "RootFile::RootFile()")
0345           << "File " << filename << " was not found or could not be opened.\n";
0346     }
0347     // filename is a valid LFN.
0348     std::unique_ptr<TFile> result(TFile::Open(catalog.fileNames(0)[0].c_str()));
0349     if (!result.get()) {
0350       throw cms::Exception("FileNotFound", "RootFile::RootFile()")
0351           << "File " << fileNames[0] << " was not found or could not be opened.\n";
0352     }
0353     return result;
0354   }
0355 
0356   // Open the input file, returning the TFile object that represents it.
0357   // The returned unique_ptr will not be null. The argument must not be null.
0358   // We first try the file name as a PFN, so that the catalog and related
0359   // services are not loaded unless needed.
0360   std::unique_ptr<TFile> makeTFile(std::string const& filename) {
0361     gErrorIgnoreLevel = kFatal;
0362     std::unique_ptr<TFile> result(TFile::Open(filename.c_str()));
0363     gErrorIgnoreLevel = kError;
0364     if (!result.get()) {
0365       // Try again with catalog.
0366       return makeTFileWithLookup(filename);
0367     }
0368     return result;
0369   }
0370 }  // namespace
0371 
0372 static std::ostream& prettyPrint(std::ostream& os,
0373                                  edm::ParameterSetEntry const& psetEntry,
0374                                  std::string const& iIndent,
0375                                  std::string const& iIndentDelta) {
0376   char const* trackiness = (psetEntry.isTracked() ? "tracked" : "untracked");
0377   os << "PSet " << trackiness << " = (";
0378   prettyPrint(os, psetEntry.pset(), iIndent + iIndentDelta, iIndentDelta);
0379   os << ")";
0380   return os;
0381 }
0382 
0383 static std::ostream& prettyPrint(std::ostream& os,
0384                                  edm::VParameterSetEntry const& vpsetEntry,
0385                                  std::string const& iIndent,
0386                                  std::string const& iIndentDelta) {
0387   std::vector<edm::ParameterSet> const& vps = vpsetEntry.vpset();
0388   os << "VPSet " << (vpsetEntry.isTracked() ? "tracked" : "untracked") << " = ({" << std::endl;
0389   std::string newIndent = iIndent + iIndentDelta;
0390   std::string start;
0391   std::string const between(",\n");
0392   for (auto const& item : vps) {
0393     os << start << newIndent;
0394     prettyPrint(os, item, newIndent, iIndentDelta);
0395     start = between;
0396   }
0397   if (!vps.empty()) {
0398     os << std::endl;
0399   }
0400   os << iIndent << "})";
0401   return os;
0402 }
0403 
0404 static std::ostream& prettyPrint(std::ostream& oStream,
0405                                  edm::ParameterSet const& iPSet,
0406                                  std::string const& iIndent,
0407                                  std::string const& iIndentDelta) {
0408   std::string newIndent = iIndent + iIndentDelta;
0409 
0410   oStream << "{" << std::endl;
0411   for (auto const& item : iPSet.tbl()) {
0412     // indent a bit
0413     oStream << newIndent << item.first << ": " << item.second << std::endl;
0414   }
0415   for (auto const& item : iPSet.psetTable()) {
0416     // indent a bit
0417     edm::ParameterSetEntry const& pe = item.second;
0418     oStream << newIndent << item.first << ": ";
0419     prettyPrint(oStream, pe, iIndent, iIndentDelta);
0420     oStream << std::endl;
0421   }
0422   for (auto const& item : iPSet.vpsetTable()) {
0423     // indent a bit
0424     edm::VParameterSetEntry const& pe = item.second;
0425     oStream << newIndent << item.first << ": ";
0426     prettyPrint(oStream, pe, newIndent, iIndentDelta);
0427     oStream << std::endl;
0428   }
0429   oStream << iIndent << "}";
0430 
0431   return oStream;
0432 }
0433 
0434 class ProvenanceDumper {
0435 public:
0436   // It is illegal to call this constructor with a null pointer; a
0437   // legal C-style string is required.
0438   ProvenanceDumper(std::string const& filename,
0439                    bool showDependencies,
0440                    bool extendedAncestors,
0441                    bool extendedDescendants,
0442                    bool excludeESModules,
0443                    bool showAllModules,
0444                    bool showTopLevelPSets,
0445                    std::vector<std::string> const& findMatch,
0446                    bool dontPrintProducts,
0447                    std::string const& dumpPSetID,
0448                    int productIDEntry);
0449 
0450   ProvenanceDumper(ProvenanceDumper const&) = delete;             // Disallow copying and moving
0451   ProvenanceDumper& operator=(ProvenanceDumper const&) = delete;  // Disallow copying and moving
0452 
0453   // Write the provenenace information to the given stream.
0454   void dump();
0455   void printErrors(std::ostream& os);
0456   int exitCode() const;
0457 
0458 private:
0459   void addAncestors(edm::BranchID const& branchID,
0460                     std::set<edm::BranchID>& ancestorBranchIDs,
0461                     std::ostringstream& sout,
0462                     std::map<edm::BranchID, std::set<edm::ParentageID>>& perProductParentage) const;
0463 
0464   void addDescendants(edm::BranchID const& branchID,
0465                       std::set<edm::BranchID>& descendantBranchIDs,
0466                       std::ostringstream& sout,
0467                       std::map<edm::BranchID, std::set<edm::BranchID>>& parentToChildren) const;
0468 
0469   std::string filename_;
0470   edm::propagate_const<std::unique_ptr<TFile>> inputFile_;
0471   int exitCode_;
0472   std::stringstream errorLog_;
0473   int errorCount_;
0474   edm::ProductRegistry reg_;
0475   edm::ProcessConfigurationVector phc_;
0476   edm::ProcessHistoryVector phv_;
0477   ParameterSetMap psm_;
0478   HistoryNode historyGraph_;
0479   bool showDependencies_;
0480   bool extendedAncestors_;
0481   bool extendedDescendants_;
0482   bool excludeESModules_;
0483   bool showOtherModules_;
0484   bool productRegistryPresent_;
0485   bool showTopLevelPSets_;
0486   std::vector<std::string> findMatch_;
0487   bool dontPrintProducts_;
0488   std::string dumpPSetID_;
0489   int const productIDEntry_;
0490 
0491   void work_();
0492   void dumpProcessHistory_();
0493   void dumpEventFilteringParameterSets_(TFile* file);
0494   void dumpEventFilteringParameterSets(edm::EventSelectionIDVector const& ids);
0495   void dumpParameterSetForID_(edm::ParameterSetID const& id);
0496   std::optional<std::tuple<edm::BranchIDListHelper, std::vector<edm::ProcessIndex>>> makeBranchIDListHelper();
0497 };
0498 
0499 ProvenanceDumper::ProvenanceDumper(std::string const& filename,
0500                                    bool showDependencies,
0501                                    bool extendedAncestors,
0502                                    bool extendedDescendants,
0503                                    bool excludeESModules,
0504                                    bool showOtherModules,
0505                                    bool showTopLevelPSets,
0506                                    std::vector<std::string> const& findMatch,
0507                                    bool dontPrintProducts,
0508                                    std::string const& dumpPSetID,
0509                                    int productIDEntry)
0510     : filename_(filename),
0511       inputFile_(makeTFile(filename)),
0512       exitCode_(0),
0513       errorLog_(),
0514       errorCount_(0),
0515       showDependencies_(showDependencies),
0516       extendedAncestors_(extendedAncestors),
0517       extendedDescendants_(extendedDescendants),
0518       excludeESModules_(excludeESModules),
0519       showOtherModules_(showOtherModules),
0520       productRegistryPresent_(true),
0521       showTopLevelPSets_(showTopLevelPSets),
0522       findMatch_(findMatch),
0523       dontPrintProducts_(dontPrintProducts),
0524       dumpPSetID_(dumpPSetID),
0525       productIDEntry_(productIDEntry) {}
0526 
0527 void ProvenanceDumper::dump() { work_(); }
0528 
0529 void ProvenanceDumper::printErrors(std::ostream& os) {
0530   if (errorCount_ > 0)
0531     os << errorLog_.str() << std::endl;
0532 }
0533 
0534 int ProvenanceDumper::exitCode() const { return exitCode_; }
0535 
0536 void ProvenanceDumper::dumpEventFilteringParameterSets(edm::EventSelectionIDVector const& ids) {
0537   edm::EventSelectionIDVector::size_type num_ids = ids.size();
0538   if (num_ids == 0) {
0539     std::cout << "No event filtering information is available.\n";
0540     std::cout << "------------------------------\n";
0541   } else {
0542     std::cout << "Event filtering information for " << num_ids << " processing steps is available.\n"
0543               << "The ParameterSets will be printed out, "
0544               << "with the oldest printed first.\n";
0545     for (edm::EventSelectionIDVector::size_type i = 0; i != num_ids; ++i) {
0546       dumpParameterSetForID_(ids[i]);
0547     }
0548   }
0549 }
0550 
0551 void ProvenanceDumper::dumpEventFilteringParameterSets_(TFile* file) {
0552   TTree* history = dynamic_cast<TTree*>(file->Get(edm::poolNames::eventHistoryTreeName().c_str()));
0553   if (history != nullptr) {
0554     edm::History h;
0555     edm::History* ph = &h;
0556 
0557     history->SetBranchAddress(edm::poolNames::eventHistoryBranchName().c_str(), &ph);
0558     if (history->GetEntry(0) <= 0) {
0559       std::cout << "No event filtering information is available; the event history tree has no entries\n";
0560     } else {
0561       dumpEventFilteringParameterSets(h.eventSelectionIDs());
0562     }
0563   } else {
0564     TTree* events = dynamic_cast<TTree*>(file->Get(edm::poolNames::eventTreeName().c_str()));
0565     assert(events != nullptr);
0566     TBranch* eventSelectionsBranch = events->GetBranch(edm::poolNames::eventSelectionsBranchName().c_str());
0567     if (eventSelectionsBranch == nullptr)
0568       return;
0569     edm::EventSelectionIDVector ids;
0570     edm::EventSelectionIDVector* pids = &ids;
0571     eventSelectionsBranch->SetAddress(&pids);
0572     if (eventSelectionsBranch->GetEntry(0) <= 0) {
0573       std::cout << "No event filtering information is available; the event selections branch has no entries\n";
0574     } else {
0575       dumpEventFilteringParameterSets(ids);
0576     }
0577   }
0578 }
0579 
0580 void ProvenanceDumper::dumpParameterSetForID_(edm::ParameterSetID const& id) {
0581   std::cout << "ParameterSetID: " << id << '\n';
0582   if (id.isValid()) {
0583     ParameterSetMap::const_iterator i = psm_.find(id);
0584     if (i == psm_.end()) {
0585       std::cout << "We are unable to find the corresponding ParameterSet\n";
0586       edm::ParameterSet empty;
0587       empty.registerIt();
0588       if (id == empty.id()) {
0589         std::cout << "But it would have been empty anyway\n";
0590       }
0591     } else {
0592       edm::ParameterSet ps(i->second.pset());
0593       prettyPrint(std::cout, ps, " ", " ");
0594       std::cout << '\n';
0595     }
0596   } else {
0597     std::cout << "This ID is not valid\n";
0598   }
0599   std::cout << "     -------------------------\n";
0600 }
0601 
0602 void ProvenanceDumper::dumpProcessHistory_() {
0603   std::cout << "Processing History:" << std::endl;
0604   std::map<edm::ProcessConfigurationID, unsigned int> simpleIDs;
0605   for (auto const& ph : phv_) {
0606     //loop over the history entries looking for matches
0607     HistoryNode* parent = &historyGraph_;
0608     for (auto const& pc : ph) {
0609       if (parent->size() == 0) {
0610         unsigned int id = simpleIDs[pc.id()];
0611         if (0 == id) {
0612           id = 1;
0613           simpleIDs[pc.id()] = id;
0614         }
0615         parent->addChild(HistoryNode(pc, id));
0616         parent = parent->lastChildAddress();
0617       } else {
0618         //see if this is unique
0619         bool isUnique = true;
0620         for (auto& child : *parent) {
0621           if (child.configurationID() == pc.id()) {
0622             isUnique = false;
0623             parent = &child;
0624             break;
0625           }
0626         }
0627         if (isUnique) {
0628           simpleIDs[pc.id()] = parent->size() + 1;
0629           parent->addChild(HistoryNode(pc, simpleIDs[pc.id()]));
0630           parent = parent->lastChildAddress();
0631         }
0632       }
0633     }
0634   }
0635   historyGraph_.printHistory();
0636 }
0637 
0638 std::optional<std::tuple<edm::BranchIDListHelper, std::vector<edm::ProcessIndex>>>
0639 ProvenanceDumper::makeBranchIDListHelper() {
0640   // BranchID-to-ProductID mapping disabled
0641   if (productIDEntry_ < 0) {
0642     return {};
0643   }
0644 
0645   TTree* metaTree = dynamic_cast<TTree*>(inputFile_->Get(edm::poolNames::metaDataTreeName().c_str()));
0646   if (nullptr == metaTree) {
0647     //std::cerr << "Did not find " << edm::poolNames::metaDataTreeName() << " tree" << std::endl;
0648     return {};
0649   }
0650 
0651   TBranch* branchIDListsBranch = metaTree->GetBranch(edm::poolNames::branchIDListBranchName().c_str());
0652   if (nullptr == branchIDListsBranch) {
0653     /*
0654     std::cerr << "Did not find " << edm::poolNames::branchIDListBranchName() << " from "
0655               << edm::poolNames::metaDataTreeName() << " tree" << std::endl;
0656     */
0657     return {};
0658   }
0659 
0660   edm::BranchIDLists branchIDLists;
0661   edm::BranchIDLists* branchIDListsPtr = &branchIDLists;
0662   branchIDListsBranch->SetAddress(&branchIDListsPtr);
0663   if (branchIDListsBranch->GetEntry(0) <= 0) {
0664     //std::cerr << "Failed to read an entry from " << edm::poolNames::branchIDListBranchName() << std::endl;
0665     return {};
0666   }
0667 
0668   edm::BranchIDListHelper branchIDListHelper;
0669   branchIDListHelper.updateFromInput(branchIDLists);
0670 
0671   TTree* events = dynamic_cast<TTree*>(inputFile_->Get(edm::poolNames::eventTreeName().c_str()));
0672   assert(events != nullptr);
0673   TBranch* branchListIndexesBranch = events->GetBranch(edm::poolNames::branchListIndexesBranchName().c_str());
0674   if (nullptr == branchListIndexesBranch) {
0675     /*
0676     std::cerr << "Did not find " << edm::poolNames::branchListIndexesBranchName() << " from "
0677               << edm::poolNames::eventTreeName() << " tree" << std::endl;
0678     */
0679     return {};
0680   }
0681   edm::BranchListIndexes branchListIndexes;
0682   edm::BranchListIndexes* pbranchListIndexes = &branchListIndexes;
0683   branchListIndexesBranch->SetAddress(&pbranchListIndexes);
0684   if (branchListIndexesBranch->GetEntry(productIDEntry_) <= 0 or branchListIndexes.empty()) {
0685     /*
0686     std::cerr << "Failed to read entry from " << edm::poolNames::branchListIndexesBranchName() << ", or it is empty"
0687               << std::endl;
0688     */
0689     return {};
0690   }
0691 
0692   if (not branchIDListHelper.fixBranchListIndexes(branchListIndexes)) {
0693     //std::cerr << "Call to branchIDListHelper.fixBranchListIndexes() failed" << std::endl;
0694     return {};
0695   }
0696 
0697   // Fill in helper map for Branch to ProductID mapping
0698   auto branchListIndexToProcessIndex = edm::makeBranchListIndexToProcessIndex(branchListIndexes);
0699 
0700   return std::tuple(std::move(branchIDListHelper), std::move(branchListIndexToProcessIndex));
0701 }
0702 
0703 void ProvenanceDumper::work_() {
0704   TTree* meta = dynamic_cast<TTree*>(inputFile_->Get(edm::poolNames::metaDataTreeName().c_str()));
0705   assert(nullptr != meta);
0706 
0707   edm::ProductRegistry* pReg = &reg_;
0708   if (meta->FindBranch(edm::poolNames::productDescriptionBranchName().c_str()) != nullptr) {
0709     meta->SetBranchAddress(edm::poolNames::productDescriptionBranchName().c_str(), &pReg);
0710   } else {
0711     productRegistryPresent_ = false;
0712   }
0713 
0714   ParameterSetMap* pPsm = &psm_;
0715   if (meta->FindBranch(edm::poolNames::parameterSetMapBranchName().c_str()) != nullptr) {
0716     meta->SetBranchAddress(edm::poolNames::parameterSetMapBranchName().c_str(), &pPsm);
0717   } else {
0718     TTree* psetTree = dynamic_cast<TTree*>(inputFile_->Get(edm::poolNames::parameterSetsTreeName().c_str()));
0719     assert(nullptr != psetTree);
0720     typedef std::pair<edm::ParameterSetID, edm::ParameterSetBlob> IdToBlobs;
0721     IdToBlobs idToBlob;
0722     IdToBlobs* pIdToBlob = &idToBlob;
0723     psetTree->SetBranchAddress(edm::poolNames::idToParameterSetBlobsBranchName().c_str(), &pIdToBlob);
0724     for (long long i = 0; i != psetTree->GetEntries(); ++i) {
0725       psetTree->GetEntry(i);
0726       psm_.insert(idToBlob);
0727     }
0728   }
0729 
0730   edm::ProcessHistoryVector* pPhv = &phv_;
0731   if (meta->FindBranch(edm::poolNames::processHistoryBranchName().c_str()) != nullptr) {
0732     meta->SetBranchAddress(edm::poolNames::processHistoryBranchName().c_str(), &pPhv);
0733   }
0734 
0735   edm::ProcessHistoryMap phm;
0736   edm::ProcessHistoryMap* pPhm = &phm;
0737   if (meta->FindBranch(edm::poolNames::processHistoryMapBranchName().c_str()) != nullptr) {
0738     meta->SetBranchAddress(edm::poolNames::processHistoryMapBranchName().c_str(), &pPhm);
0739   }
0740 
0741   if (meta->FindBranch(edm::poolNames::moduleDescriptionMapBranchName().c_str()) != nullptr) {
0742     if (meta->GetBranch(edm::poolNames::moduleDescriptionMapBranchName().c_str())->GetSplitLevel() != 0) {
0743       meta->SetBranchStatus((edm::poolNames::moduleDescriptionMapBranchName() + ".*").c_str(), false);
0744     } else {
0745       meta->SetBranchStatus(edm::poolNames::moduleDescriptionMapBranchName().c_str(), false);
0746     }
0747   }
0748 
0749   meta->GetEntry(0);
0750   assert(nullptr != pReg);
0751 
0752   edm::pset::Registry& psetRegistry = *edm::pset::Registry::instance();
0753   for (auto const& item : psm_) {
0754     edm::ParameterSet pset(item.second.pset());
0755     pset.setID(item.first);
0756     psetRegistry.insertMapped(pset);
0757   }
0758 
0759   if (!phv_.empty()) {
0760     for (auto const& history : phv_) {
0761       for (auto const& process : history) {
0762         phc_.push_back(process);
0763       }
0764     }
0765     edm::sort_all(phc_);
0766     phc_.erase(std::unique(phc_.begin(), phc_.end()), phc_.end());
0767 
0768   }
0769   // backward compatibility
0770   else if (!phm.empty()) {
0771     for (auto const& history : phm) {
0772       phv_.push_back(history.second);
0773       for (auto const& process : history.second) {
0774         phc_.push_back(process);
0775       }
0776     }
0777     edm::sort_all(phc_);
0778     phc_.erase(std::unique(phc_.begin(), phc_.end()), phc_.end());
0779   }
0780 
0781   if (!dumpPSetID_.empty()) {
0782     edm::ParameterSetID psetID;
0783     try {
0784       psetID = edm::ParameterSetID(dumpPSetID_);
0785     } catch (cms::Exception const& x) {
0786       throw cms::Exception("Command Line Argument")
0787           << "Illegal ParameterSetID string. It should contain 32 hexadecimal characters";
0788     }
0789     dumpParameterSetForID_(psetID);
0790     return;
0791   }
0792 
0793   // Helper to map BranchID to ProductID (metadata tree needed also for parentage information)
0794   auto branchIDListHelperAndToProcessIndex = makeBranchIDListHelper();
0795 
0796   //Prepare the parentage information if requested
0797   std::map<edm::BranchID, std::set<edm::ParentageID>> perProductParentage;
0798 
0799   if (showDependencies_ || extendedAncestors_ || extendedDescendants_) {
0800     TTree* parentageTree = dynamic_cast<TTree*>(inputFile_->Get(edm::poolNames::parentageTreeName().c_str()));
0801     if (nullptr == parentageTree) {
0802       std::cerr << "ERROR, no Parentage tree available so cannot show dependencies, ancestors, or descendants.\n";
0803       std::cerr << "Possibly this is not a standard EDM format file. For example, dependency, ancestor, and\n";
0804       std::cerr << "descendant options to edmProvDump will not work with nanoAOD format files.\n\n";
0805       showDependencies_ = false;
0806       extendedAncestors_ = false;
0807       extendedDescendants_ = false;
0808     } else {
0809       edm::ParentageRegistry& registry = *edm::ParentageRegistry::instance();
0810 
0811       std::vector<edm::ParentageID> orderedParentageIDs;
0812       orderedParentageIDs.reserve(parentageTree->GetEntries());
0813       for (Long64_t i = 0, numEntries = parentageTree->GetEntries(); i < numEntries; ++i) {
0814         edm::Parentage parentageBuffer;
0815         edm::Parentage* pParentageBuffer = &parentageBuffer;
0816         parentageTree->SetBranchAddress(edm::poolNames::parentageBranchName().c_str(), &pParentageBuffer);
0817         parentageTree->GetEntry(i);
0818         registry.insertMapped(parentageBuffer);
0819         orderedParentageIDs.push_back(parentageBuffer.id());
0820       }
0821       parentageTree->SetBranchAddress(edm::poolNames::parentageBranchName().c_str(), nullptr);
0822 
0823       TTree* eventMetaTree =
0824           dynamic_cast<TTree*>(inputFile_->Get(edm::BranchTypeToMetaDataTreeName(edm::InEvent).c_str()));
0825       if (nullptr == eventMetaTree) {
0826         eventMetaTree = dynamic_cast<TTree*>(inputFile_->Get(edm::BranchTypeToProductTreeName(edm::InEvent).c_str()));
0827       }
0828       if (nullptr == eventMetaTree) {
0829         std::cerr << "ERROR, no '" << edm::BranchTypeToProductTreeName(edm::InEvent)
0830                   << "' Tree in file so can not show dependencies\n";
0831         showDependencies_ = false;
0832         extendedAncestors_ = false;
0833         extendedDescendants_ = false;
0834       } else {
0835         TBranch* storedProvBranch =
0836             eventMetaTree->GetBranch(edm::BranchTypeToProductProvenanceBranchName(edm::InEvent).c_str());
0837 
0838         if (nullptr != storedProvBranch) {
0839           std::vector<edm::StoredProductProvenance> info;
0840           std::vector<edm::StoredProductProvenance>* pInfo = &info;
0841           storedProvBranch->SetAddress(&pInfo);
0842           for (Long64_t i = 0, numEntries = eventMetaTree->GetEntries(); i < numEntries; ++i) {
0843             storedProvBranch->GetEntry(i);
0844             for (auto const& item : info) {
0845               edm::BranchID bid(item.branchID_);
0846               perProductParentage[bid].insert(orderedParentageIDs.at(item.parentageIDIndex_));
0847             }
0848           }
0849         } else {
0850           //backwards compatible check
0851           TBranch* productProvBranch =
0852               eventMetaTree->GetBranch(edm::BranchTypeToBranchEntryInfoBranchName(edm::InEvent).c_str());
0853           if (nullptr != productProvBranch) {
0854             std::vector<edm::ProductProvenance> info;
0855             std::vector<edm::ProductProvenance>* pInfo = &info;
0856             productProvBranch->SetAddress(&pInfo);
0857             for (Long64_t i = 0, numEntries = eventMetaTree->GetEntries(); i < numEntries; ++i) {
0858               productProvBranch->GetEntry(i);
0859               for (auto const& item : info) {
0860                 perProductParentage[item.branchID()].insert(item.parentageID());
0861               }
0862             }
0863           } else {
0864             std::cerr << " ERROR, could not find provenance information so can not show dependencies\n";
0865             showDependencies_ = false;
0866             extendedAncestors_ = false;
0867             extendedDescendants_ = false;
0868           }
0869         }
0870       }
0871     }
0872   }
0873 
0874   std::map<edm::BranchID, std::set<edm::BranchID>> parentToChildren;
0875   edm::ParentageRegistry& registry = *edm::ParentageRegistry::instance();
0876 
0877   if (extendedDescendants_) {
0878     for (auto const& itParentageSet : perProductParentage) {
0879       edm::BranchID childBranchID = itParentageSet.first;
0880       for (auto const& itParentageID : itParentageSet.second) {
0881         edm::Parentage const* parentage = registry.getMapped(itParentageID);
0882         if (nullptr != parentage) {
0883           for (auto const& branch : parentage->parents()) {
0884             parentToChildren[branch].insert(childBranchID);
0885           }
0886         } else {
0887           std::cerr << "  ERROR:parentage info not in registry ParentageID=" << itParentageID << std::endl;
0888         }
0889       }
0890     }
0891   }
0892 
0893   dumpEventFilteringParameterSets_(inputFile_.get());
0894 
0895   dumpProcessHistory_();
0896 
0897   if (productRegistryPresent_) {
0898     std::cout << "---------Producers with data in file---------" << std::endl;
0899   }
0900 
0901   //using edm::ParameterSetID as the key does not work
0902   //   typedef std::map<edm::ParameterSetID, std::vector<edm::BranchDescription> > IdToBranches
0903   ModuleToIdBranches moduleToIdBranches;
0904   //IdToBranches idToBranches;
0905 
0906   std::map<edm::BranchID, std::string> branchIDToBranchName;
0907 
0908   for (auto const& processConfig : phc_) {
0909     edm::ParameterSet const* processParameterSet =
0910         edm::pset::Registry::instance()->getMapped(processConfig.parameterSetID());
0911     if (nullptr == processParameterSet || processParameterSet->empty()) {
0912       continue;
0913     }
0914     for (auto& item : reg_.productListUpdator()) {
0915       auto& product = item.second;
0916       if (product.processName() != processConfig.processName()) {
0917         continue;
0918       }
0919       //force it to rebuild the branch name
0920       product.init();
0921       setIsMergeable(product);
0922 
0923       if (showDependencies_ || extendedAncestors_ || extendedDescendants_) {
0924         branchIDToBranchName[product.branchID()] = product.branchName();
0925       }
0926       /*
0927         std::cout << product.branchName()
0928         << " id " << product.productID() << std::endl;
0929       */
0930       std::string moduleLabel = product.moduleLabel();
0931       if (moduleLabel == source) {
0932         moduleLabel = input;
0933       } else if (moduleLabel == triggerResults) {
0934         moduleLabel = triggerPaths;
0935       }
0936 
0937       std::stringstream s;
0938 
0939       if (processParameterSet->existsAs<edm::ParameterSet>(moduleLabel)) {
0940         edm::ParameterSet const& moduleParameterSet = processParameterSet->getParameterSet(moduleLabel);
0941         if (!moduleParameterSet.isRegistered()) {
0942           edm::ParameterSet moduleParameterSetCopy = processParameterSet->getParameterSet(moduleLabel);
0943           moduleParameterSetCopy.registerIt();
0944           s << moduleParameterSetCopy.id();
0945         } else {
0946           s << moduleParameterSet.id();
0947         }
0948         moduleToIdBranches[std::make_pair(product.processName(), product.moduleLabel())][s.str()].push_back(product);
0949       }
0950     }
0951   }
0952 
0953   for (auto const& item : moduleToIdBranches) {
0954     std::ostringstream sout;
0955     sout << "Module: " << item.first.second << " " << item.first.first << std::endl;
0956     std::set<edm::BranchID> allBranchIDsForLabelAndProcess;
0957     IdToBranches const& idToBranches = item.second;
0958     for (auto const& idBranch : idToBranches) {
0959       sout << " PSet id:" << idBranch.first << std::endl;
0960       if (!dontPrintProducts_) {
0961         sout << " products: {" << std::endl;
0962       }
0963       std::set<edm::BranchID> branchIDs;
0964       for (auto const& branch : idBranch.second) {
0965         if (!dontPrintProducts_) {
0966           sout << "  " << branch.branchName();
0967           edm::ProductID id;
0968           if (branchIDListHelperAndToProcessIndex) {
0969             sout << " ProductID "
0970                  << edm::branchIDToProductID(branch.branchID(),
0971                                              std::get<0>(*branchIDListHelperAndToProcessIndex),
0972                                              std::get<1>(*branchIDListHelperAndToProcessIndex));
0973           } else {
0974             sout << " BranchID " << branch.branchID();
0975           }
0976           sout << std::endl;
0977         }
0978         branchIDs.insert(branch.branchID());
0979         allBranchIDsForLabelAndProcess.insert(branch.branchID());
0980       }
0981       sout << " }" << std::endl;
0982       edm::ParameterSetID psid(idBranch.first);
0983       ParameterSetMap::const_iterator itpsm = psm_.find(psid);
0984       if (psm_.end() == itpsm) {
0985         ++errorCount_;
0986         errorLog_ << "No ParameterSetID for " << psid << std::endl;
0987         exitCode_ = 1;
0988       } else {
0989         sout << " parameters: ";
0990         prettyPrint(sout, edm::ParameterSet((*itpsm).second.pset()), " ", " ");
0991         sout << std::endl;
0992       }
0993       if (showDependencies_) {
0994         sout << " dependencies: {" << std::endl;
0995         std::set<edm::ParentageID> parentageIDs;
0996         for (auto const& branch : branchIDs) {
0997           //Save these BranchIDs
0998           std::set<edm::ParentageID> const& temp = perProductParentage[branch];
0999           parentageIDs.insert(temp.begin(), temp.end());
1000         }
1001         for (auto const& parentID : parentageIDs) {
1002           edm::Parentage const* parentage = registry.getMapped(parentID);
1003           if (nullptr != parentage) {
1004             for (auto const& branch : parentage->parents()) {
1005               sout << "  " << branchIDToBranchName[branch] << std::endl;
1006             }
1007           } else {
1008             sout << "  ERROR:parentage info not in registry ParentageID=" << parentID << std::endl;
1009           }
1010         }
1011         if (parentageIDs.empty()) {
1012           sout << "  no dependencies recorded (event may not contain data from this module)" << std::endl;
1013         }
1014         sout << " }" << std::endl;
1015       }
1016     }  // end loop over PSetIDs
1017     if (extendedAncestors_) {
1018       sout << " extendedAncestors: {" << std::endl;
1019       std::set<edm::BranchID> ancestorBranchIDs;
1020       for (auto const& branchID : allBranchIDsForLabelAndProcess) {
1021         addAncestors(branchID, ancestorBranchIDs, sout, perProductParentage);
1022       }
1023       for (auto const& ancestorBranchID : ancestorBranchIDs) {
1024         sout << "  " << branchIDToBranchName[ancestorBranchID] << "\n";
1025       }
1026       sout << " }" << std::endl;
1027     }
1028 
1029     if (extendedDescendants_) {
1030       sout << " extendedDescendants: {" << std::endl;
1031       std::set<edm::BranchID> descendantBranchIDs;
1032       for (auto const& branchID : allBranchIDsForLabelAndProcess) {
1033         addDescendants(branchID, descendantBranchIDs, sout, parentToChildren);
1034       }
1035       for (auto const& descendantBranchID : descendantBranchIDs) {
1036         sout << "  " << branchIDToBranchName[descendantBranchID] << "\n";
1037       }
1038       sout << " }" << std::endl;
1039     }
1040     bool foundMatch = true;
1041     if (!findMatch_.empty()) {
1042       for (auto const& stringToFind : findMatch_) {
1043         if (sout.str().find(stringToFind) == std::string::npos) {
1044           foundMatch = false;
1045           break;
1046         }
1047       }
1048     }
1049     if (foundMatch) {
1050       std::cout << sout.str() << std::endl;
1051     }
1052   }  // end loop over module label/process
1053 
1054   if (productRegistryPresent_ && showOtherModules_) {
1055     std::cout << "---------Other Modules---------" << std::endl;
1056     historyGraph_.printOtherModulesHistory(psm_, moduleToIdBranches, findMatch_, errorLog_);
1057   } else if (!productRegistryPresent_) {
1058     std::cout << "---------All Modules---------" << std::endl;
1059     historyGraph_.printOtherModulesHistory(psm_, moduleToIdBranches, findMatch_, errorLog_);
1060   }
1061 
1062   if (!excludeESModules_) {
1063     std::cout << "---------EventSetup---------" << std::endl;
1064     historyGraph_.printEventSetupHistory(psm_, findMatch_, errorLog_);
1065   }
1066 
1067   if (showTopLevelPSets_) {
1068     std::cout << "---------Top Level PSets---------" << std::endl;
1069     historyGraph_.printTopLevelPSetsHistory(psm_, findMatch_, errorLog_);
1070   }
1071   if (errorCount_ != 0) {
1072     exitCode_ = 1;
1073   }
1074 }
1075 
1076 void ProvenanceDumper::addAncestors(edm::BranchID const& branchID,
1077                                     std::set<edm::BranchID>& ancestorBranchIDs,
1078                                     std::ostringstream& sout,
1079                                     std::map<edm::BranchID, std::set<edm::ParentageID>>& perProductParentage) const {
1080   edm::ParentageRegistry& registry = *edm::ParentageRegistry::instance();
1081 
1082   std::set<edm::ParentageID> const& parentIDs = perProductParentage[branchID];
1083   for (auto const& parentageID : parentIDs) {
1084     edm::Parentage const* parentage = registry.getMapped(parentageID);
1085     if (nullptr != parentage) {
1086       for (auto const& branch : parentage->parents()) {
1087         if (ancestorBranchIDs.insert(branch).second) {
1088           addAncestors(branch, ancestorBranchIDs, sout, perProductParentage);
1089         }
1090       }
1091     } else {
1092       sout << "  ERROR:parentage info not in registry ParentageID=" << parentageID << std::endl;
1093     }
1094   }
1095 }
1096 
1097 void ProvenanceDumper::addDescendants(edm::BranchID const& branchID,
1098                                       std::set<edm::BranchID>& descendantBranchIDs,
1099                                       std::ostringstream& sout,
1100                                       std::map<edm::BranchID, std::set<edm::BranchID>>& parentToChildren) const {
1101   for (auto const& childBranchID : parentToChildren[branchID]) {
1102     if (descendantBranchIDs.insert(childBranchID).second) {
1103       addDescendants(childBranchID, descendantBranchIDs, sout, parentToChildren);
1104     }
1105   }
1106 }
1107 
1108 static char const* const kSortOpt = "sort";
1109 static char const* const kSortCommandOpt = "sort,s";
1110 static char const* const kDependenciesOpt = "dependencies";
1111 static char const* const kDependenciesCommandOpt = "dependencies,d";
1112 static char const* const kExtendedAncestorsOpt = "extendedAncestors";
1113 static char const* const kExtendedAncestorsCommandOpt = "extendedAncestors,x";
1114 static char const* const kExtendedDescendantsOpt = "extendedDescendants";
1115 static char const* const kExtendedDescendantsCommandOpt = "extendedDescendants,c";
1116 static char const* const kExcludeESModulesOpt = "excludeESModules";
1117 static char const* const kExcludeESModulesCommandOpt = "excludeESModules,e";
1118 static char const* const kShowAllModulesOpt = "showAllModules";
1119 static char const* const kShowAllModulesCommandOpt = "showAllModules,a";
1120 static char const* const kFindMatchOpt = "findMatch";
1121 static char const* const kFindMatchCommandOpt = "findMatch,f";
1122 static char const* const kDontPrintProductsOpt = "dontPrintProducts";
1123 static char const* const kDontPrintProductsCommandOpt = "dontPrintProducts,p";
1124 static char const* const kShowTopLevelPSetsOpt = "showTopLevelPSets";
1125 static char const* const kShowTopLevelPSetsCommandOpt = "showTopLevelPSets,t";
1126 static char const* const kHelpOpt = "help";
1127 static char const* const kHelpCommandOpt = "help,h";
1128 static char const* const kFileNameOpt = "input-file";
1129 static char const* const kDumpPSetIDOpt = "dumpPSetID";
1130 static char const* const kDumpPSetIDCommandOpt = "dumpPSetID,i";
1131 static char const* const kProductIDEntryOpt = "productIDEntry";
1132 
1133 int main(int argc, char* argv[]) {
1134   using namespace boost::program_options;
1135 
1136   std::string descString(argv[0]);
1137   descString += " [options] <filename>";
1138   descString += "\nAllowed options";
1139   options_description desc(descString);
1140 
1141   // clang-format off
1142   desc.add_options()(kHelpCommandOpt, "show help message")(kSortCommandOpt, "alphabetially sort EventSetup components")(
1143       kDependenciesCommandOpt, "print what data each EDProducer is directly dependent upon")(
1144       kExtendedAncestorsCommandOpt, "print what data each EDProducer is dependent upon including indirect dependences")(
1145       kExtendedDescendantsCommandOpt,
1146       "print what data depends on the data each EDProducer produces including indirect dependences")(
1147       kExcludeESModulesCommandOpt, "do not print ES module information")(
1148       kShowAllModulesCommandOpt, "show all modules (not just those that created data in the file)")(
1149       kShowTopLevelPSetsCommandOpt, "show all top level PSets")(
1150       kFindMatchCommandOpt,
1151       boost::program_options::value<std::vector<std::string>>(),
1152       "show only modules whose information contains the matching string (or all the matching strings, this option can "
1153       "be repeated with different strings)")(kDontPrintProductsCommandOpt, "do not print products produced by module")(
1154       kDumpPSetIDCommandOpt,
1155       value<std::string>(),
1156       "print the parameter set associated with the parameter set ID string (and print nothing else)")(
1157       kProductIDEntryOpt,
1158       value<int>(),
1159       "show ProductID instead of BranchID using the specified entry in the Events tree");
1160   // clang-format on
1161 
1162   //we don't want users to see these in the help messages since this
1163   // name only exists since the parser needs it
1164   options_description hidden;
1165   hidden.add_options()(kFileNameOpt, value<std::string>(), "file name");
1166 
1167   //full list of options for the parser
1168   options_description cmdline_options;
1169   cmdline_options.add(desc).add(hidden);
1170 
1171   positional_options_description p;
1172   p.add(kFileNameOpt, -1);
1173 
1174   variables_map vm;
1175   try {
1176     store(command_line_parser(argc, argv).options(cmdline_options).positional(p).run(), vm);
1177     notify(vm);
1178   } catch (error const& iException) {
1179     std::cerr << iException.what();
1180     return 1;
1181   }
1182 
1183   if (vm.count(kHelpOpt)) {
1184     std::cout << desc << std::endl;
1185     return 0;
1186   }
1187 
1188   if (vm.count(kSortOpt)) {
1189     HistoryNode::sort_ = true;
1190   }
1191 
1192   bool showDependencies = false;
1193   if (vm.count(kDependenciesOpt)) {
1194     showDependencies = true;
1195   }
1196 
1197   bool extendedAncestors = false;
1198   if (vm.count(kExtendedAncestorsOpt)) {
1199     extendedAncestors = true;
1200   }
1201 
1202   bool extendedDescendants = false;
1203   if (vm.count(kExtendedDescendantsOpt)) {
1204     extendedDescendants = true;
1205   }
1206 
1207   bool excludeESModules = false;
1208   if (vm.count(kExcludeESModulesOpt)) {
1209     excludeESModules = true;
1210   }
1211 
1212   bool showAllModules = false;
1213   if (vm.count(kShowAllModulesOpt)) {
1214     showAllModules = true;
1215   }
1216 
1217   bool showTopLevelPSets = false;
1218   if (vm.count(kShowTopLevelPSetsOpt)) {
1219     showTopLevelPSets = true;
1220   }
1221 
1222   std::string fileName;
1223   if (vm.count(kFileNameOpt)) {
1224     try {
1225       fileName = vm[kFileNameOpt].as<std::string>();
1226     } catch (boost::bad_any_cast const& e) {
1227       std::cout << e.what() << std::endl;
1228       return 2;
1229     }
1230   } else {
1231     std::cout << "Data file not specified." << std::endl;
1232     std::cout << desc << std::endl;
1233     return 2;
1234   }
1235 
1236   std::string dumpPSetID;
1237   if (vm.count(kDumpPSetIDOpt)) {
1238     try {
1239       dumpPSetID = vm[kDumpPSetIDOpt].as<std::string>();
1240     } catch (boost::bad_any_cast const& e) {
1241       std::cout << e.what() << std::endl;
1242       return 2;
1243     }
1244   }
1245 
1246   std::vector<std::string> findMatch;
1247   if (vm.count(kFindMatchOpt)) {
1248     try {
1249       findMatch = vm[kFindMatchOpt].as<std::vector<std::string>>();
1250     } catch (boost::bad_any_cast const& e) {
1251       std::cout << e.what() << std::endl;
1252       return 2;
1253     }
1254   }
1255 
1256   bool dontPrintProducts = false;
1257   if (vm.count(kDontPrintProductsOpt)) {
1258     dontPrintProducts = true;
1259   }
1260 
1261   int productIDEntry = -1;
1262   if (vm.count(kProductIDEntryOpt)) {
1263     try {
1264       productIDEntry = vm[kProductIDEntryOpt].as<int>();
1265     } catch (boost::bad_any_cast const& e) {
1266       std::cout << e.what() << std::endl;
1267       return 2;
1268     }
1269   }
1270 
1271   //silence ROOT warnings about missing dictionaries
1272   gErrorIgnoreLevel = kError;
1273 
1274   ProvenanceDumper dumper(fileName,
1275                           showDependencies,
1276                           extendedAncestors,
1277                           extendedDescendants,
1278                           excludeESModules,
1279                           showAllModules,
1280                           showTopLevelPSets,
1281                           findMatch,
1282                           dontPrintProducts,
1283                           dumpPSetID,
1284                           productIDEntry);
1285   int exitCode(0);
1286   try {
1287     dumper.dump();
1288     exitCode = dumper.exitCode();
1289   } catch (cms::Exception const& x) {
1290     std::cerr << "cms::Exception caught\n";
1291     std::cerr << x.what() << '\n';
1292     exitCode = 2;
1293   } catch (std::exception& x) {
1294     std::cerr << "std::exception caught\n";
1295     std::cerr << x.what() << '\n';
1296     exitCode = 3;
1297   } catch (...) {
1298     std::cerr << "Unknown exception caught\n";
1299     exitCode = 4;
1300   }
1301 
1302   dumper.printErrors(std::cerr);
1303   return exitCode;
1304 }