Print

Print


Commit in lcsim/src/org/lcsim/contrib/garfield/tester on MAIN
DocaTrackParameters.java+765added 1.1
ExampleDriver.java+38added 1.1
MCTrack.java+185added 1.1
RatedTrack.java+113added 1.1
TrackingTest.java+122added 1.1
TrackingTestBase.java+448added 1.1
TrackingTestKs.java+69added 1.1
package-info.java+5added 1.1
+1745
8 added files
Internal Release 2.02.01  Feb 23 2006.
Added tester package, a few changes to infrastructure.

lcsim/src/org/lcsim/contrib/garfield/tester
DocaTrackParameters.java added at 1.1
diff -N DocaTrackParameters.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ DocaTrackParameters.java	23 Feb 2006 19:10:09 -0000	1.1
@@ -0,0 +1,765 @@
+package org.lcsim.contrib.garfield.tester;
+
+import Jama.Matrix;
+
+import hep.physics.particle.Particle;
+
+import hep.physics.vec.BasicHep3Vector;
+import hep.physics.vec.Hep3Vector;
+import hep.physics.vec.VecOp;
+import org.lcsim.constants.Constants;
+
+
+/**
+ *    MODIFIED COPY OF org.lcsim.mc.fast.tracking.DocaTrackParameters.
+ *    (wish it was public)
+ *
+ * Holds DOCA parameters and error matrix of track. Can be initialized
+ * with a MC truth particle. <br>
+ *
+ * OriginalAuthor  Tony Johnson, Wolfgang Walkowiak
+ * OriginalVersion DocaTrackParameters.java,v 1.5 2005/08/20 23:24:14 tonyj
+ * 
+ * @version $Id: DocaTrackParameters.java,v 1.1 2006/02/23 19:10:09 onoprien Exp $
+ * InternalRelease 2.02.01 Feb 23, 2006
+ */
+class DocaTrackParameters
+{
+   private Hep3Vector m_pdoca_ref = null;
+   private Hep3Vector m_xdoca_ref = null;
+   private Hep3Vector m_xref = null;
+   private double[][] m_err = new double[5][5];
+   private double[] m_parm = new double[5];
+   private double m_Bz = 0.;
+   private double m_chi2 = -1.;
+   private double m_l0 = 0.;
+   private double m_l_ref = 0.;
+   private int m_ndf = 5;
+
+   //====================================================
+   //
+   //  Constructors
+   //
+   //====================================================
+   DocaTrackParameters(double bField)
+   {
+      reset();
+      m_Bz = bField;
+   }
+
+   DocaTrackParameters(double bField, Particle p)
+   {
+      this(bField, p.getMomentum(), p.getOrigin(), p.getType().getCharge());
+   }
+
+   DocaTrackParameters(double bField, Hep3Vector momentum, Hep3Vector x, double q)
+   {
+      reset();
+      m_Bz = bField;
+      calculateDoca(momentum, x, q);
+   }
+
+   DocaTrackParameters(double bField, double[] momentum, double[] x, double q)
+   {
+      reset();
+      m_Bz = bField;
+      calculateDoca(momentum, x, q);
+   }
+
+   DocaTrackParameters(double bField, double[] momentum, double[] x, double q, double[][] errorMatrix)
+   {
+      this(bField, momentum, x, q);
+      fillErrorMatrix(errorMatrix);
+   }
+
+   DocaTrackParameters(double bField, double[] parameters)
+   {
+      m_Bz = bField;
+      m_parm = parameters;
+   }
+
+   DocaTrackParameters(double bField, double[] parameters, double[][] errorMatrix)
+   {
+      this(bField, parameters);
+      fillErrorMatrix(errorMatrix);
+   }
+
+   DocaTrackParameters(double bField, double[] parameters, double[][] errorMatrix, double chi2)
+   {
+      this(bField, parameters);
+      fillErrorMatrix(errorMatrix);
+      setChi2(chi2);
+   }
+
+   DocaTrackParameters(double bField, double[] parameters, double[][] errorMatrix, double chi2, int ndf)
+   {
+      this(bField, parameters);
+      fillErrorMatrix(errorMatrix);
+      setChi2(chi2);
+      setNDF(ndf);
+   }
+
+   public double getD0()
+   {
+      return m_parm[0];
+   }
+
+   /**
+    * Get the error matrix as a 2-D array
+    * @see #getTrackParameter
+    */
+   public double[][] getErrorMatrix()
+   {
+      return m_err;
+   }
+
+   /**
+    * Get an individual element of the error matrix
+    * @see #getTrackParameter
+    */
+   public double getErrorMatrixElement(int i, int j)
+   {
+      return (i < j) ? m_err[j][i] : m_err[i][j];
+   }
+
+   /**
+    * Get momentum at DOCA.
+    */
+   public double[] getMomentum()
+   {
+      return new double[] { getPX(), getPY(), getPZ() };
+   }
+
+   public double getOmega()
+   {
+      return m_parm[2];
+   }
+
+   public double getPX()
+   {
+      return getPt() * Math.cos(m_parm[1]);
+   }
+
+   public double getPY()
+   {
+      return getPt() * Math.sin(m_parm[1]);
+   }
+
+   public double getPZ()
+   {
+      return getPt() * m_parm[4];
+   }
+
+   public double getPhi0()
+   {
+      return m_parm[1];
+   }
+
+   /**
+    * Get total momentum at DOCA.
+    */
+   public double getPtot()
+   {
+      return Math.sqrt((getPX() * getPX()) + (getPY() * getPY()) + (getPZ() * getPZ()));
+   }
+
+   public double getTanL()
+   {
+      return m_parm[4];
+   }
+
+   /**
+    * Get an individual track parameter. <br>
+    *
+    * The track parameters for LCD are defined as follows
+    * <table>
+    * <tr><th>Index</th><th>Meaning</th></tr>
+    * <tr><td> 0 </td><td> d0 = XY impact parameter </td><tr>
+    * <tr><td> 1 </td><td> phi0 </td><tr> </td><tr>
+    * <tr><td> 2 </td><td> omega = 1/curv.radius (negative for negative tracks) </td><tr>
+    * <tr><td> 3 </td><td> z0 = z of track  (z impact parameter) </td><tr>
+    * <tr><td> 4 </td><td> s = tan lambda </td><tr>
+    * </table>
+    * @param i The index of the track parameter
+    * @return The track parameter with the specified index
+    *
+    * All parameters are given at the DOCA.
+    */
+   public double getTrackParameter(int i)
+   {
+      return m_parm[i];
+   }
+
+   /**
+    * Get the track parameters as an array
+    * @see #getTrackParameter
+    */
+   public double[] getTrackParameters()
+   {
+      return m_parm;
+   }
+
+   /**
+    * Get the unit charge, ie +1, 0, -1.
+    */
+   public int getUnitCharge()
+   {
+      if (m_Bz != 0)
+      {
+         return (int) Math.signum(m_parm[2]);
+      }
+      else
+      {
+         return 0;
+      }
+   }
+
+   public double getZ0()
+   {
+      return m_parm[3];
+   }
+
+   /**
+    * Get cos(Theta) as calculated from the
+    * momentum vector at the DOCA. <br>
+    *
+    * Note: This is the same as getCosTheta()
+    */
+
+   public double magnitude()
+   {
+      return Math.sqrt(VecOp.dot(getDocaVec(), getDocaVec()));
+   }
+   public double magnitudeSquared()
+   {
+      return VecOp.dot(getDocaVec(), getDocaVec());
+   }
+
+   public double[] v()
+   {
+      return getDoca();
+   }
+
+   // IHep3Vector methods
+   public double x()
+   {
+      return getDocaX();
+   }
+
+   public double y()
+   {
+      return getDocaY();
+   }
+
+   public double z()
+   {
+      return getDocaZ();
+   }
+
+   /**
+    * Store the chi2.
+    */
+   void setChi2(double chi2)
+   {
+      m_chi2 = chi2;
+   }
+
+   /**
+    * Return the chi2 from smearing. <br>
+    *
+    * Note: The chi2 is to be calculated and
+    * stored by the smearing routine
+    * using setChi2().
+    */
+   double getChi2()
+   {
+      return m_chi2;
+   }
+
+   /**
+    * get cos(theta) at DOCA.
+    */
+   double getCosTheta()
+   {
+      return getPZ() / getPtot();
+   }
+
+   /**
+    * Get coordinates of DOCA.
+    */
+   double[] getDoca()
+   {
+      return new double[] { getDocaX(), getDocaY(), getDocaZ() };
+   }
+
+   double[] getDocaMomentum(double[] refPoint)
+   {
+      return getDocaMomentumVec(refPoint).v();
+   }
+
+   /**
+    * Calculate and get Doca momentum on track with respect to any space point.
+    */
+   Hep3Vector getDocaMomentumVec(Hep3Vector refPoint)
+   {
+      if ((refPoint.x() != 0.) && (refPoint.y() != 0.))
+      {
+         checkCalcDoca(refPoint);
+
+         return m_pdoca_ref;
+      }
+      else
+      {
+         return getMomentumVec();
+      }
+   }
+
+   Hep3Vector getDocaMomentumVec(double[] refPoint)
+   {
+      return getDocaMomentumVec(new BasicHep3Vector(refPoint[0], refPoint[1], refPoint[2]));
+   }
+
+   double[] getDocaPosition(double[] refPoint)
+   {
+      return getDocaPositionVec(refPoint).v();
+   }
+
+   //====================================================
+   //
+   //  methods
+   //
+   //====================================================
+
+   /**
+    * Calculate and get Doca position on track with respect to
+    * any space point.
+    */
+   Hep3Vector getDocaPositionVec(Hep3Vector refPoint)
+   {
+      if ((refPoint.x() != 0.) && (refPoint.y() != 0.))
+      {
+         checkCalcDoca(refPoint);
+
+         return m_xdoca_ref;
+      }
+      else
+      {
+         return getDocaVec();
+      }
+   }
+
+   Hep3Vector getDocaPositionVec(double[] refPoint)
+   {
+      return getDocaPositionVec(new BasicHep3Vector(refPoint[0], refPoint[1], refPoint[2]));
+   }
+
+   /**
+    * Calculate and get path length on track for a doca to any space point
+    * in respect to the track defining doca (with respect to the origin).
+    * The length l is given in the transverse plane. <br>
+    * Use L = l*tan(lambda) to convert.
+    */
+   double getDocaTransversePathLength(Hep3Vector refPoint)
+   {
+      if ((refPoint.x() != 0.) && (refPoint.y() != 0))
+      {
+         checkCalcDoca(refPoint);
+
+         return m_l_ref;
+      }
+      else
+      {
+         return 0.;
+      }
+   }
+
+   double getDocaTransversePathLength(double[] refPoint)
+   {
+      return getDocaTransversePathLength(new BasicHep3Vector(refPoint[0], refPoint[1], refPoint[2]));
+   }
+
+   /**
+    * Get coordinates of DOCA.
+    */
+   Hep3Vector getDocaVec()
+   {
+      return new BasicHep3Vector(getDocaX(), getDocaY(), getDocaZ());
+   }
+
+   double getDocaX()
+   {
+      return (-m_parm[0] * Math.sin(m_parm[1]));
+   }
+
+   double getDocaY()
+   {
+      return (m_parm[0] * Math.cos(m_parm[1]));
+   }
+
+   double getDocaZ()
+   {
+      return (m_parm[3]);
+   }
+
+   /**
+    * Set the (transverse) path length l0 to original track vertex.
+    */
+   void setL0(double l0)
+   {
+      m_l0 = l0;
+   }
+
+   /**
+    * Get the (transverse) path length l0 to original track vertex.
+    */
+   double getL0()
+   {
+      return m_l0;
+   }
+
+   double[] getMomentum(double l)
+   {
+      return getMomentumVec(l).v();
+   }
+
+   /**
+    * Calculate and get momentum on track with respect to
+    * any path length l on track (l in xy plane).
+    */
+   Hep3Vector getMomentumVec(double l)
+   {
+      double phi0 = m_parm[1];
+      double omega = m_parm[2];
+      double tanl = m_parm[4];
+
+      int iq = getUnitCharge();
+
+      double phi = phi0 + (omega * l);
+      double pt = Constants.fieldConversion * iq * m_Bz / omega;
+
+      double px = pt * Math.cos(phi);
+      double py = pt * Math.sin(phi);
+      double pz = pt * tanl;
+
+      //  	System.out.println("l: "+l+" p: ("+px+", "+py+", "+pz+")");
+      return new BasicHep3Vector(px, py, pz);
+   }
+
+   Hep3Vector getMomentumVec()
+   {
+      return new BasicHep3Vector(getPX(), getPY(), getPZ());
+   }
+
+   /**
+    * Change the number degrees of freedom.
+    */
+   void setNDF(int ndf)
+   {
+      m_ndf = ndf;
+   }
+
+   /**
+    * Get the number degrees of freedom.
+    *
+    * Default is 5 unless changed with setNDF().
+    */
+   int getNDF()
+   {
+      return m_ndf;
+   }
+
+   double[] getPosition(double l)
+   {
+      return getPositionVec(l).v();
+   }
+
+   /**
+    * Calculate and get position on track with respect to
+    * any path length l on track (l in xy plane).
+    */
+   Hep3Vector getPositionVec(double l)
+   {
+      double d0 = m_parm[0];
+      double phi0 = m_parm[1];
+      double omega = m_parm[2];
+      double z0 = m_parm[3];
+      double tanl = m_parm[4];
+
+      double phi = phi0 + omega;
+      double rho = 1 / omega;
+
+      double x = (rho * Math.sin(phi)) - ((rho + d0) * Math.sin(phi0));
+      double y = (-rho * Math.cos(phi)) + ((rho + d0) * Math.cos(phi0));
+      double z = z0 + (l * tanl);
+
+      return new BasicHep3Vector(x, y, z);
+   }
+
+   /**
+    * Get transverse momentum at DOCA.
+    */
+   double getPt()
+   {
+      if (m_parm[2] != 0.)
+      {
+         return Math.abs(Constants.fieldConversion * m_Bz / m_parm[2]);
+      }
+      else
+      {
+         return 0.;
+      }
+   }
+
+   /**
+    * Get theta angle at DOCA.
+    */
+   double getTheta()
+   {
+      return Math.atan2(getPt(), getPZ());
+   }
+
+   /**
+    * Calculate the error matrix for the momentum
+    * for a point on the track specified by l.
+    * Result is given as a 3x3 array for the matrix.
+    */
+   double[][] calcMomentumErrorMatrix(double l)
+   {
+      double rho = 1. / getOmega();
+      double phi = getPhi0() + (getOmega() * l);
+      double tanl = getTanL();
+      double c = Constants.fieldConversion * Math.abs(m_Bz);
+      double sphi = Math.sin(phi);
+      double cphi = Math.cos(phi);
+
+      Matrix tMatrix = new Matrix(5, 3, 0.);
+      tMatrix.set(1, 0, -c * rho * sphi);
+      tMatrix.set(1, 1, c * rho * cphi);
+      tMatrix.set(2, 0, (-c * rho * rho * cphi) - (c * rho * l * sphi));
+      tMatrix.set(2, 1, (-c * rho * rho * sphi) + (c * rho * l * cphi));
+      tMatrix.set(2, 2, -c * rho * rho * tanl);
+      tMatrix.set(4, 2, c * rho);
+
+      Matrix errorMatrix = new Matrix(getErrorMatrix());
+      Matrix pErrorMatrix = tMatrix.transpose().times(errorMatrix.times(tMatrix));
+
+      return pErrorMatrix.getArrayCopy();
+   }
+
+   /**
+    * Calculate the error matrix for the position coordinates
+    * for a point on the track specified by l.
+    * Result is given as a 3x3 array for the matrix.
+    */
+   double[][] calcPositionErrorMatrix(double l)
+   {
+      double d0 = getD0();
+      double rho = 1. / getOmega();
+      double phi = getPhi0() + (getOmega() * l);
+      double sphi0 = Math.sin(getPhi0());
+      double cphi0 = Math.cos(getPhi0());
+      double sphi = Math.sin(phi);
+      double cphi = Math.cos(phi);
+
+      Matrix tMatrix = new Matrix(5, 3, 0.);
+      tMatrix.set(0, 0, -sphi0);
+      tMatrix.set(0, 1, cphi0);
+      tMatrix.set(1, 0, (rho * cphi) - ((rho + d0) * cphi0));
+      tMatrix.set(1, 1, (rho * sphi) - ((rho + d0) * sphi0));
+      tMatrix.set(2, 0, (rho * l * cphi) - (rho * rho * (sphi - sphi0)));
+      tMatrix.set(2, 1, (rho * l * sphi) + (rho * rho * (cphi - cphi0)));
+      tMatrix.set(3, 2, 1.);
+      tMatrix.set(4, 2, l);
+
+      Matrix errorMatrix = new Matrix(getErrorMatrix());
+
+      // MyContext.println(MyContext.getHeader());
+      // MyContext.printMatrix("Error matrix:",errorMatrix,10,15);
+      // MyContext.printMatrix("Transf matrix:",tMatrix,10,15);
+      Matrix xErrorMatrix = tMatrix.transpose().times(errorMatrix.times(tMatrix));
+
+      return xErrorMatrix.getArrayCopy();
+   }
+
+   void fillErrorMatrix(double[][] errorMatrix)
+   {
+      m_err = errorMatrix;
+
+      // fill upper triangle from lower triangle
+      for (int i = 0; i < 5; i++)
+         for (int j = 0; j < i; j++)
+            m_err[j][i] = m_err[i][j];
+   }
+
+   //====================================================
+   //
+   //  private methods
+   //
+   //====================================================
+
+   /*
+    * Calculate the DOCA for a set of parameters with respect to the origin.
+    */
+   private void calculateDoca(double[] momentum, double[] trackPoint, double q)
+   {
+      Hep3Vector p = new BasicHep3Vector(momentum[0], momentum[1], momentum[2]);
+      Hep3Vector x = new BasicHep3Vector(trackPoint[0], trackPoint[1], trackPoint[2]);
+      calculateDoca(p, x, q);
+   }
+
+   /*
+    * Calculate the DOCA for a set of parameters in vectors with respect to the origin.
+    */
+   private void calculateDoca(Hep3Vector momentum, Hep3Vector trackPoint, double charge)
+   {
+      reset();
+
+      Hep3Vector xOrigin = new BasicHep3Vector(0., 0., 0.);
+
+      Hep3Vector[] result = calculateDoca(momentum, trackPoint, charge, xOrigin);
+      Hep3Vector xdoca = result[0];
+      Hep3Vector pdoca = result[1];
+      Hep3Vector dphdl = result[2];
+
+      int iq = (int) (charge / Math.abs(charge));
+      double pt = Math.sqrt((pdoca.x() * pdoca.x()) + (pdoca.y() * pdoca.y()));
+
+      // now calculate track parameters
+      double d0 = Math.sqrt((xdoca.x() * xdoca.x()) + (xdoca.y() * xdoca.y()));
+      if (VecOp.cross(xdoca, pdoca).z() > 0)
+      {
+         d0 = -d0;
+      }
+
+      double phi0 = Math.atan2(pdoca.y(), pdoca.x());
+      if (phi0 > Math.PI)
+      {
+         phi0 -= (2 * Math.PI);
+      }
+      if (phi0 < -Math.PI)
+      {
+         phi0 += (2 * Math.PI);
+      }
+
+      double omega = Constants.fieldConversion * iq * m_Bz / pt;
+      double tanl = pdoca.z() / pt;
+      double z0 = xdoca.z();
+
+      // now fill trackparameters
+      m_parm[0] = d0;
+      m_parm[1] = phi0;
+      m_parm[2] = omega;
+      m_parm[3] = z0;
+      m_parm[4] = tanl;
+
+      // save the distance to orignial track vertex
+      m_l0 = -dphdl.y();
+
+      //  	System.out.println("DocaTrackParameters: xdoca = ("+
+      //  			   xdoca.x()+", "+xdoca.y()+", "+xdoca.z()+")");
+      //  	System.out.println("DocaTrackParameters: pdoca = ("+
+      //  			   pdoca.x()+", "+pdoca.y()+", "+pdoca.z()+")");
+      //  	System.out.println("DocaTrackParameters: d0: "+m_parm[0]+
+      //  			   " phi0: "+m_parm[1]+" omega: "+m_parm[2]+
+      //  			   " z0: "+m_parm[3]+" tanl: "+m_parm[4]);
+      //  	System.out.println("DocaTrackParameters: m_l0 = "+m_l0);
+   }
+
+   /*
+    * Calculate DOCA position and momentum vectors with respect to any
+    * space point.
+    */
+   private Hep3Vector[] calculateDoca(Hep3Vector momentum, Hep3Vector trackPoint, double charge, Hep3Vector refPoint)
+   {
+      // subtract refPoint
+      Hep3Vector xp = VecOp.sub(trackPoint, refPoint);
+
+      int iq = (int) (charge / Math.abs(charge));
+      double pt = Math.sqrt((momentum.x() * momentum.x()) + (momentum.y() * momentum.y()));
+      double tanl = momentum.z() / pt;
+      double rho = pt / (m_Bz * Constants.fieldConversion);
+
+      BasicHep3Vector xdoca;
+      Hep3Vector pdoca;
+      Hep3Vector dphdl;
+
+      //  	System.out.println("calculateDoca: m_flip: "+m_flip+" iq: "+iq);
+      if (xp.magnitude() > 0.) // no need for calculation if xp = (0,0,0) !
+      {
+         // calculate position and momentum at doca
+         Hep3Vector nzv = new BasicHep3Vector(0., 0., iq);
+         Hep3Vector xxc = new BasicHep3Vector(VecOp.cross(momentum, nzv).x(), VecOp.cross(momentum, nzv).y(), 0.);
+         Hep3Vector nxxc = VecOp.unit(xxc);
+         BasicHep3Vector xc = (BasicHep3Vector) VecOp.add(xp, VecOp.mult(rho, nxxc));
+         xc.setV(xc.x(), xc.y(), 0.);
+
+         Hep3Vector nxc = VecOp.unit(xc);
+
+         BasicHep3Vector catMC = (BasicHep3Vector) VecOp.cross(nzv, nxc);
+         catMC.setV(catMC.x(), catMC.y(), 0.);
+
+         Hep3Vector ncatMC = VecOp.unit(catMC);
+
+         pdoca = new BasicHep3Vector(pt * ncatMC.x(), pt * ncatMC.y(), momentum.z());
+
+         double dphi = Math.asin(VecOp.cross(nxxc, nxc).z());
+         double dl = -dphi * rho * iq;
+
+         xdoca = (BasicHep3Vector) VecOp.add(xc, VecOp.mult(-rho, nxc));
+         xdoca.setV(xdoca.x(), xdoca.y(), xp.z() + (dl * tanl));
+
+         // save dphi and dl
+         dphdl = new BasicHep3Vector(dphi, dl, 0.);
+      }
+      else
+      {
+         xdoca = (BasicHep3Vector) xp;
+         pdoca = momentum;
+         dphdl = new BasicHep3Vector();
+      }
+
+      // add refPoint back in again
+      xdoca = (BasicHep3Vector) VecOp.add(xdoca, refPoint);
+
+      return new Hep3Vector[] { xdoca, pdoca, dphdl };
+   }
+
+   /*
+    * Calculate Doca for this track with respect to any space point,
+    * if this has not been done before.
+    */
+   private void checkCalcDoca(Hep3Vector refPoint)
+   {
+      // hassle with calculation only, if not done before yet!
+      if ((m_xref == null) || (refPoint.x() != m_xref.x()) || (refPoint.y() != m_xref.y()) || (refPoint.z() != m_xref.z()))
+      {
+         m_xref = refPoint;
+
+         // find doca vectors
+         Hep3Vector xdoca = getDocaVec();
+         Hep3Vector pdoca = getMomentumVec();
+         int iq = getUnitCharge();
+
+         // calculate doca to refPoint
+         Hep3Vector[] result = calculateDoca(pdoca, xdoca, (double) iq, refPoint);
+         m_xdoca_ref = result[0];
+         m_pdoca_ref = result[1];
+
+         // distance along track to original point
+         m_l_ref = result[2].y();
+      }
+   }
+
+   private void reset()
+   {
+      for (int i = 0; i < 5; i++)
+      {
+         m_parm[i] = 0;
+         for (int j = 0; j < 5; j++)
+         {
+            m_err[i][j] = 0;
+         }
+      }
+      m_l0 = 0.;
+   }
+}

