CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_7/src/FWCore/Framework/src/OutputModule.cc

Go to the documentation of this file.
00001 /*----------------------------------------------------------------------
00002 
00003 ----------------------------------------------------------------------*/
00004 
00005 #include "FWCore/Framework/interface/OutputModule.h"
00006 
00007 #include "DataFormats/Common/interface/Handle.h"
00008 #include "DataFormats/Provenance/interface/BranchDescription.h"
00009 #include "DataFormats/Provenance/interface/BranchKey.h"
00010 #include "DataFormats/Provenance/interface/ParentageRegistry.h"
00011 #include "DataFormats/Provenance/interface/ProductRegistry.h"
00012 #include "FWCore/Framework/interface/CurrentProcessingContext.h"
00013 #include "FWCore/Framework/interface/Event.h"
00014 #include "FWCore/Framework/interface/EventPrincipal.h"
00015 #include "FWCore/Framework/interface/OutputModuleDescription.h"
00016 #include "FWCore/Framework/interface/TriggerNamesService.h"
00017 #include "FWCore/Framework/src/CPCSentry.h"
00018 #include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
00019 #include "FWCore/ParameterSet/interface/ParameterSet.h"
00020 #include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
00021 #include "FWCore/ServiceRegistry/interface/Service.h"
00022 #include "FWCore/Utilities/interface/DebugMacros.h"
00023 
00024 #include <cassert>
00025 
00026 namespace edm {
00027 
00028   std::vector<std::string> const& getAllTriggerNames() {
00029     Service<service::TriggerNamesService> tns;
00030     return tns->getTrigPaths();
00031   }
00032 }
00033 
00034 namespace {
00035   //--------------------------------------------------------
00036   // Remove whitespace (spaces and tabs) from a std::string.
00037   void remove_whitespace(std::string& s) {
00038     s.erase(std::remove(s.begin(), s.end(), ' '), s.end());
00039     s.erase(std::remove(s.begin(), s.end(), '\t'), s.end());
00040   }
00041 
00042   void test_remove_whitespace() {
00043     std::string a("noblanks");
00044     std::string b("\t   no   blanks    \t");
00045 
00046     remove_whitespace(b);
00047     assert(a == b);
00048   }
00049 
00050   //--------------------------------------------------------
00051   // Given a path-spec (std::string of the form "a:b", where the ":b" is
00052   // optional), return a parsed_path_spec_t containing "a" and "b".
00053 
00054   typedef std::pair<std::string, std::string> parsed_path_spec_t;
00055   void parse_path_spec(std::string const& path_spec,
00056                        parsed_path_spec_t& output) {
00057     std::string trimmed_path_spec(path_spec);
00058     remove_whitespace(trimmed_path_spec);
00059 
00060     std::string::size_type colon = trimmed_path_spec.find(":");
00061     if(colon == std::string::npos) {
00062         output.first = trimmed_path_spec;
00063     } else {
00064         output.first  = trimmed_path_spec.substr(0, colon);
00065         output.second = trimmed_path_spec.substr(colon + 1,
00066                                                  trimmed_path_spec.size());
00067     }
00068   }
00069 
00070   void test_parse_path_spec() {
00071     std::vector<std::string> paths;
00072     paths.push_back("a:p1");
00073     paths.push_back("b:p2");
00074     paths.push_back("  c");
00075     paths.push_back("ddd\t:p3");
00076     paths.push_back("eee:  p4  ");
00077 
00078     std::vector<parsed_path_spec_t> parsed(paths.size());
00079     for(size_t i = 0; i < paths.size(); ++i) {
00080       parse_path_spec(paths[i], parsed[i]);
00081     }
00082 
00083     assert(parsed[0].first  == "a");
00084     assert(parsed[0].second == "p1");
00085     assert(parsed[1].first  == "b");
00086     assert(parsed[1].second == "p2");
00087     assert(parsed[2].first  == "c");
00088     assert(parsed[2].second == "");
00089     assert(parsed[3].first  == "ddd");
00090     assert(parsed[3].second == "p3");
00091     assert(parsed[4].first  == "eee");
00092     assert(parsed[4].second == "p4");
00093   }
00094 }
00095 
00096 namespace edm {
00097   namespace test {
00098     void run_all_output_module_tests() {
00099       test_remove_whitespace();
00100       test_parse_path_spec();
00101     }
00102   }
00103 
00104   // -------------------------------------------------------
00105   OutputModule::OutputModule(ParameterSet const& pset) :
00106     maxEvents_(-1),
00107     remainingEvents_(maxEvents_),
00108     keptProducts_(),
00109     hasNewlyDroppedBranch_(),
00110     process_name_(),
00111     productSelectorRules_(pset, "outputCommands", "OutputModule"),
00112     productSelector_(),
00113     moduleDescription_(),
00114     current_context_(nullptr),
00115     prodsValid_(false),
00116     wantAllEvents_(false),
00117     selectors_(),
00118     selector_config_id_(),
00119     droppedBranchIDToKeptBranchID_(),
00120     branchIDLists_(new BranchIDLists),
00121     origBranchIDLists_(nullptr),
00122     branchParents_(),
00123     branchChildren_() {
00124 
00125     hasNewlyDroppedBranch_.fill(false);
00126 
00127     Service<service::TriggerNamesService> tns;
00128     process_name_ = tns->getProcessName();
00129 
00130     ParameterSet selectevents =
00131       pset.getUntrackedParameterSet("SelectEvents", ParameterSet());
00132 
00133     selectevents.registerIt(); // Just in case this PSet is not registered
00134 
00135     selector_config_id_ = selectevents.id();
00136     // If selectevents is an emtpy ParameterSet, then we are to write
00137     // all events, or one which contains a vstrig 'SelectEvents' that
00138     // is empty, we are to write all events. We have no need for any
00139     // EventSelectors.
00140     if(selectevents.empty()) {
00141         wantAllEvents_ = true;
00142         selectors_.setupDefault(getAllTriggerNames());
00143         return;
00144     }
00145 
00146     std::vector<std::string> path_specs =
00147       selectevents.getParameter<std::vector<std::string> >("SelectEvents");
00148 
00149     if(path_specs.empty()) {
00150         wantAllEvents_ = true;
00151         selectors_.setupDefault(getAllTriggerNames());
00152         return;
00153     }
00154 
00155     // If we get here, we have the possibility of having to deal with
00156     // path_specs that look at more than one process.
00157     std::vector<parsed_path_spec_t> parsed_paths(path_specs.size());
00158     for(size_t i = 0; i < path_specs.size(); ++i) {
00159       parse_path_spec(path_specs[i], parsed_paths[i]);
00160     }
00161     selectors_.setup(parsed_paths, getAllTriggerNames(), process_name_);
00162   }
00163 
00164   void OutputModule::configure(OutputModuleDescription const& desc) {
00165     remainingEvents_ = maxEvents_ = desc.maxEvents_;
00166     origBranchIDLists_ = desc.branchIDLists_;
00167   }
00168 
00169   void OutputModule::selectProducts(ProductRegistry const& preg) {
00170     if(productSelector_.initialized()) return;
00171     productSelector_.initialize(productSelectorRules_, preg.allBranchDescriptions());
00172 
00173     // TODO: See if we can collapse keptProducts_ and productSelector_ into a
00174     // single object. See the notes in the header for ProductSelector
00175     // for more information.
00176 
00177     std::map<BranchID, BranchDescription const*> trueBranchIDToKeptBranchDesc;
00178 
00179     for(auto const& it : preg.productList()) {
00180       BranchDescription const& desc = it.second;
00181       if(desc.transient()) {
00182         // if the class of the branch is marked transient, output nothing
00183       } else if(!desc.present() && !desc.produced()) {
00184         // else if the branch containing the product has been previously dropped,
00185         // output nothing
00186       } else if(selected(desc)) {
00187         // else if the branch has been selected, put it in the list of selected branches.
00188         if(desc.produced()) {
00189           // First we check if an equivalent branch has already been selected due to an EDAlias.
00190           // We only need the check for products produced in this process.
00191           BranchID const& trueBranchID = desc.originalBranchID();
00192           std::map<BranchID, BranchDescription const*>::const_iterator iter = trueBranchIDToKeptBranchDesc.find(trueBranchID);
00193           if(iter != trueBranchIDToKeptBranchDesc.end()) {
00194              throw edm::Exception(errors::Configuration, "Duplicate Output Selection")
00195                << "Two (or more) equivalent branches have been selected for output.\n"
00196                << "#1: " << BranchKey(desc) << "\n" 
00197                << "#2: " << BranchKey(*iter->second) << "\n" 
00198                << "Please drop at least one of them.\n";
00199           }
00200           trueBranchIDToKeptBranchDesc.insert(std::make_pair(trueBranchID, &desc));
00201         }
00202         switch (desc.branchType()) {
00203           case InEvent:
00204           {
00205             consumes(TypeToGet{desc.unwrappedTypeID(),PRODUCT_TYPE},
00206                      InputTag{desc.moduleLabel(),
00207                               desc.productInstanceName(),
00208                        desc.processName()});
00209             break;
00210           }
00211           case InLumi:
00212           {
00213             consumes<InLumi>(TypeToGet{desc.unwrappedTypeID(),PRODUCT_TYPE},
00214                              InputTag(desc.moduleLabel(),
00215                                       desc.productInstanceName(),
00216                                       desc.processName()));
00217             break;
00218           }
00219           case InRun:
00220           {
00221             consumes<InRun>(TypeToGet{desc.unwrappedTypeID(),PRODUCT_TYPE},
00222                             InputTag(desc.moduleLabel(),
00223                                      desc.productInstanceName(),
00224                                      desc.processName()));
00225             break;
00226           }
00227           default:
00228             assert(false);
00229             break;
00230         }
00231         // Now put it in the list of selected branches.
00232         keptProducts_[desc.branchType()].push_back(&desc);
00233       } else {
00234         // otherwise, output nothing,
00235         // and mark the fact that there is a newly dropped branch of this type.
00236         hasNewlyDroppedBranch_[desc.branchType()] = true;
00237       }
00238     }
00239     // Now fill in a mapping needed in the case that a branch was dropped while its EDAlias was kept.
00240     for(auto const& it : preg.productList()) {
00241       BranchDescription const& desc = it.second;
00242       if(!desc.produced() || desc.isAlias()) continue;
00243       BranchID const& branchID = desc.branchID();
00244       std::map<BranchID, BranchDescription const*>::const_iterator iter = trueBranchIDToKeptBranchDesc.find(branchID);
00245       if(iter != trueBranchIDToKeptBranchDesc.end()) {
00246         // This branch, produced in this process, or an alias of it, was persisted.
00247         BranchID const& keptBranchID = iter->second->branchID();
00248         if(keptBranchID != branchID) {
00249           // An EDAlias branch was persisted.
00250           droppedBranchIDToKeptBranchID_.insert(std::make_pair(branchID.id(), keptBranchID.id()));
00251         }
00252       }
00253     }
00254   }
00255 
00256   OutputModule::~OutputModule() { }
00257 
00258   void OutputModule::doBeginJob() {
00259     this->beginJob();
00260   }
00261 
00262   void OutputModule::doEndJob() {
00263     endJob();
00264   }
00265 
00266 
00267   Trig OutputModule::getTriggerResults(Event const& ev) const {
00268     return selectors_.getOneTriggerResults(ev);
00269   }
00270 
00271   Trig OutputModule::getTriggerResults(EventPrincipal const& ep) const {
00272     // This is bad, because we're returning handles into an Event that
00273     // is destructed before the return. It might not fail, because the
00274     // actual EventPrincipal is not destroyed, but it still needs to
00275     // be cleaned up.
00276     Event ev(const_cast<EventPrincipal&>(ep),
00277              *current_context_->moduleDescription());
00278     return getTriggerResults(ev);
00279   }
00280 
00281   namespace {
00282     class  PVSentry {
00283     public:
00284       PVSentry(detail::CachedProducts& prods, bool& valid) : p(prods), v(valid) {}
00285       ~PVSentry() {
00286         p.clear();
00287         v = false;
00288       }
00289     private:
00290       detail::CachedProducts& p;
00291       bool& v;
00292 
00293       PVSentry(PVSentry const&);  // not implemented
00294       PVSentry& operator=(PVSentry const&); // not implemented
00295     };
00296   }
00297 
00298   bool
00299   OutputModule::doEvent(EventPrincipal const& ep,
00300                         EventSetup const&,
00301                         CurrentProcessingContext const* cpc) {
00302     detail::CPCSentry sentry(current_context_, cpc);
00303     PVSentry          products_sentry(selectors_, prodsValid_);
00304 
00305     FDEBUG(2) << "writeEvent called\n";
00306 
00307     if(!wantAllEvents_) {
00308       // use module description and const_cast unless interface to
00309       // event is changed to just take a const EventPrincipal
00310       Event e(const_cast<EventPrincipal&>(ep), moduleDescription_);
00311       if(!selectors_.wantEvent(e)) {
00312         return true;
00313       }
00314     }
00315     write(ep);
00316     updateBranchParents(ep);
00317     if(remainingEvents_ > 0) {
00318       --remainingEvents_;
00319     }
00320     return true;
00321   }
00322 
00323 //   bool OutputModule::wantEvent(Event const& ev)
00324 //   {
00325 //     getTriggerResults(ev);
00326 //     bool eventAccepted = false;
00327 
00328 //     typedef std::vector<NamedEventSelector>::const_iterator iter;
00329 //     for(iter i = selectResult_.begin(), e = selectResult_.end();
00330 //          !eventAccepted && i != e; ++i)
00331 //       {
00332 //         eventAccepted = i->acceptEvent(*prods_);
00333 //       }
00334 
00335 //     FDEBUG(2) << "Accept event " << ep.id() << " " << eventAccepted << "\n";
00336 //     return eventAccepted;
00337 //   }
00338 
00339   bool
00340   OutputModule::doBeginRun(RunPrincipal const& rp,
00341                                 EventSetup const&,
00342                                 CurrentProcessingContext const* cpc) {
00343     detail::CPCSentry sentry(current_context_, cpc);
00344     FDEBUG(2) << "beginRun called\n";
00345     beginRun(rp);
00346     return true;
00347   }
00348 
00349   bool
00350   OutputModule::doEndRun(RunPrincipal const& rp,
00351                               EventSetup const&,
00352                               CurrentProcessingContext const* cpc) {
00353     detail::CPCSentry sentry(current_context_, cpc);
00354     FDEBUG(2) << "endRun called\n";
00355     endRun(rp);
00356     return true;
00357   }
00358 
00359   void
00360   OutputModule::doWriteRun(RunPrincipal const& rp) {
00361     FDEBUG(2) << "writeRun called\n";
00362     writeRun(rp);
00363   }
00364 
00365   bool
00366   OutputModule::doBeginLuminosityBlock(LuminosityBlockPrincipal const& lbp,
00367                                             EventSetup const&,
00368                                             CurrentProcessingContext const* cpc) {
00369     detail::CPCSentry sentry(current_context_, cpc);
00370     FDEBUG(2) << "beginLuminosityBlock called\n";
00371     beginLuminosityBlock(lbp);
00372     return true;
00373   }
00374 
00375   bool
00376   OutputModule::doEndLuminosityBlock(LuminosityBlockPrincipal const& lbp,
00377                                           EventSetup const&,
00378                                           CurrentProcessingContext const* cpc) {
00379     detail::CPCSentry sentry(current_context_, cpc);
00380     FDEBUG(2) << "endLuminosityBlock called\n";
00381     endLuminosityBlock(lbp);
00382     return true;
00383   }
00384 
00385   void OutputModule::doWriteLuminosityBlock(LuminosityBlockPrincipal const& lbp) {
00386     FDEBUG(2) << "writeLuminosityBlock called\n";
00387     writeLuminosityBlock(lbp);
00388   }
00389 
00390   void OutputModule::doOpenFile(FileBlock const& fb) {
00391     openFile(fb);
00392   }
00393 
00394   void OutputModule::doRespondToOpenInputFile(FileBlock const& fb) {
00395     respondToOpenInputFile(fb);
00396   }
00397 
00398   void OutputModule::doRespondToCloseInputFile(FileBlock const& fb) {
00399     respondToCloseInputFile(fb);
00400   }
00401 
00402   void OutputModule::doRespondToOpenOutputFiles(FileBlock const& fb) {
00403     respondToOpenOutputFiles(fb);
00404   }
00405 
00406   void OutputModule::doRespondToCloseOutputFiles(FileBlock const& fb) {
00407     respondToCloseOutputFiles(fb);
00408   }
00409 
00410   void
00411   OutputModule::doPreForkReleaseResources() {
00412     preForkReleaseResources();
00413   }
00414 
00415   void
00416   OutputModule::doPostForkReacquireResources(unsigned int iChildIndex, unsigned int iNumberOfChildren) {
00417     postForkReacquireResources(iChildIndex, iNumberOfChildren);
00418   }
00419 
00420   void OutputModule::maybeOpenFile() {
00421     if(!isFileOpen()) doOpenFile();
00422   }
00423 
00424   void OutputModule::doCloseFile() {
00425     if(isFileOpen()) reallyCloseFile();
00426   }
00427 
00428   void OutputModule::reallyCloseFile() {
00429     fillDependencyGraph();
00430     startEndFile();
00431     writeFileFormatVersion();
00432     writeFileIdentifier();
00433     writeIndexIntoFile();
00434     writeProcessConfigurationRegistry();
00435     writeProcessHistoryRegistry();
00436     writeParameterSetRegistry();
00437     writeProductDescriptionRegistry();
00438     writeParentageRegistry();
00439     writeBranchIDListRegistry();
00440     writeProductDependencies();
00441     writeBranchMapper();
00442     finishEndFile();
00443     branchParents_.clear();
00444     branchChildren_.clear();
00445   }
00446 
00447   BranchIDLists const*
00448   OutputModule::branchIDLists() const {
00449     if(!droppedBranchIDToKeptBranchID_.empty()) {
00450       // Make a private copy of the BranchIDLists.
00451       *branchIDLists_ = *origBranchIDLists_;
00452       // Check for branches dropped while an EDAlias was kept.
00453       for(BranchIDList& branchIDList : *branchIDLists_) {
00454         for(BranchID::value_type& branchID : branchIDList) {
00455           // Replace BranchID of each dropped branch with that of the kept alias, so the alias branch will have the product ID of the original branch.
00456           std::map<BranchID::value_type, BranchID::value_type>::const_iterator iter = droppedBranchIDToKeptBranchID_.find(branchID);
00457           if(iter != droppedBranchIDToKeptBranchID_.end()) {
00458             branchID = iter->second;
00459           }
00460         }
00461       }
00462       return branchIDLists_.get();
00463     }
00464     return origBranchIDLists_;
00465   }
00466 
00467   CurrentProcessingContext const*
00468   OutputModule::currentContext() const {
00469     return current_context_;
00470   }
00471 
00472   ModuleDescription const&
00473   OutputModule::description() const {
00474     return moduleDescription_;
00475   }
00476 
00477   bool
00478   OutputModule::selected(BranchDescription const& desc) const {
00479     return productSelector_.selected(desc);
00480   }
00481 
00482   void
00483   OutputModule::fillDescriptions(ConfigurationDescriptions& descriptions) {
00484     ParameterSetDescription desc;
00485     desc.setUnknown();
00486     descriptions.addDefault(desc);
00487   }
00488   
00489   void
00490   OutputModule::fillDescription(ParameterSetDescription& desc) {
00491     ProductSelectorRules::fillDescription(desc, "outputCommands");
00492     EventSelector::fillDescription(desc);
00493   }
00494   
00495   void
00496   OutputModule::prevalidate(ConfigurationDescriptions& ) {
00497   }
00498   
00499 
00500   static const std::string kBaseType("OutputModule");
00501   const std::string&
00502   OutputModule::baseType() {
00503     return kBaseType;
00504   }
00505 
00506   void
00507   OutputModule::setEventSelectionInfo(std::map<std::string, std::vector<std::pair<std::string, int> > > const& outputModulePathPositions,
00508                                       bool anyProductProduced) {
00509 
00510     ParameterSet selectEventsInfo;
00511     selectEventsInfo.copyForModify(getParameterSet(selector_config_id_));
00512     selectEventsInfo.addParameter<bool>("InProcessHistory", anyProductProduced);
00513     std::string const& label = description().moduleLabel();
00514     std::vector<std::string> endPaths;
00515     std::vector<int> endPathPositions;
00516 
00517     // The label will be empty if and only if this is a SubProcess
00518     // SubProcess's do not appear on any end path
00519     if (!label.empty()) {
00520       std::map<std::string, std::vector<std::pair<std::string, int> > >::const_iterator iter = outputModulePathPositions.find(label);
00521       assert(iter != outputModulePathPositions.end());
00522       for (std::vector<std::pair<std::string, int> >::const_iterator i = iter->second.begin(), e = iter->second.end();
00523            i != e; ++i) {
00524         endPaths.push_back(i->first);
00525         endPathPositions.push_back(i->second);
00526       }
00527     }
00528     selectEventsInfo.addParameter<std::vector<std::string> >("EndPaths", endPaths);
00529     selectEventsInfo.addParameter<std::vector<int> >("EndPathPositions", endPathPositions);
00530     if (!selectEventsInfo.exists("SelectEvents")) {
00531       selectEventsInfo.addParameter<std::vector<std::string> >("SelectEvents", std::vector<std::string>());
00532     }
00533     selectEventsInfo.registerIt();
00534 
00535     selector_config_id_ = selectEventsInfo.id();
00536   }
00537 
00538   void
00539   OutputModule::updateBranchParents(EventPrincipal const& ep) {
00540     for(EventPrincipal::const_iterator i = ep.begin(), iEnd = ep.end(); i != iEnd; ++i) {
00541       if((*i) && (*i)->productProvenancePtr() != 0) {
00542         BranchID const& bid = (*i)->branchDescription().branchID();
00543         BranchParents::iterator it = branchParents_.find(bid);
00544         if(it == branchParents_.end()) {
00545           it = branchParents_.insert(std::make_pair(bid, std::set<ParentageID>())).first;
00546         }
00547         it->second.insert((*i)->productProvenancePtr()->parentageID());
00548         branchChildren_.insertEmpty(bid);
00549       }
00550     }
00551   }
00552 
00553   void
00554   OutputModule::fillDependencyGraph() {
00555     for(BranchParents::const_iterator i = branchParents_.begin(), iEnd = branchParents_.end();
00556         i != iEnd; ++i) {
00557       BranchID const& child = i->first;
00558       std::set<ParentageID> const& eIds = i->second;
00559       for(std::set<ParentageID>::const_iterator it = eIds.begin(), itEnd = eIds.end();
00560           it != itEnd; ++it) {
00561         Parentage entryDesc;
00562         ParentageRegistry::instance()->getMapped(*it, entryDesc);
00563         std::vector<BranchID> const& parents = entryDesc.parents();
00564         for(std::vector<BranchID>::const_iterator j = parents.begin(), jEnd = parents.end();
00565           j != jEnd; ++j) {
00566           branchChildren_.insertChild(*j, child);
00567         }
00568       }
00569     }
00570   }
00571 }