CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_5_3_13_patch3/src/PhysicsTools/UtilAlgos/interface/CachingVariable.h

Go to the documentation of this file.
00001 #ifndef ConfigurableAnalysis_CachingVariable_H
00002 #define ConfigurableAnalysis_CachingVariable_H
00003 
00004 #include "FWCore/ParameterSet/interface/ParameterSet.h"
00005 #include "FWCore/Services/interface/UpdaterService.h"
00006 #include "FWCore/ServiceRegistry/interface/Service.h"
00007 #include "FWCore/Framework/interface/Event.h"
00008 #include "DataFormats/Common/interface/Handle.h"
00009 #include "CommonTools/Utils/interface/StringObjectFunction.h"
00010 #include "CommonTools/Utils/interface/StringCutObjectSelector.h"
00011 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00012 
00013 #include "PhysicsTools/UtilAlgos/interface/InputTagDistributor.h"
00014 
00015 namespace edm {
00016   class EventSetup;
00017 }
00018 #include <vector>
00019 #include "TString.h"
00020 
00021 class Description {
00022  public:
00023   Description(){}
00024   Description(std::vector<std::string> & d) : d_(d){}
00025   std::string text() const {
00026     std::string text;
00027     for (unsigned int i=0;i!=d_.size();++i) 
00028       text+=d_[i]+"\n";
00029     return text;
00030   }
00031   const std::vector<std::string> lines(){return d_;}
00032   void addLine(const std::string & l){d_.push_back(l);}
00033  private :
00034   std::vector<std::string> d_;
00035 };
00036 
00037 class VariableComputer;
00038 
00039 class CachingVariable {
00040  public:
00041   //every variable return double values
00042   typedef double valueType;
00043   typedef std::pair<bool, valueType> evalType;
00044   typedef std::map<std::string, const CachingVariable*> vMap;
00045   struct CachingVariableFactoryArg {
00046     CachingVariableFactoryArg( const CachingVariableFactoryArg & copy) : n(copy.n),m(copy.m),iConfig(copy.iConfig){}
00047     CachingVariableFactoryArg(std::string & N,CachingVariable::vMap & M,edm::ParameterSet & P) : n(N),m(M),iConfig(P){}
00048     std::string & n;
00049     CachingVariable::vMap & m;
00050     edm::ParameterSet & iConfig;
00051   };
00052 
00053   CachingVariable(std::string m, std::string n, const edm::ParameterSet & iConfig) :
00054     cache_(std::make_pair(false,0)),method_(m),
00055     name_(n),conf_(iConfig) {}
00056 
00057   virtual ~CachingVariable() {}
00058 
00059   //does the variable computes
00060   bool compute(const edm::Event & iEvent) const {    return baseEval(iEvent).first;  }
00061 
00062   //accessor to the computed/cached value
00063   valueType operator()(const edm::Event & iEvent) const  {    return baseEval(iEvent).second;  }
00064 
00065   const std::string & name() const {return name_;}
00066   const std::string & method() const { return method_;}
00067   const Description & description()const { return d_;}
00068   void addDescriptionLine(const std::string & s){ d_.addLine(s);}
00069   const std::string & holderName() const { return holderName_;}
00070   void setHolder(std::string hn) const { holderName_=hn;}
00071 
00072   void print() const {
00073     edm::LogVerbatim("CachingVariable")<<name()
00074                                        <<"\n"<<description().text();
00075   }
00076  protected:
00077 
00078   mutable evalType cache_;
00079 
00080   std::string method_;
00081   std::string name_;
00082   mutable std::string holderName_;
00083   void setCache(valueType & v) const { 
00084     edm::Service<UpdaterService>()->checkOnce(name_+":"+holderName_);
00085     cache_.first=true; cache_.second = v;}
00086   void setNotCompute() const { 
00087     edm::Service<UpdaterService>()->checkOnce(name_+":"+holderName_);
00088     cache_.first=false; cache_.second = 0;}
00089   evalType & baseEval(const edm::Event & iEvent) const {
00090     if (edm::Service<UpdaterService>()->checkOnce(name_+":"+holderName_)){
00091       LogDebug("CachingVariable")<<name_+":"+holderName_<<" is checking once";
00092       cache_=eval(iEvent);
00093     }
00094     return cache_;
00095   }
00096   //cannot be made purely virtual otherwise one cannot have purely CachingVariableObjects
00097   virtual evalType eval(const edm::Event & iEvent) const {return std::make_pair(false,0);};
00098 
00099   Description d_;
00100   edm::ParameterSet conf_;
00101   friend class VariableComputer;
00102 };
00103 
00104 
00105 class ComputedVariable;
00106 class VariableComputer{
00107  public:
00108   VariableComputer(CachingVariable::CachingVariableFactoryArg arg);
00109   virtual ~VariableComputer(){}
00110 
00111   virtual void compute(const edm::Event & iEvent) const = 0;
00112   const std::string & name() const { return name_;}
00113   void declare(std::string var);
00114   void assign(std::string  var, double & value) const;
00115   void doesNotCompute() const;
00116   void doesNotCompute(std::string var) const;
00117 
00118  protected:
00119   CachingVariable::CachingVariableFactoryArg & arg_;
00120   std::string name_;
00121   std::string method_;
00122   mutable std::map<std::string ,const ComputedVariable *> iCompute_;
00123   std::string separator_;
00124 };
00125 
00126 
00127 #include "FWCore/PluginManager/interface/PluginFactory.h"
00128 #include "FWCore/ParameterSet/interface/ParameterSet.h"
00129 
00130 typedef edmplugin::PluginFactory< CachingVariable* (CachingVariable::CachingVariableFactoryArg) > CachingVariableFactory;
00131 typedef edmplugin::PluginFactory< VariableComputer* (CachingVariable::CachingVariableFactoryArg) > VariableComputerFactory;
00132 
00133 class ComputedVariable : public CachingVariable {
00134  public:
00135   ComputedVariable(CachingVariableFactoryArg arg );
00136   ComputedVariable(const std::string & M, std::string & N, edm::ParameterSet & P, const VariableComputer * c) : 
00137     CachingVariable(M,N,P), myComputer(c){}
00138   virtual ~ComputedVariable(){};
00139 
00140   virtual evalType eval(const edm::Event & iEvent) const {
00141     if (edm::Service<UpdaterService>()->checkOnce(myComputer->name()+":"+holderName_))
00142       myComputer->compute(iEvent);
00143     return cache_;
00144   }
00145  private:
00146   const VariableComputer * myComputer;
00147 };
00148 
00149 class VariableComputerTest : public VariableComputer {
00150  public:
00151   VariableComputerTest(CachingVariable::CachingVariableFactoryArg arg) ;
00152   ~VariableComputerTest(){};
00153 
00154   void compute(const edm::Event & iEvent) const;
00155 };
00156 
00157 class Splitter : public CachingVariable {
00158  public:
00159   Splitter(std::string method, std::string n, const edm::ParameterSet & iConfig) :
00160     CachingVariable(method,n,iConfig) {}
00161 
00162   //purely virtual here 
00163   virtual CachingVariable::evalType eval(const edm::Event & iEvent) const =0;
00164 
00165   unsigned int maxIndex() const { return maxSlots()-1;}
00166 
00167   //maximum NUMBER of slots: counting over/under flows
00168   virtual unsigned int maxSlots() const { return labels_.size();}
00169 
00170   const std::string shortLabel(unsigned int i) const{ 
00171     if (i>=short_labels_.size()){
00172       edm::LogError("Splitter")<<"trying to access slots short_label at index: "<<i<<"while of size: "<<short_labels_.size()<<"\n"<<conf_.dump();
00173       return short_labels_.back(); }
00174     else  return short_labels_[i];}
00175   
00176   const std::string & label(unsigned int i) const{ 
00177     if (i>=labels_.size()){
00178       edm::LogError("Splitter")<<"trying to access slots label at index: "<<i<<"while of size: "<<labels_.size()<<"\n"<<conf_.dump();
00179       return labels_.back(); }
00180     else return labels_[i];}
00181   
00182  protected:
00183   std::vector<std::string> labels_;
00184   std::vector<std::string> short_labels_;
00185 };
00186 
00187 
00188 class VarSplitter : public Splitter{ 
00189  public:
00190   VarSplitter(CachingVariableFactoryArg arg ) :
00191     Splitter("VarSplitter",arg.n,arg.iConfig) {
00192     var_=arg.iConfig.getParameter<std::string>("var");
00193     useUnderFlow_=arg.iConfig.getParameter<bool>("useUnderFlow");
00194     useOverFlow_=arg.iConfig.getParameter<bool>("useOverFlow");
00195     slots_=arg.iConfig.getParameter<std::vector<double> >("slots");
00196     if (useUnderFlow_){
00197       labels_.push_back("underflow");
00198       short_labels_.push_back("_"+arg.n+"_underflow");}
00199     std::vector<std::string> confLabels;
00200     if (arg.iConfig.exists("labels")){
00201       confLabels=arg.iConfig.getParameter<std::vector<std::string> >("labels");
00202     }
00203     else{
00204       std::string labelFormat = arg.iConfig.getParameter<std::string>("labelsFormat");
00205       for (unsigned int is=0;is!=slots_.size()-1;++is){
00206         std::string l(Form(labelFormat.c_str(),slots_[is],slots_[is+1]));
00207         confLabels.push_back(l);
00208       }
00209     }
00210     for (unsigned int i=0;i!=confLabels.size();++i){
00211       labels_.push_back(confLabels[i]);
00212       std::stringstream ss;
00213       ss<<"_"<<arg.n<<"_"<<i;
00214       short_labels_.push_back(ss.str());
00215     }
00216     if (useOverFlow_)
00217       { labels_.push_back("overFlow");
00218         short_labels_.push_back("_"+arg.n+"_overFlow");}
00219     
00220     //check consistency
00221     if (labels_.size()!=maxSlots())
00222       edm::LogError("Splitter")<<"splitter with name: "<<name()<<" has inconsistent configuration\n"<<conf_.dump();
00223 
00224     arg.m[arg.n]=this;
00225   }
00226 
00227   CachingVariable::evalType eval(const edm::Event & iEvent) const;
00228 
00229   //redefine the maximum number of slots
00230   unsigned int maxSlots() const{
00231     unsigned int s=slots_.size()-1;
00232     if (useUnderFlow_) s++;
00233     if (useOverFlow_) s++;
00234     return s;}
00235 
00236  protected:
00237   std::string var_;
00238   bool useUnderFlow_;
00239   bool useOverFlow_;
00240   std::vector<double> slots_;
00241 };
00242 
00243 template <typename Object> class sortByStringFunction  {
00244  public:
00245   sortByStringFunction(StringObjectFunction<Object> * f) : f_(f){}
00246   ~sortByStringFunction(){}
00247   
00248   bool operator() (const Object * o1, const Object * o2) {
00249     return (*f_)(*o1) > (*f_)(*o2);
00250   }
00251  private:
00252   StringObjectFunction<Object> * f_;
00253 };
00254 
00255 template <typename Object, const char * label> 
00256 class ExpressionVariable : public CachingVariable {
00257  public:
00258   ExpressionVariable(CachingVariableFactoryArg arg) :
00259     CachingVariable(std::string(label)+"ExpressionVariable",arg.n,arg.iConfig) , f_(0), forder_(0) {
00260     src_=edm::Service<InputTagDistributorService>()->retrieve("src",arg.iConfig);
00261     //old style constructor
00262     if (arg.iConfig.exists("expr") && arg.iConfig.exists("index")){
00263       std::string expr=arg.iConfig.getParameter<std::string>("expr");
00264       index_=arg.iConfig.getParameter<unsigned int>("index");
00265       f_ = new StringObjectFunction<Object>(expr);
00266       addDescriptionLine("calculating: "+expr);
00267       std::stringstream ss;
00268       ss<<"on object at index: "<<index_<<" of: "<<src_;
00269 
00270       if (arg.iConfig.exists("order")){
00271         std::string order=arg.iConfig.getParameter<std::string>("order");
00272         forder_ = new StringObjectFunction<Object>(order);
00273         ss<<" after sorting according to: "<<order;
00274       }else forder_ =0;
00275 
00276       if (arg.iConfig.exists("selection")){
00277         std::string selection=arg.iConfig.getParameter<std::string>("selection");
00278         selector_ = new StringCutObjectSelector<Object>(selection);
00279         ss<<" and selecting only: "<<selection;
00280       }else selector_=0;
00281 
00282 
00283 
00284       addDescriptionLine(ss.str());     ss.str("");
00285       arg.m[arg.n] = this;
00286     }
00287     else{
00288       //multiple instance constructor
00289       std::map<std::string, edm::Entry> indexEntry;
00290       if (arg.n.find("_N")!=std::string::npos){
00291         //will have to loop over indexes
00292         std::vector<unsigned int> indexes = arg.iConfig.getParameter<std::vector<unsigned int> >("indexes");
00293         for (unsigned int iI=0;iI!=indexes.size();++iI){
00294           edm::ParameterSet toUse = arg.iConfig;
00295           edm::Entry e("unsigned int",indexes[iI],true);
00296           std::stringstream ss;
00297           //add +1 0->1, 1->2, ... in the variable label
00298           ss<<indexes[iI]+1;
00299           indexEntry.insert(std::make_pair(ss.str(),e));
00300         }
00301       }//contains "_N"
00302       
00303       std::map< std::string, edm::Entry> varEntry;
00304       if (arg.n.find("_V")!=std::string::npos){
00305         //do something fancy for multiple variable from one PSet
00306         std::vector<std::string> vars = arg.iConfig.getParameter<std::vector<std::string> >("vars");
00307         for (unsigned int v=0;v!=vars.size();++v){
00308           unsigned int sep=vars[v].find(":");
00309           std::string name=vars[v].substr(0,sep);
00310           std::string expr=vars[v].substr(sep+1);
00311           
00312           edm::Entry e("string",expr,true);
00313           varEntry.insert(std::make_pair(name,e));
00314         }
00315       }//contains "_V"
00316       
00317       std::string radical = arg.n;
00318       //remove the "_V";
00319       if (!varEntry.empty())
00320         radical = radical.substr(0,radical.size()-2);
00321       //remove the "_N";
00322       if (!indexEntry.empty())
00323         radical = radical.substr(0,radical.size()-2);
00324       
00325       if(varEntry.empty()){
00326         //loop only the indexes
00327         for(std::map< std::string, edm::Entry>::iterator iIt=indexEntry.begin();iIt!=indexEntry.end();++iIt){
00328           edm::ParameterSet toUse = arg.iConfig;
00329           toUse.insert(true,"index",iIt->second);
00330           std::string newVname = radical+iIt->first;
00331           //      std::cout<<"in the loop, creating variable with name: "<<newVname<<std::endl;
00332           // the constructor auto log the new variable in the map
00333           new ExpressionVariable(CachingVariable::CachingVariableFactoryArg(newVname,arg.m,toUse));
00334         }
00335       }else{
00336         for (std::map< std::string, edm::Entry>::iterator vIt=varEntry.begin();vIt!=varEntry.end();++vIt){
00337           if (indexEntry.empty()){
00338             edm::ParameterSet toUse = arg.iConfig;
00339             toUse.insert(true,"expr",vIt->second);
00340             std::string newVname = radical+vIt->first;
00341             //      std::cout<<"in the loop, creating variable with name: "<<newVname<<std::endl;
00342             // the constructor auto log the new variable in the map
00343             new ExpressionVariable(CachingVariable::CachingVariableFactoryArg(newVname,arg.m,toUse));
00344           }else{
00345             for(std::map< std::string, edm::Entry>::iterator iIt=indexEntry.begin();iIt!=indexEntry.end();++iIt){
00346               edm::ParameterSet toUse = arg.iConfig;
00347               toUse.insert(true,"expr",vIt->second);
00348               toUse.insert(true,"index",iIt->second);
00349               std::string newVname = radical+iIt->first+vIt->first;
00350               //              std::cout<<"in the loop, creating variable with name: "<<newVname<<std::endl;
00351               // the constructor auto log the new variable in the map 
00352               new ExpressionVariable(CachingVariable::CachingVariableFactoryArg(newVname,arg.m,toUse));
00353             }}
00354         }
00355       }
00356       //there is a memory leak here, because the object we are in is not logged in the arg.m, the variable is not valid
00357       // anyways, but reside in memory with no ways of de-allocating it.
00358       // since the caching variables are actually "global" objects, it does not matter.
00359       // we cannot add it to the map, otherwise, it would be considered for eventV ntupler
00360     }
00361   }
00362   ~ExpressionVariable(){
00363     if (f_) delete f_;
00364     if (forder_) delete forder_;
00365     if (selector_) delete selector_;
00366   }
00367 
00368   CachingVariable::evalType eval(const edm::Event & iEvent) const {
00369     if (!f_) {
00370       edm::LogError(method())<<" no parser attached.";
00371       return std::make_pair(false,0);
00372     }
00373     edm::Handle<edm::View<Object> > oH;
00374     iEvent.getByLabel(src_,oH);
00375     if (index_>=oH->size()){
00376       LogDebug(method())<<"fail to get object at index: "<<index_<<" in collection: "<<src_;
00377       return std::make_pair(false,0);
00378     }
00379 
00380     //get the ordering right first. if required
00381     if (selector_ || forder_){
00382       std::vector<const Object*> copyToSort(0);
00383       copyToSort.reserve(oH->size());
00384       for (unsigned int i=0;i!=oH->size();++i){
00385         if (selector_ && !((*selector_)((*oH)[i]))) continue;
00386         copyToSort.push_back(&(*oH)[i]);
00387       }
00388       if (index_ >= copyToSort.size()) return std::make_pair(false,0);
00389       if (forder_) std::sort(copyToSort.begin(), copyToSort.end(), sortByStringFunction<Object>(forder_));
00390       
00391       const Object * o = copyToSort[index_];
00392       return std::make_pair(true,(*f_)(*o));
00393     }
00394     else{
00395       const Object & o = (*oH)[index_];
00396       return std::make_pair(true,(*f_)(o));
00397     }
00398   }
00399 
00400  private:
00401   edm::InputTag src_;
00402   unsigned int index_;
00403   StringObjectFunction<Object> * f_;
00404   StringObjectFunction<Object> * forder_;
00405   StringCutObjectSelector<Object> * selector_;
00406 };
00407 
00408 
00409 template< typename LHS,const char * lLHS, typename RHS,const char * lRHS, typename Calculator>
00410 class TwoObjectVariable : public CachingVariable {
00411 public:
00412   TwoObjectVariable(CachingVariableFactoryArg arg) :
00413     CachingVariable(Calculator::calculationType()+std::string(lLHS)+std::string(lRHS),arg.n,arg.iConfig),
00414     srcLhs_(edm::Service<InputTagDistributorService>()->retrieve("srcLhs",arg.iConfig)),
00415     indexLhs_(arg.iConfig.getParameter<unsigned int>("indexLhs")),
00416     srcRhs_(edm::Service<InputTagDistributorService>()->retrieve("srcRhs",arg.iConfig)),
00417     indexRhs_(arg.iConfig.getParameter<unsigned int>("indexRhs"))
00418       {
00419         std::stringstream ss;
00420         addDescriptionLine(Calculator::description());
00421         ss<<"with Obj1 at index: "<<indexLhs_<<" of: "<<srcLhs_;
00422         addDescriptionLine(ss.str());   ss.str("");
00423         ss<<"with Obj2 at index: "<<indexRhs_<<" of: "<<srcRhs_;
00424         addDescriptionLine(ss.str());   ss.str("");
00425         arg.m[arg.n]=this;
00426       }
00427 
00428     class getObject{
00429     public:
00430       getObject() : test(false),lhs(0),rhs(0){}
00431       bool test;
00432       const LHS * lhs;
00433       const RHS * rhs;
00434     };
00435     getObject objects(const edm::Event & iEvent) const {
00436       getObject failed;
00437       edm::Handle<std::vector<LHS> > lhsH;
00438       iEvent.getByLabel(srcLhs_, lhsH);
00439       if (lhsH.failedToGet()){
00440         LogDebug("TwoObjectVariable")<<name()<<" could not get a collection with label: "<<srcLhs_;
00441         return failed;}
00442       if (indexLhs_>=lhsH->size()){
00443         LogDebug("TwoObjectVariable")<<name()<<" tries to access index: "<<indexLhs_<<" of: "<<srcLhs_<<" with: "<<lhsH->size()<<" entries.";
00444       return failed;}
00445       const LHS & lhs = (*lhsH)[indexLhs_];
00446       
00447       edm::Handle<std::vector<RHS> > rhsH;
00448       iEvent.getByLabel(srcRhs_, rhsH);
00449       if (rhsH.failedToGet()){
00450         LogDebug("TwoObjectVariable")<<name()<<" could not get a collection with label: "<<srcLhs_;
00451         return failed;}
00452       
00453       if (indexRhs_>=rhsH->size()){
00454         LogDebug("TwoObjectVariable")<<name()<<" tries to access index: "<<indexRhs_<<" of: "<<srcRhs_<<" with: "<<rhsH->size()<<" entries.";
00455         return failed;}
00456       const RHS & rhs = (*rhsH)[indexRhs_];
00457       
00458       failed.test=true;
00459       failed.lhs=&lhs;
00460       failed.rhs=&rhs;
00461       return failed;
00462     }
00463 
00464     //to be overloaded by the user
00465     virtual CachingVariable::valueType calculate(getObject & o) const {
00466       Calculator calc;
00467       return calc(*o.lhs,*o.rhs);
00468     }
00469     CachingVariable::evalType eval(const edm::Event & iEvent) const {
00470       getObject o=objects(iEvent);
00471       if (!o.test) return std::make_pair(false,0);
00472       return std::make_pair(true,calculate(o));
00473     }
00474 private:
00475   edm::InputTag srcLhs_;
00476   unsigned int indexLhs_;
00477   edm::InputTag srcRhs_;
00478   unsigned int indexRhs_;
00479 };
00480 
00481 
00482 class VariablePower : public CachingVariable {
00483  public:
00484   VariablePower(CachingVariableFactoryArg arg) :
00485     CachingVariable("Power",arg.n,arg.iConfig){
00486     power_=arg.iConfig.getParameter<double>("power");
00487     var_=arg.iConfig.getParameter<std::string>("var");
00488     std::stringstream ss("Calculare X^Y, with X=");
00489     ss<<var_<<" and Y="<<power_;
00490     addDescriptionLine(ss.str());
00491     arg.m[arg.n]=this;
00492   }
00493   ~VariablePower(){}
00494  
00495  //concrete calculation of the variable
00496   CachingVariable::evalType eval(const edm::Event & iEvent) const;
00497 
00498  private:
00499   double power_;
00500   std::string var_;
00501 };
00502 
00503 
00504 template <typename TYPE>
00505 class SimpleValueVariable : public CachingVariable {
00506  public:
00507   SimpleValueVariable(CachingVariableFactoryArg arg) :
00508     CachingVariable("SimpleValueVariable",arg.n,arg.iConfig),
00509     src_(edm::Service<InputTagDistributorService>()->retrieve("src",arg.iConfig)) { arg.m[arg.n]=this;}
00510   CachingVariable::evalType eval(const edm::Event & iEvent) const{
00511     edm::Handle<TYPE> value;
00512     try{    iEvent.getByLabel(src_,value);   }  
00513     catch(...){ return std::make_pair(false,0); }
00514     if (value.failedToGet() || !value.isValid()) return std::make_pair(false,0);
00515     else return std::make_pair(true, *value);
00516   }
00517  private:
00518   edm::InputTag src_;
00519 };
00520 
00521 template <typename TYPE>
00522 class SimpleValueVectorVariable : public CachingVariable {
00523  public:
00524   SimpleValueVectorVariable(CachingVariableFactoryArg arg) :
00525     CachingVariable("SimpleValueVectorVariable",arg.n,arg.iConfig),
00526     src_(edm::Service<InputTagDistributorService>()->retrieve("src",arg.iConfig)),
00527     index_(arg.iConfig.getParameter<unsigned int>("index")) { arg.m[arg.n]=this;}
00528   CachingVariable::evalType eval(const edm::Event & iEvent) const{
00529     edm::Handle<std::vector<TYPE> > values;
00530     try { iEvent.getByLabel(src_,values);} 
00531     catch(...){ return std::make_pair(false,0); }
00532     if (values.failedToGet() || !values.isValid()) return std::make_pair(false,0);
00533     else if (index_>=values->size()) return std::make_pair(false,0);
00534     else return std::make_pair(true, (*values)[index_]);
00535   }
00536   
00537  private:
00538   edm::InputTag src_;
00539   unsigned int index_;
00540 };
00541 
00542 
00543 
00544 
00545 
00546 
00547 
00548 #endif