lcsim/src/org/lcsim/contrib/garfield/tester
ExampleDriver.java added at 1.1
diff -N ExampleDriver.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ExampleDriver.java	23 Feb 2006 19:10:10 -0000	1.1
@@ -0,0 +1,38 @@
+package org.lcsim.contrib.garfield.tester;
+
+import java.util.*;
+import org.lcsim.event.*;
+import org.lcsim.recon.cluster.nn.NearestNeighborClusterDriver;
+import org.lcsim.util.Driver;
+import org.lcsim.util.aida.AIDA;
+import org.lcsim.contrib.garfield.*;
+
+/**
+ * An example driver showing how to use calorimeter-assisted track finder and 
+ * the tester package.
+ *
+ * @author D. Onoprienko
+ * @version $Id: ExampleDriver.java,v 1.1 2006/02/23 19:10:10 onoprien Exp $
+ * InternalRelease 2.02.01 Feb 23, 2006
+ */
+public class ExampleDriver extends Driver {
+  
+   private AIDA aida = AIDA.defaultInstance();
+   
+   public ExampleDriver() {
+
+     add(new NearestNeighborClusterDriver(2, 2, 1, 2, 0.));
+     add(new EmcalMipStubs("GarfieldMipStubs",0));
+     add(new GarfieldTrackFinder(0));
+     
+     TrackingTest test = new TrackingTest("Example test");
+     test.set(TrackingTest.Parameter.TRACK_COLLECTION_NAME, "GarfieldTracks");
+     add(test);
+     
+     TrackingTest testKs = new TrackingTestKs("Example KS0 test");
+     testKs.set(TrackingTest.Parameter.TRACK_COLLECTION_NAME, "GarfieldTracks");
+     testKs.setPtCut(0.5*Const.GeV);
+     add(testKs);
+   }
+
+}
\ No newline at end of file

