CMS 3D CMS Logo

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