// @(#)root/test:$Id$ // Author: Lorenzo Moneta 06/2005 /////////////////////////////////////////////////////////////////////////////////// // // MathCore Benchmark test suite // ============================== // // This program performs tests of ROOT::Math 4D LorentzVectors comparing with TLorentzVector // The time performing various vector operations on a collection of vectors is measured. // The benchmarked operations are: // - vector construction from 4 values // - construction using a setter method // - simple addition of all the vector pairs in the collection // - calculation of deltaR = phi**2 + eta**2 of all vector pairs in the collection // - two simple analysis: // - the first requires some cut (on pt and eta) and on the invariant mass // of the selected pairs // - the second requires just some cut in pt, eta and delta R on all the // vector pair // - conversion between XYZTVectors to PtRhoEtaPhi based vectors // // The two analysis demostrates, especially in the second case, the advantage of using // vector based on cylindrical coordinate, given the fact that the time spent in the conversion is // much less than the time spent in the analysis routine. // // To run the program do: // stressVector : run standard test with collection of 1000 vectors // stressVector 10000 : run with a collection of 10000 vectors // /////////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include "TStopwatch.h" #include "TRandom3.h" #include "TVector2.h" #include "Math/Vector2D.h" #include "Math/Point2D.h" #include "Math/SVector.h" #include #include "limits" #ifdef HAVE_CLHEP #include "CLHEP/Vector/TwoVector.h" #endif //#define DEBUG using namespace ROOT::Math; class VectorTest { private: // global data variables std::vector dataX; std::vector dataY; size_t nGen; size_t n2Loop ; public: VectorTest(int n1, int n2) : nGen(n1), n2Loop(n2) {} void print(TStopwatch & time, std::string s) { int pr = std::cout.precision(8); std::cout << s << "\t" << " time = " << time.RealTime() << "\t(sec)\t" // << time.CpuTime() << std::endl; std::cout.precision(pr); } int check(std::string name, double s1, double s2, double s3, double scale=1) { double eps = 10*scale*std::numeric_limits::epsilon(); if ( std::fabs(s1-s2) < eps*std::fabs(s1) && std::fabs(s1-s3) < eps*std::fabs(s1) ) return 0; int pr = std::cout.precision(16); std::cout << s1 << "\t" << s2 <<"\t" << s3 << "\n"; std::cout << "Rel Diff 1-2:\t" << (s1-s2)/std::fabs(s1) << " Diff 1-3:\t" << (s1-s3)/std::fabs(s1) << std::endl; std::cout << "Test " << name << " failed !!\n\n"; std::cout.precision(pr); return -1; } void genData() { int n = nGen; // generate 2 d data TRandom3 rdm; for (int i = 0; i < n ; ++ i) { double phi = rdm.Rndm()*3.1415926535897931; double r = rdm.Exp(10.); // fill vectors Polar2DVector q( r, phi); dataX.push_back( q.x() ); dataY.push_back( q.y() ); } } template void testCreate( std::vector & dataV, TStopwatch & tim, double& t, std::string s) { int n = dataX.size(); dataV.resize(n); tim.Start(); for (int i = 0; i < n; ++i) { dataV[i] = new V( dataX[i], dataY[i] ); } tim.Stop(); t += tim.RealTime(); print(tim,s); } template void testCreate2( std::vector & dataV, TStopwatch & tim, double& t, std::string s) { int n = dataX.size(); dataV.resize(n); tim.Start(); for (int i = 0; i < n; ++i) { dataV[i] = new V(); dataV[i]->SetXY(dataX[i], dataY[i] ); } tim.Stop(); print(tim,s); t += tim.RealTime(); } void testCreate2( std::vector & dataV, TStopwatch & tim, double& t, std::string s) { int n = dataX.size(); dataV.resize(n); tim.Start(); for (int i = 0; i < n; ++i) { dataV[i] = new TVector2(); dataV[i]->Set(dataX[i], dataY[i] ); } tim.Stop(); print(tim,s); t += tim.RealTime(); } #ifdef HAVE_CLHEP void testCreate2( std::vector & dataV, TStopwatch & tim, double& t, std::string s) { int n = dataX.size(); dataV.resize(n); tim.Start(); for (int i = 0; i < n; ++i) { dataV[i] = new Hep2Vector(); dataV[i]->set(dataX[i], dataY[i] ); } tim.Stop(); print(tim,s); t += tim.RealTime(); } #endif template void clear( std::vector & dataV ) { for (unsigned int i = 0; i < dataV.size(); ++i) { V * p = dataV[i]; delete p; } dataV.clear(); } template inline double addXY(const V & v) { return v.X() + v.Y(); } inline double addXY(const SVector & v) { return v(0) + v(1); } template inline double getSum(const V & v1, const V & v2) { return v1.X()+v1.Y() + v2.X() + v2.Y(); } inline double getSum(const SVector & v1, const SVector & v2 ) { return v1(0)+v1(1) + v2(0)+v2(1); } template inline double dotProd(const V & v1, const V & v2) { return v1 * v2; } inline double dotProd(const XYVector & v1, const XYVector & v2) { return v1.Dot(v2); } inline double dotProd(const SVector & v1, const SVector & v2 ) { return Dot(v1,v2); } #ifdef HAVE_CLHEP inline double addXY(const Hep2Vector & v) { return v.x() + v.y(); } inline double getSum(const Hep2Vector & v1, const Hep2Vector & v2 ) { return v1.x() + v1.y() + v2.x() + v2.y(); } #endif template double testAddition( const std::vector & dataV, TStopwatch & tim, double& t, std::string s) { unsigned int n = dataV.size(); double tot = 0; V v0 = *(dataV[0]); tim.Start(); for (unsigned int i = 0; i < n; ++i) { V & v1 = *(dataV[i]); V v3 = v1 + v0; tot += addXY(v3); } tim.Stop(); print(tim,s); t += tim.RealTime(); return tot; } template double testAddition2( const std::vector & dataV, TStopwatch & tim, double& t, std::string s) { unsigned int n = dataV.size(); double tot = 0; V v0 = *(dataV[0]); tim.Start(); for (unsigned int i = 0; i < n; ++i) { const V & v1 = *(dataV[i]); v0 += v1; tot += addXY(v0); } tim.Stop(); print(tim,s); t += tim.RealTime(); return tot; } template double testAddition3( const std::vector & dataV, TStopwatch & tim, double& t, std::string s) { //unsigned int n = std::min(n2Loop, dataV.size() ); unsigned int n = dataV.size(); double tot = 0; V v0 = *(dataV[0]); tim.Start(); for (unsigned int i = 0; i < n; ++i) { V & v1 = *(dataV[i]); // for (unsigned int j = i +1; j < n; ++j) { // V & v2 = *(dataV[j]); // tot += getSum(v1,v2); // } tot += getSum(v1,v0); } tim.Stop(); print(tim,s); t += tim.RealTime(); return tot; } template double testDotProduct( const std::vector & dataV, TStopwatch & tim, double& t, std::string s) { //unsigned int n = std::min(n2Loop, dataV.size() ); double tot = 0; unsigned int n = dataV.size(); V v0 = *(dataV[0]); tim.Start(); for (unsigned int i = 0; i < n; ++i) { V & v1 = *(dataV[i]); // for (unsigned int j = i +1; j < n; ++j) { // V & v2 = *(dataV[j]); // tot += dotProd(v1,v2); // } tot += dotProd(v1,v0); } tim.Stop(); print(tim,s); t += tim.RealTime(); return tot; } template double testScale( const std::vector & dataV, TStopwatch & tim, double& t, std::string s) { unsigned int n = dataV.size(); double tot = 0; tim.Start(); for (unsigned int i = 0; i < n; ++i) { V & v1 = *(dataV[i]); // scale V v2 = 2.0*v1; tot += addXY(v2); } tim.Stop(); print(tim,s); t += tim.RealTime(); return tot; } template double testScale2( const std::vector & dataV, TStopwatch & tim, double& t, std::string s) { //unsigned int n = std::min(n2Loop, dataV.size() ); unsigned int n = dataV.size(); double tot = 0; tim.Start(); for (unsigned int i = 0; i < n; ++i) { V & v1 = *(dataV[i]); // scale v1 *= 2.0; tot += addXY(v1); } tim.Stop(); print(tim,s); t += tim.RealTime(); return tot; } template double testOperations( const std::vector & dataV, TStopwatch & tim, double& t, std::string s) { //unsigned int n = std::min(n2Loop, dataV.size() ); // test operations like in CMS unsigned int n = dataV.size(); double tot = 0; V v0a = *(dataV[0]); V v0b = *(dataV[n-1]); tim.Start(); for (unsigned int i = 0; i < n; ++i) { V & v1 = *(dataV[i]); //V v2(v1 - dotProd(v1,v0a)*v0b ); double a = dotProd(v1,v0a); V v2(v1 - a*v0b ); tot += addXY(v2); } tim.Stop(); print(tim,s); t += tim.RealTime(); return tot; } template inline double dPhi(V & v1, V& v2) { return std::abs(v1.Phi() - v2.Phi() ); } #ifdef HAVE_CLHEP inline double dPhi(Hep2Vector & v1, Hep2Vector & v2) { return std::abs(v1.phi() - v2.phi() ); } #endif template double testDeltaPhi( const std::vector & dataV, TStopwatch & tim, double& t, std::string s) { unsigned int n = std::min(n2Loop, dataV.size() ); tim.Start(); double tot = 0; for (unsigned int i = 0; i < n; ++i) { V & v1 = *(dataV[i]); for (unsigned int j = i +1; j < n; ++j) { V & v2 = *(dataV[j]); double delta = dPhi(v1,v2); tot += delta; } } tim.Stop(); print(tim,s); t += tim.RealTime(); return tot; } // template // int testAnalysis( const std::vector & dataV, TStopwatch & tim, double& t, std::string s) { // int nsel = 0; // int nsel2 = 0; // double deltaMax = 1.; // double ptMin = 1.; // double etaMax = 3.; // unsigned int n = std::min(n2Loop, dataV.size() ); // tim.Start(); // for (unsigned int i = 0; i < n; ++i) { // V & v1 = *(dataV[i]); // if (cutPtEta(v1,ptMin, etaMax) ) { // double delta; // for (unsigned int j = i +1; j < n; ++j) { // V & v2 = *(dataV[j]); // delta = VectorUtil::DeltaR(v1,v2); // if (delta < deltaMax) { // V v3 = v1 + v2; // nsel++; // if ( cutPtEtaAndMass(v3)) // nsel2++; // } // } // } // } // tim.Stop(); // print(tim,s); // //std::cout << nsel << "\n"; // t += tim.RealTime(); // return nsel2; // } // template // int testAnalysis2( const std::vector & dataV, TStopwatch & tim, double& t, std::string s) { // int nsel = 0; // double ptMin = 1.; // double etaMax = 3.; // unsigned int n = std::min(n2Loop, dataV.size() ); // tim.Start(); // //seal::SealTimer t(tim.name(), true, std::cout); // for (unsigned int i = 0; i < n; ++i) { // V & v1 = *(dataV[i]); // if ( cutPtEta(v1, ptMin, etaMax) ) { // for (unsigned int j = i +1; j < n; ++j) { // V & v2 = *(dataV[j]); // if ( VectorUtil::DeltaR(v1,v2) < 0.5) nsel++; // } // } // } // tim.Stop(); // print(tim,s); // t += tim.RealTime(); // return nsel; // } template void testConversion( std::vector & dataV1, std::vector & dataV2, TStopwatch & tim, double& t, std::string s) { int n = dataX.size(); dataV2.resize(n); tim.Start(); for (int i = 0; i < n; ++i) { dataV2[i] = new V2( *dataV1[i] ); } tim.Stop(); print(tim,s); t += tim.RealTime(); } // rotation template double testRotation( std::vector & dataV, double rotAngle, TStopwatch & tim, double& t, std::string s) { unsigned int n = std::min(n2Loop, dataV.size() ); tim.Start(); double sum = 0; for (unsigned int i = 0; i < n; ++i) { V & v1 = *(dataV[i]); V v2 = v1; v2.Rotate(rotAngle); sum += addXY(v2); } tim.Stop(); print(tim,s); t += tim.RealTime(); return sum; } }; int main(int argc,const char *argv[]) { int ngen = 1000000; if (argc > 1) ngen = atoi(argv[1]); int nloop2 = int(std::sqrt(2.0*ngen)+0.5); if (argc > 2) nloop2 = atoi(argv[2]); std::cout << "Test with Ngen = " << ngen << " n2loop = " << nloop2 << std::endl; TStopwatch t; VectorTest a(ngen,nloop2); a.genData(); int niter = 1; for (int i = 0; i < niter; ++i) { #ifdef DEBUG std::cout << "iteration " << i << std::endl; #endif double t1 = 0; double t2 = 0; double t3 = 0; double t4 = 0; double t5 = 0; double t6 = 0; std::vector v1; std::vector v2; std::vector v3; std::vector v4; std::vector v5; std::vector *> v6; a.testCreate (v1, t, t1, "creation TVector2 " ); a.testCreate (v2, t, t2, "creation XYVector " ); a.testCreate (v3, t, t3, "creation Polar2DVector " ); a.testCreate (v4, t, t4, "creation XYPoint " ); a.testCreate (v5, t, t5, "creation Polar2DPoint " ); a.testCreate (v6, t, t6, "creation SVector<2> " ); #ifdef HAVE_CLHEP double t7 = 0; std::vector v7; a.testCreate (v7, t, t7, "creation Hep2Vector " ); #endif a.clear(v3); a.clear(v4); a.clear(v5); #ifdef HAVE_CLHEP a.clear(v7); #endif std::cout << "\n"; a.testConversion (v2, v3, t, t3, "Conversion XY->Polar " ); a.testConversion (v2, v4, t, t4, "Conversion XYVec->XYPoint " ); a.testConversion (v2, v5, t, t5, "Conversion XYVec->PolarP " ); a.clear(v1); a.clear(v2); a.clear(v3); a.clear(v4); a.clear(v5); std::cout << "\n"; a.testCreate2 (v1, t, t1, "creationSet TVector2 " ); a.testCreate2 (v2, t, t2, "creationSet XYVector " ); a.testCreate2 (v3, t, t3, "creationSet Polar2DVector " ); a.testCreate2 (v4, t, t4, "creationSet XYPoint " ); a.testCreate2 (v5, t, t5, "creationSet Polar2DPoint " ); // a.testCreate2 (v6, t, t6, "creationSet Polar2DPoint " ); #ifdef HAVE_CLHEP a.testCreate2 (v7, t, t7, "creationSet Hep2Vector " ); #endif std::cout << "\n"; double s1,s2,s3,s4,s5,s6; s1=a.testAddition (v1, t, t1, "Addition TVector2 " ); s2=a.testAddition (v2, t, t2, "Addition XYVector " ); s3=a.testAddition (v3, t, t3, "Addition Polar2DVector " ); s6=a.testAddition (v6, t, t6, "Addition SVector<2> " ); a.check("Addition test1",s1,s2,s3); a.check("Addition test2",s1,s2,s6); #ifdef HAVE_CLHEP double s7; s7=a.testAddition (v7, t, t7, "Addition Hep2Vector " ); a.check("Addition",s7,s1,s2); #endif double s0 = s2; std::cout << "\n"; s1=a.testAddition2 (v1, t, t1, "Addition2 TVector2 " ); s2=a.testAddition2 (v2, t, t2, "Addition2 XYVector " ); s3=a.testAddition2 (v3, t, t3, "Addition2 Polar2DVector " ); s6=a.testAddition2 (v6, t, t6, "Addition2 SVector<2> " ); a.check("Addition2 test1",s1,s2,s3,100); a.check("Addition2 test2",s1,s2,s6); #ifdef HAVE_CLHEP s7=a.testAddition2 (v7, t, t7, "Addition2 Hep2Vector " ); a.check("Addition2 CLHEP",s7,s1,s2); #endif std::cout << "\n"; s1=a.testAddition3 (v1, t, t1, "Addition3 TVector2 " ); s2=a.testAddition3 (v2, t, t2, "Addition3 XYVector " ); s3=a.testAddition3 (v3, t, t3, "Addition3 Polar2DVector " ); s6=a.testAddition3 (v6, t, t6, "Addition3 SVector<2> " ); a.check("Addition3 test1",s1,s2,s3); a.check("Addition3 test2",s6,s0,s2); #ifdef HAVE_CLHEP s7=a.testAddition3 (v7, t, t7, "Addition3 Hep2Vector " ); a.check("Addition3 CLHEP",s7,s1,s2); #endif std::cout << "\n"; s1=a.testDotProduct (v1, t, t1, "DotProduct TVector2 " ); s2=a.testDotProduct (v2, t, t2, "DotProduct XYVector " ); // s3=a.testDotProduct (v3, t, t3, "DotProduct Polar2DVector " ); s6=a.testDotProduct (v6, t, t6, "DotProduct SVector<2> " ); a.check("DotProduct test1",s1,s2,s6); // a.check("DotProduct test2",s6,s1,s2); #ifdef HAVE_CLHEP s7=a.testDotProduct (v7, t, t7, "DotProduct Hep2Vector " ); a.check("DotProduct CLHEP",s7,s1,s2); #endif std::cout << "\n"; s1=a.testDeltaPhi (v1, t, t1, "DeltaPhi TVector2 " ); s2=a.testDeltaPhi (v2, t, t2, "DeltaPhi XYVector " ); s3=a.testDeltaPhi (v3, t, t3, "DeltaPhi Polar2DVector " ); s4=a.testDeltaPhi (v4, t, t4, "DeltaPhi XYPoint " ); s5=a.testDeltaPhi (v5, t, t5, "DeltaPhi Polar2DPoint " ); #ifdef WIN32 //windows is bad here a.check("DeltaPhi",s1,s2,s3,10); a.check("DeltaPhi",s2,s4,s5,10); #else a.check("DeltaPhi",s1,s2,s3); a.check("DeltaPhi",s2,s4,s5); #endif #ifdef HAVE_CLHEP s7=a.testDeltaPhi (v7, t, t7, "DeltaPhi HEP2Vector " ); a.check("DeltaPhi",s7,s1,s2); #endif std::cout << "\n"; s1=a.testScale (v1, t, t1, "Scale of TVector2 " ); s2=a.testScale (v2, t, t2, "Scale of XYVector " ); s3=a.testScale (v3, t, t3, "Scale of Polar2DVector " ); s4=a.testScale (v4, t, t4, "Scale of XYPoint " ); s5=a.testScale (v5, t, t5, "Scale of Polar2DPoint " ); a.check("Scaling",s1,s2,s3); a.check("Scaling",s2,s4,s5, 10); s6=a.testScale (v6, t, t6, "Scale of SVector<2> " ); a.check("Scaling SV",s6,s1,s2); #ifdef HAVE_CLHEP s7=a.testScale (v7, t, t7, "Scale of HEP2Vector " ); a.check("Scaling CLHEP",s7,s2,s3); #endif std::cout << "\n"; s1=a.testScale2 (v1, t, t1, "Scale2 of TVector2 " ); s2=a.testScale2 (v2, t, t2, "Scale2 of XYVector " ); s3=a.testScale2 (v3, t, t3, "Scale2 of Polar2DVector " ); s4=a.testScale2 (v4, t, t4, "Scale2 of XYPoint " ); s5=a.testScale2 (v5, t, t5, "Scale2 of Polar2DPoint " ); a.check("Scaling2",s1,s2,s3); a.check("Scaling2",s2,s4,s5, 10); s6=a.testScale2 (v6, t, t6, "Scale2 of SVector<2> " ); a.check("Scaling2 SV",s6,s1,s2); #ifdef HAVE_CLHEP s7=a.testScale2 (v7, t, t7, "Scale2 of HEP2Vector " ); a.check("Scaling CLHEP",s7,s2,s3); #endif std::cout << "\n"; s1=a.testOperations (v1, t, t1, "Operations of TVector2 " ); s2=a.testOperations (v2, t, t2, "Operations of XYVector " ); s6=a.testOperations (v6, t, t6, "Operations of SVector<2> " ); a.check("Operations testSV",s6,s1,s2); #ifdef HAVE_CLHEP s7=a.testOperations (v7, t, t7, "Operations of HEP2Vector " ); a.check("Operations CLHEP",s7,s1,s2); #endif #ifdef LATER int n1, n2, n3,n4,n5; n1 = a.testAnalysis (v1, t, t1, "Analysis1 TVector2 " ); n2 = a.testAnalysis (v2, t, t2, "Analysis1 XYVector " ); n3 = a.testAnalysis (v3, t, t3, "Analysis1 Polar2DVector " ); n4 = a.testAnalysis (v4, t, t4, "Analysis1 XYPoint " ); n5 = a.testAnalysis (v5, t, t5, "Analysis1 Polar2DPoint " ); a.check("Analysis1",n1,n2,n3); a.check("Analysis1",n2,n4,n5); #ifdef HAVE_CLHEP int n6; n6 = a.testAnalysis (v7, t, t7, "Analysis1 HEP2Vector " ); a.check("Analysis2 CLHEP",n6,n1,n2); #endif n1 = a.testAnalysis2 (v1, t, t1, "Analysis2 TVector2 " ); n2 = a.testAnalysis2 (v2, t, t2, "Analysis2 XYVector " ); n3 = a.testAnalysis2 (v3, t, t3, "Analysis2 Polar2DVector " ); n4 = a.testAnalysis2 (v4, t, t4, "Analysis2 XYPoint " ); n5 = a.testAnalysis2 (v5, t, t5, "Analysis2 Polar2DPoint " ); a.check("Analysis2",n1,n2,n3); a.check("Analysis2",n2,n4,n5); #ifdef HAVE_CLHEP n6 = a.testAnalysis2 (v7, t, t7, "Analysis2 HEP2Vector " ); a.check("Analysis2 CLHEP",n6,n1,n2); #endif n1 = a.testAnalysis3 (v1, t, t1, "Analysis3 TVector2 " ); n2 = a.testAnalysis3 (v2, t, t2, "Analysis3 XYVector " ); n3 = a.testAnalysis3 (v3, t, t3, "Analysis3 Polar2DVector " ); n4 = a.testAnalysis3 (v4, t, t4, "Analysis3 XYPoint " ); n5 = a.testAnalysis3 (v5, t, t5, "Analysis3 Polar2DPoint " ); a.check("Analysis3",n1,n2,n3); a.check("Analysis3",n2,n4,n5); #ifdef HAVE_CLHEP n6 = a.testAnalysis3 (v7, t, t7,"Analysis3 HEP2Vector " ); a.check("Analysis3 CLHEP",n6,n1,n2); #endif #endif // clean all at the end a.clear(v1); a.clear(v2); a.clear(v3); std::cout << std::endl; std::cout << "Total Time for TVector2 = " << t1 << "\t(sec)" << std::endl; std::cout << "Total Time for XYVector = " << t2 << "\t(sec)" << std::endl; std::cout << "Total Time for Polar2DVector = " << t3 << "\t(sec)" << std::endl; #ifdef HAVE_CLHEP std::cout << "Total Time for Hep2Vector = " << t7 << "\t(sec)" << std::endl; #endif } //tr.dump(); }