Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2023-03-17 10:45:44

0001 #include <cppunit/extensions/HelperMacros.h>
0002 
0003 #include "CommonTools/Utils/interface/ExpressionEvaluator.h"
0004 #include "CommonTools/Utils/interface/ExpressionEvaluatorTemplates.h"
0005 
0006 #include "DataFormats/TrackReco/interface/Track.h"
0007 #include "DataFormats/TrackReco/interface/TrackExtra.h"
0008 #include "DataFormats/Candidate/interface/CompositeCandidate.h"
0009 #include "DataFormats/Candidate/interface/LeafCandidate.h"
0010 #include "DataFormats/PatCandidates/interface/Jet.h"
0011 #include "DataFormats/PatCandidates/interface/Muon.h"
0012 
0013 class testExpressionEvaluator : public CppUnit::TestFixture {
0014   CPPUNIT_TEST_SUITE(testExpressionEvaluator);
0015   CPPUNIT_TEST(checkAll);
0016   CPPUNIT_TEST_SUITE_END();
0017 
0018 public:
0019   testExpressionEvaluator() {}  // for crappy pats
0020   ~testExpressionEvaluator() {}
0021   void checkAll();
0022 };
0023 
0024 CPPUNIT_TEST_SUITE_REGISTRATION(testExpressionEvaluator);
0025 
0026 #include <iostream>
0027 namespace {
0028   void checkCandidate(reco::LeafCandidate const &cand, const std::string &expression, double x) {
0029     std::cerr << "testing " << expression << std::endl;
0030     try {
0031       //provide definition of the virtual function as a string
0032       std::string sexpr = "double eval(reco::LeafCandidate const& cand) const override { return ";
0033       sexpr += expression + ";}";
0034       // construct the expression evaluator (pkg where precompile.h resides, name of base class, declaration of overloaded member function)
0035       reco::ExpressionEvaluator eval(
0036           "CommonTools/CandUtils", "reco::ValueOnObject<reco::LeafCandidate>", sexpr.c_str());
0037       // obtain a pointer to the base class  (to be stored in Filter and Analyser at thier costruction time!)
0038       reco::ValueOnObject<reco::LeafCandidate> const *expr = eval.expr<reco::ValueOnObject<reco::LeafCandidate>>();
0039       CPPUNIT_ASSERT(expr);
0040       // invoke
0041       CPPUNIT_ASSERT(std::abs(expr->eval(cand) - x) < 1.e-6);
0042     } catch (cms::Exception const &e) {
0043       // if compilation fails, the compiler output is part of the exception message
0044       std::cerr << e.what() << std::endl;
0045       CPPUNIT_ASSERT("ExpressionEvaluator threw" == 0);
0046     }
0047   }
0048 
0049   std::vector<reco::LeafCandidate> generate() {
0050     reco::Candidate::LorentzVector p1(10, -10, -10, 15);
0051     reco::Candidate::LorentzVector incr(0, 3, 3, 0);
0052 
0053     int sign = 1;
0054     std::vector<reco::LeafCandidate> ret;
0055     for (int i = 0; i < 10; ++i) {
0056       ret.emplace_back(sign, p1);
0057       sign = -sign;
0058       p1 += incr;
0059     }
0060     return ret;
0061   }
0062 
0063   struct MyAnalyzer {
0064     using Selector = reco::MaskCollection<reco::LeafCandidate>;
0065     explicit MyAnalyzer(std::string const &cut) {
0066       std::string sexpr = "void eval(Collection const & c, Mask & m) const override{";
0067       sexpr += "\n auto cut = [](reco::LeafCandidate const & cand){ return " + cut + ";};\n";
0068       sexpr += "mask(c,m,cut); }";
0069       std::cerr << "testing " << sexpr << std::endl;
0070       try {
0071         reco::ExpressionEvaluator eval(
0072             "CommonTools/CandUtils", "reco::MaskCollection<reco::LeafCandidate>", sexpr.c_str());
0073         m_selector = eval.expr<Selector>();
0074         CPPUNIT_ASSERT(m_selector);
0075       } catch (cms::Exception const &e) {
0076         std::cerr << e.what() << std::endl;
0077         CPPUNIT_ASSERT("ExpressionEvaluator threw" == 0);
0078       }
0079     }
0080 
0081     void analyze() const {
0082       auto inputColl = generate();
0083       Selector::Collection cands;
0084       cands.reserve(inputColl.size());
0085       for (auto const &c : inputColl)
0086         cands.push_back(&c);
0087       Selector::Mask mask;
0088       m_selector->eval(cands, mask);
0089       CPPUNIT_ASSERT(2 == std::count(mask.begin(), mask.end(), true));
0090       int ind = 0;
0091       cands.erase(
0092           std::remove_if(
0093               cands.begin(), cands.end(), [&](Selector::Collection::value_type const &) { return !mask[ind++]; }),
0094           cands.end());
0095       CPPUNIT_ASSERT(2 == cands.size());
0096     }
0097 
0098     Selector const *m_selector = nullptr;
0099   };
0100 
0101   struct MyAnalyzer2 {
0102     using Selector = reco::SelectInCollection<reco::LeafCandidate>;
0103     explicit MyAnalyzer2(std::string const &cut) {
0104       std::string sexpr = "void eval(Collection & c) const override{";
0105       sexpr += "\n auto cut = [](reco::LeafCandidate const & cand){ return " + cut + ";};\n";
0106       sexpr += "select(c,cut); }";
0107       std::cerr << "testing " << sexpr << std::endl;
0108       try {
0109         reco::ExpressionEvaluator eval(
0110             "CommonTools/CandUtils", "reco::SelectInCollection<reco::LeafCandidate>", sexpr.c_str());
0111         m_selector = eval.expr<Selector>();
0112         CPPUNIT_ASSERT(m_selector);
0113       } catch (cms::Exception const &e) {
0114         std::cerr << e.what() << std::endl;
0115         CPPUNIT_ASSERT("ExpressionEvaluator threw" == 0);
0116       }
0117     }
0118 
0119     void analyze() const {
0120       auto inputColl = generate();
0121       Selector::Collection cands;
0122       cands.reserve(inputColl.size());
0123       for (auto const &c : inputColl)
0124         cands.push_back(&c);
0125       m_selector->eval(cands);
0126       CPPUNIT_ASSERT(2 == cands.size());
0127     }
0128 
0129     Selector const *m_selector = nullptr;
0130   };
0131 
0132 }  // namespace
0133 
0134 void testExpressionEvaluator::checkAll() {
0135   reco::CompositeCandidate cand;
0136 
0137   reco::Candidate::LorentzVector p1(1, 2, 3, 4);
0138   reco::Candidate::LorentzVector p2(1.1, -2.5, 4.3, 13.7);
0139   reco::LeafCandidate c1(+1, p1);
0140   reco::LeafCandidate c2(-1, p2);
0141   cand.addDaughter(c1);
0142   cand.addDaughter(c2);
0143   CPPUNIT_ASSERT(cand.numberOfDaughters() == 2);
0144   CPPUNIT_ASSERT(cand.daughter(0) != 0);
0145   CPPUNIT_ASSERT(cand.daughter(1) != 0);
0146   {
0147     checkCandidate(cand, "cand.numberOfDaughters()", cand.numberOfDaughters());
0148     checkCandidate(cand, "cand.daughter(0)->isStandAloneMuon()", cand.daughter(0)->isStandAloneMuon());
0149     checkCandidate(cand, "cand.daughter(1)->isStandAloneMuon()", cand.daughter(1)->isStandAloneMuon());
0150     checkCandidate(cand, "cand.daughter(0)->pt()", cand.daughter(0)->pt());
0151     checkCandidate(cand, "cand.daughter(1)->pt()", cand.daughter(1)->pt());
0152     checkCandidate(cand,
0153                    "std::min(cand.daughter(0)->pt(), cand.daughter(1)->pt())",
0154                    std::min(cand.daughter(0)->pt(), cand.daughter(1)->pt()));
0155     checkCandidate(cand,
0156                    "std::max(cand.daughter(0)->pt(), cand.daughter(1)->pt())",
0157                    std::max(cand.daughter(0)->pt(), cand.daughter(1)->pt()));
0158     checkCandidate(cand,
0159                    "reco::deltaPhi(cand.daughter(0)->phi(), cand.daughter(1)->phi())",
0160                    reco::deltaPhi(cand.daughter(0)->phi(), cand.daughter(1)->phi()));
0161     // check also opposite order, to see that the sign is correct
0162     checkCandidate(cand,
0163                    "reco::deltaPhi(cand.daughter(1)->phi(), cand.daughter(0)->phi())",
0164                    reco::deltaPhi(cand.daughter(1)->phi(), cand.daughter(0)->phi()));
0165     checkCandidate(
0166         cand, "reco::deltaR(*cand.daughter(0), *cand.daughter(1))", reco::deltaR(*cand.daughter(0), *cand.daughter(1)));
0167   }
0168 
0169   MyAnalyzer analyzer("cand.pt()>15 & std::abs(cand.eta())<2");
0170   analyzer.analyze();
0171 
0172   MyAnalyzer2 analyzer2("cand.pt()>15 & std::abs(cand.eta())<2");
0173   analyzer2.analyze();
0174 
0175   // pat
0176 
0177   std::vector<reco::LeafCandidate> cands;
0178   cands.push_back(c1);
0179   cands.push_back(c2);
0180   edm::TestHandle<std::vector<reco::LeafCandidate>> constituentsHandle(&cands, edm::ProductID(42));
0181   reco::Jet::Constituents constituents;
0182   constituents.push_back(reco::Jet::Constituent(constituentsHandle, 0));
0183   constituents.push_back(reco::Jet::Constituent(constituentsHandle, 1));
0184   reco::CaloJet::Specific caloSpecific;
0185   caloSpecific.mMaxEInEmTowers = 0.5;
0186   pat::Jet jet(reco::CaloJet(p1 + p2, reco::Jet::Point(), caloSpecific, constituents));
0187   {
0188     std::string expression = "jet.userData<math::XYZVector>(\"my2int\")";
0189     std::cerr << "testing " << expression << std::endl;
0190     try {
0191       //provide definition of the virtual function as a string
0192       std::string sexpr = "math::XYZVector const * operator()(pat::Jet const& jet) const override { return ";
0193       sexpr += expression + ";}";
0194       // obtain a pointer to the base class  (to be stored in Filter and Analyser at thier costruction time!)
0195       auto const *expr =
0196           reco_expressionEvaluator("CommonTools/RecoUtils",
0197                                    SINGLE_ARG(reco::genericExpression<math::XYZVector const *, pat::Jet const &>),
0198                                    sexpr);
0199       CPPUNIT_ASSERT(expr);
0200       // invoke
0201       CPPUNIT_ASSERT((*expr)(jet) == nullptr);
0202       jet.addUserData("my2int", math::XYZVector(-2, -1, 2));
0203       CPPUNIT_ASSERT(jet.userData<math::XYZVector>("my2int")->z() == 2);
0204       std::cout << "now expr eval" << std::endl;
0205       CPPUNIT_ASSERT((*expr)(jet)->z() == 2);
0206     } catch (cms::Exception const &e) {
0207       // if compilation fails, the compiler output is part of the exception message
0208       std::cerr << e.what() << std::endl;
0209       CPPUNIT_ASSERT("ExpressionEvaluator threw" == 0);
0210     }
0211   }
0212 }