CMS 3D CMS Logo

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