lcsim/src/org/lcsim/contrib/garfield/tester
MCTrack.java added at 1.1
diff -N MCTrack.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ MCTrack.java	23 Feb 2006 19:10:10 -0000	1.1
@@ -0,0 +1,185 @@
+package org.lcsim.contrib.garfield.tester;
+
+import java.util.*;
+import org.lcsim.event.*;
+import org.lcsim.contrib.garfield.*;
+
+
+/**
+ * This class represents a Monte Carlo track - Monte Carlo particle that produced 
+ * hits in a tracker. Provides access to the underlying {@link MCParticle} object
+ * and to associated tracker hits and reconstructed tracks. 
+ * <p>
+ * An object of this class can be assigned any number of integer status codes through
+ * the call to {@link #setStatus(int,int) setStatus(int category, int status)} method.
+ * This allows users to mark Monte Carlo tracks that belong to a certain group, for example.
+ * Assigned statuses are retrieved by {@link #getStatus(int) getStatus(int category)}.
+ *
+ * @author D. Onoprienko
+ * @version $Id: MCTrack.java,v 1.1 2006/02/23 19:10:10 onoprien Exp $
+ * InternalRelease 2.02.01 Feb 23, 2006
+ */
+public class MCTrack implements Track {
+  
+// -- Private fields :  --------------------------------------------------------
+  
+  private MCParticle _mcParticle;
+  private ArrayList<TrackerHit> _trackerHits;
+  private ArrayList<Track> _tracks;
+  private boolean _hitsSorted;
+  
+  HashMap<Integer,Integer> _status;
+  
+  static private double[] _cacheTrackParameters;
+  static private MCTrack _trackInCache;
+  
+// -- Constructors :  ----------------------------------------------------------
+  
+  public MCTrack(MCParticle mcParticle) {
+    _mcParticle = mcParticle;
+    _trackerHits = new ArrayList<TrackerHit>(10);
+    _tracks = new ArrayList<Track>(1);
+    _hitsSorted = false;
+    _status = new HashMap<Integer,Integer>(2);
+  }
+  
+// -- Getters :  ---------------------------------------------------------------
+  
+  /** Returns MCParticle that produced this track. */
+  public MCParticle getMCParticle() {return _mcParticle;}
+  
+  /** Returns a list of associated reconstructed tracks. */
+  public List<Track> getTracks() {return _tracks;}
+  
+  /** Returns a list of associated tracker hits. */
+  public List<TrackerHit> getTrackerHits() {
+    if (!_hitsSorted) {
+      sortHits();
+      _hitsSorted = true;
+    }
+    return _trackerHits;
+  }
+  
+  /**
+   * Returns a status flag that has been previously assigned to this track through
+   * the call to {@link #setStatus(int,int) setStatus(int category, int status)}.
+   */
+  public int getStatus(int category) {
+    return _status.get(category);
+  }
+  
+  /** Returns transverse momentum of the track. */
+  public double getPt() {
+    double[] p = getMomentum();
+    return Math.sqrt(p[0]*p[0]+p[1]*p[1]);
+  }
+  
+  /** Returns momentum of the track. */
+  public double getP() {
+    double[] p = getMomentum();
+    return Math.sqrt(p[0]*p[0]+p[1]*p[1]+p[2]*p[2]);
+  }
+    
+  
+// -- Setters :  ---------------------------------------------------------------
+  
+  /** Add track to the list of reconstructed tracks associated with this Monte Carlo track. */
+  public void addTrack(Track track) {_tracks.add(track);}
+  
+  /** Add hit to the list of tracker hits associated with this Monte Carlo track. */
+  public void addHit(TrackerHit hit) {_trackerHits.add(hit);}
+  
+  /** Add hits to the list of tracker hits associated with this Monte Carlo track. */
+  public void addHits(List<TrackerHit> hitList) {
+    for (TrackerHit hit : hitList) if (!_trackerHits.contains(hit)) _trackerHits.add(hit);
+  }
+  
+  /**
+   * Set an integer status flag for this track.
+   *
+   *  @param category  Identifier of a status category. A track can be assigned 
+   *                   statuses in any number of categories.
+   *  @param status    Status flag that can be later retrieved through the call to
+   *                   {@link #getStatus(int) getStatus(int category)}
+   */
+  public void setStatus(int category, int status) {_status.put(category, status);}
+  
+// -- Implement org.lcsim.event.Track : ----------------------------------------
+  
+  public double getTrackParameter(int param) {
+    return getTrackParameters()[param];
+  }
+  
+  public double[] getTrackParameters() {
+    if (_trackInCache != this) {
+      _cacheTrackParameters = (new DocaTrackParameters(Const.bField, _mcParticle)).getTrackParameters();
+      _trackInCache = this;
+    }
+    return _cacheTrackParameters;
+  }
+  
+  public boolean isReferencePointPCA() {return false;}
+  public double getReferencePointX() {return _mcParticle.getOriginX();}
+  public double getReferencePointY() {return _mcParticle.getOriginY();}
+  public double getReferencePointZ() {return _mcParticle.getOriginZ();}
+  public double[] getReferencePoint() {return _mcParticle.getOrigin().v();}
+  
+  public double getdEdx() {return 0.;}
+  public double getdEdxError() {return 0.;}
+  public int getType() {return 0;}
+  public boolean fitSuccess() {return true;}
+  public double getChi2() {return 0.;}
+  public int getNDF() {return 0;}
+  public double getErrorMatrixElement(int param, int param1) {return 0.;}
+  public double[][] getErrorMatrix() {return new double[1][1];}
+  
+  public int[] getSubdetectorHitNumbers() {
+    return new int[]{0,0,0,0};
+  }
+  
+  public int getCharge() {
+    double charge = _mcParticle.getCharge();
+    int iCharge;
+    if (charge < -0.7) iCharge = -1;
+    else if (charge > 0.7) iCharge = 1;
+    else iCharge = 0;
+    return iCharge;
+  }
+  
+  public double[] getMomentum() {return _mcParticle.getMomentum().v();}
+  public double getPX() {return _mcParticle.getPX();}
+  public double getPY() {return _mcParticle.getPY();}
+  public double getPZ() {return _mcParticle.getPZ();}
+  
+  public double getRadiusOfInnermostHit() {
+    double rad = 0.;
+    if (!_trackerHits.isEmpty()) {
+      if (!_hitsSorted) {
+        sortHits();
+        _hitsSorted = true;
+      }
+      double[] pos = _trackerHits.get(0).getPosition();
+      rad = Math.hypot(pos[0], pos[1]);
+    }
+    return rad;
+  }
+  
+// -- Private helper methods :  ------------------------------------------------
+  
+  /**
+   * Sort hits in the order of increasing distance from the detector center.
+   */
+  private void sortHits() {
+    Collections.sort(_trackerHits, new Comparator<TrackerHit>() {
+      public int compare(TrackerHit hit1, TrackerHit hit2) {
+        double[] pos = hit1.getPosition();
+        double r1 = pos[0]*pos[0]+pos[1]*pos[1]+pos[2]*pos[2];
+        pos = hit2.getPosition();
+        double r2 = pos[0]*pos[0]+pos[1]*pos[1]+pos[2]*pos[2];
+        return (int)Math.signum(r1-r2);
+      }
+    });
+    
+  }
+  
+}

