Comparison of ZOOM PhysicsVectors and CLHEP

Comparison of ZOOM PhysicsVectors Package
and
(April 1998) CLHEP Vector Sub-Package


These packages cover similar functions; this note will contrast features present in one or the other. We also point out differences in treatment which might be considered a plus or minus for either side. We omit things which are either purely cosmetic (slight differences in naming choices).

The ZOOM PhysicsVectors package supplies CLHEP compatibility headers, meant to allow code using CLHEP Vectors classes to run via the ZOOM package, unchanged except for substituting the ZOOM versions of #include HepThreeVector.h etc. This comparison marks with the symbol @ cases where CLHEP functionality which becomes supported in ZOOM only if the compatibility headers are used.

Some methods in CLHEP are mathematically ambiguous on the face of it, but use arbitrary subtle assumptions and references to make them sensible. These are driven by opertions convenient to Geant4. We will point out these differences as GEANT4 rather than as usual feature differences. Again, the caompatibility headers support all these features.


Each package has four fundamental sorts of objects: 3- and 4-vectors and 3D and 4D transformations. These are listed here, along with closely related classes.
 
HepThreeVector		SpaceVector	      (UnitVector)
HepLorentzVector	LorentzVector	
HepRotation		Rotation	      
			(RotationX, RotationY, RotationZ)
HepLorentzRotation	LorentzTransformation 
			(LorentzBoost,
			LorentzBoostX, LorentzBoostY, LorentzBoostZ)
 

