00001 #ifndef PhysicsTools_CandUtils_CandCombinerBase_h 00002 #define PhysicsTools_CandUtils_CandCombinerBase_h 00003 00008 #include "DataFormats/Candidate/interface/Candidate.h" 00009 #include "DataFormats/Candidate/interface/OverlapChecker.h" 00010 #include <vector> 00011 #include <string> 00012 00013 template<typename OutputCollection, typename CandPtr> 00014 class CandCombinerBase { 00015 public: 00016 typedef std::vector<std::string> vstring; 00018 explicit CandCombinerBase(const std::string = ""); 00020 CandCombinerBase(int, int, const std::string = ""); 00022 CandCombinerBase(int, int, int, const std::string = ""); 00024 CandCombinerBase(int, int, int, int, const std::string = ""); 00026 CandCombinerBase(bool checkCharge, const std::vector <int> &, const std::string = ""); 00028 virtual ~CandCombinerBase(); 00030 std::auto_ptr<OutputCollection> 00031 combine(const std::vector<edm::Handle<reco::CandidateView> > &, const vstring = vstring()) const; 00033 std::auto_ptr<OutputCollection> 00034 combine(const edm::Handle<reco::CandidateView> &, const vstring = vstring()) const; 00036 std::auto_ptr<OutputCollection> 00037 combine(const edm::Handle<reco::CandidateView> &, 00038 const edm::Handle<reco::CandidateView> &, const vstring = vstring()) const; 00040 std::auto_ptr<OutputCollection> 00041 combine(const edm::Handle<reco::CandidateView> &, 00042 const edm::Handle<reco::CandidateView> &, 00043 const edm::Handle<reco::CandidateView> &, const vstring = vstring()) const; 00045 std::auto_ptr<OutputCollection> 00046 combine(const edm::Handle<reco::CandidateView> &, 00047 const edm::Handle<reco::CandidateView> &, 00048 const edm::Handle<reco::CandidateView> &, 00049 const edm::Handle<reco::CandidateView> &, const vstring = vstring()) const; 00050 00051 private: 00053 bool preselect(const reco::Candidate &, const reco::Candidate &) const; 00055 void combine(typename OutputCollection::value_type &, 00056 const CandPtr &, 00057 const CandPtr &, const std::string = "", const std::string = "") const; 00059 typedef std::vector<std::pair<std::pair<CandPtr, size_t>, 00060 std::vector<edm::Handle<reco::CandidateView> >::const_iterator> > CandStack; 00061 typedef std::vector<int> ChargeStack; 00063 void combine(size_t collectionIndex, CandStack &, ChargeStack &, 00064 std::vector<edm::Handle<reco::CandidateView> >::const_iterator begin, 00065 std::vector<edm::Handle<reco::CandidateView> >::const_iterator end, 00066 std::auto_ptr<OutputCollection> & comps, 00067 const vstring name = vstring()) const; 00069 virtual bool select(const reco::Candidate &) const = 0; 00071 virtual bool selectPair(const reco::Candidate & c1, const reco::Candidate & c2) const = 0; 00073 virtual void setup(typename OutputCollection::value_type &) const = 0; 00075 virtual void addDaughter(typename OutputCollection::value_type & cmp, const CandPtr & c, const std::string = "") const = 0; 00077 bool checkCharge_; 00079 std::vector<int> dauCharge_; 00081 OverlapChecker overlap_; 00083 std::string name_; 00084 }; 00085 00086 template<typename OutputCollection, typename CandPtr> 00087 CandCombinerBase<OutputCollection, CandPtr>::CandCombinerBase(const std::string name) : 00088 checkCharge_(false), dauCharge_(), overlap_(), name_(name) { 00089 } 00090 00091 template<typename OutputCollection, typename CandPtr> 00092 CandCombinerBase<OutputCollection, CandPtr>::CandCombinerBase(int q1, int q2, const std::string name) : 00093 checkCharge_(true), dauCharge_(2), overlap_(), name_(name) { 00094 dauCharge_[0] = q1; 00095 dauCharge_[1] = q2; 00096 } 00097 00098 template<typename OutputCollection, typename CandPtr> 00099 CandCombinerBase<OutputCollection, CandPtr>::CandCombinerBase(int q1, int q2, int q3, const std::string name) : 00100 checkCharge_(true), dauCharge_(3), overlap_(), name_(name) { 00101 dauCharge_[0] = q1; 00102 dauCharge_[1] = q2; 00103 dauCharge_[2] = q3; 00104 } 00105 00106 template<typename OutputCollection, typename CandPtr> 00107 CandCombinerBase<OutputCollection, CandPtr>::CandCombinerBase(int q1, int q2, int q3, int q4, const std::string name) : 00108 checkCharge_(true), dauCharge_(4), overlap_(), name_(name) { 00109 dauCharge_[0] = q1; 00110 dauCharge_[1] = q2; 00111 dauCharge_[2] = q3; 00112 dauCharge_[3] = q4; 00113 } 00114 00115 template<typename OutputCollection, typename CandPtr> 00116 CandCombinerBase<OutputCollection, CandPtr>::CandCombinerBase(bool checkCharge, const std::vector<int> & dauCharge, const std::string name) : 00117 checkCharge_(checkCharge), dauCharge_(dauCharge), overlap_(), name_(name) { 00118 } 00119 00120 template<typename OutputCollection, typename CandPtr> 00121 CandCombinerBase<OutputCollection, CandPtr>::~CandCombinerBase() { 00122 } 00123 00124 template<typename OutputCollection, typename CandPtr> 00125 bool CandCombinerBase<OutputCollection, CandPtr>::preselect(const reco::Candidate & c1, const reco::Candidate & c2) const { 00126 if (checkCharge_) { 00127 int dq1 = dauCharge_[0], dq2 = dauCharge_[1], q1 = c1.charge(), q2 = c2.charge(); 00128 bool matchCharge = (q1 == dq1 && q2 == dq2) || (q1 == -dq1 && q2 == -dq2); 00129 if (!matchCharge) return false; 00130 } 00131 if (overlap_(c1, c2)) return false; 00132 return selectPair(c1, c2); 00133 } 00134 00135 template<typename OutputCollection, typename CandPtr> 00136 void CandCombinerBase<OutputCollection, CandPtr>::combine(typename OutputCollection::value_type & cmp, 00137 const CandPtr & c1, const CandPtr & c2, 00138 const std::string name1, const std::string name2) const { 00139 addDaughter(cmp, c1, name1); 00140 addDaughter(cmp, c2, name2); 00141 setup(cmp); 00142 } 00143 00144 template<typename OutputCollection, typename CandPtr> 00145 std::auto_ptr<OutputCollection> 00146 CandCombinerBase<OutputCollection, CandPtr>::combine(const std::vector<edm::Handle<reco::CandidateView> > & src, 00147 const vstring names) const { 00148 size_t srcSize = src.size(); 00149 if (checkCharge_ && dauCharge_.size() != srcSize) 00150 throw edm::Exception(edm::errors::Configuration) 00151 << "CandCombiner: trying to combine " << srcSize << " collections" 00152 << " but configured to check against " << dauCharge_.size() << " charges."; 00153 std::auto_ptr<OutputCollection> comps(new OutputCollection); 00154 size_t namesSize = names.size(); 00155 if(srcSize == 2) { 00156 std::string name1="", name2=""; 00157 if(namesSize > 0) { 00158 if(namesSize != 2) 00159 throw edm::Exception(edm::errors::Configuration) 00160 << "CandCombiner: should specify exactly two " 00161 << " names in configuration (" << namesSize << " specified).\n"; 00162 name1 = names[0]; 00163 name2 = names[1]; 00164 } 00165 edm::Handle<reco::CandidateView> src1 = src[0], src2 = src[1]; 00166 if(src1.id() == src2.id()) { 00167 const reco::CandidateView & cands = * src1; 00168 const size_t n = cands.size(); 00169 for(size_t i1 = 0; i1 < n; ++i1) { 00170 const reco::Candidate & c1 = cands[i1]; 00171 CandPtr cr1(src1, i1); 00172 for(size_t i2 = i1 + 1; i2 < n; ++i2) { 00173 const reco::Candidate & c2 = cands[i2]; 00174 if(preselect(c1, c2)) { 00175 CandPtr cr2(src2, i2); 00176 typename OutputCollection::value_type c; 00177 combine(c, cr1, cr2, name1, name2); 00178 if(select(c)) 00179 comps->push_back(c); 00180 } 00181 } 00182 } 00183 } else { 00184 const reco::CandidateView & cands1 = * src1, & cands2 = * src2; 00185 const size_t n1 = cands1.size(), n2 = cands2.size(); 00186 for(size_t i1 = 0; i1 < n1; ++i1) { 00187 const reco::Candidate & c1 = cands1[i1]; 00188 CandPtr cr1(src1, i1); 00189 for(size_t i2 = 0; i2 < n2; ++i2) { 00190 const reco::Candidate & c2 = cands2[i2]; 00191 if(preselect(c1, c2)) { 00192 CandPtr cr2(src2, i2); 00193 typename OutputCollection::value_type c; 00194 combine(c, cr1, cr2, name1, name2); 00195 if(select(c)) 00196 comps->push_back(c); 00197 } 00198 } 00199 } 00200 } 00201 } else { 00202 CandStack stack; 00203 ChargeStack qStack; 00204 combine(0, stack, qStack, src.begin(), src.end(), comps, names); 00205 } 00206 00207 return comps; 00208 } 00209 00210 template<typename OutputCollection, typename CandPtr> 00211 std::auto_ptr<OutputCollection> 00212 CandCombinerBase<OutputCollection, CandPtr>::combine(const edm::Handle<reco::CandidateView> & src, 00213 const vstring names) const { 00214 if(checkCharge_ && dauCharge_.size() != 2) 00215 throw edm::Exception(edm::errors::Configuration) 00216 << "CandCombiner: trying to combine 2 collections" 00217 << " but configured to check against " << dauCharge_.size() << " charges."; 00218 00219 std::auto_ptr<OutputCollection> comps(new OutputCollection); 00220 size_t namesSize = names.size(); 00221 std::string name1, name2; 00222 if(namesSize > 0) { 00223 if(namesSize != 2) 00224 throw edm::Exception(edm::errors::Configuration) 00225 << "CandCombiner: should specify exactly two " 00226 << " names in configuration (" << namesSize << " specified).\n"; 00227 name1 = names[0]; 00228 name2 = names[1]; 00229 } 00230 const reco::CandidateView & cands = * src; 00231 const size_t n = cands.size(); 00232 for(size_t i1 = 0; i1 < n; ++i1) { 00233 const reco::Candidate & c1 = cands[i1]; 00234 CandPtr cr1(src, i1); 00235 for(size_t i2 = i1 + 1; i2 < n; ++i2) { 00236 const reco::Candidate & c2 = cands[i2]; 00237 if(preselect(c1, c2)) { 00238 CandPtr cr2(src, i2); 00239 typename OutputCollection::value_type c; 00240 combine(c, cr1, cr2, name1, name2); 00241 if(select(c)) 00242 comps->push_back(c); 00243 } 00244 } 00245 } 00246 00247 return comps; 00248 } 00249 00250 template<typename OutputCollection, typename CandPtr> 00251 std::auto_ptr<OutputCollection> 00252 CandCombinerBase<OutputCollection, CandPtr>::combine(const edm::Handle<reco::CandidateView> & src1, 00253 const edm::Handle<reco::CandidateView> & src2, 00254 const vstring names) const { 00255 std::vector<edm::Handle<reco::CandidateView> > src; 00256 src.push_back(src1); 00257 src.push_back(src2); 00258 return combine(src, names); 00259 } 00260 00261 template<typename OutputCollection, typename CandPtr> 00262 std::auto_ptr<OutputCollection> 00263 CandCombinerBase<OutputCollection, CandPtr>::combine(const edm::Handle<reco::CandidateView> & src1, 00264 const edm::Handle<reco::CandidateView> & src2, 00265 const edm::Handle<reco::CandidateView> & src3, 00266 const vstring names) const { 00267 std::vector<edm::Handle<reco::CandidateView> > src; 00268 src.push_back(src1); 00269 src.push_back(src2); 00270 src.push_back(src3); 00271 return combine(src, names); 00272 } 00273 00274 template<typename OutputCollection, typename CandPtr> 00275 std::auto_ptr<OutputCollection> 00276 CandCombinerBase<OutputCollection, CandPtr>::combine(const edm::Handle<reco::CandidateView> & src1, 00277 const edm::Handle<reco::CandidateView> & src2, 00278 const edm::Handle<reco::CandidateView> & src3, 00279 const edm::Handle<reco::CandidateView> & src4, 00280 const vstring names) const { 00281 std::vector<edm::Handle<reco::CandidateView> > src; 00282 src.push_back(src1); 00283 src.push_back(src2); 00284 src.push_back(src3); 00285 src.push_back(src4); 00286 return combine(src, names); 00287 } 00288 00289 template<typename OutputCollection, typename CandPtr> 00290 void CandCombinerBase<OutputCollection, CandPtr>::combine(size_t collectionIndex, CandStack & stack, ChargeStack & qStack, 00291 std::vector<edm::Handle<reco::CandidateView> >::const_iterator collBegin, 00292 std::vector<edm::Handle<reco::CandidateView> >::const_iterator collEnd, 00293 std::auto_ptr<OutputCollection> & comps, 00294 const vstring names) const { 00295 if(collBegin == collEnd) { 00296 static const int undetermined = 0, sameDecay = 1, conjDecay = -1, wrongDecay = 2; 00297 int decayType = undetermined; 00298 if(checkCharge_) { 00299 assert(qStack.size() == stack.size()); 00300 for(size_t i = 0; i < qStack.size(); ++i) { 00301 int q = qStack[i], dq = dauCharge_[i]; 00302 if(decayType == undetermined) { 00303 if(q != 0 && dq != 0) { 00304 if(q == dq) decayType = sameDecay; 00305 else if(q == -dq) decayType = conjDecay; 00306 else decayType = wrongDecay; 00307 } 00308 } else if((decayType == sameDecay && q != dq) || 00309 (decayType == conjDecay && q != -dq)) { 00310 decayType = wrongDecay; 00311 } 00312 if(decayType == wrongDecay) break; 00313 } 00314 } 00315 if(decayType != wrongDecay) { 00316 typename OutputCollection::value_type c; 00317 size_t nameIndex = 0; 00318 for(typename CandStack::const_iterator i = stack.begin(); i != stack.end(); ++i, ++ nameIndex) { 00319 if ( names.size() > 0 ) 00320 addDaughter(c, i->first.first, names[nameIndex]); 00321 else 00322 addDaughter(c, i->first.first); 00323 } 00324 setup(c); 00325 if(select(c)) 00326 comps->push_back(c); 00327 } 00328 } else { 00329 const edm::Handle<reco::CandidateView> & srcRef = * collBegin; 00330 const reco::CandidateView & src = * srcRef; 00331 size_t candBegin = 0, candEnd = src.size(); 00332 for(typename CandStack::const_iterator i = stack.begin(); i != stack.end(); ++i) 00333 if(srcRef.id() == i->second->id()) 00334 candBegin = i->first.second + 1; 00335 for(size_t candIndex = candBegin; candIndex != candEnd; ++ candIndex) { 00336 CandPtr candRef(srcRef, candIndex); 00337 bool noOverlap = true; 00338 const reco::Candidate & cand = * candRef; 00339 for(typename CandStack::const_iterator i = stack.begin(); i != stack.end(); ++i) 00340 if(overlap_(cand, *(i->first.first))) { 00341 noOverlap = false; 00342 break; 00343 } 00344 if(noOverlap) { 00345 stack.push_back(std::make_pair(std::make_pair(candRef, candIndex), collBegin)); 00346 if(checkCharge_) qStack.push_back(cand.charge()); 00347 combine(collectionIndex + 1, stack, qStack, collBegin + 1, collEnd, comps, names); 00348 stack.pop_back(); 00349 qStack.pop_back(); 00350 } 00351 } 00352 } 00353 } 00354 00355 #endif