lcsim/src/org/lcsim/contrib/garfield/tester
RatedTrack.java added at 1.1
diff -N RatedTrack.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ RatedTrack.java	23 Feb 2006 19:10:10 -0000	1.1
@@ -0,0 +1,113 @@
+package org.lcsim.contrib.garfield.tester;
+
+import java.util.*;
+import org.lcsim.event.*;
+import org.lcsim.contrib.garfield.*;
+
+/**
+ * This class wraps a {@link Track}, providing access to the underlying reconstructed
+ * track, associated Monte Carlo track, and allowing the user to associate any number
+ * of integer status flags with the track.
+ *
+ * @author D. Onoprienko
+ * @version $Id: RatedTrack.java,v 1.1 2006/02/23 19:10:10 onoprien Exp $
+ * InternalRelease 2.02.01 Feb 23, 2006
+ */
+public class RatedTrack implements Track {
+
+// -- Constructors :  ----------------------------------------------------------
+  
+  /** Create RatedTrack by wrapping a reconstructed track. */
+  public RatedTrack(Track track) {
+    _track = track;
+    _status = new HashMap<Integer,Integer>(2);
+  }
+  
+// -- Getters :  ---------------------------------------------------------------
+  
+  /** Returns underlying reconstructed Track object. */
+  public Track getTrack() {return _track;}
+
+  /** Returns associated Monte Carlo track. */
+  public MCTrack getMCTrack() {return _mcTrack;}
+  
+  /**
+   * Returns a status flag that has been previously assigned to this track through
+   * the call to {@link #setStatus(int,int) setStatus(int category, int status)}.
+   */
+  public int getStatus(int category) {return _status.get(category);}
+  
+  /** Returns momentum of the track. */
+  public double getP() {
+    double mom;
+    try {
+      mom = ((GarfieldTrack)_track).getP(Const.bField);
+    } catch (Exception e) {
+      double p[] = _track.getMomentum();
+      mom = Math.sqrt(p[0]*p[0]+p[1]*p[1]+p[2]*p[2]);
+    }
+    return mom;
+  }
+  
+  /** Returns transverse momentum of the track. */
+  public double getPt() {
+    double pt;
+    try {
+      pt = ((GarfieldTrack)_track).getPt(Const.bField);
+    } catch (Exception e) {
+      double p[] = _track.getMomentum();
+      pt = Math.sqrt(p[0]*p[0]+p[1]*p[1]);
+    }
+    return pt;
+  }
+  
+// -- Setters :  ---------------------------------------------------------------
+
+  /** Associate this track with a Monte Carlo track. */
+  public void setMCTrack(MCTrack mcTrack) {_mcTrack = mcTrack;}
+  
+  /**
+   * Set an integer status flag for this track.
+   *
+   *  @param category  Identifier of a status category. A track can be assigned 
+   *                   statuses in any number of categories.
+   *  @param status    Status flag that can be later retrieved through the call to
+   *                   {@link #getStatus(int) getStatus(int category)}
+   */
+  public void setStatus(int category, int status) {_status.put(category, status);}
+  
+// -- Implementing Track: forward calls to associated reconstructed track :  ---
+  
+  public double getTrackParameter(int param) {return _track.getTrackParameter(param);}
+  public boolean isReferencePointPCA() {return _track.isReferencePointPCA();}
+  public double getdEdxError() {return _track.getdEdxError();}
+  public double getdEdx() {return _track.getdEdx();}
+  public int getType() {return _track.getType();}
+  public List<Track> getTracks() {return _track.getTracks();}
+  public List<TrackerHit> getTrackerHits() {return _track.getTrackerHits();}
+  public double[] getTrackParameters() {return _track.getTrackParameters();}
+  public int[] getSubdetectorHitNumbers() {return _track.getSubdetectorHitNumbers();}
+  public boolean fitSuccess() {return _track.fitSuccess();}
+  public int getCharge() {return _track.getCharge();}
+  public double getChi2() {return _track.getChi2();}
+  public double[][] getErrorMatrix() {return _track.getErrorMatrix();}
+  public double getErrorMatrixElement(int param, int param1) {return _track.getErrorMatrixElement(param, param1);}
+  public double[] getMomentum() {return _track.getMomentum();}
+  public int getNDF() {return _track.getNDF();}
+  public double getPX() {return _track.getPX();}
+  public double getPY() {return _track.getPY();}
+  public double getPZ() {return _track.getPZ();}
+  public double getRadiusOfInnermostHit() {return _track.getRadiusOfInnermostHit();}
+  public double[] getReferencePoint() {return _track.getReferencePoint();}
+  public double getReferencePointX() {return _track.getReferencePointX();}
+  public double getReferencePointY() {return _track.getReferencePointY();}
+  public double getReferencePointZ() {return _track.getReferencePointZ();}
+  
+// -- Private data :  ----------------------------------------------------------
+  
+  Track _track;
+  
+  MCTrack _mcTrack;
+  HashMap<Integer,Integer> _status;
+  
+}

