Print

Print


Commit in java/trunk/tracking/src/main/java/org/hps/recon/tracking on MAIN
HPSTrack.java+1-1371 -> 372
HelicalTrackHitDriver.java+1-2371 -> 372
SimpleSvtReadout.java+1-1371 -> 372
apv25/RearTransitionModule.java+3-2371 -> 372
kalman/AddFitKalman.java+340added 372
      /AddFitter.java+178added 372
      /BoxHelper.java+45added 372
      /FullFitKalman.java+573added 372
      /HelixParamCalculator.java+206added 372
      /KalmanFilterDriver.java+133added 372
      /KalmanGeom.java+743added 372
      /KalmanSurface.java+431added 372
      /PlayingWithTracksDriver.java+64added 372
      /PrintDetectorElements.java+134added 372
      /PrintDetectorElementsDriver.java+24added 372
      /PrintIntersections.java+130added 372
      /PropDCACyl.java+732added 372
      /PropDCAXY.java+296added 372
      /PropXYCyl.java+627added 372
      /PropXYDCA.java+306added 372
      /PropXYXY.java+855added 372
      /ShapeDispatcher.java+117added 372
      /ShapeHelper.java+35added 372
      /ThinXYPlaneMs.java+212added 372
      /TrackUtils.java+150added 372
      /TrdHelper.java+281added 372
      /TrfDetector.java+44added 372
      /TubeHelper.java+44added 372
kalman/util/AddFitKalman.java+698added 372
           /CylEloss.java+360added 372
           /CylElossSim.java+199added 372
           /FullFitKalman.java+598added 372
           /HitNull.java+97added 372
           /PrintSymMatrix.java+80added 372
           /PropDCAZ.java+294added 372
           /PropZDCA.java+286added 372
           /RKDeDxFixed.java+103added 372
           /RKDebug.java+107added 372
           /RKGeom.java+403added 372
           /RKHit.java+257added 372
           /RKHitList.java+286added 372
           /RKMakeHits.java+614added 372
           /RKSurf.java+419added 372
           /RKTrack.java+150added 372
           /RKTrackGen.java+92added 372
           /RKTrackGenParams.java+202added 372
           /RKZot.java+93added 372
           /SurfaceCode.java+44added 372
           /ThinZPlaneMs.java+209added 372
           /ThinZPlaneMsSim.java+202added 372
           /ToyConfig.java+463added 372
           /ToyConfigException.java+22added 372
           /ToyConfigRecord.java+696added 372
           /VTUtil.java+166added 372
           /cyl_int.java+125added 372
           /toTRF.java+104added 372
           /zplane_int.java+87added 372
+14162-6
53 added + 4 modified, total 57 files
Add kalman filter to tracking package.  (Referenced by some classes in users.)

java/trunk/tracking/src/main/java/org/hps/recon/tracking
HPSTrack.java 371 -> 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/HPSTrack.java	2014-03-26 04:20:57 UTC (rev 371)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/HPSTrack.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -12,12 +12,12 @@
 
 import org.hps.conditions.deprecated.BeamSpot;
 import org.hps.conditions.deprecated.FieldMap;
+import org.hps.util.Pair;
 import org.lcsim.event.MCParticle;
 import org.lcsim.fit.helicaltrack.HelicalTrackFit;
 import org.lcsim.fit.helicaltrack.HelicalTrackHit;
 import org.lcsim.fit.helicaltrack.HelixUtils;
 import org.lcsim.fit.helicaltrack.MultipleScatter;
-import org.lcsim.hps.util.Pair;
 import org.lcsim.spacegeom.CartesianVector;
 import org.lcsim.spacegeom.SpacePoint;
 import org.lcsim.spacegeom.SpaceVector;

java/trunk/tracking/src/main/java/org/hps/recon/tracking
HelicalTrackHitDriver.java 371 -> 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/HelicalTrackHitDriver.java	2014-03-26 04:20:57 UTC (rev 371)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/HelicalTrackHitDriver.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -8,9 +8,8 @@
 import java.util.List;
 import java.util.Map;
 
-import static org.hps.conditions.deprecated.StereoPair.detectorVolume;
-
 import org.hps.conditions.deprecated.StereoPair;
+import org.hps.conditions.deprecated.StereoPair.detectorVolume;
 import org.hps.conditions.deprecated.SvtUtils;
 import org.lcsim.detector.IDetectorElement;
 import org.lcsim.detector.ITransform3D;

java/trunk/tracking/src/main/java/org/hps/recon/tracking
SimpleSvtReadout.java 371 -> 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/SimpleSvtReadout.java	2014-03-26 04:20:57 UTC (rev 371)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/SimpleSvtReadout.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -14,6 +14,7 @@
 import org.hps.readout.ecal.ClockSingleton;
 import org.hps.readout.ecal.ReadoutTimestamp;
 import org.hps.readout.ecal.TriggerableDriver;
+import org.hps.util.RandomGaussian;
 //--- lcsim ---//
 import org.lcsim.detector.tracker.silicon.ChargeCarrier;
 import org.lcsim.detector.tracker.silicon.SiSensor;
@@ -24,7 +25,6 @@
 import org.lcsim.event.base.BaseLCRelation;
 import org.lcsim.event.base.BaseRawTrackerHit;
 import org.lcsim.geometry.Detector;
-import org.lcsim.hps.util.RandomGaussian;
 import org.lcsim.lcio.LCIOConstants;
 import org.lcsim.recon.tracking.digitization.sisim.CDFSiSensorSim;
 import org.lcsim.recon.tracking.digitization.sisim.SiElectrodeData;

java/trunk/tracking/src/main/java/org/hps/recon/tracking/apv25
RearTransitionModule.java 371 -> 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/apv25/RearTransitionModule.java	2014-03-26 04:20:57 UTC (rev 371)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/apv25/RearTransitionModule.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -2,15 +2,16 @@
 
 //--- java ---//
 //--- Constants ---//
+import static org.hps.conditions.deprecated.HPSSVTConstants.TOTAL_STRIPS_PER_SENSOR;
+
 import java.util.ArrayList;
 import java.util.List;
 
 import org.hps.conditions.deprecated.HPSSVTCalibrationConstants;
 import org.hps.conditions.deprecated.HPSSVTConstants;
-import static org.hps.conditions.deprecated.HPSSVTConstants.TOTAL_STRIPS_PER_SENSOR;
+import org.hps.util.RandomGaussian;
 //--- org.lcsim ---//
 import org.lcsim.event.EventHeader;
-import org.lcsim.hps.util.RandomGaussian;
 import org.lcsim.util.Driver;
 //--- hps-java ---//
 

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman
AddFitKalman.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/AddFitKalman.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/AddFitKalman.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,340 @@
+package org.hps.recon.tracking.kalman;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.lcsim.recon.tracking.trfbase.ETrack;
+import org.lcsim.recon.tracking.trfbase.Hit;
+import org.lcsim.recon.tracking.trfbase.TrackError;
+import org.lcsim.recon.tracking.trfbase.TrackVector;
+import org.lcsim.recon.tracking.trfutil.Assert;
+
+import Jama.Matrix;
+// Fit tracks using Kalman filter.
+
+/**
+ *AddFitKalman  uses a Kalman filter to update the track fit.
+ *
+ *
+ *@author Norman A. Graf
+ *@version 1.0
+ *
+ */
+public class AddFitKalman extends AddFitter {
+
+    boolean _DEBUG = false;
+    // Maximum allowed hit dimension.
+    private static final int MAXDIM = 3;
+    // Maximum number of track vectors.
+    private static final int MAXVECTOR = 1;
+    // Maximum number of track errors.
+    private static final int MAXERROR = 1;
+
+    //private:  // nested classes
+    // The nested class Box holds the vectors, matrices and symmetric
+    // matrices needed for adding a hit in the main class.
+    class Box {
+        /*
+        private:  // typedefs
+        typedef Ptr<TrfVector,AutoPolicy>   VectorPtr;
+        typedef Ptr<TrfSMatrix,AutoPolicy>  SMatrixPtr;
+        typedef Ptr<TrfMatrix,AutoPolicy>   MatrixPtr;
+        typedef vector<VectorPtr>           VectorList;
+        typedef vector<SMatrixPtr>          SMatrixList;
+        typedef vector<MatrixPtr>           MatrixList;
+         */
+
+        // enums
+        // number of vectors
+        private static final int NVECTOR = 2;
+        // number of errors
+        private static final int NERROR = 3;
+        // number of vectors
+        private static final int NDERIV = 2;
+        // number of gains
+        private static final int NGAIN = 2;
+        // attributes
+        // dimension of the vector, matrix, etc
+        private int _size;
+        // array of vectors
+        List _vectors;
+        // array of error matrices
+        List _errors;
+        // array of derivatives (Nx5 matrices)
+        List _derivs;
+        // array of gains (5xN matrices)
+        List _gains;
+
+        // methods
+        // constructor
+        public Box(int size) {
+            _size = size;
+            _vectors = new ArrayList();
+            _errors = new ArrayList();
+            _derivs = new ArrayList();
+            _gains = new ArrayList();
+
+            int icnt;
+            // Track vectors
+            for (icnt = 0; icnt < NVECTOR; ++icnt)
+                _vectors.add(new Matrix(size, 1));
+            // Track errors
+            for (icnt = 0; icnt < NERROR; ++icnt)
+                _errors.add(new Matrix(size, size));
+            // Track derivatives
+            for (icnt = 0; icnt < NDERIV; ++icnt)
+                _derivs.add(new Matrix(size, 5));
+            // Gains
+            for (icnt = 0; icnt < NDERIV; ++icnt)
+                _gains.add(new Matrix(5, size));
+
+        }
+
+        // return the dimension
+        public int get_size() {
+            return _size;
+        }
+        // fetch a vector
+
+        public Matrix get_vector(int ivec) {
+            return (Matrix) _vectors.get(ivec);
+        }
+        // fetch an error
+
+        public Matrix get_error(int ierr) {
+            return (Matrix) _errors.get(ierr);
+        }
+        // fetch a derivative
+
+        public Matrix get_deriv(int ider) {
+            return (Matrix) _derivs.get(ider);
+        }
+        // fetch a gain
+
+        public Matrix get_gain(int igai) {
+            return (Matrix) _gains.get(igai);
+        }
+    } // end of Box inner class
+
+    // static methods
+    //
+    /**
+     *Return a String representation of the class' the type name.
+     *Included for completeness with the C++ version.
+     *
+     * @return   A String representation of the class' the type name.
+     */
+    public static String typeName() {
+        return "AddFitKalman";
+    }
+
+    //
+    /**
+     *Return a String representation of the class' the type name.
+     *Included for completeness with the C++ version.
+     *
+     * @return   A String representation of the class' the type name.
+     */
+    public static String staticType() {
+        return typeName();
+    }
+    // attributes
+    // Array of boxes for each supported size.
+    private List _boxes;
+    // Track vectors.
+    private List _tvectors;
+    // Track errors.
+    private List _terrors;
+
+    //methods
+    //
+    /**
+     *Construct a default instance.
+     * Allocate space needed for hits of dimension from 1 to MAXDIM.
+     *
+     */
+    public AddFitKalman() {
+        _boxes = new ArrayList();
+        _tvectors = new ArrayList();
+        _terrors = new ArrayList();
+
+        // Create boxes for hit containers.
+        for (int dim = 1; dim < MAXDIM; ++dim)
+            _boxes.add(new Box(dim));
+
+        int icnt;
+
+        for (icnt = 0; icnt < MAXVECTOR; ++icnt)
+            _tvectors.add(new Matrix(5, 1));
+
+        for (icnt = 0; icnt < MAXERROR; ++icnt)
+            _terrors.add(new Matrix(5, 5));
+
+    }
+
+    //
+    /**
+     *Return a String representation of the class' the type name.
+     *Included for completeness with the C++ version.
+     *
+     * @return   A String representation of the class' the type name.
+     */
+    public String type() {
+        return staticType();
+    }
+
+    //
+    /**
+     *Add a hit and fit with the new hit.
+     * Use a Kalman filter to add a hit to a track.
+     * The hit is updated with the input track.
+     * Note: We make direct use of the underlying vector and matrix
+     *       classes here.  It will probably be neccessary to modify
+     *       this routine if these are changed.
+     *
+     * @param   tre The ETrack to update.
+     * @param   chsq The chi-square for the fit.
+     * @param   hit The Hit to add to the track.
+     * @return  0 if successful.
+     */
+    public int addHitFit(ETrack tre, double chsq, Hit hit) {
+        // Update the hit with the input track.
+        hit.update(tre);
+
+        // Fetch hit size.
+        int dim = hit.size();
+        Assert.assertTrue(dim <= MAXDIM);
+
+        // Fetch the box holding the needed hit containers.
+        // The chice of boxes depends on the size of the hit.
+        Box box = (Box) _boxes.get(dim - 1);
+        Assert.assertTrue(box.get_size() == dim);
+
+        // Fetch the hit containers.
+        Matrix diff = box.get_vector(0);
+        Matrix hit_res = box.get_vector(1);
+        Matrix hit_err = box.get_error(0);
+        Matrix hit_err_tot = box.get_error(1);
+        Matrix hit_res_err = box.get_error(2);
+        Matrix dhit_dtrk = box.get_deriv(0);
+        Matrix new_dhit_dtrk = box.get_deriv(1);
+        Matrix trk_err_dhit_dtrk = box.get_gain(0);
+        Matrix gain = box.get_gain(1);
+
+        // Fetch the track containers.
+        Matrix new_vec = (Matrix) _tvectors.get(0);
+        Matrix new_err = (Matrix) _terrors.get(0);
+
+        hit_err = hit.measuredError().matrix();
+        //System.out.println("hit_err= \n"+hit_err);
+
+        // Fetch track prediction of hit.
+        diff = hit.differenceVector().matrix();
+        //System.out.println("diff= \n"+diff);
+        dhit_dtrk = hit.dHitdTrack().matrix();
+        //System.out.println("dhit_dtrk= \n"+dhit_dtrk);
+        // Fetch track info.
+        Matrix trk_vec = tre.vector().matrix();
+        Matrix trk_err = tre.error().getMatrix(); //need to fix this!
+
+        //System.out.println("trk_vec= \n"+trk_vec);
+        //System.out.println("trk_err= \n"+trk_err);
+
+        // Build gain matrix.
+        hit_err_tot = hit.predictedError().matrix().plus(
+                hit_err);
+        //System.out.println("hit_err_tot= \n"+hit_err_tot);
+        //if ( invert(hit_err_tot)!=0 ) return 3;
+        hit_err_tot = hit_err_tot.inverse();
+        //System.out.println("hit_err_tot inverse= \n"+hit_err_tot);
+        trk_err_dhit_dtrk = trk_err.times(dhit_dtrk.transpose());
+        gain = trk_err_dhit_dtrk.times(hit_err_tot);
+        //System.out.println("trk_err_dhit_dtrk= \n"+trk_err_dhit_dtrk);
+        //System.out.println("gain= \n"+gain);
+
+        //  if ( get_debug() ) {
+        //System.out.println("\n");
+        //System.out.println("      trk_vec: " + "\n"+       trk_vec + "\n");
+        //System.out.println("      trk_err: " + "\n"+       trk_err + "\n");
+        //System.out.println("    dhit_dtrk: " + "\n"+     dhit_dtrk + "\n");
+        //  }
+
+        // We need to return dhit_dtrk to its original state for the
+        // next call.
+        // dhit_dtrk = dhit_dtrk.transpose(); //need to check this!
+        dhit_dtrk.transpose();
+        // Build new track vector.
+        new_vec = trk_vec.minus(gain.times(diff));
+        //System.out.println("new_vec= \n"+new_vec);
+
+        // Build new error;
+        new_err = trk_err.minus(trk_err_dhit_dtrk.times(hit_err_tot.times(trk_err_dhit_dtrk.transpose())));
+        //System.out.println("new_err= \n"+new_err);
+        // Check the error.
+        {
+            int nbad = 0;
+            for (int i = 0; i < 5; ++i) {
+                if (new_err.get(i, i) < 0.0)
+                    ++nbad;
+                double eii = new_err.get(i, i);
+                for (int j = 0; j < i; ++j) {
+                    double ejj = new_err.get(j, j);
+                    double eij = new_err.get(j, i);
+                    if (Math.abs(eij * eij) >= eii * ejj)
+                        ++nbad;
+                }
+            }
+            if (nbad > 0)
+                return 5;
+        }
+
+        // Create track vector with new values.
+        tre.setVectorAndKeepDirection(new TrackVector(new_vec));
+        tre.setError(new TrackError(new_err));
+
+        // Calculate residual vector.
+
+        // Update the hit with the new track.
+        //System.out.println("update the hit");
+        hit.update(tre);
+
+        hit_res = hit.differenceVector().matrix();
+        new_dhit_dtrk = hit.dHitdTrack().matrix();
+        //System.out.println("new_dhit_dtrk= \n"+new_dhit_dtrk);
+
+        // Calculate residual covariance and invert.
+        hit_res_err = hit_err.minus(dhit_dtrk.times(new_err.times(dhit_dtrk.transpose())));
+        //		System.out.println("hit_res_err= \n"+hit_res_err);
+        hit_res_err = hit_res_err.inverse();
+        //System.out.println("hit_res_err inverse= \n"+hit_res_err);
+        // Update chi-square.
+        // result should be 1x1 matrix, so should be able to do the following
+        //System.out.println( " hr*hre*hrT=\n"+(hit_res.transpose()).times(hit_res_err.times(hit_res)) );
+        double dchsq = (hit_res.transpose()).times(hit_res_err.times(hit_res)).get(0, 0);
+        //System.out.println("chsq= "+chsq+", dchsq= "+dchsq);
+        chsq = chsq + dchsq;
+        setChisquared(chsq);
+
+        if (_DEBUG) {
+            System.out.println("         gain: " + "\n" + gain + "\n");
+            System.out.println("      new_vec: " + "\n" + new_vec + "\n");
+            System.out.println("      new_err: " + "\n" + new_err + "\n");
+            System.out.println("new_dhit_dtrk: " + "\n" + new_dhit_dtrk + "\n");
+            System.out.println("      hit_res: " + "\n" + hit_res + "\n");
+            System.out.println("  hit_res_err: " + "\n" + hit_res_err + "\n");
+            System.out.println(" dchsq & chsq: " + "\n" + dchsq + " " + chsq + "\n");
+        }
+
+        return 0;
+
+    }
+
+    /**
+     *output stream
+     *
+     * @return The String representation of this instance.
+     */
+    public String toString() {
+        return getClass().getName();
+    }
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman
AddFitter.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/AddFitter.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/AddFitter.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,178 @@
+package org.hps.recon.tracking.kalman;
+import org.lcsim.recon.tracking.trfbase.ETrack;
+import org.lcsim.recon.tracking.trfbase.Hit;
+import org.lcsim.recon.tracking.trfbase.Surface;
+import org.lcsim.recon.tracking.trffit.HTrack;
+import org.lcsim.recon.tracking.trfutil.Assert;
+/**
+ * Adds a hit prediction to a track, refits the track and uses the
+ * new track parameters to update the hit prediction.
+ *<p>
+ * Two methods are provided: one updates an ETrack and its chi-square
+ * and the other updates an HTrack.
+ *<p>
+ * This base class will always return an error.  Subclasses will typically
+ * implement the ETrack method which is then invoked by the HTrack method
+ * defined here.
+ *
+ *@author Norman A. Graf
+ *@version 1.0
+ *
+ */
+
+public class AddFitter
+{
+    
+    // Static methods.
+    
+    //
+    
+    /**
+     *Return String representation of this class' type name.
+     *Included for completeness with the C++ versin.
+     *
+     * @return String representation of this class' type.
+     */
+    public static String typeName()
+    { return "AddFitter"; }
+    
+    //
+    
+    /**
+     *Return String representation of this class' type name.
+     *Included for completeness with the C++ versin.
+     *
+     * @return String representation of this class' type.
+     */
+    public static String staticType()
+    { return typeName(); }
+    
+    // workaround
+    private double _chsq;
+    
+    // methods
+    
+    //
+    
+    /**
+     *Construct a default instance.
+     *
+     */
+    public AddFitter()
+    {
+        _chsq = 0.;
+    }
+    
+    //
+    
+    /**
+     *Return the generic type.
+     * This is only needed at this level.
+     *
+     * @return String representation of this class' type.
+     */
+    public String genericType()
+    { return staticType(); }
+    
+    //
+    
+    /**
+     *Add a hit and fit with the new hit.
+     * Return status 0 if fit is successful, negative value for a local
+     * error and positive for an error in add_hit_fit.
+     * The default method calls add_hit_fit and return its status.
+     * If the fit is successful, then the track fit is updated and the hit
+     * is added to the end of its list.
+     *
+     * @param   trh The HTrack to which the hit will be added.
+     * @param   hit The Hit to add.
+     * @return 0 if hit update and fit are successful.
+     */
+    public  int addHit(HTrack trh,  Hit hit)
+    {
+        // Fetch the starting fit and chi-square.
+        ETrack tre = trh.newTrack();
+        double chsq = trh.chisquared();
+        
+        // check the track and hit are at the same surface
+        Surface tsrf = tre.surface();
+        Surface hsrf = hit.surface();
+        Assert.assertTrue( tsrf.pureEqual(hsrf) );
+        if ( ! tsrf.pureEqual(hsrf) ) return -1;
+        
+        // Check the track is fully fit before adding hit.
+        // Unless this is the first hit.
+        if ( trh.hits().size() !=0 )
+        {
+            Assert.assertTrue( trh.isFit() );
+            if ( ! trh.isFit() ) return -2;
+        }
+        // Fit with the new point; exit if error occurs.
+        int stat = addHitFit(tre,chsq,hit); //chsq is return argument in c++
+        // need to fix this
+        if ( stat != 0 ) return stat;
+        
+        
+        // Update the track with the new fit and hit.
+        trh.addHit(hit);
+        trh.setFit(tre,_chsq);
+        
+        return 0;
+        
+    }
+    
+    
+    /**
+     *Set the chi-squared for the fit.
+     *
+     * @param   chsq The value of chi-square to set for this fit.
+     */
+    public void setChisquared(double chsq)
+    {
+        _chsq = chsq;
+    }
+    
+    
+    /**
+     *Return the chi-squared for the fit.
+     *
+     * @return  The value of chi-square for this fit.
+     */
+    public double chisquared()
+    {
+        return _chsq;
+    }
+    //
+    
+    
+    /**
+     *Refit a track and update its chi-square by adding the specified hit.
+     * Return status 0 if fit is successful, positive value for error.
+     * This is the method implemented by subclasses.
+     * If the fit fails, the track and chi-square may return any value
+     * and the hit may be updated with any track.
+     * If the fit is successful, the fit track and chi-square are
+     * returned and the hit is updated with the fit track.
+     * Normally this is not invoked directly but is called by add_hit.
+     * The default method here returns an error and throws and AssertException.
+     *
+     * @param   tre The ETrack to which the hit will be added.
+     * @param   chisq The value of chi-square to set for this fit.
+     * @param   phit The Hit to add.
+     * @return 1.
+     */
+    public int addHitFit(ETrack tre, double chisq,  Hit phit)
+    {  Assert.assertTrue( false );
+       return 1;}
+    
+    
+    /**
+     *output stream
+     *
+     * @return AString representation of this object.
+     */
+    public String toString()
+    {
+        return getClass().getName();
+    }
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman
BoxHelper.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/BoxHelper.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/BoxHelper.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,45 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.hps.recon.tracking.kalman;
+
+import org.lcsim.detector.solids.Box;
+import org.lcsim.detector.solids.ISolid;
+import org.lcsim.event.Track;
+
+/**
+ *
+ * @author ecfine
+ */
+public class BoxHelper implements ShapeHelper{
+    public void printShape(ISolid solid) {
+        checkBox(solid);
+        System.out.println("Shape: Box");
+    }
+    
+    public void printLocalCoords(ISolid solid) {
+        
+    }
+    
+    public void printGlobalCoords(ISolid solid) {
+        
+    }
+    
+    private void checkBox(ISolid solid){
+        if (solid instanceof Box) {
+        } else {
+            System.out.println("Error! This is not a box! ");
+            return;
+        }
+    }
+
+    public void findIntersection(ISolid solid, Track track) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    public KalmanSurface getKalmanSurf(ISolid solid) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman
FullFitKalman.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/FullFitKalman.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/FullFitKalman.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,573 @@
+package org.hps.recon.tracking.kalman;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+import org.hps.recon.tracking.kalman.util.RKDebug;
+import org.hps.recon.tracking.kalman.util.SurfaceCode;
+import org.lcsim.recon.tracking.trfbase.ETrack;
+import org.lcsim.recon.tracking.trfbase.Hit;
+import org.lcsim.recon.tracking.trfbase.PropDir;
+import org.lcsim.recon.tracking.trfbase.PropStat;
+import org.lcsim.recon.tracking.trfbase.Propagator;
+import org.lcsim.recon.tracking.trfbase.Surface;
+import org.lcsim.recon.tracking.trfbase.TrackError;
+import org.lcsim.recon.tracking.trfcyl.SurfCylinder;
+import org.lcsim.recon.tracking.trfcyl.ThinCylMs;
+import org.lcsim.recon.tracking.trffit.FullFitter;
+import org.lcsim.recon.tracking.trffit.HTrack;
+import org.lcsim.recon.tracking.trfzp.SurfZPlane;
+import org.lcsim.recon.tracking.trfzp.ThinZPlaneMs;
+import org.lcsim.util.aida.AIDA;
+
+/**
+ *
+ * Copied from org.lcsim.contrib.RobKutschke.TRF.trffit. Added some very naive
+ * multiple scattering, which will need to be updated.
+ *
+ *
+ * Full track fit using Kalman filter.  The propagator is specified
+ * when the fitter is constructed.  The starting surface, vector and
+ * error matrix are taken from the input track.  Errors should be
+ * increased appropriately if the fitter is applied repeatedly to
+ * a single track.
+ *
+ *@author $Author: mgraham $
+ *@version $Id: FullFitKalman.java,v 1.6 2011/11/16 18:00:03 mgraham Exp $
+ *
+ * Date $Date: 2011/11/16 18:00:03 $
+ *
+ */
+public class FullFitKalman extends FullFitter {
+
+    boolean _DEBUG = true;
+    private AIDA aida = AIDA.defaultInstance();
+    // Flags to control: multiple scattering, energy loss and adding the hit.
+    private boolean doMs = true;
+    private boolean doEloss = true;
+    private boolean doMeas = true;
+    private double dedxscale = 1.;
+    private double dedxsigma = 0.0;
+
+    // static methods
+    //
+    /**
+     *Return a String representation of the class' the type name.
+     *Included for completeness with the C++ version.
+     *
+     * @return   A String representation of the class' the type name.
+     */
+    public static String typeName() {
+        return "FullFitKalman";
+    }
+
+    //
+    /**
+     *Return a String representation of the class' the type name.
+     *Included for completeness with the C++ version.
+     *
+     * @return   A String representation of the class' the type name.
+     */
+    public static String staticType() {
+        return typeName();
+    }
+    // The propagator.
+    private Propagator _pprop;
+    // The add fitter.
+    private AddFitKalman _addfit;
+    int AddFitKalmanDebugLevel = 0;
+    //
+
+    /**
+     *Construct an instance specifying a propagator.
+     *
+     * @param   prop The Propagator to be used during the fit.
+     */
+    public FullFitKalman(Propagator prop) {
+        _pprop = prop;
+        _addfit = new AddFitKalman();
+
+//	try{
+//	    ToyConfig config = ToyConfig.getInstance();
+//	    AddFitKalmanDebugLevel = config.getInt( "AddFitKalmanDebugLevel",
+//						    AddFitKalmanDebugLevel );
+//	    dedxscale = config.getDouble("dEdXScale");
+//	    dedxsigma = config.getDouble("dEdXSigma");
+//
+//
+//	} catch (ToyConfigException e){
+//            System.out.println (e.getMessage() );
+//            System.out.println ("Stopping now." );
+//            System.exit(-1);
+//        }
+//	System.out.println ("FullfitKalman dedxscale: " + dedxscale );
+
+    }
+
+    //
+    /**
+     *Return a String representation of the class' type name.
+     *Included for completeness with the C++ version.
+     *
+     * @return   A String representation of the class' the type name.
+     */
+    public String type() {
+        return staticType();
+    }
+
+    //
+    /**
+     *Return the propagator.
+     *
+     * @return The Propagator used in the fit.
+     */
+    public Propagator propagator() {
+        return _pprop;
+    }
+
+    //
+    public void setDoMs(boolean b) {
+        doMs = b;
+    }
+
+    public void setDoEloss(boolean b) {
+        doEloss = b;
+    }
+
+    /**
+     *Fit the specified track.
+     *
+     * @param   trh The HTrack to fit.
+     * @return 0 if successful.
+     */
+    public int fit(HTrack trh) {
+        // Copy the hits from the track.
+        List hits = trh.hits();
+        if (_DEBUG)
+            System.out.println("FullFitKalman::Hits has " + hits.size() + " elements");
+        // Delete the list of hits from the track.
+        while (trh.hits().size() > 0)
+            trh.dropHit();
+//        System.out.println("Hits has "+hits.size()+" elements");
+
+        // Set direction to be nearest.
+        PropDir dir = PropDir.NEAREST;
+//        PropDir dir = PropDir.FORWARD;
+//        RKDebug.Instance().setPropDir(dir);
+
+        // Loop over hits and fit.
+        int icount = 0;
+        for (Iterator ihit = hits.iterator(); ihit.hasNext();) {
+
+            // Extract the next hit pointer.
+            Hit hit = (Hit) ihit.next();
+            if (_DEBUG) {
+                System.out.println("*******   ADDING NEW HIT    *********** ");
+                System.out.println("Hit " + icount + " is: \n");
+                System.out.println("Before prop: " + trh.newTrack());
+                System.out.println("Propogating to surface : " + hit.surface());
+            }
+            //            System.out.println("Before prop spacepoint: " + hit.surface().spacePoint(trh.newTrack().vector()));
+
+            // propagate to the surface
+            PropStat pstat = trh.propagate(_pprop, hit.surface(), dir);
+
+            if (_DEBUG) {
+                System.out.println("pstat = " + pstat);
+                System.out.println("After prop: " + trh.newTrack());
+            }
+            if (!pstat.success())
+                return -666;
+//            System.out.println("trh= \n"+trh+", hit= \n"+hit);
+//            System.out.println("_addfit= "+_addfit);
+//            System.out.println("After prop spacepoint: " + hit.cluster().surface().spacePoint(trh.newTrack().vector()));
+//            System.out.println("trh surface: " + trh.newTrack().surface().toString());
+//            System.out.println("hit surface" + hit.surface().toString());
+
+//             fit track
+            if (_DEBUG)
+                System.out.println("Predicted Hit Vector before addHit: " + hit.predictedVector());
+            int fstat = _addfit.addHit(trh, hit);
+            if (_DEBUG)
+                System.out.println("Predicted Hit Vector after addHit: " + hit.predictedVector());
+//
+            if (_DEBUG) {
+                System.out.println("Measured Hit Vector after addHit: " + hit.cluster());
+                System.out.println("After addhit: " + fstat + " chi^2 = "
+                        + trh.chisquared() + "\n" + trh.newTrack());
+//            System.out.println("After addhit spacepoint: " + hit.cluster().surface().spacePoint(trh.newTrack().vector()));
+//
+            }
+
+            // Multiple scattering--this is a silly way to do it..
+            ThinXYPlaneMs interactor = new ThinXYPlaneMs(.02);
+
+            if (_DEBUG)
+                System.out.println("trh error pre MS:  " + trh.newTrack().error().toString());
+//            ThinXYPlaneMs interactor = new ThinXYPlaneMs(.005);
+            ETrack tre2 = trh.newTrack();
+            interactor.interact(tre2);
+            trh.setFit(tre2, trh.chisquared());
+            if (_DEBUG)
+                System.out.println("trh error pre MS:  " + trh.newTrack().error().toString());
+            if (fstat > 0)
+                return 10000 + 1000 * fstat + icount;
+
+
+            icount++;
+
+        }
+        if (_DEBUG)
+            System.out.println("fit completed");
+        return 0;
+    }
+
+    public int fitForward(HTrack trh) {
+        if (_DEBUG)
+            System.out.println("fitting forward...");
+
+        PropDir dir = PropDir.FORWARD;
+//        RKDebug.Instance().setPropDir(dir);
+
+
+        // Copy the hits from the track.
+        List hits = trh.hits();
+
+        // Delete the list of hits from the track.
+        while (trh.hits().size() > 0)
+            trh.dropHit();
+
+        double sumde = 0.;
+
+        // Loop over hits and fit.
+        int icount = 0;
+        for (Iterator ihit = hits.iterator(); ihit.hasNext();) {
+            Surface s_save = trh.newTrack().surface().newPureSurface();
+            ETrack e_save = trh.newTrack();
+
+            // Extract the next hit pointer.
+            Hit hit = (Hit) ihit.next();
+
+            int from = (new SurfaceCode(s_save)).getCode();
+            int to = (new SurfaceCode(hit.surface())).getCode();
+
+            // Propagate to the next surface.
+            PropStat pstat = trh.propagate(_pprop, hit.surface(), dir);
+            if (!pstat.success()) {
+                if (AddFitKalmanDebugLevel > 0) {
+                    System.out.println("Error:        "
+                            //                            + RKDebug.Instance().getTrack() + " "
+                            //                            + RKDebug.Instance().getPropDir() + " "
+                            + icount);
+                    System.out.println("From surface 5: " + s_save);
+                    System.out.println("To surface 5:   " + hit.surface());
+                    System.out.println("Params: " + e_save.vector());
+                }
+//		aida.histogram1D("/Bugs/Fit/Failed Fwd prop from Surface",5,0,5).fill( from );
+//		aida.histogram1D("/Bugs/Fit/Failed Fwd prop to Surface",5,0,5).fill( to  );
+//		aida.cloud2D("/Bugs/Fit/Failed Fwd prop to vs from Surface").fill( from, to  );
+                if (_DEBUG)
+                    System.out.println("pstat not success :(");
+                return icount + 1;
+            }
+//
+            if (icount != 0) {
+                int istat = interact(trh, hit, dir);
+            }
+
+
+            // Add the hit.
+            int fstat = _addfit.addHit(trh, hit);
+            if (_DEBUG)
+                System.out.println("Hit added!");
+            if (fstat > 0) {
+                if (AddFitKalmanDebugLevel > 0) {
+
+//                    System.out.println("Error:        "
+//                            + RKDebug.Instance().getTrack() + " "
+//                            + RKDebug.Instance().getPropDir() + " ");
+                    System.out.println("From surface 4: " + s_save);
+                    System.out.println("To surface 4:   " + hit.surface());
+                }
+//		aida.histogram1D("/Bugs/Fit/Failed Fwd addhit from Surface",5,5,5).fill( from );
+//		aida.histogram1D("/Bugs/Fit/Failed Fwd addhit to Surface",5,0,5).fill( to  );
+//		aida.cloud2D("/Bugs/Fit/Failed Fwd addhit to vs from Surface").fill( from, to  );
+//
+            }
+            /*
+            if (fstat > 0)
+            return 10000 + 1000 * fstat + icount;
+
+            VTUtil before = new VTUtil(trh.newTrack());
+            int istat = interact(trh, hit, dir);
+            VTUtil after = new VTUtil(trh.newTrack());
+
+            double de = before.e() - after.e();
+            sumde += de;
+
+            SurfCylinder ss = (SurfCylinder) trh.newTrack().surface();
+            if (_DEBUG)System.out.printf("Forw dedx: %10.4f %12.8f  %12.8f\n", ss.radius(), de, sumde);
+             */
+
+            // Multiple scattering--this is a silly way to do it..
+            ThinXYPlaneMs interactor = new ThinXYPlaneMs(.02);
+
+            if (_DEBUG)
+                System.out.println("trh error pre MS:  " + trh.newTrack().error().toString());
+//            ThinXYPlaneMs interactor = new ThinXYPlaneMs(.005);
+            ETrack tre2 = trh.newTrack();
+            interactor.interact(tre2);
+            trh.setFit(tre2, trh.chisquared());
+            if (_DEBUG)
+                System.out.println("trh error pre MS:  " + trh.newTrack().error().toString());
+            if (fstat > 0)
+                return 10000 + 1000 * fstat + icount;
+
+
+            ++icount;
+        }
+
+
+        //System.out.println ("Forward fit sumde: " + sumde );
+//	aida.cloud1D("Forward dedx check:").fill(sumde-RKDebug.Instance().getDeGen());
+        if (_DEBUG)
+            System.out.println("Completed forward fit");
+        return 0;
+
+    }
+
+    public int fitBackward(HTrack trh) {
+        PropDir dir = PropDir.BACKWARD;
+//	RKDebug.Instance().setPropDir(dir);
+
+        //RKPrintSymMatrix psm = new RKPrintSymMatrix();
+
+        // Copy the hits from the track.
+        List hits = trh.hits();
+
+        // Delete the list of hits from the track.
+        while (trh.hits().size() > 0)
+            trh.dropHit();
+
+        double chold = 0.;
+
+        double sumde = 0.;
+
+//	RKZot zot = new RKZot(trh);
+        boolean zottable = true;
+
+        int nc = 0;
+        int nz = 0;
+        int nu = 0;
+        String thishit;
+
+
+        ListIterator bkglist = hits.listIterator(hits.size());
+        // Loop over hits and fit.
+        int icount = 0;
+        _DEBUG = false;
+        while (bkglist.hasPrevious()) {
+            Hit hit = (Hit) bkglist.previous();
+
+            if (_DEBUG) {
+                System.out.println("*******   Fit Backward:  ADDING NEW HIT    *********** ");
+                System.out.println("Fit Backward: Hit " + icount + " is: \n");
+                System.out.println("Fit Backward: Before prop: " + trh.newTrack());
+                System.out.println("Fit Backward: Propogating to surface : " + hit.surface());
+            }
+            //            System.out.println("Before prop spacepoint: " + hit.surface().spacePoint(trh.newTrack().vector()));
+            dir = PropDir.BACKWARD;
+            if (icount == 0)
+                dir = PropDir.FORWARD;//if it's the first hit, propagate forward.
+            // propagate to the surface
+            PropStat pstat = trh.propagate(_pprop, hit.surface(), dir);
+
+            if (_DEBUG) {
+                System.out.println("Fit Backward: pstat = " + pstat);
+                System.out.println("Fit Backward: After prop: " + trh.newTrack());
+            }
+
+            if (!pstat.success()) {
+                if (_DEBUG) {
+                    System.out.println("*****************************************************************************");
+                    System.out.println("FullFitKalman::fitBackward     pstat =" + pstat.toString() + " for hit# " + icount);
+                    System.out.println("FullFitKalman::fitBackward     hit   = " + hit.toString());
+                    System.out.println("FullFitKalman::fitBackward     track   = " + trh.toString());
+                    System.out.println("FullFitKalman::fitBackward     propagator   = " + _pprop.toString());
+                }
+                return -666;
+            }
+//            System.out.println("trh= \n"+trh+", hit= \n"+hit);
+//            System.out.println("_addfit= "+_addfit);
+//            System.out.println("After prop spacepoint: " + hit.cluster().surface().spacePoint(trh.newTrack().vector()));
+//            System.out.println("trh surface: " + trh.newTrack().surface().toString());
+//            System.out.println("hit surface" + hit.surface().toString());
+
+//             fit track
+            if (_DEBUG)
+                System.out.println("Fit Backward: Predicted Hit Vector before addHit: " + hit.predictedVector());
+            int fstat = _addfit.addHit(trh, hit);
+            if (icount > 2 && trh.chisquared() < 0.1)
+                _DEBUG = true;
+            if (_DEBUG)
+                System.out.println("Fit Backward: Predicted Hit Vector after addHit: " + hit.predictedVector());
+//
+            if (_DEBUG) {
+                System.out.println("Fit Backward: Measured Hit Vector after addHit: " + hit.cluster());
+                System.out.println("Fit Backward: After addhit: " + fstat + " chi^2 = "
+                        + trh.chisquared() + "\n" + trh.newTrack());
+//            System.out.println("After addhit spacepoint: " + hit.cluster().surface().spacePoint(trh.newTrack().vector()));
+//
+            }
+
+            // Multiple scattering--this is a silly way to do it..
+            if (isEven(icount)) {
+                ThinXYPlaneMs interactor = new ThinXYPlaneMs(0.01);
+
+
+                if (_DEBUG)
+                    System.out.println("Fit Backward: trh error pre MS:  " + trh.newTrack().error().toString());
+                ETrack tre2 = trh.newTrack();
+                interactor.interact(tre2);
+                trh.setFit(tre2, trh.chisquared());
+                if (_DEBUG)
+                    System.out.println("Fit Backward: trh error post MS:  " + trh.newTrack().error().toString());
+                if (fstat > 0) {
+                    System.out.println("FullFitKalman::fitBackward     fstat= = " + fstat);
+                    return 10000 + 1000 * fstat + icount;
+                }
+            }
+            icount++;
+        }
+
+        return 0;
+    }///    }
+
+    private int interact(HTrack trh, Hit hit, PropDir dir) {
+
+        if (hit.surface().pureType().equals(SurfCylinder.staticType())) {
+
+            SurfCylinder s = (SurfCylinder) hit.surface();
+            double r = s.radius();
+            if (doMs) {
+                TrackError eold = trh.newTrack().error();
+
+//		aida.histogram1D("/Bugs/Fit/Fit scat radius:",300,0.,150.).fill(r);
+
+                double l_over_radl = 0.;
+                if (r < 1.3) {
+                    l_over_radl = 0.006136;
+                } else if (r < 10.) {
+                    l_over_radl = 0.000916;
+                } else {
+                    l_over_radl = 0.013747;
+                }
+
+                ThinCylMs scat = new ThinCylMs(l_over_radl * RKDebug.Instance().getMsFac());
+                ETrack et = trh.newTrack();
+                ETrack ets = new ETrack(et);
+                double chnew = trh.chisquared();
+
+                scat.interact(et);
+                hit.update(et);
+                trh.setFit(et, chnew);
+
+
+                for (int i = 0; i < 5; ++i) {
+                    double ex1 = et.error().get(i, i);
+                    double ex2 = ets.error().get(i, i);
+                    double sigsq = ex1 - ex2;
+                    double pull = -9.;
+                    double sig = -1.;
+                    if (sigsq > 0.) {
+                        sig = Math.sqrt(sigsq);
+                        pull = (et.vector(i) - ets.vector(i)) / sig;
+                    }
+//		  aida.cloud1D("/Bugs/Fit/Forward Fit Delta param:"+i).fill(et.vector(i)-ets.vector(i));
+//		  if ( sig > 0. ) aida.cloud1D("/Bugs/Fit/Forward Fit Delta error:"+i).fill(sig);
+                }
+//		  System.out.println( "Error after: " + trh.newTrack().error().minus(eold) );
+//		  */
+            } // end if MS enabled
+//
+//
+        } // end CYlinder MS
+//
+        if (hit.surface().pureType().equals(SurfZPlane.staticType())) {
+
+            SurfZPlane s = (SurfZPlane) hit.surface();
+            double z = s.z();
+            if (doMs) {
+                TrackError eold = trh.newTrack().error();
+
+////		aida.histogram1D("/Bugs/Fit/Fit scat z forward:",300,-150,150.).fill(z);
+
+                double l_over_radl = (Math.abs(z) < 25) ? 0.000916 : 0.013747;
+                ThinZPlaneMs scat = new ThinZPlaneMs(l_over_radl * RKDebug.Instance().getMsFac());
+                ETrack et = trh.newTrack();
+                ETrack ets = new ETrack(et);
+                double chnew = trh.chisquared();
+
+                scat.interact(et);
+                hit.update(et);
+                trh.setFit(et, chnew);
+
+            } // end if MS enabled.
+
+        } // end ZPlane MS
+
+//    if ( hit.surface().pureType().equals(SurfXYPlane.staticType()) ){
+//
+//	    SurfXYPlane s = (SurfXYPlane) hit.surface();
+//	    double z = s.z();
+//	    if ( doMs ){
+//		TrackError eold = trh.newTrack().error();
+//
+//////		aida.histogram1D("/Bugs/Fit/Fit scat z forward:",300,-150,150.).fill(z);
+//
+//		double l_over_radl = ( Math.abs(z)< 25) ? 0.000916 : 0.013747;
+//		ThinZPlaneMs scat = new ThinZPlaneMs(l_over_radl*RKDebug.Instance().getMsFac());
+//		ETrack et = trh.newTrack();
+//				ETrack ets = new ETrack(et);
+//		double chnew = trh.chisquared();
+//
+//		scat.interact(et);
+//		hit.update(et);
+//		trh.setFit(et,chnew);
+//
+//	    } // end if MS enabled.
+//
+//	} // end ZPlane MS
+
+        // Successful return;
+        return 0;
+    }
+
+    // There is no hit at this site so we only need to do the interaction, not update hits.
+    private int interactonly(HTrack trh, double r, double l_over_radl) {
+
+        ThinCylMs scat = new ThinCylMs(l_over_radl * RKDebug.Instance().getMsFac());
+        ETrack et = trh.newTrack();
+        double chnew = trh.chisquared();
+
+        scat.interact(et);
+        trh.setFit(et, chnew);
+
+        // Successful return;
+        return 0;
+    }
+
+//    /**
+//     *output stream
+//     *
+//     * @return The String representation of this instance.
+//     */
+    public String toString() {
+        return getClass().getName();
+    }
+
+    private boolean isEven(int num) {
+        return num % 2 == 0;
+    }
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman
HelixParamCalculator.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/HelixParamCalculator.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/HelixParamCalculator.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,206 @@
+/*
+ * HelixParameterCalculator.java
+ *
+ * Created on July 7th, 2008, 11:09 AM
+ *
+ * 
+ */
+package org.hps.recon.tracking.kalman;
+
+import hep.physics.vec.BasicHep3Vector;
+
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.MCParticle;
+
+/**
+ * Class used for calculating MC particle track paramters
+ * @author Pelham Keahey
+ * 
+ */
+public class HelixParamCalculator  {
+
+    MCParticle mcp;
+    private double R,BField,theta,arclength;
+    //Some varibles are usesd in other calculations, thus they are global
+    /*
+    xc, yc --coordinates
+    mcdca -- MC distance of closest approach 
+    mcphi0 --azimuthal angle
+    tanL -- Slope SZ plane ds/dz
+    x0,y0 are the position of the particle at the dca
+    */
+    private double xc,yc,mcdca,mcphi0,tanL;
+    private double x0,y0;
+    /**
+     * Constructor that is fed a magnetic field and MCPARTICLE
+     * @param mcpc
+     * @param cBField
+     */
+    public HelixParamCalculator(MCParticle mcpc,double cBField)
+    {
+        //mc and event global varibles used for calculation
+        mcp=mcpc;
+        
+        //Returns the MagneticField at point (0,0,0), assumes constant magfield
+        BField = cBField;
+        
+        //Calculate theta, the of the helix projected into an SZ plane, from the z axis
+        double px = mcp.getPX();
+        double py = mcp.getPY();
+        double pz = mcp.getPZ();
+        double pt = Math.sqrt(px*px + py*py);
+        double p = Math.sqrt(pt*pt + pz*pz);
+        double cth = pz / p;
+        theta = Math.acos(cth);
+       
+        //Calculate Radius of the Helix
+        R = ((mcp.getCharge())*(mcp.getMomentum().magnitude()*Math.sin(theta))/(.0003*BField));
+        
+        //Slope in the Dz/Ds sense, tanL Calculation
+        tanL = mcp.getPZ()/(Math.sqrt(mcp.getPX()*mcp.getPX()+mcp.getPY()*mcp.getPY()));
+       
+        //Distance of closest approach Calculation
+        xc   = mcp.getOriginX() + R * Math.sin(Math.atan2(mcp.getPY(),mcp.getPX()));
+        yc   = mcp.getOriginY() - R * Math.cos(Math.atan2(mcp.getPY(),mcp.getPX()));
+        double xcyc = Math.sqrt(xc*xc + yc*yc);
+            if(mcp.getCharge()>0)
+            {
+            mcdca = R - xcyc;
+            }
+            else
+            {
+            mcdca = R + xcyc;      
+            }
+        
+        
+        //azimuthal calculation of the momentum at the DCA, phi0, Calculation
+        mcphi0 = Math.atan2(xc/(R-mcdca), -yc/(R-mcdca));
+            if(mcphi0<0)
+            {
+                mcphi0 += 2*Math.PI;
+            }
+        //z0 Calculation, z position of the particle at dca
+        x0 = -mcdca*Math.sin(mcphi0);
+        y0 = mcdca*Math.sin(mcphi0);
+        arclength  = (((mcp.getOriginX()-x0)*Math.cos(mcphi0))+((mcp.getOriginY()-y0)*Math.sin(mcphi0)));
+    
+    }
+    /**
+     * Calculates the B-Field from event
+     * @param mcpc
+     * @param eventc
+     */
+    public HelixParamCalculator(MCParticle mcpc,EventHeader eventc)
+    {
+        this(mcpc,eventc.getDetector().getFieldMap().getField(new BasicHep3Vector(0.,0.,0.)).z());
+    }
+    /**
+     * Return the magneticfield at point 0,0,0
+     * @return double BField
+     */
+    public double getMagField()
+    {
+        return BField;
+    }
+    /**
+     * Return the radius of the Helix track
+     * @return double R
+     */
+    public double getRadius()
+    {
+        return R;
+    }
+    /**
+     * Return the theta angle for the projection of the helix in the SZ plane 
+     * from the  z axis
+     * @return double theta
+     */
+    public double getTheta()
+    {
+        return theta;
+    }
+    /**
+     * Return the particle's momentum
+     * @return double mcp momentum
+     */
+    public double getMCMomentum()
+    {
+        return mcp.getMomentum().magnitude();
+    }
+    /**
+     * Return the curvature (omega)
+     * @return double omega
+     */
+    public double getMCOmega()
+    {     
+        return mcp.getCharge()/((mcp.getMomentum().magnitude()*Math.sin(theta))/(.0003*BField));
+    }
+    /**
+     * Return the transvers momentum of the MC particle, Pt
+     * @return double Pt
+     */
+    public double getMCTransverseMomentum()
+    {
+        return (mcp.getMomentum().magnitude())*Math.sin(theta);
+    }
+    /**
+     * Return the slope of the helix in the SZ plane, tan(lambda)
+     * @return double tanL
+     */
+    public double getSlopeSZPlane()
+    {
+        return tanL;
+    }
+    /**
+     * Return the distance of closest approach
+     * @return double mcdca
+     */
+    public double getDCA()
+    {
+      return mcdca;
+    }
+    /**
+     * Return the azimuthal angle of the momentum when at the position of closest approach
+     * @return double mcphi0
+     */
+    public double getPhi0()
+    {
+      return mcphi0;
+    }
+    /**
+     * Return the z position at the distance of closest approach
+     * @return double z0 position
+     */
+    public double getZ0()
+    {
+        double x0 = -mcdca*Math.sin(mcphi0);
+        double y0 = mcdca*Math.sin(mcphi0);
+        double s  = (((mcp.getOriginX()-x0)*Math.cos(mcphi0))+((mcp.getOriginY()-y0)*Math.sin(mcphi0)));
+        return mcp.getOriginZ()-(s*tanL);
+    }
+    /**
+     * Return the arclength of the helix from the ORIGIN TO THE DCA
+     * @return double arclength
+     */
+    public double getArcLength()
+    {
+        return arclength;
+    }
+    /**
+     * Return the x position of the particle when at the dca
+     * @return double arclength
+     */
+    public double getX0()
+    {
+        return x0;
+    }
+    /**
+     * Return the y position of the particle at the dca
+     * @return double arclength
+     */
+    public double getY0()
+    {
+        return y0;
+    }
+    
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman
KalmanFilterDriver.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/KalmanFilterDriver.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/KalmanFilterDriver.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,133 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.hps.recon.tracking.kalman;
+
+import java.util.List;
+
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.Track;
+import org.lcsim.event.TrackerHit;
+import org.lcsim.fit.helicaltrack.HelicalTrackFit;
+import org.lcsim.geometry.Detector;
+import org.lcsim.recon.tracking.trfbase.ETrack;
+import org.lcsim.recon.tracking.trfbase.Propagator;
+import org.lcsim.recon.tracking.trfbase.TrackError;
+import org.lcsim.recon.tracking.trfbase.VTrack;
+import org.lcsim.recon.tracking.trffit.HTrack;
+import org.lcsim.util.Driver;
+
+/**
+ *
+ * @author ecfine ([log in to unmask])
+ */
+
+
+/* Takes Matched Tracks from the Track Reconstruction Driver, and makes TRF
+ * HTracks. Adds hits from the original tracks to the new HTrack, and runs a
+ * Kalman filter over the HTrack.
+ *
+ * This only does a forward fit, and multiple scattering is only included at
+ * interacting planes, and just by assuming that each plane is .01 radiation
+ * lengths. Energy loss is not accounted for. Additionally, the method for
+ * constructing hits assumes that every hit occurs at an XY plane, while ideally,
+ * there would be a method which checks the lcsim detector geometry and then
+ * decides what kind of surface to model the shape as. There may be some methods
+ * in the ShapeHelper interface (particularly in TrdHelper) that would be useful
+ * for this, but nothing completed. Additionally, to run realistic multiple
+ * scattering with non-interacting detector elements, there would need to be a
+ * way to find the intercepts between a specific track and the detector elements.
+ *
+ * Also, magnetic field is just set at 1.0 in each class. It should be taken from
+ * the detector geometry. */
+
+public class KalmanFilterDriver extends Driver{
+    ShapeDispatcher shapeDis = new ShapeDispatcher();
+    TrackUtils trackUtils = new TrackUtils();
+    Propagator prop = null;
+    FullFitKalman fitk = null;
+    KalmanGeom geom = null;
+    Detector detector = null;
+    HTrack ht = null;
+    double bz = 0.5;
+
+
+    
+    public void detectorChanged(Detector det){
+        detector = det;
+        geom = new KalmanGeom(detector); // new geometry containing detector info
+        prop = geom.newPropagator();
+        System.out.println("geom field = " + geom.bz + ", trackUtils field = " + trackUtils.bz);
+//        trackUtils.setBZ(geom.bz);
+        fitk = new FullFitKalman(prop);
+//     
+    }
+
+    
+    public void process(EventHeader event){
+        /* Get the tracklist for each event, and then for each track
+         * get the starting track parameters and covariance matrix for an
+         * outward fit from the seedtracker. */
+         if (event.hasItem("MatchedTracks")) {
+            List<Track> trklist = (List<Track>) event.get("MatchedTracks");
+            System.out.println("number of tracks: " + trklist.size());
+            for (int i = 0; i < trklist.size(); i++) {
+                /* Start with a HelicalTrackFit, turn it into a VTrack,
+                 * turn that into an ETrack, and turn that into an HTrack.
+                 * Then add detector hits from the original track. */
+                if(trklist.get(i).getTrackerHits().size()<4) {
+                    System.out.println("Continue, this track has only " + trklist.get(i).getTrackerHits().size());
+                    continue;
+                }
+                System.out.println("Making tracks...");
+                Track track = trklist.get(i);
+                HelicalTrackFit helicalTrack = shapeDis.trackToHelix(track);
+                VTrack vt = trackUtils.makeVTrack(helicalTrack);
+                TrackError initialError = trackUtils.getInitalError(helicalTrack);
+                ETrack et = new ETrack (vt, initialError);
+                ht = new HTrack(et);
+
+                /* Add hits from original track */
+                for (int k = 0; k < track.getTrackerHits().size(); k++) {
+                    TrackerHit thit = track.getTrackerHits().get(k);
+                    System.out.println("Adding hit...");
+                    //ht = geom.addTrackerHit(thit, ht, helicalTrack, vt);
+                    // phansson
+                    // removing unused arguments to avoid confusion (see function for details)
+                    ht = geom.addTrackerHit(thit, ht); 
+                }
+
+
+                
+                /* Once we have an HTrack with the ordered list of hits, we pass
+                 * this to the Kalman fitter. */
+                System.out.println("Running Kalman fit...");
+                int fstarf = fitk.fit(ht);
+//                 System.out.println("geom field = " + geom.bz + ", trackUtils field = " + trackUtils.bz);
+//                List<RawTrackerHit> rawHits = event.get(RawTrackerHit.class, "RawTrackerHitMaker_RawTrackerHits");
+//                System.out.println("SimTrackerHits info: ");
+//                for(int j = 0; j < rawHits.size(); j++){
+//                    List<SimTrackerHit> simHits = rawHits.get(j).getSimTrackerHits();
+//                    for(int l = 0; l < simHits.size(); l++){
+//                        System.out.println("point = [" + simHits.get(l).getPoint()[0]
+//                                + ", " + simHits.get(l).getPoint()[1] +
+//                                ", " + simHits.get(l).getPoint()[2] +
+//                                "], momentum = [" + simHits.get(l).getMomentum()[0]
+//                            + ", " + simHits.get(l).getMomentum()[1]
+//                            +", " + simHits.get(l).getMomentum()[2] + "]");
+//                    }
+//                }
+            }
+
+
+        }
+//        } else {
+//            System.out.println("No tracks!");
+//        }
+
+    }
+
+
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman
KalmanGeom.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/KalmanGeom.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/KalmanGeom.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,743 @@
+package org.hps.recon.tracking.kalman;
+
+import hep.physics.vec.BasicHep3Matrix;
+import hep.physics.vec.Hep3Matrix;
+import hep.physics.vec.Hep3Vector;
+import hep.physics.vec.VecOp;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.hps.recon.tracking.HPSTransformations;
+import org.hps.recon.tracking.kalman.util.PropDCAZ;
+import org.lcsim.detector.IDetectorElement;
+import org.lcsim.detector.ILogicalVolume;
+import org.lcsim.detector.IPhysicalVolume;
+import org.lcsim.detector.ITransform3D;
+import org.lcsim.detector.solids.ISolid;
+import org.lcsim.detector.solids.Point3D;
+import org.lcsim.detector.tracker.silicon.ChargeCarrier;
+import org.lcsim.detector.tracker.silicon.SiSensor;
+import org.lcsim.detector.tracker.silicon.SiSensorElectrodes;
+import org.lcsim.event.RawTrackerHit;
+import org.lcsim.event.TrackerHit;
+import org.lcsim.fit.helicaltrack.HelicalTrackCross;
+import org.lcsim.fit.helicaltrack.HelicalTrackFit;
+import org.lcsim.fit.helicaltrack.HelicalTrackStrip;
+import org.lcsim.geometry.Detector;
+import org.lcsim.recon.tracking.trfbase.ETrack;
+import org.lcsim.recon.tracking.trfbase.Hit;
+import org.lcsim.recon.tracking.trfbase.PropDispatch;
+import org.lcsim.recon.tracking.trfbase.Propagator;
+import org.lcsim.recon.tracking.trfbase.VTrack;
+import org.lcsim.recon.tracking.trfcyl.PropCyl;
+import org.lcsim.recon.tracking.trfcyl.SurfCylinder;
+import org.lcsim.recon.tracking.trfcylplane.PropCylZ;
+import org.lcsim.recon.tracking.trfcylplane.PropZCyl;
+import org.lcsim.recon.tracking.trfdca.PropCylDCA;
+import org.lcsim.recon.tracking.trfdca.PropDCACyl;
+import org.lcsim.recon.tracking.trfdca.SurfDCA;
+import org.lcsim.recon.tracking.trffit.HTrack;
+import org.lcsim.recon.tracking.trfxyp.ClusXYPlane1;
+import org.lcsim.recon.tracking.trfxyp.PropXYXY;
+import org.lcsim.recon.tracking.trfxyp.SurfXYPlane;
+import org.lcsim.recon.tracking.trfzp.PropZZ;
+import org.lcsim.recon.tracking.trfzp.SurfZPlane;
+
+/**
+ *
+ * Extract needed information from the geometry system and serve it
+ * to the callers in a convenient form.
+ *
+ *
+ *@author $Author: phansson $
+ *@version $Id: KalmanGeom.java,v 1.6 2013/10/15 00:33:54 phansson Exp $
+ *
+ * Date $Date: 2013/10/15 00:33:54 $
+ *
+ */
+/* To make the Kalman filter work for any detector, the type of hit that is
+ * added to the HTrack has to be determined based on the lcsim detector
+ * geometry. Additionally, this class has to be able to find the intersections
+ * between a track and the detector elements to be able to implement more
+ * realistic multiple scattering. Currently this class does not support
+ * any of this functionality, and just adds hits. However there are methods for
+ * looping through detector elements, etc. that may be useful for finding
+ * intersections at some point. (ecfine) */
+public class KalmanGeom {
+
+    // TRF wants distances in cm, not mm.
+    private double mmTocm = 0.1;
+    // this flag is a temporary fix to avoid making a surface behind the origin in x.
+    private double flag = 0;
+//    //    private Array radius = null;
+//    private Subdetector sd_tbar  = null;
+//    private Subdetector sd_vbar  = null;
+//    private Subdetector sd_tec   = null;
+//    private Subdetector sd_vec   = null;
+//    private Subdetector sd_tfor  = null;
+//    private Subdetector sd_bpipe = null;
+//
+//    private IDetectorElement de_tbar  = null;
+//    private IDetectorElement de_vbar  = null;
+//    private IDetectorElement de_tec   = null;
+//    private IDetectorElement de_vec   = null;
+//    private IDetectorElement de_tfor  = null;
+    // Nominal magnetic field.
+    public double bz = 0.5;
+    // Lists of interesting surfaces.
+    public List<KalmanSurface> Surf = new ArrayList<KalmanSurface>();
+    KalmanSurface surf = null;
+    // Specific surface type A to surface type B propagators.
+    private PropCyl propcyl = null;
+    private PropZZ propzz = null;
+    private PropDCACyl propdcacyl = null;
+    private PropCylDCA propcyldca = null;
+    private PropZCyl propzcyl = null;
+    private PropCylZ propcylz = null;
+    private PropXYXY propxyxy = null;
+    private PropDCAZ propdcaz = null;
+    private PropDCAXY propdcaxy = null;
+    private PropXYDCA propxydca = null;
+//    private PropZDCA propzdca     = null;
+    // The master propagator that can go between any pair of surfaces.
+    private PropDispatch pDispatch = null;
+    // The run time configuration system.
+    //ToyConfig config;
+    // Information from the run time configuration system.
+//    double  respixel;
+//    double  resstrip;
+//    boolean trackerbarrel2d;         
+//    double  zres2dTrackerBarrel;
+//    boolean vtxFwdEquivStrips;
+    // Does this detector have forward tracking.
+    boolean hasforward = false;
+    // Stuff for adding surfaces
+    static ArrayList physicalVolumes = new ArrayList();
+    ILogicalVolume logical;
+    ShapeDispatcher shapeDispatcher = new ShapeDispatcher();
+    Detector detector = null;
+
+    public KalmanGeom(Detector det) {
+        detector = det;
+        System.out.println("New detector: " + detector.getName());
+        logical = detector.getTrackingVolume().getLogicalVolume();
+
+        
+        // Extract information from the run time configuration system.
+        //	try{
+        //	    ToyConfig config = ToyConfig.getInstance();
+        //	    respixel            = config.getDouble("respixel");
+        //	    resstrip            = config.getDouble("resstrip");
+        //	    trackerbarrel2d     = config.getBoolean("trackerbarrel2d");
+        //	    zres2dTrackerBarrel = config.getDouble("zres2dTrackerBarrel");
+        //	    vtxFwdEquivStrips   = config.getBoolean("vtxFwdEquivStrips");
+        //
+        //	} catch (ToyConfigException e){
+        //            System.out.println (e.getMessage() );
+        //            System.out.println ("Stopping now." );
+        //            System.exit(-1);
+        //        }
+
+
+
+        //	Map<String, Subdetector> subDetMap = detector.getSubdetectors();
+        //
+        //	Subdetector sd_tbar = subDetMap.get("TrackerBarrel");
+        //	Subdetector sd_vbar = subDetMap.get("VertexBarrel");
+        //	Subdetector sd_tec  = subDetMap.get("TrackerEndcap");
+        //	Subdetector sd_vec  = subDetMap.get("VertexEndcap");
+        //	Subdetector sd_tfor = subDetMap.get("TrackerForward");
+        //	Subdetector sd_bpipe  = subDetMap.get("BeamPipe");
+        //	System.out.println ("Checking .... " + sd_tbar + " | " + sd_tfor);
+        // Don't use subdetectors anymore...
+
+        //	 Check for forward tracking system.
+        //	if ( sd_tfor == null ) {
+        //	    System.out.println ("Checking 1 .... " );
+        //	    if ( detector.getName().compareTo("sid00") != 0 ){
+        //		System.out.println("Expected to find a TrackerForward Subdetector but did not!");
+        //		System.exit(-1);
+        //	    }
+        //	}else{
+        //	    System.out.println ("Checking 2  .... " );
+        //
+        //	    hasforward = true;
+        //	}           // I may want to implement something like this at some point but not now.
+
+        //	if ( hasforward ){
+        //	    de_tfor = sd_tfor.getDetectorElement();
+        //	}
+
+        /* Cycle through detector and add all surfaces to the surface list. */
+        //    addAllSurfaces();
+
+        System.out.println("Number of surfaces: " + Surf.size());
+        for (KalmanSurface surf : Surf) {
+            surf.Print();
+        }
+
+
+        double[] origin = {0., 0., 0.};
+
+//    	Map<String,Field> fields = detector.getFields();
+//    	Set<String> keys = fields.keySet();
+//    	for ( String key : keys ){
+//    	    Field field = fields.get(key);
+//    	    String classname = field.getClass().getName();
+//    	    String shortname = classname.replaceAll( "org.lcsim.geometry.field.", "");
+//    	    if ( shortname.compareTo("Solenoid") != 0 ){
+//    		System.out.println("Expected, but did not find, a solenoid: " + shortname );
+////    		System.exit(-1);
+//    	    }
+//    	    Solenoid s = (Solenoid)field;
+//    	    bz = s.getInnerField()[2];
+//    	    if ( bz == 0. ){
+//    		System.out.println("This code will not work with a magnetic field of 0: " + shortname );
+////    		System.exit(-1);
+//    	    }
+//    	    break;
+//    	}
+
+        // Instantiate surface-pair specific propagators.
+        propcyl = new PropCyl(bz);
+        propzz = new PropZZ(bz);
+        propdcacyl = new PropDCACyl(bz);
+        propcyldca = new PropCylDCA(bz);
+        propzcyl = new PropZCyl(bz);
+        propcylz = new PropCylZ(bz);
+        propxyxy = new PropXYXY(bz);
+        propdcaxy = new PropDCAXY(bz);
+        propxydca = new PropXYDCA(bz);
+        //	propdcaz   = new PropDCAZ(bz);
+        //	propzdca   = new PropZDCA(bz);
+        // Again, need xy plane propagators!
+
+        // Instantiate and configure the general purpose propagator.
+        pDispatch = new PropDispatch();
+        pDispatch.addPropagator(SurfZPlane.staticType(), SurfZPlane.staticType(), propzz);
+        pDispatch.addPropagator(SurfCylinder.staticType(), SurfCylinder.staticType(), propcyl);
+        pDispatch.addPropagator(SurfDCA.staticType(), SurfCylinder.staticType(), propdcacyl);
+        pDispatch.addPropagator(SurfCylinder.staticType(), SurfDCA.staticType(), propcyldca);
+        pDispatch.addPropagator(SurfZPlane.staticType(), SurfCylinder.staticType(), propzcyl);
+        pDispatch.addPropagator(SurfCylinder.staticType(), SurfZPlane.staticType(), propcylz);
+        pDispatch.addPropagator(SurfXYPlane.staticType(), SurfXYPlane.staticType(), propxyxy);
+        pDispatch.addPropagator(SurfDCA.staticType(), SurfXYPlane.staticType(), propdcaxy);
+        pDispatch.addPropagator(SurfXYPlane.staticType(), SurfDCA.staticType(), propxydca);
+        //	pDispatch.addPropagator( SurfDCA.staticType(),      SurfZPlane.staticType(),   propdcaz);
+        //	pDispatch.addPropagator( SurfZPlane.staticType(),   SurfDCA.staticType(),      propzdca);
+
+    }
+
+    public Propagator newPropagator() {
+        // Clone not supported for pDispatch.
+        //return pDispatch.newPropagator();
+        return (Propagator) pDispatch;
+    }
+
+//    public List<RKSurf> getCylinders(){
+//	return Surf;
+//    }
+//    public List<RKSurf> getZplus(){
+//	return ZSurfplus;
+//    }
+//
+//    public List<RKSurf> getZMinus(){
+//	return ZSurfminus;
+//    }   
+    public double getBz() {
+        return bz;
+    }
+
+    public void setBz(double bfield) {
+        bz = bfield;
+    }
+
+//   Return a list of z surfaces, going foward along the track.
+//    public List<RKSurf> getZ( double z0, double cz ){
+//	List<RKSurf> zlist = new ArrayList<RKSurf>();
+//	if ( cz > 0 ){
+//	    for ( Iterator ihit=ZSurfAll.iterator(); ihit.hasNext(); ){
+//		RKSurf s = (RKSurf) ihit.next();
+//		if ( s.zc >= z0 ){
+//		    zlist.add(s);
+//		}
+//	    }
+//	} else if ( cz < 0 ){
+//	    for ( ListIterator ihit=ZSurfAll.listIterator(ZSurfAll.size());
+//		  ihit.hasPrevious(); ){
+//		RKSurf s = (RKSurf) ihit.previous();
+//		if ( s.zc <= z0 ){
+//		    zlist.add(s);
+//		}
+//	    }
+//	}
+//
+//	return zlist;
+//    }  
+    // Adds all surfaces to the surface list
+    private void addAllSurfaces() {
+        addDaughterSurfaces(logical);
+    }
+
+    private void addDaughterSurfaces(ILogicalVolume logical) {
+        if (logical.getDaughters().size() == 0) {
+            // need to avoid making surface for target. for now, flag..
+            flag++;
+            if (flag > 5) {
+                surf = shapeDispatcher.getKalmanSurf(logical.getSolid());
+                Surf.add(surf);
+            }
+        }
+        for (int n = 0; n < logical.getNumberOfDaughters(); n++) {
+            IPhysicalVolume physical = logical.getDaughter(n);
+            addDaughterSurfaces(physicalToLogical(physical));
+            physicalVolumes.remove(physicalVolumes.size() - 1);
+        }
+    }
+
+    // Given a point, find the solid that contains it. Doesn't work.
+    private ISolid findSolidFromPoint(Point3D hitPoint) {
+        ISolid solid = checkDaughterSurfaces(logical, hitPoint);
+        return solid;
+    }
+
+    private ISolid checkDaughterSurfaces(ILogicalVolume logical, Point3D hitPoint) {
+        if (logical.getDaughters().size() == 0) {
+            if (pointIsOnSolid(logical.getSolid(), hitPoint)) {
+                return logical.getSolid();
+            }
+        }
+        for (int n = 0; n < logical.getNumberOfDaughters(); n++) {
+            IPhysicalVolume physical = logical.getDaughter(n);
+            checkDaughterSurfaces(physicalToLogical(physical), hitPoint);
+            physicalVolumes.remove(physicalVolumes.size() - 1);
+        }
+        System.out.print("This hit isn't on a solid!");
+        return null;
+    }
+
+    // Given a TrackerHit, return the surface the hit should be placed on. Doesn't work.
+    private KalmanSurface findTrackerHitSurface(TrackerHit thit) {
+        double[] position = thit.getPosition();
+        Point3D hitPoint = new Point3D(position[0], position[1], position[2]);
+        ISolid hitSolid = findSolidFromPoint(hitPoint);
+        KalmanSurface hitSurf = getKSurfFromSolid(hitSolid);
+        return hitSurf;
+    }
+
+    private KalmanSurface getKSurfFromSolid(ISolid hitSolid) {
+        throw new UnsupportedOperationException("Not yet implemented");
+    }
+
+    // Adds the physical volume to the physicalVolumes ArrayList.
+    private ILogicalVolume physicalToLogical(IPhysicalVolume physical) {
+        physicalVolumes.add(physical.getTransform());
+        return physical.getLogicalVolume();
+    }
+
+    // Adds intercepts between a HTrack and the detector. Doesn't work.
+    public void addIntercepts(HTrack ht, Detector detector) {
+        logical = detector.getTrackingVolume().getLogicalVolume();
+        addDaughterIntercepts(logical, ht);
+    }
+
+    private void addDaughterIntercepts(ILogicalVolume logical, HTrack ht) {
+        if (logical.getDaughters().size() == 0) {
+            ht = shapeDispatcher.addIntercept(logical.getSolid(), ht);
+        }
+        for (int n = 0; n < logical.getNumberOfDaughters(); n++) {
+            IPhysicalVolume physical = logical.getDaughter(n);
+            addDaughterIntercepts(physicalToLogical(physical), ht);
+            physicalVolumes.remove(physicalVolumes.size() - 1);
+        }
+    }
+
+    // Add a hit from an lcsim Track to a trf HTrack.
+    public HTrack addTrackerHit(TrackerHit thit, HTrack htrack, HelicalTrackFit track,
+            VTrack vtrack) {
+        /* This should check the kind of solid that got hit and model it as the
+         * correct surface based on the solid dimensions. For now it just
+         * assumes XY planes. */
+
+        double[] position = thit.getPosition();
+        if (position.length != 3) {
+            System.out.println("Position has more than 3 coordinates?!");
+        }
+
+
+//        // For checking surfaces
+//        KalmanSurface surface= findTrackerHitSurface(thit);
+//        PropStat prop = new PropStat();
+//        prop.setForward();
+//        double path = (position[2] - track.z0())/track.slope();
+//        KalmanHit khit = new KalmanHit(track, surface, vtrack, prop, path);
+//        Hit hit = khit.MakeHit();
+//        Point3D hitPoint = new Point3D(position[0], position[1], position[2]);
+//        ISolid hitSolid = findSolidFromPoint(hitPoint);
+
+        
+        //PELLE:
+        // The HelicalTrackFit track and VTrack vtrack are not used
+        
+        
+        
+        // Need an ETrack to add hits from clusters.
+        ETrack tre = htrack.newTrack();
+
+        // This also assumes the hit in question is a Helical Track Cross.
+        HelicalTrackCross htrackcross = (HelicalTrackCross) thit;
+        HelicalTrackStrip strip1 = (HelicalTrackStrip) htrackcross.getStrips().get(0);
+        HelicalTrackStrip strip2 = (HelicalTrackStrip) htrackcross.getStrips().get(1);
+
+        double dist1 = dotProduct(strip1.origin(), strip1.w());
+        double dist2 = dotProduct(strip2.origin(), strip2.w());
+
+
+        double phi1 = Math.atan2(strip1.w().y() * dist1 * strip1.origin().y(), strip1.w().x() * dist1 * strip1.origin().x());
+        double phi2 = Math.atan2(strip2.w().y() * dist2 * strip2.origin().y(), strip2.w().x() * dist2 * strip2.origin().x());
+        // phi needs to be between 0 and 2PI. Additionally, it seemed like
+        // rounding errors caused problems for very small negative values of phi,
+        // so these are approximated as 0.
+        if (phi1 < 0) {
+            if (phi1 > -0.00000001) {
+                phi1 = 0;
+            } else {
+                phi1 = phi1 + 2 * Math.PI;
+            }
+        }
+        if (phi2 < 0) {
+            if (phi2 > -0.00000001) {
+                phi2 = 0;
+            } else {
+                phi2 = phi2 + 2 * Math.PI;
+            }
+        }
+
+        System.out.println("Origin of strip1: " + strip1.origin());
+        System.out.println("u,v,w of strip1 : " + strip1.u().toString() + "," + strip1.v().toString() + "," + strip1.w().toString());
+        System.out.println("Origin of strip2: " + strip2.origin());
+        System.out.println("u,v,w of strip2 : " + strip2.u().toString() + "," + strip2.v().toString() + "," + strip2.w().toString());
+        System.out.println("dist1: " + dist1 + ", phi1: " + phi1);
+        System.out.println("dist2: " + dist2 + ", phi2: " + phi2);
+        // ClusXYPlane needs wz, wv, avz, phi and dist to create a cluster.
+        double wz1 = strip1.u().z();
+        double wz2 = strip2.u().z();
+        double wv1 = strip1.u().x() * (-Math.sin(phi1)) + strip1.u().y() * Math.cos(phi1);
+        double wv2 = strip2.u().x() * (-Math.sin(phi2)) + strip2.u().y() * Math.cos(phi2);
+
+
+        double avz1 = strip1.umeas()
+                - (dist1 * (Math.cos(phi1) * strip1.u().x() + Math.sin(phi1) * strip1.u().y())
+                - (strip1.origin().x() * strip1.u().x() + strip1.origin().y() * strip1.u().y()
+                + strip1.origin().z() * strip1.u().z()));
+        double avz2 = strip2.umeas()
+                - (dist2 * (Math.cos(phi2) * strip2.u().x() + Math.sin(phi2) * strip2.u().y())
+                - (strip2.origin().x() * strip2.u().x() + strip2.origin().y() * strip2.u().y()
+                + strip2.origin().z() * strip2.u().z()));
+        double davz1 = strip1.du();
+        double davz2 = strip2.du();
+
+        System.out.println("avz1 = " + avz1 + " = " + strip1.umeas() + " - " + (dist1 * (Math.cos(phi1) * strip1.u().x() + Math.sin(phi1) * strip1.u().y())
+                - (strip1.origin().x() * strip1.u().x() + strip1.origin().y() * strip1.u().y()
+                + strip1.origin().z() * strip1.u().z())));
+        System.out.println("avz2 = " + avz2 + " = " + strip2.umeas() + " - " + (dist2 * (Math.cos(phi2) * strip2.u().x() + Math.sin(phi2) * strip2.u().y())
+                - (strip2.origin().x() * strip2.u().x() + strip2.origin().y() * strip2.u().y()
+                + strip2.origin().z() * strip2.u().z())));
+        
+
+
+//        // Just to check and make sure Vtrf makes sense:
+//        if((dist1*Math.cos(phi1) - strip1.origin().x())*Math.cos(phi1) ==
+//                (dist1*Math.sin(phi1) - strip1.origin().y())*Math.sin(phi1)){
+//            System.out.println("Vtrf1 coherent!");
+//        } else{
+//            System.out.println("Vtrf1 doesn't make sense :(");
+//        }
+//        if((dist2*Math.cos(phi2) - strip2.origin().x())*Math.cos(phi2) ==
+//                (dist2*Math.sin(phi2) - strip2.origin().y())*Math.sin(phi2)){
+//            System.out.println("Vtrf2 coherent!");
+//        } else{
+//            System.out.println("Vtrf2 doesn't make sense :(");
+//        }
+
+        System.out.println("wz1 = " + wz1 + ", wv1 = " + wv1 + ", avz1 = " + avz1 + ", davz1 =" + davz1);
+        System.out.println("wz2 = " + wz2 + ", wv2 = " + wv2 + ", avz2 = " + avz2 + ", davz2 =" + davz2);
+
+        // Create new clusters and get hit predictions.
+        ClusXYPlane1 cluster1 = new ClusXYPlane1(dist1, phi1, wv1, wz1, avz1, davz1);
+        ClusXYPlane1 cluster2 = new ClusXYPlane1(dist2, phi2, wv2, wz2, avz2, davz2);
+        List hits1 = cluster1.predict(tre);
+        List hits2 = cluster2.predict(tre);
+        Hit hit1 = (Hit) hits1.get(0);
+        Hit hit2 = (Hit) hits2.get(0);
+
+        System.out.println("hit1 predicted vector: " + hit1.predictedVector());
+        System.out.println("hit2 predicted vector: " + hit2.predictedVector());
+        System.out.println("hit position from trackerhit: [" + thit.getPosition()[0] + ", "
+                + thit.getPosition()[1] + ", " + thit.getPosition()[2] + "]");
+
+        hit1.setParentPointer(cluster1);
+        hit2.setParentPointer(cluster2);
+        htrack.addHit(hit1);
+        htrack.addHit(hit2);
+
+        return htrack;
+
+    }
+    
+    
+     // Add a hit from an lcsim Track to a trf HTrack.
+    public HTrack addTrackerHit(TrackerHit thit, HTrack htrack) {
+        /* This should check the kind of solid that got hit and model it as the
+         * correct surface based on the solid dimensions. For now it just
+         * assumes XY planes. */
+        
+        System.out.println("\nAdd Tracker Hit at position " + thit.getPosition()[0]  + "," + thit.getPosition()[1] + "," + thit.getPosition()[2]);
+         
+        //PELLE:
+        // The HelicalTrackFit track and VTrack vtrack are not used so was removed 
+        // to avoid confusion.
+        // They might be needed to be able to figure out what solid to 
+        // to extrapolate between if this gets implemented.
+        
+        
+
+        double[] position = thit.getPosition();
+        if (position.length != 3) {
+            System.out.println("Position has more than 3 coordinates?!");
+        }
+
+
+//        // For checking surfaces
+//        KalmanSurface surface= findTrackerHitSurface(thit);
+//        PropStat prop = new PropStat();
+//        prop.setForward();
+//        double path = (position[2] - track.z0())/track.slope();
+//        KalmanHit khit = new KalmanHit(track, surface, vtrack, prop, path);
+//        Hit hit = khit.MakeHit();
+//        Point3D hitPoint = new Point3D(position[0], position[1], position[2]);
+//        ISolid hitSolid = findSolidFromPoint(hitPoint);
+
+       
+        
+        
+        // Need an ETrack to add hits from clusters.
+        ETrack tre = htrack.newTrack();
+
+        // This also assumes the hit in question is a Helical Track Cross.
+        HelicalTrackCross htrackcross = (HelicalTrackCross) thit;
+        HelicalTrackStrip strip1 = (HelicalTrackStrip) htrackcross.getStrips().get(0);
+        HelicalTrackStrip strip2 = (HelicalTrackStrip) htrackcross.getStrips().get(1);
+
+        Hep3Vector u1 = strip1.u();
+        Hep3Vector u2 = strip2.u();
+        Hep3Vector v1 = strip1.v();
+        Hep3Vector v2 = strip2.v();
+        Hep3Vector w1 = strip1.w();
+        Hep3Vector w2 = strip2.w();
+        
+        Hep3Vector origin1 = strip1.origin();
+        Hep3Vector origin2 = strip2.origin();
+        
+        double u1meas = strip1.umeas();
+        double u2meas = strip2.umeas();
+        
+        
+        System.out.println("strip1 origin: " + origin1);
+        System.out.println("strip2 origin: " + origin2);
+        System.out.printf("strip1 u=%s\tv=%s\tw=%s\n",u1.toString(),v1.toString(),w1.toString());
+        System.out.printf("strip2 u=%s\tv=%s\tw=%s\n",u2.toString(),v2.toString(),w2.toString());
+        System.out.println("strip1 umeas: " + u1meas);
+        System.out.println("strip2 umeas: " + u2meas);
+
+        System.out.println("Rotate strip2 u,v,w into strip1 frame");
+        
+        Hep3Matrix strip2ToTrk = getStripToTrackRotation(strip2);
+        System.out.println("Strip2ToTrk matrix " + strip2ToTrk.toString());
+        System.out.println("Get the rotation matrix for going from track frame to strip1 frame");
+        Hep3Matrix trackToStrip1 = getTrackToStripRotation(strip1);        
+        Hep3Matrix strip2ToStrip1 = VecOp.mult(trackToStrip1,strip2ToTrk);
+
+        
+        u2 = VecOp.mult(strip2ToStrip1, u2);
+        v2 = VecOp.mult(strip2ToStrip1, v2);
+        w2 = VecOp.mult(strip2ToStrip1, w2);
+        
+        System.out.printf("strip2 u=%s\tv=%s\tw=%s\n",u2.toString(),v2.toString(),w2.toString());
+        
+        
+        
+        double dist1 = dotProduct(origin1, w1);
+        double dist2 = dotProduct(origin2, w2);
+
+
+        double phi1 = Math.atan2(w1.y() * dist1 * origin1.y(), w1.x() * dist1 * origin1.x());
+        double phi2 = Math.atan2(w2.y() * dist2 * origin2.y(), w2.x() * dist2 * origin2.x());
+        // phi needs to be between 0 and 2PI. Additionally, it seemed like
+        // rounding errors caused problems for very small negative values of phi,
+        // so these are approximated as 0.
+        if (phi1 < 0) {
+            if (phi1 > -0.00000001) {
+                phi1 = 0;
+            } else {
+                phi1 = phi1 + 2 * Math.PI;
+            }
+        }
+        if (phi2 < 0) {
+            if (phi2 > -0.00000001) {
+                phi2 = 0;
+            } else {
+                phi2 = phi2 + 2 * Math.PI;
+            }
+        }
+        System.out.println("dist1: " + dist1 + ", phi1: " + phi1);
+        System.out.println("dist2: " + dist2 + ", phi2: " + phi2);
+        // ClusXYPlane needs wz, wv, avz, phi and dist to create a cluster.
+        double wz1 = u1.z();
+        double wz2 = u2.z();
+        double wv1 = u1.x() * (-Math.sin(phi1)) + u1.y() * Math.cos(phi1);
+        double wv2 = u2.x() * (-Math.sin(phi2)) + u2.y() * Math.cos(phi2);
+
+
+        double avz1 = u1meas
+                - (dist1 * (Math.cos(phi1) * u1.x() + Math.sin(phi1) * u1.y())
+                - (origin1.x() * u1.x() + origin1.y() * u1.y()
+                + origin1.z() * u1.z()));
+        double avz2 = u2meas
+                - (dist2 * (Math.cos(phi2) * u2.x() + Math.sin(phi2) * u2.y())
+                - (origin2.x() * u2.x() + origin2.y() * u2.y()
+                + origin2.z() * u2.z()));
+        double davz1 = strip1.du();
+        double davz2 = strip2.du();
+
+        System.out.println("avz1 = " + avz1 + " = " + u1meas + " - " + (dist1 * (Math.cos(phi1) * u1.x() + Math.sin(phi1) * u1.y())
+                - (origin1.x() * u1.x() + origin1.y() * u1.y()
+                + origin1.z() * u1.z())));
+        System.out.println("avz2 = " + avz2 + " = " + u2meas + " - " + (dist2 * (Math.cos(phi2) * u2.x() + Math.sin(phi2) * u2.y())
+                - (origin2.x() * u2.x() + origin2.y() * u2.y()
+                + origin2.z() * u2.z())));
+        
+
+
+//        // Just to check and make sure Vtrf makes sense:
+//        if((dist1*Math.cos(phi1) - origin1.x())*Math.cos(phi1) ==
+//                (dist1*Math.sin(phi1) - origin1.y())*Math.sin(phi1)){
+//            System.out.println("Vtrf1 coherent!");
+//        } else{
+//            System.out.println("Vtrf1 doesn't make sense :(");
+//        }
+//        if((dist2*Math.cos(phi2) - origin2.x())*Math.cos(phi2) ==
+//                (dist2*Math.sin(phi2) - origin2.y())*Math.sin(phi2)){
+//            System.out.println("Vtrf2 coherent!");
+//        } else{
+//            System.out.println("Vtrf2 doesn't make sense :(");
+//        }
+
+        System.out.println("wz1 = " + wz1 + ", wv1 = " + wv1 + ", avz1 = " + avz1 + ", davz1 =" + davz1);
+        System.out.println("wz2 = " + wz2 + ", wv2 = " + wv2 + ", avz2 = " + avz2 + ", davz2 =" + davz2);
+
+        // Create new clusters and get hit predictions.
+        ClusXYPlane1 cluster1 = new ClusXYPlane1(dist1, phi1, wv1, wz1, avz1, davz1);
+        ClusXYPlane1 cluster2 = new ClusXYPlane1(dist2, phi2, wv2, wz2, avz2, davz2);
+        List hits1 = cluster1.predict(tre);
+        List hits2 = cluster2.predict(tre);
+        Hit hit1 = (Hit) hits1.get(0);
+        Hit hit2 = (Hit) hits2.get(0);
+
+        System.out.println("hit1 predicted vector: " + hit1.predictedVector());
+        System.out.println("hit2 predicted vector: " + hit2.predictedVector());
+        System.out.println("hit position from trackerhit: [" + thit.getPosition()[0] + ", "
+                + thit.getPosition()[1] + ", " + thit.getPosition()[2] + "]");
+
+        hit1.setParentPointer(cluster1);
+        hit2.setParentPointer(cluster2);
+        htrack.addHit(hit1);
+        htrack.addHit(hit2);
+
+        return htrack;
+
+    }
+    
+    
+    
+    
+
+    private boolean pointIsOnSolid(ISolid solid, Point3D hitPoint) {
+        return shapeDispatcher.pointIsOnSolid(solid, hitPoint);
+    }
+
+    private double dotProduct(Hep3Vector v1, Hep3Vector v2) {
+        double dotProduct = v1.x() * v2.x() + v1.y() * v2.y() + v1.z() * v2.z();
+        return dotProduct;
+    }
+
+
+    private Hep3Matrix getStripToTrackRotation(HelicalTrackStrip strip) {
+        //This function transforms the vec to the track coordinates that the supplied strip has
+        
+        //Transform from strip frame (u,v,w) to JLab frame (done through the RawTrackerHit)
+        ITransform3D stripToDet = GetLocalToGlobal(strip);
+        //Get rotation matrix
+        Hep3Matrix stripToDetMatrix = (BasicHep3Matrix) stripToDet.getRotation().getRotationMatrix();
+        //Transformation between JLab and tracking coordinates
+        Hep3Matrix detToTrackMatrix = (BasicHep3Matrix) HPSTransformations.getMatrix();
+        
+        if (true) {
+            System.out.println("Getting the rotation to go from strip (u,v,w) to track coordinates");
+            System.out.println("stripToDet (JLab) translation:");
+            System.out.println(stripToDet.getTranslation().toString());
+            System.out.println("stripToDet Rotation:");
+            System.out.println(stripToDet.getRotation().toString());
+            System.out.println("detToTrack Rotation:");
+            System.out.println(detToTrackMatrix.toString());
+            
+            
+        }
+
+        return (Hep3Matrix) VecOp.mult(detToTrackMatrix,stripToDetMatrix);
+    }
+
+    private ITransform3D GetLocalToGlobal(HelicalTrackStrip strip) {
+        //Transform from sensor frame (u,v,w) to tracking frame
+        RawTrackerHit rth = (RawTrackerHit) strip.rawhits().get(0);
+        IDetectorElement ide = rth.getDetectorElement();
+        SiSensor sensor = ide.findDescendants(SiSensor.class).get(0);
+        SiSensorElectrodes electrodes = sensor.getReadoutElectrodes(ChargeCarrier.HOLE);
+        return electrodes.getLocalToGlobal();
+    }
+    
+    private Hep3Matrix getTrackToStripRotation(HelicalTrackStrip strip) {
+        //This function transforms the hit to the sensor coordinates
+        
+        //Transform from JLab frame to sensor frame (done through the RawTrackerHit)
+        ITransform3D detToStrip = GetGlobalToLocal(strip);
+        //Get rotation matrix
+        Hep3Matrix detToStripMatrix = (BasicHep3Matrix) detToStrip.getRotation().getRotationMatrix();
+        //Transformation between the JLAB and tracking coordinate systems
+        Hep3Matrix detToTrackMatrix = (BasicHep3Matrix) HPSTransformations.getMatrix();
+
+        if (true) {
+            System.out.println("Getting the rotation to go from track to strip (u,v,w)");
+            System.out.println("gblToLoc translation:");
+            System.out.println(detToStrip.getTranslation().toString());
+            System.out.println("gblToLoc Rotation:");
+            System.out.println(detToStrip.getRotation().toString());
+            System.out.println("detToTrack Rotation:");
+            System.out.println(detToTrackMatrix.toString());
+        }
+
+        return (Hep3Matrix) VecOp.mult(detToStripMatrix, VecOp.inverse(detToTrackMatrix));
+    }
+
+    private ITransform3D GetGlobalToLocal(HelicalTrackStrip strip) {
+        //Transform from JLab frame (RawTrackerHit) to sensor frame (i.e. u,v,w)
+        RawTrackerHit rth = (RawTrackerHit) strip.rawhits().get(0);
+        IDetectorElement ide = rth.getDetectorElement();
+        SiSensor sensor = ide.findDescendants(SiSensor.class).get(0);
+        SiSensorElectrodes electrodes = sensor.getReadoutElectrodes(ChargeCarrier.HOLE);
+        return electrodes.getGlobalToLocal();
+    }
+
+
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman
KalmanSurface.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/KalmanSurface.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/KalmanSurface.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,431 @@
+package org.hps.recon.tracking.kalman;
+
+import hep.physics.vec.Hep3Vector;
+
+import java.util.List;
+
+import org.lcsim.detector.IDetectorElement;
+import org.lcsim.detector.IGeometryInfo;
+import org.lcsim.detector.ILogicalVolume;
+import org.lcsim.detector.material.IMaterial;
+import org.lcsim.detector.solids.ISolid;
+import org.lcsim.detector.solids.Tube;
+import org.lcsim.geometry.compact.Subdetector;
+import org.lcsim.geometry.subdetector.PolyconeSupport;
+import org.lcsim.geometry.subdetector.PolyconeSupport.ZPlane;
+import org.lcsim.material.Material;
+import org.lcsim.recon.tracking.trfbase.Surface;
+import org.lcsim.recon.tracking.trfcyl.BSurfCylinder;
+import org.lcsim.recon.tracking.trfcyl.SurfCylinder;
+import org.lcsim.recon.tracking.trfcyl.ThinCylMs;
+import org.lcsim.recon.tracking.trfcyl.ThinCylMsSim;
+import org.lcsim.recon.tracking.trfxyp.SurfXYPlane;
+import org.lcsim.recon.tracking.trfzp.SurfZPlane;
+
+/**
+ *
+ * Holds summary information about one sensitive surface.  The information
+ * is extracted from the org.lcsim geometry system.  This is a routine
+ * that needs to know that org.lcsim uses mm for distances but TRF uses cm.
+ *
+ *
+ *@author $Author: jeremy $
+ *@version $Id: KalmanSurface.java,v 1.1 2011/06/01 17:08:04 jeremy Exp $
+ *
+ * Date $Date: 2011/06/01 17:08:04 $
+ *
+ */
+
+public class KalmanSurface{
+
+    // TRF wants distances in cm, not mm.
+    private double mmTocm = 0.1;
+
+//    // Name of this Subdetector.
+//    public String name = "";
+
+    // Readout dimension:
+    // 0 = inactive
+    // 1 = strips
+    // 2 = pixels
+    public int rodim;
+
+    // References to subdetector and detector element info.
+//    public Subdetector      sd = null;
+//    public IDetectorElement de = null;
+
+    public double radius = 0.;
+    public double thick  = 0.;
+    public double zmin   = 0.;
+    public double zmax   = 0.;
+    public double zc     = 0.;
+    public double rmin   = 0.;
+    public double rmax   = 0.;
+
+    // Does a 1D measurement measure the first or second coordinate?
+    public int ixy = -1;
+    static public int ixy_Undef = -1;
+    static public int ixy_x   = 0;
+    static public int ixy_y   = 1;
+    static public int ixy_phi = 0;
+    static public int ixy_z   = 1;
+
+    private double[] resolutions;
+
+    // Different inputs have different places to find materials.
+    public Material   material = null;
+    public IMaterial imaterial = null;
+
+    // Name of the material.
+    public String matname = "Undefined";
+
+    // Radiation length of the material;
+    public double radl = 0;
+
+    // Thickness in units of radiation length.
+    public double thick_radl = 0.;
+
+    // Density.
+    public double density = 0.0;
+
+    // Tolerance for comparing floating point numbers.
+    private double tolerance = 1.e-4;
+
+    // Types
+    private int type;
+    // Types
+    static public int type_tube=0;
+    static public int type_zdisc=1;
+    static public int type_xyplane=2;
+    Surface surf = null;
+
+    KalmanSurface(String string, double distnorm, double normphi) {
+        if(string.equals("xyplane")){
+            System.out.println("dist norm = " + distnorm + ", normphi = " + normphi);
+            surf = new SurfXYPlane(distnorm, normphi);
+            type = type_xyplane;
+        } else{
+            throw new UnsupportedOperationException("Not yet implemented");
+        }
+    }
+
+    public SurfCylinder getCylinder(){
+	if ( type != type_tube ){
+//	    System.out.println("Cannot return a cylinder from a non-tube surface: " + name );
+	    System.exit(-1);
+	}
+	SurfCylinder s    = new SurfCylinder( radius*mmTocm );
+	ThinCylMs    scat = new ThinCylMs   ( thick_radl );
+	ThinCylMsSim sim  = new ThinCylMsSim( thick_radl );
+	s.setInteractor(scat);
+	s.setSimInteractor(sim);
+	return s;
+    }
+
+    public BSurfCylinder getBCylinder(){
+	if ( type != type_tube ){
+//	    System.out.println("Cannot return a bounded cylinder from a non-tube surface: " + name );
+	    System.exit(-1);
+	}
+	return new BSurfCylinder( radius*mmTocm, zmin*mmTocm, zmax*mmTocm );
+    }
+
+    public boolean inBounds ( double trfarg ){
+	if ( type == type_tube ){
+	    double z = trfarg/mmTocm;
+	    return (z>=zmin)&&(z<=zmax);
+	} else if ( type == type_zdisc ){
+	    double r = trfarg/mmTocm;
+	    return (r>=rmin)&&(r<=rmax);
+	}
+	return false;
+    }
+
+    public int getType(){
+	return type;
+    }
+
+    public String getTypeAsString(){
+	if ( type == type_tube ){
+	    return "Tube ";
+	} else if ( type == type_zdisc ){
+	    return "Zdisc";
+	}
+	return "Unknown";
+    }
+
+    public SurfZPlane getZPlane(){
+	if ( type != type_zdisc ){
+//	    System.out.println("Cannot return a ZPlane from a non-zplane surface: " + name );
+	    System.exit(-1);
+	}
+	return new SurfZPlane( zc*mmTocm );
+    }
+
+    public double[] getResolutions(){
+	return resolutions;
+    }
+
+    public double getResolution0(){
+	boolean ok = true;
+	if ( resolutions == null ){
+	    ok = false;
+	} else {
+	    if ( resolutions.length < 1 ){
+		ok = false;
+	    }
+	}
+	if ( !ok ){
+//	    System.out.println ("KalmanSurface: Illegal request for getResolution0 " + name );
+	    return 0.;
+	}
+	return resolutions[0];
+    }
+
+    public double getResolution1(){
+	boolean ok = true;
+	if ( resolutions == null ){
+	    ok = false;
+	} else {
+	    if ( resolutions.length < 1 ){
+		ok = false;
+	    }
+	}
+	if ( !ok ){
+//	    System.out.println ("KalmanSurface: Illegal request for getResolution1 " + name );
+	    return 0.;
+	}
+	return resolutions[1];
+    }
+
+
+    public KalmanSurface( IDetectorElement de, int rodim, int ixy, double[] res ){
+	if ( de == null ){
+//	    System.out.println("KalmanSurface: Cannot instantiate RKSurf with null DetectorElement." );
+	    System.exit(-1);
+	}
+
+//	this.name  = de.getName();
+	this.rodim = rodim;
+	this.ixy   = ixy;
+	resolutions = new double[res.length];
+	for ( int i=0; i<res.length; ++i){
+	    resolutions[i] = res[i]*mmTocm;
+	}
+	Build( de);
+    }
+
+    public KalmanSurface( IDetectorElement de, int rodim, int ixy, double res ){
+	if ( de == null ){
+	    System.out.println("KalmanSurface: Cannot instantiate KalmanSurface with null DetectorElement." );
+	    System.exit(-1);
+	}
+
+//	this.name  = de.getName();
+	this.rodim = rodim;
+	this.ixy   = ixy;
+	resolutions = new double[1];
+	resolutions[0] = res*mmTocm;
+	Build( de);
+    }
+
+    public KalmanSurface( IDetectorElement de, int rodim, int ixy, double res0, double res1 ){
+	if ( de == null ){
+	    System.out.println("KalmanSurface: Cannot instantiate KalmanSurface with null DetectorElement." );
+	    System.exit(-1);
+	}
+
+//	this.name  = de.getName();
+	this.rodim = rodim;
+	this.ixy   = ixy;
+	resolutions = new double[2];
+	resolutions[0] = res0*mmTocm;
+	resolutions[1] = res1*mmTocm;
+	Build( de);
+    }
+
+
+
+    public KalmanSurface( Subdetector sd ){
+	if ( sd == null ){
+	    System.out.println("KalmanSurface: Cannot instantiate RKSurf with null Subdetector." );
+	    System.exit(-1);
+	}
+
+//	this.sd = sd;
+	rodim   = 0;
+//	name    = sd.getName();
+	Build( sd );
+    }
+
+    // Adjust z position.  Used in the equivstrips model.
+    public void hackZc( double dz){
+	zc+=dz;
+    }
+
+    public void Print(){
+	if ( type == type_tube ){
+//	    System.out.printf ( "%-40s %1d %3d %10.2f %10.2f %10.2f %10.2f %-20s %10.2f %10.6f %10.6f\n",
+//				name,
+//				rodim,
+//				ixy,
+//				radius,
+//				thick,
+//				zmin,
+//				zmax,
+//				matname,
+//				radl,
+//				thick_radl,
+//				density
+//				);
+	} else {
+//	    System.out.printf ( "%-40s %1d %3d %10.2f %10.2f %10.2f %10.2f %-20s %10.2f %10.6f %10.6f\n",
+//				name,
+//				rodim,
+//				ixy,
+//				zc,
+//				thick,
+//				rmin,
+//				rmax,
+//				matname,
+//				radl,
+//				thick_radl,
+//				density
+//				);
+	}
+    }
+
+
+    private void Build( Subdetector sd ){
+
+	String classname  = sd.getClass().getName();
+	String shortname  = classname.replaceAll("org.lcsim.geometry.subdetector.","");
+
+	if ( shortname.compareTo("PolyconeSupport") == 0 ) {
+	    PolyconeSupport pc = (PolyconeSupport) sd;
+	    AddPolycone(pc);
+
+	} else {
+//	    System.out.println("KalmanSurface: Do not know how to add this subdetector: "
+//			       + name + " " + classname);
+	    System.exit(-1);
+	}
+
+	matname = material.getName();
+	radl    = material.getRadiationLength();
+
+	thick_radl = thick/radl;
+
+    }
+
+    private void Build( IDetectorElement de ){
+
+	//System.out.println ("Starting: " + name );
+	IGeometryInfo g   = de.getGeometry();
+	if ( g == null ){
+//	    System.out.println("Missing geometry for detector element: " + name );
+	    System.exit(-1);
+	}
+	ILogicalVolume lv = g.getLogicalVolume();
+	if ( lv == null ){
+//	    System.out.println("Missing logical volume for detector element: " + name );
+	    System.exit(-1);
+	}
+	IMaterial mat     = lv.getMaterial();
+	ISolid solid      = lv.getSolid();
+	Hep3Vector center = g.getPosition();
+
+	String solidname  = getSolidTypeName(solid);
+
+	if ( solidname.compareTo("Tube") == 0  ){
+	    Tube tube = (Tube) solid;
+	    if ( tube.getZHalfLength() > 1.0 ){
+		AddTube( tube, center );
+	    }else{
+		AddZDisc( tube, center);
+	    }
+
+	} else {
+//	    System.out.println ( "KalmanSurface: Do not recognize this shape for this DetectorElement: "
+//				 + solidname + " " + name );
+	    System.exit(-1);
+	}
+	matname = mat.getName();
+	radl    = mat.getRadiationLength();
+	density = mat.getDensity();
+
+	thick_radl = thick/radl;
+
+    }
+
+    private void AddPolycone ( PolyconeSupport pc ){
+	type = type_tube;
+	List<ZPlane> zplanes = pc.getZPlanes();
+	boolean ok = false;
+	for ( int i=1; i<zplanes.size(); ++i ){
+	    ZPlane zp1 = zplanes.get(i-1);
+	    ZPlane zp2 = zplanes.get(i);
+	    if ( zp1.getZ() < 0. && zp2.getZ() > 0. ){
+		if ( Math.abs(zp1.getRMax()-zp1.getRMax()) > tolerance ||
+		     Math.abs(zp1.getRMin()-zp1.getRMin()) > tolerance    ){
+//		    System.out.println ("RKSurf: Mismatched radii in beampipe: "
+//					+ name );
+		}
+		radius = 0.5*(zp1.getRMax() + zp1.getRMin());
+		thick  = zp1.getRMax() - zp1.getRMin();
+		zmin   = zp1.getZ();
+		zmax   = zp2.getZ();
+		ok = true;
+	    }
+	}
+
+	if ( !ok ){
+//	    System.out.println( "RKSurf: Could not parse PolyconeSupport for subdetector"
+//				+ name );
+	    System.exit(-1);
+	}
+
+	// Depracated but replacement appears not to be in place.
+	material = pc.getMaterial();
+
+	radl = material.getRadiationLength();
+	density = material.getDensity();
+
+    }
+
+    private void AddTube ( Tube tube, Hep3Vector center ){
+	type = type_tube;
+	if ( Math.abs( center.x()) > tolerance ||
+	     Math.abs( center.y()) > tolerance ||
+	     Math.abs( center.z()) > tolerance    ){
+	    System.out.println("RKSurf: Only do tubes centered on (0.0,0.0,0.) " );
+	    System.exit(-1);
+	}
+
+	zmin   = -tube.getZHalfLength();
+	zmax   = tube.getZHalfLength();
+	radius = 0.5*(tube.getOuterRadius()+tube.getInnerRadius());
+	thick  = tube.getOuterRadius()-tube.getInnerRadius();
+
+    }
+
+    private void AddZDisc ( Tube tube, Hep3Vector center ){
+	type   = type_zdisc;
+	zmin   = center.z()-tube.getZHalfLength();
+	zmax   = center.z()+tube.getZHalfLength();
+	radius = 0.5*(tube.getOuterRadius()+tube.getInnerRadius());
+	thick  = 2.*tube.getZHalfLength();
+
+	zc     = center.z();
+	rmin   = tube.getInnerRadius();
+	rmax   = tube.getOuterRadius();
+    }
+
+    // Utility function to extract a short version of the class name.
+    private String getSolidTypeName( ISolid s ){
+	String fullname = s.getClass().getName();
+	String name     = fullname.replaceAll( "org.lcsim.detector.solids.", "");
+	return name;
+    }
+
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman
PlayingWithTracksDriver.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/PlayingWithTracksDriver.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/PlayingWithTracksDriver.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,64 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.hps.recon.tracking.kalman;
+
+import java.util.List;
+
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.MCParticle;
+import org.lcsim.event.Track;
+import org.lcsim.event.TrackerHit;
+import org.lcsim.fit.helicaltrack.HelicalTrack2DHit;
+import org.lcsim.fit.helicaltrack.HelicalTrack3DHit;
+import org.lcsim.fit.helicaltrack.HelicalTrackCross;
+import org.lcsim.fit.helicaltrack.HelicalTrackHit;
+import org.lcsim.util.Driver;
+
+/**
+ *
+ * @author ecfine
+ */
+public class PlayingWithTracksDriver extends Driver{
+
+    public PlayingWithTracksDriver() {
+    }
+
+    
+    public void process(EventHeader event){
+        
+        System.out.println("event number " + event.getEventNumber());
+        System.out.println("event detector name: " +event.getDetectorName());
+        List<MCParticle> mcparticles = event.getMCParticles();
+        System.out.println("number of mcparticles: " + mcparticles.size());
+        MCParticle firstParticle = mcparticles.get(0);
+        System.out.println("energy of first particle: " + firstParticle.getEnergy());
+        if (event.hasItem("MatchedTracks")) {
+            List<Track> trklist = (List<Track>) event.get("MatchedTracks");
+            System.out.println("number of tracks: " + trklist.size());
+            for (int i = 0; i < trklist.size(); i ++){
+                Track trk = trklist.get(i);
+                for (int k = 0; k < trk.getTrackerHits().size(); k++){
+                    TrackerHit hit = (TrackerHit) trk.getTrackerHits().get(k);
+                    if (hit instanceof HelicalTrack2DHit){
+                        System.out.println("HelicalTrack2DHit");
+                    } else
+                    if (hit instanceof HelicalTrack3DHit){
+                        System.out.println("HelicalTrack3DHit");
+                    } else if(hit instanceof HelicalTrackCross){
+                        System.out.println("HelicalTrackCross");
+                    } else
+                    if (hit instanceof HelicalTrackHit){
+                        System.out.println("HelicalTrackHit");
+                    } else {
+                        System.out.println("Don't know this kind of track...");
+                    }
+                }
+            }
+        } else {
+            System.out.println("No tracks!");
+        }
+    }
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman
PrintDetectorElements.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/PrintDetectorElements.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/PrintDetectorElements.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,134 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.hps.recon.tracking.kalman;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.lcsim.detector.ILogicalVolume;
+import org.lcsim.detector.IPhysicalVolume;
+import org.lcsim.detector.ITransform3D;
+import org.lcsim.detector.solids.Point3D;
+import org.lcsim.geometry.Detector;
+
+/**
+ *
+ * @author ecfine
+ */
+
+public class PrintDetectorElements{
+    ShapeDispatcher shapeDispatcher = new ShapeDispatcher();
+    static int indent = 0;
+    List<Point3D> coords = null;
+    static ArrayList physicalVolumes = new ArrayList();
+    Boolean printing = true;
+
+
+    public void run(Detector detector, Boolean print) {
+       printing = print;
+       if (printing) {
+           System.out.println();
+           System.out.println();
+           System.out.println("Detector name is " + detector.getDetectorName());
+       }
+       ILogicalVolume logical = getLogicalVolume(detector);
+       loopThroughDaughters(logical);
+    }
+
+    private ILogicalVolume getLogicalVolume(Detector det) {
+         ILogicalVolume logical = det.getTrackingVolume().getLogicalVolume();
+         return logical;
+    }
+
+    private void loopThroughDaughters(ILogicalVolume logical) {
+        if (printing) {
+            printIndent();
+            System.out.println("Logical Volume: " + logical.getName());
+            indent ++;
+            printIndent();
+            System.out.println("Solid: " + logical.getSolid().getName());
+            printIndent();
+            System.out.println("Material: " + logical.getMaterial().getName());
+            printIndent();
+            System.out.println("Volume: " + logical.getSolid().getCubicVolume());
+            printIndent();
+            shapeDispatcher.printShape(logical.getSolid());
+            printIndent();
+            shapeDispatcher.printLocalCoords(logical.getSolid());
+            shapeDispatcher.printGlobalCoords(logical.getSolid());
+            System.out.println();
+            indent ++;
+        }
+        for (int n = 0; n < logical.getNumberOfDaughters(); n++) {
+            IPhysicalVolume physical = logical.getDaughter(n);
+            loopThroughDaughters(physicalToLogical(physical));
+            indent = (indent - 2);
+            physicalVolumes.remove(physicalVolumes.size() - 1);
+        }
+    }
+
+
+    // Prints the information in the physical volume and returns the logical
+    // volume associated with the physical volume. Adds the physical volume to
+    // the physicalVolumes ArrayList. Obtains the local rotation and caluculates
+    // global rotation.
+    private ILogicalVolume physicalToLogical(IPhysicalVolume physical) {
+        physicalVolumes.add(physical.getTransform());
+        if (printing){
+            printIndent();
+            System.out.println("Physical Volume: " + physical.getName());
+
+            indent ++;
+            printIndent();
+            System.out.println("Sensitive? " + physical.isSensitive());
+            printIndent();
+            System.out.println("Local Translation: " + physical.getTranslation());
+            printIndent();
+            System.out.println("Local Rotation: [" + physical.getRotation().getComponent(0,0) +
+                    "  " + physical.getRotation().getComponent(0, 1) +
+                    "  " + physical.getRotation().getComponent(0, 2));
+            printIndent();
+            System.out.println("                 " + physical.getRotation().getComponent(1,0) +
+                    "  " + physical.getRotation().getComponent(1, 1) +
+                    "  " + physical.getRotation().getComponent(1, 2));
+            printIndent();
+            System.out.println("                 " + physical.getRotation().getComponent(2,0) +
+                    "  " + physical.getRotation().getComponent(2, 1) +
+                    "  " + physical.getRotation().getComponent(2, 2) + "]");
+        }
+            getGlobalTransform(physical);
+            indent --;
+            return physical.getLogicalVolume();
+    }
+
+    private void getGlobalTransform(IPhysicalVolume physical) {
+        ITransform3D transform = (ITransform3D) physicalVolumes.get(0);
+        for (int i = 1; i < physicalVolumes.size(); i++){
+            ITransform3D lastTransform = (ITransform3D) physicalVolumes.get(i);
+            transform.multiplyBy(lastTransform);
+        }
+        printIndent();
+        System.out.println("Global Transform: " + transform.getTranslation());
+        printIndent();
+        System.out.println("                   [" + transform.getRotation().getComponent(0,0) +
+                    "  " + transform.getRotation().getComponent(0, 1) +
+                    "  " + transform.getRotation().getComponent(0, 2));
+            printIndent();
+            System.out.println("                    " + transform.getRotation().getComponent(1,0) +
+                    "  " + transform.getRotation().getComponent(1, 1) +
+                    "  " + transform.getRotation().getComponent(1, 2));
+            printIndent();
+            System.out.println("                    " + transform.getRotation().getComponent(2,0) +
+                    "  " + transform.getRotation().getComponent(2, 1) +
+                    "  " + transform.getRotation().getComponent(2, 2) + "]");
+    }
+
+    public void printIndent () {
+        for (int k = indent; k > 0; k --) {
+             System.out.print("     ");
+        }
+    }
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman
PrintDetectorElementsDriver.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/PrintDetectorElementsDriver.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/PrintDetectorElementsDriver.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,24 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.hps.recon.tracking.kalman;
+
+import org.lcsim.geometry.Detector;
+import org.lcsim.util.Driver;
+
+
+/**
+ *
+ * @author ecfine
+ */
+public class PrintDetectorElementsDriver extends Driver{
+    final boolean printing = true; // Determines whether results are printed
+
+    
+    public void detectorChanged(Detector detector) {
+        PrintDetectorElements loop = new PrintDetectorElements();
+        loop.run(detector, printing);
+    }
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman
PrintIntersections.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/PrintIntersections.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/PrintIntersections.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,130 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.hps.recon.tracking.kalman;
+
+import java.util.ArrayList;
+
+import org.lcsim.detector.ILogicalVolume;
+import org.lcsim.detector.IPhysicalVolume;
+import org.lcsim.detector.ITransform3D;
+import org.lcsim.event.Track;
+import org.lcsim.geometry.Detector;
+
+/**
+ *
+ * @author ecfine
+ */
+
+public class PrintIntersections{
+    ShapeDispatcher shapeDispatcher = new ShapeDispatcher();
+    static int indent = 0;
+    static ArrayList physicalVolumes = new ArrayList();
+    Track track;
+
+    public void run(Detector detector, Track trk) {
+       System.out.println();
+       System.out.println();
+       System.out.println("Detector name is " + detector.getDetectorName());
+       track = trk;
+       ILogicalVolume logical = getLogicalVolume(detector);
+       loopThroughDaughters(logical);
+      
+    }
+
+    private ILogicalVolume getLogicalVolume(Detector det) {
+         ILogicalVolume logical = det.getTrackingVolume().getLogicalVolume();
+         return logical;
+    }
+
+    private void loopThroughDaughters(ILogicalVolume logical) {
+        printIndent();
+        System.out.println("Logical Volume: " + logical.getName());
+        indent ++;
+//        printIndent();
+//        System.out.println("Solid: " + logical.getSolid().getName());
+//        printIndent();
+//        System.out.println("Material: " + logical.getMaterial().getName());
+//        printIndent();
+//        System.out.println("Volume: " + logical.getSolid().getCubicVolume());
+//        printIndent();
+//        shapeDispatcher.printShape(logical.getSolid());
+//        printIndent();
+//        shapeDispatcher.printLocalCoords(logical.getSolid());
+//        shapeDispatcher.printGlobalCoords(logical.getSolid());
+//        System.out.println();
+//        indent ++;
+          if (logical.getDaughters().size() == 0){
+              System.out.println("finding intersections");
+              shapeDispatcher.findIntersection(logical.getSolid(), track);
+          }
+          for (int n = 0; n < logical.getNumberOfDaughters(); n++) {
+            IPhysicalVolume physical = logical.getDaughter(n);
+            loopThroughDaughters(physicalToLogical(physical));
+            indent = (indent - 1);
+            physicalVolumes.remove(physicalVolumes.size() - 1);
+        }
+    }
+
+
+    // Prints the information in the physical volume and returns the logical
+    // volume associated with the physical volume. Adds the physical volume to
+    // the physicalVolumes ArrayList. Obtains the local rotation and caluculates
+    // global rotation.
+    private ILogicalVolume physicalToLogical(IPhysicalVolume physical) {
+        physicalVolumes.add(physical.getTransform());
+        printIndent();
+        System.out.println("Physical Volume: " + physical.getName());
+//        indent ++;
+//        printIndent();
+//        System.out.println("Sensitive? " + physical.isSensitive());
+//        printIndent();
+//        System.out.println("Local Translation: " + physical.getTranslation());
+//        printIndent();
+//        System.out.println("Local Rotation: [" + physical.getRotation().getComponent(0,0) +
+//                "  " + physical.getRotation().getComponent(0, 1) +
+//                "  " + physical.getRotation().getComponent(0, 2));
+//        printIndent();
+//        System.out.println("                 " + physical.getRotation().getComponent(1,0) +
+//                "  " + physical.getRotation().getComponent(1, 1) +
+//                "  " + physical.getRotation().getComponent(1, 2));
+//        printIndent();
+//        System.out.println("                 " + physical.getRotation().getComponent(2,0) +
+//                "  " + physical.getRotation().getComponent(2, 1) +
+//                "  " + physical.getRotation().getComponent(2, 2) + "]");
+
+//        getGlobalTransform(physical);
+//        indent --;
+        return physical.getLogicalVolume();
+    }
+
+    private void getGlobalTransform(IPhysicalVolume physical) {
+        ITransform3D transform = (ITransform3D) physicalVolumes.get(0);
+        for (int i = 1; i < physicalVolumes.size(); i++){
+            ITransform3D lastTransform = (ITransform3D) physicalVolumes.get(i);
+            transform.multiplyBy(lastTransform);
+        }
+        printIndent();
+        System.out.println("Global Transform: " + transform.getTranslation());
+        printIndent();
+        System.out.println("                   [" + transform.getRotation().getComponent(0,0) +
+                    "  " + transform.getRotation().getComponent(0, 1) +
+                    "  " + transform.getRotation().getComponent(0, 2));
+            printIndent();
+            System.out.println("                    " + transform.getRotation().getComponent(1,0) +
+                    "  " + transform.getRotation().getComponent(1, 1) +
+                    "  " + transform.getRotation().getComponent(1, 2));
+            printIndent();
+            System.out.println("                    " + transform.getRotation().getComponent(2,0) +
+                    "  " + transform.getRotation().getComponent(2, 1) +
+                    "  " + transform.getRotation().getComponent(2, 2) + "]");
+    }
+
+    public void printIndent() {
+        for (int k = indent; k > 0; k --) {
+             System.out.print("     ");
+        }
+    }
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman
PropDCACyl.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/PropDCACyl.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/PropDCACyl.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,732 @@
+package org.hps.recon.tracking.kalman;
+
+
+import org.lcsim.recon.tracking.trfbase.PropDir;
+import org.lcsim.recon.tracking.trfbase.PropDirected;
+import org.lcsim.recon.tracking.trfbase.PropStat;
+import org.lcsim.recon.tracking.trfbase.Propagator;
+import org.lcsim.recon.tracking.trfbase.Surface;
+import org.lcsim.recon.tracking.trfbase.TrackDerivative;
+import org.lcsim.recon.tracking.trfbase.TrackVector;
+import org.lcsim.recon.tracking.trfbase.VTrack;
+import org.lcsim.recon.tracking.trfcyl.SurfCylinder;
+import org.lcsim.recon.tracking.trfdca.SurfDCA;
+import org.lcsim.recon.tracking.trfutil.Assert;
+import org.lcsim.recon.tracking.trfutil.TRFMath;
+/**
+ * Propagates tracks from a DCA surface to a Cylinder.
+ *<p>
+ * Propagation will fail if either the origin is not a DCA surface,
+ * or the destination is not a Cylinder.
+ *<p>
+ * The default direction for propagation is forward.
+ *<p>
+ * Propagation to a cylinder at the radius of the DCA will succeed
+ * and the track parameters are valid but the errors are not valid.
+ *
+ *
+ *@author Norman A. Graf
+ *@version 1.0
+ *
+ */
+public class PropDCACyl extends PropDirected
+{
+    
+    // static variables
+    // Assign track parameter indices
+    
+    
+    public static final int IRSIGNED = SurfDCA.IRSIGNED;
+    public static final int IZ_DCA   = SurfDCA.IZ;
+    public static final int IPHID    = SurfDCA.IPHID;
+    public static final int ITLM_DCA = SurfDCA.ITLM;
+    public static final int IQPT_DCA = SurfDCA.IQPT;
+    
+    public static final int IPHI     = SurfCylinder.IPHI;
+    public static final int IZ_CYL   = SurfCylinder.IZ;
+    public static final int IALF     = SurfCylinder.IALF;
+    public static final int ITLM_CYL = SurfCylinder.ITLM;
+    public static final int IQPT_CYL = SurfCylinder.IQPT;
+    
+    // Attributes   ***************************************************
+    
+    
+    
+    // bfield * BFAC
+    private double _bfac;
+    
+    
+    // Methods   ******************************************************
+    
+    // static methods
+    
+    /**
+     *Return a String representation of the class' type name.
+     *Included for completeness with the C++ version.
+     *
+     * @return   A String representation of the class' type name.
+     */
+    public  static String typeName()
+    { return "PropDCACyl";
+    }
+    
+    /**
+     *Return a String representation of the class' type name.
+     *Included for completeness with the C++ version.
+     *
+     * @return   A String representation of the class' type name.
+     */
+    public  static String staticType()
+    { return typeName();
+    }
+    
+    
+    
+    /**
+     *Construct an instance from a constant solenoidal magnetic field in Tesla.
+     *
+     * @param   bfield The magnetic field strength in Tesla.
+     */
+    public PropDCACyl(double bfield)
+    {
+        super(PropDir.FORWARD);
+        _bfac=bfield * TRFMath.BFAC;
+    }
+    
+    /**
+     *Clone an instance.
+     *
+     * @return A Clone of this instance.
+     */
+    public Propagator newPropagator()
+    {
+        return new PropDCACyl( bField() );
+    }
+    
+    /**
+     *Return a String representation of the class' type name.
+     *Included for completeness with the C++ version.
+     *
+     * @return   A String representation of the class' type name.
+     */
+    public String type()
+    { return staticType();
+    }
+    
+    /**
+     *Propagate a track without error in the specified direction.
+     *and return the derivative matrix in deriv.
+     *
+     * The track parameters for a cylinder are:
+     * phi z alpha tan(lambda) curvature
+     *
+     * @param   trv The VTrack to propagate.
+     * @param   srf The Surface to which to propagate.
+     * @param   dir The direction in which to propagate.
+     * @param   deriv The track derivatives to update at the surface srf.
+     * @return The propagation status.
+     */
+    public PropStat vecDirProp( VTrack trv,  Surface srf,
+            PropDir dir, TrackDerivative deriv )
+    {
+        return dcaCylPropagate( _bfac, trv, srf, dir, deriv );
+    }
+    
+    /**
+     *Propagate a track without error in the specified direction.
+     *
+     * The track parameters for a cylinder are:
+     * phi z alpha tan(lambda) curvature
+     *
+     * @param   trv The VTrack to propagate.
+     * @param   srf The Surface to which to propagate.
+     * @param   dir The direction in which to propagate.
+     * @return The propagation status.
+     */
+    public PropStat vecDirProp( VTrack trv,  Surface srf,
+            PropDir dir )
+    {
+        TrackDerivative deriv =null;
+        return vecDirProp(trv, srf, dir, deriv);
+        
+    }
+    
+    // propagate a track with error in the specified direction
+    //  PropStat err_dir_prop( ETrack& tre,  Surface& srf,
+    //                                            PropDir dir ) ;
+    
+    //
+    
+    /**
+     *Return the strength of the magnetic field in Tesla.
+     *
+     * @return The strength of the magnetic field in Tesla.
+     */
+    public  double bField()
+    {
+        return _bfac/TRFMath.BFAC;
+    }
+    
+    
+    /**
+     *output stream
+     * @return  A String representation of this instance.
+     */
+    public String toString()
+    {
+        return "DCA propagation to a Cylinder with constant "
+                + bField() + " Tesla field";
+    }
+    
+    
+    
+    /**
+     * Propagate from dca to cylinder.
+     * Why is this public?
+     *
+     * @param   _bfac The numerical factor (including the field)
+     * @param   trv The VTrack to propagate.
+     * @param   srf The cylindrical surface to which to propagate.
+     * @param   dir The direction in which to propagate.
+     * @param   deriv The track derivatives to update at the surface srf.
+     * @return The propagation status.
+     */
+    public PropStat dcaCylPropagate(       double             _bfac,
+            VTrack             trv,
+            Surface            srf,
+            PropDir            dir,
+            TrackDerivative    deriv )
+    {
+        
+        // construct return status
+        PropStat pstat = new PropStat();
+        
+        // fetch the originating Surface and check it is a DCA surface
+        Surface srf0 = trv.surface();
+        Assert.assertTrue( srf0.pureType().equals(SurfDCA.staticType() ));
+        if ( ! srf0.pureType( ).equals(SurfDCA.staticType()) ){
+            System.out.println("Failing PropDCACyl because it's not a DCA surface");
+            return pstat;
+        }
+        SurfDCA srf_dca = ( SurfDCA ) srf0;
+        
+        // Check that dca surface has zero tilt.
+        
+        boolean tilted = srf_dca.dXdZ() != 0 || srf_dca.dYdZ() != 0;
+        Assert.assertTrue(!tilted);
+        if(tilted)    {
+             System.out.println("Failing PropDCACyl DCA surface is tilted");
+            return pstat;
+        }
+        
+        // check that the destination surface is a Cylinder
+        Assert.assertTrue( srf.pureType().equals(SurfCylinder.staticType()) );
+        if ( !srf.pureType( ).equals(SurfCylinder.staticType()) ){
+             System.out.println("Failing PropDCACyl because it's not a Cyl surface");
+            return pstat;
+        }
+        SurfCylinder srf_cyl = ( SurfCylinder ) srf;
+        //SurfCylinder srf_cyl = new SurfCylinder( (SurfCylinder) srf);
+        
+        // fetch the originating TrackVector
+        TrackVector vec_dca = trv.vector();
+        double r1p   = Math.abs(vec_dca.get(IRSIGNED));        // r
+        double z1    = vec_dca.get(IZ_DCA);                // z
+        double phid1p= vec_dca.get(IPHID);                 // phi_direction
+        double tlam1 = vec_dca.get(ITLM_DCA);              // tan(lambda)
+        double qpt1  = vec_dca.get(IQPT_DCA);              // q/pT
+        
+        double xv = srf_dca.x();
+        double yv = srf_dca.y();
+        
+        // calculate alf1 and phi1
+        double sign_alf1p;
+        double sign_r1p=0.;
+        
+        if ( !TRFMath.isZero( vec_dca.get(IRSIGNED) ) )
+        {
+            sign_alf1p  = vec_dca.get(IRSIGNED)/Math.abs(vec_dca.get(IRSIGNED));
+            sign_r1p = sign_alf1p;
+        }
+        else
+        {
+            sign_alf1p  = 0.0;
+        }
+        
+        if( (!TRFMath.isZero(xv) || !TRFMath.isZero(yv)) &&  TRFMath.isZero(sign_alf1p) )  sign_alf1p=1;
+        
+        double alf1p = sign_alf1p * TRFMath.PI2;                 // alpha
+        double phi1p = phid1p - alf1p;                    // phi_position
+        phi1p = TRFMath.fmod2( phi1p, TRFMath.TWOPI );
+        
+        // calculate salf1, calf1 and crv1
+        double salf1p=0.;
+        salf1p = alf1p>0. ? 1.:( alf1p < 0. ? -1. : 0.) ;
+        
+        double cosphi1p=Math.cos(phi1p);
+        double sinphi1p=Math.sin(phi1p);
+        
+        double x1=r1p*cosphi1p+xv;
+        double y1=r1p*sinphi1p+yv;
+        
+        double phi1 = Math.atan2(y1,x1);       // phi position in (xv,yv) coord system
+        double r1 = Math.sqrt(x1*x1+y1*y1);    // r1 in (xv,yv) coord system
+        double alf1 = alf1p + phi1p - phi1; // alf1 in (xv,yv) coord system
+        if( TRFMath.isZero(x1) && TRFMath.isZero(y1)  )
+        {
+            phi1 = phid1p;
+            alf1 = 0.;
+        }
+        if( sign_r1p == 0 && !TRFMath.isZero(r1) )
+            sign_r1p=1;
+        
+        // calculate salf1, calf1 and crv1
+        double salf1 = Math.sin( alf1 );
+        double calf1 = Math.cos( alf1 );
+        
+        if( TRFMath.isZero(alf1) )
+        {
+            salf1=0.;
+            calf1=1.;
+        }
+        if( TRFMath.isEqual(Math.abs(alf1),TRFMath.PI2) )
+        {
+            salf1= alf1 > 0 ? 1. : -1. ;
+            calf1=0.;
+        }
+        
+        double  crv1 = _bfac * qpt1;
+        double sign_crv = 1.;
+        
+        // fetch r2 of the destination Cylinder
+        double r2 = srf_cyl.parameter(SurfCylinder.RADIUS);
+        
+        // calculate tlam2, qpt2 and crv2 of the destination Cylinder
+        double tlam2 = tlam1;
+        double qpt2  = qpt1;
+        double crv2  = crv1;
+        
+        // calculate salf2 of the destination Cylinder
+        double salf2 = r1/r2*salf1 + 0.5*crv1/r2*(r2*r2-r1*r1);
+        
+        // If salf2 is close to 1 or -1, set it to that value.
+        double diff = Math.abs( Math.abs(salf2) - 1.0 );
+        if ( diff < 1.e-10 ) salf2 = salf2>0 ? 1.0 : -1.0;
+        // if salf2 > 1, track does not cross cylinder
+        if ( Math.abs(salf2) > 1.0 ) {
+             System.out.println("Failing PropDCACyl track does not cross cylinder:  salf2 = "+salf2);
+             System.out.println("r1 = "+r1+"; r2 = "+r2+"; salf1="+salf1+"; crv1 = "+crv1);
+             System.out.println("r1p = "+r1p+"; x1 = "+x1+"; y1 ="+y1+"; phi1p = "+phi1p);
+             return pstat;
+        }
+        
+        // there are two possibilities for alf2
+        double alf21 = Math.asin( salf2 );
+        double alf22 = alf21>0 ? Math.PI-alf21 : -Math.PI-alf21;
+        double calf21 = Math.cos( alf21 );
+        double calf22 = Math.cos( alf22 );
+        //double phi21 = phi1 + atan2( -sign_crv*calf21, r2*crv2-salf2 );
+        //double phi22 = phi1 + atan2( -sign_crv*calf22, r2*crv2-salf2 );
+        //        double cnst = salf1-r1*crv1 > 0 ? TRFMath.PI2 : -TRFMath.PI2;
+        //        cnst = (r1 == 0.) ? 0. : cnst;
+        
+        double cnst = Math.atan2(salf1-r1*crv1,calf1);
+        if( TRFMath.isEqual(Math.abs(alf1),TRFMath.PI2) )
+        {
+            cnst = salf1-r1*crv1 > 0 ? TRFMath.PI2 : -TRFMath.PI2;
+            cnst = (r1==0.) ? 0. : cnst;
+        }
+        
+        double phi21 = phi1 + cnst - Math.atan2( salf2-r2*crv2, calf21 );
+        double phi22 = phi1 + cnst - Math.atan2( salf2-r2*crv2, calf22 );
+        
+        if( TRFMath.isZero(crv1) )
+        {
+            phi21 = phi1 + cnst  - alf21;
+            phi22 = phi1 + cnst  - alf22;
+        }
+        
+        if ( TRFMath.isZero(calf21) )
+        {
+            phi21 = phi1;
+            phi22 = phi1;
+        }
+        
+        // construct an sT object for each solution
+        ST_DCACyl sto1 = new ST_DCACyl(r1,phi1,alf1,crv1,r2,phi21,alf21);
+        ST_DCACyl sto2 = new ST_DCACyl(r1,phi1,alf1,crv1,r2,phi22,alf22);
+        // check the two solutions are nonzero and have opposite sign
+        // or at least one is nonzero
+        
+        // choose the correct solution
+        boolean use_first_solution;
+        
+        if( dir.equals(PropDir.NEAREST))
+            use_first_solution = Math.abs(sto2.st()) > Math.abs(sto1.st());
+        
+        else if( dir.equals(PropDir.FORWARD))
+            use_first_solution = sto1.st() > 0.0;
+        
+        else if( dir.equals(PropDir.BACKWARD))
+            use_first_solution = sto1.st() < 0.0;
+        
+        else
+        {
+            use_first_solution = false;
+            System.out.println( "PropCyl._vec_propagate: Unknown direction.");
+            System.exit(1);
+        }
+        
+        // assign phi2, alf2 and sto2 for the chosen solution
+        double phi2, alf2;
+        ST_DCACyl sto = new ST_DCACyl();
+        double calf2;
+        if ( use_first_solution )
+        {
+            sto = sto1;
+            phi2 = phi21;
+            alf2 = alf21;
+            calf2 = calf21;
+        }
+        else
+        {
+            sto = sto2;
+            phi2 = phi22;
+            alf2 = alf22;
+            calf2 = calf22;
+        }
+        
+        // check alpha range
+        Assert.assertTrue( Math.abs(alf2) <= Math.PI );
+        
+        // fetch sT
+        double st = sto.st();
+        double s = st*Math.sqrt(1+tlam1*tlam1);
+        
+        // calculate z2 of the destination Cylinder
+        double z2 = z1 + st * tlam1;
+        
+        // construct the destination TrackVector
+        TrackVector vec_cyl = new TrackVector();
+        /*
+#ifdef TRF_PHIRANGE
+  vec_cyl(IPHI)     = fmod1(phi2, TWOPI);
+#else
+  vec_cyl(IPHI)     = phi2;
+#endif
+         */
+        vec_cyl.set(IPHI     , phi2);
+        vec_cyl.set(IZ_CYL   , z2);
+        vec_cyl.set(IALF     , alf2);
+        vec_cyl.set(ITLM_CYL , tlam2);
+        vec_cyl.set(IQPT_CYL , qpt2);
+/*
+   // For axial tracks, zero z and tan(lambda).
+ 
+  if(trv.is_axial()) {
+    vec_cyl(SurfDCA::IZ) = 0.;
+    vec_cyl(SurfDCA::ITLM) = 0.;
+  }
+ */
+        
+        // set the surface of trv to the destination Cylinder
+        trv.setSurface( srf_cyl.newPureSurface() );
+        
+        // set the vector of trv to the destination TrackVector (Cyl. coord.)
+        trv.setVector(vec_cyl);
+        
+        // set the direction of trv
+        if ( Math.abs(alf2) <= TRFMath.PI2 ) trv.setForward();
+        else trv.setBackward();
+        
+        // set the return status
+        pstat.setPathDistance(s);
+        
+        // exit now if user did not ask for error matrix.
+        if ( deriv == null ) {
+             System.out.println("PropDCACyl did not ask for error matrix");
+            return pstat;
+        }
+        
+        
+        // calculate derivatives
+        
+        //double dalf2_dr1   = (salf1-r1*crv1)/(r2*calf2);
+        //double dalf2_dr1   = (1.0-r1*crv1*salf1)/(r2*calf2);
+        // commented out by SK ( DCA to DCA(xv,yv) change)
+        double salf12 = sign_r1p*salf1;
+        if( sign_r1p == 0 && salf1 == 0. )
+            salf12 = 1;
+        double dalf2_dr1_sign = (salf12-crv1*r1*sign_r1p)/r2/calf2;
+        double dalf2_dr1 = (salf1-crv1*r1)/r2/calf2;
+        double dalf2_dalf1_or = 1/r2*calf1/calf2; // over r1
+        double dalf2_dalf1 = r1*dalf2_dalf1_or;
+        double dalf2_dcrv1 = (r2*r2-r1*r1)/(2.0*r2*calf2);
+        
+        //double dphi2_dr1 = -sign_crv*
+        //               (r2*crv2*salf2-1.0)*(r1*crv1-salf1)/
+        //               (r2*calf2*(1.0 + r2*r2*crv2*crv2 - 2.0*r2*crv2*salf2));
+        // commented out on 10.16.2001 by SK ( DCA to DCA(xv,yv) change)
+        //        double dphi2_dr1 = -sign_crv *
+        //        (r2*crv2*salf2-1.0)*(sign_alf1*r1*crv1-1.)/
+        //        (r2*calf2*(1.0 + r2*r2*crv2*crv2 - 2.0*r2*crv2*salf2));
+        //
+        //        double dphi2_dcrv1 = -sign_crv*
+        //        ((1.0-r2*crv2*salf2)*(r2*r2-r1*r1)-2.0*r2*r2*calf2*calf2)/
+        //        (2.0*r2*calf2*(1.0 + r2*r2*crv2*crv2 - 2.0*r2*crv2*salf2));
+        
+        double dphi2_dphi1=1.;
+        double dphi2_dr1_sign = -crv1*calf1*sign_r1p/(1.-2.*r1*crv1*salf1+r1*r1*crv1*crv1)
+        - dalf2_dr1_sign*(1-salf2*crv2*r2)/(1.-2.*r2*crv2*salf2+r2*r2*crv2*crv2);
+        
+        double dphi2_dr1 = -crv1*calf1/(1.-2.*r1*crv1*salf1+r1*r1*crv1*crv1)
+        - dalf2_dr1*(1-salf2*crv2*r2)/(1.-2.*r2*crv2*salf2+r2*r2*crv2*crv2);
+        double dphi2_dalf1_m1_or = (-salf1*crv1-r1*crv1*crv1+2.*crv1*salf1)/(1.-2.*r1*crv1*salf1+r1*r1*crv1*crv1)
+        - dalf2_dalf1_or*(1-salf2*crv2*r2)/(1.-2.*r2*crv2*salf2+r2*r2*crv2*crv2); // minus 1
+        double dphi2_dalf1 = dphi2_dalf1_m1_or*r1 + 1;
+        double dphi2_dcrv1 = -r1*calf1/(1.-2.*r1*crv1*salf1+r1*r1*crv1*crv1)
+        -(dalf2_dcrv1*(1.-r2*crv2*salf2) - r2*calf2)/(1.-2.*r2*crv2*salf2+r2*r2*crv2*crv2);
+        
+        
+        //double dst_dr1  = sto.d_st_dr1(dphi2_dr1,   dalf2_dr1  );
+        //        double dst_dr1  = sto.d_st_dr1(sign_alf1*dphi2_dr1,sign_alf1*dalf2_dr1  );
+        //        double dst_crv1 = sto.d_st_dcrv1(dphi2_dcrv1, dalf2_dcrv1);
+        double dst_dr1_sign   = sto.d_st_dr1_sign(sign_r1p,dphi2_dr1_sign,dalf2_dr1_sign);
+        double dst_dr1   = sto.d_st_dr1(dphi2_dr1,dalf2_dr1);
+        double dst_dcrv1 = sto.d_st_dcrv1(dphi2_dcrv1, dalf2_dcrv1);
+        double dst_dalf1_or = sto.d_st_dalf1_or(r1,dphi2_dalf1_m1_or, dalf2_dalf1_or);
+        
+        
+        // build the derivative matrix
+        // derivatives to prime coordinates
+        
+        double dphi1_dphi1p_tr = r1p*Math.cos(phi1p-phi1); // times r1
+        double dphi1_dr1p_tr = sign_r1p*Math.sin(phi1p-phi1); // times r1
+        
+        double dalf1_dphi1p_tr = r1 - dphi1_dphi1p_tr;
+        double dalf1_dr1p_tr = -dphi1_dr1p_tr;
+        
+        double dr1_dr1p_sign = Math.cos(phi1p-phi1);
+        double dr1_dphi1p = r1p*Math.sin(phi1-phi1p);
+        
+        
+        double dphi2_dphi1p = dphi2_dr1*dr1_dphi1p +dphi2_dalf1 - dphi1_dphi1p_tr*dphi2_dalf1_m1_or;
+        double dphi2_dr1p = dphi2_dr1_sign*dr1_dr1p_sign - dphi2_dalf1_m1_or*dphi1_dr1p_tr;
+        
+        double dalf2_dphi1p = dalf2_dr1*dr1_dphi1p + dalf2_dalf1_or*dalf1_dphi1p_tr;
+        double dalf2_dr1p = dalf2_dr1_sign*dr1_dr1p_sign + dalf2_dalf1_or*dalf1_dr1p_tr;
+        
+        double dst_dphi1p = dst_dr1*dr1_dphi1p + dst_dalf1_or*dalf1_dphi1p_tr;
+        double dst_dr1p = dst_dr1_sign*dr1_dr1p_sign + dst_dalf1_or*dalf1_dr1p_tr;
+        
+        //deriv(IPHI,     IRSIGNED,  sign_alf1 * dphi2_dr1);
+        deriv.set(IPHI,     IRSIGNED,  dphi2_dr1p);
+        deriv.set(IPHI,     IZ_DCA,    0.0);
+        deriv.set(IPHI,     IPHID,     dphi2_dphi1p);
+        deriv.set(IPHI,     ITLM_DCA,  0.0);
+        deriv.set(IPHI,     IQPT_DCA,  _bfac * dphi2_dcrv1);
+        
+        deriv.set(IZ_CYL,   IRSIGNED,  tlam1 * dst_dr1p);
+        deriv.set(IZ_CYL,   IZ_DCA,    1.0);
+        deriv.set(IZ_CYL,   IPHID,     tlam1 * dst_dphi1p);
+        deriv.set(IZ_CYL,   ITLM_DCA,  st);
+        deriv.set(IZ_CYL,   IQPT_DCA,  tlam1 * _bfac * dst_dcrv1);
+        
+        //deriv.set(IALF,     IRSIGNED,  sign_alf1 * dalf2_dr1);
+        deriv.set(IALF,     IRSIGNED,  dalf2_dr1p);
+        deriv.set(IALF,     IZ_DCA,    0.0);
+        deriv.set(IALF,     IPHID,     dalf2_dphi1p);
+        deriv.set(IALF,     ITLM_DCA,  0.0);
+        deriv.set(IALF,     IQPT_DCA,  _bfac * dalf2_dcrv1);
+        
+        deriv.set(ITLM_CYL, IRSIGNED,  0.0);
+        deriv.set(ITLM_CYL, IZ_DCA,    0.0);
+        deriv.set(ITLM_CYL, IPHID,     0.0);
+        deriv.set(ITLM_CYL, ITLM_DCA,  1.0);
+        deriv.set(ITLM_CYL, IQPT_DCA,  0.0);
+        
+        deriv.set(IQPT_CYL, IRSIGNED,  0.0);
+        deriv.set(IQPT_CYL, IZ_DCA,    0.0);
+        deriv.set(IQPT_CYL, IPHID,     0.0);
+        deriv.set(IQPT_CYL, ITLM_DCA,  0.0);
+        deriv.set(IQPT_CYL, IQPT_DCA,  1.0);
+        
+        
+/*
+  // For axial tracks, zero all derivatives of or with respect to z or
+  // tan(lambda), that are not already zero.  This will force the error
+  // matrix to have zero errors for z and tan(lambda).
+ 
+  if(trv.is_axial()) {
+    deriv.set(IZ_CYL,   IRSIGNED,  0.);
+    deriv.set(IZ_CYL,   IZ_DCA,    0.);
+    deriv.set(IZ_CYL,   IPHID,     0.);
+    deriv.set(IZ_CYL,   ITLM_DCA,  0.);
+    deriv.set(IZ_CYL,   IQPT_DCA,  0.);
+ 
+    deriv.set(ITLM_CYL, ITLM_DCA, 0.);
+  }
+ */
+        return pstat;
+        
+    }
+    
+    
+    // Private class STCalc.
+    //
+    // An STCalc_ object calculates sT (the signed transverse path length)
+    // and its derivatives w.r.t. alf1 and crv1.  It is constructed from
+    // the starting (r1, phi1, alf1, crv1) and final track parameters
+    // (r2, phi2, alf2) assuming these are consistent.  Methods are
+    // provided to retrieve sT and the two derivatives.
+    
+    class ST_DCACyl
+    {
+        
+        private boolean _big_crv;
+        private double _st;
+        //  double _dst_dalf2;
+        private double _dst_dr1;
+        private double _dst_dcrv1;
+        private double _dst_dphi2;
+        double _dst_dphi2_or;
+        private double _crv1; // was public? need to look into this
+        // constructor
+        public ST_DCACyl()
+        {
+        }
+        public ST_DCACyl(double r1, double phi1, double alf1, double crv1,
+                double r2, double phi2, double alf2)
+        {
+            
+            _crv1 = crv1;
+            Assert.assertTrue( r1 >= 0.0 );
+            Assert.assertTrue( r2 >= 0.0 );
+            double rmax = r1+r2;
+            
+            // Calculate the change in xy direction
+            double phi_dir_diff = TRFMath.fmod2(phi2+alf2-phi1-alf1,TRFMath.TWOPI);
+            Assert.assertTrue( Math.abs(phi_dir_diff) <= Math.PI );
+            
+            // Evaluate whether |C| is "big"
+            _big_crv = rmax*Math.abs(crv1) > 0.001;
+            
+            // If the curvature is big we can use
+            // sT = (phi_dir2 - phi_dir1)/crv1
+            if ( _big_crv )
+            {
+                Assert.assertTrue( crv1 != 0.0 );
+                _st = phi_dir_diff/crv1;
+            }
+            
+            // Otherwise, we calculate the straight-line distance
+            // between the points and use an approximate correction
+            // for the (small) curvature.
+            else
+            {
+                
+                // evaluate the distance
+                double d = Math.sqrt( r1*r1 + r2*r2 - 2.0*r1*r2*Math.cos(phi2-phi1) );
+                double arg = 0.5*d*crv1;
+                double arg2 = arg*arg;
+                double st_minus_d = d*arg2*( 1.0/6.0 + 3.0/40.0*arg2 );
+                _st = d + st_minus_d;
+                
+                // evaluate the sign
+                // We define a metric xsign = abs( (dphid-d*C)/(d*C) ).
+                // Because sT*C = dphid and d = abs(sT):
+                // xsign = 0 for sT > 0
+                // xsign = 2 for sT < 0
+                // Numerical roundoff will smear these predictions.
+                double sign = 0.0;
+                if ( crv1*_st != 0. )
+                {
+                    double xsign = Math.abs( (phi_dir_diff - _st*crv1) / (_st*crv1) );
+                    if ( xsign < 0.5 ) sign = 1.0;
+                    if ( xsign > 1.5  &&  xsign < 3.0 ) sign = -1.0;
+                }
+                // If the above is indeterminate, assume zero curvature.
+                // In this case abs(alpha) decreases monotonically
+                // with sT.  Track passing through origin has alpha = 0 on one
+                // side and alpha = +/-pi on the other.  If both points are on
+                // the same side, we use dr/ds > 0 for |alpha|<pi/2.
+                if ( sign == 0. )
+                {
+                    sign = 1.0;
+                    if ( Math.abs(alf2) > Math.abs(alf1) ) sign = -1.0;
+                    if ( Math.abs(alf2) == Math.abs(alf1) )
+                    {
+                        if ( Math.abs(alf2) < TRFMath.PI2 )
+                        {
+                            if ( r2 < r1 ) sign = -1.0;
+                        }
+                        else
+                        {
+                            if ( r2 > r1 ) sign = -1.0;
+                        }
+                    }
+                }
+                
+                // Correct _st using the above sign.
+                Assert.assertTrue( Math.abs(sign) == 1.0 );
+                _st = sign*_st;
+                
+                // save derivatives
+                //    _dst_dalf2 = (_st/d)*2.0*(r1-r2*cos(phi2-phi1));
+                //_dst_dphi2 = (_st/d)*2.0*r1*r2*sin(phi2-phi1);
+                //                _dst_dcrv1 = sign*d*d*arg*( 1.0/6.0 + 3.0/20.0*arg2);
+                //                double root = (1.0 + 0.5*arg*arg + 3.0/8.0*arg*arg*arg*arg );
+                //                _dst_dphi2 = sign*(r1*r2*Math.sin(phi2-phi1))*root/d;
+                //                _dst_dr1 =   sign*(r1-r2*Math.cos(phi2-phi1))*root/d;
+                
+                if ( TRFMath.isZero(d) )
+                {
+                    _dst_dcrv1 = 0.0;
+                    _dst_dphi2 = sign*r1;
+                    _dst_dphi2_or = sign;
+                    _dst_dr1 =  0.0;
+                }
+                else
+                {
+                    _dst_dcrv1 = sign*d*d*arg*( 1.0/6.0 + 3.0/20.0*arg2);
+                    double root = (1.0 + 0.5*arg*arg + 3.0/8.0*arg*arg*arg*arg );
+                    _dst_dphi2_or = sign*(r2*Math.sin(phi2-phi1))*root/d;
+                    _dst_dphi2 = _dst_dphi2_or*r1;
+                    _dst_dr1 =   sign*(r1-r2*Math.cos(phi2-phi1))*root/d;
+                }
+            }
+            
+        }
+        public double st()
+        {
+            return _st;
+        }
+        
+        public double d_st_dr1_sign(double sign_alf1,double dphi2_dr1_sign,double dalf2_dr1_sign)
+        {
+            if ( _big_crv ) return ( dphi2_dr1_sign + dalf2_dr1_sign ) / _crv1;
+            else return   _dst_dphi2 * dphi2_dr1_sign + _dst_dr1*sign_alf1;
+        }
+        
+        public double d_st_dr1(   double d_phi2_dr1,   double d_alf2_dr1   )
+        {
+            if ( _big_crv ) return ( d_phi2_dr1 + d_alf2_dr1 ) / _crv1;
+            else return   _dst_dphi2 * d_phi2_dr1 + _dst_dr1;
+        }
+        public double d_st_dcrv1( double d_phi2_dcrv1, double d_alf2_dcrv1 )
+        {
+            if ( _big_crv ) return ( d_phi2_dcrv1 + d_alf2_dcrv1 - _st ) / _crv1;
+            else return   _dst_dphi2 * d_phi2_dcrv1 + _dst_dcrv1;
+        }
+        
+        public double d_st_dalf1_or(double r1,double dphi2_dalf1_m1_or, double dalf2_dalf1_or)
+        {
+            if ( _big_crv ) return ( dphi2_dalf1_m1_or + dalf2_dalf1_or) / _crv1;
+            else return _dst_dphi2_or * (dphi2_dalf1_m1_or*r1+1);
+        }
+        
+    }
+    
+}
+
+

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman
PropDCAXY.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/PropDCAXY.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/PropDCAXY.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,296 @@
+package org.hps.recon.tracking.kalman;
+
+// May need to remove next line when moved to proper package.
+import org.lcsim.recon.tracking.trfbase.PropDir;
+import org.lcsim.recon.tracking.trfbase.PropDirected;
+import org.lcsim.recon.tracking.trfbase.PropStat;
+import org.lcsim.recon.tracking.trfbase.Propagator;
+import org.lcsim.recon.tracking.trfbase.Surface;
+import org.lcsim.recon.tracking.trfbase.TrackDerivative;
+import org.lcsim.recon.tracking.trfbase.VTrack;
+import org.lcsim.recon.tracking.trfcyl.SurfCylinder;
+//import org.lcsim.recon.tracking.trfdca.PropDCACyl;
+import org.lcsim.recon.tracking.trfcylplane.PropCylXY;
+import org.lcsim.recon.tracking.trfdca.SurfDCA;
+import org.lcsim.recon.tracking.trfutil.Assert;
+import org.lcsim.recon.tracking.trfutil.TRFMath;
+import org.lcsim.recon.tracking.trfxyp.SurfXYPlane;
+
+/**
+ * Propagates tracks from a DCA surface to an XYPlane.
+ * It does so by creating an intermediate Cylinder surface,
+ * and using existing code to perform the transformation in two steps.
+ *<p>
+ * Propagation will fail if either the origin is not a DCA surface,
+ * or the destination is not a XYPlane.
+ *<p>
+ * The default direction for propagation is forward.
+ *<p>
+ * PropDCACyl and PropCylXY do not work in all circumstances.  See those
+ * codes for details.
+ *
+ *
+ *@author $Author: mgraham $
+ *@version $Id: PropDCAXY.java,v 1.3 2011/11/16 18:00:03 mgraham Exp $
+ *
+ * Date $Date: 2011/11/16 18:00:03 $
+ *
+ */
+public class PropDCAXY extends PropDirected {
+
+    // static variables
+    // Assign track parameter indices
+    public static final int IRSIGNED = SurfDCA.IRSIGNED;
+    public static final int IZ_DCA = SurfDCA.IZ;
+    public static final int IPHID = SurfDCA.IPHID;
+    public static final int ITLM_DCA = SurfDCA.ITLM;
+    public static final int IQPT_DCA = SurfDCA.IQPT;
+    public static final int IPHI = SurfCylinder.IPHI;
+    public static final int IZ_CYL = SurfCylinder.IZ;
+    public static final int IALF = SurfCylinder.IALF;
+    public static final int ITLM_CYL = SurfCylinder.ITLM;
+    public static final int IQPT_CYL = SurfCylinder.IQPT;
+    private static final int IV = SurfXYPlane.IV;
+    private static final int IZC = SurfXYPlane.IZ;
+    private static final int IDVDU = SurfXYPlane.IDVDU;
+    private static final int IDZDU = SurfXYPlane.IDZDU;
+    private static final int IQP_XY = SurfXYPlane.IQP;
+    // Attributes   ***************************************************
+    // bfield * BFAC
+    private double _bfac;
+
+    // Methods   ******************************************************
+    // static methods
+    /**
+     *Return a String representation of the class' type name.
+     *Included for completeness with the C++ version.
+     *
+     * @return   A String representation of the class' type name.
+     */
+    public static String typeName() {
+        return "PropDCAXY";
+    }
+
+    /**
+     *Return a String representation of the class' type name.
+     *Included for completeness with the C++ version.
+     *
+     * @return   A String representation of the class' type name.
+     */
+    public static String staticType() {
+        return typeName();
+    }
+
+    /**
+     *Construct an instance from a constant solenoidal magnetic field in Tesla.
+     *
+     * @param   bfield The magnetic field strength in Tesla.
+     */
+    public PropDCAXY(double bfield) {
+        super(PropDir.FORWARD);
+        _bfac = bfield * TRFMath.BFAC;
+    }
+
+    /**
+     *Clone an instance.
+     *
+     * @return A Clone of this instance.
+     */
+    public Propagator newPropagator() {
+        return new PropDCAXY(bField());
+    }
+
+    /**
+     *Return a String representation of the class' type name.
+     *Included for completeness with the C++ version.
+     *
+     * @return   A String representation of the class' type name.
+     */
+    public String type() {
+        return staticType();
+    }
+
+    /**
+     *Propagate a track without error in the specified direction.
+     *and return the derivative matrix in deriv.
+     *
+     * The track parameters for a cylinder are:
+     * phi z alpha tan(lambda) curvature
+     *
+     * @param   trv The VTrack to propagate.
+     * @param   srf The Surface to which to propagate.
+     * @param   dir The direction in which to propagate.
+     * @param   deriv The track derivatives to update at the surface srf.
+     * @return The propagation status.
+     */
+    public PropStat vecDirProp(VTrack trv, Surface srf,
+            PropDir dir, TrackDerivative deriv) {
+        return dcaXYPropagate(_bfac, trv, srf, dir, deriv);
+    }
+
+    /**
+     *Propagate a track without error in the specified direction.
+     *
+     * The track parameters for a cylinder are:
+     * phi z alpha tan(lambda) curvature
+     *
+     * @param   trv The VTrack to propagate.
+     * @param   srf The Surface to which to propagate.
+     * @param   dir The direction in which to propagate.
+     * @return The propagation status.
+     */
+    public PropStat vecDirProp(VTrack trv, Surface srf,
+            PropDir dir) {
+        TrackDerivative deriv = null;
+        return vecDirProp(trv, srf, dir, deriv);
+
+    }
+
+    // propagate a track with error in the specified direction
+    //  PropStat err_dir_prop( ETrack& tre,  Surface& srf,
+    //                                            PropDir dir ) ;
+    //
+    /**
+     *Return the strength of the magnetic field in Tesla.
+     *
+     * @return The strength of the magnetic field in Tesla.
+     */
+    public double bField() {
+        return _bfac / TRFMath.BFAC;
+    }
+
+    /**
+     *output stream
+     * @return  A String representation of this instance.
+     */
+    public String toString() {
+        return "DCA propagation to an XYPlane with constant "
+                + bField() + " Tesla field";
+    }
+
+    /**
+     * Propagate from dca to cylinder.
+     * Why is this public?
+     *
+     * @param   _bfac The numerical factor (including the field)
+     * @param   trv The VTrack to propagate.
+     * @param   srf The cylindrical surface to which to propagate.
+     * @param   dir The direction in which to propagate.
+     * @param   deriv The track derivatives to update at the surface srf.
+     * @return The propagation status.
+     */
+    public PropStat dcaXYPropagate(double _bfac,
+            VTrack trv,
+            Surface srf,
+            PropDir dir,
+            TrackDerivative deriv) {
+//        System.out.println("running PropDCAXY");
+
+        // Construct return status
+        PropStat pstat = new PropStat();
+
+        // Fetch the originating Surface and check it is a DCA surface
+        Surface srf0 = trv.surface();
+        Assert.assertTrue(srf0.pureType().equals(SurfDCA.staticType()));
+        if (!srf0.pureType().equals(SurfDCA.staticType())) {
+            System.out.println("Failing PropDCAXY because it's not a DCA");
+            return pstat;
+        }
+        SurfDCA srf_dca = (SurfDCA) srf0;
+
+        // Check that dca surface has zero tilt.
+        boolean tilted = srf_dca.dXdZ() != 0 || srf_dca.dYdZ() != 0;
+        Assert.assertTrue(!tilted);
+        if (tilted) {
+            System.out.println("Failing PropDCAXY because it's tilted");
+            return pstat;
+        }
+        // Check that the destination surface is an XYPlane
+        Assert.assertTrue(srf.pureType().equals(SurfXYPlane.staticType()));
+        if (!srf.pureType().equals(SurfXYPlane.staticType())) {
+            System.out.println("Failing PropDCAXY because it's not a XY plane");
+            return pstat;
+        }
+        SurfXYPlane srf_xyp = (SurfXYPlane) srf;
+
+        // Instantiate the intermediate propagators.
+        PropDCACyl prop1 = new PropDCACyl(bField());
+        PropCylXY prop2 = new PropCylXY(bField());
+
+        // Radius of a cylinder going through the PCA ...
+        // But:
+        //   PropDCACyl requires that the cylinder be at a different radius than the DCA
+        //   so put it 100 microns outside the dca.
+        double rhack = Math.abs(trv.vector(IRSIGNED)) + 0.01;
+
+        // Instantiate the surface at the intermediate step.
+        SurfCylinder srf_cyl = new SurfCylinder(rhack);
+
+        // Setup for receiving the derivatives.
+        TrackDerivative d1 = null;
+        TrackDerivative d2 = null;
+        if (deriv != null) {
+            d1 = new TrackDerivative();
+            d2 = new TrackDerivative();
+        }
+
+        // Save the track z direction for later use.
+        boolean forward = trv.vector(ITLM_DCA) >= 0.;
+
+
+
+        // Do the propagation in two steps.
+        PropStat p1 = prop1.vecDirProp(trv, srf_cyl, dir, d1);
+        if (!p1.success()) {
+            System.out.println("Failing PropDCAXY propagation PropDCACyl failed");
+            System.out.println("trv = "+trv.toString());
+            System.out.println("cylinder = "+srf_cyl.toString());
+//            trv.setTrackBackward();
+//            p1=prop1.vecDirProp(trv, srf_cyl, dir, d1);
+            if(!p1.success())return p1;
+//            System.out.println("SUCCESS!!!!!!");
+        }
+        //    System.out.println("propagated to fake cylinder, track is: " + trv.toString());
+        PropStat p2 = prop2.vecDirProp(trv, srf_xyp, dir, d2);
+//    System.out.println("propagated to plane, track is: " + trv.toString());
+        if (!p2.success()) {
+            System.out.println("Failing PropDCAXY propagation PropCylXY failed");
+            return p2;
+        }
+
+        // Forward/backward is defined wrt positive z axis.
+
+        //mg...I'm not sure if this is what we want...seems to screw up PropXYXY
+        //mg (months later)   ...  how can this screw up PropXYXY???
+/*
+        if ( forward ){
+        trv.setForward();
+        } else{
+        trv.setBackward();
+        }
+         */
+        trv.setForward();  //mg set to setForward by default
+
+        // Set the transformation matrix to the product of the those from
+        // the two intermediate steps.
+        if (deriv != null) {
+            deriv.set(d2.times(d1));
+        }
+
+        // Set properties of the return value.
+        if (p2.forward()) {
+            pstat.setForward();
+        } else if (p2.backward()) {
+            pstat.setBackward();
+        } else if (p2.same()) {
+            pstat.setSame();
+        }
+        double s = p1.pathDistance() + p2.pathDistance();
+        pstat.setPathDistance(s);
+
+
+
+        return pstat;
+
+    }
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman
PropXYCyl.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/PropXYCyl.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/PropXYCyl.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,627 @@
+package org.hps.recon.tracking.kalman;
+
+import org.lcsim.recon.tracking.trfbase.PropDir;
+import org.lcsim.recon.tracking.trfbase.PropDirected;
+import org.lcsim.recon.tracking.trfbase.PropStat;
+import org.lcsim.recon.tracking.trfbase.Propagator;
+import org.lcsim.recon.tracking.trfbase.Surface;
+import org.lcsim.recon.tracking.trfbase.TrackDerivative;
+import org.lcsim.recon.tracking.trfbase.TrackVector;
+import org.lcsim.recon.tracking.trfbase.VTrack;
+import org.lcsim.recon.tracking.trfcyl.SurfCylinder;
+import org.lcsim.recon.tracking.trfutil.Assert;
+import org.lcsim.recon.tracking.trfutil.TRFMath;
+import org.lcsim.recon.tracking.trfxyp.SurfXYPlane;
+
+/**
+ * Propagates tracks from an XYPlane to a Cylinder in a constant field.
+ *<p>
+ * Propagation will fail if either the origin is not an XYPlane
+ * or destination is not a Cylinder.
+ * Propagator works incorrectly for tracks with very small curvatures.
+ *<p>
+ *@author Norman A. Graf
+ *@version 1.0
+ *
+ */
+public class PropXYCyl extends PropDirected
+{
+    
+    // Assign track parameter indices.
+    
+    private static final int IV = SurfXYPlane.IV;
+    private static final int IZC   = SurfXYPlane.IZ;
+    private static final int IDVDU = SurfXYPlane.IDVDU;
+    private static final int IDZDU = SurfXYPlane.IDZDU;
+    private static final int IQP_XY  = SurfXYPlane.IQP;
+    
+    private static final int IPHI = SurfCylinder.IPHI;
+    private static final int IZ   = SurfCylinder.IZ;
+    private static final int IALF = SurfCylinder.IALF;
+    private static final int ITLM = SurfCylinder.ITLM;
+    private static final int IQPT  = SurfCylinder.IQPT;
+    
+    
+    
+    // attributes
+    
+    // BFAC * bfield
+    private double _bfac;
+    
+    // static methods
+    
+    /**
+     *Return a String representation of the class' type name.
+     *Included for completeness with the C++ version.
+     *
+     * @return   A String representation of the class' type name.
+     */
+    public static String typeName()
+    { return "PropXYCyl";
+    }
+    
+    /**
+     *Return a String representation of the class' type name.
+     *Included for completeness with the C++ version.
+     *
+     * @return   A String representation of the class' type name.
+     */
+    public static String staticType()
+    { return typeName();
+    }
+    
+    
+    /**
+     *Construct an instance from a constant solenoidal magnetic field in Tesla.
+     *
+     * @param   bfield The magnetic field strength in Tesla.
+     */
+    public PropXYCyl(double bfield)
+    {
+        _bfac = TRFMath.BFAC*bfield;
+    }
+    
+    /**
+     *Clone an instance.
+     *
+     * @return A Clone of this instance.
+     */
+    public Propagator newPropagator( )
+    {
+        return new PropXYCyl( bField() );
+    }
+    
+    /**
+     *Propagate a track without error in the specified direction.
+     *
+     * The track parameters for a cylinder are:
+     * phi z alpha tan(lambda) curvature
+     *
+     * @param   trv The VTrack to propagate.
+     * @param   srf The Surface to which to propagate.
+     * @param   dir The direction in which to propagate.
+     * @return The propagation status.
+     */
+    public PropStat vecDirProp(VTrack trv,  Surface srf,
+            PropDir dir )
+    {
+        TrackDerivative deriv = null;
+        return vecDirProp(trv, srf, dir, deriv);
+    }
+    
+    /**
+     *Propagate a track without error in the specified direction
+     *and return the derivative matrix in deriv.
+     *
+     * The track parameters for a cylinder are:
+     * phi z alpha tan(lambda) curvature
+     *
+     * @param   trv The VTrack to propagate.
+     * @param   srf The Surface to which to propagate.
+     * @param   dir The direction in which to propagate.
+     * @param   deriv The track derivatives to update at the surface srf.
+     * @return The propagation status.
+     */
+    public PropStat vecDirProp(VTrack trv,  Surface srf,
+            PropDir dir, TrackDerivative deriv )
+    {
+        return vecPropagateXYCyl( _bfac, trv, srf, dir, deriv);
+        
+    }
+    
+    /**
+     *Return the strength of the magnetic field in Tesla.
+     *
+     * @return The strength of the magnetic field in Tesla.
+     */
+    public double bField()
+    {
+        return _bfac/TRFMath.BFAC;
+    }
+    
+    /**
+     *Return a String representation of the class' type name.
+     *Included for completeness with the C++ version.
+     *
+     * @return   A String representation of the class' type name.
+     */
+    public String type()
+    { return staticType();
+    }
+    
+    /**
+     *output stream
+     * @return  A String representation of this instance.
+     */
+    public String toString()
+    {
+        return "XYPlane-Cylinder propagation with constant "
+                + bField() +" Tesla field";
+        
+    }
+    
+    
+    //**********************************************************************
+    
+    // Private function to propagate a track without error
+    //
+    // The track parameters for a cylinder are:
+    // phi z alpha tan(lambda) curvature
+    // (NOT [. . . lambda .] as in TRF and earlier version of TRF++.)
+    //
+    // If pderiv is nonzero, return the derivative matrix there.
+    // On Cylinder:
+    // r (cm) is fixed
+    // 0 - phi
+    // 1 - z (cm)
+    // 2 - alp
+    // 3 - tlam
+    // 4 - q/pt   pt is transverse momentum of a track, q is its charge
+    // On XYPlane:
+    // u (cm) is fixed
+    // 0 - v (cm)
+    // 1 - z (cm)
+    // 2 - dv/du
+    // 3 - dz/du
+    // 4 - q/p   p is momentum of a track, q is its charge
+    
+    PropStat
+            vecPropagateXYCyl( double bfac, VTrack trv, Surface srf,
+            PropDir dir,
+            TrackDerivative deriv  )
+    {
+//        System.out.println("In vecPropagateXYCyl");
+        // construct return status
+        PropStat pstat = new PropStat();
+        
+        // fetch the originating surface and vector
+        Surface srf1 = trv.surface();
+        TrackVector vec1 = trv.vector();
+        
+        // Check origin is a XYPlane.
+        Assert.assertTrue( srf1.pureType().equals(SurfXYPlane.staticType()) );
+        if ( !srf1.pureType( ).equals(SurfXYPlane.staticType()) )
+            return pstat;
+        SurfXYPlane sxyp1 = ( SurfXYPlane) srf1;
+//         System.out.println("In vecPropagateXYCyl:  XYPlane is ok");
+        
+        // Check destination is a cylinder.
+        Assert.assertTrue( srf.pureType().equals(SurfCylinder.staticType()) );
+        if ( !srf.pureType( ).equals(SurfCylinder.staticType()) )
+            return pstat;
+        SurfCylinder scy2 = ( SurfCylinder) srf;
+//          System.out.println("In vecPropagateXYCyl:  Cylinder Surface is ok");
+        
+        // Fetch the dist and phi of the plane and the starting track vector.
+        int iphi  = SurfXYPlane.NORMPHI;
+        int idist = SurfXYPlane.DISTNORM;
+        double phi = sxyp1.parameter(iphi);
+        double    r = sxyp1.parameter(idist);
+        
+        TrackVector vec = trv.vector();
+        double v = vec.get(IV);                  // v
+        double z = vec.get(IZC);                  // z
+        double b = vec.get(IDVDU);               // dv/du
+        double a = vec.get(IDZDU);               // dz/du
+        double e = vec.get(IQP_XY);              // q/p
+        
+        // Fetch the radii and the starting track vector.
+        int irad = SurfCylinder.RADIUS;
+        double r2 = scy2.parameter(irad);
+        
+        int sign_du = 0;
+        if(trv.isForward())  sign_du =  1;
+        if(trv.isBackward()) sign_du = -1;
+        if(sign_du == 0)
+        {
+            System.out.println("PropXYCyl._vec_propagate: Unknown direction of a track ");
+            return pstat;
+        }
+        
+        // Calculate cylindrical coordinates
+        
+        double cnst=sign_du>0?0.: Math.PI;
+        double atn=Math.atan(v/r);
+        Assert.assertTrue(r!=0.);
+        
+        double phi1= TRFMath.fmod2(phi+atn,TRFMath.TWOPI);
+        double r1=Math.sqrt(r*r+v*v);
+        double z1=z;
+        double alp1= TRFMath.fmod2(Math.atan(b)-atn+cnst,TRFMath.TWOPI);
+        double tlm1= a*sign_du/Math.sqrt(1+b*b);
+        double qpt1=e*Math.sqrt((1+a*a+b*b)/(1+b*b));
+        
+        
+        // Check alpha range.
+        alp1 = TRFMath.fmod2( alp1, TRFMath.TWOPI );
+        Assert.assertTrue( Math.abs(alp1) <= Math.PI );
+        //if ( trv.is_forward() ) Assert.assertTrue( Math.abs(alp1) <= TRFMath.PI2 );
+        //else Assert.assertTrue( Math.abs(alp1) > TRFMath.PI2 );
+        
+        // Calculate the cosine of lambda.
+        //double clam1 = 1.0/Math.sqrt(1+tlm1*tlm1);
+        
+        // Calculate curvature: C = _bfac*(q/p)/Math.cos(lambda)
+        // and its derivatives
+        // Assert.assertTrue( clam1 != 0.0 );
+        // double dcrv1_dqp1 = bfac/clam1;
+        // double crv1 = dcrv1_dqp1*qp1;
+        // double dcrv1_dtlm1 = crv1*clam1*clam1*tlm1;
+        
+        // Calculate the curvature = _bfac*(q/pt)
+        double dcrv1_dqpt1 = bfac;
+        double crv1 = dcrv1_dqpt1*qpt1;
+        //double dcrv1_dtlm1 = 0.0;
+        
+        // Evaluate the new track vector.
+        // See dla log I-044
+        
+        // lambda and curvature do not change
+        double tlm2 = tlm1;
+        double crv2 = crv1;
+        double qpt2 = qpt1;
+        
+        // We can evaluate Math.sin(alp2), leaving two possibilities for alp2
+        // 1st solution: alp21, phi21, phid21, tht21
+        // 2nd solution: alp22, phi22, phid22, tht22
+        // evaluate phi2 to choose
+        double salp1 = Math.sin( alp1 );
+        double calp1 = Math.cos( alp1 );
+        double salp2 = r1/r2*salp1 + 0.5*crv1/r2*(r2*r2-r1*r1);
+        // if salp2 > 1, track does not cross cylinder
+//          System.out.println("In vecPropagateXYCyl:  Math.abs(salp2) = "+Math.abs(salp2));
+        if ( Math.abs(salp2) > 1.0 ) return pstat;
+        double alp21 = Math.asin( salp2 );
+        double alp22 = alp21>0 ? Math.PI-alp21 : -Math.PI-alp21;
+        double calp21 = Math.cos( alp21 );
+        double calp22 = Math.cos( alp22 );
+        double phi20 = phi1 + Math.atan2( salp1-r1*crv1, calp1 );
+        double phi21 = phi20 - Math.atan2( salp2-r2*crv2, calp21 );   // phi position
+        double phi22 = phi20 - Math.atan2( salp2-r2*crv2, calp22 );
+        
+        // Construct an sT object for each solution.
+        STCalcXY sto1 = new STCalcXY(r1,phi1,alp1,crv1,r2,phi21,alp21);
+        STCalcXY sto2 = new STCalcXY(r1,phi1,alp1,crv1,r2,phi22,alp22);
+        // Check the two solutions are nonzero and have opposite sign
+        // or at least one is nonzero.
+        
+        // Choose the correct solution
+        boolean use_first_solution = false;
+        
+        if (dir.equals(PropDir.NEAREST))
+        {
+            use_first_solution = Math.abs(sto2.st()) > Math.abs(sto1.st());
+        }
+        else if (dir.equals(PropDir.FORWARD))
+        {
+            use_first_solution = sto1.st() > 0.0;
+        }
+        else if (dir.equals(PropDir.BACKWARD))
+        {
+            use_first_solution = sto1.st() < 0.0;
+        }
+        else
+        {
+            System.out.println("PropCyl._vec_propagate: Unknown direction.");
+            System.exit(1);
+        }
+        
+        // Assign phi2, alp2 and sto2 for the chosen solution.
+        double phi2, alp2;
+        STCalcXY sto;
+        double calp2;
+        if ( use_first_solution )
+        {
+            sto = sto1;
+            phi2 = phi21;
+            alp2 = alp21;
+            calp2 = calp21;
+        }
+        else
+        {
+            sto = sto2;
+            phi2 = phi22;
+            alp2 = alp22;
+            calp2 = calp22;
+        }
+        
+        // fetch sT.
+        double st = sto.st();
+        
+        // use sT to evaluate z2
+        double z2 = z1 + tlm1*st;
+        
+        // Check alpha range.
+        Assert.assertTrue( Math.abs(alp2) <= Math.PI );
+        
+        // put new values in vec
+        vec.set(IPHI , phi2);
+        vec.set(IZ   , z2);
+        vec.set(IALF , alp2);
+        vec.set(ITLM , tlm2);
+        vec.set(IQPT , qpt2);
+        
+        // Update trv
+        trv.setSurface(srf.newPureSurface());
+        trv.setVector(vec);
+        if ( Math.abs(alp2) <= TRFMath.PI2 ) trv.setForward();
+        else trv.setBackward();
+        
+        // Set the return status.
+        double s = st*Math.sqrt(1.0+tlm2*tlm2);
+        pstat.setPathDistance(s);
+        //st > 0 ? pstat.set_forward() : pstat.set_backward();
+        
+        // exit now if user did not ask for error matrix.
+        if ( deriv == null ) return pstat;
+        
+        // Calculate derivatives.
+        // dphi1
+        
+        double dphi1_dv= r/(r*r+v*v);
+        
+        // dz1
+        
+        double dz1_dz=1.;
+        
+        // dalf1
+        
+        double dalp1_db= 1./(1.+b*b);
+        double dalp1_dv= -r/(r*r+v*v);
+        
+        // dr1
+        
+        double dr1_dv= v/Math.sqrt(v*v+r*r);
+        
+        // dtlm1
+        
+        double dtlm1_da= sign_du/Math.sqrt(1+b*b);
+        double dtlm1_db= -a*sign_du*b/(1+b*b)/Math.sqrt(1+b*b);
+        
+        // dcrv1
+        
+        double dqpt1_de= Math.sqrt((1+a*a+b*b)/(1+b*b));
+        double dqpt1_da= a*e/Math.sqrt((1+b*b)*(1+a*a+b*b));
+        double dqpt1_db= -e*b*a*a/Math.sqrt(1+a*a+b*b)/Math.sqrt(1+b*b)/(1+b*b);
+        
+        double dcrv1_de= dqpt1_de*bfac;
+        double dcrv1_da= dqpt1_da*bfac;
+        double dcrv1_db= dqpt1_db*bfac;
+        
+        // alpha_2
+        double da2da1 = r1*calp1/r2/calp2;
+        double da2dc1 = (r2*r2-r1*r1)*0.5/r2/calp2;
+        double da2dr1 = (salp1-crv2*r1)/r2/calp2;
+        
+        // phi2
+        double rcsal1 = r1*crv1*salp1;
+        double rcsal2 = r2*crv2*salp2;
+        double den1 = 1.0 + r1*r1*crv1*crv1 - 2.0*rcsal1;
+        double den2 = 1.0 + r2*r2*crv2*crv2 - 2.0*rcsal2;
+        double dp2dp1 = 1.0;
+        double dp2da1 = (1.0-rcsal1)/den1 - (1.0-rcsal2)/den2*da2da1;
+        double dp2dc1 = -r1*calp1/den1 + r2*calp2/den2
+                - (1.0-rcsal2)/den2*da2dc1;
+        double dp2dr1= -crv1*calp1/den1-(1.0-rcsal2)*da2dr1/den2;
+        
+        // z2
+        double dz2dz1 = 1.0;
+        double dz2dl1 = st;
+        double dz2da1 = tlm1*sto.d_st_dalp1(dp2da1, da2da1);
+        double dz2dc1 = tlm1*sto.d_st_dcrv1(dp2dc1, da2dc1);
+        double dz2dr1 = tlm1*sto.d_st_dr1(  dp2dr1, da2dr1);
+        
+        // final derivatives
+        
+        // phi2
+        double dphi2_dv=dp2dp1*dphi1_dv+dp2da1*dalp1_dv+dp2dr1*dr1_dv;
+        double dphi2_db=dp2da1*dalp1_db+dp2dc1*dcrv1_db;
+        double dphi2_da=dp2dc1*dcrv1_da;
+        double dphi2_de=dp2dc1*dcrv1_de;
+        
+        // alp2
+        double dalp2_dv= da2da1*dalp1_dv+da2dr1*dr1_dv;
+        double dalp2_db= da2da1*dalp1_db+da2dc1*dcrv1_db;
+        double dalp2_da= da2dc1*dcrv1_da;
+        double dalp2_de= da2dc1*dcrv1_de;
+        
+        // crv2
+        double dqpt2_da=dqpt1_da;
+        double dqpt2_db=dqpt1_db;
+        double dqpt2_de=dqpt1_de;
+        
+        
+        // tlm2
+        double dtlm2_da= dtlm1_da;
+        double dtlm2_db= dtlm1_db;
+        
+        // z2
+        double dz2_dz= dz2dz1*dz1_dz;
+        double dz2_dv= dz2dr1*dr1_dv+dz2da1*dalp1_dv;
+        double dz2_db= dz2da1*dalp1_db+dz2dl1*dtlm1_db+dz2dc1*dcrv1_db;
+        double dz2_da= dz2dl1*dtlm1_da+dz2dc1*dcrv1_da;
+        double dz2_de= dz2dc1*dcrv1_de;
+        
+        
+        // Build derivative matrix.
+        
+        deriv.set(IPHI,IV , dphi2_dv);
+        deriv.set(IPHI,IDVDU,  dphi2_db);
+        deriv.set(IPHI,IDZDU,  dphi2_da);
+        deriv.set(IPHI,IQP_XY,  dphi2_de);
+        deriv.set(IZ,IV   ,  dz2_dv);
+        deriv.set(IZ,IZC  ,  dz2_dz);
+        deriv.set(IZ,IDVDU , dz2_db);
+        deriv.set(IZ,IDZDU , dz2_da);
+        deriv.set(IZ,IQP_XY, dz2_de);
+        deriv.set(IALF,IV ,  dalp2_dv);
+        deriv.set(IALF,IDVDU ,  dalp2_db);
+        deriv.set(IALF,IDZDU ,  dalp2_da);
+        deriv.set(IALF,IQP_XY ,  dalp2_de);
+        deriv.set(ITLM,IDVDU ,  dtlm2_db);
+        deriv.set(ITLM,IDZDU ,  dtlm2_da);
+        deriv.set(IQPT,IDVDU ,  dqpt2_db);
+        deriv.set(IQPT,IDZDU ,  dqpt2_da);
+        deriv.set(IQPT,IQP_XY ,  dqpt2_de);
+        
+        return pstat;
+        
+    }
+    
+    //**********************************************************************
+    // helpers
+    //**********************************************************************
+    
+    // Private class STCalcXY.
+    //
+    // An STCalcXY_ object calculates sT (the signed transverse path length)
+    // and its derivatives w.r.t. alf1 and crv1.  It is constructed from
+    // the starting (r1, phi1, alf1, crv1) and final track parameters
+    // (r2, phi2, alf2) assuming these are consistent.  Methods are
+    // provided to retrieve sT and the two derivatives.
+    
+    class STCalcXY
+    {
+        
+        private boolean _big_crv;
+        private double _st;
+        private double _dst_dphi21;
+        private double _dst_dcrv1;
+        private double _dst_dr1;
+        private double _cnst1,_cnst2;
+        public  double _crv1;
+        
+        // constructor
+        public STCalcXY()
+        {
+        }
+        public STCalcXY(double r1, double phi1, double alf1, double crv1,
+                double r2, double phi2, double alf2)
+        {
+            
+            _crv1 = crv1;
+            Assert.assertTrue( r1 > 0.0 );
+            Assert.assertTrue( r2 > 0.0 );
+            double rmax = r1+r2;
+            
+            // Calculate the change in xy direction
+            double phi_dir_diff = TRFMath.fmod2(phi2+alf2-phi1-alf1,TRFMath.TWOPI);
+            Assert.assertTrue( Math.abs(phi_dir_diff) <= Math.PI );
+            
+            // Evaluate whether |C| is" big"
+            _big_crv = rmax*Math.abs(crv1) > 0.001 || Math.abs(r1-r2)<1.e-9;
+            if( Math.abs(crv1) < 1.e-10 ) _big_crv=false;
+            
+            // If the curvature is big we can use
+            // sT = (phi_dir2 - phi_dir1)/crv1
+            if ( _big_crv )
+            {
+                Assert.assertTrue( crv1 != 0.0 );
+                _st = phi_dir_diff/crv1;
+            }
+            
+            // Otherwise, we calculate the straight-line distance
+            // between the points and use an approximate correction
+            // for the (small) curvature.
+            else
+            {
+                
+                // evaluate the distance
+                double d = Math.sqrt( r1*r1 + r2*r2 - 2.0*r1*r2*Math.cos(phi2-phi1) );
+                double arg = 0.5*d*crv1;
+                double arg2 = arg*arg;
+                double st_minus_d = d*arg2*( 1.0/6.0 + 3.0/40.0*arg2 );
+                _st = d + st_minus_d;
+                
+                // evaluate the sign
+                // We define a metric xsign = abs( (dphid-d*C)/(d*C) ).
+                // Because sT*C = dphid and d = abs(sT):
+                // xsign = 0 for sT > 0
+                // xsign = 2 for sT < 0
+                // Numerical roundoff will smear these predictions.
+                double xsign = (crv1 == 0. ? 0.: Math.abs( (phi_dir_diff - _st*crv1) / (_st*crv1)) );
+                double sign = 0.0;
+                if ( crv1 != 0. )
+                {
+                    if ( xsign < 0.5 ) sign = 1.0;
+                    if ( xsign > 1.5  &&  xsign < 3.0 ) sign = -1.0;
+                }
+                // If the above is indeterminate, assume zero curvature.
+                // In this case abs(alpha) decreases monotonically
+                // with sT.  Track passing through origin has alpha = 0 on one
+                // side and alpha = +/-pi on the other.  If both points are on
+                // the same side, we use dr/ds > 0 for |alpha|<pi/2.
+                if ( sign == 0. )
+                {
+                    sign = 1.0;
+                    if ( Math.abs(alf2) > Math.abs(alf1) ) sign = -1.0;
+                    if ( Math.abs(alf2) == Math.abs(alf1) )
+                    {
+                        if ( Math.abs(alf2) < TRFMath.PI2 )
+                        {
+                            if ( r2 < r1 ) sign = -1.0;
+                        }
+                        else
+                        {
+                            if ( r2 > r1 ) sign = -1.0;
+                        }
+                    }
+                }
+                
+                // Correct _st using the above sign.
+                Assert.assertTrue( Math.abs(sign) == 1.0 );
+                _st = sign*_st;
+                
+                // save derivatives
+                _dst_dcrv1 = sign*d*d*arg*( 1.0/6.0 + 3.0/20.0*arg2);
+                double root = (1.0 + 0.5*arg*arg + 3.0/8.0*arg*arg*arg*arg );
+                _dst_dphi21 = sign*(r1*r2*Math.sin(phi2-phi1))*root/d;
+                _dst_dr1= (1.+arg2/2.*(1+3./4.*arg2))/d*sign;
+                _cnst1=r1-r2*Math.cos(phi2-phi1);
+                _cnst2=r1*r2*Math.sin(phi2-phi1);
+            }
+        }
+        
+        public double st()
+        { return _st;
+        }
+        
+        public double d_st_dalp1(double d_phi2_dalf1, double d_alf2_dalf1 )
+        {
+            if ( _big_crv ) return ( d_phi2_dalf1 + d_alf2_dalf1 - 1.0 ) / _crv1;
+            else return _dst_dphi21 * d_phi2_dalf1;
+            
+        }
+        public double d_st_dcrv1(double d_phi2_dcrv1, double d_alf2_dcrv1 )
+        {
+            if ( _big_crv ) return ( d_phi2_dcrv1 + d_alf2_dcrv1 - _st ) / _crv1;
+            else return _dst_dcrv1 + _dst_dphi21*d_phi2_dcrv1;
+            
+        }
+        public double d_st_dr1(  double d_phi2_dr1,   double d_alf2_dr1   )
+        {
+            if ( _big_crv ) return ( d_phi2_dr1 + d_alf2_dr1 ) / _crv1;
+            else return _dst_dr1*(_cnst1+_cnst2*d_phi2_dr1);
+        }
+    }
+}
\ No newline at end of file

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman
PropXYDCA.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/PropXYDCA.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/PropXYDCA.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,306 @@
+package org.hps.recon.tracking.kalman;
+
+// May need to remove next line when moved to proper package.
+import org.lcsim.recon.tracking.trfbase.PropDir;
+import org.lcsim.recon.tracking.trfbase.PropDirected;
+import org.lcsim.recon.tracking.trfbase.PropStat;
+import org.lcsim.recon.tracking.trfbase.Propagator;
+import org.lcsim.recon.tracking.trfbase.Surface;
+import org.lcsim.recon.tracking.trfbase.TrackDerivative;
+import org.lcsim.recon.tracking.trfbase.VTrack;
+import org.lcsim.recon.tracking.trfcyl.SurfCylinder;
+//import org.lcsim.recon.tracking.trfcylplane.PropXYCyl;
+import org.lcsim.recon.tracking.trfdca.PropCylDCA;
+import org.lcsim.recon.tracking.trfdca.SurfDCA;
+import org.lcsim.recon.tracking.trfutil.Assert;
+import org.lcsim.recon.tracking.trfutil.TRFMath;
+import org.lcsim.recon.tracking.trfxyp.SurfXYPlane;
+
+
+/**
+ * Propagates tracks from an XY surface to an DCA surface.
+ * It does so by creating an intermediate Cylinder surface,
+ * and using existing code to perform the transformation in two steps.
+ *<p>
+ * Propagation will fail if either the origin is not an XY surface,
+ * or the destination is not a DCA surface.
+ *<p>
+ * The default direction for propagation is forward.
+ *<p>
+ * PropDCACyl and PropCylXY do not work in all circumstances.  See those
+ * codes for details.
+ *
+ *
+ *@author $Author: mgraham $
+ *@version $Id: PropXYDCA.java,v 1.1 2011/07/07 20:57:38 mgraham Exp $
+ *
+ * Date $Date: 2011/07/07 20:57:38 $
+ *
+ */
+public class PropXYDCA extends PropDirected
+{
+
+    // static variables
+    // Assign track parameter indices
+
+    public static final int IRSIGNED = SurfDCA.IRSIGNED;
+    public static final int IZ_DCA   = SurfDCA.IZ;
+    public static final int IPHID    = SurfDCA.IPHID;
+    public static final int ITLM_DCA = SurfDCA.ITLM;
+    public static final int IQPT_DCA = SurfDCA.IQPT;
+
+    public static final int IPHI     = SurfCylinder.IPHI;
+    public static final int IZ_CYL   = SurfCylinder.IZ;
+    public static final int IALF     = SurfCylinder.IALF;
+    public static final int ITLM_CYL = SurfCylinder.ITLM;
+    public static final int IQPT_CYL = SurfCylinder.IQPT;
+
+    private static final int IV      = SurfXYPlane.IV;
+    private static final int IZC     = SurfXYPlane.IZ;
+    private static final int IDVDU   = SurfXYPlane.IDVDU;
+    private static final int IDZDU   = SurfXYPlane.IDZDU;
+    private static final int IQP_XY  = SurfXYPlane.IQP;
+
+
+    // Attributes   ***************************************************
+
+    // bfield * BFAC
+    private double _bfac;
+
+
+    // Methods   ******************************************************
+
+    // static methods
+
+    /**
+     *Return a String representation of the class' type name.
+     *Included for completeness with the C++ version.
+     *
+     * @return   A String representation of the class' type name.
+     */
+    public  static String typeName()
+    { return "PropXYDCA";
+    }
+
+    /**
+     *Return a String representation of the class' type name.
+     *Included for completeness with the C++ version.
+     *
+     * @return   A String representation of the class' type name.
+     */
+    public  static String staticType()
+    { return typeName();
+    }
+
+
+
+    /**
+     *Construct an instance from a constant solenoidal magnetic field in Tesla.
+     *
+     * @param   bfield The magnetic field strength in Tesla.
+     */
+    public PropXYDCA(double bfield)
+    {
+        super(PropDir.FORWARD);
+        _bfac=bfield * TRFMath.BFAC;
+    }
+
+    /**
+     *Clone an instance.
+     *
+     * @return A Clone of this instance.
+     */
+    public Propagator newPropagator()
+    {
+        return new PropXYDCA( bField() );
+    }
+
+    /**
+     *Return a String representation of the class' type name.
+     *Included for completeness with the C++ version.
+     *
+     * @return   A String representation of the class' type name.
+     */
+    public String type()
+    { return staticType();
+    }
+
+    /**
+     *Propagate a track without error in the specified direction.
+     *and return the derivative matrix in deriv.
+     *
+     * The track parameters for a cylinder are:
+     * phi z alpha tan(lambda) curvature
+     *
+     * @param   trv The VTrack to propagate.
+     * @param   srf The Surface to which to propagate.
+     * @param   dir The direction in which to propagate.
+     * @param   deriv The track derivatives to update at the surface srf.
+     * @return The propagation status.
+     */
+    public PropStat vecDirProp( VTrack trv,  Surface srf,
+            PropDir dir, TrackDerivative deriv )
+    {
+        return dcaXYPropagate( _bfac, trv, srf, dir, deriv );
+    }
+
+    /**
+     *Propagate a track without error in the specified direction.
+     *
+     * The track parameters for a cylinder are:
+     * phi z alpha tan(lambda) curvature
+     *
+     * @param   trv The VTrack to propagate.
+     * @param   srf The Surface to which to propagate.
+     * @param   dir The direction in which to propagate.
+     * @return The propagation status.
+     */
+    public PropStat vecDirProp( VTrack trv,  Surface srf,
+            PropDir dir )
+    {
+        TrackDerivative deriv =null;
+        return vecDirProp(trv, srf, dir, deriv);
+
+    }
+
+    // propagate a track with error in the specified direction
+    //  PropStat err_dir_prop( ETrack& tre,  Surface& srf,
+    //                                            PropDir dir ) ;
+
+    //
+
+    /**
+     *Return the strength of the magnetic field in Tesla.
+     *
+     * @return The strength of the magnetic field in Tesla.
+     */
+    public  double bField()
+    {
+        return _bfac/TRFMath.BFAC;
+    }
+
+
+    /**
+     *output stream
+     * @return  A String representation of this instance.
+     */
+    public String toString()
+    {
+        return "XYPlane  propagation to a DCA surface with constant "
+                + bField() + " Tesla field";
+    }
+
+
+
+    /**
+     * Propagate from XY to dca.
+     * Why is this public?
+     *
+     * @param   _bfac The numerical factor (including the field)
+     * @param   trv The VTrack to propagate.
+     * @param   srf The cylindrical surface to which to propagate.
+     * @param   dir The direction in which to propagate.
+     * @param   deriv The track derivatives to update at the surface srf.
+     * @return The propagation status.
+     */
+    public PropStat dcaXYPropagate( double          _bfac,
+				   VTrack          trv,
+				   Surface         srf,
+				   PropDir         dir,
+				   TrackDerivative deriv )
+    {
+//        System.out.println("running PropXYDCA");
+
+        // Construct return status
+        PropStat pstat = new PropStat();
+
+        // Fetch the originating Surface and check it is a XYPlane surface
+        Surface srf0 = trv.surface();
+        Assert.assertTrue( srf0.pureType().equals(SurfXYPlane.staticType() ));
+        if ( ! srf0.pureType( ).equals(SurfXYPlane.staticType()) )
+            return pstat;
+        SurfXYPlane srf_xy = ( SurfXYPlane ) srf0;
+        //System.out.println("XY Plane surface is OK...");
+         //  check the final surface is a DCA surface
+         Assert.assertTrue( srf.pureType().equals(SurfDCA.staticType() ));
+        if ( ! srf.pureType( ).equals(SurfDCA.staticType()) )
+            return pstat;
+        SurfDCA srf_dca = ( SurfDCA ) srf;
+        //System.out.println("DCA surface is a DCA surface...");
+        // Check that dca surface has zero tilt.
+        boolean tilted = srf_dca.dXdZ() != 0 || srf_dca.dYdZ() != 0;
+        Assert.assertTrue(!tilted);
+        if(tilted)    return pstat;
+         //System.out.println("...and is not tilted");
+
+	// Instantiate the intermediate propagators.
+        PropXYCyl   prop1 = new PropXYCyl( bField() );
+	PropCylDCA  prop2 = new PropCylDCA( bField() );
+	
+
+	// Radius of a cylinder going through the PCA ...
+	// But:
+	//   PropDCACyl requires that the cylinder be at a different radius than the DCA
+	//   so put it 100 microns outside the dca.
+//  	double rhack = Math.abs(trv.vector(IRSIGNED))+0.01;
+//        double rhack = Math.sqrt(srf_dca.x()*srf_dca.x()+srf_dca.y()*srf_dca.y())+0.01;
+        //take this back to 10cm (layer 1)...if this is too small, track misses surface???
+        double rhack = Math.sqrt(10.0);
+	// Instantiate the surface at the intermediate step.
+	SurfCylinder srf_cyl = new SurfCylinder(rhack);
+
+	// Setup for receiving the derivatives.
+	TrackDerivative d1 = null;
+	TrackDerivative d2 = null;
+	if ( deriv != null ){
+	    d1 = new TrackDerivative();
+	    d2 = new TrackDerivative();
+	}
+
+	// Save the track z direction for later use.
+	boolean forward = trv.vector(ITLM_DCA)>=0.;
+
+
+//System.out.println("Propagating!");
+	// Do the propagation in two steps.
+	PropStat p1 = prop1.vecDirProp(trv, srf_cyl, dir, d1);
+	if ( !p1.success() ) return p1;
+//    System.out.println("propagated to fake cylinder, track is: " + trv.toString());
+	PropStat p2 = prop2.vecDirProp(trv,srf_dca,  dir, d2);
+//    System.out.println("propagated to DCA, track is: " + trv.toString());
+	if ( !p2.success() ) return p2;
+
+	// Forward/backward is defined wrt positive z axis.
+/*  mg...I'm not sure if this is what we want...seems to screw up PropXYXY
+        if ( forward ){
+	    trv.setForward();
+	} else{
+	    trv.setBackward();
+	}
+ */
+
+         trv.setForward();
+	// Set the transformation matrix to the product of the those from
+	// the two intermediate steps.
+	if ( deriv != null ){
+	    deriv.set(d2.times(d1));
+	}
+
+	// Set properties of the return value.
+	if ( p2.forward() ){
+	    pstat.setForward();
+	}else if ( p2.backward() ){
+	    pstat.setBackward();
+	} else if ( p2.same() ){
+	    pstat.setSame();
+	}
+	double s = p1.pathDistance() + p2.pathDistance();
+	pstat.setPathDistance(s);
+
+
+
+	return pstat;
+
+    }
+
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman
PropXYXY.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/PropXYXY.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/PropXYXY.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,855 @@
+package org.hps.recon.tracking.kalman;
+
+import org.lcsim.recon.tracking.trfbase.PropDir;
+import org.lcsim.recon.tracking.trfbase.PropDirected;
+import org.lcsim.recon.tracking.trfbase.PropStat;
+import org.lcsim.recon.tracking.trfbase.Propagator;
+import org.lcsim.recon.tracking.trfbase.Surface;
+import org.lcsim.recon.tracking.trfbase.TrackDerivative;
+import org.lcsim.recon.tracking.trfbase.TrackVector;
+import org.lcsim.recon.tracking.trfbase.VTrack;
+import org.lcsim.recon.tracking.trfutil.Assert;
+import org.lcsim.recon.tracking.trfutil.TRFMath;
+import org.lcsim.recon.tracking.trfxyp.SurfXYPlane;
+
+/**
+ * Propagates tracks from one XYPlane to another in a constant field.
+ *<p>
+ * Propagation will fail if either the origin or destination is
+ * not a XYPlane.
+ * Propagator works incorrectly for tracks with very small curvatures
+ *
+ *
+ *@author Norman A. Graf
+ *@version 1.0
+ *
+ */
+public class PropXYXY extends PropDirected {
+
+    // attributes
+    private boolean _debug=false;
+    private double _bfac;
+    private static final int IV = SurfXYPlane.IV;
+    private static final int IZ = SurfXYPlane.IZ;
+    private static final int IDVDU = SurfXYPlane.IDVDU;
+    private static final int IDZDU = SurfXYPlane.IDZDU;
+    private static final int IQP = SurfXYPlane.IQP;
+
+    // static methods
+    /**
+     *Return a String representation of the class' type name.
+     *Included for completeness with the C++ version.
+     *
+     * @return   A String representation of the class' type name.
+     */
+    public static String typeName() {
+        return "PropXYXY";
+    }
+
+    /**
+     *Return a String representation of the class' type name.
+     *Included for completeness with the C++ version.
+     *
+     * @return   A String representation of the class' type name.
+     */
+    public static String staticType() {
+        return typeName();
+    }
+
+    /**
+     *Construct an instance from a constant solenoidal magnetic field in Tesla.
+     *
+     * @param   bfield The magnetic field strength in Tesla.
+     */
+    public PropXYXY(double bfield) {
+        _bfac = TRFMath.BFAC * bfield;
+    }
+
+    /**
+     *Clone an instance.
+     *
+     * @return A Clone of this instance.
+     */
+    public Propagator newPropagator() {
+        return new PropXYXY(bField());
+    }
+
+    /**
+     *Propagate a track without error in the specified direction
+     *and return the derivative matrix in deriv.
+     *
+     * @param   trv The VTrack to propagate.
+     * @param   srf The Surface to which to propagate.
+     * @param   dir The direction in which to propagate.
+     * @param   deriv The track derivatives to update at the surface srf.
+     * @return The propagation status.
+     **/
+    public PropStat vecDirProp(VTrack trv, Surface srf,
+            PropDir dir, TrackDerivative deriv) {
+        PropStat pstat = vec_propagatexyxy_(_bfac, trv, srf, dir, deriv);
+        return pstat;
+    }
+
+    /**
+     *Propagate a track without error in the specified direction.
+     *
+     * @param   trv The VTrack to propagate.
+     * @param   srf The Surface to which to propagate.
+     * @param   dir The direction in which to propagate.
+     * @return The propagation status.
+     */
+    @Override
+    public PropStat vecDirProp(VTrack trv, Surface srf,
+            PropDir dir) {
+        TrackDerivative deriv = null;
+        return vecDirProp(trv, srf, dir, deriv);
+    }
+
+    /**
+     *Return the strength of the magnetic field in Tesla.
+     *
+     * @return The strength of the magnetic field in Tesla.
+     */
+    public double bField() {
+        return _bfac / TRFMath.BFAC;
+    }
+
+    /**
+     *Return a String representation of the class' type name.
+     *Included for completeness with the C++ version.
+     *
+     * @return   A String representation of the class' type name.
+     */
+    public String type() {
+        return staticType();
+    }
+
+    /**
+     *output stream
+     *
+     * @return  A String representation of this instance.
+     */
+    @Override
+    public String toString() {
+        return "XYPlane-XYPlane propagation with constant "
+                + bField() + " Tesla field";
+    }
+
+    // Private function to determine dphi of the propagation
+    double direction(int flag_forward, int sign_dphi,
+            double du,
+            double norm, double cat,
+            double sinphi, double cosphi) {
+
+        int sign_cat = 0;
+        if (du * flag_forward > 0.)
+            sign_cat = 1;
+        if (du * flag_forward < 0.)
+            sign_cat = -1;
+        if (du == 0.) {
+            if (sinphi >= 0.)
+                sign_cat = 1;
+            if (sinphi < 0.)
+                sign_cat = -1;
+        }
+
+        double sin_dphi = norm * sinphi + cat * cosphi * sign_cat;
+        double cos_dphi = -norm * cosphi + cat * sinphi * sign_cat;
+
+        int sign_sindphi = 0;
+        if (sin_dphi > 0.)
+            sign_sindphi = 1;
+        if (sin_dphi < 0.)
+            sign_sindphi = -1;
+        if (sin_dphi == 0.)
+            sign_sindphi = sign_dphi;
+
+        if (Math.abs(cos_dphi) > 1.) {
+            double sn = -1.;
+            if (cos_dphi > 0)
+                sn = 1.;
+            cos_dphi = sn * Math.sqrt(1. - sin_dphi * sin_dphi);
+        }
+        if (Math.abs(sin_dphi) > 1.) {
+            double sn = -1.;
+            if (sin_dphi > 0)
+                sn = 1.;
+            sin_dphi = sn * Math.sqrt(1. - cos_dphi * cos_dphi);
+        }
+
+        double dphi = Math.PI * (sign_dphi - sign_sindphi) + sign_sindphi * Math.acos(cos_dphi);
+        return dphi;
+
+    }
+    //**********************************************************************
+
+    // Private function to propagate a track without error
+    // The corresponding track parameters are:
+    // u (cm) is fixed
+    // 0 - v (cm)
+    // 1 - z (cm)
+    // 2 - dv/du
+    // 3 - dz/du
+    // 4 - q/p   p is momentum of a track, q is its charge
+    // If deriv is nonzero, return the derivative matrix there.
+    PropStat vec_propagatexyxy_(double B, VTrack trv, Surface srf,
+            PropDir dir1,
+            TrackDerivative deriv) {
+
+        // construct return status
+        PropStat pstat = new PropStat();
+
+        PropDir dir = dir1; //need to check constness of this
+        boolean move = Propagator.reduceDirection(dir);
+        if (move)
+            dir = reduce(dir);
+        // fetch the originating surface and vector
+        Surface srf1 = trv.surface();
+        // TrackVector vec1 = trv.get_vector();
+
+        // Check origin is a XYPlane.
+        Assert.assertTrue(srf1.pureType().equals(SurfXYPlane.staticType()));
+        if (!srf1.pureType().equals(SurfXYPlane.staticType()))
+            return pstat;
+        SurfXYPlane sxyp1 = (SurfXYPlane) srf1;
+
+        // Check destination is an XYPlane.
+        Assert.assertTrue(srf.pureType().equals(SurfXYPlane.staticType()));
+        if (!srf.pureType().equals(SurfXYPlane.staticType()))
+            return pstat;
+        SurfXYPlane sxyp2 = (SurfXYPlane) srf;
+
+
+        // If surfaces are the same and no XXX_MOVE is requested we can return now.
+        boolean same = srf.pureEqual(srf1);
+        if(_debug)System.out.println("same=" + same + "; move=" + move + "; " + dir1.toString() + "    " + dir.toString());
+
+        if (same && !move) {
+            if (deriv != null) {
+                deriv.setIdentity();
+            }
+            pstat.setSame();
+            return pstat;
+        }
+
+
+        if (same && dir1.equals(PropDir.NEAREST_MOVE))
+            dir = PropDir.FORWARD;
+
+        //v00.63.04  cng 01/12/01
+        if (Math.abs(B) < 1e-7)
+            return zeroBField(trv, sxyp1, sxyp2, dir1, deriv);
+
+        // Fetch the u's and phi's of the planes and the starting track vector.
+        TrackVector vec = trv.vector();
+        int iphi = SurfXYPlane.NORMPHI;
+        int idist = SurfXYPlane.DISTNORM;
+        double phi_0 = sxyp1.parameter(iphi);
+        double u_0 = sxyp1.parameter(idist);
+        double phi_n = sxyp2.parameter(iphi);
+        double u_n = sxyp2.parameter(idist);
+        if (same && move) {
+            int forw = trv.isForward() ? 1 : -1;
+            int forw_dir = (dir == PropDir.FORWARD) ? 1 : -1;
+            int sn = vec.get(IDVDU) > 0. ? 1 : -1;
+            u_0 += 1.e-7 * (double) (forw * forw_dir * sn);
+        }
+
+        double b1_0 = vec.get(IV);                  // v
+        double b2_0 = vec.get(IZ);                  // z
+        double b3_0 = vec.get(IDVDU);               // dv/du
+        double b4_0 = vec.get(IDZDU);               // dz/du
+        double b5_0 = vec.get(IQP);                 // q/p
+
+        double phi_u = phi_0 - phi_n;
+
+        double cosphi_u = Math.cos(phi_u);
+        double sinphi_u = Math.sin(phi_u);
+//         System.out.println( "PropXYXY._vec_propagate: phi_u = "+phi_u);
+        // check if du == 0 ( that is track moves parallel to the destination plane )
+        double du_du_0 = cosphi_u - b3_0 * sinphi_u;
+        if (du_du_0 == 0.)
+            return pstat;
+
+        double a_hat_u = 1. / du_du_0;
+        double a_hat_u2 = a_hat_u * a_hat_u;
+
+        double u = u_0 * cosphi_u - b1_0 * sinphi_u;
+        double b1 = b1_0 * cosphi_u + u_0 * sinphi_u;
+        double b2 = b2_0;
+        double b3 = (b3_0 * cosphi_u + sinphi_u) * a_hat_u;
+        double b4 = b4_0 * a_hat_u;
+        double b5 = b5_0;
+
+        int sign_du0 = 0;
+        if (trv.isForward())
+            sign_du0 = 1;
+        if (trv.isBackward())
+            sign_du0 = -1;
+        if (sign_du0 == 0) {
+            System.out.println("PropXYXY._vec_propagate: Unknown direction of a track ");
+            System.exit(1);
+        }
+        int sign_du = 0;
+        if (du_du_0 * sign_du0 > 0)
+            sign_du = 1;
+        if (du_du_0 * sign_du0 < 0)
+            sign_du = -1;
+
+        // check that q/p != 0
+        Assert.assertTrue(b5 != 0.);
+
+        // 1/curv of the track is r
+        double r = 1 / (b5 * B) * Math.sqrt(1 + b3_0 * b3_0) / Math.sqrt(1 + b3_0 * b3_0 + b4_0 * b4_0);
+        double b3_hat = Math.sqrt(1 + b3 * b3);
+        double b34_hat = Math.sqrt(1 + b3 * b3 + b4 * b4);
+        double b3_hat2 = b3_hat * b3_hat;
+        double b34_hat2 = b34_hat * b34_hat;
+        double cosphi = -b3 * sign_du / b3_hat;
+        double sinphi = sign_du / b3_hat;
+        double rsinphi = 1. / (b5 * B) * sign_du / b34_hat;
+        double rcosphi = -b3 / (b5 * B) * sign_du / b34_hat;
+
+        double du = u_n - u;
+        double norm = du / r - cosphi;
+        if(_debug)System.out.println("PropXYXY._vec_propagate: u_n = " + u_n + "; u = " + u + "; r = " + r);
+
+        // xy-xy propagation failed : noway to the new plane
+        if (Math.abs(norm) > 1.)
+            return pstat;
+
+        double cat = Math.sqrt(1. - norm * norm);
+        int flag_forward = 0;
+        int sign_dphi = 0;
+
+        if (dir.equals(PropDir.NEAREST)) {
+            // try forward propagation
+            flag_forward = 1;
+            if (b5 * B > 0.)
+                sign_dphi = 1;
+            if (b5 * B < 0.)
+                sign_dphi = -1;
+            double dphi1 =
+                    direction(flag_forward, sign_dphi, du, norm, cat, sinphi, cosphi);
+            // try backward propagation
+            flag_forward = -1;
+            if (b5 * B > 0.)
+                sign_dphi = -1;
+            if (b5 * B < 0.)
+                sign_dphi = 1;
+            double dphi2 =
+                    direction(flag_forward, sign_dphi, du, norm, cat, sinphi, cosphi);
+            if (Math.abs(dphi2) > Math.abs(dphi1)) {
+                flag_forward = -flag_forward;
+                sign_dphi = -sign_dphi;
+            }
+        } else if (dir.equals(PropDir.FORWARD)) {
+            flag_forward = 1;
+            if (b5 * B > 0.)
+                sign_dphi = 1;
+            if (b5 * B < 0.)
+                sign_dphi = -1;
+        } else if (dir.equals(PropDir.BACKWARD)) {
+            flag_forward = -1;
+            if (b5 * B > 0.)
+                sign_dphi = -1;
+            if (b5 * B < 0.)
+                sign_dphi = 1;
+        } else {
+            System.out.println("PropXYXY._vec_propagate: Unknown direction.");
+            System.exit(1);
+        }
+
+        int sign_cat = 0;
+        if (du * sign_dphi * b5 * B > 0.)
+            sign_cat = 1;
+        if (du * sign_dphi * b5 * B < 0.)
+            sign_cat = -1;
+        if (du == 0.) {
+            if (sinphi >= 0.)
+                sign_cat = 1;
+            if (sinphi < 0.)
+                sign_cat = -1;
+        }
+
+        double sin_dphi = norm * sinphi + cat * cosphi * sign_cat;
+        double cos_dphi = -norm * cosphi + cat * sinphi * sign_cat;
+        if (cos_dphi > 1.)
+            cos_dphi = 1.;
+        if (cos_dphi < -1.)
+            cos_dphi = -1.;
+
+        int sign_sindphi = 0;
+        if (sin_dphi > 0.)
+            sign_sindphi = 1;
+        if (sin_dphi < 0.)
+            sign_sindphi = -1;
+        if (sin_dphi == 0.)
+            sign_sindphi = sign_dphi;
+
+        double dphi = Math.PI * (sign_dphi - sign_sindphi) + sign_sindphi * Math.acos(cos_dphi);
+
+        // check that I didn't make any mistakes
+
+        Assert.assertTrue(Math.abs(Math.sin(dphi) - sin_dphi) < 1.e-5);
+
+        // check if dun == 0 ( that is track moves parallel to the destination plane)
+        double du_n_du = cos_dphi - b3 * sin_dphi;
+        if (du_n_du == 0.)
+            return pstat;
+
+        double a_hat_dphi = 1. / du_n_du;
+        double a_hat_dphi2 = a_hat_dphi * a_hat_dphi;
+        double c_hat_dphi = sin_dphi + b3 * cos_dphi;
+
+        double b1_n = b1 + rsinphi * (1 - cos_dphi) - rcosphi * sin_dphi;
+        double b2_n = b2 + b4 / (b5 * B) * sign_du / b34_hat * dphi;
+        double b3_n = c_hat_dphi * a_hat_dphi;
+        double b4_n = b4 * a_hat_dphi;
+        double b5_n = b5;
+        if(_debug)System.out.println(trv.toString());
+        if(_debug) System.out.println("PropXYXY._vec_propagate: sign_du0=" + sign_du0 + "; du_du_0=" + du_du_0);
+        if(_debug)System.out.println("PropXYXY._vec_propagate: sign_du=" + sign_du + "; b3_hat=" + b3_hat);
+        if(_debug)System.out.println("PropXYXY._vec_propagate: sign_cat=" + sign_cat + "; cosphi=" + cosphi
+                + "; sinphi=" + sinphi + "; cat=" + cat);
+        if(_debug)System.out.println("PropXYXY._vec_propagate: a_hat_dphi=" + a_hat_dphi + "; cos_dphi=" + cos_dphi
+                + "; norm=" + norm);
+        if(_debug)System.out.println("PropXYXY._vec_propagate: b3=" + b3 + "; sin_dphi=" + sin_dphi);
+        if(_debug)System.out.println("PropXYXY._vec_propagate: b4_0=" + b4_0 + "; b4=" + b4 + "; b4_n=" + b4_n);
+
+        // double u_n_0 = u_n*cosphi_u + b1_n*sinphi_u;
+
+        // check if track crossed original plane during the propagation
+        // switch (dir) {
+        //  if( dir.equals(PropDir.FORWARD:
+        //   if((u_n_0 - u_0)*sign_du0<0) return pstat;
+        //  break;
+        //  if( dir.equals(PropDir.BACKWARD:
+        //   if((u_n_0 - u_0)*sign_du0>0) return pstat;
+        //  break;
+        // }
+
+        int sign_dun = 0;
+        if (du_n_du * sign_du > 0)
+            sign_dun = 1;
+        if (du_n_du * sign_du < 0)
+            sign_dun = -1;
+
+        vec.set(IV, b1_n);
+        vec.set(IZ, b2_n);
+        vec.set(IDVDU, b3_n);
+        vec.set(IDZDU, b4_n);
+        vec.set(IQP, b5_n);
+        if(_debug)System.out.println("PropXYXY._vec_propagate:  sign_dun = "+sign_dun+"; du_n_du = "+du_n_du+"; sign_du="+sign_du);
+
+        // Update trv
+        trv.setSurface(srf.newPureSurface());
+        trv.setVector(vec);
+
+        // set new direction of the track
+        if (sign_dun == 1)
+            trv.setForward();
+        if (sign_dun == -1)
+            trv.setBackward();
+
+        // Calculate sT.
+        double crv = B * b5;
+        double dv = b1_n - b1;
+        double dxy = Math.sqrt(du * du + dv * dv);
+        double arg = 0.5 * crv * dxy;
+        double dst = dxy * TRFMath.asinrat(arg);
+
+        // Calculate s.
+        double dz = b2_n - b2;
+        Assert.assertTrue(flag_forward == 1 || flag_forward == -1);
+        double ds = ((double) (flag_forward)) * Math.sqrt(dst * dst + dz * dz);
+
+        // Set the return status.
+        pstat.setPathDistance(ds);
+        //(flag_forward==1)?pstat.set_forward():pstat.set_backward();
+
+        // exit now if user did not ask for error matrix.
+        if (deriv == null)
+            return pstat;
+
+        // du_d0
+
+        double du_db1_0 = -sinphi_u;
+
+        // db1_d0
+
+        double db1_db1_0 = cosphi_u;
+
+        // db3_d0
+
+        double db3_db3_0 = a_hat_u2;
+
+        // db4_d0
+
+        double db4_db3_0 = b4_0 * sinphi_u * a_hat_u2;
+        double db4_db4_0 = a_hat_u;
+
+        // dr_d
+
+        double dr_db3 = r * b3 * b4 * b4 / (b3_hat2 * b34_hat2);
+        double dr_db4 = -r * b4 / b34_hat2;
+        double dr_db5 = -r / b5;
+
+        // dcosphi_d
+
+        double dcosphi_db3 = -sign_du / b3_hat - cosphi * b3 / b3_hat2;
+
+        // dsinphi_d
+
+        double dsinphi_db3 = -sinphi * b3 / b3_hat2;
+
+        // dcat_d
+
+        double dcat_db3 = norm / cat * (du / (r * r) * dr_db3 + dcosphi_db3);
+        double dcat_db4 = norm / cat * du / (r * r) * dr_db4;
+        double dcat_db5 = norm / cat * du / (r * r) * dr_db5;
+        double dcat_du = norm / (cat * r);
+
+        // dnorm_d
+
+        double dnorm_db3 = -du / (r * r) * dr_db3 - dcosphi_db3;
+        double dnorm_db4 = -du / (r * r) * dr_db4;
+        double dnorm_db5 = -du / (r * r) * dr_db5;
+        double dnorm_du = -1. / r;
+
+        // dcos_dphi_d
+
+        double dcos_dphi_db3 = -cosphi * dnorm_db3 - norm * dcosphi_db3
+                + sign_cat * (sinphi * dcat_db3 + cat * dsinphi_db3);
+        double dcos_dphi_db4 = -cosphi * dnorm_db4 + sign_cat * sinphi * dcat_db4;
+        double dcos_dphi_db5 = -cosphi * dnorm_db5 + sign_cat * sinphi * dcat_db5;
+        double dcos_dphi_du = -cosphi * dnorm_du + sign_cat * sinphi * dcat_du;
+
+        // dsin_dphi_d
+
+        double dsin_dphi_db3 = sinphi * dnorm_db3 + norm * dsinphi_db3
+                + sign_cat * (cosphi * dcat_db3 + cat * dcosphi_db3);
+        double dsin_dphi_db4 = sinphi * dnorm_db4 + sign_cat * cosphi * dcat_db4;
+        double dsin_dphi_db5 = sinphi * dnorm_db5 + sign_cat * cosphi * dcat_db5;
+        double dsin_dphi_du = sinphi * dnorm_du + sign_cat * cosphi * dcat_du;
+
+        // ddphi_d
+
+        double ddphi_db3;
+        double ddphi_db4;
+        double ddphi_db5;
+        double ddphi_du;
+        if (Math.abs(sin_dphi) > 0.5) {
+            ddphi_db3 = -dcos_dphi_db3 / sin_dphi;
+            ddphi_db4 = -dcos_dphi_db4 / sin_dphi;
+            ddphi_db5 = -dcos_dphi_db5 / sin_dphi;
+            ddphi_du = -dcos_dphi_du / sin_dphi;
+        } else {
+            ddphi_db3 = dsin_dphi_db3 / cos_dphi;
+            ddphi_db4 = dsin_dphi_db4 / cos_dphi;
+            ddphi_db5 = dsin_dphi_db5 / cos_dphi;
+            ddphi_du = dsin_dphi_du / cos_dphi;
+        }
+
+        // da_hat_dphi_d
+
+        double da_hat_dphi_db3 = -a_hat_dphi2
+                * (dcos_dphi_db3 - sin_dphi - b3 * dsin_dphi_db3);
+        double da_hat_dphi_db4 = -a_hat_dphi2 * (dcos_dphi_db4 - b3 * dsin_dphi_db4);
+        double da_hat_dphi_db5 = -a_hat_dphi2 * (dcos_dphi_db5 - b3 * dsin_dphi_db5);
+        double da_hat_dphi_du = -a_hat_dphi2 * (dcos_dphi_du - b3 * dsin_dphi_du);
+
+        // dc_hat_dphi_d
+
+        double dc_hat_dphi_db3 = b3 * dcos_dphi_db3 + dsin_dphi_db3 + cos_dphi;
+        double dc_hat_dphi_db4 = b3 * dcos_dphi_db4 + dsin_dphi_db4;
+        double dc_hat_dphi_db5 = b3 * dcos_dphi_db5 + dsin_dphi_db5;
+        double dc_hat_dphi_du = b3 * dcos_dphi_du + dsin_dphi_du;
+
+        // db1_n_d
+
+        double db1_n_db1 = 1;
+        double db1_n_db3 = (dr_db3 * sinphi + r * dsinphi_db3) * (1 - cos_dphi)
+                - rsinphi * dcos_dphi_db3
+                - dr_db3 * cosphi * sin_dphi - r * dcosphi_db3 * sin_dphi
+                - rcosphi * dsin_dphi_db3;
+        double db1_n_db4 = dr_db4 * sinphi * (1 - cos_dphi) - rsinphi * dcos_dphi_db4
+                - dr_db4 * cosphi * sin_dphi - rcosphi * dsin_dphi_db4;
+        double db1_n_db5 = dr_db5 * sinphi * (1 - cos_dphi) - rsinphi * dcos_dphi_db5
+                - dr_db5 * cosphi * sin_dphi - rcosphi * dsin_dphi_db5;
+        double db1_n_du = -rsinphi * dcos_dphi_du - rcosphi * dsin_dphi_du;
+
+        // db2_n_d
+
+        double db2_n_db2 = 1.;
+        double db2_n_db3 = 1. / (b5 * B) * b4 * sign_du / b34_hat
+                * (-dphi * b3 / b34_hat2 + ddphi_db3);
+        double db2_n_db4 = 1. / (b5 * B) * sign_du / b34_hat
+                * (-dphi * b4 * b4 / b34_hat2 + b4 * ddphi_db4 + dphi);
+        double db2_n_db5 = 1. / (b5 * B) * b4 * sign_du / b34_hat * (ddphi_db5 - dphi / b5);
+        double db2_n_du = 1. / (b5 * B) * b4 * sign_du / b34_hat * ddphi_du;
+
+        // db3_n_d
+
+        double db3_n_db3 = a_hat_dphi * dc_hat_dphi_db3 + da_hat_dphi_db3 * c_hat_dphi;
+        double db3_n_db4 = a_hat_dphi * dc_hat_dphi_db4 + da_hat_dphi_db4 * c_hat_dphi;
+        double db3_n_db5 = a_hat_dphi * dc_hat_dphi_db5 + da_hat_dphi_db5 * c_hat_dphi;
+        double db3_n_du = a_hat_dphi * dc_hat_dphi_du + da_hat_dphi_du * c_hat_dphi;
+
+        // db4_n_d
+
+        double db4_n_db3 = b4 * da_hat_dphi_db3;
+        double db4_n_db4 = b4 * da_hat_dphi_db4 + a_hat_dphi;
+        double db4_n_db5 = b4 * da_hat_dphi_db5;
+        double db4_n_du = b4 * da_hat_dphi_du;
+
+        // db5_n_d
+
+        // db1_n_d0
+
+        double db1_n_db1_0 = db1_n_du * du_db1_0 + db1_n_db1 * db1_db1_0;
+        double db1_n_db2_0 = 0.;
+        double db1_n_db3_0 = db1_n_db3 * db3_db3_0 + db1_n_db4 * db4_db3_0;
+        double db1_n_db4_0 = db1_n_db4 * db4_db4_0;
+        double db1_n_db5_0 = db1_n_db5;
+
+        // db2_n_d0
+
+        double db2_n_db1_0 = db2_n_du * du_db1_0;
+        double db2_n_db2_0 = db2_n_db2;
+        double db2_n_db3_0 = db2_n_db3 * db3_db3_0 + db2_n_db4 * db4_db3_0;
+        double db2_n_db4_0 = db2_n_db4 * db4_db4_0;
+        double db2_n_db5_0 = db2_n_db5;
+
+        // db3_n_d0
+
+        double db3_n_db1_0 = db3_n_du * du_db1_0;
+        double db3_n_db2_0 = 0.;
+        double db3_n_db3_0 = db3_n_db3 * db3_db3_0 + db3_n_db4 * db4_db3_0;
+        double db3_n_db4_0 = db3_n_db4 * db4_db4_0;
+        double db3_n_db5_0 = db3_n_db5;
+
+        // db4_n_d0
+
+        double db4_n_db1_0 = db4_n_du * du_db1_0;
+        double db4_n_db2_0 = 0.;
+        double db4_n_db3_0 = db4_n_db3 * db3_db3_0 + db4_n_db4 * db4_db3_0;
+        double db4_n_db4_0 = db4_n_db4 * db4_db4_0;
+        double db4_n_db5_0 = db4_n_db5;
+
+        // db5_n_d0
+
+        double db5_n_db1_0 = 0.;
+        double db5_n_db2_0 = 0.;
+        double db5_n_db3_0 = 0.;
+        double db5_n_db4_0 = 0.;
+        double db5_n_db5_0 = 1.;
+
+
+        deriv.set(IV, IV, db1_n_db1_0);
+        deriv.set(IV, IZ, db1_n_db2_0);
+        deriv.set(IV, IDVDU, db1_n_db3_0);
+        deriv.set(IV, IDZDU, db1_n_db4_0);
+        deriv.set(IV, IQP, db1_n_db5_0);
+        deriv.set(IZ, IV, db2_n_db1_0);
+        deriv.set(IZ, IZ, db2_n_db2_0);
+        deriv.set(IZ, IDVDU, db2_n_db3_0);
+        deriv.set(IZ, IDZDU, db2_n_db4_0);
+        deriv.set(IZ, IQP, db2_n_db5_0);
+        deriv.set(IDVDU, IV, db3_n_db1_0);
+        deriv.set(IDVDU, IZ, db3_n_db2_0);
+        deriv.set(IDVDU, IDVDU, db3_n_db3_0);
+        deriv.set(IDVDU, IDZDU, db3_n_db4_0);
+        deriv.set(IDVDU, IQP, db3_n_db5_0);
+        deriv.set(IDZDU, IV, db4_n_db1_0);
+        deriv.set(IDZDU, IZ, db4_n_db2_0);
+        deriv.set(IDZDU, IDVDU, db4_n_db3_0);
+        deriv.set(IDZDU, IDZDU, db4_n_db4_0);
+        deriv.set(IDZDU, IQP, db4_n_db5_0);
+        deriv.set(IQP, IV, db5_n_db1_0);
+        deriv.set(IQP, IZ, db5_n_db2_0);
+        deriv.set(IQP, IDVDU, db5_n_db3_0);
+        deriv.set(IQP, IDZDU, db5_n_db4_0);
+        deriv.set(IQP, IQP, db5_n_db5_0);
+
+        return pstat;
+
+    }
+
+    //cng
+    PropStat zeroBField(VTrack trv, SurfXYPlane sxyp1,
+            SurfXYPlane sxyp2, PropDir dir1,
+            TrackDerivative deriv) {
+        // construct return status
+        PropStat pstat = new PropStat();
+
+        PropDir dir = dir1; //need to check constness of this
+        boolean move = Propagator.reduceDirection(dir);
+        boolean same = sxyp2.pureEqual(sxyp1);
+
+        // There is only one solution. Can't XXX_MOVE
+        if (same && move)
+            return pstat;
+
+        if (same) {
+            if (deriv != null) {
+                deriv.setIdentity();
+            }
+            pstat.setSame();
+            return pstat;
+        }
+
+        TrackVector vec = trv.vector();
+        double v0 = vec.get(IV);
+        double z0 = vec.get(IZ);
+        double dvdu0 = vec.get(IDVDU);
+        double dzdu0 = vec.get(IDZDU);
+
+        double du0 = 1.;
+        if (trv.isBackward())
+            du0 = -1.;
+
+        double phi0 = sxyp1.parameter(SurfXYPlane.NORMPHI);
+        double cphi0 = Math.cos(phi0);
+        double sphi0 = Math.sin(phi0);
+        double u0 = sxyp1.parameter(SurfXYPlane.DISTNORM);
+
+        double phi1 = sxyp2.parameter(SurfXYPlane.NORMPHI);
+        double cphi1 = Math.cos(phi1);
+        double sphi1 = Math.sin(phi1);
+        double u1 = sxyp2.parameter(SurfXYPlane.DISTNORM);
+
+        double a = (cphi0 - dvdu0 * sphi0) * du0;
+        double b = (sphi0 + dvdu0 * cphi0) * du0;
+        double c = dzdu0 * du0;
+
+        double x0 = u0 * cphi0 - v0 * sphi0;
+        double y0 = u0 * sphi0 + v0 * cphi0;
+
+        double ap = u1 * cphi1;
+        double bp = u1 * sphi1;
+        double cp = 0;
+
+        double xp = ap;
+        double yp = bp;
+        double zp = 0.0;
+
+        double denom = a * ap + b * bp + c * cp;
+
+        if (denom == 0.)
+            return pstat;
+
+        double S = ((xp - x0) * ap + (yp - y0) * bp + (zp - z0) * cp) / denom;
+
+        double x1 = x0 + S * a;
+        double y1 = y0 + S * b;
+        double z1 = z0 + S * c;
+
+        boolean forward = S > 0. ? true : false;
+
+        if (dir == PropDir.FORWARD && !forward)
+            return pstat;
+        if (dir == PropDir.BACKWARD && forward)
+            return pstat;
+
+        double v1 = y1 * cphi1 - x1 * sphi1;
+
+        double v01 = y0 * cphi1 - x0 * sphi1;
+        double u01 = y0 * sphi1 + x0 * cphi1;
+        double z01 = z0;
+
+        if (u01 == u1)
+            return pstat;
+
+        double dvdu1 = (v1 - v01) / (u1 - u01);
+        double dzdu1 = (z1 - z01) / (u1 - u01);
+
+        vec.set(IV, v1);
+        vec.set(IZ, z1);
+        vec.set(IDVDU, dvdu1);
+        vec.set(IDZDU, dzdu1);
+
+        // Update trv
+        trv.setSurface(sxyp2.newPureSurface());
+        trv.setVector(vec);
+        // set new direction of the track
+        if (b * sphi1 + a * cphi1 > 0)
+            trv.setForward();
+        else
+            trv.setBackward();
+
+        // Calculate s.
+        double ds = S * Math.sqrt(a * a + b * b + c * c);
+
+        // Set the return status.
+        pstat.setPathDistance(ds);
+
+        if (deriv == null)
+            return pstat;
+
+        double dx0dv0 = -sphi0;
+        double dy0dv0 = cphi0;
+
+        double dadv_du = -sphi0 * du0;
+        double dbdv_du = cphi0 * du0;
+        double dcdz_du = du0;
+
+        double ddenomdv_du = dadv_du * ap + dbdv_du * bp;
+        double ddenomdz_du = dcdz_du * cp;
+
+
+        double dSdv0 = -(dx0dv0 * ap + dy0dv0 * bp) / denom;
+        double dSdz0 = -cp / denom;
+        double dSdv_du = -S / denom * ddenomdv_du;
+        double dSdz_du = -S / denom * ddenomdz_du;
+
+        double dy1dv0 = dy0dv0 + dSdv0 * b;
+        double dx1dv0 = dx0dv0 + dSdv0 * a;
+        double dx1dv_du = dSdv_du * a + S * dadv_du;
+        double dy1dv_du = dSdv_du * b + S * dbdv_du;
+
+        double du01dv0 = dy0dv0 * sphi1 + dx0dv0 * cphi1;
+        double dv01dv0 = dy0dv0 * cphi1 - dx0dv0 * sphi1;
+
+        double dv1dv0 = dy1dv0 * cphi1 - dx1dv0 * sphi1;
+        double dv1dv_du = dy1dv_du * cphi1 - dx1dv_du * sphi1;
+
+        double dz1dz0 = 1 + dSdz0 * c;
+        double dz1dv0 = dSdv0 * c;
+        double dz1dv_du = dSdv_du * c;
+        double dz1dz_du = dSdz_du * c + S * dcdz_du;
+
+        double dv_du1dv0 = ((dv1dv0 - dv01dv0) * (u1 - u01) + du01dv0 * (v1 - v01)) / (u1 - u01) / (u1 - u01);
+        double dv_du1dv_du = dv1dv_du / (u1 - u01);
+
+        double dz_du1dv0 = (dz1dv0 * (u1 - u01) + du01dv0 * (z1 - z01)) / (u1 - u01) / (u1 - u01);
+        double dz_du1dz0 = (dz1dz0 - 1.) / (u1 - u01);
+        double dz_du1dv_du = dz1dv_du / (u1 - u01);
+        double dz_du1dz_du = dz1dz_du / (u1 - u01);
+
+        //Set the track derivatives...
+        deriv.setIdentity();
+
+        deriv.set(IV, IV, dv1dv0);
+        deriv.set(IV, IDVDU, dv1dv_du);
+
+        deriv.set(IZ, IV, dz1dv0);
+        deriv.set(IZ, IZ, dz1dz0);
+        deriv.set(IZ, IDVDU, dz1dv_du);
+        deriv.set(IZ, IDZDU, dz1dz_du);
+
+        deriv.set(IDVDU, IV, dv_du1dv0);
+        deriv.set(IDVDU, IDVDU, dv_du1dv_du);
+
+        deriv.set(IDZDU, IV, dz_du1dv0);
+        deriv.set(IDZDU, IZ, dz_du1dz0);
+        deriv.set(IDZDU, IDVDU, dz_du1dv_du);
+        deriv.set(IDZDU, IDZDU, dz_du1dz_du);
+
+        deriv.set(IQP, IQP, 1.0);
+
+        return pstat;
+
+    }
+    //cng
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman
ShapeDispatcher.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/ShapeDispatcher.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/ShapeDispatcher.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,117 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.hps.recon.tracking.kalman;
+
+import org.lcsim.detector.solids.Box;
+import org.lcsim.detector.solids.ISolid;
+import org.lcsim.detector.solids.Point3D;
+import org.lcsim.detector.solids.Trd;
+import org.lcsim.detector.solids.Tube;
+import org.lcsim.event.Track;
+import org.lcsim.fit.helicaltrack.HelicalTrackFit;
+import org.lcsim.recon.tracking.seedtracker.SeedCandidate;
+import org.lcsim.recon.tracking.seedtracker.SeedTrack;
+import org.lcsim.recon.tracking.trffit.HTrack;
+
+/**
+ * This class takes a solid and dispatches it to its Helper class,
+ * for any of the possible Helper methods.
+ *
+ * @author ecfine
+ */
+public class ShapeDispatcher implements ShapeHelper{
+
+    public void printShape(ISolid solid) {
+         if (solid instanceof Trd) {
+            TrdHelper trapHelper = new TrdHelper();
+            trapHelper.printShape(solid);
+        } else if (solid instanceof Tube) {
+//            TubeHelper tubeHelper = new TubeHelper();
+//            tubeHelper.printShape(solid);
+        } else if (solid instanceof Box) {
+            BoxHelper boxHelper = new BoxHelper();
+            boxHelper.printShape(solid);
+        } else {
+             System.out.println("Error! I don't recognize this shape!");
+        }
+    }
+
+    public void printLocalCoords(ISolid solid) {
+         if (solid instanceof Trd) {
+            TrdHelper trapHelper = new TrdHelper();
+            trapHelper.printLocalCoords(solid);
+        } else if (solid instanceof Tube) {
+//            TubeHelper tubeHelper = new TubeHelper();
+//            tubeHelper.printLocalCoords(solid);
+        } else if (solid instanceof Box) {
+            BoxHelper boxHelper = new BoxHelper();
+            boxHelper.printLocalCoords(solid);
+        } else {
+             System.out.println("Error! I don't recognize this shape!");
+        }
+    }
+
+    public void printGlobalCoords(ISolid solid) {
+        if (solid instanceof Trd) {
+            TrdHelper trapHelper = new TrdHelper();
+            trapHelper.printGlobalCoords(solid);
+        } else if (solid instanceof Tube) {
+//            TubeHelper tubeHelper = new TubeHelper();
+//            tubeHelper.printGlobalCoords(solid);
+        } else if (solid instanceof Box) {
+            BoxHelper boxHelper = new BoxHelper();
+            boxHelper.printGlobalCoords(solid);
+        } else {
+             System.out.println("Error! I don't recognize this shape!");
+        }
+    }
+
+    public HTrack addIntercept(ISolid solid, HTrack ht) {
+        HTrack track = null;
+        if (solid instanceof Trd) {
+            TrdHelper trapHelper = new TrdHelper();
+//            track = trapHelper.addIntercept(solid, ht);
+        } else {
+            System.out.println("This shape is not supported yet");
+
+        }
+        return track;
+    }
+
+    public HelicalTrackFit trackToHelix(Track track) {
+        SeedTrack stEle = (SeedTrack) track;
+        SeedCandidate seedEle = stEle.getSeedCandidate();
+        HelicalTrackFit ht = seedEle.getHelix();
+        return ht;
+    }
+
+    public KalmanSurface getKalmanSurf(ISolid solid) {
+        KalmanSurface surf = null;
+        if (solid instanceof Trd) {
+            TrdHelper trapHelper = new TrdHelper();
+            surf = trapHelper.getKalmanSurf(solid);
+        } else {
+            System.out.println("This solid is not supported yet");
+        }
+        return surf;
+    }
+
+    public void findIntersection(ISolid solid, Track track) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    public boolean pointIsOnSolid(ISolid solid, Point3D hitPoint) {
+        boolean pointOnSolid = false;
+        if (solid instanceof Trd){
+            TrdHelper trapHelper = new TrdHelper();
+            pointOnSolid = trapHelper.pointIsOnSolid(solid, hitPoint);
+        } else {
+            System.out.print("This solid is not supported yet");
+        }
+        return pointOnSolid;
+
+   }
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman
ShapeHelper.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/ShapeHelper.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/ShapeHelper.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,35 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.hps.recon.tracking.kalman;
+
+import org.lcsim.detector.solids.ISolid;
+import org.lcsim.event.Track;
+
+/**
+ * Interface for dealing with lcsim solids and converting them to trf surfaces.
+ * Most of the classes which extend this are basically empty, with the exception
+ * of the TrdHelper, which has some geometry things, and ShapeDispatcher, which
+ * dispatches solids to the correct helper.
+ * 
+ * @author ecfine
+ */
+public interface ShapeHelper {
+
+    /* Prints the shape of the solid */
+    public void printShape(ISolid solid);
+
+    /* Prints the local coordinates of the solid */
+    public void printLocalCoords(ISolid solid);
+
+    /* Prints the global coordinates of the solid */
+    public void printGlobalCoords(ISolid solid);
+
+    /* Finds the intersection of a solid and a track */
+    public void findIntersection(ISolid solid, Track track);
+
+    public KalmanSurface getKalmanSurf(ISolid solid);
+
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman
ThinXYPlaneMs.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/ThinXYPlaneMs.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/ThinXYPlaneMs.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,212 @@
+package org.hps.recon.tracking.kalman;
+// ThinXYPlaneMs
+
+import org.lcsim.recon.tracking.trfbase.ETrack;
+import org.lcsim.recon.tracking.trfbase.Interactor;
+import org.lcsim.recon.tracking.trfbase.PropDir;
+import org.lcsim.recon.tracking.trfbase.Surface;
+import org.lcsim.recon.tracking.trfbase.TrackError;
+import org.lcsim.recon.tracking.trfbase.TrackVector;
+import org.lcsim.recon.tracking.trfutil.Assert;
+import org.lcsim.recon.tracking.trfutil.TRFMath;
+import org.lcsim.recon.tracking.trfxyp.SurfXYPlane;
+/**
+ *
+ * Class for modifying the covariance matrix of a track to account
+ * for multiple scattering at a thin XY-plane whose material is
+ *represented by the number of radiation lengths.
+ *
+ *@author Norman A. Graf
+ *@version 1.0
+ *
+ */
+public class ThinXYPlaneMs extends Interactor
+{
+    
+    // static methods
+    
+    /**
+     *Return a String representation of the class' type name.
+     *Included for completeness with the C++ version.
+     *
+     * @return   A String representation of the class' type name.
+     */
+    public static String typeName()
+    { return "ThinXYPlaneMs"; }
+    
+    /**
+     *Return a String representation of the class' type name.
+     *Included for completeness with the C++ version.
+     *
+     * @return   A String representation of the class' type name.
+     */
+    public static String staticType()
+    { return typeName(); }
+    
+    // static attributes
+    // Assign track parameter indices.
+    
+    private static final int IV = SurfXYPlane.IV;
+    private static final int IZ   = SurfXYPlane.IZ;
+    private static final int IDVDU = SurfXYPlane.IDVDU;
+    private static final int IDZDU = SurfXYPlane.IDZDU;
+    private static final int IQP  = SurfXYPlane.IQP;
+    
+    //attributes
+    private  double _radLength;
+    
+    //non-static methods
+    
+    // Constructor.  The Interactor is constructed with the
+    // appropriate number of radiation lengths.
+    
+    /**
+     * Construct an instance from the number of radiation
+     * lengths of the thin xy plane material.
+     * The Interactor is constructed with the
+     * appropriate number of radiation lengths.
+     *
+     * @param   radLength The thickness of the material in radiation lengths.
+     */
+    public ThinXYPlaneMs(double radLength)
+    {
+        _radLength = radLength;
+    }
+    
+    /**
+     *Interact the given track in this xy plane,
+     *using the thin material approximation for multiple scattering.
+     *Note that the track parameters are not modified. Only the
+     *covariance matrix is updated to reflect the uncertainty caused
+     *by traversing the thin xy plane of material.
+     *
+     * @param   tre The ETrack to scatter.
+     */
+    public void interact(ETrack tre)
+    {
+        
+        // This can only be used with XYplanes... check that we have one..
+        
+        SurfXYPlane XYpl = new SurfXYPlane( 10.0, 0.0 );
+        Surface srf = tre.surface();
+        Assert.assertTrue( srf.pureType().equals(XYpl.pureType()) );
+        
+        TrackError cleanError = tre.error();
+        TrackError newError = new TrackError(cleanError);
+        
+        // set the rms scattering appropriate to this momentum
+        
+        // Theta = (0.0136 GeV)*(z/p)*(sqrt(radLength))*(1+0.038*log(radLength))
+        
+        
+        
+        TrackVector theVec = tre.vector();
+        double trackMomentum = theVec.get(IQP);
+        
+        double f = theVec.get(IDVDU);
+        double g = theVec.get(IDZDU);
+        
+        double theta = Math.atan(Math.sqrt(f*f + g*g));
+        double phi = f!=0. ? Math.atan(Math.sqrt((g*g)/(f*f))) : TRFMath.PI2;
+        if ( f==0 && g<0 ) phi=3*TRFMath.PI2;
+        if((f<0)&&(g>0))
+            phi = Math.PI - phi;
+        if((f<0)&&(g<0))
+            phi = Math.PI + phi;
+        if((f>0)&&(g<0))
+            phi = 2*Math.PI - phi;
+        
+        double trueLength = _radLength/Math.cos(theta);
+        
+        double stdTheta = (0.0136)*trackMomentum*Math.sqrt(trueLength)*
+                (1 + 0.038*Math.log(trueLength));
+        
+        double uhat = Math.sqrt(1-Math.sin(theta)*Math.sin(theta));
+        double vhat = Math.sin(theta)*Math.cos(phi);
+        double zhat = Math.sin(theta)*Math.sin(phi);
+        
+        double Qvu,Qzu,Qvz;
+        
+        // The MS covariance matrix can now be set.
+        
+        // **************** code for matrix ***********************//
+        
+        // Insert values for upper triangle... use symmetry to set lower.
+        
+        double norm = Math.sqrt(vhat*vhat + zhat*zhat);
+        
+        Qvu = (zhat/(norm*uhat))*(zhat/(norm*uhat));
+        Qvu += Math.pow((vhat/norm)*(1 + (norm*norm)/(uhat*uhat)),2.0);
+        Qvu *= stdTheta;
+        Qvu *= stdTheta;
+        
+        Qzu = (vhat/(norm*uhat))*(vhat/(norm*uhat));
+        Qzu += Math.pow((zhat/norm)*(1 + (norm*norm)/(uhat*uhat)),2.0);
+        Qzu *= stdTheta;
+        Qzu *= stdTheta;
+        
+        Qvz = - vhat*zhat/(uhat*uhat);
+        Qvz += vhat*zhat/(norm*norm)*Math.pow((1 + (norm*norm)/(uhat*uhat)),2.0);
+        Qvz *= stdTheta;
+        Qvz *= stdTheta;
+        
+        newError.set(IDVDU,IDVDU, newError.get(IDVDU,IDVDU) + Qvu);
+        newError.set(IDZDU,IDZDU, newError.get(IDZDU,IDZDU) + Qzu);
+        newError.set(IDVDU,IDZDU, newError.get(IDVDU,IDZDU) + Qvz);
+        
+        
+        tre.setError( newError );
+        
+    }
+    
+    // method for adding the interaction with direction
+    public void interact_dir(ETrack tre, PropDir dir)
+    {
+        interact(tre);
+    }
+    
+    /**
+     *Return the number of radiation lengths.
+     *
+     * @return The thickness of the scattering material in radiation lengths.
+     */
+    public double radLength()
+    {
+        return _radLength;
+    }
+    
+    /**
+     *Make a clone of this object.
+     *
+     * @return A Clone of this instance.
+     */
+    public Interactor newCopy()
+    {
+        return new ThinXYPlaneMs(_radLength);
+    }
+    
+    
+    /**
+     *Return a String representation of the class' type name.
+     *Included for completeness with the C++ version.
+     *
+     * @return   A String representation of the class' type name.
+     */
+    public String type()
+    { return staticType(); }
+    
+    /**
+     *output stream
+     *
+     * @return  A String representation of this instance.
+     */
+    public String toString()
+    {
+        return "ThinXYPlaneMs with "+_radLength+" radiation lengths";
+    }
+    
+    
+    
+    
+}
+

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman
TrackUtils.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/TrackUtils.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/TrackUtils.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,150 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.hps.recon.tracking.kalman;
+
+import hep.physics.matrix.SymmetricMatrix;
+import hep.physics.vec.BasicHep3Vector;
+import hep.physics.vec.Hep3Vector;
+
+import org.lcsim.event.MCParticle;
+import org.lcsim.fit.helicaltrack.HelicalTrackFit;
+import org.lcsim.fit.helicaltrack.HelixParamCalculator;
+import org.lcsim.fit.helicaltrack.HelixUtils;
+import org.lcsim.recon.tracking.trfbase.TrackError;
+import org.lcsim.recon.tracking.trfbase.TrackSurfaceDirection;
+import org.lcsim.recon.tracking.trfbase.TrackVector;
+import org.lcsim.recon.tracking.trfbase.VTrack;
+import org.lcsim.recon.tracking.trfdca.SurfDCA;
+import org.lcsim.recon.tracking.trfutil.TRFMath;
+
+import Jama.Matrix;
+
+/**
+ * Class for converting lcsim tracks to trf tracks.
+ * @author ecfine
+ */
+public class TrackUtils {
+
+    private double mmTocm = 0.1; // TRF wants distances in cm, not mm.
+    public double bz = 0.5;
+    private double _epsilon = 1e-4;
+    boolean _DEBUG = false;
+
+    // Converts a HelicalTrackFit to a VTrack, prints track params.
+    public VTrack makeVTrack(HelicalTrackFit t) {
+
+        // Opposite sign convention.
+        double r_signed = -(t.dca());
+
+        TrackVector tv = new TrackVector();
+        tv.set(0, r_signed * mmTocm);
+        tv.set(1, t.z0() * mmTocm);
+        tv.set(2, Math.tan(t.phi0()));
+        tv.set(3, t.slope());
+        tv.set(4, -t.curvature() / mmTocm / (TRFMath.BFAC * bz)); // curvature to q/pt
+        double q = t.pT(bz) / (t.R() * mmTocm * TRFMath.BFAC * bz);
+        if ((q / t.pT(bz) + tv.get(4)) > _epsilon) {
+            System.out.println("something wrong with curvature? q/pt = "
+                    + (q / t.pT(bz)) + ", -tv.get(4) = " + -tv.get(4));
+        }
+//        SurfDCA s = new SurfDCA((t.dca() * Math.sin(t.phi0())),
+//                (-t.dca() * Math.cos(t.phi0())));
+        double dcaX = mmTocm * HelixUtils.PointOnHelix(t, 0).x();
+        double dcaY = mmTocm * HelixUtils.PointOnHelix(t, 0).y();
+        if(_DEBUG)System.out.println("DCA X="+dcaX+"; Y="+dcaY);
+//        SurfDCA s = new SurfDCA(dcaX, dcaY);
+//        I think this should be 0,0
+        SurfDCA s = new SurfDCA(0, 0);
+
+        //mg this is just wrong...
+//        SurfDCA s = new SurfDCA(r_signed * mmTocm, 0.);
+
+//        VTrack vt = new VTrack(s, tv);
+        VTrack vt = new VTrack(s, tv, TrackSurfaceDirection.TSD_FORWARD);
+        if (_DEBUG) {
+            System.out.println("making VTrack with: ");
+            System.out.println("    r_signed = " + r_signed * mmTocm);
+            System.out.println("    z0 = " + t.z0() * mmTocm);
+            System.out.println("    tanphi0 =  " + Math.tan(t.phi0()));
+            System.out.println("    tanlamda = " + t.slope());
+            System.out.println("    q/pt = " + -t.curvature() / mmTocm / (TRFMath.BFAC * bz));
+//        System.out.println("    q/pt = " + t.curvature() * 0.299999 * bz);
+            System.out.println("from HelicalTrackFit with: ");
+            System.out.println("    dca = " + t.dca() + "+/-" + Math.sqrt(t.covariance().e(HelicalTrackFit.dcaIndex, HelicalTrackFit.dcaIndex)));
+            System.out.println("    z0 = " + t.z0() + "+/-" + Math.sqrt(t.covariance().e(HelicalTrackFit.z0Index, HelicalTrackFit.z0Index)));
+            System.out.println("    phi0 =  " + t.phi0() + "+/-" + Math.sqrt(t.covariance().e(HelicalTrackFit.phi0Index, HelicalTrackFit.phi0Index)));
+            System.out.println("    slope = " + t.slope() + "+/-" + Math.sqrt(t.covariance().e(HelicalTrackFit.slopeIndex, HelicalTrackFit.slopeIndex)));
+            System.out.println("    curvature = " + t.curvature() + "+/-" + Math.sqrt(t.covariance().e(HelicalTrackFit.curvatureIndex, HelicalTrackFit.curvatureIndex)));
+//        System.out.println("SurfDCA at " + t.dca() * Math.sin(t.phi0()) + ", " +
+//                -t.dca() * Math.cos(t.phi0()));
+        }
+        return vt;
+    }
+    //make a VTrack from an MC particle
+
+    public VTrack makeVTrack(MCParticle mcp) {
+        TrackVector tv = new TrackVector();
+        HelixParamCalculator helix = new HelixParamCalculator(mcp, bz);
+        double r_signed = -(helix.getDCA());
+        double curvemc = (-1) / helix.getRadius();
+        tv.set(0, r_signed * mmTocm);
+        tv.set(1, helix.getZ0() * mmTocm);
+        tv.set(2, Math.tan(helix.getPhi0()));
+        tv.set(3, helix.getSlopeSZPlane());
+        tv.set(4, curvemc / mmTocm / (TRFMath.BFAC * bz)); // curvature to q/pt      
+//        SurfDCA s = new SurfDCA(r_signed * mmTocm, 0.);
+         SurfDCA s = new SurfDCA(0, 0.);
+        VTrack vt = new VTrack(s, tv);
+        return vt;
+
+    }
+
+    public void setBZ(double b) {
+        bz = b;
+    }
+
+    public Hep3Vector getMomentum(VTrack vt){
+        double qoverpt=vt.qOverP();
+        double phi0=Math.atan(vt.vector().get(2));
+        double slope=vt.vector().get(3);
+        double Pt = Math.abs(1./qoverpt);
+        double px = Pt * Math.cos(phi0);
+        double py = Pt * Math.sin(phi0);
+        double pz = Pt * slope;
+        Hep3Vector p=new BasicHep3Vector(px,py,pz);
+ 
+        return p;
+    }
+
+    // Returns a TrackError from a HelicalTrackFit.
+    public TrackError getInitalError(HelicalTrackFit t) {
+        SymmetricMatrix oldError = t.covariance();
+        SymmetricMatrix newError = new SymmetricMatrix(5);
+        double edca = oldError.e(HelicalTrackFit.dcaIndex, HelicalTrackFit.dcaIndex);
+        newError.setElement(0, 0, edca * mmTocm * mmTocm * 1e6);
+        double ez0 = oldError.e(HelicalTrackFit.z0Index, HelicalTrackFit.z0Index);
+        newError.setElement(1, 1, ez0 * mmTocm * mmTocm * 1e6);
+        double ephi0 = oldError.e(HelicalTrackFit.phi0Index, HelicalTrackFit.phi0Index);
+        newError.setElement(2, 2, ephi0 * 1e6);
+        double eslope = oldError.e(HelicalTrackFit.slopeIndex, HelicalTrackFit.slopeIndex);
+        newError.setElement(3, 3, eslope * 100000);
+        double ecurve = oldError.e(HelicalTrackFit.curvatureIndex, HelicalTrackFit.curvatureIndex);
+        newError.setElement(4, 4, (ecurve / Math.pow(TRFMath.BFAC * bz * mmTocm, 2)) * 1e6);
+
+//        for (int i = 0; i < error.getNColumns(); i++){
+//            double newElement = error.e(i, i) * 10000;
+//            error.setElement(i, i, newElement);
+//        }
+        Matrix errorMatrix = new Matrix(5, 5);
+        for (int k = 0; k < 5; k++) {
+            for (int j = 0; j < 5; j++) {
+                errorMatrix.set(k, j, newError.e(k, j));
+            }
+        }
+        if(_DEBUG) System.out.println("Setting initial error:\n"+errorMatrix.toString());
+        TrackError trackerror = new TrackError(errorMatrix);
+        return trackerror;
+    }
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman
TrdHelper.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/TrdHelper.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/TrdHelper.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,281 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.hps.recon.tracking.kalman;
+
+import hep.physics.vec.Hep3Vector;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.lcsim.detector.IRotation3D;
+import org.lcsim.detector.ITransform3D;
+import org.lcsim.detector.solids.ISolid;
+import org.lcsim.detector.solids.Point3D;
+import org.lcsim.detector.solids.Polygon3D;
+import org.lcsim.detector.solids.Trd;
+import org.lcsim.event.Track;
+import org.lcsim.fit.helicaltrack.HelicalTrackFit;
+
+/**
+ *
+ * @author ecfine
+ */
+public class TrdHelper implements ShapeHelper{
+    PrintDetectorElements printDetectorElements = new PrintDetectorElements();
+
+    /* Prints that solid is trapezoid */
+    public void printShape(ISolid solid) {
+        checkTrapezoid(solid);
+        System.out.println("Shape: Trapezoid");
+    }
+
+    /* Prints the local coordinates of the trapezoid */
+    public void printLocalCoords(ISolid solid){
+        checkTrapezoid(solid);
+        Trd trap = (Trd) solid;
+        System.out.println("Local Coordinates: " + trap.getVertices().get(0));
+         for (int n = 1; n < trap.getVertices().size(); n ++) {
+            printDetectorElements.printIndent();
+            System.out.println("                    " + trap.getVertices().get(n));
+        }
+    }
+
+    /* Prints the global coordinates of the trapezoid */
+    public void printGlobalCoords(ISolid solid){
+        checkTrapezoid(solid);
+        Trd trap = (Trd) solid;
+         for(int i = 0; i < trap.getVertices().size(); i++) {
+            Hep3Vector currentPoint = (Hep3Vector) trap.getVertices().get(i);
+            Hep3Vector transformedPoint = (Hep3Vector) currentPoint;
+            for(int k = PrintDetectorElements.physicalVolumes.size(); k > 0; k--) {
+                ITransform3D lastTransform = (ITransform3D) PrintDetectorElements.physicalVolumes.get(k-1);
+                currentPoint = lastTransform.transformed(currentPoint);
+            }
+            transformedPoint = currentPoint;
+            printDetectorElements.printIndent();
+            if (i == 0){
+                System.out.println("Global Coordinates: [    " + transformedPoint.x() +
+                        ",      " + transformedPoint.y() + ",        " + transformedPoint.z() +"]");
+            } else{
+                 System.out.println("                     [     " + transformedPoint.x() +
+                        ",       " + transformedPoint.y() + ",      " + transformedPoint.z() +"]");
+            }
+        }
+    }
+
+    public void findIntersection(ISolid solid, Track track) {
+        checkTrapezoid(solid);
+        Trd trap = (Trd) solid;
+        ShapeDispatcher shapedis = new ShapeDispatcher();
+        HelicalTrackFit helix = shapedis.trackToHelix(track);
+        List<Polygon3D> faces = trap.getFaces();
+        
+        // For each face, find the vertices
+        for (int i = 0; i < faces.size(); i++) {
+            Polygon3D face = faces.get(i);
+            Hep3Vector localNormal = face.getNormal();
+            Hep3Vector normal = getGlobalRot(localNormal); // get the normal in global coords
+            List<Hep3Vector> vertices = new ArrayList<Hep3Vector>();
+
+            // For each vertex, find and print the Global coordinates
+            for(int k = 0; k < face.getVertices().size(); k++){
+                Hep3Vector localVertex = (Hep3Vector) face.getVertices().get(k);
+//                System.out.println("local vertex: " + localVertex);
+                Hep3Vector vertex = getGlobalCoords(localVertex);
+                System.out.println("vertex: " + vertex);
+                vertices.add(vertex);
+            }
+//            System.out.println("local normal: " + localNormal);
+            System.out.println("normal: " + normal);
+            if (0.01 > normal.z() && normal.z() > -0.01){
+                if (org.lcsim.fit.helicaltrack.HelixUtils.isInterceptingBoundedXYPlane(helix, normal, vertices)) {
+                    System.out.println("INTERSECTING BOUNDED PLANE!");
+                } else {
+                    System.out.println("No intersection");
+                }
+                if (org.lcsim.fit.helicaltrack.HelixUtils.isInterceptingXYPlane(helix, normal, vertices.get(0))) {
+                    System.out.println("INTERSECTING PLANE!");
+                } else {
+                    System.out.println("No intersection");
+                }
+            } else {
+                System.out.println("wrong orientation");
+            }
+        }
+    }
+
+
+    // This is (clearly) a work in progress...
+   public KalmanSurface getKalmanSurf(ISolid solid) {
+        KalmanSurface surf = null;
+//        checkTrapezoid(solid);
+//        Trd trap = (Trd) solid;
+//        List<Polygon3D> faces = trap.getFaces();
+//        /* This needs to decide what surface the trapezoid should be modeled as.
+//         * I suspect xy plane and z plane are the main choices. For now, it's
+//         * just going to default to an xy plane, but that should be revisited. */
+////        List vertices = trap.getVertices();
+//
+//        // From a list of 8 vertices, need to match the pairs with the smallest difference
+//        // between them. Or alternatively, need to find the two biggest squares. That
+//        // may actually be a better way to do things... could do it using faces that way?
+//
+//        ArrayList areas = new ArrayList();
+//        for (int i = 0; i < faces.size(); i++) {
+//            Polygon3D face = faces.get(i);
+//            double area = findArea(face);
+//            areas.add(area);
+//        }
+//        for (int k )
+//
+//
+//            Hep3Vector localNormal = face.getNormal();
+//            Hep3Vector normal = getGlobalRot(localNormal); // get the normal in global coords
+//            List<Hep3Vector> vertices = new ArrayList<Hep3Vector>();
+//            Hep3Vector planeNormal = null;
+//            // Only want to make surface for xy plane faces
+//            if (0.01 > normal.z() && normal.z() > -0.01){
+//                // For each vertex, find the Global coordinates & add to vertices
+//                for(int k = 0; k < face.getVertices().size(); k++){
+//                    Hep3Vector localVertex = (Hep3Vector) face.getVertices().get(k);
+//                    Hep3Vector vertex = getGlobalCoords(localVertex);
+//                    vertices.add(vertex);
+//                    planeNormal = normal;
+//                }
+//             /* From the 8 vertices, we want one origin point, since
+//             * the origin and a vector define the plane. Need a single x & y value.
+//             * Here, we find the smallest difference in x and y values between two
+//             * points. Once we find this pair, we can average the x and y values
+//             * for our origin point. */
+//                double minxDiff = (vertices.get(0).x() - vertices.get(1).x());
+//                double minyDiff = (vertices.get(0).y() - vertices.get(1).y());
+//                int secondPoint = 1;
+//                for (int j = 2; j < vertices.size(); j++){
+//                    double xDiff = vertices.get(0).x() - vertices.get(j).x();
+//                    double yDiff = vertices.get(0).y() - vertices.get(j).y();
+//                    if (xDiff < minxDiff && yDiff < minyDiff) {
+//                        minxDiff = xDiff;
+//                        minyDiff = yDiff;
+//                        secondPoint = j;
+//                    }
+//                }
+//                // Average the x, y, and z values of the two points to find origin.
+//                Hep3Vector doubleMidPoint = VecOp.add(vertices.get(0), vertices.get(secondPoint));
+//                Hep3Vector origin = VecOp.mult(.5, doubleMidPoint);
+//
+//               /* Make a new surface from the origin and plane normal as found
+//                * above. */
+//
+//                double distnorm = (planeNormal.x() * origin.x() + planeNormal.y() * origin.y()
+//                        + planeNormal.z() * origin.z())/planeNormal.magnitude();
+//                double normphi = Math.atan2(planeNormal.y(), planeNormal.x());
+//                if (normphi < 0){
+//                    normphi = normphi + TRFMath.TWOPI;
+//                }
+//                System.out.println("Plane normal = " + planeNormal + ", origin = " + origin);
+//                surf = new KalmanSurface("xyplane", distnorm, normphi);
+//            }
+//
+//
+//
+
+        return surf;
+    }
+
+    boolean pointIsOnSolid(ISolid solid, Point3D hitPoint) {
+        boolean onSolid = true;
+        checkTrapezoid(solid);
+        Trd trap = (Trd) solid;
+        List faces = trap.getFaces();
+        // Want to find all projections for each face, and see if projections
+        // of the hit point are inside them. This is almost certainly not the
+        // most efficient way to see whether the point is in the solid, but
+        // I'm not really sure how else to deal with it.
+        for(int i = 0; i < faces.size(); i++){
+            Polygon3D face = (Polygon3D) faces.get(i);
+            List vertices = face.getVertices();
+            ArrayList xProjVertices = new ArrayList();
+            ArrayList yProjVertices = new ArrayList();
+            ArrayList zProjVertices = new ArrayList();
+            for (int k = 0; k < vertices.size(); k ++){
+                Point3D currentPoint = (Point3D) vertices.get(k);
+                double[] xProj = new double[2];
+
+
+            }
+        }
+        return onSolid;
+    }
+
+    // Finds the area of an arbitrary quadrilateral. See http://softsurfer.com/
+    // Archive/algorithm_0101/algorithm_0101.htm#Quandrilaterals for more info.
+    private double findArea(Polygon3D face) {
+        double[] v2_v0 = new double[3];
+        v2_v0[0] = face.getVertices().get(2).x() - face.getVertices().get(0).x();
+        v2_v0[1] = face.getVertices().get(2).y() - face.getVertices().get(0).y();
+        v2_v0[2] = face.getVertices().get(2).z() - face.getVertices().get(0).z();
+        double[] v3_v1 = new double[3];
+        v3_v1[0] = face.getVertices().get(3).x() - face.getVertices().get(1).x();
+        v3_v1[1] = face.getVertices().get(3).y() - face.getVertices().get(1).y();
+        v3_v1[2] = face.getVertices().get(3).z() - face.getVertices().get(1).z();
+        double area = .5 * magnitude(crossProduct(v2_v0, v3_v1));
+        return area;
+    }
+
+    // Finds the cross product of two 3d vectors, represented as double[]s.
+    private double[] crossProduct(double[] v1, double[] v2){
+        double[] cross = new double[3];
+        cross[0] = v1[1]*v2[2] - v2[1]*v1[2];
+        cross[1] = v1[2]*v2[0] - v2[2]*v1[0];
+        cross[2] = v1[0]*v2[1] - v2[0]*v1[1];
+        return cross;
+    }
+
+    // Finds the magnitude of a 3d vector, represented as a double[]
+    private double magnitude(double[] v){
+        double mag = Math.sqrt(Math.pow(v[0], 2) + Math.pow(v[1], 2) + Math.pow(v[2], 2));
+        return mag;
+    }
+//
+//    public HTrack addIntercept(ISolid solid, HTrack ht) {
+//
+//    }
+
+
+
+    
+    /* Finds the global coordinates of a local point */
+    private Hep3Vector getGlobalCoords(Hep3Vector local){
+        Hep3Vector currentPoint = local;
+        for(int k = PrintIntersections.physicalVolumes.size(); k > 0; k--) {
+            ITransform3D lastTransform = (ITransform3D) PrintIntersections.physicalVolumes.get(k-1);
+            currentPoint = lastTransform.transformed(currentPoint);
+        }
+        return currentPoint;
+    }
+
+    /* Finds the global rotation of a local point. Use this for normals, where
+     the translation is irrelevant. */
+    private Hep3Vector getGlobalRot(Hep3Vector local){
+        Hep3Vector currentPoint = local;
+        for(int k = PrintIntersections.physicalVolumes.size(); k > 0; k--) {
+            ITransform3D lastTransform = (ITransform3D) PrintIntersections.physicalVolumes.get(k-1);
+            IRotation3D lastRotation = lastTransform.getRotation();
+            currentPoint = lastRotation.rotated(currentPoint);
+        }
+        return currentPoint;
+    }
+
+    /* Checks that solid is really trapezoid */
+    public void checkTrapezoid(ISolid solid){
+        if (solid instanceof Trd) {
+         } else {
+            System.out.println("Error! This shape is not a trapezoid!");
+            return;
+        }
+    }
+
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman
TrfDetector.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/TrfDetector.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/TrfDetector.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,44 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.hps.recon.tracking.kalman;
+
+import java.util.List;
+import java.util.Map;
+
+import org.lcsim.recon.tracking.trflayer.Detector;
+import org.lcsim.recon.tracking.trflayer.Layer;
+
+/**
+ *
+ * @author ecfine
+ */
+public class TrfDetector extends Detector {
+     // List of layer names in original order.
+    private List _names;
+    
+    // Map layer names to layers.
+    private Map _layermap;
+
+
+    
+    public int addLayer(String name, Layer lyr)
+    {
+        // Set unchecked.
+//        if ( _check == CHECKED_OK ) _check = UNCHECKED;
+
+        // Check name does not already appear in map.
+        if ( isAssigned(name) ){
+            System.out.println("Name already assigned, layer not added.");
+            return 0;
+        }
+        // Add layer.
+        _names.add(name);
+        _layermap.put(name, lyr);
+        System.out.println("Layer named " + name + " added");
+        return 1;
+    }
+
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman
TubeHelper.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/TubeHelper.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/TubeHelper.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,44 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.hps.recon.tracking.kalman;
+
+import org.lcsim.detector.solids.ISolid;
+import org.lcsim.detector.solids.Tube;
+import org.lcsim.event.Track;
+
+/**
+ *
+ * @author ecfine
+ */
+public class TubeHelper implements ShapeHelper {
+
+    public void printShape(ISolid solid) {
+        checkTube(solid);
+        System.out.println("Shape: Tube");
+
+    }
+
+    public void printLocalCoords(ISolid solid) {
+    }
+
+    public void printGlobalCoords(ISolid solid) {
+    }
+
+    public void checkTube(ISolid solid) {
+        if (solid instanceof Tube) {
+        } else {
+            System.out.print("Error! This isn't a tube!");
+            return;
+        }
+    }
+
+    public void findIntersection(ISolid solid, Track track) {
+    }
+
+    public KalmanSurface getKalmanSurf(ISolid solid) {
+         KalmanSurface surf = null;
+         return surf;
+    }
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util
AddFitKalman.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/AddFitKalman.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/AddFitKalman.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,698 @@
+package org.hps.recon.tracking.kalman.util;
+
+import java.math.BigDecimal;
+import java.math.MathContext;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.lcsim.recon.tracking.trfbase.ETrack;
+import org.lcsim.recon.tracking.trfbase.Hit;
+import org.lcsim.recon.tracking.trfbase.PropDir;
+import org.lcsim.recon.tracking.trfbase.TrackError;
+import org.lcsim.recon.tracking.trfbase.TrackVector;
+import org.lcsim.recon.tracking.trffit.AddFitter;
+import org.lcsim.recon.tracking.trfutil.Assert;
+import org.lcsim.util.aida.AIDA;
+
+import Jama.Matrix;
+
+
+// Fit tracks using Kalman filter.
+
+/**
+ * Copied from org.lcsim.recon.tracking.trffit.AddFitKalman
+ * and added debug printout.  
+ *
+ * Original author was Norman Graf.
+ * 
+ * AddFitKalman  uses a Kalman filter to update the track fit.
+ *
+ * 
+ *@author $Author: jeremy $
+ *@version $Id: AddFitKalman.java,v 1.1 2011/07/28 18:28:19 jeremy Exp $
+ *
+ * Date $Date: 2011/07/28 18:28:19 $
+ */
+
+public class AddFitKalman extends AddFitter
+{
+
+    private AIDA aida = AIDA.defaultInstance();
+    
+    
+    // Maximum allowed hit dimension.
+    private static final int MAXDIM = 3;
+    
+    // Maximum number of track vectors.
+    private static final int MAXVECTOR = 1;
+    
+    // Maximum number of track errors.
+    private static final int MAXERROR = 1;
+    
+    //private:  // nested classes
+    
+    // The nested class Box holds the vectors, matrices and symmetric
+    // matrices needed for adding a hit in the main class.
+    class Box
+    {
+                /*
+                private:  // typedefs
+                typedef Ptr<TrfVector,AutoPolicy>   VectorPtr;
+                typedef Ptr<TrfSMatrix,AutoPolicy>  SMatrixPtr;
+                typedef Ptr<TrfMatrix,AutoPolicy>   MatrixPtr;
+                typedef vector<VectorPtr>           VectorList;
+                typedef vector<SMatrixPtr>          SMatrixList;
+                typedef vector<MatrixPtr>           MatrixList;
+                 */
+        
+        // enums
+        // number of vectors
+        private static final int  NVECTOR = 2 ;
+        // number of errors
+        private static final int NERROR = 3 ;
+        // number of vectors
+        private static final int  NDERIV = 2 ;
+        // number of gains
+        private static final int  NGAIN = 2 ;
+        
+        // attributes
+        // dimension of the vector, matrix, etc
+        private int _size;
+        // array of vectors
+        List  _vectors;
+        // array of error matrices
+        List _errors;
+        // array of derivatives (Nx5 matrices)
+        List _derivs;
+        // array of gains (5xN matrices)
+        List _gains;
+        
+        // methods
+        // constructor
+        public Box(int size)
+        {
+            _size= size;
+            _vectors = new ArrayList();
+            _errors = new ArrayList();
+            _derivs = new ArrayList();
+            _gains = new ArrayList();
+            
+            int icnt;
+            // Track vectors
+            for ( icnt=0; icnt<NVECTOR; ++icnt )
+                _vectors.add(  new Matrix(size,1) );
+            // Track errors
+            for ( icnt=0; icnt<NERROR; ++icnt )
+                _errors.add(  new Matrix(size,size) );
+            // Track derivatives
+            for ( icnt=0; icnt<NDERIV; ++icnt )
+                _derivs.add(  new Matrix(size,5) );
+            // Gains
+            for ( icnt=0; icnt<NDERIV; ++icnt )
+                _gains.add(  new Matrix(5,size) );
+            
+        }
+        
+        // return the dimension
+        public int get_size()
+        { return _size;
+        }
+        // fetch a vector
+        public Matrix get_vector(int ivec)
+        {
+            return (Matrix) _vectors.get(ivec);
+        }
+        // fetch an error
+        public Matrix get_error(int ierr)
+        {
+            return (Matrix) _errors.get(ierr);
+        }
+        // fetch a derivative
+        public Matrix get_deriv(int ider)
+        {
+            return (Matrix) _derivs.get(ider);
+        }
+        // fetch a gain
+        public Matrix get_gain(int igai)
+        {
+            return (Matrix) _gains.get(igai);
+        }
+    } // end of Box inner class
+    
+    // static methods
+    
+    //
+    
+    /**
+     *Return a String representation of the class' the type name.
+     *Included for completeness with the C++ version.
+     *
+     * @return   A String representation of the class' the type name.
+     */
+    public static String typeName()
+    { return "AddFitKalman";
+    }
+    
+    //
+    
+    /**
+     *Return a String representation of the class' the type name.
+     *Included for completeness with the C++ version.
+     *
+     * @return   A String representation of the class' the type name.
+     */
+    public static String staticType()
+    { return typeName();
+    }
+    
+    // attributes
+    
+    // Array of boxes for each supported size.
+    private List _boxes;
+    
+    // Track vectors.
+    private List _tvectors;
+    
+    // Track errors.
+    private List _terrors;
+    
+    //methods
+    
+    //
+    
+    int AddFitKalmanDebugLevel = 0;
+    
+    
+    /**
+     *Construct a default instance.
+     * Allocate space needed for hits of dimension from 1 to MAXDIM.
+     *
+     */
+    public AddFitKalman()
+    {
+        _boxes = new ArrayList();
+        _tvectors = new ArrayList();
+        _terrors = new ArrayList();
+        
+        // Create boxes for hit containers.
+        for ( int dim=1; dim<MAXDIM; ++dim )
+            _boxes.add( new Box(dim) );
+        
+        int icnt;
+        
+        for ( icnt=0; icnt<MAXVECTOR; ++icnt )
+            _tvectors.add(  new Matrix(5, 1) );
+        
+        for ( icnt=0; icnt<MAXERROR; ++icnt )
+            _terrors.add(  new Matrix(5,5) );
+
+	try{
+	    ToyConfig config = ToyConfig.getInstance();
+	    AddFitKalmanDebugLevel = config.getInt( "AddFitKalmanDebugLevel", 
+						    AddFitKalmanDebugLevel );
+	    
+
+	} catch (ToyConfigException e){
+            System.out.println (e.getMessage() );
+            System.out.println ("Stopping now." );
+            System.exit(-1);
+        }
+	
+        
+    }
+    
+    //
+    
+    /**
+     *Return a String representation of the class' the type name.
+     *Included for completeness with the C++ version.
+     *
+     * @return   A String representation of the class' the type name.
+     */
+    public String type()
+    { return staticType();
+    }
+    
+    //
+    
+    
+    /**
+     *Add a hit and fit with the new hit.
+     * Use a Kalman filter to add a hit to a track.
+     * The hit is updated with the input track.
+     * Note: We make direct use of the underlying vector and matrix
+     *       classes here.  It will probably be neccessary to modify
+     *       this routine if these are changed.
+     *
+     * @param   tre The ETrack to update.
+     * @param   chsq The chi-square for the fit.
+     * @param   hit The Hit to add to the track.
+     * @return  0 if successful.
+     */
+    public int addHitFit(ETrack tre, double chsq,  Hit hit)
+    {
+
+        // Update the hit with the input track.
+        hit.update(tre);
+        
+        // Fetch hit size.
+        int dim = hit.size();
+        Assert.assertTrue( dim <= MAXDIM );
+        
+        // Fetch the box holding the needed hit containers.
+        // The chice of boxes depends on the size of the hit.
+        Box box = (Box)_boxes.get(dim-1);
+        Assert.assertTrue( box.get_size() == dim );
+        
+        // Fetch the hit containers.
+        Matrix diff    = box.get_vector(0);
+        Matrix hit_res = box.get_vector(1);
+        Matrix hit_err     = box.get_error(0);
+        Matrix hit_err_tot = box.get_error(1);
+        Matrix hit_res_err = box.get_error(2);
+        Matrix dhit_dtrk         = box.get_deriv(0);
+        Matrix new_dhit_dtrk     = box.get_deriv(1);
+        Matrix trk_err_dhit_dtrk = box.get_gain(0);
+        Matrix gain              = box.get_gain(1);
+        Matrix gain2             = gain.copy();
+
+        // Fetch the track containers.
+        Matrix new_vec = (Matrix) _tvectors.get(0);
+        Matrix new_err = (Matrix)  _terrors.get(0);
+        
+        hit_err = hit.measuredError().matrix();
+	Matrix Vm    = hit_err.copy();
+	Matrix VmInv = Vm.inverse();
+        //System.out.println("hit_err= \n"+hit_err);
+        
+        // Fetch track prediction of hit.
+        diff = hit.differenceVector().matrix();
+        //System.out.println("diff= \n"+diff);
+        dhit_dtrk = hit.dHitdTrack().matrix();
+	Matrix D = dhit_dtrk.copy();
+        //System.out.println("dhit_dtrk= \n"+dhit_dtrk);
+        // Fetch track info.
+        Matrix trk_vec = tre.vector().matrix();
+        Matrix trk_err = tre.error().getMatrix(); //need to fix this!
+        Matrix V       = tre.error().getMatrix();
+	VTUtil vtu = new VTUtil( tre );
+        
+        //System.out.println("trk_vec= \n"+trk_vec);
+        //System.out.println("trk_err= \n"+trk_err);
+        
+        // Build gain matrix.
+        hit_err_tot = hit.predictedError().matrix().plus(
+                hit_err);
+        //System.out.println("hit_err_tot= \n"+hit_err_tot);
+        //if ( invert(hit_err_tot)!=0 ) return 3;
+	Matrix hetot  = new Matrix(2,2);
+	Matrix hetoti = new Matrix(2,2);
+	hetot = hit.predictedError().matrix().plus(hit_err);
+	hetoti = hetot.inverse();
+        hit_err_tot= hit_err_tot.inverse();
+
+        //System.out.println("hit_err_tot inverse= \n"+hit_err_tot);
+        trk_err_dhit_dtrk = trk_err.times(dhit_dtrk.transpose());
+        gain = trk_err_dhit_dtrk.times(hit_err_tot);
+        //System.out.println("trk_err_dhit_dtrk= \n"+trk_err_dhit_dtrk);
+        //System.out.println("gain= \n"+gain);
+        
+        //  if ( get_debug() ) {
+        //System.out.println("\n");
+        //System.out.println("      trk_vec: " + "\n"+       trk_vec + "\n");
+        //System.out.println("      trk_err: " + "\n"+       trk_err + "\n");
+        //System.out.println("    dhit_dtrk: " + "\n"+     dhit_dtrk + "\n");
+        //  }
+        
+        // We need to return dhit_dtrk to its original state for the
+        // next call.
+        // dhit_dtrk = dhit_dtrk.transpose(); //need to check this!
+        dhit_dtrk.transpose();
+        // Build new track vector.
+        new_vec = trk_vec.minus(gain.times(diff));
+        //System.out.println("new_vec= \n"+new_vec);
+        
+        // Build new error;
+        new_err = trk_err.minus(trk_err_dhit_dtrk.times(hit_err_tot.times(trk_err_dhit_dtrk.transpose())));
+
+	Matrix Vnew = new_err.copy();
+	D = D.transpose();
+	gain2 = Vnew.times(D.times(VmInv));
+	Matrix etap = trk_vec.minus(gain2.times(diff));
+
+        //System.out.println("new_err= \n"+new_err);
+        // Check the error.
+        if ( AddFitKalmanDebugLevel > 0 ) {
+            int nbad = 0;
+            for ( int i=0; i<5; ++i )
+            {
+                if ( new_err.get(i,i) < 0.0 ) {
+		    if ( nbad == 0 ) System.out.println("");
+		    System.out.println ( "Bad on: " + i + " " + new_err.get(i,i) );
+		    ++nbad;
+		}
+                double eii = new_err.get(i,i);
+                for ( int j=0; j<i; ++j )
+                {
+                    double ejj = new_err.get(j,j);
+                    double eij = new_err.get(j,i);
+                    if ( Math.abs(eij*eij) >= eii*ejj  ) {
+			double delta = -Math.abs(eij*eij) + eii*ejj;
+			if ( nbad == 0 ) System.out.println("");
+			System.out.println( "Bad off: " + i + " " 
+					    + j + " "
+					    + eii + " "
+					    + ejj + " "
+					    + eij + " "
+					    + delta
+					    );
+			++nbad;
+		    }
+                }
+            }
+	    if ( nbad > 0 ){
+		PrintSymMatrix psm = new PrintSymMatrix();
+		System.out.println ("Illegal cov in addfitkalman: " 
+				    + RKDebug.Instance().getTrack() + " "
+				    + RKDebug.Instance().getPropDir() + " "
+				    );
+		System.out.println ("Surface:   " + tre.surface() );
+		
+		System.out.println ("old_err \n" );
+		psm.Print(tre.error());
+
+		System.out.println ("Predicted error: " );
+		psm.Print(hit.predictedError().matrix() );
+
+		System.out.println ("Measured error: " );
+		psm.Print(hit.measuredError().matrix() );
+
+		System.out.println ("Total error: " );
+		psm.Print( hetot );
+
+		System.out.println ("Inverse: " );
+		psm.Print( hetoti );
+		
+		psm.Print( hetoti.times(hetot) );
+
+
+		System.out.println ("Derivs: \n" + hit.dHitdTrack() );
+		
+		System.out.println ("new_err \n" );
+		psm.Print(new_err);
+	    }
+            if ( nbad > 0 ) return 5;
+        }
+        
+        // Create track vector with new values.
+        tre.setVectorAndKeepDirection(new TrackVector(new_vec));
+        tre.setError(new TrackError(new_err));
+        
+        // Calculate residual vector.
+        
+        // Update the hit with the new track.
+        //System.out.println("update the hit");
+        hit.update(tre);
+        
+        hit_res = hit.differenceVector().matrix();
+        new_dhit_dtrk = hit.dHitdTrack().matrix();
+        //System.out.println("new_dhit_dtrk= \n"+new_dhit_dtrk);
+        
+        // Calculate residual covariance and invert.
+        hit_res_err = hit_err.minus(dhit_dtrk.times(new_err.times(dhit_dtrk.transpose())));
+        //		System.out.println("hit_res_err= \n"+hit_res_err);
+        hit_res_err = hit_res_err.inverse();
+        //System.out.println("hit_res_err inverse= \n"+hit_res_err);
+        // Update chi-square.
+        // result should be 1x1 matrix, so should be able to do the following
+        //System.out.println( " hr*hre*hrT=\n"+(hit_res.transpose()).times(hit_res_err.times(hit_res)) );
+        double dchsq = (hit_res.transpose()).times(hit_res_err.times(hit_res)).get(0,0);
+        //System.out.println("chsq= "+chsq+", dchsq= "+dchsq);
+
+	Matrix dEta = etap.minus(trk_vec);
+	Matrix dM   = hit.differenceVector().matrix();
+	Matrix VInv = V.inverse();
+
+	/*
+	System.out.printf ( "Dim1: (%d,%d) (%d,%d) (%d,%d)\n",
+			    dEta.getRowDimension(),  dEta.getColumnDimension(),
+			    dM.getRowDimension(),    dM.getColumnDimension(),
+			    VmInv.getRowDimension(), VmInv.getColumnDimension() 
+			    );
+	*/
+	double dch1 = ((dM.transpose()).times(VmInv.times(dM))).get(0,0);
+	double dch2 = ((dEta.transpose()).times(VInv.times(dEta))).get(0,0);
+	double dch  = dch1 + dch2;
+
+	double ddd = dch-dchsq;
+
+	if ( Math.abs(ddd) > 0.01 ){
+	    if ( RKDebug.Instance().getPropDir() == PropDir.BACKWARD ){
+		aida.cloud1D("/Bugs/Chisq/Back: Delta Chisq: ").fill(dch-dchsq);
+		aida.cloud2D("/Bugs/Chisq/Back: Chisq TRF vs CLEO").fill(dch,dchsq);
+		aida.cloud1D("/Bugs/Chisq/radius of bad chisq").fill( vtu.r() );
+		aida.cloud1D("/Bugs/Chisq/z of bad chisq").fill( vtu.z() );
+		aida.cloud2D("/Bugs/Chisq/Back: Chisq TRF vs r").fill( vtu.r(), dchsq );
+		aida.cloud2D("/Bugs/Chisq/Back: Chisq TRF vs z").fill( vtu.z(), dchsq );
+	    } else {
+		aida.cloud1D("/Bugs/Chisq/Forw: Delta Chisq: ").fill(dch-dchsq);
+		aida.cloud2D("/Bugs/Chisq/Forw: Chisq TRF vs CLEO").fill(dch,dchsq);
+	    }
+	} else {
+	    if ( RKDebug.Instance().getPropDir() == PropDir.BACKWARD ){
+		aida.cloud1D("/Bugs/Chisq/Back: Small Delta Chisq: ").fill(dch-dchsq);
+	    } else {
+		aida.cloud1D("/Bugs/Chisq/Forw: Small Delta Chisq: ").fill(dch-dchsq);
+	    }
+	}
+
+	dchsq = dch;
+
+
+	/*
+	System.out.println ("Chitest: " + dchsq + " " + dch + " | " + dch1 + " " + dch2 );
+	for ( int i=0; i<5; ++i ){
+	    System.out.printf ("Eta  %3d %12.7f %12.7f %12.7f %12.7f %12.7f  | %12.7f \n", i,
+			       trk_vec.get(i,0),
+			       new_vec.get(i,0),
+			       etap.get(i,0),
+			       (new_vec.minus(etap)).get(i,0),
+			       Math.sqrt(new_err.get(i,i)),
+			       dEta.get(i,0)
+			       );
+		    
+	}
+
+	if ( Vm.getRowDimension() == 1){
+	    Hack1D ( trk_vec, V, Vm, new_vec, new_err );
+	} else if ( Vm.getRowDimension() == 2){
+	    Hack2D ( trk_vec, V, Vm, diff, new_vec, new_err );
+	}
+	*/
+
+	// Warn about bad chisquared contribution, ignoring small problems that might
+	// well be just round off error.
+
+	if ( dchsq <   -0.001 ){
+	    /*
+	    System.out.println ("\ndchisq: " 
+				+ RKDebug.Instance().getTrack() + " "
+				+ RKDebug.Instance().getPropDir() + " "
+				+ dchsq + " "
+				+ tre.surface() + " "
+				+ RKDebug.Instance().getRKTrack().cz() + " "
+				);
+	    */
+	    if ( RKDebug.Instance().getPropDir() == PropDir.BACKWARD ){
+		aida.histogram1D( "/Bugs/Backward: cz for tracks with bad dchisquared",100,-1.,1.)
+		    .fill( RKDebug.Instance().getRKTrack().cz() );
+		aida.histogram1D( "/Bugs/Backward: bad dchisquared",100,-20.,0.).fill( dchsq );
+		aida.cloud2D( "/Bugs/Backward: dch vs cz for tracks with bad dchisquared",-1)
+		    .fill( RKDebug.Instance().getRKTrack().cz(), dchsq );
+	    }else{
+		aida.histogram1D( "/Bugs/Forward: cz for tracks with bad dchisquared",100,-1.,1.)
+		    .fill( RKDebug.Instance().getRKTrack().cz() );
+		aida.histogram1D( "/BugsForward: bad dchisquared",100,-20.,0.).fill( dchsq );
+		aida.cloud2D( "/Bugs/Forward: dch vs cz for tracks with bad dchisquared",-1)
+		    .fill( RKDebug.Instance().getRKTrack().cz(), dchsq );
+	    }
+	}
+
+        chsq = chsq + dchsq;
+        setChisquared(chsq);
+        
+        //  if ( get_debug() ) {
+        //System.out.println("         gain: " + "\n"+          gain + "\n");
+        //System.out.println("      new_vec: " + "\n"+       new_vec + "\n");
+        //System.out.println("      new_err: " + "\n"+       new_err + "\n");
+        //System.out.println("new_dhit_dtrk: " + "\n"+ new_dhit_dtrk + "\n");
+        //System.out.println("      hit_res: " + "\n"+       hit_res + "\n");
+        //System.out.println("  hit_res_err: " + "\n"+   hit_res_err + "\n");
+        //System.out.println(" dchsq & chsq: " + "\n"+ dchsq + " " + chsq + "\n");
+        //  }
+        
+        return 0;
+        
+    }
+    
+    
+    /**
+     *output stream
+     *
+     * @return The String representation of this instance.
+     */
+    public String toString()
+    {
+        return getClass().getName();
+    }
+
+    /**
+     * Perform matrix operations as BigDecimal, specialized to a 1D measurement.
+     *
+     * 
+     */
+    private void Hack1D ( Matrix etain, 
+			  Matrix Vin, 
+			  Matrix Vm, 
+			  Matrix etat,
+			  Matrix Vt ){
+
+	BigDecimal sigsq  =  new BigDecimal(  Vm.get(0,0), MathContext.DECIMAL128 );
+	BigDecimal V00    =  new BigDecimal( Vin.get(0,0), MathContext.DECIMAL128 );
+	BigDecimal denom  = sigsq.add(V00);
+	
+	BigDecimal[] Vi0 = { new BigDecimal( Vin.get(0,0), MathContext.DECIMAL128 ),
+			     new BigDecimal( Vin.get(1,0), MathContext.DECIMAL128 ),
+			     new BigDecimal( Vin.get(2,0), MathContext.DECIMAL128 ),
+			     new BigDecimal( Vin.get(3,0), MathContext.DECIMAL128 ),
+			     new BigDecimal( Vin.get(4,0), MathContext.DECIMAL128 ) };
+
+	Matrix Vp = new Matrix(5,5);
+	for ( int i=0; i<5; ++i ){
+	    for ( int j=i; j<5; ++j ){
+		BigDecimal Vij = new BigDecimal( Vin.get(i,j), MathContext.DECIMAL128 );
+		BigDecimal numer = Vi0[i].multiply(Vi0[j]);
+		BigDecimal ratio = numer.divide(denom,MathContext.DECIMAL128);
+		BigDecimal Vijnew = Vij.subtract(ratio);
+		Vp.set(i,j,Vijnew.doubleValue() );
+	    }
+	}
+	System.out.println ("Hack 1D");
+	PrintSymMatrix psm = new PrintSymMatrix();
+	psm.Print(Vp);
+    }
+
+    /**
+     * Perform matrix operations as BigDecimal, specialized to a 2D measurement.
+     *
+     * 
+     */
+    private void Hack2D ( Matrix etain, 
+			  Matrix Vin, 
+			  Matrix Vm,
+			  Matrix dM,
+			  Matrix etat,
+			  Matrix Vt ){
+
+	BigDecimal DTVD00 = new BigDecimal( Vin.get(0,0), MathContext.DECIMAL128 );
+	BigDecimal DTVD11 = new BigDecimal( Vin.get(1,1), MathContext.DECIMAL128 );
+	BigDecimal DTVD01 = new BigDecimal( Vin.get(0,1), MathContext.DECIMAL128 );
+
+	BigDecimal sigsqx  =  new BigDecimal(  Vm.get(0,0), MathContext.DECIMAL128 );
+	BigDecimal sigsqy  =  new BigDecimal(  Vm.get(1,1), MathContext.DECIMAL128 );
+
+	BigDecimal Sum00 = DTVD00.add(sigsqx);
+	BigDecimal Sum11 = DTVD11.add(sigsqy);
+	BigDecimal Sum01 = DTVD01;
+
+	BigDecimal Disc  = (Sum00.multiply(Sum11)).subtract(Sum01.multiply(Sum01));
+
+	BigDecimal U00 = Sum11.divide(Disc,MathContext.DECIMAL128);
+	BigDecimal U11 = Sum00.divide(Disc,MathContext.DECIMAL128);
+	BigDecimal U01 = (Sum01.negate()).divide(Disc,MathContext.DECIMAL128);
+	BigDecimal U10 = U01;
+
+
+	
+	BigDecimal[] Vi0 = { new BigDecimal( Vin.get(0,0), MathContext.DECIMAL128 ),
+			     new BigDecimal( Vin.get(1,0), MathContext.DECIMAL128 ),
+			     new BigDecimal( Vin.get(2,0), MathContext.DECIMAL128 ),
+			     new BigDecimal( Vin.get(3,0), MathContext.DECIMAL128 ),
+			     new BigDecimal( Vin.get(4,0), MathContext.DECIMAL128 ) };
+
+	BigDecimal[] Vi1 = { new BigDecimal( Vin.get(0,1), MathContext.DECIMAL128 ),
+			     new BigDecimal( Vin.get(1,1), MathContext.DECIMAL128 ),
+			     new BigDecimal( Vin.get(2,1), MathContext.DECIMAL128 ),
+			     new BigDecimal( Vin.get(3,1), MathContext.DECIMAL128 ),
+			     new BigDecimal( Vin.get(4,1), MathContext.DECIMAL128 ) };
+
+	// New covariance matrix, both as Matrix and as 2D array of BigDecimal.
+	Matrix Vp = new Matrix(5,5);
+	BigDecimal BigZero = new BigDecimal ( 0., MathContext.DECIMAL128 );
+	BigDecimal[][] VpBig = { { BigZero, BigZero, BigZero, BigZero, BigZero},
+				 { BigZero, BigZero, BigZero, BigZero, BigZero},
+				 { BigZero, BigZero, BigZero, BigZero, BigZero},
+				 { BigZero, BigZero, BigZero, BigZero, BigZero},
+				 { BigZero, BigZero, BigZero, BigZero, BigZero} };
+
+
+	for ( int i=0; i<5; ++i ){
+	    for ( int j=i; j<5; ++j ){
+
+		BigDecimal a = U00.multiply(Vi0[j]);
+		BigDecimal b = U01.multiply(Vi1[j]);
+		BigDecimal c = U01.multiply(Vi0[j]);
+		BigDecimal d = U11.multiply(Vi1[j]);
+
+		BigDecimal s1 = Vi0[i].multiply( a.add(b));
+		BigDecimal s2 = Vi1[i].multiply( c.add(d));
+
+		BigDecimal Vij = new BigDecimal( Vin.get(i,j), MathContext.DECIMAL128 );
+		BigDecimal Vijnew = Vij.subtract( s1.add(s2) );
+
+		Vp.set(i,j,Vijnew.doubleValue() );
+		VpBig[i][j] = Vijnew;
+		double denom = (Vp.get(i,j)+Vt.get(i,j))/2.;
+		if ( denom != 0. ){
+		    double frac = (Vp.get(i,j)-Vt.get(i,j))/denom;
+		    aida.cloud1D( "/Bugs/AddFit/Frac Vdiff " + i + " " + j ).fill(frac);
+		}
+		if ( i != j ){
+		    Vp.set(j,i,Vp.get(i,j));
+		    VpBig[j][i] = Vijnew;
+		}
+	    }
+	}
+
+	// Predicted-measured vector as BigDecimal.
+	BigDecimal dM0 = new BigDecimal( dM.get(0,0), MathContext.DECIMAL128);
+	BigDecimal dM1 = new BigDecimal( dM.get(1,0), MathContext.DECIMAL128);
+
+	// New track parameters, both as Matrix and as 2D array of BigDecimal.
+	BigDecimal[] etanew = { BigZero, BigZero, BigZero, BigZero, BigZero };
+	Matrix etap = new Matrix(5,1);
+	for ( int i=0; i<5; ++i ){
+	    BigDecimal rx = VpBig[i][0].divide(sigsqx,MathContext.DECIMAL128);
+	    BigDecimal ry = VpBig[i][1].divide(sigsqy,MathContext.DECIMAL128);
+	    BigDecimal deta = (rx.multiply(dM0)).add(ry.multiply(dM1));
+	    BigDecimal etai = new BigDecimal( etain.get(i,0),MathContext.DECIMAL128);
+	    etanew[i] = etai.subtract(deta);
+	    etap.set(i,0,etanew[i].doubleValue());
+	    aida.cloud1D("/Bugs/AddFit/Diff eta " + i).fill(etap.get(i,0)-etat.get(i,0));
+	    double denom = (etap.get(i,0)+etat.get(i,0))/2.;
+	    if ( denom != 0. ){
+		double frac = (etap.get(i,0)-etat.get(i,0))/denom;
+		aida.cloud1D("/Bugs/AddFit/Frac Diff eta " + i).fill(frac);
+	    }
+
+	}
+
+	System.out.println ("Hack 2D " + dM0 + " " + dM1 );
+	PrintSymMatrix psm = new PrintSymMatrix();
+	psm.Print(etap, Vp);
+
+
+    }
+    
+}
+

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util
CylEloss.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/CylEloss.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/CylEloss.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,360 @@
+package org.hps.recon.tracking.kalman.util;
+
+import static java.lang.Math.abs;
+import static java.lang.Math.cos;
+import static java.lang.Math.sqrt;
+import static org.lcsim.recon.tracking.trfcyl.SurfCylinder.IALF;
+import static org.lcsim.recon.tracking.trfcyl.SurfCylinder.IPHI;
+import static org.lcsim.recon.tracking.trfcyl.SurfCylinder.IQPT;
+import static org.lcsim.recon.tracking.trfcyl.SurfCylinder.ITLM;
+import static org.lcsim.recon.tracking.trfcyl.SurfCylinder.IZ;
+
+import org.lcsim.recon.tracking.trfbase.ETrack;
+import org.lcsim.recon.tracking.trfbase.Interactor;
+import org.lcsim.recon.tracking.trfbase.PropDir;
+import org.lcsim.recon.tracking.trfbase.Propagator;
+import org.lcsim.recon.tracking.trfbase.Surface;
+import org.lcsim.recon.tracking.trfbase.TrackError;
+import org.lcsim.recon.tracking.trfbase.TrackVector;
+import org.lcsim.recon.tracking.trfcyl.SurfCylinder;
+import org.lcsim.recon.tracking.trfeloss.DeDx;
+import org.lcsim.recon.tracking.trfutil.Assert;
+import org.lcsim.util.aida.AIDA;
+
+/**
+ * Class for modifying the covariance matrix of a track which
+ * has been propagated to an InteractingLayer containing
+ * a LayerCylinder. The modifications correspond to energy
+ *loss in a cylindrical shell whose material is
+ *represented by the thickness and energy loss model
+ * is represented by a DeDx class.
+ *
+ *@author Norman A. Graf
+ *@version 1.0
+ *
+ */
+public class CylEloss extends Interactor
+{
+
+    // Added for debugging.
+    private AIDA aida = AIDA.defaultInstance();
+    static private boolean donew = false;
+    public static void SetNewModel( boolean b ){
+	donew = b;
+    }
+    
+    //attributes
+    
+    private double _thickness;
+    private DeDx _dedx;
+    
+    //methods
+    
+    //
+    
+    /**
+     *Construct an instance from the cylindrical shell's thickness and dE/dx class.
+     *
+     * @param   thickness The thickness of the cylindrical shell.
+     * @param   dedx The DeDx model of energy loss to use.
+     */
+    public CylEloss(double thickness, DeDx dedx)
+    {
+        _thickness = thickness;
+        _dedx = dedx;
+    }
+    
+    //
+    
+    /**
+     *Interact the given track in this cylindrical shell,
+     *using the DeDx model for energy loss.
+     *Note that both the track parameters and the
+     *covariance matrix are updated to reflect the uncertainty caused
+     *by traversing the cylindrical shell of material.
+     *
+     * @param   tre The ETrack to scatter.
+     */
+    public void interact(ETrack tre)
+    {
+        // This can only be used with cylinders... check that we have one..
+        
+        SurfCylinder cyl = new SurfCylinder(10.0);
+        Surface srf = tre.surface();
+        Assert.assertTrue( srf.pureType().equals(cyl.pureType()) );
+        
+        TrackError cleanError = tre.error();
+        TrackError newError = new TrackError(cleanError);
+        
+        TrackVector theVec = tre.vector();
+        TrackVector newVector = new TrackVector(theVec);
+        
+        double pionMass = 0.13957; // GeV
+        double ptmax = 10000.; // GeV
+        
+        double pinv = Math.abs(theVec.get(SurfCylinder.IQPT)*Math.cos(Math.atan(theVec.get(SurfCylinder.ITLM))));
+        
+        // make sure pinv is greater than a threshold (1/ptmax)
+        // in this case assume q = 1, otherwise q = q/pt/abs(q/pt)
+        
+        double sign = 1;
+        if(pinv < 1./ptmax)
+            pinv = 1./ptmax;
+        else
+            sign = theVec.get(SurfCylinder.IQPT)/Math.abs(theVec.get(SurfCylinder.IQPT));
+        
+        // Evaluate the initial energy assuming the particle is a pion.
+        
+        double trackEnergy = Math.sqrt(1./pinv/pinv+pionMass*pionMass);
+        
+        double trueLength = _thickness/Math.abs(Math.cos(theVec.get(SurfCylinder.IALF)))/
+                Math.cos(Math.atan(theVec.get(SurfCylinder.ITLM)));
+        // assume the energy loss distribution to be Gaussian
+        double stdEnergy = _dedx.sigmaEnergy(trackEnergy, trueLength);
+        
+        double stdMomentum = stdEnergy;
+        // What direction are we going?
+        // If forward, that means we lose energy
+        // backwards means gain energy
+        if(tre.isTrackBackward()) trueLength = -trueLength;
+        trackEnergy = _dedx.loseEnergy(trackEnergy, trueLength);
+        
+        double newMomentum = trackEnergy>pionMass ?
+            Math.sqrt(trackEnergy*trackEnergy-
+                pionMass*pionMass): 1./pinv;
+        
+        // Only vec(SurfCylinder.IQPT) changes due to E loss.
+        newVector.set(SurfCylinder.IQPT, 1./newMomentum/Math.cos(Math.atan(theVec.get(SurfCylinder.ITLM)))*sign);
+        
+        // Also only error(SurfCylinder.IQPT,IQPT) changes.
+        double stdVec = theVec.get(SurfCylinder.IQPT)*theVec.get(SurfCylinder.IQPT)*stdMomentum*Math.cos(Math.atan(
+                theVec.get(SurfCylinder.ITLM)));
+        stdVec *= stdVec;
+        newError.set(SurfCylinder.IQPT, SurfCylinder.IQPT,  newError.get(SurfCylinder.IQPT, SurfCylinder.IQPT) + stdVec);
+        
+        tre.setVectorAndKeepDirection(newVector);
+        tre.setError( newError );
+        
+    }
+    
+    public void interact_dir(ETrack theTrack, PropDir direction )
+    {
+        // This can only be used with cylinders... check that we have one..
+        
+        Surface srf = theTrack.surface();
+        Assert.assertTrue( srf instanceof SurfCylinder );
+        
+        // Reduced direction must be forward or backward.
+        
+        Propagator.reduceDirection(direction);
+        Assert.assertTrue(direction == PropDir.FORWARD || direction == PropDir.BACKWARD);
+        
+        TrackError cleanError = theTrack.error();
+        TrackError newError = new TrackError(cleanError);
+        
+        TrackVector theVec = theTrack.vector();
+        TrackVector newVector = new TrackVector(theVec);
+        
+        double pionMass = 0.13957; // GeV
+        double ptmax = 10000.; // GeV
+        
+        double tanlm = theVec.get(ITLM);
+        double coslm = 1. / sqrt(1. + tanlm*tanlm);
+        double pinv = abs(theVec.get(IQPT)*coslm);
+        
+        // make sure pinv is greater than a threshold (1/ptmax)
+        // in this case assume q = 1, otherwise q = q/pt/abs(q/pt)
+        
+        int sign = 1;
+        if ( pinv < 1./ptmax )
+            pinv = 1./ptmax;
+        else
+            sign = (int) (theVec.get(IQPT)/abs(theVec.get(IQPT)));
+        
+	/*
+	System.out.println ("Sign test: " 
+			    + sign + " " 
+			    + theVec.get(IQPT) + " " 
+			    + pinv + " "
+			    + 1./ptmax + " "
+			    + (pinv<1./ptmax)
+			    );
+	*/
+
+        // Evaluate the initial energy assuming the particle is a pion.
+        
+        double trackEnergy = sqrt(1./pinv/pinv+pionMass*pionMass);
+        
+        double trueLength = _thickness/abs(cos(theVec.get(IALF)))/coslm;
+
+        if(direction == PropDir.BACKWARD){
+	    aida.cloud1D("Test/Truelength Fit backward").fill(trueLength);
+	}else{
+	    aida.cloud1D("Test/Truelength Fit forward").fill(trueLength);
+	}
+        
+        // assume the energy loss distribution to be Gaussian
+        double stdEnergy = _dedx.sigmaEnergy(trackEnergy, trueLength);
+
+	aida.cloud1D("Test/sigma e, fit").fill(stdEnergy);
+        
+        double stdMomentum = stdEnergy; 
+        if(direction == PropDir.BACKWARD)
+            trueLength = -trueLength;
+	double eold = trackEnergy;
+        trackEnergy = _dedx.loseEnergy(trackEnergy, trueLength);
+
+
+        if(direction == PropDir.BACKWARD){
+	    aida.cloud1D("Test/DE Backwards").fill(trackEnergy-eold);
+	}else{
+	    aida.cloud1D("Test/DE Forwards").fill(trackEnergy-eold);
+	}
+    
+        double newMomentum = trackEnergy>pionMass ?
+            sqrt(trackEnergy*trackEnergy-
+                pionMass*pionMass): 1./pinv;
+
+	double kold = theVec.get(IQPT);
+	double knew = 1./newMomentum/coslm*sign;
+
+        // Only vec(IQPT) changes due to E loss.
+        newVector.set(IQPT, knew);
+        
+        double stdVec = theVec.get(IQPT)*trackEnergy/newMomentum/newMomentum*stdEnergy;
+        double ddk = stdVec*stdVec;
+	
+	if ( !donew ){
+
+	    // Just the staggling term.
+	    double vkk =   newError.get(IQPT,IQPT) + ddk;
+	    newError.set(IQPT, IQPT, vkk);
+	}
+	else{
+
+	    stdVec = kold*eold*pinv*pinv*stdEnergy;
+	    ddk    = stdVec*stdVec;
+
+	    // Following the CLEO internal note: CBX-96-20.
+	    SurfCylinder cyl = (SurfCylinder)theTrack.surface();
+	    double r = cyl.radius();
+	    
+	    double re  = trackEnergy/eold;
+	    double rk  = knew/kold;
+	    double rk2 = rk*rk;
+	    double t   = theVec.get(ITLM);
+	    double rt  = t/( 1. + t*t );
+	
+	    double a  = rk2*rk*re;
+	    double b  = knew*rt*( 1. - rk2*re);
+	    a = 1.;
+	    b = 0.;
+	    double sb = sign*b;
+	    if ( direction == PropDir.FORWARD ){
+		if ( r < 10 ){
+		    aida.cloud1D("A Vtx Fwd").fill(a);
+		    aida.cloud1D("B Vtx Fwd" ).fill(sb);
+		}else{
+		    aida.cloud1D("A Trk Fwd").fill(a);
+		    aida.cloud1D("B Trk Fwd").fill(sb);
+		}
+		aida.cloud2D("r vs A Fwd").fill(r,a);
+		aida.cloud2D("r vs B Fwd").fill(r,sb);
+	    }else{
+		if ( r < 10 ){
+		    aida.cloud1D("A Vtx Bwd").fill(a);
+		    aida.cloud1D("B Vtx Bwd" ).fill(sb);
+		}else{
+		    aida.cloud1D("A Trk Bwd").fill(a);
+		    aida.cloud1D("B Trk Bwd").fill(sb);
+		}
+		aida.cloud2D("r vs A Bwd").fill(r,a);
+		aida.cloud2D("r vs B Bwd").fill(r,sb);
+	    }
+	    double vkk =    a*a*newError.get(IQPT,IQPT) +
+		         2.*a*b*newError.get(IQPT,ITLM) +
+		            b*b*newError.get(ITLM,ITLM) + ddk;
+	    double vka =      a*newError.get(IQPT,IALF) + b*newError.get(ITLM,IALF);
+	    double vkf =      a*newError.get(IQPT,IPHI) + b*newError.get(ITLM,IPHI);
+	    double vkt =      a*newError.get(IQPT,ITLM) + b*newError.get(ITLM,ITLM);
+	    double vkz =      a*newError.get(IQPT,IZ  ) + b*newError.get(ITLM,IZ  );
+	    
+	    // Also only error(IQPT,IQPT) changes due to straggling.
+	    newError.set(IQPT, IQPT, vkk);
+	    newError.set(IQPT, IALF, vka);
+	    newError.set(IQPT, IPHI, vkf);
+	    newError.set(IQPT, ITLM, vkt);
+	    newError.set(IQPT, IZ  , vkz);
+
+	    newError.set(IALF, IQPT, vka);
+	    newError.set(IPHI, IQPT, vkf);
+	    newError.set(ITLM, IQPT, vkt);
+	    newError.set(IZ  , IQPT, vkz);
+	}
+
+// TODO introduce axial definition to ETrack
+//  // Axial track?
+//  if(theTrack.is_axial()) {
+//    newError(IPHI,IZ) = 0.;
+//    newError(IZ,IZ) = 0.;
+//    newError(IALF,IZ) = 0.;
+//    newError(ITLM,IZ) = 0.;
+//    newError(IQPT,IZ) = 0.;
+//    newError(IPHI,ITLM) = 0.;
+//    newError(IALF,ITLM) = 0.;
+//    newError(ITLM,ITLM) = 0.;
+//    newError(IQPT,ITLM) = 0.;
+//  }
+        
+        theTrack.setVector(newVector);
+        theTrack.setError( newError );
+        
+    }
+    
+//
+    
+    /**
+     *Return the thickness of material in the cylindrical shell.
+     *
+     * @return The thickness of the  energy loss material.
+     */
+    public double thickness()
+    {
+        return _thickness;
+    }
+    
+//
+    
+    /**
+     *Return the energy loss model used in this Interactor.
+     *
+     * @return The DeDx class representing energy loss.
+     */
+    public DeDx dEdX()
+    {
+        return _dedx; //cng shallow copy!
+    }
+    
+//
+    
+    /**
+     *Make a clone of this object.
+     *
+     * @return A Clone of this instance.
+     */
+    public Interactor newCopy()
+    {
+        return new CylEloss(_thickness, _dedx);
+    }
+    
+    
+    /**
+     *output stream
+     *
+     * @return A String representation of this instance.
+     */
+    public String toString()
+    {
+        return "CylEloss with thickness "+_thickness+" and energy loss "+_dedx;
+    }
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util
CylElossSim.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/CylElossSim.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/CylElossSim.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,199 @@
+package org.hps.recon.tracking.kalman.util;
+
+import java.util.Random;
+
+import org.lcsim.recon.tracking.trfbase.SimInteractor;
+import org.lcsim.recon.tracking.trfbase.TrackVector;
+import org.lcsim.recon.tracking.trfbase.VTrack;
+import org.lcsim.recon.tracking.trfcyl.CylEloss;
+import org.lcsim.recon.tracking.trfcyl.SurfCylinder;
+import org.lcsim.recon.tracking.trfeloss.DeDx;
+import org.lcsim.recon.tracking.trfutil.Assert;
+import org.lcsim.util.aida.AIDA;
+
+/**
+* Class for simulating Energy Loss in SurfCylinders.
+ *
+ *@author Norman A. Graf
+ *@version 1.0
+ *
+*/
+public class CylElossSim extends SimInteractor
+{
+
+    private AIDA aida = AIDA.defaultInstance();
+
+    
+    //attributes
+    //thickness of the material in the cylinder
+    private double _thickness;
+    // type of energy loss being simulated
+    private DeDx _dedx;
+
+    private Random _ran = null;
+    
+    //
+    
+    /**
+     *Construct in instance with the
+     *appropriate thickness and DeDx class to model
+     * 
+     *
+     * @param   thickness Thickness of the cylindrical shell.
+     * @param   dedx The DeDx class representing energy loss.
+     */
+    public CylElossSim(double thickness, DeDx dedx)
+    {
+        _thickness = thickness;
+        _dedx = dedx;
+    }
+
+    public CylElossSim(double thickness, DeDx dedx, Random ran)
+    {
+        _thickness = thickness;
+        _dedx = dedx;
+	_ran  = ran;
+    }
+    
+    //
+    
+    /**
+     *Construct an instance from a CylEloss Interactor.
+     *
+     * @param   inter The CylEloss Interactor to use for simulation.
+     */
+    public CylElossSim(CylEloss inter)
+    {
+        _thickness = inter.thickness();
+        _dedx = inter.dEdX();
+    }
+    
+    //
+    
+    /**
+     *Interact the given track in this cylindrical shell,
+     *using the DeDx model for energy loss.
+     *Note that the track parameters are updated to reflect the
+     *energy lost by traversing the cylindrical shell of material.
+     *
+     * @param   vtrk The VTrack to scatter.
+     */
+    public void interact( VTrack vtrk )
+    {
+        // This can only be used with cylinders... check that we have one..
+        
+        Assert.assertTrue( vtrk.surface() instanceof SurfCylinder );
+        
+        
+        TrackVector theVec = vtrk.vector();
+        TrackVector newVector = new TrackVector(theVec);
+        
+        double pionMass = 0.13957; // GeV
+        double ptmax = 10000.; // GeV
+        
+        double pinv = Math.abs(theVec.get(SurfCylinder.IQPT)*Math.cos(Math.atan(theVec.get(SurfCylinder.ITLM))));
+        
+        // make sure pinv is greater than a threshold (1/ptmax)
+        // in this case assume q = 1, otherwise q = q/pt/abs(q/pt)
+        
+        double sign = 1;
+        if(pinv < 1./ptmax)
+            pinv = 1./ptmax;
+        else
+            sign = theVec.get(SurfCylinder.IQPT)/Math.abs(theVec.get(SurfCylinder.IQPT));
+        
+        // Evaluate the initial energy assuming the particle is a pion.
+        
+        double trackEnergy = Math.sqrt(1./pinv/pinv+pionMass*pionMass);
+        
+        double trueLength = _thickness/Math.abs(Math.cos(theVec.get(SurfCylinder.IALF)))/
+        Math.cos(Math.atan(theVec.get(SurfCylinder.ITLM)));
+	aida.cloud1D("Test/true length").fill(trueLength);
+	aida.cloud1D("Test/alpha").fill(theVec.get(SurfCylinder.IALF));
+	aida.cloud1D("Test/tanlam").fill(theVec.get(SurfCylinder.ITLM)  );
+	aida.histogram1D("Test/true lengthxx",1000,-0.5, 0.5).fill(trueLength);
+	aida.histogram1D("Test/tanlamba",100, -1., 1.).fill(theVec.get(SurfCylinder.ITLM)  );
+
+        // assume the energy loss distribution to be Gaussian
+        double stdEnergy = _dedx.sigmaEnergy(trackEnergy, trueLength);
+        double stdMomentum = stdEnergy;
+        // What direction are we going?
+        // If forward, that means we lose energy
+        // backwards means gain energy
+
+        if(vtrk.isTrackBackward()) {
+	    aida.cloud1D("Test/is Backwards").fill(1.);
+	}else{
+	    aida.cloud1D("Test/is Backwards").fill(-1.);
+	}
+
+        if(vtrk.isTrackBackward()) trueLength = -trueLength;
+
+	double eold = trackEnergy;
+
+        trackEnergy=_dedx.loseEnergy(trackEnergy, trueLength);
+
+	aida.cloud1D("Test/DE no smear").fill(trackEnergy-eold);
+
+	if ( _ran != null ) {
+	    trackEnergy += stdEnergy*_ran.nextGaussian();
+	}
+	aida.cloud1D("Test/DE with smear").fill(trackEnergy-eold);
+	if ( trackEnergy-eold > -0.005 ){
+	    aida.cloud1D("Test/DE with smear, detail").fill(trackEnergy-eold);
+	}
+
+        double newMomentum = trackEnergy>pionMass ?
+        Math.sqrt(trackEnergy*trackEnergy-
+        pionMass*pionMass): 1./pinv;
+        // Only vec(SurfCylinder.IQPT) changes due to E loss.
+        newVector.set(SurfCylinder.IQPT, 1./newMomentum/Math.cos(Math.atan(theVec.get(SurfCylinder.ITLM)))*sign);
+        vtrk.setVectorAndKeepDirection(newVector);
+        
+    }
+    //
+    
+    /**
+     *Return the thickness of material in the cylindrical shell.
+     *
+     * @return The thickness of the  energy loss material.
+     */
+    public double thickness()
+    { return _thickness;
+    }
+    //
+    
+     /**
+     *Return the energy loss model used in this Interactor.
+     *
+     * @return The DeDx class representing energy loss.
+     */
+    public DeDx dEdX()
+    {
+        return _dedx; //cng shallow copy!
+    }
+    
+    //
+    
+    /**
+     *Make a clone of this object.
+     * Note that new copy will have different random number generator.
+     *
+     * @return A Clone of this instance.
+     */
+    public SimInteractor newCopy()
+    {
+        return new CylElossSim(_thickness,_dedx);
+    }
+    
+    
+    /**
+     *output stream
+     *
+     * @return A String representation of this instance.
+     */
+    public String toString()
+    {
+        return "CylElossSim with thickness "+_thickness+" and energy loss "+_dedx;
+    }
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util
FullFitKalman.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/FullFitKalman.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/FullFitKalman.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,598 @@
+package org.hps.recon.tracking.kalman.util;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.lcsim.recon.tracking.trfbase.ETrack;
+import org.lcsim.recon.tracking.trfbase.Hit;
+import org.lcsim.recon.tracking.trfbase.PropDir;
+import org.lcsim.recon.tracking.trfbase.PropStat;
+import org.lcsim.recon.tracking.trfbase.Propagator;
+import org.lcsim.recon.tracking.trfbase.Surface;
+import org.lcsim.recon.tracking.trfbase.TrackError;
+import org.lcsim.recon.tracking.trfcyl.HitCylPhi;
+import org.lcsim.recon.tracking.trfcyl.HitCylPhiZ2D;
+import org.lcsim.recon.tracking.trfcyl.SurfCylinder;
+import org.lcsim.recon.tracking.trfcyl.ThinCylMs;
+import org.lcsim.recon.tracking.trfdca.SurfDCA;
+import org.lcsim.recon.tracking.trffit.FullFitter;
+import org.lcsim.recon.tracking.trffit.HTrack;
+import org.lcsim.recon.tracking.trfzp.HitZPlane1;
+import org.lcsim.recon.tracking.trfzp.HitZPlane2;
+import org.lcsim.recon.tracking.trfzp.SurfZPlane;
+import org.lcsim.recon.tracking.trfzp.ThinZPlaneMs;
+import org.lcsim.util.aida.AIDA;
+
+/**
+ *
+ * Copied from org.lcsim.recon.tracking.trffit.FullFitKalman
+ *   - added fitForward() and fitBackward() methods.
+ *   - added debug printout
+ *
+ * Full track fit using Kalman filter.  The propagator is specified
+ * when the fitter is constructed.  The starting surface, vector and
+ * error matrix are taken from the input track.  Errors should be
+ * increased appropriately if the fitter is applied repeatedly to
+ * a single track.
+ *
+ *@author $Author: jeremy $
+ *@version $Id: FullFitKalman.java,v 1.1 2011/07/28 18:28:19 jeremy Exp $
+ *
+ * Date $Date: 2011/07/28 18:28:19 $
+ *
+ */
+
+public class FullFitKalman extends FullFitter
+{
+
+    private AIDA aida = AIDA.defaultInstance();
+
+    // Flags to control: multiple scattering, energy loss and adding the hit.
+    private boolean doMs    = true;
+    private boolean doEloss = true;
+    private boolean doMeas  = true;
+
+    private double dedxscale = 1.;
+    private double dedxsigma = 0.0;
+    
+    // static methods
+    
+    //
+    
+    /**
+     *Return a String representation of the class' the type name.
+     *Included for completeness with the C++ version.
+     *
+     * @return   A String representation of the class' the type name.
+     */
+    public static String typeName()
+    { return "FullFitKalman"; }
+    
+    //
+    
+    /**
+     *Return a String representation of the class' the type name.
+     *Included for completeness with the C++ version.
+     *
+     * @return   A String representation of the class' the type name.
+     */
+    public static String staticType()
+    { return typeName(); }
+    
+    // The propagator.
+    private Propagator _pprop;
+    
+    // The add fitter.
+    private AddFitKalman _addfit;
+   
+    int AddFitKalmanDebugLevel = 0;
+    //
+    
+    /**
+     *Construct an instance specifying a propagator.
+     *
+     * @param   prop The Propagator to be used during the fit.
+     */
+    public FullFitKalman(Propagator prop)
+    {
+        _pprop = prop;
+        _addfit = new AddFitKalman();
+
+	try{
+	    ToyConfig config = ToyConfig.getInstance();
+	    AddFitKalmanDebugLevel = config.getInt( "AddFitKalmanDebugLevel", 
+						    AddFitKalmanDebugLevel );
+	    dedxscale = config.getDouble("dEdXScale");
+	    dedxsigma = config.getDouble("dEdXSigma");
+	    
+
+	} catch (ToyConfigException e){
+            System.out.println (e.getMessage() );
+            System.out.println ("Stopping now." );
+            System.exit(-1);
+        }
+	System.out.println ("FullfitKalman dedxscale: " + dedxscale );
+
+    }
+    
+    //
+    
+    /**
+     *Return a String representation of the class' type name.
+     *Included for completeness with the C++ version.
+     *
+     * @return   A String representation of the class' the type name.
+     */
+    public String type()
+    { return staticType(); }
+    
+    //
+    
+    /**
+     *Return the propagator.
+     *
+     * @return The Propagator used in the fit.
+     */
+    public  Propagator propagator()
+    { return _pprop; }
+    
+    //
+
+    public void setDoMs( boolean b){
+	doMs = b;
+    }
+
+    public void setDoEloss( boolean b){
+	doEloss = b;
+    }
+    
+    /**
+     *Fit the specified track.
+     *
+     * @param   trh The HTrack to fit.
+     * @return 0 if successful.
+     */
+    public int fit(HTrack trh)
+    {
+        // Copy the hits from the track.
+        List hits = trh.hits();
+        //System.out.println("Hits has "+hits.size()+" elements");
+        // Delete the list of hits from the track.
+        while ( trh.hits().size()>0 ) trh.dropHit();
+        //System.out.println("Hits has "+hits.size()+" elements");
+        
+        // Set direction to be nearest.
+        //PropDir dir = PropDir.NEAREST;
+        PropDir dir = PropDir.FORWARD;
+	RKDebug.Instance().setPropDir(dir);
+        
+        // Loop over hits and fit.
+        int icount = 0;
+        for ( Iterator ihit=hits.iterator(); ihit.hasNext(); )
+        {
+
+            // Extract the next hit pointer.
+            Hit hit = (Hit)ihit.next();
+            //System.out.println("Hit "+icount+" is: \n"+hit);
+            // propagate to the surface
+	    //System.out.println ("Before prop: " + trh.newTrack() );
+            PropStat pstat = trh.propagate(_pprop,hit.surface(),dir);
+            
+	    //System.out.println ("After prop: " + trh.newTrack() );
+            // fit track
+            //System.out.println("trh= \n"+trh+", hit= \n"+hit);
+            //System.out.println("_addfit= "+_addfit);
+            int fstat = _addfit.addHit(trh,hit);
+	    //System.out.println ("After addhit: " + fstat + " " 
+	    //		+ trh.chisquared() + "\n" + trh.newTrack() );
+            if ( fstat>0 ) return 10000 + 1000*fstat + icount;
+            
+        }
+        return 0;
+        
+    }
+    
+    public int fitForward(HTrack trh)
+    {
+
+        PropDir dir = PropDir.FORWARD;
+	RKDebug.Instance().setPropDir(dir);
+
+        // Copy the hits from the track.
+        List hits = trh.hits();
+
+        // Delete the list of hits from the track.
+        while ( trh.hits().size()>0 ) trh.dropHit();
+       
+	double sumde = 0.;
+        
+        // Loop over hits and fit.
+        int icount = 0;
+        for ( Iterator ihit=hits.iterator(); ihit.hasNext(); )
+        {
+	    Surface s_save = trh.newTrack().surface().newPureSurface();
+	    ETrack e_save = trh.newTrack();
+
+            // Extract the next hit pointer.
+            Hit hit = (Hit)ihit.next();
+
+	    int from = (new SurfaceCode(s_save)).getCode();
+	    int to   = (new SurfaceCode(hit.surface())).getCode();
+
+	    // Propagate to the next surface.
+            PropStat pstat = trh.propagate(_pprop,hit.surface(),dir);
+            if ( ! pstat.success() ) {
+		if ( AddFitKalmanDebugLevel > 0 ) {
+		    System.out.println ("Error:        "  
+					+ RKDebug.Instance().getTrack() + " " 
+					+ RKDebug.Instance().getPropDir() + " " 
+					+ icount
+					);
+		    System.out.println ("From surface 5: " + s_save );
+		    System.out.println ("To surface 5:   " + hit.surface());
+		    System.out.println ("Params: " + e_save.vector() );
+		}
+		aida.histogram1D("/Bugs/Fit/Failed Fwd prop from Surface",5,0,5).fill( from );
+		aida.histogram1D("/Bugs/Fit/Failed Fwd prop to Surface",5,0,5).fill( to  );
+		aida.cloud2D("/Bugs/Fit/Failed Fwd prop to vs from Surface").fill( from, to  );
+
+		return icount+1;
+	    }
+	    
+	    //if ( icount != 0 ) {
+	    //	int istat = interact( trh, hit, dir );
+	    //}
+
+
+	    // Add the hit.
+            int fstat = _addfit.addHit(trh,hit);
+	    if ( fstat>0 ){
+		if ( AddFitKalmanDebugLevel > 0){
+		
+		    System.out.println ("Error:        "  
+					+ RKDebug.Instance().getTrack() + " " 
+					+ RKDebug.Instance().getPropDir() + " " 
+					);
+		    System.out.println ("From surface 4: " + s_save );
+		    System.out.println ("To surface 4:   " + hit.surface());		
+		}
+		aida.histogram1D("/Bugs/Fit/Failed Fwd addhit from Surface",5,5,5).fill( from );
+		aida.histogram1D("/Bugs/Fit/Failed Fwd addhit to Surface",5,0,5).fill( to  );
+		aida.cloud2D("/Bugs/Fit/Failed Fwd addhit to vs from Surface").fill( from, to  );
+
+	    }
+            if ( fstat>0 ) return 10000 + 1000*fstat + icount;
+
+	    VTUtil before = new VTUtil( trh.newTrack() );
+	    int istat = interact( trh, hit, dir );
+	    VTUtil after = new VTUtil( trh.newTrack() );
+
+	    double de = before.e() - after.e();
+	    sumde += de;
+
+	    //SurfCylinder ss = (SurfCylinder)trh.newTrack().surface();
+	    //System.out.printf ("Forw dedx: %10.4f %12.8f  %12.8f\n", ss.radius(), de, sumde );
+
+
+            ++icount;
+        }
+
+
+	//System.out.println ("Forward fit sumde: " + sumde );
+	aida.cloud1D("Forward dedx check:").fill(sumde-RKDebug.Instance().getDeGen());
+
+        return 0;
+        
+    }
+
+    public int fitBackward(HTrack trh)
+    {
+        PropDir dir = PropDir.BACKWARD;
+	RKDebug.Instance().setPropDir(dir);
+
+	//RKPrintSymMatrix psm = new RKPrintSymMatrix();
+
+        // Copy the hits from the track.
+        List hits = trh.hits();
+
+        // Delete the list of hits from the track.
+        while ( trh.hits().size()>0 ) trh.dropHit();
+
+	double chold = 0.;
+
+	double sumde = 0.;
+
+	RKZot zot = new RKZot(trh);
+	boolean zottable = true;
+
+	int nc = 0;
+	int nz = 0;
+	int nu = 0;
+	String thishit;
+
+
+        // Loop over hits and fit.
+        int icount = 0;
+        for ( Iterator ihit=hits.iterator(); ihit.hasNext(); )
+        {
+            // Extract the next hit pointer.
+            Hit hit = (Hit)ihit.next();
+
+	    Surface s_save = trh.newTrack().surface().newPureSurface();
+
+	    int from = (new SurfaceCode(s_save)).getCode();
+	    int to   = (new SurfaceCode(hit.surface())).getCode();
+
+	    /*
+	    Surface s_new  = hit.surface();
+	    if ( s_new instanceof SurfCylinder ){
+		System.out.printf ("Next: %3d Cylinder\n",icount);
+		++nc;
+		thishit = "Cylinder";
+	    } else if ( s_new instanceof SurfZPlane ){
+		System.out.printf ("Next: %3d ZPlane\n",icount);
+		++nz;
+		thishit = "ZPlane";
+		zottable = false;
+	    } else {
+		System.out.printf ("Next: %3d Unknown\n",icount);
+		++nu;
+		thishit = "Unknown";
+	    }
+	    */
+	    if ( hit instanceof HitCylPhi ){
+		//System.out.printf ("Next: %3d Cylinder 1D\n",icount);
+		++nc;
+		thishit = "Cylinder1D";
+	    } else if ( hit instanceof HitCylPhiZ2D ){
+		//System.out.printf ("Next: %3d Cylinder 2D\n",icount);
+		++nc;
+		++nz;
+		zottable = false;
+		thishit = "Cylinder2D";
+	    } else if ( hit instanceof HitZPlane1 ){
+		//System.out.printf ("Next: %3d ZPlane 1D\n",icount);
+		++nc;
+		++nz;
+		zottable = false;
+		thishit = "ZPlane1D";
+	    } else if ( hit instanceof HitZPlane2 ){
+		//System.out.printf ("Next: %3d ZPlane 2D\n",icount);
+		++nc;
+		++nz;
+		zottable = false;
+		thishit = "ZPlane2D";
+	    } else{
+		System.out.printf ("Next: %3d Unknown\n",icount);
+		thishit = "Unknown";
+	    }
+	    //System.out.println("Error before prop: ");
+	    //psm.Print(trh.newTrack());
+
+            PropStat pstat = trh.propagate(_pprop,hit.surface(),dir);
+
+            if ( ! pstat.success() ) {
+		if ( AddFitKalmanDebugLevel > 0 ){
+		    System.out.println ("Error:        "  
+					+ RKDebug.Instance().getTrack() + " " 
+					+ RKDebug.Instance().getPropDir() + " " 
+					+ icount
+					);
+		    System.out.println ("From surface 1: " + s_save );
+		    System.out.println ("To surface 1:   " + hit.surface());
+		    System.out.println ("Failed prop: " + nc + " " + nz + " " + nu + " " + thishit );
+		}
+
+		aida.histogram1D("/Bugs/Fit/Failed prop from Surface",5,0,5).fill( from );
+		aida.histogram1D("/Bugs/Fit/Failed prop to Surface",5,0,5).fill( to  );
+		aida.cloud2D("/Bugs/Fit/Failed prop to vs from Surface").fill( from, to  );
+
+		return icount+1;
+	    }
+	    //System.out.println("Error after prop: ");
+	    //psm.Print(trh.newTrack());
+
+	    if ( zottable ){
+	    	zot.Zot(trh);
+		//System.out.println("Error after zot: ");
+		//psm.Print(trh.newTrack());
+	    }
+	    
+
+	    //if ( icount != 0 ) {
+	    //int istat = interact( trh, hit, dir );
+	    //}
+	    //VTUtil before = new VTUtil( trh.newTrack() );
+	    //int istat = interact( trh, hit, dir );
+	    //VTUtil after = new VTUtil( trh.newTrack() );
+
+
+	    // Add the hit.
+            int fstat = _addfit.addHit(trh,hit);
+
+	    //System.out.println ("Hit info: " + hit );
+
+
+	    if ( fstat>0 ){
+		if ( AddFitKalmanDebugLevel > 0){
+		    System.out.println ("Error:        "  
+					+ RKDebug.Instance().getTrack() + " " 
+					+ RKDebug.Instance().getPropDir() + " " 
+					);
+		    System.out.println ("From surface 2: " + s_save );
+		    System.out.println ("To surface 2:   " + hit.surface());		
+		    System.out.println ("Failed addhit: " + nc + " " + nz + " " + nu + " " + thishit );
+		}
+		aida.histogram1D("/Bugs/Fit/Failed addhit from Surface",5,0,5).fill( from );
+		aida.histogram1D("/Bugs/Fit/Failed addhit to Surface",5,0,5).fill( to  );
+		aida.cloud2D("/Bugs/Fit/Failed addhit to vs from Surface").fill( from, to  );
+
+	    }
+            if ( fstat>0 ) return 10000 + 1000*fstat + icount;
+
+
+	    double chnew = trh.chisquared();
+	    double dch = chnew - chold;
+
+	    //System.out.printf("Error after addhit: %15.5f\n", dch);
+	    //psm.Print(trh.newTrack());
+
+	    /*
+	    if( dch < -0.001 ){
+		System.out.println ("From surface 3: " + s_save );
+		System.out.println ("To surface 3:   " + hit.surface());				
+	    }
+	    */
+	    chold = chnew;
+
+	    // Save track for diagnostics.
+	    VTUtil before = new VTUtil( trh.newTrack() );
+
+	    // Apply multiple scattering and energy loss
+	    int istat = interact( trh, hit, dir );
+
+	    // Compute change in energy.
+	    VTUtil after = new VTUtil( trh.newTrack() );
+	    double de = after.e() - before.e();
+
+	    sumde += de;
+
+	    //SurfCylinder ss = (SurfCylinder)trh.newTrack().surface();
+	    //System.out.printf ("Back dedx: %10.4f %12.8f  %12.8f\n", ss.radius(), de, sumde );
+            ++icount;
+        }
+
+	// Propagate to the beampipe and interact.
+	if ( doMs ){
+
+	    // Beampipe parameters for sid02
+	    double radius = 1.22;
+	    double l_over_radl = 0.006136;
+
+	    SurfCylinder sbp = new SurfCylinder(radius);
+	    PropStat pstat = trh.propagate( _pprop, sbp, dir );
+	    if ( ! pstat.success() ) return -2;
+
+	    int istat = interactonly( trh, radius, l_over_radl );
+
+	}
+
+	// Propagate to the PCAO.
+	SurfDCA sdca = new SurfDCA( 0., 0. );
+	PropStat pstat = trh.propagate( _pprop, sdca, dir );
+	if ( ! pstat.success() ) return -1;
+
+	//System.out.println ("Backwards fit sumde: " + sumde );
+	aida.cloud1D("Backward dedx check:").fill(sumde-RKDebug.Instance().getDeGen());
+
+	//System.out.println("Error at PCAO: ");
+	//psm.Print(trh.newTrack());
+
+        return 0;
+        
+    }
+
+    private int interact ( HTrack trh, Hit hit, PropDir dir ){
+
+	if ( hit.surface().pureType().equals(SurfCylinder.staticType()) ){
+
+	    SurfCylinder s = (SurfCylinder) hit.surface();
+	    double r = s.radius();
+	    if ( doMs ){
+		TrackError eold = trh.newTrack().error(); 
+		
+		aida.histogram1D("/Bugs/Fit/Fit scat radius:",300,0.,150.).fill(r);
+		
+		double l_over_radl = 0.;
+		if ( r < 1.3 ) {
+		    l_over_radl = 0.006136;
+		}else if ( r < 10. ){
+		    l_over_radl = 0.000916;
+		}else {
+		    l_over_radl = 0.013747;
+		}
+
+		ThinCylMs scat = new ThinCylMs(l_over_radl*RKDebug.Instance().getMsFac());
+		ETrack et = trh.newTrack();
+		ETrack ets = new ETrack(et);
+		double chnew = trh.chisquared();
+		
+		scat.interact(et);
+		hit.update(et);
+		trh.setFit(et,chnew);
+
+		/*
+		  for ( int i=0; i<5; ++i ){
+		  double ex1 = et.error().get(i,i);
+		  double ex2 = ets.error().get(i,i);
+		  double sigsq = ex1-ex2;
+		  //double pull = -9.;
+		  double sig=-1.;
+		  if ( sigsq > 0. ){
+		  sig = Math.sqrt(sigsq);
+		  //pull = (et.vector(i)-ets.vector(i))/sig;
+		  }
+		  aida.cloud1D("/Bugs/Fit/Forward Fit Delta param:"+i).fill(et.vector(i)-ets.vector(i));
+		  if ( sig > 0. ) aida.cloud1D("/Bugs/Fit/Forward Fit Delta error:"+i).fill(sig);
+		  }
+		  //System.out.println( "Error after: " + trh.newTrack().error().minus(eold) );
+		  */
+	    } // end if MS enabled
+
+
+	} // end CYlinder MS
+	
+	if ( hit.surface().pureType().equals(SurfZPlane.staticType()) ){
+	    
+	    SurfZPlane s = (SurfZPlane) hit.surface();
+	    double z = s.z();
+	    if ( doMs ){
+		TrackError eold = trh.newTrack().error(); 
+		
+		aida.histogram1D("/Bugs/Fit/Fit scat z forward:",300,-150,150.).fill(z);
+		
+		double l_over_radl = ( Math.abs(z)< 25) ? 0.000916 : 0.013747;
+		ThinZPlaneMs scat = new ThinZPlaneMs(l_over_radl*RKDebug.Instance().getMsFac());
+		ETrack et = trh.newTrack();
+		//		ETrack ets = new ETrack(et);
+		double chnew = trh.chisquared();
+		
+		scat.interact(et);
+		hit.update(et);
+		trh.setFit(et,chnew);
+		
+	    } // end if MS enabled.
+	    
+	} // end ZPlane MS
+	
+	// Successful return;
+	return 0;
+    }
+
+
+    // There is no hit at this site so we only need to do the interaction, not update hits.
+    private int interactonly ( HTrack trh, double r, double l_over_radl ){
+
+	ThinCylMs scat = new ThinCylMs(l_over_radl*RKDebug.Instance().getMsFac());
+	ETrack et = trh.newTrack();
+	double chnew = trh.chisquared();
+	
+	scat.interact(et);
+	trh.setFit(et,chnew);
+	
+	// Successful return;
+	return 0;
+    }
+ 
+    /**
+     *output stream
+     *
+     * @return The String representation of this instance.
+     */
+    public String toString()
+    {
+        return getClass().getName();
+    }
+    
+}
+

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util
HitNull.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/HitNull.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/HitNull.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,97 @@
+package org.hps.recon.tracking.kalman.util;
+
+import org.lcsim.recon.tracking.trfbase.ETrack;
+import org.lcsim.recon.tracking.trfbase.Hit;
+import org.lcsim.recon.tracking.trfbase.HitDerivative;
+import org.lcsim.recon.tracking.trfbase.HitError;
+import org.lcsim.recon.tracking.trfbase.HitVector;
+import org.lcsim.recon.tracking.trfutil.Assert;
+
+/**
+ * 
+ * A null hit so that I have a way to add pure
+ * scattering surfaces to HTracks.
+ *
+ *@author $Author: jeremy $
+ *@version $Id: HitNull.java,v 1.1 2011/07/28 18:28:19 jeremy Exp $
+ *
+ * Date $Date: 2011/07/28 18:28:19 $
+ *
+ */
+
+
+public class HitNull extends Hit
+{
+    
+    private static final int SIZE=0;
+    private int _ival;
+            
+    public String toString()
+    {
+	return "Dummy hit prediction " + _ival + "\n"
+	    + "Cluster address: " + _pclus + "\n"
+	    + "Cluster: " + _pclus + "\n";
+    }
+            
+    protected boolean equal(Hit hp)
+    {
+	Assert.assertTrue( hp.type().equals(type()) );
+	// All null hits are equal to each other.
+	return true;
+    }
+            
+    // static methods
+    // Return the type name.
+    public static String typeName()
+    { return "HitNull";
+    }
+
+    // Return the type.
+    public static String staticType()
+    { return typeName();
+    }
+            
+    public HitNull()
+    {
+    }
+            
+    HitNull( HitNull ht)
+    {
+    }
+
+    public String type()
+    { return staticType();
+    }
+    
+    public int size()
+    { return SIZE;
+    };
+
+    public HitVector measuredVector()
+    {
+	return new HitVector();
+    }
+    public HitError measuredError()
+    {
+	return new HitError();
+    }
+    public HitVector predictedVector()
+    {
+	return new HitVector();
+    }
+    public HitError predictedError()
+    {
+	return new HitError();
+    }
+    public HitDerivative dHitdTrack()
+    {
+	return new HitDerivative();
+    }
+    public HitVector differenceVector()
+    { return new HitVector();
+    }
+    public void update(ETrack tre)
+    { 
+    }
+}
+

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util
PrintSymMatrix.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/PrintSymMatrix.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/PrintSymMatrix.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,80 @@
+package org.hps.recon.tracking.kalman.util;
+
+import org.lcsim.recon.tracking.trfbase.ETrack;
+import org.lcsim.recon.tracking.trfbase.TrackError;
+
+import Jama.Matrix;
+
+/**
+ * 
+ * Print a square matrix, assumed to be symmetric, as sqrt(diagonal elements)
+ * and correlation coefficients.
+ *
+ *@author $Author: jeremy $
+ *@version $Id: PrintSymMatrix.java,v 1.1 2011/07/28 18:28:19 jeremy Exp $
+ *
+ * Date $Date: 2011/07/28 18:28:19 $
+ *
+ */
+
+
+public class  PrintSymMatrix{
+
+    public PrintSymMatrix(){
+    }
+
+    public void Print( TrackError e){
+	Print (e.getMatrix());
+    }
+
+    public void Print( ETrack tre){
+    	System.out.printf ( "Params: %14.8e %14.8e %14.8e %14.8e %14.8e\n",
+			    tre.vector(0),
+			    tre.vector(1),
+			    tre.vector(2),
+			    tre.vector(3),
+			    tre.vector(4)
+			    );
+	Print (tre.error().getMatrix());
+    }
+
+    public void Print( Matrix eta, Matrix m){
+    	System.out.printf ( "Params: %14.8e %14.8e %14.8e %14.8e %14.8e\n",
+			    eta.get(0,0),
+			    eta.get(1,0),
+			    eta.get(2,0),
+			    eta.get(3,0),
+			    eta.get(4,0)
+			    );
+	Print (m);
+    }
+
+
+    public void Print( Matrix m){
+	int dim = m.getColumnDimension();
+	if ( m.getRowDimension() != dim ) return;
+	
+	double[] diag = new double[dim];
+	System.out.printf ( "Diag: " );
+	for ( int i=0; i<dim; ++i ){
+	    if ( m.get(i,i) >= 0 ){
+		diag[i] = Math.sqrt(m.get(i,i));
+	    }else{
+		diag[i] = -1.;
+	    }
+	    System.out.printf ( " %14.8e", diag[i] );
+	}
+	System.out.printf("\n");
+
+	for ( int i=0; i<dim; ++i ){
+	    for ( int j=i+1; j<dim; ++j ){
+		double rho = -2.;
+		if ( diag[i] >0. && diag[j] >0. ){
+		    rho = m.get(i,j)/diag[i]/diag[j];
+		}
+		System.out.printf ("%22.16f", rho );
+	    }
+	    System.out.printf("\n");
+	}
+    }	
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util
PropDCAZ.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/PropDCAZ.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/PropDCAZ.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,294 @@
+package org.hps.recon.tracking.kalman.util;
+
+// May need to remove next line when moved to proper package.
+import org.lcsim.recon.tracking.trfbase.PropDir;
+import org.lcsim.recon.tracking.trfbase.PropDirected;
+import org.lcsim.recon.tracking.trfbase.PropStat;
+import org.lcsim.recon.tracking.trfbase.Propagator;
+import org.lcsim.recon.tracking.trfbase.Surface;
+import org.lcsim.recon.tracking.trfbase.TrackDerivative;
+import org.lcsim.recon.tracking.trfbase.VTrack;
+import org.lcsim.recon.tracking.trfcyl.SurfCylinder;
+import org.lcsim.recon.tracking.trfcylplane.PropCylZ;
+import org.lcsim.recon.tracking.trfdca.PropDCACyl;
+import org.lcsim.recon.tracking.trfdca.SurfDCA;
+import org.lcsim.recon.tracking.trfutil.Assert;
+import org.lcsim.recon.tracking.trfutil.TRFMath;
+import org.lcsim.recon.tracking.trfzp.SurfZPlane;
+
+
+/**
+ * Propagates tracks from a DCA surface to a ZPlane.
+ * It does so by creating an intermediate Cylinder surface,
+ * and using existing code to perform the transformation in two steps.
+ *<p>
+ * Propagation will fail if either the origin is not a DCA surface,
+ * or the destination is not a ZPlane.
+ *<p>
+ * The default direction for propagation is forward.
+ *<p>
+ * PropDCACyl and PropCylZ do not work in all circumstances.  See those
+ * codes for details.
+ *
+ *
+ *@author $Author: jeremy $
+ *@version $Id: PropDCAZ.java,v 1.1 2011/07/28 18:28:19 jeremy Exp $
+ *
+ * Date $Date: 2011/07/28 18:28:19 $
+ *
+ */
+public class PropDCAZ extends PropDirected
+{
+    
+    // static variables
+    // Assign track parameter indices
+    
+    public static final int IRSIGNED = SurfDCA.IRSIGNED;
+    public static final int IZ_DCA   = SurfDCA.IZ;
+    public static final int IPHID    = SurfDCA.IPHID;
+    public static final int ITLM_DCA = SurfDCA.ITLM;
+    public static final int IQPT_DCA = SurfDCA.IQPT;
+    
+    public static final int IPHI     = SurfCylinder.IPHI;
+    public static final int IZ_CYL   = SurfCylinder.IZ;
+    public static final int IALF     = SurfCylinder.IALF;
+    public static final int ITLM_CYL = SurfCylinder.ITLM;
+    public static final int IQPT_CYL = SurfCylinder.IQPT;
+        
+    private static final int IX      = SurfZPlane.IX;
+    private static final int IY      = SurfZPlane.IY;
+    private static final int IDXDZ   = SurfZPlane.IDXDZ;
+    private static final int IDYDZ   = SurfZPlane.IDYDZ;
+    private static final int IQP     = SurfZPlane.IQP;
+
+
+    // Attributes   ***************************************************
+     
+    // bfield * BFAC
+    private double _bfac;
+    
+    
+    // Methods   ******************************************************
+    
+    // static methods
+    
+    /**
+     *Return a String representation of the class' type name.
+     *Included for completeness with the C++ version.
+     *
+     * @return   A String representation of the class' type name.
+     */
+    public  static String typeName()
+    { return "PropDCAZ";
+    }
+    
+    /**
+     *Return a String representation of the class' type name.
+     *Included for completeness with the C++ version.
+     *
+     * @return   A String representation of the class' type name.
+     */
+    public  static String staticType()
+    { return typeName();
+    }
+    
+    
+    
+    /**
+     *Construct an instance from a constant solenoidal magnetic field in Tesla.
+     *
+     * @param   bfield The magnetic field strength in Tesla.
+     */
+    public PropDCAZ(double bfield)
+    {
+        super(PropDir.FORWARD);
+        _bfac=bfield * TRFMath.BFAC;
+    }
+    
+    /**
+     *Clone an instance.
+     *
+     * @return A Clone of this instance.
+     */
+    public Propagator newPropagator()
+    {
+        return new PropDCAZ( bField() );
+    }
+    
+    /**
+     *Return a String representation of the class' type name.
+     *Included for completeness with the C++ version.
+     *
+     * @return   A String representation of the class' type name.
+     */
+    public String type()
+    { return staticType();
+    }
+    
+    /**
+     *Propagate a track without error in the specified direction.
+     *and return the derivative matrix in deriv.
+     *
+     * The track parameters for a cylinder are:
+     * phi z alpha tan(lambda) curvature
+     *
+     * @param   trv The VTrack to propagate.
+     * @param   srf The Surface to which to propagate.
+     * @param   dir The direction in which to propagate.
+     * @param   deriv The track derivatives to update at the surface srf.
+     * @return The propagation status.
+     */
+    public PropStat vecDirProp( VTrack trv,  Surface srf,
+            PropDir dir, TrackDerivative deriv )
+    {
+        return dcaZPropagate( _bfac, trv, srf, dir, deriv );
+    }
+    
+    /**
+     *Propagate a track without error in the specified direction.
+     *
+     * The track parameters for a cylinder are:
+     * phi z alpha tan(lambda) curvature
+     *
+     * @param   trv The VTrack to propagate.
+     * @param   srf The Surface to which to propagate.
+     * @param   dir The direction in which to propagate.
+     * @return The propagation status.
+     */
+    public PropStat vecDirProp( VTrack trv,  Surface srf,
+            PropDir dir )
+    {
+        TrackDerivative deriv =null;
+        return vecDirProp(trv, srf, dir, deriv);
+        
+    }
+    
+    // propagate a track with error in the specified direction
+    //  PropStat err_dir_prop( ETrack& tre,  Surface& srf,
+    //                                            PropDir dir ) ;
+    
+    //
+    
+    /**
+     *Return the strength of the magnetic field in Tesla.
+     *
+     * @return The strength of the magnetic field in Tesla.
+     */
+    public  double bField()
+    {
+        return _bfac/TRFMath.BFAC;
+    }
+    
+    
+    /**
+     *output stream
+     * @return  A String representation of this instance.
+     */
+    public String toString()
+    {
+        return "DCA propagation to a ZPlane with constant "
+                + bField() + " Tesla field";
+    }
+    
+    
+    
+    /**
+     * Propagate from dca to cylinder.
+     * Why is this public?
+     *
+     * @param   _bfac The numerical factor (including the field)
+     * @param   trv The VTrack to propagate.
+     * @param   srf The cylindrical surface to which to propagate.
+     * @param   dir The direction in which to propagate.
+     * @param   deriv The track derivatives to update at the surface srf.
+     * @return The propagation status.
+     */
+    public PropStat dcaZPropagate( double          _bfac,
+				   VTrack          trv,
+				   Surface         srf,
+				   PropDir         dir,
+				   TrackDerivative deriv )
+    {
+
+        // Construct return status
+        PropStat pstat = new PropStat();
+        
+        // Fetch the originating Surface and check it is a DCA surface
+        Surface srf0 = trv.surface();
+        Assert.assertTrue( srf0.pureType().equals(SurfDCA.staticType() ));
+        if ( ! srf0.pureType( ).equals(SurfDCA.staticType()) )
+            return pstat;
+        SurfDCA srf_dca = ( SurfDCA ) srf0;
+        
+        // Check that dca surface has zero tilt.
+        boolean tilted = srf_dca.dXdZ() != 0 || srf_dca.dYdZ() != 0;
+        Assert.assertTrue(!tilted);
+        if(tilted)    return pstat;
+        
+        // Check that the destination surface is a ZPlane
+        Assert.assertTrue( srf.pureType().equals(SurfZPlane.staticType()) );
+        if ( !srf.pureType( ).equals(SurfZPlane.staticType()) )
+            return pstat;
+        SurfZPlane srf_zp = ( SurfZPlane ) srf;
+
+	// Instantiate the intermediate propagators.
+	PropDCACyl prop1 = new PropDCACyl( bField() );
+	PropCylZ   prop2 = new PropCylZ( bField() );
+
+	// Radius of a cylinder going through the PCA ...
+	// But:
+	//   PropDCACyl requires that the cylinder be at a different radius than the DCA
+	//   so put it 100 microns outside the dca.
+	double rhack = Math.abs(trv.vector(IRSIGNED))+0.01;
+	
+	// Instantiate the surface at the intermediate step.
+	SurfCylinder srf_cyl = new SurfCylinder(rhack);
+
+	// Setup for receiving the derivatives.
+	TrackDerivative d1 = null;
+	TrackDerivative d2 = null;
+	if ( deriv != null ){
+	    d1 = new TrackDerivative();
+	    d2 = new TrackDerivative();
+	}
+	
+	// Save the track z direction for later use.
+	boolean forward = trv.vector(ITLM_DCA)>=0.;
+
+	// Do the propagation in two steps.
+	PropStat p1 = prop1.vecDirProp(trv, srf_cyl, dir, d1);
+	if ( !p1.success() ) return p1;
+	PropStat p2 = prop2.vecDirProp(trv, srf_zp,  dir, d2);
+	if ( !p2.success() ) return p2;
+
+	// Forward/backward is defined wrt positive z axis.
+	if ( forward ){
+	    trv.setForward();
+	} else{
+	    trv.setBackward();
+	}
+
+	// Set the transformation matrix to the product of the those from
+	// the two intermediate steps.
+	if ( deriv != null ){
+	    deriv.set(d2.times(d1));
+	}
+
+	// Set properties of the return value.
+	if ( p2.forward() ){
+	    pstat.setForward();
+	}else if ( p2.backward() ){
+	    pstat.setBackward();
+	} else if ( p2.same() ){
+	    pstat.setSame();
+	}
+	double s = p1.pathDistance() + p2.pathDistance();
+	pstat.setPathDistance(s);
+
+
+
+	return pstat;
+	
+    }
+    
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util
PropZDCA.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/PropZDCA.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/PropZDCA.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,286 @@
+package org.hps.recon.tracking.kalman.util;
+
+// May need to remove next line when moved to proper package.
+import org.lcsim.recon.tracking.trfbase.PropDir;
+import org.lcsim.recon.tracking.trfbase.PropDirected;
+import org.lcsim.recon.tracking.trfbase.PropStat;
+import org.lcsim.recon.tracking.trfbase.Propagator;
+import org.lcsim.recon.tracking.trfbase.Surface;
+import org.lcsim.recon.tracking.trfbase.TrackDerivative;
+import org.lcsim.recon.tracking.trfbase.VTrack;
+import org.lcsim.recon.tracking.trfcyl.SurfCylinder;
+import org.lcsim.recon.tracking.trfcylplane.PropZCyl;
+import org.lcsim.recon.tracking.trfdca.PropCylDCA;
+import org.lcsim.recon.tracking.trfdca.SurfDCA;
+import org.lcsim.recon.tracking.trfutil.Assert;
+import org.lcsim.recon.tracking.trfutil.TRFMath;
+import org.lcsim.recon.tracking.trfzp.SurfZPlane;
+
+
+/**
+ * Propagates tracks from a ZPlane to a DCA surface.
+ * It does so by creating an intermediate Cylinder surface,
+ * and using existing code to perform the transformation in two steps.
+ *<p>
+ * Propagation will fail if either the origin is not a ZPlane
+ * or the destination is not a DCA Surface.
+ *<p>
+ * The default direction for propagation is forward.
+ *<p>
+ * PropZCyl and PropCylDCA do not work in all circumstances.  See those
+ * codes for details.
+ *
+ *
+ *@author $Author: jeremy $
+ *@version $Id: PropZDCA.java,v 1.1 2011/07/28 18:28:19 jeremy Exp $
+ *
+ * Date $Date: 2011/07/28 18:28:19 $
+ *
+ */
+public class PropZDCA extends PropDirected
+{
+    
+    // static variables
+    // Assign track parameter indices
+    
+    public static final int IRSIGNED = SurfDCA.IRSIGNED;
+    public static final int IZ_DCA   = SurfDCA.IZ;
+    public static final int IPHID    = SurfDCA.IPHID;
+    public static final int ITLM_DCA = SurfDCA.ITLM;
+    public static final int IQPT_DCA = SurfDCA.IQPT;
+    
+    public static final int IPHI     = SurfCylinder.IPHI;
+    public static final int IZ_CYL   = SurfCylinder.IZ;
+    public static final int IALF     = SurfCylinder.IALF;
+    public static final int ITLM_CYL = SurfCylinder.ITLM;
+    public static final int IQPT_CYL = SurfCylinder.IQPT;
+        
+    private static final int IX      = SurfZPlane.IX;
+    private static final int IY      = SurfZPlane.IY;
+    private static final int IDXDZ   = SurfZPlane.IDXDZ;
+    private static final int IDYDZ   = SurfZPlane.IDYDZ;
+    private static final int IQP     = SurfZPlane.IQP;
+
+
+    // Attributes   ***************************************************
+     
+    // bfield * BFAC
+    private double _bfac;
+    
+    
+    // Methods   ******************************************************
+    
+    // static methods
+    
+    /**
+     *Return a String representation of the class' type name.
+     *Included for completeness with the C++ version.
+     *
+     * @return   A String representation of the class' type name.
+     */
+    public  static String typeName()
+    { return "PropZDCA";
+    }
+    
+    /**
+     *Return a String representation of the class' type name.
+     *Included for completeness with the C++ version.
+     *
+     * @return   A String representation of the class' type name.
+     */
+    public  static String staticType()
+    { return typeName();
+    }
+    
+    
+    
+    /**
+     *Construct an instance from a constant solenoidal magnetic field in Tesla.
+     *
+     * @param   bfield The magnetic field strength in Tesla.
+     */
+    public PropZDCA(double bfield)
+    {
+        super(PropDir.FORWARD);
+        _bfac=bfield * TRFMath.BFAC;
+    }
+    
+    /**
+     *Clone an instance.
+     *
+     * @return A Clone of this instance.
+     */
+    public Propagator newPropagator()
+    {
+        return new PropZDCA( bField() );
+    }
+    
+    /**
+     *Return a String representation of the class' type name.
+     *Included for completeness with the C++ version.
+     *
+     * @return   A String representation of the class' type name.
+     */
+    public String type()
+    { return staticType();
+    }
+    
+    /**
+     *Propagate a track without error in the specified direction.
+     *and return the derivative matrix in deriv.
+     *
+     * The track parameters for a cylinder are:
+     * phi z alpha tan(lambda) curvature
+     *
+     * @param   trv The VTrack to propagate.
+     * @param   srf The Surface to which to propagate.
+     * @param   dir The direction in which to propagate.
+     * @param   deriv The track derivatives to update at the surface srf.
+     * @return The propagation status.
+     */
+    public PropStat vecDirProp( VTrack trv,  Surface srf,
+            PropDir dir, TrackDerivative deriv )
+    {
+        return zDCAPropagate( _bfac, trv, srf, dir, deriv );
+    }
+    
+    /**
+     *Propagate a track without error in the specified direction.
+     *
+     * The track parameters for a cylinder are:
+     * phi z alpha tan(lambda) curvature
+     *
+     * @param   trv The VTrack to propagate.
+     * @param   srf The Surface to which to propagate.
+     * @param   dir The direction in which to propagate.
+     * @return The propagation status.
+     */
+    public PropStat vecDirProp( VTrack trv,  Surface srf,
+            PropDir dir )
+    {
+        TrackDerivative deriv =null;
+        return vecDirProp(trv, srf, dir, deriv);
+        
+    }
+    
+    // propagate a track with error in the specified direction
+    //  PropStat err_dir_prop( ETrack& tre,  Surface& srf,
+    //                                            PropDir dir ) ;
+    
+    //
+    
+    /**
+     *Return the strength of the magnetic field in Tesla.
+     *
+     * @return The strength of the magnetic field in Tesla.
+     */
+    public  double bField()
+    {
+        return _bfac/TRFMath.BFAC;
+    }
+    
+    
+    /**
+     *output stream
+     * @return  A String representation of this instance.
+     */
+    public String toString()
+    {
+        return "ZPlane propagation to a DCA surface with constant "
+                + bField() + " Tesla field";
+    }
+    
+    
+    
+    /**
+     * Propagate from dca to cylinder.
+     * Why is this public?
+     *
+     * @param   _bfac The numerical factor (including the field)
+     * @param   trv The VTrack to propagate.
+     * @param   srf The cylindrical surface to which to propagate.
+     * @param   dir The direction in which to propagate.
+     * @param   deriv The track derivatives to update at the surface srf.
+     * @return The propagation status.
+     */
+    public PropStat zDCAPropagate( double          _bfac,
+				   VTrack          trv,
+				   Surface         srf,
+				   PropDir         dir,
+				   TrackDerivative deriv )
+    {
+
+        // Construct return status
+        PropStat pstat = new PropStat();
+        
+        // Fetch the originating Surface and check it is a Zplane.
+        Surface srf0 = trv.surface();
+        Assert.assertTrue( srf0.pureType().equals(SurfZPlane.staticType() ));
+        if ( ! srf0.pureType( ).equals(SurfZPlane.staticType()) )
+            return pstat;
+        
+        // Check that the destination surface is a DCA surface.
+        Assert.assertTrue( srf.pureType().equals(SurfDCA.staticType()) );
+        if ( !srf.pureType( ).equals(SurfDCA.staticType()) )
+            return pstat;
+        SurfDCA srf_dca = ( SurfDCA ) srf;
+
+        // Check that dca surface has zero tilt.
+        boolean tilted = srf_dca.dXdZ() != 0 || srf_dca.dYdZ() != 0;
+        Assert.assertTrue(!tilted);
+        if(tilted)    return pstat;
+
+	// Instantiate the intermediate propagators.
+	PropZCyl   prop1 = new PropZCyl( bField() );
+	PropCylDCA prop2 = new PropCylDCA( bField() );
+
+	// Radius of the track at the ZPlane
+	double r = Math.sqrt(trv.vector(IX)*trv.vector(IX) + trv.vector(IY)*trv.vector(IY));
+
+	// PropDCACyl requires that the cylinder be at a different radius than the DCA
+	// so put it 100 microns outside the dca.  This is just a guess at a safe number.
+	// Is this really true?
+	double rhack = r+0.01;
+
+	// Instantiate the surface at the intermediate step.
+	SurfCylinder srf_cyl = new SurfCylinder(rhack);
+
+	// Setup for receiving the derivatives.
+	TrackDerivative d1 = null;
+	TrackDerivative d2 = null;
+	if ( deriv != null ){
+	    d1 = new TrackDerivative();
+	    d2 = new TrackDerivative();
+	}
+
+	// Do the propagation in two steps.
+	PropStat p1 = prop1.vecDirProp(trv, srf_cyl, dir, d1);
+	if ( !p1.success() ) return p1;
+	PropStat p2 = prop2.vecDirProp(trv, srf_dca,  dir, d2);
+	if ( !p2.success() ) return p2;
+
+
+	// Set the transformation matrix to the product of the those from
+	// the two intermediate steps.
+	if ( deriv != null ){
+	    deriv.set(d2.times(d1));
+	}
+
+	// Set properties of the return value.
+	if ( p2.forward() ){
+	    pstat.setForward();
+	}else if ( p2.backward() ){
+	    pstat.setBackward();
+	} else if ( p2.same() ){
+	    pstat.setSame();
+	}
+	double s = p1.pathDistance() + p2.pathDistance();
+	pstat.setPathDistance(s);
+
+	return pstat;
+	
+    }
+    
+}
+
+

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util
RKDeDxFixed.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/RKDeDxFixed.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/RKDeDxFixed.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,103 @@
+package org.hps.recon.tracking.kalman.util;
+
+import org.lcsim.recon.tracking.trfeloss.DeDx;
+
+/**
+ *  DeDx code for testing the fitter performance:
+ *     - constant energy loss
+ *     - gaussian straggling.
+ *
+ *  The amount of energy loss and the sigma of the gaussian are
+ *  controlled c'tor arguments.  
+
+ *  For a large enough sigma, this code will allow "negative" energy 
+ *  loss in the tail of the gaussian. This is the desired behaviour to
+ *  get a zero offset in the track parameter pull distributions.
+ *
+ *@author $author$
+ *@version $Id: RKDeDxFixed.java,v 1.1 2011/07/28 18:28:19 jeremy Exp $
+ *
+ */
+public class RKDeDxFixed extends DeDx
+{
+    
+    private double _density;
+
+    // Scale the nominal energy loss by this factor.
+    private double _scale = 1.0;
+
+    // Sigma of the gaussian smearing.
+    private double _sigma   = 0.15;
+
+    /**
+     *Construct an instance given a material density.
+     *
+     * @param   density The density of the material.
+     */
+    public RKDeDxFixed(double density)
+    {
+        _density = density;
+    }
+
+    public RKDeDxFixed(double density, double scale, double sigma)
+    {
+        _density = density;
+	_scale   = scale;
+	_sigma   = sigma;
+    }
+
+    
+    /**
+     *Return energy loss (dE/dx) for a given energy.
+     *
+     * @param   energy The energy of the particle.
+     * @return The average energy lost by a particle of this energy.
+     */
+    public double dEdX(double energy)
+    {
+        double mip = 1.665; // this is an average mip
+        double de_dx = mip*_density;   // MeV/cm
+        de_dx /= 1000.; // GeV/cm
+
+	de_dx *= _scale;
+        return de_dx;
+    }
+    
+    /**
+     *Return the uncertainty in the energy lost sigma(E).
+     *
+     * @param   energy The energy of the particle.
+     * @param   x The amount of material.
+     * @return The uncertainty in the energy lost sigma(E).
+     */
+    public double sigmaEnergy(double energy, double x)
+    {
+	double sigma_e = _sigma*dEdX(energy)*x;
+        return sigma_e;
+    }
+    
+    /**
+     *Return new energy for a given path distance.
+     * Energy increases if x < 0.
+     *
+     * @param   energy The energy of the particle.
+     * @param   x The amount of material.
+     * @return New energy for a given path distance.
+     */
+    public double loseEnergy(double energy, double x)
+    {
+        double deltaE = dEdX(energy)*x;
+        return energy-deltaE;
+    }
+    
+    
+    /**
+     *output stream
+     *
+     * @return A String representation of this instance.
+     */
+    public String toString()
+    {
+        return "RKDeDxFixed with density "+_density;
+    }
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util
RKDebug.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/RKDebug.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/RKDebug.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,107 @@
+package org.hps.recon.tracking.kalman.util;
+
+import org.lcsim.recon.tracking.trfbase.PropDir;
+
+/**
+ * 
+ * A way to propagate debug info to low level routines.
+ *
+ *@author $Author: jeremy $
+ *@version $Id: RKDebug.java,v 1.1 2011/07/28 18:28:19 jeremy Exp $
+ *
+ * Date $Date: 2011/07/28 18:28:19 $
+ *
+ */
+
+public class RKDebug {
+
+    static private int track = -1;
+    static private PropDir pdir;
+    static private RKTrack rkt;
+    static private int start_type;
+
+    static private double msfac    = 1.;
+    static private boolean doms    = true;
+    static private boolean doeloss = true;
+
+    static private boolean printoutliers = false;
+
+    static private RKDebug instance = null;
+
+    // A "common block" to pass info around.
+    static private double degen     = 0.;
+
+    private RKDebug(){
+    }
+
+    static public RKDebug Instance(){
+	if ( instance == null ){
+	    instance = new RKDebug();
+	}
+	return instance;
+    }
+
+    static public int getTrack(){
+	return track;
+    }
+    static public void setTrack( int trk){
+	track = trk;
+    }
+
+    static public PropDir getPropDir(){
+	return pdir;
+    }
+    static public void setPropDir( PropDir dir){
+	pdir = dir;
+    }
+
+    static public RKTrack getRKTrack(){
+	return rkt;
+    }
+    static public void setRKTrack( RKTrack t){
+	rkt = t;
+    }
+
+    static public int getStartType(){
+	return start_type;
+    }
+    static public void setStartType( int type){
+	start_type = type;
+    }
+
+    static public double getMsFac(){
+	return msfac;
+    }
+    static public void setMsFac( double f){
+	msfac = f;
+    }
+
+    static public boolean getDoMs(){
+	return doms;
+    }
+    static public void setDoMs( boolean b){
+	doms = b;
+    }
+
+    static public boolean getDoEloss(){
+	return doeloss;
+    }
+    static public void setDoEloss( boolean b){
+	doeloss = b;
+    }
+
+    static public boolean getPrintOutliers(){
+	return printoutliers;
+    }
+    static public void setPrintOutliers( boolean b){
+	printoutliers = b;
+    }
+
+    static public double getDeGen(){
+	return degen;
+    }
+    static public void setDeGen( double b){
+	degen = b;
+    }
+
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util
RKGeom.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/RKGeom.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/RKGeom.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,403 @@
+package org.hps.recon.tracking.kalman.util;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.lcsim.detector.IDetectorElement;
+import org.lcsim.detector.IDetectorElementContainer;
+import org.lcsim.geometry.Detector;
+import org.lcsim.geometry.compact.Field;
+import org.lcsim.geometry.compact.Subdetector;
+import org.lcsim.geometry.field.Solenoid;
+import org.lcsim.recon.tracking.trfbase.PropDispatch;
+import org.lcsim.recon.tracking.trfbase.Propagator;
+import org.lcsim.recon.tracking.trfcyl.PropCyl;
+import org.lcsim.recon.tracking.trfcyl.SurfCylinder;
+import org.lcsim.recon.tracking.trfcylplane.PropCylZ;
+import org.lcsim.recon.tracking.trfcylplane.PropZCyl;
+import org.lcsim.recon.tracking.trfdca.PropCylDCA;
+import org.lcsim.recon.tracking.trfdca.PropDCACyl;
+import org.lcsim.recon.tracking.trfdca.SurfDCA;
+import org.lcsim.recon.tracking.trfzp.PropZZ;
+import org.lcsim.recon.tracking.trfzp.SurfZPlane;
+
+/**
+ * 
+ * Extract needed information from the geometry system and serve it 
+ * to the callers in a convenient form.
+ *  
+ *
+ *@author $Author: jeremy $
+ *@version $Id: RKGeom.java,v 1.1 2011/07/28 18:28:19 jeremy Exp $
+ *
+ * Date $Date: 2011/07/28 18:28:19 $
+ *
+ */
+
+
+public class RKGeom {
+
+    // TRF wants distances in cm, not mm.
+    private double mmTocm = 0.1;
+
+    //    private Array radius = null;
+    private Subdetector sd_tbar  = null;
+    private Subdetector sd_vbar  = null;
+    private Subdetector sd_tec   = null;
+    private Subdetector sd_vec   = null;
+    private Subdetector sd_tfor  = null;
+    private Subdetector sd_bpipe = null;
+
+    private IDetectorElement de_tbar  = null;
+    private IDetectorElement de_vbar  = null;
+    private IDetectorElement de_tec   = null;
+    private IDetectorElement de_vec   = null;
+    private IDetectorElement de_tfor  = null;
+
+    // Nominal magnetic field.
+    public double bz = 0.;
+
+    // Lists of interesting surfaces.
+    public List<RKSurf> Surf = new ArrayList<RKSurf>();
+    public List<RKSurf> ZSurfplus  = new ArrayList<RKSurf>();
+    public List<RKSurf> ZSurfminus = new ArrayList<RKSurf>();
+    public List<RKSurf> ZSurfAll   = new ArrayList<RKSurf>();
+
+    // Specific surface type A to surface type B propagators.
+    private PropCyl propcyl       = null;
+    private PropZZ  propzz        = null;
+    private PropDCACyl propdcacyl = null;
+    private PropCylDCA propcyldca = null;
+    private PropZCyl propzcyl     = null;
+    private PropCylZ propcylz     = null;
+    private PropDCAZ propdcaz     = null;
+    private PropZDCA propzdca     = null;
+
+    // The master propagator that can go between any pair of surfaces.
+    private PropDispatch pDispatch = null;
+
+    // The run time configuration system.
+    //ToyConfig config;
+
+    // Information from the run time configuration system.
+    double  respixel;
+    double  resstrip;
+    boolean trackerbarrel2d;
+    double  zres2dTrackerBarrel;
+    boolean vtxFwdEquivStrips;
+
+    // Does this detector have forward tracking.
+    boolean hasforward = false;
+
+    public RKGeom ( Detector detector ){
+	
+	System.out.println("New detector: " + detector.getName() );
+	if ( detector.getName().compareTo("sid00") != 0 &&
+	     detector.getName().compareTo("sid02") != 0    ){
+	    System.out.println("This driver works only with sid00 or sid02." );
+	    System.exit(-1);
+	}
+
+	// Extract information from the run time configuration system.
+	try{
+	    ToyConfig config = ToyConfig.getInstance();
+	    respixel            = config.getDouble("respixel");
+	    resstrip            = config.getDouble("resstrip");
+	    trackerbarrel2d     = config.getBoolean("trackerbarrel2d");
+	    zres2dTrackerBarrel = config.getDouble("zres2dTrackerBarrel");
+	    vtxFwdEquivStrips   = config.getBoolean("vtxFwdEquivStrips");
+
+	} catch (ToyConfigException e){
+            System.out.println (e.getMessage() );
+            System.out.println ("Stopping now." );
+            System.exit(-1);
+        }
+
+
+
+	Map<String, Subdetector> subDetMap = detector.getSubdetectors();
+	
+	Subdetector sd_tbar = subDetMap.get("TrackerBarrel");
+	Subdetector sd_vbar = subDetMap.get("VertexBarrel");
+	Subdetector sd_tec  = subDetMap.get("TrackerEndcap");
+	Subdetector sd_vec  = subDetMap.get("VertexEndcap");
+	Subdetector sd_tfor = subDetMap.get("TrackerForward");
+	Subdetector sd_bpipe  = subDetMap.get("BeamPipe");
+	System.out.println ("Checking .... " + sd_tbar + " | " + sd_tfor);
+
+	// Check for forward tracking system.
+	if ( sd_tfor == null ) {
+	    System.out.println ("Checking 1 .... " );
+	    if ( detector.getName().compareTo("sid00") != 0 ){
+		System.out.println("Expected to find a TrackerForward Subdetector but did not!");
+		System.exit(-1);
+	    }
+	}else{
+	    System.out.println ("Checking 2  .... " );
+
+	    hasforward = true;
+	}
+
+	// Other parts must be present.
+	if ( sd_tbar == null ){
+	    System.out.println("Could not find TrackerBarrel Subdetector.");
+	    System.exit(-1);
+	}
+	if (sd_vbar == null ){
+	    System.out.println("Could not find VertexBarrel Subdetector.");
+	    System.exit(-1);
+	}
+	if ( sd_tec == null ){
+	    System.out.println("Could not find TrackerEndcap Subdetector.");
+	    System.exit(-1);
+	}
+	if ( sd_vec == null ){
+	    System.out.println("Could not find VertexEndcap Subdetector.");
+	    System.exit(-1);
+	}
+	if ( sd_bpipe == null ){
+	    System.out.println("Could not find BeamPipe Subdetector.");
+	    System.exit(-1);
+	}
+
+	de_tbar  = sd_tbar.getDetectorElement();
+	de_vbar  = sd_vbar.getDetectorElement();
+	de_tec   = sd_tec.getDetectorElement();
+	de_vec   = sd_vec.getDetectorElement();
+
+	if ( hasforward ){
+	    de_tfor = sd_tfor.getDetectorElement();
+	}
+
+	if ( de_tbar == null ){
+	    System.out.println("Could not find TrackerBarrel Detector Element.");
+	    System.exit(-1);
+	}
+	if (de_vbar == null ){
+	    System.out.println("Could not find VertexBarrel Detector Element.");
+	    System.exit(-1);
+	}
+	if ( de_tec == null ){
+	    System.out.println("Could not find TrackerEndcap Detector Element.");
+	    System.exit(-1);
+	}
+	if ( de_vec == null ){
+	    System.out.println("Could not find VertexEndcap Detector Element.");
+	    System.exit(-1);
+	}
+	if ( de_tfor == null && hasforward ){
+	    System.out.println("Could not find TrackerForward Detector Element.");
+	    System.exit(-1);
+	}
+
+
+	IDetectorElementContainer tbar_layers = de_tbar.getChildren();
+	IDetectorElementContainer vbar_layers = de_vbar.getChildren();
+	IDetectorElementContainer tec_layers  = de_tec.getChildren();
+	IDetectorElementContainer vec_layers  = de_vec.getChildren();
+	IDetectorElementContainer tfor_layers = de_tfor.getChildren();
+
+	// Add the beampipe to the list.
+	Surf.add( new RKSurf ( sd_bpipe ) );
+
+	// Add the vertex and tracker barrels to the list.
+	for ( IDetectorElement de: vbar_layers ){
+	    Surf.add( new RKSurf ( de, 2, RKSurf.ixy_Undef, respixel, respixel ) );
+	}
+	for ( IDetectorElement de: tbar_layers ){
+	    if ( trackerbarrel2d ) {
+		Surf.add( new RKSurf ( de, 2, RKSurf.ixy_phi, resstrip, zres2dTrackerBarrel ) );
+	    }else{
+		Surf.add( new RKSurf ( de, 1, RKSurf.ixy_phi, resstrip ) );
+	    }
+	}
+
+	System.out.println( "Number of surfaces: " + Surf.size() );
+	for ( RKSurf surf : Surf ){
+	    surf.Print();
+	}
+
+	if ( vec_layers.size() != 2 ){
+	    System.out.println ("Expected two z hemispheres for: " + de_vec.getName () );
+	    System.exit(-1);
+	}
+
+	if ( tec_layers.size() != 2 ){
+	    System.out.println ("Expected two z hemispheres for: " + de_vec.getName () );
+	    System.exit(-1);
+	}
+
+	if ( tfor_layers.size() != 2 ){
+	    System.out.println ("Expected two z hemispheres for: " + de_tfor.getName () );
+	    System.exit(-1);
+	}
+
+	for ( IDetectorElement de: vec_layers.get(0).getChildren() ){
+	    if ( vtxFwdEquivStrips ){
+		ZSurfplus.add( new RKSurf( de, 1, RKSurf.ixy_x, resstrip) );
+
+		//ZSurfplus.add( new RKSurf( de, 1, RKSurf.ixy_y, resstrip) );
+		RKSurf tmp = new RKSurf( de, 1, RKSurf.ixy_y, resstrip);
+		tmp.hackZc(-0.1);
+		ZSurfplus.add(tmp);
+
+	    }
+	    else{
+		ZSurfplus.add( new RKSurf( de, 2, RKSurf.ixy_Undef, respixel, respixel) );
+	    }
+
+	}
+
+	for ( IDetectorElement de: tfor_layers.get(0).getChildren() ){
+	    ZSurfplus.add( new RKSurf( de, 2, RKSurf.ixy_Undef, respixel, respixel) );
+	}
+
+	int xy = -1;
+	for ( IDetectorElement de: tec_layers.get(0).getChildren() ){
+	    if ( (++xy)%2 == 0 ){
+		ZSurfplus.add( new RKSurf( de, 1, RKSurf.ixy_x, resstrip) );
+	    }else{
+		ZSurfplus.add( new RKSurf( de, 1, RKSurf.ixy_y, resstrip) );
+	    }
+	}
+
+	for ( IDetectorElement de: vec_layers.get(1).getChildren() ){
+	    if ( vtxFwdEquivStrips ){
+		ZSurfminus.add( new RKSurf( de, 1, RKSurf.ixy_x, resstrip) );
+		//ZSurfminus.add( new RKSurf( de, 1, RKSurf.ixy_y, resstrip) );
+		RKSurf tmp = new RKSurf( de, 1, RKSurf.ixy_y, resstrip);
+		tmp.hackZc(+0.1);
+		ZSurfminus.add(tmp);
+	    }
+	    else{
+		ZSurfminus.add( new RKSurf( de, 2, RKSurf.ixy_Undef, respixel, respixel) );
+	    }
+	}
+
+	for ( IDetectorElement de: tfor_layers.get(1).getChildren() ){
+	    ZSurfminus.add( new RKSurf( de, 2, RKSurf.ixy_Undef, respixel, respixel) );
+	}
+
+
+	xy = -1;
+	for ( IDetectorElement de: tec_layers.get(1).getChildren() ){
+	    if ( (++xy)%2 == 0 ){
+		ZSurfminus.add( new RKSurf( de, 1, RKSurf.ixy_x, resstrip) );
+	    } else {
+		ZSurfminus.add( new RKSurf( de, 1, RKSurf.ixy_y, resstrip) );
+	    }
+	}
+
+	System.out.println( "Number of +Zsurfaces: " + ZSurfplus.size() );
+	for ( RKSurf surf : ZSurfplus ){
+	    surf.Print();
+	}
+
+	System.out.println( "Number of -Zsurfaces: " + ZSurfminus.size() );
+	for ( RKSurf surf : ZSurfminus ){
+	    surf.Print();
+	}
+
+	// List of all Z Surfaces.
+	for ( ListIterator ihit=ZSurfminus.listIterator(ZSurfminus.size());
+	      ihit.hasPrevious(); ){
+	    ZSurfAll.add((RKSurf)ihit.previous());
+	}
+	for ( Iterator ihit=ZSurfplus.iterator(); ihit.hasNext(); ){
+	    ZSurfAll.add((RKSurf)ihit.next());
+	}
+
+
+	double[] origin = {0.,0.,0.};
+
+	Map<String,Field> fields = detector.getFields();
+	Set<String> keys = fields.keySet();
+	for ( String key : keys ){
+	    Field field = fields.get(key);
+	    String classname = field.getClass().getName();
+	    String shortname = classname.replaceAll( "org.lcsim.geometry.field.", "");
+	    if ( shortname.compareTo("Solenoid") != 0 ){
+		System.out.println("Expected, but did not find, a solenoid: " + shortname );
+		System.exit(-1);
+	    }
+	    Solenoid s = (Solenoid)field;
+	    bz = s.getInnerField()[2];
+	    if ( bz == 0. ){
+		System.out.println("This code will not work with a magnetic field of 0: " + shortname );
+		System.exit(-1);
+	    }
+	    break;
+	}
+
+	// Instantiate surface-pair specific propagators.
+	propcyl    = new PropCyl(bz);
+	propzz     = new PropZZ(bz);
+	propdcacyl = new PropDCACyl(bz);
+	propcyldca = new PropCylDCA(bz);
+	propzcyl   = new PropZCyl(bz);
+	propcylz   = new PropCylZ(bz);
+	propdcaz   = new PropDCAZ(bz);
+	propzdca   = new PropZDCA(bz);
+
+	// Instantiate and configure the general purpose propagator.
+	pDispatch = new PropDispatch();
+	pDispatch.addPropagator( SurfZPlane.staticType(),   SurfZPlane.staticType(),   propzz);
+	pDispatch.addPropagator( SurfCylinder.staticType(), SurfCylinder.staticType(), propcyl);
+	pDispatch.addPropagator( SurfDCA.staticType(),      SurfCylinder.staticType(), propdcacyl);
+	pDispatch.addPropagator( SurfCylinder.staticType(), SurfDCA.staticType(),      propcyldca);
+	pDispatch.addPropagator( SurfZPlane.staticType(),   SurfCylinder.staticType(), propzcyl);
+	pDispatch.addPropagator( SurfCylinder.staticType(), SurfZPlane.staticType(),   propcylz);
+	pDispatch.addPropagator( SurfDCA.staticType(),      SurfZPlane.staticType(),   propdcaz);
+	pDispatch.addPropagator( SurfZPlane.staticType(),   SurfDCA.staticType(),      propzdca);
+
+    }
+
+    public Propagator newPropagator(){
+	// Clone not supported for pDispatch.
+	//return pDispatch.newPropagator();
+	return (Propagator)pDispatch;
+    }
+
+    public List<RKSurf> getCylinders(){
+	return Surf;
+    }
+    public List<RKSurf> getZplus(){
+	return ZSurfplus;
+    }
+    
+    public List<RKSurf> getZMinus(){
+	return ZSurfminus;
+    }
+
+    public double getBz(){
+	return bz;
+    }
+    
+
+    // Return a list of z surfaces, going foward along the track.
+    public List<RKSurf> getZ( double z0, double cz ){
+	List<RKSurf> zlist = new ArrayList<RKSurf>();
+	if ( cz > 0 ){
+	    for ( Iterator ihit=ZSurfAll.iterator(); ihit.hasNext(); ){
+		RKSurf s = (RKSurf) ihit.next();
+		if ( s.zc >= z0 ){
+		    zlist.add(s);
+		}
+	    }
+	} else if ( cz < 0 ){
+	    for ( ListIterator ihit=ZSurfAll.listIterator(ZSurfAll.size());
+		  ihit.hasPrevious(); ){
+		RKSurf s = (RKSurf) ihit.previous();
+		if ( s.zc <= z0 ){
+		    zlist.add(s);
+		}
+	    }
+	}
+
+	return zlist;
+    }
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util
RKHit.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/RKHit.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/RKHit.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,257 @@
+package org.hps.recon.tracking.kalman.util;
+
+import java.util.List;
+import java.util.Random;
+
+import org.lcsim.recon.tracking.trfbase.ETrack;
+import org.lcsim.recon.tracking.trfbase.Hit;
+import org.lcsim.recon.tracking.trfbase.PropStat;
+import org.lcsim.recon.tracking.trfbase.TrackError;
+import org.lcsim.recon.tracking.trfbase.VTrack;
+import org.lcsim.recon.tracking.trfcyl.ClusCylPhi;
+import org.lcsim.recon.tracking.trfcyl.ClusCylPhiZ2D;
+import org.lcsim.recon.tracking.trfcyl.HitCylPhi;
+import org.lcsim.recon.tracking.trfcyl.HitCylPhiZ2D;
+import org.lcsim.recon.tracking.trfcyl.SurfCylinder;
+import org.lcsim.recon.tracking.trfzp.ClusZPlane1;
+import org.lcsim.recon.tracking.trfzp.ClusZPlane2;
+import org.lcsim.recon.tracking.trfzp.HitZPlane1;
+import org.lcsim.recon.tracking.trfzp.HitZPlane2;
+import org.lcsim.recon.tracking.trfzp.SurfZPlane;
+import org.lcsim.util.aida.AIDA;
+/**
+ * 
+ * Interface between RKGeom and the TRF hit classes.
+ * The main purpose of this class is to produce the 
+ * various sorts of TRF hits.
+ *
+ *@author $Author: jeremy $
+ *@version $Id: RKHit.java,v 1.1 2011/07/28 18:28:19 jeremy Exp $
+ *
+ * Date $Date: 2011/07/28 18:28:19 $
+ *
+ */
+
+public class RKHit{
+
+    static private Random ran  = new Random();
+    static private Random ranz = new Random();
+
+    private AIDA aida = AIDA.defaultInstance();
+
+
+    // Resolutions in cm ( ie TRF units ).
+    //static private double respixel   =  0.0025;
+    //static private double resstrip   =  0.0050;
+    //static private double zres_strip =  2.89;    // 10 cm /sqrt(12).
+    //static private double zres_strip =  1.00;    // see if a smaller number helps.
+
+    private RKTrack  track;
+    private RKSurf   surf;
+    private VTrack   vt;
+    private PropStat ps;
+    private double   path;
+    private double   psi;
+    private Hit ghit = null;
+
+    // Dimension of the readout 
+    private int rodim = 0;
+
+    // Number of stereo measurements in this device.
+    private int zdim  = 0;
+
+    public RKHit( RKTrack track, RKSurf surf, VTrack vt, PropStat ps, double path){
+	this.track = track;
+	this.surf  = surf;
+	this.vt    = new VTrack(vt);
+	this.ps    = new PropStat(ps);
+	this.path  = path;
+	psi = path*track.sz()/track.rho();
+
+	rodim = surf.rodim;
+	if ( surf.getType() ==  RKSurf.type_zdisc ){
+	    zdim = 1;
+	} else if (  surf.getType() ==  RKSurf.type_tube ){
+	    if ( rodim == 2 ) {
+		zdim=1;
+	    }
+	}
+
+    }
+
+
+    public RKTrack  getRKTrack() { return track; }
+    public RKSurf   getSurface() { return surf;  }
+    public VTrack   getVTrack()  { return vt;    }
+    public PropStat getPropStat(){ return ps;    }
+    public double   getPath()    { return path;  }
+    public double   getPsi()     { return psi;   }
+    public int      getRodim()   { return rodim; }
+    public int      getZdim()    { return zdim;  }
+
+    static public void setSeed( long seed ){
+	ran.setSeed(seed);
+	ranz.setSeed(seed+1234578);
+    }
+
+    public Hit MakeHit(){
+	if ( ghit != null ) return ghit;
+
+	if ( surf.getType() == RKSurf.type_tube ){
+	    if ( surf.rodim == 0 ){
+		return null;
+	    } else if ( surf.rodim == 1 ){
+		return MakeCylPhi( surf.getResolution0() );
+	    } else if ( surf.rodim == 2 ){
+		return MakeCylPhiZ2D( surf.getResolution0(), surf.getResolution1() );
+	    }
+	} else if ( surf.getType() == RKSurf.type_zdisc ){
+	    if ( surf.rodim == 0 ){
+		return null;
+	    } else if ( surf.rodim == 1 ){
+		return MakeZPlane1D( surf.getResolution0() );
+	    } else if ( surf.rodim == 2 ){
+		return MakeZPlane2D( surf.getResolution0(), surf.getResolution1() );
+	    }
+	}
+	return null;
+    }
+    
+    private Hit MakeCylPhi( double res){
+	SurfCylinder s = (SurfCylinder)vt.surface();
+	double r = s.radius();
+
+	double sig0 = res/r;
+
+	double m0 = vt.vector(0) + sig0*ran.nextGaussian();
+	//double m0 = vt.vector(0);
+
+	double stereo = 0.;
+	int mcid = 0;
+	ClusCylPhi cluster = new ClusCylPhi( r, m0, sig0, mcid );
+	TrackError  verr = new TrackError();
+	verr.set(0,0,10.);
+	verr.set(1,1,100.);
+	verr.set(2,2,2.);
+	verr.set(3,3,10.);
+	verr.set(4,4,10.);
+
+	ETrack et =  new ETrack(s.newPureSurface(), vt.vector(), verr );
+	List ghits = cluster.predict(et,cluster);
+	ghit = (HitCylPhi)ghits.get(0);
+	return ghit;
+    }
+
+    private Hit MakeCylPhiZ2D( double sigpixel, double sigz ){
+
+	SurfCylinder s = (SurfCylinder)vt.surface();
+	double r = s.radius();
+
+	double sig0 = sigpixel/r;
+	double sig1 = sigz;
+
+	double m0 = vt.vector(0) + sig0*ran.nextGaussian();
+
+	//double m1 = vt.vector(1) + sig1*ran.nextGaussian();
+
+	// Hack to decouple r-phi and z fits.
+	double m1;
+	if ( r > 100 ){
+	    m1 = vt.vector(1) + sig1*ranz.nextGaussian();
+	}else{
+	    m1 = vt.vector(1) + sig1*ran.nextGaussian();
+	}
+
+	//double m0 = vt.vector(0);
+	//double m1 = vt.vector(1);
+
+	double stereo = 0.;
+	int mcid = 0;
+	ClusCylPhiZ2D cluster = new ClusCylPhiZ2D( r, m0, sig0, m1, sig1, stereo, mcid );
+	TrackError  verr = new TrackError();
+	verr.set(0,0,10.);
+	verr.set(1,1,100.);
+	verr.set(2,2,2.);
+	verr.set(3,3,10.);
+	verr.set(4,4,10.);
+
+	ETrack et =  new ETrack(s.newPureSurface(), vt.vector(), verr );
+	List ghits = cluster.predict(et,cluster);
+	ghit = (HitCylPhiZ2D)ghits.get(0);
+	return ghit;
+    }
+
+    private Hit MakeZPlane1D( double res){
+	SurfZPlane s = (SurfZPlane)vt.surface();
+	double z     =  s.z();
+
+	// Measurement error.
+	double sig0 = res;
+
+	// Measurement direction.
+	double wx  = 1.;
+	double wy  = 0.;
+	if ( surf.ixy == RKSurf.ixy_y ){
+	    wx = 0.;
+	    wy = 1.;
+	}
+	double m0  = vt.vector(0)*wx + vt.vector(1)*wy;
+	m0 += sig0*ran.nextGaussian();
+ 
+	int mcid = 0;
+	ClusZPlane1 cluster = new ClusZPlane1( z, wx, wy, m0, sig0, mcid );
+	TrackError  verr = new TrackError();
+	verr.set(0,0,10.);
+	verr.set(1,1,10.);
+	verr.set(2,2,10.);
+	verr.set(3,3,10.);
+	verr.set(4,4,10.);
+
+	ETrack et =  new ETrack(s.newPureSurface(), vt.vector(), verr );
+	List ghits = cluster.predict(et,cluster);
+	ghit = (HitZPlane1)ghits.get(0);
+	return ghit;
+
+    }
+
+    private Hit MakeZPlane2D( double res0, double res1){
+	SurfZPlane s = (SurfZPlane)vt.surface();
+	double z     =  s.z();
+
+	double sig0 = res0;
+	double sig1 = res1;
+
+	double m0 = vt.vector(0) + sig0*ran.nextGaussian();
+	double m1 = vt.vector(1) + sig1*ran.nextGaussian();
+	//double m0 = vt.vector(0);
+	//double m1 = vt.vector(1);
+
+	double dxdy = 0.;
+	int mcid = 0;
+	ClusZPlane2 cluster = new ClusZPlane2( z, m0, m1, sig0*sig0, sig1*sig1, dxdy, mcid );
+	TrackError  verr = new TrackError();
+	verr.set(0,0,10.);
+	verr.set(1,1,10.);
+	verr.set(2,2,10.);
+	verr.set(3,3,10.);
+	verr.set(4,4,10.);
+
+	ETrack et =  new ETrack(s.newPureSurface(), vt.vector(), verr );
+	List ghits = cluster.predict(et,cluster);
+	ghit = (HitZPlane2)ghits.get(0);
+	return ghit;
+
+    }
+
+    private Hit MakeNullCyl( ){
+	SurfCylinder s = (SurfCylinder)vt.surface();
+	double r = s.radius();
+
+	ghit = new HitNull();
+
+	return ghit;
+    }
+
+
+
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util
RKHitList.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/RKHitList.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/RKHitList.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,286 @@
+package org.hps.recon.tracking.kalman.util;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ *  
+ * Holds a list of RKHits.  Can return the hits sorted in different
+ * orders.  Can return properties of the ensemble of hits.
+ *
+ *@author $Author: jeremy $
+ *@version $Id: RKHitList.java,v 1.1 2011/07/28 18:28:19 jeremy Exp $
+ *
+ * Date $Date: 2011/07/28 18:28:19 $
+ *
+ */
+
+public class RKHitList {
+
+    // Original list.
+    private List<RKHit> list = new ArrayList<RKHit>();
+
+    // Sorted copies of the lists.
+    private List<RKHit> forward  = null;
+    private List<RKHit> backward = null;
+
+    private int nmeas  = 0;
+    private int nzmeas = 0;
+
+    private int ncyl = 0;
+    private int nzp  = 0;
+
+    RKHitList (){
+    }
+    
+    public void addHit( RKHit h ){
+	list.add(h);
+	nmeas  += h.getRodim();
+	nzmeas += h.getZdim();
+
+	int type = h.getSurface().getType();
+	if ( type == RKSurf.type_tube ){
+	    ncyl += 1;
+	} else if ( type == RKSurf.type_zdisc ){
+	    nzp += 1;
+	}
+
+	// Any existing sorts are no longer valid.
+	forward  = null;
+	backward = null;
+    }
+
+    public RKHit get( int i){
+	return list.get(i);
+    }
+
+    public List<RKHit> getForward(){
+	if( forward !=  null ) return forward;
+	forward = new ArrayList<RKHit>(list);
+	Collections.sort( forward, new CompareRKHit<RKHit>(+1) );	
+	return forward;
+    }
+
+    public List<RKHit> getBackward(){
+	if ( backward != null ) return backward;
+	backward = new ArrayList<RKHit>(list);
+	Collections.sort( backward, new CompareRKHit<RKHit>(-1) );	
+	return backward;
+    }
+
+    public int nHits(){ return list.size(); }
+    public int nDof(){ return nDof(5); }
+    public int nDof( int n){ return nmeas-n; }
+
+    public int nZ(){ return nzmeas;}
+
+    public int nCyl(){ return ncyl;}
+    public int nZp() { return nzp;}
+
+    // Does the track have enough measurements to be fittable.
+    // This is an arbitrary definition.  
+    public boolean fitable(){
+	if ( nDof() < 1 ) return false;
+	if ( nzmeas < 3 ) return false;
+	return true;
+    }
+
+
+    public RKHit outerMostHit(){
+	for ( RKHit h : getBackward() ){
+	    if ( h.getRodim() > 0 ) return h;
+	}
+	return null;
+    }
+
+    public RKHit innerMostHit(){
+	for ( RKHit h : getForward() ){
+	    if ( h.getRodim() > 0 ) return h;
+	}
+	return null;
+    }
+
+    public int nLeadingStrips(){
+	int n = 0;
+	int nLeadingStrips = 0;
+	int firstZType = 0;
+	boolean firstZ = false;
+	for ( RKHit h: getBackward() ){
+	    RKSurf s  = h.getSurface();
+	    int rodim = h.getRodim();
+	    int zdim  = h.getZdim();
+	    if ( zdim > 0 ){
+		firstZ = true;
+		if ( s.getType() == RKSurf.type_tube ){
+		    firstZType = 1;
+		} else{
+		    firstZType = 2;
+		}
+		break;
+	    }
+	    if ( rodim == 1 & 
+		 s.getType() == RKSurf.type_tube ){
+		++nLeadingStrips;
+	    }
+	    
+	}
+	return nLeadingStrips;
+    }
+
+
+    public int firstZType(){
+	int type = 0;
+	for ( RKHit h: getBackward() ){
+	    RKSurf s  = h.getSurface();
+	    int zdim  = h.getZdim();
+	    if ( zdim > 0 ){
+		if ( s.getType() == RKSurf.type_tube ){
+		    type = 1;
+		} else{
+		    type = 2;
+		}
+		break;
+	    }
+	}
+	return type;
+    }
+
+    public void PrintBackward(){
+	for ( RKHit h: getBackward() ){
+	    RKSurf s  = h.getSurface();
+	    s.Print();
+	    /*
+	    int zdim  = h.getZdim();
+	    int rodim = h.getRodim();
+	    String ctype = "";
+	    double zc = 0.;
+	    if ( rodim > 0 ){
+		if ( s.getType() == RKSurf.type_tube ){
+		    ctype = "Barrel";
+		} else{
+		    ctype = "Endcap";
+		    zc = s.zc;
+		}
+		System.out.printf ( "Hit: %6s %4d %4d %9.2f %9.2f\n", 
+				    ctype,
+				    rodim,
+				    s.ixy,
+                                    h.getPath(),
+				    zc
+				    );
+		
+	    } else{
+		s.Print();
+	    }
+	    */
+	}
+    }
+
+    public double deltaZ(){
+	RKHit  h0  = getBackward().get(0); 
+	RKSurf s0  = h0.getSurface();
+	int    ro0 = h0.getRodim();
+
+	// Only consider tracks that start with zdisc strips.
+	if ( s0.getType() != RKSurf.type_zdisc ) return 0.;
+	if ( ro0 != 1 ) return 0.;
+
+	// z of first z measuring surface.
+	double z0  = s0.zc;
+
+	// z of first z measuring surface with enough lever arm to be useful.
+	double z1  = z0;
+
+	int n = 0;
+	for ( RKHit h: getBackward() ){
+	    
+	    // Start looking at the third measurement.
+            // ie skip second plane if it is part of a doublet.
+	    if ( ++n < 3 ) continue;
+
+	    RKSurf s  = h.getSurface();
+	    if ( s.getType() == RKSurf.type_zdisc  ){
+		// Accept any z disc.
+		z1 = s.zc;
+		break;
+	    } else if ( h.getRodim() > 1 ) {
+		// Accept barrel pixels.
+		z1 = h.getVTrack().vector(1);
+		break;
+	    }
+
+	}
+
+	return Math.abs(z0-z1);
+    }
+
+    // Look for patterns of z hits that can cause problems.
+    public int Pattern(){
+
+	// Number of endcap hits before the first barrel hit.
+	int nec = 0;
+	for ( RKHit h: getBackward() ){
+	    RKSurf s  = h.getSurface();
+	    if ( s.getType() == RKSurf.type_zdisc  ){
+		++nec;
+	    }else{
+		break;
+	    }
+	}
+
+	// The first hit is a barrel hit.
+	if ( nec == 0 ) return 0;
+
+	// There is are hits from at least 2 z stations so at least
+	// one slope will be well defined.
+	if ( nec > 2  ) return 0;
+
+	int nbar  = 0;
+	int nskip = 0;
+	for ( RKHit h: getBackward() ){
+	    if ( ++nskip <= nec ) continue;
+
+	    RKSurf s  = h.getSurface();
+	    if ( s.getType() == RKSurf.type_tube  ){
+		++nbar;
+	    }else{
+		break;
+	    }
+	}
+
+	// Number of barrel hits between the first z hit and 
+	return nbar;
+
+    }
+
+    // ??? This should be in the RKHits definition, not in this file????
+    //
+    // Class to compare two RKHits, sorted by path length.
+    // If the argument is positive, then the sort is done in increasing order.
+    // If the argument is negative, then the sort is done in decreasing order.
+    private class CompareRKHit<T> implements Comparator<T>{
+	private int sign = 1;
+	public CompareRKHit(){
+	}
+	public CompareRKHit(int sign){
+	    this.sign = sign;
+	}
+	public int compare ( Object o1, Object o2 ){
+	    RKHit h1 = (RKHit)o1;
+	    RKHit h2 = (RKHit)o2;
+	    double l1 = h1.getPath();
+	    double l2 = h2.getPath();
+	    if ( l1 == l2 ) {
+		return 0;
+	    } else if ( l1 > l2 ) {
+		return +1*sign;
+	    } else{
+		return -1*sign;
+	    }
+	}
+    }
+    
+
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util
RKMakeHits.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/RKMakeHits.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/RKMakeHits.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,614 @@
+package org.hps.recon.tracking.kalman.util;
+
+import java.util.List;
+import java.util.Random;
+import org.lcsim.recon.tracking.trfbase.ETrack;
+import org.lcsim.recon.tracking.trfbase.PropDir;
+import org.lcsim.recon.tracking.trfbase.PropStat;
+import org.lcsim.recon.tracking.trfbase.Propagator;
+import org.lcsim.recon.tracking.trfbase.TrackError;
+import org.lcsim.recon.tracking.trfbase.VTrack;
+import org.lcsim.recon.tracking.trfcyl.ThinCylMs;
+import org.lcsim.recon.tracking.trfcyl.ThinCylMsSim;
+import org.lcsim.util.aida.AIDA;
+
+/**
+ * Propagate a track through a detector and generate hits.
+ * Include multiple scattering and eloss, or not, as controlled by
+ * the configuration file.
+ *
+ *@author $Author: jeremy $
+ *@version $Id: RKMakeHits.java,v 1.1 2011/07/28 18:28:19 jeremy Exp $
+ *
+ * Date $Date: 2011/07/28 18:28:19 $
+ *
+ */
+
+
+public class RKMakeHits {
+    
+    // Copies of arguments to c'tor.
+    // The geometry summary extracted from the GeomConverter classes.
+    RKGeom rkgeom = null;
+
+    // A random number generator to use.
+    Random random;
+
+    private AIDA aida = AIDA.defaultInstance();
+
+    // TRF wants distances in cm, not mm.
+    private double mmTocm = 0.1;
+
+    // Thicknesses in radiation lengths of the 3 classes of cylindrical surfaces.
+    private double scatThick0 = 0.006136;
+    private double scatThick1 = 0.000916;
+    private double scatThick2 = 0.013747;
+
+    // Simulators for scattering at the 3 classes of cylindrical surfaces
+    // and 2 classes of z surfaces.
+    private ThinCylMsSim scatSim0     = null;
+    private ThinCylMsSim scatSim1     = null;
+    private ThinCylMsSim scatSim2     = null;
+    private ThinZPlaneMsSim zscatSim1 = null;
+    private ThinZPlaneMsSim zscatSim2 = null;
+
+    // Simulators for energy loss at the 3 classes of cylindrical surfaces
+    // and 2 classes of z surfaces.
+    private CylElossSim celoss0 = null;
+    private CylElossSim celoss1 = null;
+    private CylElossSim celoss2 = null;
+    private CylElossSim zeloss1 = null;
+    private CylElossSim zeloss2 = null;
+
+    // The run time configuration system.
+    ToyConfig config;
+
+    // Quantities taken from the run time configuration system.
+    private boolean doms       = false;
+    private boolean doeloss    = false;
+    private double  msfac      = 1.0;
+    private double  dedxscale  = 7.5;
+    private double  dedxsigma  = 0.00;
+    private boolean doHitCheck = false;
+
+    public RKMakeHits( RKGeom rkgeom, Random random ){
+	this.rkgeom = rkgeom;
+	this.random = random;
+
+	// Copy information from the run time configuration system.
+	try{
+	    ToyConfig config = ToyConfig.getInstance();
+	    doms                 = config.getBoolean("DoMS");
+	    doeloss              = config.getBoolean("DoELoss");
+	    msfac                = config.getDouble("MsFac");
+	    dedxscale            = config.getDouble("dEdXScale");
+	    dedxsigma            = config.getDouble("dEdXSigma");
+	    doHitCheck           = config.getBoolean("doHitCheck");
+
+	} catch (ToyConfigException e){
+            System.out.println (e.getMessage() );
+            System.out.println ("Stopping now." );
+            System.exit(-1);
+        }
+	System.out.println ("RKMakeHits dedxscale: " + dedxscale );
+
+	// Seed for track random number generator.
+	long seed          = -398783512;
+
+	// An increment used to generate independent streams of random
+	// numbers - I have no proof that this really works.
+	long seedIncrement = 876633217;
+
+	CylEloss.SetNewModel(true);
+
+	scatSim0 = new ThinCylMsSim(scatThick0*msfac);
+	scatSim1 = new ThinCylMsSim(scatThick1*msfac);
+	scatSim2 = new ThinCylMsSim(scatThick2*msfac);
+
+	zscatSim1 = new ThinZPlaneMsSim(scatThick1*msfac);
+	zscatSim2 = new ThinZPlaneMsSim(scatThick2*msfac);
+	
+	// Seed the random number generators in the Siminteractors.
+	seed += seedIncrement;
+	scatSim0.setSeed(seed);
+	seed += seedIncrement;
+	scatSim1.setSeed(seed);
+	seed += seedIncrement;
+	scatSim2.setSeed(seed);
+	seed += seedIncrement;
+	zscatSim1.setSeed(seed);
+	seed += seedIncrement;
+	zscatSim2.setSeed(seed);
+
+	double densityBe = rkgeom.getCylinders().get(0).density;
+	double densitySi = rkgeom.getCylinders().get(1).density;
+	RKDeDxFixed dedxBe = new RKDeDxFixed(densityBe,dedxscale, dedxsigma);
+	RKDeDxFixed dedxSi = new RKDeDxFixed(densitySi,dedxscale, dedxsigma);
+
+	double thickbeampipe = rkgeom.getCylinders().get(0).thick;
+	double thickpixel    = rkgeom.getCylinders().get(1).thick;
+	double thickstrip    = rkgeom.getCylinders().get(6).thick;
+
+	celoss0 = new CylElossSim( thickbeampipe, dedxBe, random );
+	celoss1 = new CylElossSim( thickpixel, dedxSi, random  );
+	celoss2 = new CylElossSim( thickstrip, dedxSi, random );
+
+	zeloss1 = new CylElossSim( thickpixel, dedxSi, random );
+	zeloss2 = new CylElossSim( thickstrip, dedxSi, random );
+	System.out.println( "ELoss thicknesses: " + thickbeampipe + " " + thickpixel + " " + thickstrip );
+	System.out.println( "Densities: " + densityBe + " " + densitySi );
+
+
+	// This is probably not necessary - check later.
+	seed += seedIncrement;
+	celoss0.setSeed(seed);
+	seed += seedIncrement;
+	celoss1.setSeed(seed);
+	seed += seedIncrement;
+	celoss2.setSeed(seed);
+	seed += seedIncrement;
+	zeloss1.setSeed(seed);
+	seed += seedIncrement;
+	zeloss2.setSeed(seed);
+
+    }
+
+    // Generate perfect hits on the outward going arc only.
+    // Do not apply energy loss or multiple scattering.
+    public RKHitList GenerateOneArcHits( RKTrack rktrk ){
+
+	// Convert to TRF style track.
+	toTRF trftrk = new toTRF(rktrk);
+	VTrack vtdca = trftrk.atDcaZaxis();
+	VTrack vtz   = trftrk.atZPlane(rktrk.z0());
+
+	// This code only looks at the first arc of a track.
+	double pathlimit = trftrk.halfarc();
+	int nmeas  = 0;
+	int nzmeas = 0;
+	int ncmeas = 0;
+	RKHitList rkl = new RKHitList();
+	Propagator prop = rkgeom.newPropagator();
+	double sum = 0.;
+	for ( RKSurf s: rkgeom.getCylinders() ){
+	    PropStat ps = prop.vecDirProp( vtdca, s.getCylinder(), PropDir.FORWARD);
+	    if ( ps.success() ){
+		sum += ps.pathDistance();
+		if ( sum > pathlimit ) break;
+		if ( s.inBounds(vtdca.vector(1)) ){
+		    rkl.addHit( new RKHit( rktrk, s, vtdca, ps, sum ) );
+		    aida.cloud2D( "HitGenNoScat/C r vs z",-1).fill( vtdca.vector(1), s.radius*mmTocm );
+		    aida.cloud2D( "HitGenNoScat/Both r vs z",-1).fill( vtdca.vector(1), s.radius*mmTocm );
+		    double r = s.radius*mmTocm;
+		    /*
+		    System.out.printf ("Adding Cyl: %10.4f %10.4f %10.4f %10.4f %10.4f %10.4f\n",
+				       r*Math.cos(vtdca.vector(0)),
+				       r*Math.sin(vtdca.vector(0)),
+				       r,
+				       vtdca.vector(1),
+				       sum,
+				       vtdca.vector(3)
+				       );
+		    */
+		    nmeas  += s.rodim;
+		    ncmeas += s.rodim;
+		}
+	    }
+	}
+	aida.cloud2D("HitGenNoScat/Path length vs cz",-1).fill(rktrk.cz(),sum);
+	aida.cloud1D("HitGenNoScat/Sum").fill(sum);
+	aida.cloud2D("HitGenNoScat/Hits vs cz",-1).fill( rktrk.cz(), ncmeas );
+
+	sum = 0;
+	for ( RKSurf s: rkgeom.getZ( rktrk.z0(), rktrk.cz() ) ){
+	    PropStat ps = prop.vecDirProp( vtz, s.getZPlane(), PropDir.FORWARD );
+	    if ( ps.success() ){
+		sum += ps.pathDistance();
+		if ( sum > pathlimit ) break;
+		double r = Math.sqrt(vtz.vector(0)*vtz.vector(0) + vtz.vector(1)*vtz.vector(1) );
+		if ( s.inBounds(r) ){
+		    rkl.addHit( new RKHit( rktrk, s, vtz, ps, sum ) );
+		    aida.cloud2D( "HitGenNoScat/Z r vs z",-1).fill( s.zc*mmTocm, r );
+		    aida.cloud2D( "HitGenNoScat/Both r vs z",-1).fill( s.zc*mmTocm, r );
+		    nmeas += s.rodim;
+		    nzmeas += s.rodim;
+		    /*
+		    System.out.printf ("Adding Z:   %10.4f %10.4f %10.4f %10.4f %10.4f\n",
+				       vtz.vector(0),
+				       vtz.vector(1),
+				       r,
+				       s.zc*0.1,
+				       sum );
+		    */
+		}
+	    }	    
+	}
+	aida.cloud2D("HitGenNoScat/Z Hits vs cz",-1).fill( rktrk.cz(), nzmeas );
+	aida.cloud2D("HitGenNoScat/Nmeas vs cz",-1).fill( rktrk.cz(), nmeas );
+	aida.cloud2D("HitGenNoScat/Nz vs Nc",-1).fill( ncmeas, nzmeas );
+
+	return rkl;
+    }
+
+    // Generate perfect hits on the outward going arc only.
+    // Do not apply energy loss or multiple scattering.
+    public RKHitList GenerateMixedOneArcHits( RKTrack rktrk ){
+
+	// Convert to TRF style track.
+	toTRF trftrk = new toTRF(rktrk);
+	VTrack vtdca = trftrk.atDcaZaxis();
+
+	// This code only looks at the first arc of a track.
+	double pathlimit = trftrk.halfarc();
+
+	int nmeas  = 0;
+	int nzmeas = 0;
+	int ncmeas = 0;
+	double sum = 0.;
+	RKHitList rkl = new RKHitList();
+	Propagator prop = rkgeom.newPropagator();
+
+	List<RKSurf> cyls = rkgeom.getCylinders();
+	List<RKSurf> zps  = rkgeom.getZ( rktrk.z0(), rktrk.cz() );
+
+	int next_cyl = 0;
+	int next_zp  = 0;
+	int max_cyl  = cyls.size();
+	int max_zp   = zps.size();
+
+	double sumde = 0;
+
+	// At top of the loop, vtdca contains the track parameters at the 
+	// departure point for this step.
+	while ( (next_cyl<max_cyl) || ( next_zp < max_zp ) ){
+
+	    VTrack vt_cyl = null;
+	    VTrack vt_zp  = null;
+	    
+	    double path_cyl = 0.;
+	    double path_zp  = 0.;
+
+	    int status_cyl  = 0;
+	    int status_zp   = 0;
+
+	    RKSurf rks_cyl  = null;	    
+	    RKSurf rks_zp   = null;	    
+
+	    PropStat ps_cyl = null;
+	    PropStat ps_zp  = null;
+
+	    double r_cyl = 0.;
+	    double z_cyl = 0.;
+	    double r_zp  = 0.;
+	    double z_zp  = 0.;
+
+	    int next_cyl_sav = next_cyl;
+	    int next_zp_sav  = next_zp;
+
+	    // Check cylindrical surfaces until the next good one is found.
+	    //while ( next_cyl < -1 ){
+	    while ( next_cyl < max_cyl ){
+
+		// Default status is failure.
+		status_cyl = 0;
+		
+		// Parameters at the starting surface for this step.
+		vt_cyl  = new VTrack(vtdca);
+
+		// Move to the next surface.
+		rks_cyl = cyls.get(next_cyl);
+		ps_cyl  = prop.vecDirProp( vt_cyl, rks_cyl.getCylinder(), PropDir.FORWARD);
+
+		// If we do not get to this cylinder, try the next one.
+		// This can happen if starting point is outside this one but inside a later one.
+		if ( !ps_cyl.success() ) {
+		    ++next_cyl;
+		    continue;
+		}
+
+		// If we moved backwards, try the next cylinder outward.
+		path_cyl = ps_cyl.pathDistance();
+		if ( path_cyl < 0. ) {
+		    //System.out.println ("Negative path at cyl..." );
+		    status_cyl = 3;
+		    ++next_cyl;
+		    continue;
+		}
+		status_cyl = 1;
+
+		// Needed for downstream diagnostics.
+		r_cyl = rks_cyl.radius*mmTocm;
+		z_cyl = vt_cyl.vector(1);
+
+		if ( rks_cyl.inBounds(z_cyl) ){
+
+		    // We have the next good surface from this list.
+		    status_cyl = 2;
+		    break;
+
+		} else{
+
+		    // If not in bounds, try the next surface.
+		    ++next_cyl;
+		    continue;
+		}
+		
+	    }
+	    
+	    // Check the next z surface.
+	    while ( next_zp < max_zp ){
+
+		// Default status is failure.
+		status_zp = 0;
+
+		// Parameters at the start of this step.
+		vt_zp  = new VTrack(vtdca);
+
+		// Move to the next surface.
+		rks_zp = zps.get(next_zp);
+	        ps_zp  = prop.vecDirProp( vt_zp, rks_zp.getZPlane(), PropDir.FORWARD );
+
+
+		// This happens when the z surface being tested is behind the starting point.
+		// Try the next surface.
+		if ( !ps_zp.success() ) {
+		    ++next_zp;
+		    continue;
+		}
+
+		// Normally this will not happen.  If it does, try the next surface.
+		path_zp = ps_zp.pathDistance();
+		if ( path_zp < 0. ) {
+		    status_zp = 3;
+		    ++next_zp;
+		    continue;
+		}
+		status_zp = 1;
+
+		// Needed for downstream diagnostics
+		r_zp = Math.sqrt(vt_zp.vector(0)*vt_zp.vector(0) + 
+				 vt_zp.vector(1)*vt_zp.vector(1) );
+		z_zp = rks_zp.zc*mmTocm;
+
+		if ( rks_zp.inBounds(r_zp) ){
+
+		    // We have the next good surface from this list.
+		    status_zp = 2;
+		    break;
+		}else{
+
+		    // Out of bounds so try the next surface.
+		    ++next_zp;
+		    continue;
+		}
+
+	    }
+
+	    // At this point we have zero, one or two good solutions.
+	    // If two, choose the one with the shortest step length.
+	    boolean addcyl = false;
+	    boolean addzp  = false;
+	    if ( status_cyl == 2 && status_zp == 2 ){
+		if (  path_cyl < path_zp ) {
+		    addcyl = true;
+		} else {
+		    addzp = true;
+		}
+	    } else if ( status_cyl == 2 ){
+		addcyl = true;
+
+	    } else if ( status_zp == 2 ){
+		addzp = true;
+	    } else {
+		
+		// This should only happen when both lists are exhausted.
+		// Or when one of the hit types is turned off.
+		if ( next_cyl<max_cyl || next_zp < max_zp ){
+		    System.out.println ("Don't know how I got here ... " 
+					+ next_cyl + " "
+					+ max_cyl  + " "
+					+ next_zp  + " "
+					+ max_zp
+					);
+		}
+	    }
+	    
+
+	    // Add the chosen hit.
+	    if ( addcyl ){
+
+		// Advance counter to next surface.
+		++next_cyl;
+
+		// Restore the z index to it's position at the start of this step.
+		next_zp = next_zp_sav;
+		
+		// Did we exceed the half-arc limit?
+		sum += path_cyl;
+		if ( sum > pathlimit ) break;
+
+		// Track parameters at this step.
+		vtdca = new VTrack(vt_cyl);
+
+		// Some diagnostics
+		aida.cloud2D( "HitGen/C r vs z",-1).fill( z_cyl, r_cyl );
+		aida.cloud2D( "HitGen/Both r vs z",-1).fill( z_cyl, r_cyl);
+
+		// Bookkeeping.
+		nmeas  += rks_cyl.rodim;
+		ncmeas += rks_cyl.rodim;
+
+		if ( doms ){
+
+		    // Interact.
+		    // Should modify this to not interact if this is the last point on the outward trace.
+		    VTrack test = new VTrack(vtdca);
+		    if ( r_cyl < 1.3 ){
+			scatSim0.interact(vtdca);
+		    } else if ( r_cyl < 10. ){
+			scatSim1.interact(vtdca);
+		    }else{
+			scatSim2.interact(vtdca);
+		    }
+
+
+		    // Diagnostics.
+		    double scatThick = 0.;
+		    if ( r_cyl < 1.3 ){
+			scatThick = scatThick0;
+		    }else if ( r_cyl < 10. ){
+			scatThick = scatThick1;
+		    } else{
+			scatThick = scatThick2;
+		    }
+		    ThinCylMs scat1  = new ThinCylMs(scatThick);
+		    TrackError vtmp  = new TrackError();
+		    ETrack et  = new ETrack( test.surface().newPureSurface(), test.vector(), vtmp);
+		    ETrack ets = new ETrack(et);
+		    scat1.interact(et);
+
+		    double dd = vtdca.vector().get(2)-test.vector().get(2);
+		    double ee = et.error().get(2,2);
+		    double r = dd/Math.sqrt(ee);
+		    aida.cloud1D( "HitGen/Scat pull").fill(r);
+		    aida.histogram1D("HitGen/Gen scat radius", 300, 0., 150.).fill(r_cyl);
+
+		}
+
+		// Add the hit.
+		rkl.addHit( new RKHit( rktrk, rks_cyl, vtdca, ps_cyl, sum ) );
+
+
+	    } else if ( addzp ) {
+
+		// Advance counter to next surface.
+		++next_zp;
+
+		// Restore the cylinder index to it's position at the start of this step.
+		next_cyl = next_cyl_sav;
+
+		// Did we exceed the half-arc limit?
+		sum += path_zp;
+		if ( sum > pathlimit ) break;
+
+		// Track parameters at this step.
+		vtdca = vt_zp;
+
+
+		// Some diagnostics
+		aida.cloud2D( "HitGen/Z r vs z",-1).fill( z_zp, r_zp );
+		aida.cloud2D( "HitGen/Both r vs z",-1).fill( z_zp, r_zp );
+
+		// Bookkeeping.
+		nmeas += rks_zp.rodim;
+		nzmeas += rks_zp.rodim;
+
+		if ( doms ){
+
+		    // Interact.
+		    // Should modify this to not interact if this is the last point on the outward trace.
+		    VTrack test = new VTrack(vtdca);
+		    if ( Math.abs(z_zp) < 25. ){
+			zscatSim1.interact(vtdca);
+		    }else{
+			zscatSim2.interact(vtdca);
+		    }
+		    aida.histogram1D("HitGen/Gen scat z", 340, -170., 170.).fill(z_zp);
+
+		}
+
+		// Add the hit.
+		rkl.addHit( new RKHit( rktrk, rks_zp, vtdca, ps_zp, sum ) );
+		
+
+	    } else {
+
+		// Neither intersected but try next surfaces for both lists.
+		++next_cyl;
+		++next_zp;
+	    }
+
+	}
+
+	// More diagnostics.
+	aida.cloud2D("HitGen/Path length vs cz",-1).fill(rktrk.cz(),sum);
+	aida.cloud2D("HitGen/C Hits vs cz",-1).fill( rktrk.cz(), ncmeas );
+	aida.cloud2D("HitGen/Z Hits vs cz",-1).fill( rktrk.cz(), nzmeas );
+	aida.cloud2D("HitGen/Nmeas vs cz",-1).fill( rktrk.cz(), nmeas );
+	aida.cloud2D("HitGen/Nz vs Nc",-1).fill( ncmeas, nzmeas );
+
+	aida.cloud1D("HitGen/Generated sumde:",-1).fill(sumde);
+	aida.histogram1D("HitGen/Generated sumde hist", 100, 0., 20.).fill(sumde*1000.);
+	RKDebug.Instance().setDeGen(sumde);
+
+	// If requested, also generate hits using the old algorithm and check that they
+	// agree with those from the new algorithm.  This only makes sense if ms and eloss
+	// are disabled.
+	if ( doHitCheck && !( doeloss || doms ) ){
+	    CheckHitList( rkl, rktrk );
+	}
+
+	return rkl;
+    }
+
+
+    // Check that the Mixed one arc hit generator matches the simple one.
+    // Only valid when scattering and eloss are turned off.
+    void CheckHitList( RKHitList hlist, RKTrack rktrk ){
+
+
+	RKHitList hlist2 = GenerateOneArcHits( rktrk );
+	int d1 = hlist.nHits() - hlist2.nHits();
+	int d2 = hlist.nCyl() - hlist2.nCyl();
+	int d3 = hlist.nZp()  - hlist2.nZp();
+	int d4 = hlist.nDof() - hlist2.nDof();
+
+	if ( (d1==0) && (d2==0) && (d3==0) && (d4 ==0) ){
+	    List<RKHit> l1 = hlist.getForward();
+	    List<RKHit> l2 = hlist2.getForward();
+	    for ( int i=0;i<l1.size(); ++i ){
+		RKHit h1 = l1.get(i);
+		RKHit h2 = l2.get(i);
+		double diff = h2.getPath()-h1.getPath();
+		aida.cloud1D("HitCheck/Difference in Path length: ").fill(diff);
+		
+	    }
+	}else{
+	    System.out.println ( "Diffs: " + d1 + " " +  d2 + " " + d3 + " " + d4 + " " + rktrk.cz() );
+	    System.out.println ( "Hits1: " 
+				 + hlist2.nHits() + " " 
+				 + hlist2.nCyl() + " " 
+				 + hlist2.nZp() + " " 
+				 + hlist2.nDof() + " " 
+				 );
+	    System.out.println ( "Hits2: " 
+				 + hlist.nHits() + " " 
+				 + hlist.nCyl() + " " 
+				 + hlist.nZp() + " " 
+				 + hlist.nDof() + " " 
+				 );
+	    int i=0;
+	    for ( RKHit h: hlist.getForward() ){
+		System.out.printf ( "Hits1: %3d %-20s %10.4f %10.4f\n",
+				    i++,
+				    h.getSurface().getTypeAsString(),
+				    h.getSurface().radius,
+				    h.getSurface().zc
+				    );
+	    }
+	    i=0;
+	    for ( RKHit h: hlist2.getForward() ){
+		System.out.printf ( "Hits2: %3d %-20s %10.4f %10.4f\n",
+				    i++,
+				    h.getSurface().getTypeAsString(),
+				    h.getSurface().radius,
+				    h.getSurface().zc
+				    );
+	    }
+
+	}
+
+    }
+
+}
+

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util
RKSurf.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/RKSurf.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/RKSurf.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,419 @@
+package org.hps.recon.tracking.kalman.util;
+
+import hep.physics.vec.Hep3Vector;
+
+import java.util.List;
+
+import org.lcsim.detector.IDetectorElement;
+import org.lcsim.detector.IGeometryInfo;
+import org.lcsim.detector.ILogicalVolume;
+import org.lcsim.detector.material.IMaterial;
+import org.lcsim.detector.solids.ISolid;
+import org.lcsim.detector.solids.Tube;
+import org.lcsim.geometry.compact.Subdetector;
+import org.lcsim.geometry.subdetector.PolyconeSupport;
+import org.lcsim.geometry.subdetector.PolyconeSupport.ZPlane;
+import org.lcsim.material.Material;
+import org.lcsim.recon.tracking.trfcyl.BSurfCylinder;
+import org.lcsim.recon.tracking.trfcyl.SurfCylinder;
+import org.lcsim.recon.tracking.trfcyl.ThinCylMs;
+import org.lcsim.recon.tracking.trfcyl.ThinCylMsSim;
+import org.lcsim.recon.tracking.trfzp.SurfZPlane;
+
+/**
+ * 
+ * Holds summary information about one sensitive surface.  The information
+ * is extracted from the org.lcsim geometry system.  This is a routine
+ * that needs to know that org.lcsim uses mm for distances but TRF uses cm.
+ *
+ *
+ *@author $Author: jeremy $
+ *@version $Id: RKSurf.java,v 1.1 2011/07/28 18:28:19 jeremy Exp $
+ *
+ * Date $Date: 2011/07/28 18:28:19 $
+ *
+ */
+
+public class RKSurf{
+
+    // TRF wants distances in cm, not mm.
+    private double mmTocm = 0.1;
+
+    // Name of this Subdetector.
+    public String name = "";
+
+    // Readout dimension:
+    // 0 = inactive
+    // 1 = strips
+    // 2 = pixels
+    public int rodim;
+
+    // References to subdetector and detector element info.
+    public Subdetector      sd = null;
+    public IDetectorElement de = null;
+
+    public double radius = 0.;
+    public double thick  = 0.;
+    public double zmin   = 0.;
+    public double zmax   = 0.;
+    public double zc     = 0.;
+    public double rmin   = 0.;
+    public double rmax   = 0.;
+
+    // Does a 1D measurement measure the first or second coordinate?
+    public int ixy = -1;
+    static public int ixy_Undef = -1;
+    static public int ixy_x   = 0;
+    static public int ixy_y   = 1;
+    static public int ixy_phi = 0;
+    static public int ixy_z   = 1;
+
+    private double[] resolutions;
+
+    // Different inputs have different places to find materials.
+    public Material   material = null;
+    public IMaterial imaterial = null;
+
+    // Name of the material.
+    public String matname = "Undefined";
+
+    // Radiation length of the material;
+    public double radl = 0;
+
+    // Thickness in units of radiation length.
+    public double thick_radl = 0.;
+
+    // Density.
+    public double density = 0.0;
+
+    // Tolerance for comparing floating point numbers.
+    private double tolerance = 1.e-4;
+
+    // Types
+    private int type;
+    // Types
+    static public int type_tube=0;
+    static public int type_zdisc=1;
+
+    public SurfCylinder getCylinder(){
+	if ( type != type_tube ){
+	    System.out.println("Cannot return a cylinder from a non-tube surface: " + name );
+	    System.exit(-1);
+	}
+	SurfCylinder s    = new SurfCylinder( radius*mmTocm );
+	ThinCylMs    scat = new ThinCylMs   ( thick_radl );
+	ThinCylMsSim sim  = new ThinCylMsSim( thick_radl );
+	s.setInteractor(scat);
+	s.setSimInteractor(sim);
+	return s;
+    }
+
+    public BSurfCylinder getBCylinder(){
+	if ( type != type_tube ){
+	    System.out.println("Cannot return a bounded cylinder from a non-tube surface: " + name );
+	    System.exit(-1);
+	}
+	return new BSurfCylinder( radius*mmTocm, zmin*mmTocm, zmax*mmTocm );
+    }
+
+    public boolean inBounds ( double trfarg ){
+	if ( type == type_tube ){
+	    double z = trfarg/mmTocm;
+	    return (z>=zmin)&&(z<=zmax);
+	} else if ( type == type_zdisc ){
+	    double r = trfarg/mmTocm;
+	    return (r>=rmin)&&(r<=rmax);
+	}
+	return false;
+    }
+
+    public int getType(){
+	return type;
+    }
+
+    public String getTypeAsString(){
+	if ( type == type_tube ){
+	    return "Tube ";
+	} else if ( type == type_zdisc ){
+	    return "Zdisc";
+	}
+	return "Unknown";
+    }
+
+    public SurfZPlane getZPlane(){
+	if ( type != type_zdisc ){
+	    System.out.println("Cannot return a ZPlane from a non-zplane surface: " + name );
+	    System.exit(-1);
+	}
+	return new SurfZPlane( zc*mmTocm );
+    }
+
+    public double[] getResolutions(){
+	return resolutions;
+    }
+
+    public double getResolution0(){
+	boolean ok = true;
+	if ( resolutions == null ){
+	    ok = false;
+	} else {
+	    if ( resolutions.length < 1 ){
+		ok = false;
+	    }
+	}
+	if ( !ok ){
+	    System.out.println ("RKSurf: Illegal request for getResolution0 " + name );
+	    return 0.;
+	}
+	return resolutions[0];
+    }
+
+    public double getResolution1(){
+	boolean ok = true;
+	if ( resolutions == null ){
+	    ok = false;
+	} else {
+	    if ( resolutions.length < 1 ){
+		ok = false;
+	    }
+	}
+	if ( !ok ){
+	    System.out.println ("RKSurf: Illegal request for getResolution1 " + name );
+	    return 0.;
+	}
+	return resolutions[1];
+    }
+
+
+    public RKSurf( IDetectorElement de, int rodim, int ixy, double[] res ){
+	if ( de == null ){
+	    System.out.println("RKSurf: Cannot instantiate RKSurf with null DetectorElement." );
+	    System.exit(-1);
+	}
+
+	this.name  = de.getName();
+	this.rodim = rodim;
+	this.ixy   = ixy;
+	resolutions = new double[res.length];
+	for ( int i=0; i<res.length; ++i){
+	    resolutions[i] = res[i]*mmTocm;
+	}
+	Build( de);
+    }
+
+    public RKSurf( IDetectorElement de, int rodim, int ixy, double res ){
+	if ( de == null ){
+	    System.out.println("RKSurf: Cannot instantiate RKSurf with null DetectorElement." );
+	    System.exit(-1);
+	}
+
+	this.name  = de.getName();
+	this.rodim = rodim;
+	this.ixy   = ixy;
+	resolutions = new double[1];
+	resolutions[0] = res*mmTocm;
+	Build( de);
+    }
+
+    public RKSurf( IDetectorElement de, int rodim, int ixy, double res0, double res1 ){
+	if ( de == null ){
+	    System.out.println("RKSurf: Cannot instantiate RKSurf with null DetectorElement." );
+	    System.exit(-1);
+	}
+
+	this.name  = de.getName();
+	this.rodim = rodim;
+	this.ixy   = ixy;
+	resolutions = new double[2];
+	resolutions[0] = res0*mmTocm;
+	resolutions[1] = res1*mmTocm;
+	Build( de);
+    }
+
+
+
+    public RKSurf( Subdetector sd ){
+	if ( sd == null ){
+	    System.out.println("RKSurf: Cannot instantiate RKSurf with null Subdetector." );
+	    System.exit(-1);
+	}
+
+	this.sd = sd;
+	rodim   = 0;
+	name    = sd.getName();
+	Build( sd );
+    }
+    
+    // Adjust z position.  Used in the equivstrips model.
+    public void hackZc( double dz){
+	zc+=dz;
+    }
+
+    public void Print(){
+	if ( type == type_tube ){
+	    System.out.printf ( "%-40s %1d %3d %10.2f %10.2f %10.2f %10.2f %-20s %10.2f %10.6f %10.6f\n",
+				name,
+				rodim, 
+				ixy,
+				radius,
+				thick,
+				zmin,
+				zmax,
+				matname,
+				radl,
+				thick_radl,
+				density
+				);
+	} else {
+	    System.out.printf ( "%-40s %1d %3d %10.2f %10.2f %10.2f %10.2f %-20s %10.2f %10.6f %10.6f\n",
+				name,
+				rodim, 
+				ixy,
+				zc,
+				thick,
+				rmin,
+				rmax,
+				matname,
+				radl,
+				thick_radl,
+				density
+				);
+	}
+    }
+
+
+    private void Build( Subdetector sd ){
+
+	String classname  = sd.getClass().getName();
+	String shortname  = classname.replaceAll("org.lcsim.geometry.subdetector.","");
+
+	if ( shortname.compareTo("PolyconeSupport") == 0 ) {
+	    PolyconeSupport pc = (PolyconeSupport) sd;
+	    AddPolycone(pc);
+
+	} else {
+	    System.out.println("RKSurf: Do not know how to add this subdetector: "
+			       + name + " " + classname);
+	    System.exit(-1);
+	}
+
+	matname = material.getName();
+	radl    = material.getRadiationLength();
+
+	thick_radl = thick/radl;
+
+    }
+
+    private void Build( IDetectorElement de ){
+	
+	//System.out.println ("Starting: " + name );
+	IGeometryInfo g   = de.getGeometry();
+	if ( g == null ){
+	    System.out.println("Missing geometry for detector element: " + name );
+	    System.exit(-1);
+	}
+	ILogicalVolume lv = g.getLogicalVolume();
+	if ( lv == null ){
+	    System.out.println("Missing logical volume for detector element: " + name );
+	    System.exit(-1);
+	}
+	IMaterial mat     = lv.getMaterial();
+	ISolid solid      = lv.getSolid();
+	Hep3Vector center = g.getPosition();
+
+	String solidname  = getSolidTypeName(solid);
+
+	if ( solidname.compareTo("Tube") == 0  ){
+	    Tube tube = (Tube) solid;
+	    if ( tube.getZHalfLength() > 1.0 ){
+		AddTube( tube, center );
+	    }else{
+		AddZDisc( tube, center);
+	    }
+	    
+	} else {
+	    System.out.println ( "RKSurf: Do not recognize this shape for this DetectorElement: "
+				 + solidname + " " + name );
+	    System.exit(-1);
+	}
+	matname = mat.getName();
+	radl    = mat.getRadiationLength();
+	density = mat.getDensity();
+
+	thick_radl = thick/radl;
+
+    }
+
+    private void AddPolycone ( PolyconeSupport pc ){
+	type = type_tube;
+	List<ZPlane> zplanes = pc.getZPlanes();
+	boolean ok = false;
+	for ( int i=1; i<zplanes.size(); ++i ){
+	    ZPlane zp1 = zplanes.get(i-1);
+	    ZPlane zp2 = zplanes.get(i);
+	    if ( zp1.getZ() < 0. && zp2.getZ() > 0. ){
+		if ( Math.abs(zp1.getRMax()-zp1.getRMax()) > tolerance ||
+		     Math.abs(zp1.getRMin()-zp1.getRMin()) > tolerance    ){
+		    System.out.println ("RKSurf: Mismatched radii in beampipe: "
+					+ name );
+		}
+		radius = 0.5*(zp1.getRMax() + zp1.getRMin());
+		thick  = zp1.getRMax() - zp1.getRMin();
+		zmin   = zp1.getZ();
+		zmax   = zp2.getZ();
+		ok = true;
+	    }
+	}
+
+	if ( !ok ){
+	    System.out.println( "RKSurf: Could not parse PolyconeSupport for subdetector"
+				+ name );
+	    System.exit(-1);
+	}
+
+	// Depracated but replacement appears not to be in place.
+	material = pc.getMaterial();
+
+	radl = material.getRadiationLength();
+	density = material.getDensity();
+
+    }
+
+    private void AddTube ( Tube tube, Hep3Vector center ){
+	type = type_tube;
+	if ( Math.abs( center.x()) > tolerance ||
+	     Math.abs( center.y()) > tolerance ||
+	     Math.abs( center.z()) > tolerance    ){
+	    System.out.println("RKSurf: Only do tubes centered on (0.0,0.0,0.) " );
+	    System.exit(-1);
+	}
+
+	zmin   = -tube.getZHalfLength();
+	zmax   = tube.getZHalfLength();
+	radius = 0.5*(tube.getOuterRadius()+tube.getInnerRadius());
+	thick  = tube.getOuterRadius()-tube.getInnerRadius();
+
+    }
+
+    private void AddZDisc ( Tube tube, Hep3Vector center ){
+	type   = type_zdisc;
+	zmin   = center.z()-tube.getZHalfLength();
+	zmax   = center.z()+tube.getZHalfLength();
+	radius = 0.5*(tube.getOuterRadius()+tube.getInnerRadius());
+	thick  = 2.*tube.getZHalfLength();
+	
+	zc     = center.z();
+	rmin   = tube.getInnerRadius();
+	rmax   = tube.getOuterRadius();
+    }
+
+
+
+    // Utility function to extract a short version of the class name. 
+    private String getSolidTypeName( ISolid s ){
+	String fullname = s.getClass().getName();
+	String name     = fullname.replaceAll( "org.lcsim.detector.solids.", "");
+	return name;
+    }
+
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util
RKTrack.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/RKTrack.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/RKTrack.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,150 @@
+package org.hps.recon.tracking.kalman.util;
+
+import org.lcsim.constants.Constants;
+import org.lcsim.recon.tracking.trfutil.TRFMath;
+
+/**
+ * 
+ * One generated track.  The constructor uses a parameterization that
+ * is useful for thinking about the range of generated parameters.
+ * Other information is available.  Distances are in mm and momentum in GeV/c.
+ * 
+ *  pt  = transverse momentum (GeV)
+ *  cz  = cos(theta)
+ *  phi = azimuth of momentum (radians)
+ *  d0  = signed DCA wrt z axis (mm)
+ *  z0  = z at PCA to z axis (mm)
+ * 
+ * Parameters are defined in the CLEO convention.
+ * 
+ *@author $Author: jeremy $
+ *@version $Id: RKTrack.java,v 1.1 2011/07/28 18:28:19 jeremy Exp $
+ *
+ * Date $Date: 2011/07/28 18:28:19 $
+ *
+ */
+
+
+public class RKTrack {
+
+
+    public RKTrack( double q, 
+		    double pt, 
+		    double cz, 
+		    double phi0, 
+		    double d0,
+		    double z0,
+		    double bz){
+	
+	this.q    = q;
+	this.pt   = pt;
+	this.cz   = cz;
+	this.phi0 = phi0;
+	this.d0   = d0;
+	this.z0   = z0;
+	this.bz   = bz;
+	
+	update();
+    }
+
+    public RKTrack ( RKTrack t ){
+	q    = t.q;
+	pt   = t.pt;
+	cz   = t.cz;
+	phi0 = t.phi0;
+	d0   = t.d0;
+	z0   = t.z0;
+	bz   = t.bz;
+	
+	update();
+    }
+
+    
+    public double q()     { return     q;}
+    public double pt()    { return    pt;}
+    public double cz()    { return    cz;}
+    public double phi0()  { return  phi0;}
+    public double d0()    { return    d0;}
+    public double z0()    { return    z0;}
+    public double cu()    { return    cu;}
+    public double p()     { return     p;}
+    public double cotth() { return cz/sz;}
+    public double x0()    { return    x0;}
+    public double y0()    { return    y0;}
+    public double sz()    { return    sz;}
+    public double rho()   { return   rho;}
+
+    public double e() {
+	return e(m_pi);
+    }
+
+    public double e( double m ){
+	return Math.sqrt( p*p + m*m);
+    }
+    
+    // Synonym for cottan(theta);
+    public double tanlam()  { return cz/sz;}
+
+    public double momentum(){ return     p;}
+    public double charge()  { return     q;}
+
+    public String toString(){
+	return String.format("CLEO Style track: q=%4.1f pt=%10.4f cz=%10.4f phi0=%10.4f d0=%10.4f z0=%10.4f\n",
+			   q, pt, cz, phi0, d0, z0  );
+    }
+
+    public double phi_pos(){
+	return TRFMath.fmod2(Math.atan2(y0,x0),TRFMath.TWOPI);
+    }
+
+    private double bz=5.0;
+
+    private double  q;       // Charge
+    private double pt;       // Transverse momentum wrt z axis
+    private double cz;       // Cos(theta) of momentum
+    private double phi0;     // Azimuth of momentum
+    private double d0;       // Signed DCA to z axis
+    private double z0;       // z0 at PCA to z axis
+
+
+    // Derived quantities:
+    private double p;        // momentum
+    private double rho;      // Radius of curvature
+    private double cu;       // Curvature in cleo convention ( = q/2/rho).
+
+    private double sz;       // sin(theta)
+    private double cotth;    // cot(theta)
+
+    private double sphi0;    // sin(phi0)
+    private double cphi0;    // cos(phi0)
+
+    private double x0;       // x at PCA to z axis.
+    private double y0;       // y at PCA to z axis.
+
+    // Matches precicision in TRF.
+    private double m_pi = 0.13957;
+
+    private void update(){
+	rho   = pt/Constants.fieldConversion/bz;
+	cu    = 0.5*q/rho;
+	sphi0 = Math.sin(phi0);
+	cphi0 = Math.cos(phi0);
+	sz    = Math.sqrt( 1. - cz*cz);
+	cotth = cz/sz;
+	p     = pt/sz;
+	x0    = -d0*sphi0;
+	y0    =  d0*cphi0;
+
+    }
+
+    // Some other possibly useful things.
+    //double rc = d0 + 0.5/kappa;
+    //double xc = -rc*sphi0;
+    //double yc =  rc*cphi0;
+
+
+    //double cx = cphi0*sinth;
+    //double cy = sphi0*sinth;
+    //double cz = costh;
+
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util
RKTrackGen.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/RKTrackGen.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/RKTrackGen.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,92 @@
+package org.hps.recon.tracking.kalman.util;
+
+import java.util.Random;
+
+import org.lcsim.util.aida.AIDA;
+
+/**
+ * 
+ * A crude track generator.  It emits tracks in the CLEO parameterization.
+ *
+ *@author $Author: jeremy $
+ *@version $Id: RKTrackGen.java,v 1.1 2011/07/28 18:28:19 jeremy Exp $
+ *
+ * Date $Date: 2011/07/28 18:28:19 $
+ *
+ */
+
+public class RKTrackGen {
+
+    private AIDA aida = AIDA.defaultInstance();
+
+    public RKTrackGen( long seed){
+	par= new RKTrackGenParams();
+	ran = new Random(seed);
+    }
+
+    public RKTrackGen( RKTrackGenParams par, long seed){
+	this.par=par;
+	ran = new Random(seed);
+    }
+
+    public RKTrack newRKTrack (){
+
+	// Generate track parameters in cleo convention.
+	double pt    = par.ptmin()  + (par.ptmax()-par.ptmin())*ran.nextDouble();
+	double q = 1.;
+	if ( par.chargeControl() == -1 ){
+	    q = -1;
+	}else if ( par.chargeControl() != 1 ){
+	    q = ( ran.nextDouble() > 0.5 ) ? 1. : -1.;
+	}
+	double cz    = par.czmin()  + (par.czmax()-par.czmin())*ran.nextDouble();
+	double phi0  = par.phimin() + (par.phimax()-par.phimin())*ran.nextDouble();
+	double d0    = par.d0min()  + (par.d0max()-par.d0min())*ran.nextDouble();
+	double z0    = par.z0min()  + (par.z0max()-par.z0min())*ran.nextDouble();
+
+	// Use endcap mode for cz.
+	if ( par.czEndcapMode ){
+	    if ( ran.nextDouble() > 0.5 ) cz = -cz;
+	}
+
+	RKTrack t = new RKTrack( q, pt, cz, phi0, d0, z0, par.bz());
+
+	plotGenTrack(t);
+
+	return t;
+    }
+
+    // Monitoring histograms for the generated track.
+    public void plotGenTrack( RKTrack t ){
+
+	int nbins = 50;
+
+	double d0min = -5.;
+	double d0max =  5.;
+	double z0min = -15.;
+	double z0max =  15.;
+
+	aida.histogram1D("GeneratedParams/charge",5,-2.,2.).fill(t.q());
+	aida.histogram1D("GeneratedParams/pt", nbins,0.,25.).fill(t.pt());
+	aida.histogram1D("GeneratedParams/cos(theta)", nbins, -1., 1.).fill(t.cz());
+	aida.histogram1D("GeneratedParams/phi0",nbins, -Math.PI, Math.PI).fill(t.phi0());
+	aida.histogram1D("GeneratedParams/d0", nbins, d0min, d0max).fill(t.d0());
+	aida.histogram1D("GeneratedParams/z0", nbins, z0min, z0max).fill(t.z0());
+	aida.histogram1D("GeneratedParams/p", nbins, 0., 50.).fill(t.p());
+	aida.cloud2D("GeneratedParams/PCA0",-1).fill(t.x0(),t.y0());
+	aida.cloud2D("GeneratedParams/D0 vs Z0",-1).fill(t.z0(),t.d0());
+
+    }
+
+
+    public RKTrackGenParams getParams(){
+	return new RKTrackGenParams(par);
+    }
+
+    private Random ran = null;
+    private RKTrackGenParams par = null;
+
+
+
+
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util
RKTrackGenParams.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/RKTrackGenParams.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/RKTrackGenParams.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,202 @@
+package org.hps.recon.tracking.kalman.util;
+
+/**
+ * 
+ * Parameters to control RKTrackGen.
+ *
+ *@author $Author: jeremy $
+ *@version $Id: RKTrackGenParams.java,v 1.1 2011/07/28 18:28:19 jeremy Exp $
+ *
+ * Date $Date: 2011/07/28 18:28:19 $
+ *
+ */
+
+public class RKTrackGenParams {
+
+    // Limits for track parameter generation.
+    private double ptmin =      1.00;
+    private double ptmax =     10.00;
+    private double czmin =     -0.95;
+    private double czmax =      0.95;
+    private double phimin = -Math.PI;
+    private double phimax =  Math.PI;
+    private double d0min =     -4.00;
+    private double d0max =      4.00; 
+    private double z0min =    -10.00;
+    private double z0max =     10.00;
+
+    // Control of charge generation:
+    //  +1  = generate only charge +1
+    //  -1  = generate only charge -1
+    // else = generate both charges +1 and -1 in equal amounts.
+    int chargeControl = 0;
+
+    // Enable end cap mode for cz generation.
+    // That is, generate cz uniformly over:
+    //         czmin< cz <=  czmax
+    //   and  -czmax< cz <= -czmin
+    // The default mode is to generate uniformly over:
+    //    czmin< cz <=  czmax
+    boolean czEndcapMode = false;
+
+    // Strength of solenoidal magnetic field on z axis.
+    private double bz = 5.00;
+
+    public RKTrackGenParams(){
+    }
+
+    public RKTrackGenParams( ToyConfig config ){
+
+	// Override default values using values specified in the
+	// runtime configuration file, if present.
+	ptmin   = config.getDouble( "ptmin",  ptmin);
+	ptmax   = config.getDouble( "ptmax",  ptmax);
+	czmin   = config.getDouble( "czmin",  czmin);
+	czmax   = config.getDouble( "czmax",  czmax);
+	phimin  = config.getDouble( "phimin", phimin);
+	phimax  = config.getDouble( "phimax", phimax);
+	d0min   = config.getDouble( "d0min",  d0min);
+	d0max   = config.getDouble( "d0max",  d0max);
+	z0min   = config.getDouble( "z0min",  z0min);
+	z0max   = config.getDouble( "z0max",  z0max);
+
+	bz            = config.getDouble ( "bz",            bz);
+	chargeControl = config.getInt    ( "chargeControl", chargeControl);
+	czEndcapMode  = config.getBoolean( "czEndcapMode",  czEndcapMode);
+
+    }
+
+    public RKTrackGenParams(
+			    double ptmin,
+			    double ptmax,
+			    double czmin,
+			    double czmax,
+			    double phimax,
+			    double phimin,
+			    double d0min,
+			    double d0max,
+			    double z0min,
+			    double z0max,
+			    double bz,
+			    int chargeControl
+			    ){
+	this.ptmin  = ptmin;
+	this.ptmax  = ptmax;
+	this.czmin  = czmin;
+	this.czmax  = czmax;
+	this.phimax = phimax;
+	this.phimin = phimin;
+	this.d0min  = d0min;
+	this.d0max  = d0max;
+	this.z0min  = z0min;
+	this.z0max  = z0max;
+	this.bz     = bz;
+	this.chargeControl = chargeControl;
+    }
+
+    public RKTrackGenParams( RKTrackGenParams par ){
+	ptmin  = par.ptmin;
+	ptmax  = par.ptmax;
+	czmin  = par.czmin;
+	czmax  = par.czmax;
+	phimax = par.phimax;
+	phimin = par.phimin;
+	d0min  = par.d0min;
+	d0max  = par.d0max;
+	z0min  = par.z0min;
+	z0max  = par.z0max;
+	bz     = par.bz;
+	chargeControl = par.chargeControl;
+    }
+
+
+    public void setptmin(double ptmin){
+	this.ptmin=ptmin;
+    }
+
+    public void setptmax(double ptmax){
+	this.ptmax=ptmax;
+    }
+
+    public void setczmin(double czmin){
+	this.czmin=czmin;
+    }
+
+    public void setczmax(double czmax){
+	this.czmax=czmax;
+    }
+
+    public void setphimin(double phimin){
+	this.phimin=phimin;
+    }
+
+    public void setphimax(double phimax){
+	this.phimax=phimax;
+    }
+
+    public void setd0min(double d0min){
+	this.d0min=d0min;
+    }
+
+    public void setd0max(double d0max){
+	this.d0max=d0max;
+    }
+
+    public void setz0min(double z0min){
+	this.z0min=z0min;
+    }
+
+    public void setz0max(double z0max){
+	this.z0max=z0max;
+    }
+
+    public void setbz(double bz){
+	this.bz=bz;
+    }
+
+    public void setchargeControl(int c){
+	chargeControl=c;
+    }
+
+    public double ptmin(){ return ptmin;}
+    public double ptmax(){ return ptmax;}
+
+    public double czmin(){ return czmin;}
+    public double czmax(){ return czmax;}
+
+    public double phimin(){ return phimin;}
+    public double phimax(){ return phimax;}
+
+    public double d0min(){ return d0min;}
+    public double d0max(){ return d0max;}
+
+    public double z0min(){ return z0min;}
+    public double z0max(){ return z0max;}
+
+    public double bz(){ return bz;}
+
+    public double chargeControl(){ return chargeControl;}
+
+    public String toString(){
+	StringBuffer s = new StringBuffer();
+	s.append("Parameters for track generation: \n");
+	s.append(String.format( "Pt:   (%10.4f, %10.4f) (GeV)\n", ptmin,  ptmax ));
+	s.append(String.format( "cz:   (%10.4f, %10.4f)\n", czmin,  czmax ));
+	s.append(String.format( "Phi0: (%10.4f, %10.4f)\n", phimin, phimax ));
+	s.append(String.format( "d0:   (%10.4f, %10.4f) (mm)\n", d0min,  d0max ));
+	s.append(String.format( "z0:   (%10.4f, %10.4f) (mm)\n", z0min,  z0max ));
+	if ( chargeControl == 1 || chargeControl == -1 ){
+	    s.append(String.format( "Charge %3d only.  ", chargeControl ));
+	} else{
+	    s.append("Charge +1 and -1 equally.  ");
+	}
+	if ( czEndcapMode ){
+	    s.append("Endcap mode for cos(theta).\n");
+	} else{
+	    s.append("Normal mode for cos(theta).\n");
+	}
+
+	s.append(String.format("BField strength %10.2f (T)\n", bz));
+	return s.toString();
+    }
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util
RKZot.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/RKZot.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/RKZot.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,93 @@
+package org.hps.recon.tracking.kalman.util;
+
+import org.lcsim.recon.tracking.trfbase.ETrack;
+import org.lcsim.recon.tracking.trfbase.TrackError;
+import org.lcsim.recon.tracking.trfcyl.SurfCylinder;
+import org.lcsim.recon.tracking.trffit.HTrack;
+
+
+/**
+ * 
+ * A utility used to debug precision problems with
+ * inwards going fits.  It resets the z dependent parts
+ * of the covariance matrix of a track to the values 
+ * that it had at the start of the fit.
+ * 
+ * This is used to effectively do a 2-D circle fit instead
+ * of a 3D helix fit but throwing out the z information
+ * after each hit has been added.
+ *
+ * For this to work properly the track must start
+ * at the SurfCyl surface but I never put a check in the
+ * code for this.
+ *
+ * Usage:
+ * - at the start of a fit, instantiate a new RKZot object.
+ * - whenever you feel like throwing out the z information
+ *   call the Zot method.
+ *
+ *@author $Author: jeremy $
+ *@version $Id: RKZot.java,v 1.1 2011/07/28 18:28:19 jeremy Exp $
+ *
+ * Date $Date: 2011/07/28 18:28:19 $
+ *
+ *
+ */
+
+
+public class  RKZot{
+
+    static final int IPHI = SurfCylinder.IPHI;
+    static final int IZ   = SurfCylinder.IZ;
+    static final int IALF = SurfCylinder.IALF;
+    static final int ITLM = SurfCylinder.ITLM;
+    static final int IQPT = SurfCylinder.IQPT;
+
+    TrackError e0;
+
+    public RKZot( HTrack h0 ){
+	ETrack et =h0.newTrack();
+
+	// Do I want to check that this is a SurfCyl?
+	
+	e0 = et.error();
+
+    }
+    
+    public void Zot( HTrack h  ){
+	ETrack et = h.newTrack();
+
+	if ( !(et.surface() instanceof SurfCylinder) ){
+	    System.out.println ("Error RKZot2: Not a cylinder ... " );
+	    return;
+	}
+
+	TrackError err = et.error();
+
+	err.set(   IZ,   IZ, e0.get(  IZ,  IZ) );
+	err.set( ITLM, ITLM, e0.get(ITLM,ITLM) );
+
+	err.set(   IZ, IPHI, 0. );
+	err.set(   IZ, IALF, 0. );
+	err.set(   IZ, ITLM, 0. );
+	err.set(   IZ, IQPT, 0. );
+
+	err.set( IPHI,   IZ, 0. );
+	err.set( IALF,   IZ, 0. );
+	err.set( ITLM,   IZ, 0. );
+	err.set( IQPT,   IZ, 0. );
+
+	err.set( ITLM, IPHI, 0. );
+	err.set( ITLM, IALF, 0. );
+	err.set( ITLM, IQPT, 0. );
+
+	err.set( IPHI, ITLM, 0. );
+	err.set( IALF, ITLM, 0. );
+	err.set( IQPT, ITLM, 0. );
+
+	et.setError( err ); 
+	h.setFit( et, h.chisquared() ); 
+    }
+
+}
+           

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util
SurfaceCode.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/SurfaceCode.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/SurfaceCode.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,44 @@
+package org.hps.recon.tracking.kalman.util;
+
+import org.lcsim.recon.tracking.trfbase.Surface;
+import org.lcsim.recon.tracking.trfcyl.SurfCylinder;
+import org.lcsim.recon.tracking.trfdca.SurfDCA;
+import org.lcsim.recon.tracking.trfzp.SurfZPlane;
+
+/**
+ * 
+ * Define integer codes, and corresponding strings, to identify a type of surface.
+ *
+ *@author $Author: jeremy $
+ *@version $Id: SurfaceCode.java,v 1.1 2011/07/28 18:28:19 jeremy Exp $
+ *
+ * Date $Date: 2011/07/28 18:28:19 $
+ *
+ */
+
+
+public class SurfaceCode {
+
+    static final String[] namelist = { "Unknown", "Cylinder", "ZPlane", "DCA" };
+
+    private int code=0;
+
+    public SurfaceCode ( Surface s ){
+	if ( s.pureType().equals( SurfCylinder.staticType() ) ){
+	    code = 1;
+	} else if ( s.pureType().equals( SurfZPlane.staticType() ) ){
+	    code = 2;
+	} else if ( s.pureType().equals( SurfDCA.staticType() ) ){
+	    code = 3;
+	}
+	
+    }
+
+    public int getCode(){
+	return code;
+    }
+
+    public String getName(){
+	return namelist[code];
+    }
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util
ThinZPlaneMs.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/ThinZPlaneMs.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/ThinZPlaneMs.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,209 @@
+package  org.hps.recon.tracking.kalman.util;
+//package  org.lcsim.recon.tracking.trfzp;
+
+import org.lcsim.recon.tracking.trfbase.ETrack;
+import org.lcsim.recon.tracking.trfbase.Interactor;
+import org.lcsim.recon.tracking.trfbase.Surface;
+import org.lcsim.recon.tracking.trfbase.TrackError;
+import org.lcsim.recon.tracking.trfbase.TrackVector;
+import org.lcsim.recon.tracking.trfutil.Assert;
+import org.lcsim.recon.tracking.trfutil.TRFMath;
+import org.lcsim.recon.tracking.trfzp.SurfZPlane;
+
+/**
+ * This class modifies the covariance matrix of a track
+ *corresponding to multiple
+ *scattering in a thin z plane whose material is
+ *represented by the number of radiation lengths.
+ *
+ *@author Norman A. Graf
+ *@version 1.0
+ *
+ */
+
+public class ThinZPlaneMs extends Interactor
+{
+    
+    // static methods
+    
+    //
+    
+    /**
+     *Return a String representation of the class' type name.
+     *Included for completeness with the C++ version.
+     *
+     * @return   A String representation of the class' type name.
+     */
+    public  static String typeName()
+    { return "ThinZPlaneMs"; }
+    
+    //
+    
+    /**
+     *Return a String representation of the class' type name.
+     *Included for completeness with the C++ version.
+     *
+     * @return   A String representation of the class' type name.
+     */
+    public  static String staticType()
+    { return typeName(); }
+    
+    // static attributes
+    // Assign track parameter indices.
+    
+    private static final int IX = SurfZPlane.IX;
+    private static final int IY   = SurfZPlane.IY;
+    private static final int IDXDZ = SurfZPlane.IDXDZ;
+    private static final int IDYDZ = SurfZPlane.IDYDZ;
+    private static final int IQP  = SurfZPlane.IQP;
+    
+    
+    // attributes
+    private double _radLength;
+    
+    //
+    
+    /**
+     * Construct an instance from the number of radiation
+     * lengths of the thin z plane material.
+     * The Interactor is constructed with the
+     * appropriate number of radiation lengths.
+     *
+     * @param   radLength The thickness of the material in radiation lengths.
+     */
+    public ThinZPlaneMs( double radLength )
+    {
+        _radLength = radLength;
+    }
+    
+    //
+    
+    /**
+     *Interact the given track in this z plane,
+     *using the thin material approximation for multiple scattering.
+     *Note that the track parameters are not modified. Only the
+     *covariance matrix is updated to reflect the uncertainty caused
+     *by traversing the thin z plane of material.
+     *
+     * @param   tre The ETrack to scatter.
+     */
+    public void interact(ETrack tre)
+    {
+        // This can only be used with zplanes... check that we have one..
+        SurfZPlane szp = new SurfZPlane(1.0);
+        Surface srf = tre.surface();
+        Assert.assertTrue( srf.pureType().equals(szp.pureType()) );
+        
+        TrackError cleanError = tre.error();
+        TrackError newError = new TrackError(cleanError);
+        
+        // set the rms scattering appropriate to this momentum
+        
+        // Theta = (0.0136 GeV)*(z/p)*(sqrt(radLength))*(1+0.038*log(radLength))
+        
+        
+        
+        TrackVector theVec = tre.vector();
+        double trackMomentum = theVec.get(IQP);
+        
+        double f = theVec.get(IDXDZ);
+        double g = theVec.get(IDYDZ);
+        
+        double theta = Math.atan(Math.sqrt(f*f + g*g));
+        double phi = f!=0 ? Math.atan(Math.sqrt((g*g)/(f*f))) : TRFMath.PI2;
+        if ( f==0 && g<0 ) phi=3*TRFMath.PI2;
+        if((f<0)&&(g>0))
+            phi = Math.PI - phi;
+        if((f<0)&&(g<0))
+            phi = Math.PI + phi;
+        if((f>0)&&(g<0))
+            phi = 2*Math.PI - phi;
+        
+        double trueLength = _radLength/Math.cos(theta);
+        
+        double stdTheta = (0.0136)*trackMomentum*Math.sqrt(trueLength)*
+                (1 + 0.038*Math.log(trueLength));
+        
+        double zhat = Math.sqrt(1-Math.sin(theta)*Math.sin(theta));
+        double xhat = Math.sin(theta)*Math.cos(phi);
+        double yhat = Math.sin(theta)*Math.sin(phi);
+        
+        double Qxz,Qyz,Qxy;
+        
+        // The MS covariance matrix can now be set.
+        
+        // **************** code for matrix *********************** //
+        
+        
+        // Insert values for upper triangle... use symmetry to set lower.
+
+        double norm = Math.sqrt(xhat*xhat + yhat*yhat);
+        
+	double fac = stdTheta*stdTheta/norm/norm/zhat/zhat;
+	Qxz = fac*( yhat*yhat + f*f);
+	Qyz = fac*( xhat*xhat + g*g);
+	Qxy = fac*( -xhat*yhat + f*g);
+	
+        
+        newError.set(IDXDZ,IDXDZ, newError.get(IDXDZ,IDXDZ) + Qxz);
+        newError.set(IDYDZ,IDYDZ, newError.get(IDYDZ,IDYDZ) + Qyz);
+        newError.set(IDXDZ,IDYDZ, newError.get(IDXDZ,IDYDZ) + Qxy);
+        
+        //**********************************************************************
+        
+        tre.setError( newError );
+        
+    }
+    
+    //
+    
+    /**
+     *Return the number of radiation lengths.
+     *
+     * @return The thickness of the scattering material in radiation lengths.
+     */
+    public double radLength()
+    {
+        return _radLength;
+    }
+    
+    
+    //
+    
+    /**
+     *Make a clone of this object.
+     *
+     * @return A Clone of this instance.
+     */
+    public Interactor newCopy()
+    {
+        return new ThinZPlaneMs(_radLength);
+    }
+    
+    
+    //
+    
+    /**
+     *Return a String representation of the class' type name.
+     *Included for completeness with the C++ version.
+     *
+     * @return   A String representation of the class' type name.
+     */
+    public String type()
+    {
+        return staticType();
+    }
+    
+    
+    
+    /**
+     *output stream
+     *
+     * @return  A String representation of this instance.
+     */
+    public String toString()
+    {
+        return "ThinZPlaneMs with "+_radLength+" radiation lengths";
+    }
+    
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util
ThinZPlaneMsSim.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/ThinZPlaneMsSim.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/ThinZPlaneMsSim.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,202 @@
+package org.hps.recon.tracking.kalman.util;
+//package  org.lcsim.recon.tracking.trfzp;
+
+
+import java.util.Random;
+
+import org.lcsim.recon.tracking.trfbase.SimInteractor;
+import org.lcsim.recon.tracking.trfbase.TrackVector;
+import org.lcsim.recon.tracking.trfbase.VTrack;
+import org.lcsim.recon.tracking.trfzp.SurfZPlane;
+
+
+/**
+ * Class for adding Multiple Scattering to track vectors defined at
+ * ZPlanes.  Single point interaction is assumed.
+ *
+ *@author Norman A. Graf
+ *@version 1.0
+ *
+ */
+public class ThinZPlaneMsSim extends SimInteractor
+{
+    // static attributes
+    // Assign track parameter indices.
+    
+    private static final int IX = SurfZPlane.IX;
+    private static final int IY   = SurfZPlane.IY;
+    private static final int IDXDZ = SurfZPlane.IDXDZ;
+    private static final int IDYDZ = SurfZPlane.IDYDZ;
+    private static final int IQP  = SurfZPlane.IQP;
+    
+    
+    // attributes
+    
+    // random number generator
+    private Random _r;
+    
+    // radiation lengths in material
+    private double _radLength;
+    
+    //
+    
+    /**
+     * Construct an instance from the number of radiation
+     * lengths of the thin z plane material.
+     * The Interactor is constructed with the
+     * appropriate number of radiation lengths.
+     *
+     * @param   radLengths The thickness of the material in radiation lengths.
+     */
+    public ThinZPlaneMsSim( double radLengths )
+    {
+        _radLength = radLengths;
+        _r = new Random();
+    }
+    
+    //
+    
+    /**
+     *Interact the given track in this thin z plane,
+     *using the thin material approximation for multiple scattering.
+     *Note that the track parameters are modified to simulate
+     *the effects of multiple scattering in traversing the thin z
+     *plane of material.
+     *
+     * @param   vtrk  The Vrack to scatter.
+     */
+    public void interact( VTrack vtrk )
+    {
+        TrackVector trv = new TrackVector( vtrk.vector() );
+        // first, how much should the track be scattered:
+        // uses radlength from material and angle track - plane (leyer)
+        double  trackMomentum = trv.get(IQP);
+        
+        double f = trv.get(IDXDZ);
+        double g = trv.get(IDYDZ);
+        
+        double theta = Math.atan(Math.sqrt(f*f + g*g));
+        double phi = 0.;
+        if (f != 0.) phi = Math.atan(Math.sqrt((g*g)/(f*f)));
+        if (f == 0.0 && g < 0.0) phi = 3.*Math.PI/2.;
+        if (f == 0.0 && g > 0.0) phi = Math.PI/2.;
+        if (f == 0.0 && g == 0.0)
+        {
+            phi = 99.;// that we can go on further.....
+            System.out.println(" DXDY and DXDZ both 0");
+        }
+        if((f<0)&&(g>0))
+            phi = Math.PI - phi;
+        if((f<0)&&(g<0))
+            phi = Math.PI + phi;
+        if((f>0)&&(g<0))
+            phi = 2*Math.PI - phi;
+        
+        double trueLength = _radLength/Math.cos(theta);
+        
+        double scatRMS = (0.0136)*trackMomentum*Math.sqrt(trueLength)*
+                (1 + 0.038*Math.log(trueLength));
+        
+        double zhat = Math.sqrt(1-Math.sin(theta)*Math.sin(theta));
+        double xhat = Math.sin(theta)*Math.cos(phi);
+        double yhat = Math.sin(theta)*Math.sin(phi);
+        
+        double[] scatterVec = new double[3];
+        double[] finalVec = new double[3];
+        double[][] Rotation = new double[3][3];
+        
+        //set Rotation matrix as given in D0note ????
+        double ctrans = Math.sqrt(xhat*xhat + yhat*yhat);
+        Rotation[0][0] = -yhat/ctrans;
+        Rotation[0][1] = -zhat*xhat/ctrans;
+        Rotation[0][2] = xhat;
+        Rotation[1][0] = xhat/ctrans;
+        Rotation[1][1] = -zhat*yhat/ctrans;
+        Rotation[1][2] = yhat;
+        Rotation[2][0] = 0;
+        Rotation[2][1] = (xhat*xhat+yhat*yhat)/ctrans;
+        Rotation[2][2] = zhat;
+        
+        //now set the Vector after scattering ( (0,0,1) ->( theta1, theta2, 1)*norm)
+        scatterVec[0] = scatRMS*_r.nextGaussian();
+        scatterVec[1] = scatRMS*_r.nextGaussian();
+        scatterVec[2] = 1.0;
+        double norm = Math.sqrt(scatterVec[0]*scatterVec[0] + scatterVec[1]*scatterVec[1]
+                + scatterVec[2]*scatterVec[2]);
+        
+        if (norm!=0)
+        {
+            scatterVec[0] /= norm;
+            scatterVec[1] /= norm;
+            scatterVec[2] /= norm;
+        };
+        
+        //now go back to the global coordinate system
+        //leave that step out if track coodsys = global coordsys
+        double finalxz;
+        double finalyz;
+        if (phi != 99.)
+        {
+            for (int k = 0; k<3; k++)
+            {
+                finalVec[k] = 0.;
+                for (int l = 0; l<3 ; l++)
+                {
+                    finalVec[k] += Rotation[k][l]*scatterVec[l];
+                }
+            }
+            finalxz = finalVec[0]/finalVec[2];
+            finalyz = finalVec[1]/finalVec[2];
+        }
+        else
+        {
+            finalxz = scatterVec[0];
+            finalyz = scatterVec[1];
+        };
+        
+        trv.set(IDXDZ, finalxz);
+        trv.set(IDYDZ, finalyz);
+        
+        // assume that we don't encounter back-scattering... which is
+        // assumed above anyway.
+        vtrk.setVectorAndKeepDirection( trv );
+        
+    }
+    
+    
+    /**
+     *Return the number of radiation lengths of material in this thin z plane.
+     *
+     * @return The number of radiation lengths.
+     */
+    public double radLength()
+    {
+        return _radLength;
+    }
+    
+    //
+    
+    /**
+     * Make a clone of this object.
+     * Note that new copy will have a different random number generator.
+     *
+     * @return A Clone of this instance.
+     */
+    public SimInteractor newCopy()
+    {
+        return new ThinZPlaneMsSim(_radLength);
+    }
+    
+    
+    
+    /**
+     *output stream
+     *
+     * @return A String representation of this instance.
+     */
+    public String toString()
+    {
+        return "ThinZPlaneMsSim with "+_radLength+" radiation lengths";
+    }
+    
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util
ToyConfig.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/ToyConfig.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/ToyConfig.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,463 @@
+package org.hps.recon.tracking.kalman.util;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ *
+ * Main class in a primitive runtime configuration utility.
+ * Parses the input file into records, holds a collection of
+ * records and provides access by parameter name.  Provides
+ * error checking of the global structure of the file and
+ * for attempts to access non-existent parameters.
+ *
+ *@author $Author: jeremy $
+ *@version $Id: ToyConfig.java,v 1.1 2011/07/28 18:28:19 jeremy Exp $
+ *
+ * Date $Date: 2011/07/28 18:28:19 $
+ *
+ */
+
+//
+// Work list:
+// 1) Should I make the copy c'tor and assignment operators private?
+//    or is this even a sensible question in java?
+// 2) The following record will fail to parse correctly.
+//    String name = "//This is not a comment";
+// 3) Catch exceptions??
+// 4) Rename toString so that it can throw??
+
+public class ToyConfig{
+
+    /**
+     * Manage creation of the singleton instance and access to it.
+     *
+     * @return The singleton instance of this class.
+     */
+    static public ToyConfig getInstance() throws ToyConfigException{
+	if ( instance == null ){
+	    instance = new ToyConfig();
+	}
+	return instance;
+    }
+
+
+    /**
+     * Read the input file to populate this class.
+     *
+     * @return The singleton instance of this class.
+     */
+    private ToyConfig( ) throws ToyConfigException{
+	ReadFile();
+    }
+
+
+    /**
+     * Change the configuration file to be read. Gives a warning if
+     * a configuration file has already been read.
+     *
+     */
+    public static void setConfigFile( String file ){
+	if ( instance == null ){
+	    configfile = file;
+	} else {
+	    System.err.println("Configuration file already read;" +
+			       " setConfigFile() will be ignored." );
+	}
+    }
+
+    /**
+     * Return a Set<String> containing all variable names found in
+     * the configuration file.
+     *
+     * @return a Set<String> containing all variable names.
+     */
+    public Set<String> getAllNames(){
+	return rmap.keySet();
+    }
+
+    // Accessors to named parameters, separated by data type.
+    // All checking is done in the ToyConfigRecord class.
+
+
+    /**
+     * Get a specified parameter as a string.  Works for all record types.
+     *
+     * @return the value of the parameter.
+     */
+    public String getString ( String name ) throws ToyConfigException{
+	ToyConfigRecord r = getRecord(name);
+	return r.getString();
+    }
+
+    /**
+     * Get a specified parameter as a String, if not present in the file
+     * return the value specified by the second argument.
+     *
+     * @return the value of the parameter as an String.
+     */
+    public String getString ( String name, String def ){
+	String i=def;
+	try{
+	    ToyConfigRecord r = getRecord(name);
+	    i = r.getString();
+	} catch ( ToyConfigException e ){
+	}
+	return i;
+    }
+
+    /**
+     * Get a specified parameter as a int.
+     *
+     * @return the value of the parameter as an int.
+     */
+    public int getInt ( String name ) throws ToyConfigException{
+	ToyConfigRecord r = getRecord(name);
+	return r.getInt();
+    }
+
+    /**
+     * Get a specified parameter as a int, if not present in the file
+     * return the value specified by the second argument.
+     *
+     * @return the value of the parameter as an int.
+     */
+    public int getInt ( String name, int def ){
+	int i=def;
+	try{
+	    ToyConfigRecord r = getRecord(name);
+	    i = r.getInt();
+	} catch ( ToyConfigException e ){
+	}
+
+	return i;
+    }
+
+    /**
+     * Get a specified parameter as a double.
+     *
+     * @return the value of the parameter as an double.
+     */
+    public double getDouble ( String name ) throws ToyConfigException{
+	ToyConfigRecord r = getRecord(name);
+	return r.getDouble();
+    }
+
+    /**
+     * Get a specified parameter as a double, if not present in the file
+     * return the value specified by the second argument.
+     *
+     * @return the value of the parameter as an double.
+     */
+    public double getDouble ( String name, double def ){
+	double d=def;
+	try{
+	    ToyConfigRecord r = getRecord(name);
+	    d = r.getDouble();
+	} catch ( ToyConfigException e ){
+	}
+
+	return d;
+    }
+
+
+    /**
+     * Get a specified parameter as a boolean.
+     *
+     * @return the value of the parameter as an boolean.
+     */
+    public boolean getBoolean ( String name ) throws ToyConfigException{
+	ToyConfigRecord r = getRecord(name);
+	return r.getBoolean();
+    }
+
+    /**
+     * Get a specified parameter as a boolean, if not present in the file
+     * return the value specified by the second argument.
+     *
+     * @return the value of the parameter as an boolean.
+     */
+    public boolean getBoolean ( String name, boolean def ){
+	boolean b=def;
+	try{
+	    ToyConfigRecord r = getRecord(name);
+	    b = r.getBoolean();
+	} catch ( ToyConfigException e ){
+	}
+
+	return b;
+    }
+
+
+    /**
+     * Get a specified parameter as a List<String>. Works for all parameter types.
+     *
+     * @return the value of the parameter as a List<String>.
+     */
+    public List<String> getListString ( String name ) throws ToyConfigException{
+	ToyConfigRecord r = getRecord(name);
+	return r.getListString();
+    }
+
+
+    /**
+     * Get a specified parameter as a List<Integer>.
+     *
+     * @return the value of the parameter as a List<Integer>.
+     */
+    public List<Integer> getListInteger ( String name ) throws ToyConfigException{
+	ToyConfigRecord r = getRecord(name);
+	return r.getListInteger();
+    }
+
+    /**
+     * Get a specified parameter as an array int[].
+     *
+     * @return the value of the parameter as an array int[].
+     */
+    public int[] getArrayInt ( String name ) throws ToyConfigException{
+	ToyConfigRecord r = getRecord(name);
+	List<Integer> l = r.getListInteger();
+
+	// Copy to array format.
+	int[] a = new int[l.size()];
+	for ( int i=0; i<l.size(); ++i ){
+	    a[i]=(l.get(i)).intValue();
+	}
+	return a;
+    }
+
+
+    /**
+     * Get a specified parameter as a List<Double>.
+     *
+     * @return the value of the parameter as a List<Double>.
+     */
+    public List<Double> getListDouble ( String name ) throws ToyConfigException{
+	ToyConfigRecord r = getRecord(name);
+	return r.getListDouble();
+    }
+
+    /**
+     * Get a specified parameter as an array double[].
+     *
+     * @return the value of the parameter as an array double[].
+     */
+    public double[] getArrayDouble ( String name ) throws ToyConfigException{
+	ToyConfigRecord r = getRecord(name);
+	List<Double> l = r.getListDouble();
+
+	// Copy to array format.
+	double[] a = new double[l.size()];
+	for ( int i=0; i<l.size(); ++i ){
+	    a[i]=(l.get(i)).doubleValue();
+	}
+	return a;
+    }
+
+    /**
+     * Get a specified parameter as a List<Boolean>.
+     *
+     * @return the value of the parameter as a List<Boolean>.
+     */
+    public List<Boolean> getListBoolean ( String name ) throws ToyConfigException{
+	ToyConfigRecord r = getRecord(name);
+	return r.getListBoolean();
+    }
+
+    /**
+     * Get a specified parameter as an array boolean[].
+     *
+     * @return the value of the parameter as an array boolean[].
+     */
+    public boolean[] getArrayBoolean ( String name ) throws ToyConfigException{
+	ToyConfigRecord r = getRecord(name);
+	List<Boolean> l = r.getListBoolean();
+
+	// Copy to array format.
+	boolean[] a = new boolean[l.size()];
+	for ( int i=0; i<l.size(); ++i ){
+	    a[i]=(l.get(i)).booleanValue();
+	}
+	return a;
+    }
+
+
+    /**
+     * Return a the parameter as a formatted string.
+     *
+     * @return a formatted copy of the requested parameter.
+     */
+    public String toString ( String name ){
+	try { 
+	    ToyConfigRecord r = getRecord(name);
+	    return r.toString();
+	} catch ( ToyConfigException e ){
+	    return e.getMessage();
+	}
+    }
+
+
+    /**
+     * Return the complete record as s formatted string.
+     *
+     * @return a formatted copy of the record for the requested parameter.
+     */
+    public ToyConfigRecord getRecord ( String name ) throws ToyConfigException{
+	ToyConfigRecord r = rmap.get(name);
+	if ( r == null ) {
+	    throw new ToyConfigException ("No such parameter: " + name 
+				       + " in file: " + configfile );
+	}
+	return r;
+    }
+
+    /**
+     * Return the name of the input file.
+     *
+     * @return name of the input file.
+     */
+    public String ToyConfigfile(){
+	return configfile;
+    }
+
+    /**
+     * Print a formatted copy of the full configuration file
+     * to the specified output stream.
+     *
+     */
+    public void printAll( PrintStream out){
+	for ( ToyConfigRecord r : image ){
+	    out.println( r.toString() );
+	}
+	out.println("");
+    }
+
+    /**
+     * Print a formatted copy of the full configuration file
+     * to System.out.
+     *
+     */
+    public void printAll( ){
+	printAll(System.out);
+    }
+
+    // Private instance data.
+
+    // Access to the configuration data, keyed by parameter name.
+    Map<String,ToyConfigRecord> rmap = null;
+
+    // Access to the info in rmap in the order in which the records were present
+    // in the input file.
+    List<ToyConfigRecord> image = null;
+
+    // Name of the configuration file, initialized to its default value.
+    private static String configfile = "runtime.conf";
+
+    // Singleton instance.
+    private static ToyConfig instance = null;
+
+    // Private methods, other than the constructor.
+
+
+    /**
+     * Read the input file, break it into records.
+     * Keep a copy of the input file in the orginal record order.
+     * Create a map to access records by parameter name.
+     *
+     */
+    private void ReadFile() throws ToyConfigException{
+
+	rmap  = new HashMap<String,ToyConfigRecord>();
+	image = new ArrayList<ToyConfigRecord>();
+
+	try {
+	    FileReader fr = new FileReader(configfile);
+	    BufferedReader file = new BufferedReader(fr);
+
+	    // Can make this a single loop.
+
+	    String line;
+	    while ( (line = file.readLine()) != null ){
+
+		// Remove comments.
+		line = StripComment(line);
+
+		// Add extension lines if needed.
+		if ( WantsExtension(line) ){
+
+		    StringBuffer all = new StringBuffer(line.substring(0,line.length()));
+		    String nextline;
+		    while ( (nextline = file.readLine()) != null ){
+			nextline = StripComment(nextline);
+			if ( WantsExtension(nextline) ){
+			    if ( nextline.length() != 0 ) 
+			    all.append(nextline.substring(0,nextline.length()).trim());
+			    line = all.toString();
+			} else{
+			    all.append(nextline.trim());
+			    line = all.toString();
+			    break;
+			}
+		    }
+		}
+
+		ToyConfigRecord r = new ToyConfigRecord(line);
+		image.add(r);
+		if ( !r.isCommentOrBlank() ) {
+		    rmap.put(r.getName(),r);
+		}
+	    }
+	    
+	} catch (IOException e){
+	    throw new ToyConfigException( "Error reading configuration file: "  
+					  + configfile 
+					  );
+	}
+    }
+
+    /**
+     * Test to see if this record is complete.
+     * 
+     * A valid end of line indicator is a semi-colon as the last non-blank character
+     * before any comments.  Otherwise this record needs an extension.
+     *
+     * @return true if this record is incomplete and false if it is complete.
+     */
+    private boolean WantsExtension( String s){
+	int icomment = s.indexOf("//");
+	String line = ( icomment == -1 ) ? s.trim() : s.substring(0,icomment).trim();
+	if ( line.length() == 0 ) return false;
+	return ( !line.endsWith(";")) ;
+    }
+
+    /**
+     * Remove, comments, trailing white space and leading whitespace input string.
+     *  - a comment begins with // and continues for the rest of the line.
+     *
+     * This will give a wrong result on a line like:
+     * String name = "//This is not supposed to be a comment"; 
+     *
+     * @return a copy of the input with comments and insignificant whitespace removed.
+     */
+    private String StripComment( String s){
+
+	// Find comment delimiter if present.
+	int islash = s.indexOf("//");
+
+	if ( islash < 0 ){
+	    return s.trim();
+	}
+
+	return s.substring(0,islash).trim();
+
+    }
+
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util
ToyConfigException.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/ToyConfigException.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/ToyConfigException.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,22 @@
+package org.hps.recon.tracking.kalman.util;
+
+
+/**
+ *
+ * Exception class for primitive Run Time configuration utility.
+ *
+ *
+ *@author $Author: jeremy $
+ *@version $Id: ToyConfigException.java,v 1.1 2011/07/28 18:28:19 jeremy Exp $
+ *
+ * Date $Date: 2011/07/28 18:28:19 $
+ *
+ */
+
+
+public class ToyConfigException extends Exception{
+    
+    public ToyConfigException ( String s){
+	super(s);
+    }
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util
ToyConfigRecord.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/ToyConfigRecord.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/ToyConfigRecord.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,696 @@
+package org.hps.recon.tracking.kalman.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ *
+ * A class to hold one record within the primitive 
+ * RunTimeConfiguration utility.
+ *
+ *@author $Author: jeremy $
+ *@version $Id: ToyConfigRecord.java,v 1.1 2011/07/28 18:28:19 jeremy Exp $
+ *
+ * Date $Date: 2011/07/28 18:28:19 $
+ *
+ */
+
+//
+// This class holds a single record from the configuration file.
+// It parses the record, checks for internal consistency and provides
+// accesors for information in the record.
+// 
+// Notes:
+// 1) Supported types:
+//    String, int, double, boolean.
+//    List<String>, List<Integer>, List<Double>, List<Boolean>.
+//    Note that scalar types are primitives but List types are objects.
+//
+// 2) Supports empty lists and empty strings.
+//
+//
+// Work list:
+// 1) Is List the right interface for the return values?
+// 2) Is it aproblem that I return int for scalars and Integer for integer lists?
+//    Similarly for boolean and double? Should I make it symmetric?
+// 3) Should I make copy and assignment c'tors private or non-existant?
+//    Needed in C++ what about Java?
+// 4) Rename toString so that it can throw?
+// 5) Do the type conversion in c'tor so that we fail immediately
+//    and not later on when someone tries to read the value.
+// 6) Add extra accessors to return other arrays as an option to Lists.
+// 7) Add accessor to return a scalar as a list of length 1??
+// 8) 
+//
+
+public class ToyConfigRecord {
+    
+    // Constructor.
+    public ToyConfigRecord( String record ) throws ToyConfigException{
+	this.record = record;
+	Parse();
+    }
+
+
+    /**
+     * Returns a copy of the input record as it was found in the input file
+     * but with line breaks removed.
+     *
+     * @return A copy of the raw record.
+     */
+    public String getRecord(){
+	return record;
+    }
+
+    /**
+     * Returns the type field of this record.
+     * @return The type.
+     */
+    public String getType (){
+	return Type;
+    }
+
+    /**
+     * Returns the variable name field of this record.
+     * @return The variable name.
+     */
+    public String getName (){
+	return Name;
+    }
+
+    /**
+     * Returns the comment field, if any, of this record.
+     * @return The comment, if any, that is part of this record.
+     */
+    public String getComment(){
+	return comment;
+    }
+
+    /**
+     * Returns true if the record contains nothing more than a comment or if the
+     * the record is blank.
+     *
+     * @return true if the record is a pure comment or is blank; false otherwise.
+     */
+    public boolean isCommentOrBlank(){
+	return isCommentOrBlank;
+    }
+
+    // Accessors to return supported data types.
+
+    /**
+     * Return the value as string.  This will work for any data type.
+     * @return The value as a string.
+     */
+    public String getString (){
+	return Values.get(0);
+    }
+
+    /**
+     * Return the value as an int.  Only works for recrods that are of type int.
+     *
+     * @return The value of an int record.
+     */
+    public int getInt () throws ToyConfigException{
+	CheckType("int");
+	try{
+	    return Integer.valueOf(Values.get(0));
+	} catch(NumberFormatException e){
+	    throw new ToyConfigException("Cannot parse this value as an integer: "
+				      + record );
+	}
+    }
+
+    /**
+     * Return the value as an double.  Only works for records that are of type double.
+     * 
+     * @return The value of a double record.
+     */
+    public double getDouble () throws ToyConfigException{
+	CheckType("double");
+	double x=0.;
+	try{
+	    x = Double.valueOf(Values.get(0));
+	} catch(NumberFormatException e){
+	    throw new ToyConfigException("Cannot parse this value as a double: "
+				      + record );
+	}
+	return x;
+    }
+
+    /**
+     * Return the value as a boolean.  Only works for records that are of type boolean.
+     * 
+     * @return The value of a boolean record.
+     */
+    public boolean getBoolean() throws ToyConfigException {
+	CheckType("boolean");
+	boolean b=false;
+	try{
+	    b = Boolean.valueOf(Values.get(0));
+	} catch(NumberFormatException e){
+	    throw new ToyConfigException("Cannot parse this value as a boolean: "
+				      + record );
+	}
+	return b;
+    }
+
+    /**
+     * Return the value as a list of strings.  Works for all record types.
+     *
+     * @return The value of a the record.
+     */
+    // Can return any type of list as a list of strings.
+    public List<String> getListString() throws ToyConfigException{
+	AnyList();
+	return Values;
+    }
+
+    /**
+     * Return the value as a List<Integer>.  Only works for records that are of type List<Integer>.
+     * 
+     * @return The value of a List<int> record.
+     */
+    public List<Integer> getListInteger() throws ToyConfigException {
+	CheckType("List<int>");
+	List<Integer> l = new ArrayList<Integer>();
+	for ( String v : Values ){
+	    Integer I =0;
+	    try{
+		I = Integer.valueOf(v);
+	    } catch(NumberFormatException e){
+		throw new ToyConfigException("Cannot parse this value as a List<int>: "
+					  + record );
+	    }
+	    l.add(I);
+	}
+	return l;
+    }
+
+    /**
+     * Return the value as a List<Double>.  Only works for records that are of type List<Double>.
+     * 
+     * @return return the value of a List<double> record.
+     */
+    public List<Double> getListDouble() throws ToyConfigException {
+	CheckType("List<double>");
+	List<Double> l = new ArrayList<Double>();
+	for ( String v : Values ){
+	    Double D = 0.;
+	    try{
+		D = Double.valueOf(v);
+	    } catch(NumberFormatException e){
+		throw new ToyConfigException("Cannot parse this value as a List<double>: "
+					  + record );
+	    }
+	    l.add(D);
+	}
+	return l;
+    }
+
+    /**
+     * Return the value as a List<Boolean>.  Only works for records that are of type List<Boolean>.
+     * 
+     * @return the value of a List<boolean> record.
+     */
+    public List<Boolean> getListBoolean() throws ToyConfigException {
+	CheckType("List<boolean>");
+	List<Boolean> l = new ArrayList<Boolean>();
+	for ( String v : Values ){
+	    Boolean D = false;
+	    try{
+		D = Boolean.valueOf(v);
+	    } catch(NumberFormatException e){
+		throw new ToyConfigException("Cannot parse this value as a List<boolean>: "
+					  + record );
+	    }
+	    l.add(D);
+	}
+	return l;
+    }
+
+    /**
+     * 
+     * Format the record as a string with standard spacing, ignoring the spacing
+     * on the input line. If the data are strings, then enclose each string in 
+     * quotes, even if it has no embedded spaces.
+     *
+     * 
+     * @return A formatted copy of the record.
+     */
+    // I would like this to throw but it cannot since it overrides a method of the base 
+    // class "Object" that does not throw an exception.
+    public String toString() {
+	if ( isCommentOrBlank ){
+	    return comment;
+	}
+	StringBuffer s = new StringBuffer(Type);
+	s.append(" ");
+	s.append(Name);
+	s.append(" = ");
+	try{
+	    if ( isList ) {
+		s.append("{ ");
+		if ( Type.equals("List<int>") ){
+		    boolean first = true;
+		    for ( Integer I : getListInteger() ){
+			if( !first ){
+			    s.append(", ");
+			} else{
+			    first = false;
+			}
+			s.append(I.toString());
+		    }
+		} else if ( Type.equals("List<double>")){
+		    boolean first = true;
+		    for ( Double D : getListDouble() ){
+			if( !first ){
+			    s.append(", ");
+			} else{
+			    first = false;
+			}
+			s.append(D.toString());
+		    }
+		} else if ( Type.equals("List<boolean>")){
+		    boolean first = true;
+		    for ( Boolean B : getListBoolean() ){
+			if( !first ){
+			    s.append(", ");
+			} else{
+			    first = false;
+			}
+			s.append(B.toString());
+		    }
+		} else {
+		    boolean first = true;
+		    for ( String B : getListString() ){
+			if( !first ){
+			    s.append(", \"");
+			} else{
+			    s.append("\"");
+			    first = false;
+			}
+			s.append(B.toString());
+			s.append( "\"");		}
+		}
+		s.append(" }");
+	    }else{
+		if ( Type.equals("int") ){
+		    try{
+			Integer I = getInt();
+			s.append(I.toString());
+		    }catch(ToyConfigException e){
+			s.append("???");
+		    }
+		} else if ( Type.equals("double")){
+		    try{
+			Double D = getDouble();
+			s.append(D.toString());
+		    } catch (ToyConfigException e){
+			s.append("???");
+		    }
+		} else if ( Type.equals("boolean")){
+		    Boolean B = getBoolean();
+		    s.append( B.toString());
+		} else {
+		    s.append( "\"");
+		    s.append( getString() );
+		    s.append( "\"");
+		}
+	    }
+	}catch (ToyConfigException e) {
+	    System.out.println (e.getMessage() );
+	    s.append(" [Error formating this item], ");
+	}
+	s.append(";");
+	return s.toString();
+    }
+
+    // Private instance data.
+
+    // A copy of the record as it came in.
+    // An external class does the concatenation of multiple line records into a single string.
+    // Present implementation also strips comments - but that could change in the future.
+    private String record;
+
+    // Record with comments and enclosing white space stripped out.
+    private String barerecord;
+
+    // Comment field, including the // delimiter.
+    private String comment = "";
+
+    // Data type.
+    private String Type = null;
+
+    // Name of the datum.
+    private String Name = null;
+
+    // The value field - not yet parsed into components.
+    private String Value = null;
+
+    // The value field, parsed into components.
+    private List<String> Values = null;
+
+    // State data.
+    private boolean isCommentOrBlank = false;
+    private boolean isList           = false;
+
+    // Private methods.
+
+    /**
+     * 
+     * Parse this record, starting from its input string.
+     * 
+     */
+    private void Parse () throws ToyConfigException{
+
+	// Find comment delimiter if present.
+	int islash = record.indexOf("//");
+
+	// Extract comment, if any.
+	if ( islash >= 0 ) comment = record.substring(islash);
+
+	// Extract the part of the record that preceeds the comment.
+	// Trim leading and trailing whitespace.
+	String tmp = (islash < 0 ) ? record.trim() : record.substring(0,islash).trim();
+
+	// Line is blank or contains only a comment.
+	if ( tmp.length() == 0 ){
+	    isCommentOrBlank = true;
+	    return;
+	}
+
+	// Check for syntax of a complete record.
+	if ( tmp.charAt(tmp.length()-1) != ';' ){
+	    throw new ToyConfigException ("Not terminated by Semicolon: " + record);
+	}
+
+	// Strip the trailing semicolon and the leading and trailing whitespace.
+	barerecord = tmp.substring(0,tmp.length()-1).trim();
+	
+	// Split the line into: type name = value;
+	SplitLine();
+
+	// Parse the value part of the record.
+	ParseValue();
+
+    }
+
+
+    /**
+     * 
+     * Split this record into 3 fields: Type Name = Value; 
+     * 
+     */
+    private void SplitLine() throws ToyConfigException{
+
+	// Is there an equals sign with enough space before and after it?
+	// The minimal line is:
+	// t n=v
+	// where,
+	// t = type
+	// n = name
+	// v = value
+	// the space between t and n is significant.
+	// No embedded whitespace allowed within t or n.
+	// So the first legal spot for the equals sign is:
+	//   - must be at index 3 or greater
+	//   - the first equals sign in the line must not be the last non-whitespace character in the line.
+	// Remember that barerecord has leading and trailing spaces trimmed.
+	int iequal = barerecord.indexOf("=");
+	if ( iequal < 3 || iequal >= barerecord.length()-1){
+	    throw new ToyConfigException( "Misplaced equals sign in record: " + record );
+	}
+
+	// The value part of the field, to be parsed elsewhere.
+	Value = barerecord.substring(iequal+1).trim();
+	
+	// Extract type and name fields.
+	String first = barerecord.substring(0,iequal);
+	String [] tmp = first.split("[ \t]+");
+	if ( tmp.length != 2 || Value.length() < 1 ){
+	    throw new ToyConfigException( "Too many files in record: " + record );
+	}
+	Type = tmp[0];
+	Name = tmp[1];
+
+    }
+
+
+    /**
+     * 
+     * Parse the Value part of the record.
+     * 
+     */
+    private void ParseValue() throws ToyConfigException{
+
+	// Check for a record that is a list.
+	isList = ( Type.indexOf("List<") > -1 ) ? true: false;
+
+	// Part of the string to parse.
+	// Default is for non-lists.
+	int iopen  = 0;
+	int iclose = Value.length();
+
+	// If this is a list, strip the enclosing {}.
+	if ( isList ){
+	    iopen  = Value.indexOf("{");
+	    iclose = Value.lastIndexOf("}");
+	    if ( ( iopen  < 0 ) ||
+		 ( iclose < 0 ) ||
+		 ( iclose < (iopen+1) ) ){
+		throw new ToyConfigException( "Cannot parse record as a list: " +  record );
+	    }
+	    iopen = iopen + 1;
+	} 
+
+	// Remove {}, if present, and any leading and trailing whitespace.
+	String listpart = Value.substring(iopen,iclose).trim();
+
+	// Output of the parsing: one entry for each value in the list.
+	Values = new ArrayList<String>();
+
+	// Accumulate the next value in this variable.
+	StringBuffer next = new StringBuffer();
+
+	// Some predefined characters that hve special meaning.
+	Character quote = Character.valueOf('\"');
+	Character slash = Character.valueOf('\\');
+	Character comma = Character.valueOf(',');
+
+	// States:
+	// 0: not within any value
+	// 1: within a value that is not started by a quotation mark.
+	// 2: within a value that is started by a quotation mark.
+	// 3: into white space delimitation but have not yet found comma.
+	// 10: last character was an escape, otherwise in state 0
+	// 11: last character was an escape, otherwise in state 1
+	// 12: last character was an escape, otherwise in state 2
+	// 13: last character was an escape, otherwise in state 3
+
+	int state=0;
+	int i=-1;
+	while (++i<listpart.length()){
+	    
+	    // Next Character, need both primitive and object representations.
+	    char c = listpart.charAt(i);
+	    Character C = c;
+
+	    // If this character was escaped, add it to the next field
+	    // and drop out of escape mode.
+	    if ( state > 9 ){
+		next.append(c);
+		state = state - 10;
+		continue;
+
+	    } 
+	    // Not within any list value.
+	    else if ( state == 0 ){
+
+		// Skip white space between tokens.
+		if ( Character.isWhitespace(c) ) {
+		    continue;
+
+		} 
+
+		// Starting a new item with a quote, strip the quote.
+		else if ( C.compareTo(quote) == 0 ){
+		    state = 2;
+		    continue;
+
+		} 
+
+		// Starting a new item with a escape.
+		else if ( C.compareTo(slash) == 0 ){
+		    next.append(c);
+		    state = 11;
+		    continue;
+
+		} 
+
+		// Consecutive commas add an empty item to the list.
+		// State stays at 0.
+		else if ( C.compareTo(comma) == 0 && next.length() == 0 ){
+		    Values.add("");
+		    continue;
+
+		} 
+		// Starting a new item with neither escape nor quote.
+		else {
+		    next.append(c);
+		    state = 1;
+		    continue;
+		}
+
+	    } 
+
+	    // In the middle of a field not started by a quote.
+	    else if ( state == 1 ) {
+
+		// End of item is marked by white space
+		if ( Character.isWhitespace(c) ){
+		    state = 3;
+		    continue;
+		    
+		} 
+
+		// End of item marked by comma without preceeding whitespace.
+		else if ( C.compareTo(comma) == 0 ){
+		    Values.add(next.toString());
+		    next = new StringBuffer();
+		    state = 0;
+		    continue;
+		    
+		} 
+
+		// Do not allow an unescaped quote in mid word ...
+		else if ( C.compareTo(quote) == 0 ){
+		    throw new ToyConfigException( "Unexpected \" character in record: " + record );
+		} 
+
+		// Next character is to be escaped.
+		else if ( C.compareTo(slash) == 0 ) {
+		    next.append(c);
+		    state = 11;
+		    continue;
+
+		} 
+
+		// Not a special character, just add it to the string.
+		else{
+		    next.append(c);
+		    continue;
+		}
+
+	    } 
+
+	    // In the middle of a field started by a quote.
+	    else if ( state == 2 ){
+
+
+		// Terminal quote marks the end of an item.
+		if ( C.compareTo(quote) == 0 ){
+		    state = 3;
+
+		} 
+
+		// Escape the next character.
+		else if ( C.compareTo(slash) == 0 ) {
+		    next.append(c);
+		    state = 12;
+		    continue;
+
+		} 
+
+		// Add character. Comma and white space are normal characters in this case.
+		else {
+		    next.append(c);
+		    continue;
+		}
+
+	    } 
+
+	    // Finished with a field but have not yet seen a comma or end of record.
+	    else if ( state == 3 ){
+
+		// Skip white space between fields.
+		if ( Character.isWhitespace(c) ) {
+		    continue;
+
+		} 
+		// Add the previous item to the output list.
+		else if ( C.compareTo(comma) == 0 ) {
+		    Values.add(next.toString());
+		    next = new StringBuffer();
+		    state = 0;
+		    continue;
+		}
+	    } 
+
+	    // On a legal record there is no way to reach this else.
+	    else{
+		throw new ToyConfigException("Confused state while parsing record: " + record );
+
+	    }// end main branch, starting with: "if ( state > 9 )"
+
+	} // end loop over characters
+
+
+	// Record ended with an unterminated quote
+	if ( state == 2 || state == 12 ){
+	    throw new ToyConfigException("Unclosed quotes in this record: " + record );
+
+	// Treat an end of record as the trailing delimiter for the last field.
+	} else if ( state == 1 || state == 3 ){
+	    Values.add(next.toString());
+
+	// Last non-blank item was a non-quoted comma.
+	// So add a blank item to the list.
+	} else if ( isList && state ==0 ){
+	    if ( Values.size() > 0 ){
+		Values.add("");
+	    }
+	} 
+
+	// On a legal record there is no way to reach this else.
+	else{
+	    throw new ToyConfigException("Confused final state while parsing: " + record );
+	}
+
+	// For a scalar record, make sure that there was exactly 1 item.
+	if ( !isList ){
+	    if( Values.size() != 1 ){
+		throw new ToyConfigException("Too many values for a scalar type  record: " + record );
+	    }
+	}
+
+    }
+ 
+
+    /**
+     * 
+     * Check that the type of the current record matches the specified type.
+     *
+     */
+    private void CheckType( String s) throws ToyConfigException{
+	if ( Type.compareTo(s) !=0 ){
+	    throw new ToyConfigException("Requested type (" + s + ") does not match record: "
+				      + record );
+	}
+    }
+
+    /**
+     * 
+     * Check that the type of the current record is one of the List types.
+     *
+     */
+    private void AnyList() throws ToyConfigException{
+	if ( Type.substring(0,5).compareTo("List<") != 0 ){
+	    throw new ToyConfigException("Requested a list for a non-list record: "
+				      + record );
+	}
+    }
+
+
+
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util
VTUtil.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/VTUtil.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/VTUtil.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,166 @@
+package org.hps.recon.tracking.kalman.util;
+
+import hep.physics.vec.BasicHep3Vector;
+import hep.physics.vec.Hep3Vector;
+
+import org.lcsim.recon.tracking.trfbase.ETrack;
+import org.lcsim.recon.tracking.trfbase.Surface;
+import org.lcsim.recon.tracking.trfbase.VTrack;
+import org.lcsim.recon.tracking.trfcyl.SurfCylinder;
+import org.lcsim.recon.tracking.trfzp.SurfZPlane;
+
+/**
+ * 
+ * Compute various derived quantities from a VTrack or an ETrack.
+ *
+ *@author $Author: jeremy $
+ *@version $Id: VTUtil.java,v 1.1 2011/07/28 18:28:19 jeremy Exp $
+ *
+ * Date $Date: 2011/07/28 18:28:19 $
+ *
+ */
+
+
+public class VTUtil {
+
+    // Matches the precision in the TRF eloss code.
+    private double m_pi   = 0.13957;
+
+    public VTUtil( VTrack v){
+	this.v    = v;
+	Surface s = v.surface();
+
+	if ( s.pureType().equals( SurfCylinder.staticType()) ){
+	    DoCylinder();
+	} else if ( s.pureType().equals( SurfZPlane.staticType()) ){
+	    DoZPlane();
+	}
+	else{
+	    DoNull();
+	}
+    }
+
+    public VTUtil( ETrack e){
+	v = new VTrack( e.surface(), e.vector() );
+	Surface s = v.surface();
+
+	if ( s.pureType().equals( SurfCylinder.staticType()) ){
+	    DoCylinder();
+	} else if ( s.pureType().equals( SurfZPlane.staticType()) ){
+	    DoZPlane();
+	}
+	else{
+	    DoNull();
+	}
+    }
+
+
+    public double momentum(){ 
+	return p;
+    }
+
+    public double p(){ 
+	return p;
+    }
+
+    public double e(){
+	return e(m_pi);
+    }
+
+    public double e(double m){
+	return Math.sqrt( p()*p() +m*m );
+    }
+
+    public Hep3Vector asHep3Vector(){
+	double px = pt*Math.cos(phi);
+	double py = pt*Math.sin(phi);
+	double pz = p *costh;
+	return new BasicHep3Vector(px,py,pz);
+    }
+
+    public double costh(){
+	return costh;
+    }
+
+    public double sinth(){
+	return sinth;
+    }
+    public double q(){
+	return q;
+    }
+
+    public double z(){
+	return z;
+    }
+
+    public double r(){
+	return r;
+    }
+
+    private VTrack v = null;
+    private double costh;
+    private double sinth;
+    private double cotth;
+    private double pt;
+    private double p;
+    private double phi;
+    private double phi0;
+    private double q;
+
+    private double r;
+    private double z;
+
+    private void DoCylinder(){
+	    cotth = v.vector(SurfCylinder.ITLM);
+	    sinth = 1./Math.sqrt( 1. + cotth*cotth );
+	    costh = cotth*sinth;
+	    pt    = 1./Math.abs(v.vector(SurfCylinder.IQPT));
+	    p     = pt/sinth;
+	    phi   = v.vector(SurfCylinder.IPHI)+v.vector(SurfCylinder.IALF);
+	    q = Math.signum(v.vector(SurfCylinder.IQPT));
+
+	    SurfCylinder cyl = (SurfCylinder) v.surface();
+	    r = cyl.radius();
+	    z = v.vector(SurfCylinder.IZ);
+    }
+
+    private void DoNull(){
+	cotth = 0.;
+	costh = 0.;
+	sinth = 0.;
+	pt    = 0.;
+	p     = 0.;
+	phi   = 0.;
+	q     = 1.;
+	r     = 0.;
+	z     = 0.;
+
+    }
+
+    private void DoZPlane(){
+	double xpr = v.vector(SurfZPlane.IDXDZ);
+	double ypr = v.vector(SurfZPlane.IDYDZ);
+
+	costh = 1./Math.sqrt( 1. + xpr*xpr + ypr*ypr);
+	SurfZPlane sz = (SurfZPlane) v.surface();
+
+	// This is a hack and needs to be done more generally.
+	if ( sz.z() <  0) costh = -costh;
+
+	sinth = Math.sqrt( 1. - costh*costh);
+	cotth = costh/sinth;
+	p     = Math.abs(1./v.vector(SurfZPlane.IQP));
+	pt    = p*sinth;
+	phi   = Math.atan2( ypr, xpr );
+
+	q = Math.signum(v.vector(SurfZPlane.IQP));
+
+	double x = v.vector(SurfZPlane.IX);
+	double y = v.vector(SurfZPlane.IY);
+	r = Math.sqrt( x*x + y*y );
+	z = ((SurfZPlane)v.surface()).z();
+
+    }
+
+
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util
cyl_int.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/cyl_int.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/cyl_int.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,125 @@
+package org.hps.recon.tracking.kalman.util;
+
+
+/**
+ * 
+ * Find the interesection of a track, specified by the CLEO paramters
+ * with the a cylinder of radius r, centered on the origin.
+ *
+ *@author $Author: jeremy $
+ *@version $Id: cyl_int.java,v 1.1 2011/07/28 18:28:19 jeremy Exp $
+ *
+ * Date $Date: 2011/07/28 18:28:19 $
+ *
+ */
+
+public class cyl_int{
+
+    public double x;
+    public double y;
+    public double psi;
+
+    public double k;
+    public double d0;
+    public double phi;
+    public double z;
+    public double t;
+
+    public double q;
+    public double rho;
+
+    public cyl_int( double k, 
+		    double d0, 
+		    double phi, 
+		    double z, 
+		    double t, 
+		    double r
+		    ){
+
+	this.k   = k;
+	this.d0  = d0;
+	this.phi = phi;
+	this.z   = z;
+	this.t   = t;
+
+	// Some other quantities derived from the track parameters.
+
+	q   =  (k > 0 ) ? 1.0 : -1.0;
+	rho = Math.abs( 0.5/k );
+
+
+	double u0   =  Math.cos(phi);
+	double v0   =  Math.sin(phi);
+	double x0   = -d0 * v0;
+	double y0   =  d0 * u0;
+
+	double x0t  = x0-q*rho*v0;
+	double y0t  = y0+q*rho*u0;
+
+	double dpsi = Math.atan2(-y0t,x0t);
+	
+	double sang = (r*r-x0t*x0t-y0t*y0t-rho*rho)/
+	    (2.*q*rho*Math.sqrt(x0t*x0t+y0t*y0t));
+	if ( sang > 1.0 ){
+	    sang = 1.0; 
+	}else if ( sang < -1.0 ){
+	    sang = -1.0;
+	}
+
+	double psi1=(Math.asin(sang)-phi-dpsi);
+	double psi2=(Math.PI-Math.asin(sang)-phi-dpsi);
+
+	double twopi = 2.*Math.PI;
+
+	// Put angles in the correct quadrant.
+	if (psi1 > twopi){
+	    psi1 -= twopi;
+	}
+	if (psi1 < 0.0) {
+	    psi1 += twopi;
+	}
+	if (psi1 < 0.0) {
+	    psi1 += twopi;
+	}
+	
+	if (psi2 > twopi) {
+	    psi2 -= twopi;
+	}
+	if (psi2 < 0.0) {
+	    psi2 += twopi;
+	}
+	if (psi2 < 0.0) {
+	    psi2 += twopi;
+	}
+
+	psi = ( psi2 < psi1) ? psi2 : psi1;
+	
+	x = x0t + q*rho*Math.sin(phi+q*psi);
+	y = y0t - q*rho*Math.cos(phi+q*psi);
+    }
+    
+    public double getX(){
+	return x;
+    }
+
+    public double getY(){
+	return y;
+    }
+
+    public double getZ(){
+	double cz = t / Math.sqrt( 1. + t*t );
+	return z + rho*psi*t;
+    }
+
+
+    public double getPsi(){
+	return psi;
+    }
+
+
+}
+
+
+
+
+

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util
toTRF.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/toTRF.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/toTRF.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,104 @@
+package org.hps.recon.tracking.kalman.util;
+
+import org.lcsim.recon.tracking.trfbase.TrackVector;
+import org.lcsim.recon.tracking.trfbase.VTrack;
+import org.lcsim.recon.tracking.trfcyl.SurfCylinder;
+import org.lcsim.recon.tracking.trfdca.SurfDCA;
+import org.lcsim.recon.tracking.trfutil.TRFMath;
+import org.lcsim.recon.tracking.trfzp.SurfZPlane;
+
+/**
+ * 
+ * Utility routine to convert RKTracks into TRF VTracks.
+ *
+ *@author $Author: jeremy $
+ *@version $Id: toTRF.java,v 1.1 2011/07/28 18:28:19 jeremy Exp $
+ *
+ * Date $Date: 2011/07/28 18:28:19 $
+ *
+ */
+
+
+public class toTRF {
+
+    // TRF wants distances in cm, not mm.
+    private double mmTocm = 0.1;
+
+    private RKTrack t;
+
+    public toTRF( RKTrack t ){
+	this.t = t;
+    }
+
+    public VTrack atDcaZaxis(){
+
+	// Opposite sign convention.
+	double r_signed = -t.d0();
+
+	TrackVector tv  = new TrackVector();
+	tv.set(0, r_signed * mmTocm );
+	tv.set(1, t.z0()   * mmTocm );
+	tv.set(2, t.phi0()          );
+	tv.set(3, t.cotth()         );
+	tv.set(4, t.q()/t.pt()      );
+	SurfDCA s = new SurfDCA( 0., 0. );
+	VTrack vt = new VTrack(s, tv);
+	return vt;
+	
+    }
+
+    public VTrack atCyl( double r){
+
+	cyl_int c = new cyl_int( t.cu(), t.d0(), t.phi0(), t.z0(), t.cotth(), r );
+
+	double phi_pos = Math.atan2(c.getY(),c.getX());
+	double phi_dir = TRFMath.fmod2(t.phi0() + t.charge()*c.getPsi(),TRFMath.TWOPI);
+	double alpha   = TRFMath.fmod2(phi_dir-phi_pos,TRFMath.TWOPI);
+
+	TrackVector tv  = new TrackVector();
+	tv.set(0, phi_pos           );
+	tv.set(1, c.getZ() * mmTocm );
+	tv.set(2, alpha             );
+	tv.set(3, t.cotth()         );
+	tv.set(4, t.q()/t.pt()      );
+
+	SurfCylinder s = new SurfCylinder( r*mmTocm );
+	VTrack vt = new VTrack(s, tv);
+	return vt;
+    }
+
+    public VTrack atZPlane( double z){
+
+	zplane_int zpi = new zplane_int ( t.cu(), t.d0(), t.phi0(), t.z0(), t.cotth(), z );
+	
+	double phi = t.phi0() + t.q()*zpi.getPsi();
+	double dxdz = Math.cos(phi)/t.cotth();
+	double dydz = Math.sin(phi)/t.cotth();
+
+	TrackVector tv  = new TrackVector();
+	tv.set(0, zpi.getX()*mmTocm );
+	tv.set(1, zpi.getY()*mmTocm );
+	tv.set(2, dxdz              );
+	tv.set(3, dydz              );
+	tv.set(4, t.q()/t.p()       );
+
+	SurfZPlane s = new SurfZPlane( z*mmTocm );
+	VTrack vt = new VTrack(s, tv);
+	if ( t.cz() >= 0. ){
+	    vt.setForward();
+	}else{
+	    vt.setBackward();
+	}
+
+	return vt;
+
+    }
+
+    // Path length corresponding to one half of an arc.
+    public double halfarc(){
+	return Math.PI*t.rho()/t.sz()*mmTocm;
+    }
+
+
+    
+}

java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util
zplane_int.java added at 372
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/zplane_int.java	                        (rev 0)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/kalman/util/zplane_int.java	2014-03-26 04:31:31 UTC (rev 372)
@@ -0,0 +1,87 @@
+package org.hps.recon.tracking.kalman.util;
+
+
+/**
+ * 
+ * Find the interesection of a track, specified by the cleo paramters 
+ * with a plane normal to the z axis and at the specfied z.
+ *
+ *@author $Author: jeremy $
+ *@version $Id: zplane_int.java,v 1.1 2011/07/28 18:28:19 jeremy Exp $
+ *
+ * Date $Date: 2011/07/28 18:28:19 $
+ *
+ */
+
+
+public class zplane_int{
+
+    public double x;
+    public double y;
+    public double z;
+    public double psi;
+
+    // Track parameters referenced to PCA (0,0,0);
+    public double k;
+    public double d0;
+    public double phi;
+    public double z0;
+    public double t;
+
+    public double q;
+    public double rho;
+
+    public zplane_int( double k,
+		       double d0,
+		       double phi,
+		       double z0,
+		       double t,
+		       double zp
+		       ){
+
+	this.k   = k;
+	this.d0  = d0;
+	this.phi = phi;
+	this.z0  = z0;
+	this.t   = t;
+
+	// Some other quantities derived from the track parameters.
+
+	q   =  (k > 0 ) ? 1.0 : -1.0;
+	rho = Math.abs( 0.5/k );
+
+	double rhopsi = (zp-z0)/t;
+	psi = rhopsi/rho;
+
+	double u0  =  Math.cos(phi);
+	double v0  =  Math.sin(phi);
+	double x0  = -d0 * v0;
+	double y0  =  d0 * u0;
+
+	double xc = x0-q*rho*v0;
+	double yc = y0+q*rho*u0;
+	
+	x = xc + q*rho*Math.sin(phi+q*psi);
+	y = yc - q*rho*Math.cos(phi+q*psi);
+	z = zp;
+    }
+    
+    public double getX(){
+	return x;
+    }
+
+    public double getY(){
+	return y;
+    }
+
+    public double getZ(){
+	return z;
+    }
+
+
+    public double getPsi(){
+	return psi;
+    }
+
+
+}
SVNspam 0.1