We will use v for a 3-vector, w for a 4-vector, R for a rotation, and T for a Lorentz transformation in these illustrations.


  1. Component access
  2. The PhysicsVectors package has the following attitude about components specifying a vector or transformation: The Vector package provides a slightly slimmer variety of component forms, and does not support changing indiviual components in a given form. The specific differences are:
       PhysicsVectors			CLHEP Vector
       --------------			------------
    
       == Accessor mechanism ==
    +  v.x() = whatever;  or also
       v.setX(whatever)			v.setX(whatever) only
    +  w.x() = whatever;
    +  v.x() += whatever; and so forth
    
    +  v.r() = whatever;
    +  v.phi() = whatever;
    +  v.theta() = whatever;
    +  p = v.r() along with p=v.mag()	v.mag() only
    
    @					v(j) 
    					  components by index 
    
       == Cylindrical coordinates ==
    +  p = v.rho();
    +  v.rho() = whatever;
    +  setCylTheta(theta):
             keeping rho, phi fixed.
    
       == PseudoRapidity substituting for theta ==
    +  p = v.eta();
    	This is a big one; users work with eta along the Z
    	axis rather that theta very often.
    +  v.eta() = whatever;
    	keeping r and phi fixed
    +  v.setCylEta
    	keeping rho and phi fixed
    
       PhysicsVectors			CLHEP Vector
       --------------			------------
    
      == Rotation in terms of axis/delta and in terms of EulerAngles ==
    +  Rotation(axis, delta) 		
    -					rotate(axis, delta)		
    					   does a further rotation 
    					   around this new axis; 
    					   related to multiplication. 
    +  p = R.axis()				
    +  p = R.delta()
    +  R.axis() = whatever;
    +  R.delta() = whatever;
    +  R.delta()+= whatever;  
    +  R.delta()*= whatever;  e.g R.delta -= 1
    
    +  R ( phi, theta, psi );
    +  p = R.psi()   and R.psi()   = whatever;
    +  p = R.theta() and R.theta() = whatever;
    +  p = R.phi()   and R.phi()   = whatever;
    
      == Rows and columns ==
    +  u = R.rowX() u = R.rowY(); u = R.rowZ();
    	One note about a major performance hit in a CLHEP-using
    	code was because they were extracting rows by multiplying by
    	unit coordinate vectors.  
    	This would make such a happening unlikely! 
    +  w = T.row1(); w=T.row2(); 
       w = T.row3(); w=T.row4(); 
       Constructor from 3 columns		RotateAxes from 3 columns
    +  Constructor from 3 rows
    
    +  T.row1() T.row2() T.row3() T.row4() 
       T.row1() T.row2() T.row3() T.row4() 
       for  LorentzTransformation
    +  Constructor of T from 4 columns.
    
    +  R.ZMpvRep3x3() 
    +  T.ZMpvRep4x4()
    	for all 9 or 16 elements in one chunk
    
    


  3. Specialized Classes
  4. There are minor conceptual advantages, and at times substatntial efficiency advantages, to classes for UnitVector, pure boost, and coordinate axis rotations and boosts. There are also some side consequences.
       PhysicsVectors			CLHEP Vector
       --------------			------------
    
    +  UnitVector
    	Whenever a reference direction is needed, the fore-knowledge
    	that this need not be normalized is a major performance edge.
    
    @ UnitVector(v)	   			v.unit()
    
      X_HAT, Y_HAT, Z_HAT			HepXhat, HepYhat, HepZhat
        known to be unit vectors
    
    +  RotationX
    +  RotationY 
    +  RotationZ
    +  LorentzBoost
    +  LorentzBoostX
    +  LorentzBoostY
    +  LorentzBoostZ
    	Comment:  These are important both in terms of stroage and
    	when applying a transformation to a vector or 4-vector.  
    
    + Rotation::IDENTITY
    + LorentzTransfomration::IDENTITY
    
    


  5. Nearness and distance metrics
  6. Because comparisons are often meaningful only within some precision (dictated either be accuracy of data input or by round-off error), the PhysicsVectors class provides boolean isNear() methods, with default or user-specified tolerances. In the same vein, the package supplies the raw "distance" measure, which the user can cut on, plot, or whatever.
       PhysicsVectors			CLHEP Vector
       --------------			------------
    
    +  v.isNear(v2) 
    +  v.howNear(v2)
    +  v.deltaR(v2)
    	This has been requested by quite a few people from
    	CDF and D0 independantly.  Both experiments use the same 
    	term for the same concept so its meaning is clear to the 
    	key people.
    	deltaR = sqrt(delta_eta**2 + delta_phi**2)
    +  v.isParallel(v2)
    +  v.howParallel(v2)
    +  v.isOrthogonal(v2)
    +  v.howOrthogonal(v2)
    
    +  w.isNear(w2) 
    +  w.howNear(w2)
    +  w.isNearCM(w2) 
    +  w.howNearCM(w2)
    	Lorentz invariant measures of nearness in CM frame;
    	these are applicable only to timelike 4-vectors.  
    +  w.deltaR(w2)
    +  w.delta2Euclidean(w2)
    +  w.isSpacelike() 
    +  w.isTimelike()
    +  w.isLightlike()
    +  w.howLightlike()
    +  w.isParallel(w2)
    +  w.howParallel(w2)
    


  7. Methods on 3-vectors
  8. The PhysicsVectors class provides a variety of methods acting on 3-vectors. The primary extensions relative to the CLHEP classes are that many methods which have an implied Z reference direction also have forms (in SpaceVector) taking an arbitrary reference direction. The PhysicsVectors package also has rapidity and angle decomposition methods.
       PhysicsVectors			CLHEP Vector
       --------------			------------
    
       v.perp2()    v.perp()		v.perp2()   v.perp()
    +  v.perp2(u)   v.perp(u) 
    +  v.perpPart() v.perpPart(u)
    +  v.project()  v.project(u)
    +  v.polarAngle(u)
    +  v.azimAngle(u)
    	Angle decomposition methods stemmed from a discussion with
    	Marc Paterno.
    
    +  v.rotate(Euler angles)
    +  v/scalar
    +  unary minus on vectors and 4-vectors
    
    +  v.rapidity  v.rapidity(u)
    +  v.colinearRapidity()
       v.angle(u)				v.angle(v)
    +  v.cosTheta(u)
    
    There are some methods in HepVector that are specific for the convenience of Geant4. These are mathematically unnatural or contain hidden assumptions in their definitions. Nonetheless, the compatibility headers support these, as they are useful to the Geant4 crowd.
       PhysicsVectors			CLHEP Vector
    				(and PhysicsVectors compaibility)
       --------------		---------------------------------
    
    GEANT4 				v.orthogonal()  
    				  returns a vector orthogonal to
    				  v; the choice is contrived 
    GEANT4				R.rotateUz()    
    				  Rotates axes so that the Z axis is
    				  along some new vector.  The choice
    				  among the set of such rotations is
    				  contrived
    


  9. Operator overloading of * and application of rotations
  10. It was agreed that PhysicsVectors would not overload * to mean dot product and application of rotations. It was felt that ambiguities in meaning would be present if we did. However, this convenient notation is popular enough that it is supported via PhysVec.h
       PhysicsVectors			CLHEP Vector
       --------------			------------
    
    @  v1.dot(v2)				v1 * v2   or  v1.dot(w2) 	
    @  w1.dot(w2)				w1 * w2   or  w1.dot(w2)
    @  R(v)					R*v
    	The "apply" syntax makes more sense mathematically but
    	since physicists think of a rotation in terms of its matrix 
    	representation,	the natural looking R*v will be in PhysVec.h 
       R(v)					v.transform(R)
    	This is a serious design difference.  In the PhysicsVectors
    	package, SpaceVector is at a "lower" level than Rotation, and 
    	the class does not know about Rotation at all -- direct 
    	rotations are expressed in terms of EulerAngles or axis and 
    	delta.  So if Rotations as objects in their own right are not 
    	part of the user's task, he need not pull in the Rotation 
    	class.
    	In consequence, however, there can be no method of 
    	SpaceVector that works with a Rotation argument. 
    +  v*R
    +  w*T
    	These are defined such that constructs like 
    	v1*R*v2  and  w1*T*w2  are associative 
    	and give the expected results. 
    
    


  11. 4-Vector methods
  12. The PhysicsVectors package has more kinematics methods, and can work with containers of LorentzVectors.
       PhysicsVectors			CLHEP Vector
       --------------			------------
    
    +  setMetric()
    	At the January workshop, it was indicated that 
    	the desired metric was (+ + + -).  CLHEP 
    	uses (- - - +) which in many ways is much more convenient.  
    	To resolve this, PhysicsVectors defaults to the CLHEP 
    	standard, but allows the user to change to TimeNegative. 
    
    					w(j)
    			  		  components by index 
       w.plus()     w.minus()		w.plus()  w.minus()
    +  w.plus(u)    w.minus(u)
    +  w.eta()      w.eta(u)
    +  w.rapidity() w.colinearRapidity()
    +  restVector()
    
    +  invariantMass (Container)
    +  findBoostToCM (Container)
    +  applyBoostToCM(Container)
    
    HepLorentzVectors have more convenient notation for working with their 3-vector parts. These are obviously provided as a remnant of the 4-vector inheriting from 3-vector: The methods would have worked then, so they must work now. PhysicsVectors could be extended to include those notations if desired but since there are many more 3-vector methods available, it is more work.
       PhysicsVectors			CLHEP Vector
       --------------			------------
    
    @  w.getV().phi()			w.phi()					
    @  w.getV().theta()			w.theta()					
    @  w.getV().r()				w.rho()					
    				Note naming differnece:  with no
    				cylindrical coordinates, using rho
    				for radius is sensible.
    @  w.getV().perp()   or w.z()		w.perp()
    @  w.getV().perp2(v)			w.perp2(v) 
    @  w.getV().angle(v)			w.angle(v)
       w.v()				HepThreeVector(w)
    				The cast to a 3-vector, dropping 
    				the t component, is potentially 
    				trappy 	and confusiing.  But again, 
    				it is needed for back compatibility 
    				with CLHEP versions using inheritance. 
    
    @					w.px() w.py() w.pz() w.E()
       w.x()  w.y()  w.z()  w.t()		w.x()  w.y()  w.z()  w.t()
    
    
    Several differences reflect a matter of taste:
       PhysicsVectors			CLHEP Vector
       --------------			------------
    
       T(w)					w.transform(T)
       w.invariantMass2() 			w.m2() 
       w.invariantMass() 			w.m() 
       w.findBoostToCM()   			w.boostVector()
    
       LorentzVector(x,y,z,Tcomponent(t))	HepLorentzVector(x,y,z,t)
       LorentzVector(Tcomponent(t),x,y,z)
    	The convenience of not haveing to specify which is the T 
    	component, versus the trap of not catching the error of 
    	supplying (t,x,y,z).
    


  13. Treatment of Rotations and Lorentz Transformations
  14.    PhysicsVectors			CLHEP Vector
       --------------			------------
    
    +  rectify()
         In case a long series of operations
         might accumulate round-off error. 
    + w1 = R(w2)				v = R*w
    	The application of a Rotation to HepLorentzVector
    	in CLHEP yields a 3-vector, dropping the t component.  
    	This is plain wrong.
    @					R(i,j)
    @					T(i,j)
    					  components by index 		
       (R == Rotation::IDENTITY)		R.isIdentity()
    
    @  					R.transform(R2) 
    					  left-multiplication analog 
    					  of *= that is, R = R2*R
       inverseOf(R) 			R.inverse() 
    
    +  T.decompose(B, R)
    +  T.decompose(R, B)
    +  LorentzBoost b.direction() 
    +  b.beta()
    +  b.gamma()
    
    +  R(Container)
    +  R(Container)
    +  T(Container)
    
    GEANT4				        R.phiX() const;
    GEANT4				        R.phiY() const;
    GEANT4				        R.phiZ() const;
    GEANT4				        R.thetaX() const;
    GEANT4				        R.thetaY() const;
    GEANT4				        R.thetaZ() const;
    	 Angles made by rotated axes against the originals; 
    	Mathematically needs one more piece of info for phi to 
    	be well defined.
    


  15. Sorting comparisons
  16. Each data type in PhysicsVector contains "dictionary ordering" coparison operators so that one can form a standard container of that class and use all the various sort and search algorithms. HepVector, having been created before standard containers were sensible to use, saw no need for these.
       PhysicsVectors			CLHEP Vector
       --------------			------------
    
    +  operator >   operator < 
    +  operator >=  operator <=
    

PhysicsVectors Page - ZOOM Home Page - Fermilab at Work - Fermilab Home


Mark Fischler
Last modified: June 10, 1998