lcsim/src/org/lcsim/contrib/garfield/tester
TrackingTest.java added at 1.1
diff -N TrackingTest.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ TrackingTest.java	23 Feb 2006 19:10:10 -0000	1.1
@@ -0,0 +1,122 @@
+package org.lcsim.contrib.garfield.tester;
+
+import java.util.*;
+import java.lang.reflect.*;
+import org.lcsim.event.*;
+import org.lcsim.event.MCParticle.SimulatorStatus;
+import org.lcsim.event.EventHeader.LCMetaData;
+import org.lcsim.util.Driver;
+import hep.physics.particle.Particle;
+import org.lcsim.util.aida.AIDA;
+import hep.aida.ITree;
+
+import javax.swing.*;
+
+
+/**
+ * A general example of track finding performance test.
+ *
+ * @author D. Onoprienko
+ * @version $Id: TrackingTest.java,v 1.1 2006/02/23 19:10:10 onoprien Exp $
+ * InternalRelease 2.02.01 Feb 23, 2006
+ */
+public class TrackingTest extends TrackingTestBase {
+  
+// -- Indices into the statistics (per event and cumulative) arrays :  ---------
+  
+  protected final int _I_nMCTracks;
+  protected final int _I_eMCTracks;
+  protected final int _I_nRecoTracks;
+  protected final int _I_nRecoTracksFake;
+  protected final int _I_nMCTracksReconstructed;
+  protected final int _I_eMCTracksReconstructed;
+  
+// -- Constructors :  ----------------------------------------------------------
+  
+  public TrackingTest(String name) {
+    this();
+    set(Parameter.TEST_NAME, name);
+  }
+  
+  public TrackingTest() {
+    _I_nMCTracks = createIndex("Number of MC Tracks in class");
+    _I_eMCTracks = createIndex("Total momentum of MC Tracks in class", IndexType.NOPRINT);
+    _I_nMCTracksReconstructed = createIndex("Number of MC Tracks in class that have been reconstructed");
+    _I_eMCTracksReconstructed = createIndex("Total momentum of MC Tracks in class that have been reconstructed", IndexType.NOPRINT);
+    _I_nRecoTracks = createIndex("Number of reconstructed tracks", IndexType.NOPRINT);
+    _I_nRecoTracksFake = createIndex("Total number of fakes", IndexType.PRINTEVENT);
+    
+    _ptCut = 0.;
+  }
+  
+// -- Setters :  ---------------------------------------------------------------
+  
+  public void setPtCut(double ptCut) { _ptCut = ptCut;}
+  
+// -- Processing event :  ------------------------------------------------------
+  
+  protected void analyzeEvent(EventHeader event) {
+    
+    // Number and momentum of tracks in class and those of them that have been reconstructed
+    
+    for (MCTrack mcTrack : _mcTrackList) {
+      if (mcTrack.getStatus(IN_CLASS) == YES) {
+        _statE[_I_nMCTracks] += 1.;
+        _statE[_I_eMCTracks] += mcTrack.getP();
+        if (mcTrack.getTracks().size() > 0) {
+          _statE[_I_nMCTracksReconstructed] += 1.;
+          _statE[_I_eMCTracksReconstructed] += mcTrack.getP();
+        }
+      }
+    }
+    
+    // Number of reconstracted tracks and fakes
+    
+    _statE[_I_nRecoTracks] = _ratedTrackList.size();
+    for (RatedTrack ratedTrack : _ratedTrackList) {
+      if (ratedTrack.getMCTrack() == null) _statE[_I_nRecoTracksFake] += 1.;
+    }
+    
+    // Fill histograms for reconstructed tracks in class :
+    
+    for (RatedTrack rTrack : _ratedTrackList) {
+      MCTrack mcTrack = rTrack.getMCTrack();
+      if (mcTrack != null && mcTrack.getStatus(IN_CLASS) == YES) {
+        double p = mcTrack.getP();
+        double dp = rTrack.getP()-p;
+        _aida.cloud1D(_testName + " deltaP over P").fill(dp/p);
+        p = mcTrack.getPt();
+        dp = rTrack.getPt()-p;
+        _aida.cloud1D(_testName + " deltaPt over Pt").fill(dp/p);
+      }
+    }
+
+    // Print statistics
+    
+    printStatistics(event);
+  }
+  
+  
+  protected boolean mcTrackFilter(MCTrack mcTrack) {
+    MCParticle mcPart = mcTrack.getMCParticle();
+    if (mcPart.getGeneratorStatus() != Particle.FINAL_STATE) return false;
+    if (Math.abs(mcPart.getCharge()) < .8) return false;
+    if (mcTrack.getPt() < _ptCut) return false;
+    return true;
+  }
+  
+  protected void suspend() {
+    String[] messages = new String[] {
+      "Reconstruction efficiency for tracks in class: " + _statC[_I_nMCTracksReconstructed]/_statC[_I_nMCTracks],
+      "Fraction of reconstructed momentum for tracks in class: " + _statC[_I_eMCTracksReconstructed]/_statC[_I_eMCTracks],
+      "Purity (all tracks): " + (1.-_statC[_I_nRecoTracksFake]/_statC[_I_nRecoTracks])
+    };
+    printCumulativeStatistics(messages);
+  }
+  
+  protected void endOfData() {suspend();}
+  
+// -- Private fields :  --------------------------------------------------------
+  
+  double _ptCut;
+}

