CMS 3D CMS Logo

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