Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2025-03-10 23:53:32

0001 // -*- C++ -*-
0002 //
0003 // Package:     FwkIO
0004 // Class  :     DQMRootOutputModule
0005 //
0006 // Implementation:
0007 //     [Notes on implementation]
0008 //
0009 // Original Author:  Chris Jones
0010 //         Created:  Fri Apr 29 13:26:29 CDT 2011
0011 //
0012 
0013 // system include files
0014 #include <algorithm>
0015 #include <iostream>
0016 #include <memory>
0017 
0018 #include <map>
0019 #include <memory>
0020 #include <string>
0021 #include <vector>
0022 
0023 #include "TFile.h"
0024 #include "TTree.h"
0025 #include "TString.h"
0026 #include "TH1.h"
0027 #include "TH2.h"
0028 #include "TProfile.h"
0029 
0030 #include "oneapi/tbb/task_arena.h"
0031 
0032 // user include files
0033 #include "FWCore/Framework/interface/GetterOfProducts.h"
0034 #include "FWCore/Framework/interface/one/OutputModule.h"
0035 #include "FWCore/Framework/interface/RunForOutput.h"
0036 #include "FWCore/Framework/interface/LuminosityBlockForOutput.h"
0037 #include "FWCore/Framework/interface/TypeMatch.h"
0038 #include "DQMServices/Core/interface/DQMStore.h"
0039 #include "FWCore/ServiceRegistry/interface/Service.h"
0040 #include "FWCore/Framework/interface/MakerMacros.h"
0041 #include "FWCore/MessageLogger/interface/JobReport.h"
0042 #include "FWCore/Utilities/interface/BranchType.h"
0043 #include "FWCore/Utilities/interface/Digest.h"
0044 #include "FWCore/Utilities/interface/GlobalIdentifier.h"
0045 
0046 #include "DataFormats/Provenance/interface/ProcessHistory.h"
0047 #include "DataFormats/Provenance/interface/ProcessHistoryID.h"
0048 #include "DataFormats/Provenance/interface/ProcessHistoryRegistry.h"
0049 #include "FWCore/ParameterSet/interface/Registry.h"
0050 
0051 #include "DataFormats/Histograms/interface/DQMToken.h"
0052 
0053 #include "format.h"
0054 
0055 namespace {
0056   typedef dqm::legacy::MonitorElement MonitorElement;
0057   typedef dqm::legacy::DQMStore DQMStore;
0058 
0059   class TreeHelperBase {
0060   public:
0061     TreeHelperBase() : m_wasFilled(false), m_firstIndex(0), m_lastIndex(0) {}
0062     virtual ~TreeHelperBase() {}
0063     void fill(MonitorElement* iElement) {
0064       doFill(iElement);
0065       if (m_wasFilled) {
0066         ++m_lastIndex;
0067       }
0068       m_wasFilled = true;
0069     }
0070     bool wasFilled() const { return m_wasFilled; }
0071     void getRangeAndReset(ULong64_t& iFirstIndex, ULong64_t& iLastIndex) {
0072       iFirstIndex = m_firstIndex;
0073       iLastIndex = m_lastIndex;
0074       m_wasFilled = false;
0075       m_firstIndex = m_lastIndex + 1;
0076       m_lastIndex = m_firstIndex;
0077     }
0078 
0079   private:
0080     virtual void doFill(MonitorElement*) = 0;
0081     bool m_wasFilled;
0082     ULong64_t m_firstIndex;
0083     ULong64_t m_lastIndex;
0084   };
0085 
0086   template <class T>
0087   class TreeHelper : public TreeHelperBase {
0088   public:
0089     TreeHelper(TTree* iTree, std::string* iFullNameBufferPtr)
0090         : m_tree(iTree), m_flagBuffer(0), m_fullNameBufferPtr(iFullNameBufferPtr) {
0091       setup();
0092     }
0093     void doFill(MonitorElement* iElement) override {
0094       *m_fullNameBufferPtr = iElement->getFullname();
0095       m_flagBuffer = 0;
0096       m_bufferPtr = dynamic_cast<T*>(iElement->getRootObject());
0097       assert(nullptr != m_bufferPtr);
0098       //std::cout <<"#entries: "<<m_bufferPtr->GetEntries()<<std::endl;
0099       tbb::this_task_arena::isolate([&] { m_tree->Fill(); });
0100     }
0101 
0102   private:
0103     void setup() {
0104       m_tree->Branch(kFullNameBranch, &m_fullNameBufferPtr);
0105       m_tree->Branch(kFlagBranch, &m_flagBuffer);
0106 
0107       m_bufferPtr = nullptr;
0108       m_tree->Branch(kValueBranch, &m_bufferPtr, 128 * 1024, 0);
0109     }
0110     TTree* m_tree;
0111     uint32_t m_flagBuffer;
0112     std::string* m_fullNameBufferPtr;
0113     T* m_bufferPtr;
0114   };
0115 
0116   class IntTreeHelper : public TreeHelperBase {
0117   public:
0118     IntTreeHelper(TTree* iTree, std::string* iFullNameBufferPtr)
0119         : m_tree(iTree), m_flagBuffer(0), m_fullNameBufferPtr(iFullNameBufferPtr) {
0120       setup();
0121     }
0122 
0123     void doFill(MonitorElement* iElement) override {
0124       *m_fullNameBufferPtr = iElement->getFullname();
0125       m_flagBuffer = 0;
0126       m_buffer = iElement->getIntValue();
0127       tbb::this_task_arena::isolate([&] { m_tree->Fill(); });
0128     }
0129 
0130   private:
0131     void setup() {
0132       m_tree->Branch(kFullNameBranch, &m_fullNameBufferPtr);
0133       m_tree->Branch(kFlagBranch, &m_flagBuffer);
0134       m_tree->Branch(kValueBranch, &m_buffer);
0135     }
0136     TTree* m_tree;
0137     uint32_t m_flagBuffer;
0138     std::string* m_fullNameBufferPtr;
0139     Long64_t m_buffer;
0140   };
0141 
0142   class FloatTreeHelper : public TreeHelperBase {
0143   public:
0144     FloatTreeHelper(TTree* iTree, std::string* iFullNameBufferPtr)
0145         : m_tree(iTree), m_flagBuffer(0), m_fullNameBufferPtr(iFullNameBufferPtr) {
0146       setup();
0147     }
0148     void doFill(MonitorElement* iElement) override {
0149       *m_fullNameBufferPtr = iElement->getFullname();
0150       m_flagBuffer = 0;
0151       m_buffer = iElement->getFloatValue();
0152       tbb::this_task_arena::isolate([&] { m_tree->Fill(); });
0153     }
0154 
0155   private:
0156     void setup() {
0157       m_tree->Branch(kFullNameBranch, &m_fullNameBufferPtr);
0158       m_tree->Branch(kFlagBranch, &m_flagBuffer);
0159       m_tree->Branch(kValueBranch, &m_buffer);
0160     }
0161 
0162     TTree* m_tree;
0163     uint32_t m_flagBuffer;
0164     std::string* m_fullNameBufferPtr;
0165     double m_buffer;
0166   };
0167 
0168   class StringTreeHelper : public TreeHelperBase {
0169   public:
0170     StringTreeHelper(TTree* iTree, std::string* iFullNameBufferPtr)
0171         : m_tree(iTree), m_flagBuffer(0), m_fullNameBufferPtr(iFullNameBufferPtr), m_bufferPtr(&m_buffer) {
0172       setup();
0173     }
0174     void doFill(MonitorElement* iElement) override {
0175       *m_fullNameBufferPtr = iElement->getFullname();
0176       m_flagBuffer = 0;
0177       m_buffer = iElement->getStringValue();
0178       tbb::this_task_arena::isolate([&] { m_tree->Fill(); });
0179     }
0180 
0181   private:
0182     void setup() {
0183       m_tree->Branch(kFullNameBranch, &m_fullNameBufferPtr);
0184       m_tree->Branch(kFlagBranch, &m_flagBuffer);
0185       m_tree->Branch(kValueBranch, &m_bufferPtr);
0186     }
0187 
0188     TTree* m_tree;
0189     uint32_t m_flagBuffer;
0190     std::string* m_fullNameBufferPtr;
0191     std::string m_buffer;
0192     std::string* m_bufferPtr;
0193   };
0194 
0195 }  // namespace
0196 
0197 namespace edm {
0198   class ModuleCallingContext;
0199 }
0200 
0201 class DQMRootOutputModule : public edm::one::OutputModule<> {
0202 public:
0203   explicit DQMRootOutputModule(edm::ParameterSet const& pset);
0204   void beginJob() override;
0205   ~DQMRootOutputModule() override;
0206   static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
0207 
0208 private:
0209   void write(edm::EventForOutput const& e) override;
0210   void writeLuminosityBlock(edm::LuminosityBlockForOutput const&) override;
0211   void writeRun(edm::RunForOutput const&) override;
0212   bool isFileOpen() const override;
0213   void openFile(edm::FileBlock const&) override;
0214   void reallyCloseFile() override;
0215 
0216   void startEndFile();
0217   void finishEndFile();
0218   std::string m_fileName;
0219   std::string m_logicalFileName;
0220   std::unique_ptr<TFile> m_file;
0221   std::vector<std::shared_ptr<TreeHelperBase> > m_treeHelpers;
0222 
0223   unsigned int m_run;
0224   unsigned int m_lumi;
0225   unsigned int m_type;
0226   unsigned int m_presentHistoryIndex;
0227   ULong64_t m_beginTime;
0228   ULong64_t m_endTime;
0229   ULong64_t m_firstIndex;
0230   ULong64_t m_lastIndex;
0231   unsigned int m_filterOnRun;
0232 
0233   std::string m_fullNameBuffer;
0234   std::string* m_fullNameBufferPtr;
0235   std::map<unsigned int, unsigned int> m_dqmKindToTypeIndex;
0236   TTree* m_indicesTree;
0237 
0238   std::vector<edm::ProcessHistoryID> m_seenHistories;
0239   edm::ProcessHistoryRegistry m_processHistoryRegistry;
0240   edm::JobReport::Token m_jrToken;
0241 
0242   edm::GetterOfProducts<DQMToken> m_getterOfProductsLumi;
0243   edm::GetterOfProducts<DQMToken> m_getterOfProductsRun;
0244 };
0245 
0246 //
0247 // constants, enums and typedefs
0248 //
0249 
0250 static TreeHelperBase* makeHelper(unsigned int iTypeIndex, TTree* iTree, std::string* iFullNameBufferPtr) {
0251   switch (iTypeIndex) {
0252     case kIntIndex:
0253       return new IntTreeHelper(iTree, iFullNameBufferPtr);
0254     case kFloatIndex:
0255       return new FloatTreeHelper(iTree, iFullNameBufferPtr);
0256     case kStringIndex:
0257       return new StringTreeHelper(iTree, iFullNameBufferPtr);
0258     case kTH1FIndex:
0259       return new TreeHelper<TH1F>(iTree, iFullNameBufferPtr);
0260     case kTH1SIndex:
0261       return new TreeHelper<TH1S>(iTree, iFullNameBufferPtr);
0262     case kTH1DIndex:
0263       return new TreeHelper<TH1D>(iTree, iFullNameBufferPtr);
0264     case kTH1IIndex:
0265       return new TreeHelper<TH1I>(iTree, iFullNameBufferPtr);
0266     case kTH2FIndex:
0267       return new TreeHelper<TH2F>(iTree, iFullNameBufferPtr);
0268     case kTH2SIndex:
0269       return new TreeHelper<TH2S>(iTree, iFullNameBufferPtr);
0270     case kTH2DIndex:
0271       return new TreeHelper<TH2D>(iTree, iFullNameBufferPtr);
0272     case kTH2PolyIndex:
0273       return new TreeHelper<TH2Poly>(iTree, iFullNameBufferPtr);
0274     case kTH2IIndex:
0275       return new TreeHelper<TH2I>(iTree, iFullNameBufferPtr);
0276     case kTH3FIndex:
0277       return new TreeHelper<TH3F>(iTree, iFullNameBufferPtr);
0278     case kTProfileIndex:
0279       return new TreeHelper<TProfile>(iTree, iFullNameBufferPtr);
0280     case kTProfile2DIndex:
0281       return new TreeHelper<TProfile2D>(iTree, iFullNameBufferPtr);
0282   }
0283   assert(false);
0284   return nullptr;
0285 }
0286 
0287 //
0288 // static data member definitions
0289 //
0290 
0291 //
0292 // constructors and destructor
0293 //
0294 DQMRootOutputModule::DQMRootOutputModule(edm::ParameterSet const& pset)
0295     : edm::one::OutputModuleBase::OutputModuleBase(pset),
0296       edm::one::OutputModule<>(pset),
0297       m_fileName(pset.getUntrackedParameter<std::string>("fileName")),
0298       m_logicalFileName(pset.getUntrackedParameter<std::string>("logicalFileName")),
0299       m_file(nullptr),
0300       m_treeHelpers(kNIndicies, std::shared_ptr<TreeHelperBase>()),
0301       m_presentHistoryIndex(0),
0302       m_filterOnRun(pset.getUntrackedParameter<unsigned int>("filterOnRun")),
0303       m_fullNameBufferPtr(&m_fullNameBuffer),
0304       m_indicesTree(nullptr),
0305       m_getterOfProductsLumi(edm::TypeMatch(), this, edm::InLumi),
0306       m_getterOfProductsRun(edm::TypeMatch(), this, edm::InRun) {
0307   // Declare dependencies for all Lumi and Run tokens here. In
0308   // principle could use the keep statements, but then DQMToken would
0309   // have to be made persistent (transient products are ignored),
0310   // which would lead to a need to (finally) remove underscores from
0311   // DQM module labels.
0312   // This is needed to support unscheduled DQM modules now that
0313   // non-consumed EDProducers are deleted from the job at beginJob.
0314   callWhenNewProductsRegistered([this](edm::ProductDescription const& bd) {
0315     m_getterOfProductsLumi(bd);
0316     m_getterOfProductsRun(bd);
0317   });
0318 }
0319 
0320 // DQMRootOutputModule::DQMRootOutputModule(const DQMRootOutputModule& rhs)
0321 // {
0322 //    // do actual copying here;
0323 // }
0324 
0325 void DQMRootOutputModule::beginJob() {}
0326 
0327 DQMRootOutputModule::~DQMRootOutputModule() {}
0328 
0329 //
0330 // assignment operators
0331 //
0332 // const DQMRootOutputModule& DQMRootOutputModule::operator=(const DQMRootOutputModule& rhs)
0333 // {
0334 //   //An exception safe implementation is
0335 //   DQMRootOutputModule temp(rhs);
0336 //   swap(rhs);
0337 //
0338 //   return *this;
0339 // }
0340 
0341 //
0342 // member functions
0343 //
0344 bool DQMRootOutputModule::isFileOpen() const { return nullptr != m_file.get(); }
0345 
0346 void DQMRootOutputModule::openFile(edm::FileBlock const&) {
0347   //NOTE: I need to also set the I/O performance settings
0348 
0349   m_file = std::make_unique<TFile>(m_fileName.c_str(),
0350                                    "RECREATE",
0351                                    "1"  //This is the file format version number
0352   );
0353 
0354   edm::Service<edm::JobReport> jr;
0355   cms::Digest branchHash;
0356   std::string guid{edm::createGlobalIdentifier()};
0357   std::transform(guid.begin(), guid.end(), guid.begin(), (int (*)(int))std::toupper);
0358 
0359   m_file->WriteObject(&guid, kCmsGuid);
0360   m_jrToken = jr->outputFileOpened(m_fileName,
0361                                    m_logicalFileName,
0362                                    std::string(),
0363                                    "DQMRootOutputModule",
0364                                    description().moduleLabel(),
0365                                    guid,
0366                                    std::string(),
0367                                    branchHash.digest().toString(),
0368                                    std::vector<std::string>());
0369 
0370   m_indicesTree = new TTree(kIndicesTree, kIndicesTree);
0371   m_indicesTree->Branch(kRunBranch, &m_run);
0372   m_indicesTree->Branch(kLumiBranch, &m_lumi);
0373   m_indicesTree->Branch(kProcessHistoryIndexBranch, &m_presentHistoryIndex);
0374   m_indicesTree->Branch(kBeginTimeBranch, &m_beginTime);
0375   m_indicesTree->Branch(kEndTimeBranch, &m_endTime);
0376   m_indicesTree->Branch(kTypeBranch, &m_type);
0377   m_indicesTree->Branch(kFirstIndex, &m_firstIndex);
0378   m_indicesTree->Branch(kLastIndex, &m_lastIndex);
0379   m_indicesTree->SetDirectory(m_file.get());
0380 
0381   unsigned int i = 0;
0382   for (std::vector<std::shared_ptr<TreeHelperBase> >::iterator it = m_treeHelpers.begin(), itEnd = m_treeHelpers.end();
0383        it != itEnd;
0384        ++it, ++i) {
0385     //std::cout <<"making "<<kTypeNames[i]<<std::endl;
0386     TTree* tree = new TTree(kTypeNames[i], kTypeNames[i]);
0387     *it = std::shared_ptr<TreeHelperBase>(makeHelper(i, tree, m_fullNameBufferPtr));
0388     tree->SetDirectory(m_file.get());  //TFile takes ownership
0389   }
0390 
0391   m_dqmKindToTypeIndex[(int)MonitorElement::Kind::INT] = kIntIndex;
0392   m_dqmKindToTypeIndex[(int)MonitorElement::Kind::REAL] = kFloatIndex;
0393   m_dqmKindToTypeIndex[(int)MonitorElement::Kind::STRING] = kStringIndex;
0394   m_dqmKindToTypeIndex[(int)MonitorElement::Kind::TH1F] = kTH1FIndex;
0395   m_dqmKindToTypeIndex[(int)MonitorElement::Kind::TH1S] = kTH1SIndex;
0396   m_dqmKindToTypeIndex[(int)MonitorElement::Kind::TH1D] = kTH1DIndex;
0397   m_dqmKindToTypeIndex[(int)MonitorElement::Kind::TH1I] = kTH1IIndex;
0398   m_dqmKindToTypeIndex[(int)MonitorElement::Kind::TH2F] = kTH2FIndex;
0399   m_dqmKindToTypeIndex[(int)MonitorElement::Kind::TH2S] = kTH2SIndex;
0400   m_dqmKindToTypeIndex[(int)MonitorElement::Kind::TH2D] = kTH2DIndex;
0401   m_dqmKindToTypeIndex[(int)MonitorElement::Kind::TH2Poly] = kTH2PolyIndex;
0402   m_dqmKindToTypeIndex[(int)MonitorElement::Kind::TH2I] = kTH2IIndex;
0403   m_dqmKindToTypeIndex[(int)MonitorElement::Kind::TH3F] = kTH3FIndex;
0404   m_dqmKindToTypeIndex[(int)MonitorElement::Kind::TPROFILE] = kTProfileIndex;
0405   m_dqmKindToTypeIndex[(int)MonitorElement::Kind::TPROFILE2D] = kTProfile2DIndex;
0406 }
0407 
0408 void DQMRootOutputModule::write(edm::EventForOutput const&) {}
0409 
0410 void DQMRootOutputModule::writeLuminosityBlock(edm::LuminosityBlockForOutput const& iLumi) {
0411   //std::cout << "DQMRootOutputModule::writeLuminosityBlock"<< std::endl;
0412   edm::Service<DQMStore> dstore;
0413   m_run = iLumi.id().run();
0414   m_lumi = iLumi.id().value();
0415   m_beginTime = iLumi.beginTime().value();
0416   m_endTime = iLumi.endTime().value();
0417   bool shouldWrite = (m_filterOnRun == 0 || (m_filterOnRun != 0 && m_filterOnRun == m_run));
0418 
0419   if (!shouldWrite)
0420     return;
0421   std::vector<MonitorElement*> items(dstore->getAllContents("", m_run, m_lumi));
0422   for (std::vector<MonitorElement*>::iterator it = items.begin(), itEnd = items.end(); it != itEnd; ++it) {
0423     assert((*it)->getScope() == MonitorElementData::Scope::LUMI);
0424     std::map<unsigned int, unsigned int>::iterator itFound = m_dqmKindToTypeIndex.find((int)(*it)->kind());
0425     assert(itFound != m_dqmKindToTypeIndex.end());
0426     m_treeHelpers[itFound->second]->fill(*it);
0427   }
0428 
0429   const edm::ProcessHistoryID& id = iLumi.processHistoryID();
0430   std::vector<edm::ProcessHistoryID>::iterator itFind = std::find(m_seenHistories.begin(), m_seenHistories.end(), id);
0431   if (itFind == m_seenHistories.end()) {
0432     m_processHistoryRegistry.registerProcessHistory(iLumi.processHistory());
0433     m_presentHistoryIndex = m_seenHistories.size();
0434     m_seenHistories.push_back(id);
0435   } else {
0436     m_presentHistoryIndex = itFind - m_seenHistories.begin();
0437   }
0438 
0439   //Now store the relationship between run/lumi and indices in the other TTrees
0440   bool storedLumiIndex = false;
0441   unsigned int typeIndex = 0;
0442   for (std::vector<std::shared_ptr<TreeHelperBase> >::iterator it = m_treeHelpers.begin(), itEnd = m_treeHelpers.end();
0443        it != itEnd;
0444        ++it, ++typeIndex) {
0445     if ((*it)->wasFilled()) {
0446       m_type = typeIndex;
0447       (*it)->getRangeAndReset(m_firstIndex, m_lastIndex);
0448       storedLumiIndex = true;
0449       tbb::this_task_arena::isolate([&] { m_indicesTree->Fill(); });
0450     }
0451   }
0452   if (not storedLumiIndex) {
0453     //need to record lumis even if we stored no MonitorElements since some later DQM modules
0454     // look to see what lumis were processed
0455     m_type = kNoTypesStored;
0456     m_firstIndex = 0;
0457     m_lastIndex = 0;
0458     tbb::this_task_arena::isolate([&] { m_indicesTree->Fill(); });
0459   }
0460 
0461   edm::Service<edm::JobReport> jr;
0462   jr->reportLumiSection(m_jrToken, m_run, m_lumi);
0463 }
0464 
0465 void DQMRootOutputModule::writeRun(edm::RunForOutput const& iRun) {
0466   //std::cout << "DQMRootOutputModule::writeRun"<< std::endl;
0467   edm::Service<DQMStore> dstore;
0468   m_run = iRun.id().run();
0469   m_lumi = 0;
0470   m_beginTime = iRun.beginTime().value();
0471   m_endTime = iRun.endTime().value();
0472   bool shouldWrite = (m_filterOnRun == 0 || (m_filterOnRun != 0 && m_filterOnRun == m_run));
0473 
0474   if (!shouldWrite)
0475     return;
0476 
0477   std::vector<MonitorElement*> items(dstore->getAllContents("", m_run, 0));
0478   for (std::vector<MonitorElement*>::iterator it = items.begin(), itEnd = items.end(); it != itEnd; ++it) {
0479     assert((*it)->getScope() == MonitorElementData::Scope::RUN);
0480     std::map<unsigned int, unsigned int>::iterator itFound = m_dqmKindToTypeIndex.find((int)(*it)->kind());
0481     assert(itFound != m_dqmKindToTypeIndex.end());
0482     m_treeHelpers[itFound->second]->fill(*it);
0483   }
0484 
0485   const edm::ProcessHistoryID& id = iRun.processHistoryID();
0486   std::vector<edm::ProcessHistoryID>::iterator itFind = std::find(m_seenHistories.begin(), m_seenHistories.end(), id);
0487   if (itFind == m_seenHistories.end()) {
0488     m_processHistoryRegistry.registerProcessHistory(iRun.processHistory());
0489     m_presentHistoryIndex = m_seenHistories.size();
0490     m_seenHistories.push_back(id);
0491   } else {
0492     m_presentHistoryIndex = itFind - m_seenHistories.begin();
0493   }
0494 
0495   //Now store the relationship between run/lumi and indices in the other TTrees
0496   unsigned int typeIndex = 0;
0497   for (std::vector<std::shared_ptr<TreeHelperBase> >::iterator it = m_treeHelpers.begin(), itEnd = m_treeHelpers.end();
0498        it != itEnd;
0499        ++it, ++typeIndex) {
0500     if ((*it)->wasFilled()) {
0501       m_type = typeIndex;
0502       (*it)->getRangeAndReset(m_firstIndex, m_lastIndex);
0503       tbb::this_task_arena::isolate([&] { m_indicesTree->Fill(); });
0504     }
0505   }
0506 
0507   edm::Service<edm::JobReport> jr;
0508   jr->reportRunNumber(m_jrToken, m_run);
0509 }
0510 
0511 void DQMRootOutputModule::reallyCloseFile() {
0512   startEndFile();
0513   finishEndFile();
0514 }
0515 
0516 void DQMRootOutputModule::startEndFile() {
0517   //std::cout << "DQMRootOutputModule::startEndFile"<< std::endl;
0518   //fill in the meta data
0519   m_file->cd();
0520   TDirectory* metaDataDirectory = m_file->mkdir(kMetaDataDirectory);
0521 
0522   //Write out the Process History
0523   TTree* processHistoryTree = new TTree(kProcessHistoryTree, kProcessHistoryTree);
0524   processHistoryTree->SetDirectory(metaDataDirectory);
0525 
0526   unsigned int index = 0;
0527   processHistoryTree->Branch(kPHIndexBranch, &index);
0528   std::string processName;
0529   processHistoryTree->Branch(kProcessConfigurationProcessNameBranch, &processName);
0530   std::string parameterSetID;
0531   processHistoryTree->Branch(kProcessConfigurationParameterSetIDBranch, &parameterSetID);
0532   std::string releaseVersion;
0533   processHistoryTree->Branch(kProcessConfigurationReleaseVersion, &releaseVersion);
0534   std::string hardwareResourcesSerialized;
0535   processHistoryTree->Branch(kProcessConfigurationHardwareResources, &hardwareResourcesSerialized);
0536 
0537   for (std::vector<edm::ProcessHistoryID>::iterator it = m_seenHistories.begin(), itEnd = m_seenHistories.end();
0538        it != itEnd;
0539        ++it) {
0540     const edm::ProcessHistory* history = m_processHistoryRegistry.getMapped(*it);
0541     assert(nullptr != history);
0542     index = 0;
0543     for (edm::ProcessHistory::collection_type::const_iterator itPC = history->begin(), itPCEnd = history->end();
0544          itPC != itPCEnd;
0545          ++itPC, ++index) {
0546       processName = itPC->processName();
0547       releaseVersion = itPC->releaseVersion();
0548       hardwareResourcesSerialized = itPC->hardwareResourcesDescriptionSerialized();
0549       parameterSetID = itPC->parameterSetID().compactForm();
0550       tbb::this_task_arena::isolate([&] { processHistoryTree->Fill(); });
0551     }
0552   }
0553 
0554   //Store the ParameterSets
0555   TTree* parameterSetsTree = new TTree(kParameterSetTree, kParameterSetTree);
0556   parameterSetsTree->SetDirectory(metaDataDirectory);
0557   std::string blob;
0558   parameterSetsTree->Branch(kParameterSetBranch, &blob);
0559 
0560   edm::pset::Registry* psr = edm::pset::Registry::instance();
0561   assert(nullptr != psr);
0562   for (edm::pset::Registry::const_iterator it = psr->begin(), itEnd = psr->end(); it != itEnd; ++it) {
0563     blob.clear();
0564     it->second.toString(blob);
0565     tbb::this_task_arena::isolate([&] { parameterSetsTree->Fill(); });
0566   }
0567 }
0568 
0569 void DQMRootOutputModule::finishEndFile() {
0570   //std::cout << "DQMRootOutputModule::finishEndFile"<< std::endl;
0571   m_file->Write();
0572   m_file->Close();
0573   edm::Service<edm::JobReport> jr;
0574   jr->outputFileClosed(m_jrToken);
0575 }
0576 
0577 //
0578 // const member functions
0579 //
0580 
0581 //
0582 // static member functions
0583 //
0584 void DQMRootOutputModule::fillDescriptions(edm::ConfigurationDescriptions& descriptions) {
0585   edm::ParameterSetDescription desc;
0586 
0587   desc.addUntracked<std::string>("fileName");
0588   desc.addUntracked<std::string>("logicalFileName", "");
0589   desc.addUntracked<unsigned int>("filterOnRun", 0)
0590       ->setComment("Only write the run with this run number. 0 means write all runs.");
0591   desc.addOptionalUntracked<int>("splitLevel", 99)
0592       ->setComment("UNUSED Only here to allow older configurations written for PoolOutputModule to work.");
0593   const std::vector<std::string> keep = {"drop *", "keep DQMToken_*_*_*"};
0594   edm::one::OutputModule<>::fillDescription(desc, keep);
0595 
0596   edm::ParameterSetDescription dataSet;
0597   dataSet.setAllowAnything();
0598   desc.addUntracked<edm::ParameterSetDescription>("dataset", dataSet)
0599       ->setComment("PSet is only used by Data Operations and not by this module.");
0600 
0601   descriptions.addDefault(desc);
0602 }
0603 
0604 DEFINE_FWK_MODULE(DQMRootOutputModule);