lcsim/src/org/lcsim/contrib/garfield/tester
TrackingTestBase.java added at 1.1
diff -N TrackingTestBase.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ TrackingTestBase.java	23 Feb 2006 19:10:10 -0000	1.1
@@ -0,0 +1,448 @@
+package org.lcsim.contrib.garfield.tester;
+
+import java.util.*;
+import java.lang.reflect.*;
+import javax.swing.*;
+import org.lcsim.event.*;
+import org.lcsim.event.MCParticle.SimulatorStatus;
+import org.lcsim.event.EventHeader.LCMetaData;
+import org.lcsim.util.Driver;
+import hep.physics.particle.Particle;
+import org.lcsim.util.aida.AIDA;
+import hep.aida.ITree;
+
+
+/**
+ * Abstract class that provides infrastructure and utility methods for testing track finders.
+ * See {@link TrackingTest} and {@link TrackingTestKs} for examples of use.
+ * <p>
+ * Classes implementing particular tests should extend this class, overwriting
+ * {@link #analyzeEvent(EventHeader)} and, if necessary,
+ * {@link #eventFilter(EventHeader)},
+ * {@link #matchTracks(Track track, MCTrack mcTrack)},
+ * {@link #mcTrackFilter(MCTrack mcTrack)},
+ * {@link #suspend()}, and {@link #endOfData()} methods.
+ * <p>
+ * Subclusses extending this driver should be added to the event processing chain
+ * after track findind stage. When the driver's {@link #process(EventHeader event)}
+ * method is called by the framework, it creates a list of Monte Carlo tracks,
+ * associates hits and reconstructed tracks with them, and then calls
+ * {@link #analyzeEvent(EventHeader)} method that should be implemented by subclasses.
+ * <p>
+ * Only events for which {@link #eventFilter(EventHeader)} returns <code>true</code>
+ * are processed. Reconstructed track is associated with Monte Carlo track if
+ * {@link #matchTracks(Track track, MCTrack mcTrack)} returns <code>true</code>.
+ * Monte Carlo tracks for which {@link #mcTrackFilter(MCTrack mcTrack)} returns 
+ * <code>true</code> are marked as being in the requested class (subsequent calls to
+ * {@link MCTrack#getStatus(int) mcTrack.getStatus(TrackingTestBase.IN_CLASS)}
+ * will return <code>TrackingTestBase.YES</code>. Default implementations are provided
+ * for these methods, but subclasses will need to overwrite some or all of them to 
+ * perform a meaningful test.
+ * <p>
+ * Any number of variables for accumulating statistics can be created with
+ * {@link #createIndex(String name, IndexType... args)}. Data put into
+ * these variables is automatically accumulated at the end of event processing,
+ * and can be printed out with {@link #printStatistics(EventHeader event)} and 
+ * {@link #printCumulativeStatistics()}.
+ * <p>
+ * A few utility methods that might be useful in testing tracking performance are also provided.
+ *
+ * @author D. Onoprienko
+ * @version $Id: TrackingTestBase.java,v 1.1 2006/02/23 19:10:10 onoprien Exp $
+ * InternalRelease 2.02.01 Feb 23, 2006
+ */
+abstract public class TrackingTestBase extends Driver {
+  
+// -- Constants defining status categories and values:  ------------------------
+  
+  public static final int IN_CLASS = -1;
+  public static final int FAKE = -2;
+  
+  public static final int YES = -1;
+  public static final int NO = -2;
+  
+// -- Constructors :  ----------------------------------------------------------
+  
+  public TrackingTestBase() {
+    _testName = "";
+    _aida = AIDA.defaultInstance();
+    _tree = _aida.tree();
+    _trackCollectionName = "";
+    _trackerHitCollectionName = "";
+    _nEvents = 0;
+  }
+  
+  // -- Setters :  -------------------------------------------------------------
+  
+  public enum Parameter {
+    TEST_NAME,
+    TRACK_COLLECTION_NAME,
+    HIT_COLLECTION_NAME
+  }
+  
+  /**
+   * Set test parameters.
+   * @param par    Indicates what parameter is being changed.
+   * @param value  Value to be assigned to this parameter.
+   */
+  public void set(Parameter par, String value) {
+    switch (par) {
+      case TEST_NAME:
+        _testName = value;
+        break;
+      case TRACK_COLLECTION_NAME:
+        _trackCollectionName = value;
+        break;
+      case HIT_COLLECTION_NAME:
+        _trackerHitCollectionName = value;
+        break;
+      default: throw new Error("No such parameter: " + par);
+    }
+  }
+  
+// -- Processing event :  ------------------------------------------------------
+  
+  /** Process event. */
+  public final void process(EventHeader event) {
+    
+    // Skip undesired events
+    
+    if (!eventFilter(event)) return;
+    
+    // Reset "per event" statistics
+    
+    if (_statE != null) Arrays.fill(_statE, 0.);
+    
+    // Create list of Monte Carlo Tracks
+    
+    List<List<TrackerHit>> hitCollections;
+    List<TrackerHit> hitList;
+    if (_trackerHitCollectionName == "") {
+      hitCollections = event.get(TrackerHit.class);
+      hitList = new ArrayList<TrackerHit>(100);
+      for (List<TrackerHit> list : hitCollections) hitList.addAll(list);
+    } else {
+      hitList = event.get(TrackerHit.class, _trackerHitCollectionName);
+    }
+    
+    _mcTrackList = new ArrayList<MCTrack>(100);
+    List<MCParticle> mcParticleList = event.getMCParticles();
+    for (MCParticle mcPart : mcParticleList) {
+      List<TrackerHit> relatedHits = findRelatedHits(mcPart, hitList);
+      if (relatedHits.size() > 0) {
+        MCTrack mcTrack = new MCTrack(mcPart);
+        mcTrack.addHits(relatedHits);
+        mcTrack.setStatus(IN_CLASS, mcTrackFilter(mcTrack) ? YES : NO);
+        _mcTrackList.add(mcTrack);
+      }
+    }
+    hitList = null;
+    _mcTrackList.trimToSize();
+    
+    // Associate reconstructed tracks with Monte Carlo Tracks
+    
+    _recoTrackList = event.get(Track.class, _trackCollectionName);
+    _ratedTrackList = new ArrayList<RatedTrack>(_recoTrackList.size());
+    
+    for (Track track : _recoTrackList) {
+      _ratedTrackList.add(createRatedTrack(track));
+    }
+    
+    // User's analysis
+    
+    analyzeEvent(event);
+    
+    // Update cumulative statistics
+    
+    if (_statE != null) {
+      for (int i=0; i<_statE.length; i++) _statC[i] += _statE[i];
+    }
+    _nEvents++;
+    
+    // Free memory
+    
+    _mcTrackList = null;
+    _recoTrackList = null;
+    _ratedTrackList = null;
+  }
+  
+  /**
+   * Returns <code>true</code> for events that should be included in analysis.
+   * Default implementation always returns <code>true</code>.
+   * Subclasses should overwrite this method if some events need to be excluded.
+   */
+  protected boolean eventFilter(EventHeader event) {
+    return true;
+  }
+  
+  /**
+   * Returns <code>true</code> if reconstructed track and Monte Carlo track are deemed to describe the same track.
+   * Default implementation returns <code>true</code> if all hits associated with the reconstructed track are
+   * also associated with the MC track. Subclasses should overwrite this method if different algorithm is desired.
+   */
+  protected boolean matchTracks(Track track, MCTrack mcTrack) {
+    List<TrackerHit> recoTrackHitList = track.getTrackerHits();
+    List<TrackerHit> mcTrackHitList = mcTrack.getTrackerHits();
+    return mcTrackHitList.containsAll(recoTrackHitList);
+  }
+  
+  /**
+   * Returns <code>true</code> if Monte Carlo track belongs to the class that needs to be included in analysis.
+   * Default implementation always returns <code>true</code>.
+   * Subclasses should overwrite this method if more narrow class is desired (for example, requesting only
+   * tracks produced by final state charged particles is usually a good idea at the moment).
+   */
+  protected boolean mcTrackFilter(MCTrack mcTrack) {
+    return true;
+  }
+  
+  /** User analysis of the event. */
+  abstract protected void analyzeEvent(EventHeader event);
+  
+  /**
+   * Called by the framework when the event processing is suspended.
+   * Unless overwritten in the subclass, prints out standard cumulative statistics.
+   */
+  protected void suspend() {printCumulativeStatistics();}
+  
+  /**
+   * Called when all data processing is finished.
+   * Unless overwritten in the subclass, prints out standard cumulative statistics.
+   */
+  protected void endOfData() {printCumulativeStatistics();}
+  
+  /**
+   * Called before the first event is processed, or after a rewind.
+   * Unless overwritten in the subclass, resets standard cumulative statistics.
+   */
+  protected void startOfData() {
+    _nEvents = 0;
+    if (_statE != null) Arrays.fill(_statC, 0.);
+  }
+  
+// -- Public helper methods :  -------------------------------------------------
+  
+  /**
+   * Returns a list of hits from the list supplied as an argument that were produced by the given MCParticle.
+   */
+  public static List<TrackerHit> findRelatedHits(MCParticle mcParticle, List<TrackerHit> hitList) {
+    ArrayList<TrackerHit> outputList = new ArrayList<TrackerHit>(1);
+    for (TrackerHit hit : hitList) {
+      List<MCParticle> mcList = extractMCParticles(hit);
+      if (mcList == null || mcList.isEmpty()) {
+        mcList = new ArrayList<MCParticle>(1);
+        List rawHitList = hit.getRawHits();
+        for (Object rawHit : rawHitList) {
+          List<MCParticle> list = extractMCParticles(rawHit);
+          if (list != null) mcList.addAll(list);
+        }
+      }
+      if (mcList.contains(mcParticle)) outputList.add(hit);
+    }
+    return outputList;
+  }
+  
+  /**
+   * Returns a list of MCParticles associated with the given object.
+   * If the object has either <code>getMCParticle()</code> or <code>getMCParticles()</code>
+   * methods, their output is returned unless it is <code>null</code> (in which case empty list is
+   * returned). If the object has none of these methods, <code>null</code> is returned.
+   */
+  public static List<MCParticle> extractMCParticles(Object object) {
+    List<MCParticle> outputList;
+    Class objectClass = object.getClass();
+    try {
+      Method method = objectClass.getMethod("getMCParticle");
+      MCParticle mcPart = (MCParticle) method.invoke(object);
+      outputList = new ArrayList<MCParticle>(1);
+      if (mcPart != null) {
+        outputList.add(mcPart);
+      }
+    } catch (Exception ex) {
+      try {
+        Method method = objectClass.getMethod("getMCParticles");
+        outputList = (List<MCParticle>) method.invoke(object);
+        if (outputList == null) outputList = new ArrayList<MCParticle>(1);
+      } catch (Exception exx) {
+        outputList = null;
+      }
+    }
+    return outputList;
+  }
+  
+// -- Protected helper methods:  -----------------------------------------------
+  
+  /**
+   * Creates RatedTrack from a reconstructed track and associates a Monte Carlo track with it.
+   * This method calls <code>matchTracks(Track track, MCTrack mcTrack)</code>
+   * method that can be overwritten by subclasses to reflect the
+   * desired algorithm for associating Monte Carlo tracks with reconstructed tracks.
+   */
+  protected RatedTrack createRatedTrack(Track track) {
+    
+    RatedTrack ratedTrack = new RatedTrack(track);
+    
+    MCTrack matchingMCTrack = null;
+    for (MCTrack mcTrack : _mcTrackList) {
+      if (matchTracks(track, mcTrack)) {
+        matchingMCTrack = mcTrack;
+        break;
+      }
+    }
+    if (matchingMCTrack != null) {
+      ratedTrack.setMCTrack(matchingMCTrack);
+      matchingMCTrack.addTrack(ratedTrack);
+    }
+    
+    return ratedTrack;
+  }
+  
+  protected enum IndexType {NOSUM, SUM, SUM2, NOPRINT, PRINTEVENT, PRINTSUM, PRINTALL}
+  
+  /**
+   * Creates a new statistical variable and returns an index that can be used to access it.
+   * "Per event" data can be put into <code>_statE[index]</code>, these variables are reset
+   * to zero at the beginning of each event. At the end of the event, statistics is
+   * automatically accumulated into <code>_statC[index]</code>. The name of the variable
+   * is accessable through <code>_statName[index]</code>.
+   *
+   * @param name  Name to be assigned to the variable.
+   * @param args  Optional flags defining accumulation type and printing preferences. Possible flags and their meanings:<p>
+   *    &nbsp; NOSUM - do not accumulate this variable.<br>
+   *    &nbsp; SUM - <code>_statE[index]</code> added to <code>_statC[index]</code> at the end of event.<br>
+   *    &nbsp; SUM2 - square of <code>_statE[index]</code> added to <code>_statC[index]</code> at the end of event.<br>
+   *    &nbsp; If no flag is given, SUM is assumed.<p>
+   *    &nbsp; NOPRINT - variable is not printed by {@link #printStatistics(EventHeader event)} and {@link #printCumulativeStatistics()}<br>
+   *    &nbsp; PRINTEVENT - variable is printed by {@link #printStatistics(EventHeader event)} but not by {@link #printCumulativeStatistics()}<br>
+   *    &nbsp; PRINTSUM - variable is printed by {@link #printCumulativeStatistics()} but not by {@link #printStatistics(EventHeader event)}<br>
+   *    &nbsp; PRINTALL - variable is printed by both {@link #printCumulativeStatistics()} and {@link #printStatistics(EventHeader event)}<br>
+   *    &nbsp; &nbsp; If no flag is given, PRINTALL is assumed.<p>
+   * @return  Index into {@link #_statE}, {@link #_statC}, and {@link #_statName} arrays that can be used to access the variable being created.
+   */
+  protected int createIndex(String name, IndexType... args) {
+    
+    int size;
+    if (_statE == null) {
+      _statE = new double[] {0.};
+      _statC = new double[] {0.};
+      _statName = new String[] {name};
+      _statAccumulateFlag = new IndexType[] {IndexType.SUM};
+      _statPrintFlag = new IndexType[] {IndexType.PRINTALL};
+      size = 0;
+    } else {
+      
+      size = _statE.length;
+      
+      double[] tempD = new double[size+1];
+      System.arraycopy(_statE, 0, tempD, 0, size);
+      _statE = tempD;
+      _statE[size] = 0.;
+      
+      tempD = new double[size+1];
+      System.arraycopy(_statC, 0, tempD, 0, size);
+      _statC = tempD;
+      _statC[size] = 0.;
+      
+      String[] tempS = new String[size+1];
+      System.arraycopy(_statName, 0, tempS, 0, size);
+      _statName = tempS;
+      _statName[size] = name;
+      
+      IndexType[] tempI = new IndexType[size+1];
+      System.arraycopy(_statAccumulateFlag, 0, tempI, 0, size);
+      _statAccumulateFlag = tempI;
+      _statAccumulateFlag[size] = IndexType.SUM;
+      
+      tempI = new IndexType[size+1];
+      System.arraycopy(_statPrintFlag, 0, tempI, 0, size);
+      _statPrintFlag = tempI;
+      _statPrintFlag[size] = IndexType.PRINTALL;
+    }
+    
+    if (args != null) {
+      for (IndexType type : args) {
+        switch (type) {
+          case NOSUM:
+          case SUM:
+          case SUM2:
+            _statAccumulateFlag[size] = type; break;
+          case NOPRINT:
+          case PRINTEVENT:
+          case PRINTSUM:
+          case PRINTALL:
+            _statPrintFlag[size] = type; break;
+        }
+      }
+    }
+    
+    return size;
+  }
+  
+  /** Print statistics at the end of an event. */
+  protected void printStatistics(EventHeader event) {
+    System.out.println("");
+    System.out.println("Tracking test: " + _testName + ", statistics for event " + event.getEventNumber());
+    for (int i=0; i<_statE.length; i++) {
+      if (_statPrintFlag[i] == IndexType.PRINTEVENT || _statPrintFlag[i] == IndexType.PRINTALL) {
+        System.out.println("  " + _statName[i] + "  " + _statE[i]);
+      }
+    }
+    System.out.println("");
+  }
+  
+  /** 
+   * Print cumulative statistics. 
+   * @param messages  Array of strings that should be printed before standard statistics.
+   * @param printStandard   Flag to indicate whether to print standard statistics.
+   */
+  protected void printCumulativeStatistics(String[] messages, boolean printStandard) {
+    ArrayList<String> msgList = new ArrayList<String>(20);
+    msgList.add("");
+    if (messages != null) for (String msg : messages) msgList.add("  " + msg);
+    if (printStandard && _nEvents > 0) {
+      for (int i=0; i<_statE.length; i++) {
+        if (_statPrintFlag[i] == IndexType.PRINTSUM || _statPrintFlag[i] == IndexType.PRINTALL) {
+          msgList.add("  Average  " + _statName[i] + "  " + _statC[i]/_nEvents);
+        }
+      }
+    }
+    msgList.add("");
+    Object[] msgArray = msgList.toArray();
+    JOptionPane.showMessageDialog(null, msgArray,
+            "Tracking test: " + _testName + " cumulative statistics  (" + _nEvents + " events)",
+            JOptionPane.INFORMATION_MESSAGE);
+  }
+  
+  /** 
+   * Print standard cumulative statistics. 
+   */
+  protected void printCumulativeStatistics() {printCumulativeStatistics(null, true);}
+  
+  /** 
+   * Print cumulative statistics. 
+   * @param messages  Array of strings that should be printed before standard statistics.
+   */
+  protected void printCumulativeStatistics(String[] messages) {printCumulativeStatistics(messages, true);}
+  
+// -- Private fields :  --------------------------------------------------------
+  
+  protected String _testName;
+  
+  protected ArrayList<MCTrack> _mcTrackList;
+  protected List<Track> _recoTrackList;
+  protected ArrayList<RatedTrack> _ratedTrackList;
+  
+  protected String _trackCollectionName;
+  protected String _trackerHitCollectionName;
+  
+  protected int _nEvents;         // Number of events analyzed
+  protected double[] _statE;      // Array to hold per event statistics
+  protected double[] _statC;      // Array to hold cumulative statistics
+  protected String[] _statName;   // Array to hold names of statical variables
+  protected IndexType[]  _statAccumulateFlag;  // Array to hold flags indicating accumulation methods
+  protected IndexType[]  _statPrintFlag       ;  // Array to hold flags indicating accumulation printing options
+  
+  protected AIDA _aida;
+  protected ITree _tree;
+  
+}

lcsim/src/org/lcsim/contrib/garfield/tester
TrackingTestKs.java added at 1.1
diff -N TrackingTestKs.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ TrackingTestKs.java	23 Feb 2006 19:10:10 -0000	1.1
@@ -0,0 +1,69 @@
+package org.lcsim.contrib.garfield.tester;
+
+import java.util.*;
+import java.lang.reflect.*;
+import org.lcsim.event.*;
+import org.lcsim.event.MCParticle.SimulatorStatus;
+import org.lcsim.event.EventHeader.LCMetaData;
+import org.lcsim.util.Driver;
+import hep.physics.particle.Particle;
+import org.lcsim.util.aida.AIDA;
+import hep.aida.ITree;
+
+
+/**
+ * An example of track finding performance test that looks at reconstruction of
+ * charged pions produced in K short decays.
+ *
+ * @author D. Onoprienko
+ * @version $Id: TrackingTestKs.java,v 1.1 2006/02/23 19:10:10 onoprien Exp $
+ * InternalRelease 2.02.01 Feb 23, 2006
+ */
+public class TrackingTestKs extends TrackingTest {
+  
+// -- Indices into the statistics (per event and cumulative) arrays :  ---------
+  
+  protected final int _I_eKshortsPFraction;
+  
+// -- Constructors :  ----------------------------------------------------------
+  
+  public TrackingTestKs(String name) {
+    this();
+    set(Parameter.TEST_NAME, name);
+  }
+  
+  public TrackingTestKs() {
+    _I_eKshortsPFraction = createIndex("Fraction of energy carried by Kshorts");
+  }
+  
+// -- Processing event :  ------------------------------------------------------
+  
+  protected void analyzeEvent(EventHeader event) {
+    
+    // Calculate fraction of charged track momenta carried by Kshorts
+    
+    List<MCParticle> mcParticleList = event.getMCParticles();
+    double eTotal = 0.;
+    double eKs = 0.;
+    for (MCParticle mcPart : mcParticleList) {
+      if (mcPart.getGeneratorStatus() == Particle.FINAL_STATE) eTotal += mcPart.getEnergy();
+      if (mcPart.getPDGID() == 310) eKs += mcPart.getEnergy();
+    }
+    _statE[_I_eKshortsPFraction] = eKs / eTotal;
+    
+    super.analyzeEvent(event);
+    
+  }
+
+  protected boolean mcTrackFilter(MCTrack mcTrack) {
+    
+    if (!super.mcTrackFilter(mcTrack)) return false;
+    
+    MCParticle mcPart = mcTrack.getMCParticle();
+    List<MCParticle> parentList = mcPart.getParents();
+    return (((mcPart.getPDGID() == 211) || (mcPart.getPDGID() == -211))
+         && (parentList != null) && (parentList.size() == 1)
+         && (parentList.get(0).getPDGID() == 310));
+  }
+  
+}

lcsim/src/org/lcsim/contrib/garfield/tester
package-info.java added at 1.1
diff -N package-info.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ package-info.java	23 Feb 2006 19:10:10 -0000	1.1
@@ -0,0 +1,5 @@
+/**
+ * Contains classes necessary for running simple performance tests on track finders.
+ */
+package org.lcsim.contrib.garfield.tester;
+
CVSspam 0.2.8