Commit in java/sandbox/tracking on MAIN
pom.xml+61added 348
src/main/java/org/hps/recon/tracking/AlignmentParameters.java+560added 348
                                    /AxialTrackReconDriver.java+436added 348
                                    /DataTrackerFakeHitDriver.java+1030added 348
                                    /DataTrackerHitDriver.java+231added 348
                                    /DumbShaperFit.java+62added 348
                                    /EcalTrackMatch.java+142added 348
                                    /EventQuality.java+114added 348
                                    /FindableTrack.java+343added 348
                                    /FpgaData.java+197added 348
                                    /HPSClusteringAlgorithm.java+25added 348
                                    /HPSFittedRawTrackerHit.java+37added 348
                                    /HPSNearestNeighborRMS.java+258added 348
                                    /HPSRawTrackerHitFitterDriver.java+116added 348
                                    /HPSSVTData.java+307added 348
                                    /HPSShapeFitParameters.java+144added 348
                                    /HPSShaperAnalyticFitAlgorithm.java+106added 348
                                    /HPSShaperFitAlgorithm.java+18added 348
                                    /HPSStripMaker.java+353added 348
                                    /HPSTrack.java+524added 348
                                    /HPSTransformations.java+66added 348
                                    /HelicalTrackHitDriver.java+571added 348
                                    /HelixConverter.java+142added 348
                                    /HelixFitter.java+29added 348
                                    /LCIOTrackAnalysis.java+169added 348
                                    /MaterialManager.java+43added 348
                                    /MaterialSupervisor.java+421added 348
                                    /MultipleScattering.java+455added 348
                                    /NoiselessReadoutChip.java+318added 348
                                    /RunAlignment.java+96added 348
                                    /SVTBadChannelFilterDriver.java+45added 348
                                    /SVTRawTrackerHitThresholdDriver.java+80added 348
                                    /SeedTracker.java+76added 348
                                    /SimpleSvtReadout.java+425added 348
                                    /SimpleTrackerDigiDriver.java+70added 348
                                    /StraightLineTrack.java+193added 348
                                    /TrackAnalysis.java+298added 348
                                    /TrackUtils.java+735added 348
                                    /TrackerDigiDriver.java+299added 348
                                    /TrackerHitUtils.java+280added 348
                                    /TrackerReconDriver.java+202added 348
                                    /WTrack.java+338added 348
src/main/java/org/hps/recon/tracking/apv25/Apv25AnalogData.java+123added 348
                                          /Apv25DigitalData.java+92added 348
                                          /Apv25Full.java+290added 348
                                          /DataProcessingModule.java+117added 348
                                          /HPSAPV25.java+353added 348
                                          /HPSDataProcessingModule.java+398added 348
                                          /HPSRTM.java+127added 348
                                          /HPSSVTDataBuffer.java+158added 348
                                          /HPSSiSensorReadout.java+474added 348
                                          /RearTransitionModule.java+135added 348
                                          /SvtHalfModule.java+59added 348
                                          /SvtReadout.java+318added 348
                                          /TestRunDataProcessingModule.java+134added 348
src/main/java/org/hps/recon/tracking/gbl/GBLEventData.java+89added 348
                                        /GBLFileIO.java+255added 348
                                        /GBLOutput.java+943added 348
                                        /GBLOutputDriver.java+199added 348
                                        /GBLStripClusterData.java+307added 348
                                        /GBLTrackData.java+108added 348
                                        /TruthResiduals.java+349added 348
+15443
62 added files
First compiling version of new tracking code module in the sandbox.

java/sandbox/tracking
pom.xml added at 348
--- java/sandbox/tracking/pom.xml	                        (rev 0)
+++ java/sandbox/tracking/pom.xml	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>hps-tracking</artifactId>
+    <name>hps-tracking</name>
+    <description>HPS tracking reconstruction module</description>
+    
+    <parent>
+        <groupId>org.hps</groupId>
+        <artifactId>hps-parent</artifactId>
+        <relativePath>../parent/pom.xml</relativePath>
+        <version>3.0.2-SNAPSHOT</version>
+    </parent>
+    
+    <scm>
+        <url>http://java.freehep.org/svn/repos/hps/list/java/trunk/tracking/</url>
+        <connection>scm:svn:svn://svn.freehep.org/hps/java/trunk/tracking/</connection>
+        <developerConnection>scm:svn:svn://svn.freehep.org/hps/java/trunk/tracking/</developerConnection>
+    </scm>
+    
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <excludes>
+                        <exclude>org/lcsim/hps/recon/tracking/TruthResidualTest.java</exclude>
+                    </excludes>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.lcsim</groupId>
+            <artifactId>lcsim-distribution</artifactId>
+            <version>${lcsimVersion}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.hps</groupId>
+            <artifactId>hps-conditions</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.hps</groupId>
+            <artifactId>hps-util</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.hps</groupId>
+            <artifactId>hps-ecal-readout-sim</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-math3</artifactId>
+            <version>3.2</version>
+        </dependency>
+    </dependencies>
+    
+</project>

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
AlignmentParameters.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/AlignmentParameters.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/AlignmentParameters.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,560 @@
+package org.hps.recon.tracking;
+
+import hep.physics.matrix.BasicMatrix;
+import hep.physics.matrix.MatrixOp;
+import hep.physics.vec.BasicHep3Matrix;
+import hep.physics.vec.BasicHep3Vector;
+import hep.physics.vec.Hep3Matrix;
+import hep.physics.vec.Hep3Vector;
+import hep.physics.vec.VecOp;
+
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.lcsim.detector.IDetectorElement;
+import org.lcsim.detector.ITransform3D;
+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.Track;
+import org.lcsim.event.TrackerHit;
+import org.lcsim.fit.helicaltrack.HelicalTrackCross;
+import org.lcsim.fit.helicaltrack.HelicalTrackFit;
+import org.lcsim.fit.helicaltrack.HelicalTrackHit;
+import org.lcsim.fit.helicaltrack.HelicalTrackStrip;
+import org.lcsim.fit.helicaltrack.HelixUtils;
+import org.lcsim.fit.helicaltrack.MultipleScatter;
+import org.lcsim.fit.helicaltrack.TrackDirection;
+import org.lcsim.recon.tracking.seedtracker.SeedCandidate;
+import org.lcsim.recon.tracking.seedtracker.SeedTrack;
+
+/**
+ * Class to calculate and print the residuals and derivatives
+ * of the alignment parameters...used as input for MillePede
+ * Notation follows the MillePede manual:
+ * http://www.desy.de/~blobel/Mptwo.pdf
+ *
+ * the track is measured in the HelicalTrackFit frame
+ * and residuals are in the sensor frame (u,v,w)
+ *
+ * ordering of track parameters is
+ *    double d0 = _trk.dca();
+ *    double z0 = _trk.z0();
+ *    double slope = _trk.slope();
+ *    double phi0 = _trk.phi0();
+ *    double R = _trk.R();
+ *
+ * @author mgraham
+ */
+public class AlignmentParameters {
+
+    private int _nlc = 5;  //the five track parameters
+    private int _ngl = 1; //delta(u) and delta(gamma) for each plane
+    private BasicMatrix _dfdq;
+    private BasicMatrix _dfdp;
+    private HelicalTrackFit _trk;
+    private double[] _resid = new double[3];
+    private double[] _error = new double[3];
+    private int[] _globalLabel = new int[1];
+    FileWriter fWriter;
+    PrintWriter pWriter;
+    Set<SiSensor> _process_sensors = new HashSet<SiSensor>();
+    boolean _DEBUG = false;
+    double smax = 1e3;
+
+    public AlignmentParameters(String outfile) {
+        try {
+//open things up
+            fWriter = new FileWriter(outfile);
+            pWriter = new PrintWriter(fWriter);
+        } catch (IOException ex) {
+            Logger.getLogger(RunAlignment.class.getName()).log(Level.SEVERE, null, ex);
+        }
+
+    }
+
+    public void PrintResidualsAndDerivatives(Track track) {
+        SeedTrack st = (SeedTrack) track;
+        SeedCandidate seed = st.getSeedCandidate();
+        Map<HelicalTrackHit, MultipleScatter> msmap = seed.getMSMap();
+        _trk = seed.getHelix();
+        List<TrackerHit> hitsOnTrack = track.getTrackerHits();
+        for (TrackerHit hit : hitsOnTrack) {
+            HelicalTrackHit htc = (HelicalTrackHit) hit;
+            double msdrphi = msmap.get(htc).drphi();
+            double msdz = msmap.get(htc).dz();
+            double sHit = _trk.PathMap().get(htc);
+            HelicalTrackCross cross = (HelicalTrackCross) htc;
+            List<HelicalTrackStrip> clusterlist = cross.getStrips();
+            TrackDirection trkdir = HelixUtils.CalculateTrackDirection(_trk, sHit);
+            cross.setTrackDirection(trkdir, _trk.covariance());
+            for (HelicalTrackStrip cl : clusterlist) {
+                CalculateLocalDerivatives(cl);
+                CalculateGlobalDerivatives(cl);
+                CalculateResidual(cl, msdrphi, msdz);
+//                CalculateResidual(cl, 0,0);
+                PrintStripResiduals(cl);
+            }
+        }
+        AddTarget(0.1, 0.02);
+    }
+
+    private void CalculateLocalDerivatives(HelicalTrackStrip strip) {
+        //get track parameters.
+        double d0 = _trk.dca();
+        double z0 = _trk.z0();
+        double slope = _trk.slope();
+        double phi0 = _trk.phi0();
+        double R = _trk.R();
+//strip origin is defined in the tracking coordinate system (x=beamline)
+        double xint = strip.origin().x();
+        double s = HelixUtils.PathToXPlane(_trk, xint, smax, _nlc).get(0);
+        double phi = s / R - phi0;
+        double[][] dfdq = new double[3][5];
+        //dx/dq
+        //these are wrong for X, but for now it doesn't matter
+        dfdq[0][0] = Math.sin(phi0);
+        dfdq[0][1] = 0;
+        dfdq[0][2] = 0;
+        dfdq[0][3] = d0 * Math.cos(phi0) + R * Math.sin(phi0) - s * Math.cos(phi0);
+        dfdq[0][4] = (phi - phi0) * Math.cos(phi0);
+        double[] mydydq = dydq(R, d0, phi0, xint, s);
+        double[] mydzdq = dzdq(R, d0, phi0, xint, slope, s);
+        for (int i = 0; i < 5; i++) {
+            dfdq[1][i] = mydydq[i];
+            dfdq[2][i] = mydzdq[i];
+        }
+
+        BasicMatrix dfdqGlobal = FillMatrix(dfdq, 3, 5);
+        Hep3Matrix trkToStrip = getTrackToStripRotation(strip);
+        _dfdq = (BasicMatrix) MatrixOp.mult(trkToStrip, dfdqGlobal);
+
+        if (_DEBUG) {
+            double[] trackpars = {d0, z0, slope, phi0, R, s, xint};
+            System.out.println("Strip Origin: ");
+            System.out.println(strip.origin());
+            System.out.println("trkToStrip Rotation:");
+            System.out.println(trkToStrip.toString());
+            printDerivatives(trackpars, dfdq);
+        }
+    }
+
+    private void CalculateGlobalDerivatives(HelicalTrackStrip strip) {
+        //1st index = alignment parameter (only u so far)
+        //2nd index = residual coordinate (on du so far)
+
+        double[][] dfdpLab = new double[3][1];
+        dfdpLab[0][0] = 0; //df/dx
+        dfdpLab[1][0] = 0; //df/dy
+        dfdpLab[2][0] = 1; //df/dz
+        BasicMatrix _dfdpLab = FillMatrix(dfdpLab, 3, 1);
+        Hep3Matrix trkToStrip = getTrackToStripRotation(strip);
+        _dfdp = (BasicMatrix) MatrixOp.mult(trkToStrip, _dfdpLab);
+        if (_DEBUG) {
+            System.out.printf("dfdz = %5.5f     %5.5f   %5.5f\n", _dfdp.e(0, 0), _dfdp.e(1, 0), _dfdp.e(2, 0));
+        }
+        _globalLabel[0] = GetIdentifier(strip);
+//         _globalLabel[0] = GetIdentifierModule(strip);
+
+    }
+
+    private void CalculateResidual(HelicalTrackStrip strip, double msdrdphi, double msdz) {
+
+        Hep3Vector u = strip.u();
+        Hep3Vector v = strip.v();
+        Hep3Vector w = strip.w();
+        Hep3Vector corigin = strip.origin();
+        double phi0 = _trk.phi0();
+        double R = _trk.R();
+        double xint = strip.origin().x();
+        double s = HelixUtils.PathToXPlane(_trk, xint, smax, _nlc).get(0);
+        double phi = s / R - phi0;
+        Hep3Vector trkpos = HelixUtils.PointOnHelix(_trk, s);
+
+        //System.out.println("trkpos = "+trkpos.toString());
+        //System.out.println("origin = "+corigin.toString());
+
+        Hep3Vector mserr = new BasicHep3Vector(msdrdphi * Math.sin(phi), msdrdphi * Math.sin(phi), msdz);
+        Hep3Vector vdiffTrk = VecOp.sub(trkpos, corigin);
+        Hep3Matrix trkToStrip = getTrackToStripRotation(strip);
+        Hep3Vector vdiff = VecOp.mult(trkToStrip, vdiffTrk);
+        double umc = vdiff.x();
+        double vmc = vdiff.y();
+        double wmc = vdiff.z();
+        double umeas = strip.umeas();
+        double uError = strip.du();
+        double msuError = VecOp.dot(mserr, u);
+        double vmeas = 0;
+        double vError = (strip.vmax() - strip.vmin()) / Math.sqrt(12);
+        double wmeas = 0;
+        double wError = 0.001;
+        //System.out.println("strip error="+uError+"; ms error ="+msuError);
+        _resid[0] = umeas - umc;
+        _error[0] = Math.sqrt(uError * uError + msuError * msuError);
+        _resid[1] = vmeas - vmc;
+        _error[1] = vError;
+        _resid[2] = wmeas - wmc;
+        _error[2] = wError;
+        if (_DEBUG) {
+            System.out.println("Strip Origin: ");
+            System.out.println(corigin.toString());
+            System.out.println("Position on Track:");
+            System.out.println(trkpos.toString());
+            System.out.println("vdiff :");
+            System.out.println(vdiff.toString());
+            System.out.println("u :");
+            System.out.println(u.toString());
+            System.out.println("umeas = " + umeas + "; umc = " + umc);
+            System.out.println("udiff = " + _resid[0] + " +/- " + _error[0]);
+
+        }
+
+    }
+
+    public double[] getResidual(Track track, int layer) {
+        double[] res = new double[7];
+        SeedTrack st = (SeedTrack) track;
+        SeedCandidate seed = st.getSeedCandidate();
+        Map<HelicalTrackHit, MultipleScatter> msmap = seed.getMSMap();
+        _trk = seed.getHelix();
+        List<TrackerHit> hitsOnTrack = track.getTrackerHits();
+        for (TrackerHit hit : hitsOnTrack) {
+            HelicalTrackHit htc = (HelicalTrackHit) hit;
+            double sHit = _trk.PathMap().get(htc);
+            HelicalTrackCross cross = (HelicalTrackCross) htc;
+            List<HelicalTrackStrip> clusterlist = cross.getStrips();
+            TrackDirection trkdir = HelixUtils.CalculateTrackDirection(_trk, sHit);
+            double msdrphi = msmap.get(htc).drphi();
+            double msdz = msmap.get(htc).dz();
+            cross.setTrackDirection(trkdir, _trk.covariance());
+            for (HelicalTrackStrip cl : clusterlist) {
+                if (cl.layer() == layer) {
+                    CalculateResidual(cl, msdrphi, msdz);
+                    res[0] = _resid[0];
+                    res[1] = _resid[1];
+                    res[2] = _resid[2];
+                    res[3] = _error[0];
+                    res[4] = _error[1];
+                    res[5] = _error[2];
+                    res[6] = layer;
+                    if(hit.getPosition()[2]<0)res[6]=layer+10;
+                }
+            }
+        }
+        return res;
+
+    }
+
+    public void AddTarget(double beamdy, double beamdz) {
+        double[][] dfdp = new double[3][1];
+        double d0 = _trk.dca();
+        double z0 = _trk.z0();
+        double slope = _trk.slope();
+        double phi0 = _trk.phi0();
+        double R = _trk.R();
+        double xint = 0; //target
+        double s = HelixUtils.PathToXPlane(_trk, xint, smax, _nlc).get(0);
+        Hep3Vector ptAtTarget = HelixUtils.PointOnHelix(_trk, s);
+        double[] mydydq = dydq(R, d0, phi0, xint, s);
+        double[] mydzdq = dzdq(R, d0, phi0, xint, slope, s);
+        _resid[0] = ptAtTarget.z();
+        _resid[1] = ptAtTarget.y();
+        _resid[2] = ptAtTarget.x();
+        _error[0] = beamdz;
+        _error[1] = beamdy;
+        _error[2] = 666;
+        dfdp[0][0] = 1;
+        dfdp[1][0] = 0;
+        dfdp[2][0] = 0;
+        _dfdp = FillMatrix(dfdp, 3, 1);
+        _globalLabel[0] = 666;
+        pWriter.printf("%4d\n", 666);
+        pWriter.printf("%5.5e %5.5e %5.5e\n", _resid[0], _resid[1], _resid[2]);
+        pWriter.printf("%5.5e %5.5e %5.5e\n", _error[0], _error[1], _error[2]);
+        for (int i = 0; i < _nlc; i++) {
+            pWriter.printf("%5.5e %5.5e -1.0\n", mydzdq[i], mydydq[i]);
+        }
+        for (int j = 0; j < _ngl; j++) {
+            pWriter.printf("%5.5e %5.5e %5.5e   %5d\n", _dfdp.e(0, j), _dfdp.e(1, j), _dfdp.e(2, j), _globalLabel[j]);
+        }
+
+    }
+
+    private void PrintStripResiduals(HelicalTrackStrip strip) {
+        if (_DEBUG) {
+            System.out.printf("Strip Layer =  %4d\n", strip.layer());
+            System.out.printf("Residuals (u,v,w) : %5.5e %5.5e %5.5e\n", _resid[0], _resid[1], _resid[2]);
+            System.out.printf("Errors (u,v,w)    : %5.5e %5.5e %5.5e\n", _error[0], _error[1], _error[2]);
+            String[] q = {"d0", "z0", "slope", "phi0", "R"};
+            System.out.println("track parameter derivatives");
+            for (int i = 0; i < _nlc; i++) {
+                System.out.printf("%s     %5.5e %5.5e %5.5e\n", q[i], _dfdq.e(0, i), _dfdq.e(1, i), _dfdq.e(2, i));
+            }
+            String[] p = {"u-displacement"};
+            System.out.println("global parameter derivatives");
+            for (int j = 0; j < _ngl; j++) {
+                System.out.printf("%s  %5.5e %5.5e %5.5e   %5d\n", p[j], _dfdp.e(0, j), _dfdp.e(1, j), _dfdp.e(2, j), _globalLabel[j]);
+            }
+
+        }
+        pWriter.printf("%4d\n", strip.layer());
+        pWriter.printf("%5.5e %5.5e %5.5e\n", _resid[0], _resid[1], _resid[2]);
+        pWriter.printf("%5.5e %5.5e %5.5e\n", _error[0], _error[1], _error[2]);
+        for (int i = 0; i < _nlc; i++) {
+            pWriter.printf("%5.5e %5.5e %5.5e\n", _dfdq.e(0, i), _dfdq.e(1, i), _dfdq.e(2, i));
+        }
+        for (int j = 0; j < _ngl; j++) {
+            pWriter.printf("%5.5e %5.5e %5.5e   %5d\n", _dfdp.e(0, j), _dfdp.e(1, j), _dfdp.e(2, j), _globalLabel[j]);
+        }
+    }
+
+    private Hep3Matrix getTrackToStripRotation(HelicalTrackStrip strip) {
+        ITransform3D detToStrip = GetGlobalToLocal(strip);
+        Hep3Matrix detToStripMatrix = (BasicHep3Matrix) detToStrip.getRotation().getRotationMatrix();
+        Hep3Matrix detToTrackMatrix = (BasicHep3Matrix) HPSTransformations.getMatrix();
+
+        if (_DEBUG) {
+            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) {
+        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();
+    }
+
+    private int GetIdentifier(HelicalTrackStrip strip) {
+        RawTrackerHit rth = (RawTrackerHit) strip.rawhits().get(0);
+        IDetectorElement ide = rth.getDetectorElement();
+        SiSensor sensor = ide.findDescendants(SiSensor.class).get(0);
+        //       return rth.getIdentifierFieldValue(sensor.getName());
+        return sensor.getSensorID();  //individual sensor positions
+//        int sid=sensor.getSensorID();
+//        int global=1;
+//        if(sid>10)global=2;
+//        return global;  //return top/bottom plates
+    }
+
+    private int GetIdentifierModule(HelicalTrackStrip strip) {
+        RawTrackerHit rth = (RawTrackerHit) strip.rawhits().get(0);
+        IDetectorElement ide = rth.getDetectorElement();
+        SiSensor sensor = ide.findDescendants(SiSensor.class).get(0);
+        //       return rth.getIdentifierFieldValue(sensor.getName());
+//        return sensor.getSensorID();  //individual sensor positions
+        int sid = sensor.getSensorID();
+        int gid = -1;
+        switch (sid) {
+            case 1:
+                gid = 1; break;
+            case 2:
+                gid = 1;break;
+            case 3:
+                gid = 2;break;
+            case 4:
+                gid = 2;break;
+            case 5:
+                gid = 3;break;
+            case 6:
+                gid = 3;break;
+            case 7:
+                gid = 4;break;
+            case 8:
+                gid = 4;break;
+            case 9:
+                gid = 5;break;
+            case 10:
+                gid = 5;break;
+            case 11:
+                gid = 11;break;
+            case 12:
+                gid = 11;break;
+            case 13:
+                gid = 12;break;
+            case 14:
+                gid = 12;break;
+            case 15:
+                gid = 13;break;
+            case 16:
+                gid = 13;break;
+            case 17:
+                gid = 14;break;
+            case 18:
+                gid = 14;break;
+            case 19:
+                gid = 15;break;
+            case 20:
+                gid = 15;break;
+        }
+
+        return gid;  //return top/bottom plates
+    }
+
+    private BasicMatrix FillMatrix(double[][] array, int nrow, int ncol) {
+        BasicMatrix retMat = new BasicMatrix(nrow, ncol);
+        for (int i = 0; i < nrow; i++) {
+            for (int j = 0; j < ncol; j++) {
+                retMat.setElement(i, j, array[i][j]);
+            }
+        }
+        return retMat;
+    }
+
+    public void closeFile() throws IOException {
+        pWriter.close();
+        fWriter.close();
+    }
+
+    private double dsdR(double R, double d0, double phi0, double xint) {
+        double sqrtTerm = Sqrt(R * R - Math.pow(((d0 - R) * Sin(phi0) + xint), 2));
+
+        double rsign = Math.signum(R);
+        double dsdr = (1 / sqrtTerm) * ((-rsign * xint) + (-rsign) * d0 * Sin(phi0)
+                + ArcTan(R * Cos(phi0), (-R) * Sin(phi0))
+                * sqrtTerm
+                - ArcTan(rsign * sqrtTerm, xint + (d0 - R) * Sin(phi0))
+                * sqrtTerm);
+
+
+        if (_DEBUG)
+            System.out.println("xint = " + xint + "; dsdr = " + dsdr);
+        return dsdr;
+
+    }
+
+    private double dsdphi(double R, double d0, double phi0, double xint) {
+        double sqrtTerm = Sqrt(R * R - Math.pow(((d0 - R) * Sin(phi0) + xint), 2));
+        double rsign = Math.signum(R);
+        double dsdphi = R * (sqrtTerm + rsign * d0 * Cos(phi0) - rsign * R * Cos(phi0)) / sqrtTerm;
+        if (_DEBUG)
+            System.out.println("xint = " + xint + "; dsdphi = " + dsdphi);
+        return dsdphi;
+    }
+
+    private double dsdd0(double R, double d0, double phi0, double xint) {
+        double sqrtTerm = Sqrt(R * R - Math.pow(((d0 - R) * Sin(phi0) + xint), 2));
+        double rsign = Math.signum(R);
+        double dsdd0 = rsign * (R * Sin(phi0)) / sqrtTerm;
+        if (_DEBUG)
+            System.out.println("xint = " + xint + "; dsdd0 = " + dsdd0);
+        return dsdd0;
+    }
+
+    private double[] dydq(double R, double d0, double phi0, double xint, double s) {
+        double[] dy = new double[5];
+//        dy[0] = Cos(phi0) + Cot(phi0 - s / R) * Csc(phi0 - s / R) * dsdd0(R, d0, phi0, xint);
+        dy[0] = Cos(phi0) - Sec(phi0 - s / R) * Tan(phi0 - s / R) * dsdd0(R, d0, phi0, xint);
+        dy[1] = 0;
+        dy[2] = 0;
+//        dy[3] = (-(d0 - R)) * Sin(phi0) - R * Cot(phi0 - s / R) * Csc(phi0 - s / R) * (1 - dsdphi(R, d0, phi0, xint) / R);
+        dy[3] = (-(d0 - R)) * Sin(phi0) + Sec(phi0 - s / R) * Tan(phi0 - s / R) * (R - dsdphi(R, d0, phi0, xint));
+        //        dy[4] = -Cos(phi0) + Csc(phi0 - s / R) - R * Cot(phi0 - s / R) * Csc(phi0 - s / R) * (s / (R * R) - dsdR(R, d0, phi0, xint) / R);
+        dy[4] = -Cos(phi0) + Sec(phi0 - s / R) + (1 / R) * Sec(phi0 - s / R) * Tan(phi0 - s / R) * (s - R * dsdR(R, d0, phi0, xint));
+        return dy;
+    }
+
+    private double[] dzdq(double R, double d0, double phi0, double xint, double slope, double s) {
+        double[] dz = new double[5];
+        dz[0] = slope * dsdd0(R, d0, phi0, xint);
+        dz[1] = 1;
+        dz[2] = s;
+        dz[3] = slope * dsdphi(R, d0, phi0, xint);
+        dz[4] = slope * dsdR(R, d0, phi0, xint);
+        return dz;
+    }
+
+    private double Csc(double val) {
+        return 1 / Math.sin(val);
+    }
+
+    private double Cot(double val) {
+        return 1 / Math.tan(val);
+    }
+
+    private double Sec(double val) {
+        return 1 / Math.cos(val);
+    }
+
+    private double Sin(double val) {
+        return Math.sin(val);
+    }
+
+    private double Cos(double val) {
+        return Math.cos(val);
+    }
+
+    private double Tan(double val) {
+        return Math.tan(val);
+    }
+
+    private double ArcTan(double val1, double val2) {
+        return Math.atan2(val1, val2);
+    }
+
+    private double Sign(double val) {
+        return Math.signum(val);
+    }
+
+    private double Sqrt(double val) {
+        return Math.sqrt(val);
+    }
+
+    private void printDerivatives(double[] trackpars, double[][] dfdq) {
+        System.out.println("======================================================");
+        System.out.println("s         xint");
+        System.out.printf("%5.5f %5.5f\n", trackpars[5], trackpars[6]);
+        System.out.println("             d0           z0           slope         phi0          R");
+        System.out.printf("Values       %5.5f    %5.5f     %5.5f      %5.5f      %5.5f\n", trackpars[0], trackpars[1], trackpars[2], trackpars[3], trackpars[4]);
+        System.out.printf("dzdq         ");
+        for (int i = 0; i < 5; i++) {
+            System.out.printf("%5.3e   ", dfdq[2][i]);
+        }
+        System.out.println();
+        System.out.printf("dudq         ");
+        for (int i = 0; i < _nlc; i++) {
+            System.out.printf("%5.3e   ", _dfdq.e(0, i));
+        }
+        System.out.println();
+        System.out.println();
+        System.out.printf("dydq         ");
+        for (int i = 0; i < 5; i++) {
+            System.out.printf("%5.3e   ", dfdq[1][i]);
+        }
+        System.out.println();
+        System.out.printf("dvdq         ");
+        for (int i = 0; i < _nlc; i++) {
+            System.out.printf("%5.3e   ", _dfdq.e(1, i));
+        }
+        System.out.println();
+        System.out.println();
+        System.out.printf("dxdq         ");
+        for (int i = 0; i < 5; i++) {
+            System.out.printf("%5.3e   ", dfdq[0][i]);
+        }
+        System.out.println();
+        System.out.printf("dwdq         ");
+        for (int i = 0; i < _nlc; i++) {
+            System.out.printf("%5.3e   ", _dfdq.e(2, i));
+        }
+        System.out.println();
+        //        System.out.println(        _trk.xc()+ "; "+_trk.yc());
+//          System.out.println(        _trk.x0()+ "; "+_trk.y0());
+    }
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
AxialTrackReconDriver.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/AxialTrackReconDriver.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/AxialTrackReconDriver.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,436 @@
+package org.hps.recon.tracking;
+
+import hep.physics.matrix.SymmetricMatrix;
+import hep.physics.vec.BasicHep3Vector;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.lcsim.detector.tracker.silicon.SiTrackerModule;
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.Track;
+import org.lcsim.event.TrackerHit;
+import org.lcsim.fit.helicaltrack.HelicalTrack2DHit;
+import org.lcsim.fit.helicaltrack.HelicalTrackFit;
+import org.lcsim.fit.helicaltrack.HelicalTrackHit;
+import org.lcsim.fit.helicaltrack.MultipleScatter;
+import org.lcsim.fit.line.SlopeInterceptLineFit;
+import org.lcsim.fit.line.SlopeInterceptLineFitter;
+import org.lcsim.geometry.Detector;
+import org.lcsim.lcio.LCIOConstants;
+import org.lcsim.recon.tracking.digitization.sisim.config.ReadoutCleanupDriver;
+import org.lcsim.recon.tracking.seedtracker.SeedCandidate;
+import org.lcsim.recon.tracking.seedtracker.SeedStrategy;
+import org.lcsim.recon.tracking.seedtracker.SeedTrack;
+import org.lcsim.recon.tracking.seedtracker.StrategyXMLUtils;
+import org.lcsim.util.Driver;
+
+/**
+ * This class runs the Track Reconstruction for the HPS Test Proposal detector.
+ * The tracker digitization must be run in front of it. It is intended to work
+ * with the {@link TrackerDigiDriver} digitization Driver.
+ *
+ * @author jeremym
+ * @version $Id: TrackerReconDriver.java,v 1.18 2012/05/03 20:50:29 mgraham Exp
+ * $
+ */
+public final class AxialTrackReconDriver extends Driver {
+
+    // Debug flag.
+    //private final static boolean DEBUG = false;
+    private boolean debug = false;
+    // Tracks found across all events.
+    int ntracks = 0;
+    // Number of events processed.
+    int nevents = 0;
+    // Cache detector object.
+    Detector detector = null;
+    // Default B-field value.
+    private double bfield = 0.5;
+    // Name of the SVT subdetector.
+    private String subdetectorName = "Tracker";
+    // SimTrackerHit input collection for readout cleanup.
+    private String simTrackerHitCollectionName = "TrackerHits";
+    // Tracking strategies resource path.
+    private String strategyResource = "HPS-Test-1pt3.xml";
+    // Output track collection.
+    private String trackCollectionName = "MatchedTracks";
+    // HelicalTrackHit input collection.
+    private String stInputCollectionName = "RotatedHelicalTrackHits";
+    // Output hit collection for HelicalTrackHits.
+    private String hthOutputCollectionName = "HelicalTrackHits";
+    // Input strip hits collection from digi.
+    private String stripHitsCollectionName = "StripClusterer_SiTrackerHitStrip1D";
+    // Hit relations output collection.
+    private String helicalTrackHitRelationsCollectionName = "HelicalTrackHitRelations";
+    // Track to MC relations output collection.
+    private String helicalTrackMCRelationsCollectionName = "HelicalTrackMCRelations";
+    // Max strip separation when making HelicalTrackHits.
+    private double stripMaxSeparation = 10.01;
+    // Tolerance factor when making HelicalTrackHits.
+    private double stripTolerance = 0.01;
+    private List<SeedStrategy> sFinallist;
+
+    public AxialTrackReconDriver() {
+    }
+
+    public void setDebug(boolean debug) {
+        this.debug = debug;
+    }
+
+    public void setSubdetectorName(String subdetectorName) {
+        this.subdetectorName = subdetectorName;
+    }
+
+    /**
+     * Set the tracking strategy resource.
+     *
+     * @param strategyResource The absolute path to the strategy resource in the
+     * hps-java jar.
+     */
+    public void setStrategyResource(String strategyResource) {
+        this.strategyResource = strategyResource;
+    }
+
+    public void setHelicalTrackHitRelationsCollectionName(String helicalTrackHitRelationsCollectionName) {
+        this.helicalTrackHitRelationsCollectionName = helicalTrackHitRelationsCollectionName;
+    }
+
+    public void setHelicalTrackMCRelationsCollectionName(String helicalTrackMCRelationsCollectionName) {
+        this.helicalTrackMCRelationsCollectionName = helicalTrackMCRelationsCollectionName;
+    }
+
+    public void setInputHitCollectionName(String inputHitCollectionName) {
+        this.stInputCollectionName = inputHitCollectionName;
+    }
+
+    public void setOutputHitCollectionName(String outputHitCollectionName) {
+        this.hthOutputCollectionName = outputHitCollectionName;
+    }
+
+    public void setStripHitsCollectionName(String stripHitsCollectionName) {
+        this.stripHitsCollectionName = stripHitsCollectionName;
+    }
+
+    public void setTrackCollectionName(String trackCollectionName) {
+        this.trackCollectionName = trackCollectionName;
+    }
+
+    public void setStripMaxSeparation(double stripMaxSeparation) {
+        this.stripMaxSeparation = stripMaxSeparation;
+    }
+
+    public void setStripTolerance(double stripTolerance) {
+        this.stripTolerance = stripTolerance;
+    }
+
+    /**
+     * Set the SimTrackerHit collection to be used for tracking.
+     *
+     * @param simTrackerHitCollectionName The name of the SimTrackerHit
+     * collection in the event.
+     */
+    public void setSimTrackerHitCollectionName(String simTrackerHitCollectionName) {
+        this.simTrackerHitCollectionName = simTrackerHitCollectionName;
+    }
+
+    /**
+     * This is used to setup the Drivers after XML config.
+     */
+    public void detectorChanged(Detector detector) {
+        // Cache Detector object.
+        this.detector = detector;
+
+        // Get B-field Y with no sign. Seed Tracker doesn't like signed B-field components.
+        // FIXME Is this always right?
+        this.bfield = Math.abs((detector.getFieldMap().getField(new BasicHep3Vector(0, 0, 0)).y()));
+        if (debug) {
+            System.out.println("Set B-field to " + this.bfield);
+        }
+
+        initialize();
+
+        super.detectorChanged(detector);
+    }
+
+    /**
+     * Setup all the child Drivers necessary for track reconstruction.
+     */
+    private void initialize() {
+        //
+        // 1) Driver to create HelicalTrackHits expected by Seedtracker.
+        //
+        // TODO Make this step its own separate Driver??? (Matt)
+
+        // Setup default stereo pairings, which should work for even number of
+        // modules.
+        List<SiTrackerModule> modules = detector.getSubdetector(subdetectorName).getDetectorElement().findDescendants(SiTrackerModule.class);
+        if (modules.size() == 0) {
+            throw new RuntimeException("No SiTrackerModules found in detector.");
+        }
+
+
+        // Create the Driver.
+        HelicalTrackHitDriver hthdriver = new HelicalTrackHitDriver();
+        hthdriver.addCollection(stripHitsCollectionName);
+        hthdriver.setOutputCollectionName(hthOutputCollectionName);
+//        hthdriver.setHitRelationName(helicalTrackHitRelationsCollectionName);
+//        hthdriver.setMCRelationName(helicalTrackMCRelationsCollectionName);
+
+  //      hthdriver.setStripMaxSeparation(stripMaxSeparation);
+  //      hthdriver.setStripTolerance(stripTolerance); // user parameter?
+        hthdriver.setTransformToTracking(true);
+        hthdriver.setDebug(true);
+        add(hthdriver);
+
+        //
+        // 2) Driver to run Seed Tracker.
+        //
+        sFinallist = StrategyXMLUtils.getStrategyListFromInputStream(this.getClass().getResourceAsStream(strategyResource));
+        // 3) Cleanup the readouts for next event.
+        //
+        List<String> readoutCleanup = new ArrayList<String>();
+        readoutCleanup.add(this.simTrackerHitCollectionName);
+        add(new ReadoutCleanupDriver(readoutCleanup));
+
+    }
+
+    /**
+     * Call super for child processing at start of data.
+     */
+    public void startOfData() {
+        super.startOfData();
+    }
+
+    /**
+     * This method is used to run the reconstruction and print debug
+     * information.
+     */
+    public void process(EventHeader event) {
+        // This call runs the track reconstruction using the sub-Drivers.
+        super.process(event);
+        double maxChi2 = 250;
+        List<HelicalTrackHit> hth = event.get(HelicalTrackHit.class, stInputCollectionName);
+
+
+        System.out.println("The HelicalTrackHit collection " + hthOutputCollectionName + " has " + hth.size() + " hits.");
+        List<HelicalTrackHit> hitsLayer1 = getLayerHits(hth, 1);
+        List<HelicalTrackHit> hitsLayer3 = getLayerHits(hth, 3);
+        List<HelicalTrackHit> hitsLayer5 = getLayerHits(hth, 5);
+        List<HelicalTrackHit> hitsLayer7 = getLayerHits(hth, 7);
+        List<HelicalTrackHit> hitsLayer9 = getLayerHits(hth, 9);
+
+        List<SeedCandidate> seedtracks = new ArrayList<SeedCandidate>();
+        for (HelicalTrackHit h1 : hitsLayer1) {
+            for (HelicalTrackHit h3 : hitsLayer3) {
+                for (HelicalTrackHit h5 : hitsLayer5) {
+                    for (HelicalTrackHit h7 : hitsLayer7) {
+//                        for (HelicalTrackHit h9 : hitsLayer9) {
+
+                            SeedCandidate seed = new SeedCandidate(sFinallist.get(0), bfield);
+                            seed.addHit(h1);
+                            seed.addHit(h3);
+                            seed.addHit(h5);
+                            seed.addHit(h7);
+//                            seed.addHit(h9);
+
+                            HelicalTrackFit fitRes = fit(seed);
+                            if (fitRes != null) {
+                                seed.setHelix(fitRes);
+                                if (fitRes.chisq()[1] > maxChi2)
+                                    continue;
+
+                                seedtracks.add(seed);
+//                       System.out.println(fitRes.toString());
+                            }
+//                        }
+                    }
+                }
+            }
+        }
+
+        addTracksToEvent(event, seedtracks, bfield);
+        // Debug printouts.
+        if (debug) {
+            // Check for HelicalTrackHits.
+
+            // Check for Tracks.
+            List<Track> tracks = event.get(Track.class, trackCollectionName);
+            System.out.println("The Track collection " + trackCollectionName + " has " + tracks.size() + " tracks.");
+
+            // Print out track info.
+            for (Track track : tracks) {
+                System.out.println(track.toString());
+                System.out.println("chi2 = " + track.getChi2());
+            }
+        }
+
+        // Increment number of events.
+        ++nevents;
+
+        // Add to tracks found.
+        ntracks += event.get(Track.class, trackCollectionName).size();
+    }
+
+    public HelicalTrackFit fit(SeedCandidate seed) {
+        List<HelicalTrackHit> hitcol = seed.getHits();
+        Map<HelicalTrackHit, MultipleScatter> msmap = new HashMap<HelicalTrackHit, MultipleScatter>();
+        SlopeInterceptLineFitter _lfitter = new SlopeInterceptLineFitter();
+        SlopeInterceptLineFit _lfit;
+        boolean success = false;
+        //  Check if we have enough pixel hits to do a straight-line fit of s vs z
+        int npix = hitcol.size();
+        //  Calculate the arc lengths from the DCA to each hit and check for backwards hits
+        Map<HelicalTrackHit, Double> smap = getPathLengths(hitcol);
+        //  Create the objects that will hold the fit output
+        double[] chisq = new double[2];
+        int[] ndof = new int[2];
+        ndof[0] = 0;
+        chisq[0] = 0;
+        double[] par = new double[5];
+        SymmetricMatrix cov = new SymmetricMatrix(5);
+
+
+        //  Setup for the line fit
+        double[] s = new double[npix];
+        double[] z = new double[npix];
+        double[] dz = new double[npix];
+
+        //  Store the coordinates and errors for the line fit
+        for (int i = 0; i < npix; i++) {
+            HelicalTrackHit hit = hitcol.get(i);
+            z[i] = hit.z();
+            System.out.println(hit.getCorrectedCovMatrix().toString());
+            dz[i] = Math.sqrt(hit.getCorrectedCovMatrix().e(2, 2));
+            s[i] = smap.get(hit);
+            System.out.println(z[i] + " " + dz[i] + " " + s[i]);
+        }
+
+        //  Call the line fitter and check for success
+        success = _lfitter.fit(s, z, dz, npix);
+        if (!success) {
+            return null;
+        }
+
+        //  Save the line fit, chi^2, and DOF
+        _lfit = _lfitter.getFit();
+        chisq[1] = _lfit.chisquared();
+        ndof[1] = npix - 2;
+
+        //  Save the line fit parameters
+        par[HelicalTrackFit.z0Index] = _lfit.intercept();
+        par[HelicalTrackFit.slopeIndex] = _lfit.slope();
+        par[HelicalTrackFit.curvatureIndex] = 0.0001;
+        par[HelicalTrackFit.dcaIndex] = 0.0001;
+        par[HelicalTrackFit.phi0Index] = 0.000;
+
+
+        //  Save the line fit covariance matrix elements
+        cov.setElement(HelicalTrackFit.z0Index, HelicalTrackFit.z0Index, Math.pow(_lfit.interceptUncertainty(), 2));
+        cov.setElement(HelicalTrackFit.z0Index, HelicalTrackFit.slopeIndex, _lfit.covariance());
+        cov.setElement(HelicalTrackFit.slopeIndex, HelicalTrackFit.slopeIndex, Math.pow(_lfit.slopeUncertainty(), 2));
+        cov.setElement(HelicalTrackFit.curvatureIndex, HelicalTrackFit.curvatureIndex, 0);
+        cov.setElement(HelicalTrackFit.curvatureIndex, HelicalTrackFit.phi0Index, 0);
+        cov.setElement(HelicalTrackFit.phi0Index, HelicalTrackFit.phi0Index, 0);
+        cov.setElement(HelicalTrackFit.curvatureIndex, HelicalTrackFit.dcaIndex, 0);  // fix d0 sign convention
+        cov.setElement(HelicalTrackFit.phi0Index, HelicalTrackFit.dcaIndex, 0);  // fix d0 sign convention
+        cov.setElement(HelicalTrackFit.dcaIndex, HelicalTrackFit.dcaIndex, 0);
+
+
+        //  Create the HelicalTrackFit for this helix
+        return new HelicalTrackFit(par, cov, chisq, ndof, smap, msmap);
+
+    }
+
+    private Map<HelicalTrackHit, Double> getPathLengths(List<HelicalTrackHit> hits) {
+
+        //  Create a map to store the arc lengths
+        Map<HelicalTrackHit, Double> smap = new HashMap<HelicalTrackHit, Double>();
+
+        //  Initialize looper tracking and iterate over ordered list of hits
+        double slast = 0.;
+        int ilast = -1;
+        double s;
+        for (int i = 0; i < hits.size(); i++) {
+
+            // Retrieve the next hit ordered by z coordinate and check hit type
+            HelicalTrackHit hit = hits.get(i);
+            if (hit instanceof HelicalTrack2DHit) {
+
+                //  Axial hit - measure from the DCA (can't handle loopers)
+//                s = HelixUtils.PathLength(_cfit, hit);
+                s = hit.getPosition()[0];
+                //  Save the arc length for this hit
+                smap.put(hit, s);
+            }
+        }
+        return smap;
+    }
+
+    private List<HelicalTrackHit> getLayerHits(List<HelicalTrackHit> hth, int layer) {
+        List<HelicalTrackHit> layerHits = new ArrayList<HelicalTrackHit>();
+
+        for (HelicalTrackHit hit : hth) {
+            if (hit.Layer() == layer)
+                layerHits.add(hit);
+        }
+        return layerHits;
+    }
+
+    public void endOfData() {
+        if (debug) {
+            System.out.println("-------------------------------------------");
+            System.out.println(this.getName() + " found " + ntracks + " tracks in " + nevents + " events which is " + ((double) ntracks / (double) nevents) + " tracks per event.");
+        }
+    }
+
+    private void addTracksToEvent(EventHeader event, List<SeedCandidate> seedlist, double bfield) {
+        //  Create a the track list
+        List<Track> tracks = new ArrayList<Track>();
+
+        //  Initialize the reference point to the origin
+        double[] ref = new double[3];
+        ref[0] = 0.;
+        ref[1] = 0.;
+        ref[2] = 0.;
+        //  Loop over the SeedCandidates that have survived
+        for (SeedCandidate trackseed : seedlist) {
+
+            //  Create a new SeedTrack (SeedTrack extends BaseTrack)
+            SeedTrack trk = new SeedTrack();
+
+            //  Add the hits to the track
+            for (HelicalTrackHit hit : trackseed.getHits()) {
+                trk.addHit((TrackerHit) hit);
+            }
+
+            //  Retrieve the helix and save the relevant bits of helix info
+            HelicalTrackFit helix = trackseed.getHelix();
+            trk.setTrackParameters(helix.parameters(), bfield);
+            trk.setCovarianceMatrix(helix.covariance());
+            trk.setChisq(helix.chisqtot());
+            trk.setNDF(helix.ndf()[0] + helix.ndf()[1]);
+
+            //  Flag that the fit was successful and set the reference point
+            trk.setFitSuccess(true);
+            trk.setReferencePoint(ref);
+            trk.setRefPointIsDCA(true);
+
+            //  Set the strategy used to find this track
+            trk.setStratetgy(trackseed.getSeedStrategy());
+
+            //  Set the SeedCandidate this track is based on
+            trk.setSeedCandidate(trackseed);
+
+
+            //  Add the track to the list of tracks
+            tracks.add((Track) trk);
+        }
+
+        // Put the tracks back into the event and exit
+        int flag = 1 << LCIOConstants.TRBIT_HITS;
+        event.put(trackCollectionName, tracks, Track.class, flag);
+    }
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
DataTrackerFakeHitDriver.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/DataTrackerFakeHitDriver.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/DataTrackerFakeHitDriver.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,1030 @@
+package org.hps.recon.tracking;
+
+import hep.aida.IAnalysisFactory;
+import hep.aida.IHistogram1D;
+import hep.aida.IPlotter;
+import hep.aida.IProfile1D;
+import hep.physics.matrix.SymmetricMatrix;
+import hep.physics.vec.BasicHep3Vector;
+import hep.physics.vec.Hep3Matrix;
+import hep.physics.vec.Hep3Vector;
+import hep.physics.vec.VecOp;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.hps.conditions.deprecated.SvtUtils;
+import org.lcsim.detector.IDetectorElement;
+import org.lcsim.detector.ITransform3D;
+import org.lcsim.detector.ITranslation3D;
+import org.lcsim.detector.Transform3D;
+import org.lcsim.detector.Translation3D;
+import org.lcsim.detector.identifier.IIdentifier;
+import org.lcsim.detector.solids.Box;
+import org.lcsim.detector.solids.Inside;
+import org.lcsim.detector.solids.Polygon3D;
+import org.lcsim.detector.tracker.silicon.ChargeCarrier;
+import org.lcsim.detector.tracker.silicon.DopedSilicon;
+import org.lcsim.detector.tracker.silicon.SiSensor;
+import org.lcsim.detector.tracker.silicon.SiSensorElectrodes;
+import org.lcsim.detector.tracker.silicon.SiStrips;
+import org.lcsim.detector.tracker.silicon.SiTrackerIdentifierHelper;
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.MCParticle;
+import org.lcsim.event.RawTrackerHit;
+import org.lcsim.event.SimTrackerHit;
+import org.lcsim.event.base.BaseRawTrackerHit;
+import org.lcsim.event.base.BaseSimTrackerHit;
+import org.lcsim.fit.helicaltrack.HelicalTrackFit;
+import org.lcsim.fit.helicaltrack.HelicalTrackHit;
+import org.lcsim.fit.helicaltrack.HelixUtils;
+import org.lcsim.fit.helicaltrack.HitIdentifier;
+import org.lcsim.geometry.Detector;
+import org.lcsim.geometry.subdetector.BarrelEndcapFlag;
+import org.lcsim.recon.tracking.digitization.sisim.SiTrackerHit;
+import org.lcsim.recon.tracking.digitization.sisim.SiTrackerHitStrip1D;
+import org.lcsim.recon.tracking.digitization.sisim.TrackerHitType;
+import org.lcsim.recon.tracking.digitization.sisim.TrackerHitType.CoordinateSystem;
+import org.lcsim.util.Driver;
+import org.lcsim.util.aida.AIDA;
+
+/**
+ *
+ * @author phansson
+ */
+public class DataTrackerFakeHitDriver extends Driver {
+
+    private boolean debug = false;
+    TrackerHitUtils trackerhitutils = new TrackerHitUtils();
+    Hep3Matrix detToTrk;
+    Hep3Vector _bfield;
+    TrackerHitType trackerType = new TrackerHitType(TrackerHitType.CoordinateSystem.GLOBAL, TrackerHitType.MeasurementType.STRIP_1D);
+    CoordinateSystem coordinate_system = trackerType.getCoordinateSystem();
+    private HitIdentifier _ID = new HitIdentifier();
+    private EventHeader.LCMetaData metaData = null;
+    private boolean _doHth = false;
+    boolean createSimTrackerHits = false;
+    // Collections
+    List<SimTrackerHit> simHits = null;
+    List<SiTrackerHit> stripHits1D = null;
+    List<HelicalTrackHit> hths = null;
+    String trackCollectionName = "MCParticle_HelicalTrackFit";
+    String stripHitOutputCollectionName = "StripClusterer_SiTrackerHitStrip1D";
+    String hthOutputCollectionName = "RotatedHelicalTrackHits";
+    String simTrackerHitCollectionName = "FakeTrackerHits";
+    // Subdetector name.
+    private String subdetectorName = "Tracker";
+    // Various data lists required by digitization.
+    private List<String> processPaths = new ArrayList<String>();
+    private List<IDetectorElement> processDEs = new ArrayList<IDetectorElement>();
+    private Set<SiSensor> processSensors = new HashSet<SiSensor>();
+    //Visualization
+    private boolean hideFrame = false;
+    private AIDA aida = AIDA.defaultInstance();
+    private HashMap<SiSensor, IProfile1D> _delta_histos;
+    private HashMap<SiSensor, IHistogram1D> _delta_itercount = new HashMap<SiSensor, IHistogram1D>();
+    IProfile1D _prf_final_deltas;
+    IProfile1D _prf_all_deltas;
+    IHistogram1D _h_nstriphits_top;
+    IHistogram1D _h_nstriphits_bottom;
+    IAnalysisFactory af = aida.analysisFactory();
+    IPlotter plotter_iter;
+    IPlotter plotter_itercount;
+    IPlotter plotter_iter_final;
+    IPlotter plotter_iter_all;
+    IPlotter plotter_nstripclusters;
+    IPlotter plotter_trackposodd;
+    int[][] counts = new int[2][10];
+
+    public void setDebug(boolean debug) {
+        this.debug = debug;
+    }
+
+    public void setHideFrame(boolean hide) {
+        this.hideFrame = hide;
+    }
+
+    public void setDoHth(boolean debug) {
+        this._doHth = debug;
+    }
+
+    /**
+     * Enable/disable the creation of SimTrackerHits
+     */
+    public void setCreateSimTrackerHits(boolean createSimTrackerHits) {
+        this.createSimTrackerHits = createSimTrackerHits;
+    }
+
+//    public void setReadoutCollectionName(String readoutCollectionName) {
+//        this.readoutCollectionName = readoutCollectionName;
+//    }
+    public void setSubdetectorName(String subdetectorName) {
+        this.subdetectorName = subdetectorName;
+    }
+
+    public void setStripHitOutputCollectionName(String stripHitOutputCollectionName) {
+        this.stripHitOutputCollectionName = stripHitOutputCollectionName;
+    }
+
+    public void setHthOutputCollectionName(String hthOutputCollectionName) {
+        this.hthOutputCollectionName = hthOutputCollectionName;
+    }
+
+    public void setTrackCollectionName(String trackCollectionName) {
+        this.trackCollectionName = trackCollectionName;
+    }
+
+    /**
+     * Creates a new instance of TrackerHitDriver.
+     */
+    public DataTrackerFakeHitDriver() {
+        this._delta_histos = new HashMap<SiSensor, IProfile1D>();
+    }
+
+    /**
+     * Do initialization once we get a Detector.
+     */
+    @Override
+    public void detectorChanged(Detector detector) {
+
+        // Call sub-Driver's detectorChanged methods.
+        super.detectorChanged(detector);
+
+
+        Hep3Vector IP = new BasicHep3Vector(0., 0., 1.);
+        _bfield = new BasicHep3Vector(0, 0, detector.getFieldMap().getField(IP).y());
+        detToTrk = trackerhitutils.detToTrackRotationMatrix();
+
+
+        // Process detectors specified by path, otherwise process entire
+        // detector
+        IDetectorElement deDetector = detector.getDetectorElement();
+
+        for (String path : processPaths) {
+            processDEs.add(deDetector.findDetectorElement(path));
+        }
+
+        if (processDEs.isEmpty()) {
+            processDEs.add(deDetector);
+        }
+
+        for (IDetectorElement detectorElement : processDEs) {
+            processSensors.addAll(detectorElement.findDescendants(SiSensor.class));
+        }
+
+        // Set the detector to process.
+        processPaths.add(subdetectorName);
+
+        this.makePlots();
+
+    }
+
+    /**
+     * Perform the digitization.
+     */
+    @Override
+    public void process(EventHeader event) {
+
+
+        // Obtain the tracks from the event
+        if (!event.hasCollection(HPSTrack.class, trackCollectionName)) {
+            this.printDebug("No HPSTracks were found, skipping event");
+            simHits = null;
+            return;
+        }
+        List<HPSTrack> tracks = event.get(HPSTrack.class, trackCollectionName);
+
+        if (debug) {
+            System.out.println(this.getClass().getSimpleName() + ": found " + tracks.size() + " tracks (" + this.trackCollectionName + ")");
+        }
+
+        // Instantiate the list of interest 
+        if (this._doHth) {
+            this.printDebug("Creating HelicalTrackHits...");
+            hths = new ArrayList<HelicalTrackHit>();
+        } else if (createSimTrackerHits) {
+            this.printDebug("Creating SimTrackerHits...");
+            simHits = new ArrayList<SimTrackerHit>();
+            metaData = event.getMetaData(event.get(SimTrackerHit.class, "TrackerHits"));
+        } else {
+            // Create StripHit1Ds by default
+            this.printDebug("Creating StripHit1D...");
+            stripHits1D = new ArrayList<SiTrackerHit>();
+        }
+
+        if (debug) {
+            System.out.println(this.getClass().getSimpleName() + ": Add hits for " + tracks.size() + " tracks (" + this.trackCollectionName + ")");
+        }
+
+        for (HPSTrack helix : tracks) {
+            if (debug) {
+                System.out.println(this.getClass().getSimpleName() + ": trying to add hits for this track");
+            }
+
+            // Get the MC Particle associated with this track
+            MCParticle mcParticle = helix.getMCParticle();
+
+            if (debug) {
+                System.out.println(this.getClass().getSimpleName() + helix.toString());
+                System.out.println(this.getClass().getSimpleName() + ": htf x0 " + helix.x0() + " y0 " + helix.y0());
+
+                System.out.println(this.getClass().getSimpleName() + ": create a WTrack object");
+            }
+
+            WTrack wtrack = new WTrack(helix, Math.abs(_bfield.z()), true); //remove sign from B-field (assumed to go along z-direction)
+
+            if (debug) {
+                System.out.println(this.getClass().getSimpleName() + ": " + wtrack.toString());
+
+            }
+
+
+
+            int n_hits_top = 0;
+            int n_hits_bot = 0;
+            boolean isTopTrack = false;
+            boolean isBotTrack = false;
+
+            // Make hits if the helix passed through the sensor 
+            for (SiSensor sensor : processSensors) {
+
+                if (debug) {
+                    System.out.println(this.getClass().getSimpleName() + ": add hits to sensor " + sensor.getName() + " at position " + sensor.getGeometry().getPosition().toString());
+                }
+
+                // When creating stereo hits, skip the even sensors
+                if (this._doHth && _ID.getLayer(sensor) % 2 == 0) {
+                    if (debug) {
+                        System.out.println(this.getClass().getSimpleName() + ": this was an even sensor -> skip for HTH production");
+                    }
+                    continue;
+                }
+
+                // Get the position where the sensor and track intercept (Maybe this should go 
+                // inside the method makeSimTrackerHit since it's the only method that uses it
+                Hep3Vector trackPosAtSensor = this.getHelixPlaneIntercept(sensor, wtrack);
+                this.printDebug("The track/plane intercept at " + trackPosAtSensor.toString());
+
+                // Check if the track lies within the sensor
+                boolean isHit = TrackUtils.sensorContainsTrack(trackPosAtSensor, sensor);
+
+                if (isHit) {
+                    if (debug) {
+                        System.out.println(this.getClass().getSimpleName() + ": make a tracker hit and add to this sensor");
+                    }
+                    if (SvtUtils.getInstance().isTopLayer(sensor)) {
+                        n_hits_top++;
+                        isTopTrack = true;
+                    } else {
+                        n_hits_bot++;
+                        isBotTrack = true;
+                    }
+                    if (this._doHth) {
+                        hths.add(this.makeHelicalTrackHit(sensor, wtrack));
+                    } else if (createSimTrackerHits) {
+                        // Create a SimTrackerHit at the intersect between a track and a sensor
+                        simHits.add(this.makeSimTrackerHit(metaData, sensor, trackPosAtSensor, mcParticle, wtrack));
+                    } else {
+                        stripHits1D.add(this.makeTrackerHit(sensor, wtrack));
+                    }
+                } else {
+                    if (debug) {
+                        System.out.println(this.getClass().getSimpleName() + ": this helix didn't pass within the sensor so no hit was added");
+                    }
+                }
+
+            }
+
+            if (isTopTrack) {
+                this._h_nstriphits_top.fill(n_hits_top);
+            }
+            if (isBotTrack) {
+                this._h_nstriphits_bottom.fill(n_hits_bot);
+            }
+            if (isTopTrack && isBotTrack) {
+                System.out.println(this.getClass().getSimpleName() + ": tris track is both top and bottom??? \n" + wtrack.toString() + "\nHTF:" + helix.toString());
+                System.exit(1);
+            }
+
+            /*
+             stripHits1D.addAll(stripHits1D_for_track);
+             hths.addAll(hths_for_track);
+             */
+        }
+
+
+
+        if (debug) {
+            if (stripHits1D != null) {
+                System.out.println(this.getClass().getSimpleName() + ": Produced " + stripHits1D.size() + " hits for collection " + this.stripHitOutputCollectionName);
+            }
+            if (hths != null) {
+                System.out.println(this.getClass().getSimpleName() + ": Produced " + hths.size() + " hits for collection " + this.hthOutputCollectionName);
+            }
+        }
+
+
+        //int flag = LCIOUtil.bitSet(0, 31, true); // Turn on 64-bit cell ID.
+        //event.put(this.rawTrackerHitOutputCollectionName, rawHits, RawTrackerHit.class, flag, toString());
+        // Put the collection of interest into the event
+
+        if (_doHth) {
+            event.put(hthOutputCollectionName, hths, HelicalTrackHit.class, 0);
+        } else if (createSimTrackerHits) {
+            event.put(simTrackerHitCollectionName, simHits, SimTrackerHit.class, 0);
+            this.printDebug("SimTrackerHits created: " + simHits.size());
+        } else {
+            event.put(stripHitOutputCollectionName, stripHits1D, SiTrackerHitStrip1D.class, 0, toString());
+        }
+        //event.put("RotatedHelicalTrackHits", rotatedhits, HelicalTrackHit.class, 0);
+
+        /*
+         if (debug) {
+         if(event.hasCollection(HelicalTrackHit.class, "RotatedHelicalTrackHits")) {
+         System.out.println(this.getClass().getSimpleName() + ": has hths:");
+         for(HelicalTrackHit hth : hths) {
+         System.out.println(this.getClass().getSimpleName() + ": " + hth.getPosition().toString());
+         }
+         } else {
+         System.out.println(this.getClass().getSimpleName() + ": has not hths!");
+         }
+         }
+         if (debug) {
+         for (int mod = 0; mod < 2; mod++) {
+         for (int layer = 0; layer < 10; layer++) {
+         counts[mod][layer] += SvtUtils.getInstance().getSensor(mod, layer).getReadout().getHits(SiTrackerHit.class).size();
+         }
+         }
+         }*/
+    }
+
+    private SiTrackerHitStrip1D makeTrackerHit(SiSensor sensor, WTrack wtrack) {
+        //private SiTrackerHitStrip1D makeTrackerHit(List<HPSFittedRawTrackerHit> cluster, SiSensorElectrodes electrodes) {
+        //create fake raw tracker hit
+
+        if (debug) {
+            System.out.println(this.getClass().getSimpleName() + ": makeTrackerHit");
+        }
+
+        List<RawTrackerHit> rth_cluster = this.makeRawTrackerFakeHit(sensor);
+        if (rth_cluster.size() != 1) {
+            System.out.println(this.getClass().getSimpleName() + ": the fake raw tracker hit cluster is different than one!? " + rth_cluster.size());
+            System.exit(1);
+        }
+        if (debug) {
+            System.out.println(this.getClass().getSimpleName() + ": created a fake raw tracker hit ");
+        }
+        RawTrackerHit raw_hit = rth_cluster.get(0);
+        IIdentifier id = raw_hit.getIdentifier();
+
+        //Get the electrode objects
+        SiTrackerIdentifierHelper _sid_helper = (SiTrackerIdentifierHelper) sensor.getIdentifierHelper();
+        ChargeCarrier carrier = ChargeCarrier.getCarrier(_sid_helper.getSideValue(id));
+        SiSensorElectrodes electrodes = ((SiSensor) raw_hit.getDetectorElement()).getReadoutElectrodes(carrier);
+
+
+
+
+        ITransform3D local_to_global;
+        if (coordinate_system == TrackerHitType.CoordinateSystem.GLOBAL) {
+            local_to_global = new Transform3D();
+        } else if (coordinate_system == TrackerHitType.CoordinateSystem.SENSOR) {
+            local_to_global = sensor.getGeometry().getLocalToGlobal();
+        } else {
+            throw new RuntimeException(this.getClass().getSimpleName() + " problem with coord system " + coordinate_system.toString());
+        }
+
+
+        ITransform3D electrodes_to_global = electrodes.getLocalToGlobal();
+        ITransform3D global_to_hit = local_to_global.inverse();
+        ITransform3D electrodes_to_hit = Transform3D.multiply(global_to_hit, electrodes_to_global);
+
+        Hep3Vector u = electrodes_to_hit.rotated(electrodes.getMeasuredCoordinate(0));
+        Hep3Vector v = electrodes_to_hit.rotated(electrodes.getUnmeasuredCoordinate(0));
+        Hep3Vector w = VecOp.cross(u, v);
+        Hep3Vector _orgloc = new BasicHep3Vector(0., 0., 0.);
+        electrodes_to_global.transformed(_orgloc);
+        if (debug) {
+            System.out.println(this.getClass().getSimpleName() + ": electrodes  u " + u.toString());
+            System.out.println(this.getClass().getSimpleName() + ": electrodes  v " + v.toString());
+            System.out.println(this.getClass().getSimpleName() + ": electrodes  w " + w.toString() + "( " + w.magnitude() + ")");
+        }
+
+        electrodes_to_global.getTranslation().translate(_orgloc);
+        if (debug) {
+            System.out.print(this.getClass().getSimpleName() + ": orgloc " + _orgloc.toString() + "  -> ");
+        }
+        _orgloc = VecOp.mult(detToTrk, _orgloc);
+        if (debug) {
+            System.out.println(_orgloc.toString());
+        }
+
+
+
+
+        if (debug) {
+            System.out.println(this.getClass().getSimpleName() + ": Try to find the interception point");
+        }
+
+        //B-field must go along Z direction
+        Hep3Vector h = new BasicHep3Vector(_bfield.x(), _bfield.y(), Math.abs(_bfield.z()));
+        h = VecOp.unit(h);
+        //Rotate into tracking frame
+        Hep3Vector eta = VecOp.mult(detToTrk, w);
+
+        if (debug) {
+            System.out.println(this.getClass().getSimpleName() + ": eta  " + eta.toString());
+        }
+
+        Hep3Vector position = wtrack.getHelixAndPlaneIntercept(_orgloc, eta, h);
+
+        if (debug) {
+            System.out.println(this.getClass().getSimpleName() + ": found interception point at position " + position.toString());
+        }
+
+
+        HelicalTrackFit htf = wtrack._htf;
+        List<Double> s = HelixUtils.PathToXPlane(htf, position.x(), 0, 0);
+        Hep3Vector posOnHelix = HelixUtils.PointOnHelix(htf, s.get(0));
+        Hep3Vector posdiff = VecOp.sub(position, posOnHelix);
+        System.out.println(this.getClass().getSimpleName() + ": diffpos " + posdiff.toString() + " L " + position.toString() + " posOnHelix " + posOnHelix.toString() + " R=" + htf.R());
+
+        position = VecOp.mult(VecOp.inverse(detToTrk), position);
+
+        if (debug) {
+            System.out.println(this.getClass().getSimpleName() + ": rotate the hit position to the global frame -> " + position.toString());
+        }
+
+
+
+        // Need to make sure that the position is at the edge of the strip in the global frame
+        // 1. Rotate to the local sensor frame
+        position = ((SiSensor) electrodes.getDetectorElement()).getGeometry().getGlobalToLocal().transformed(position);
+
+        if (debug) {
+            System.out.println(this.getClass().getSimpleName() + ": local (sensor) hit position " + position.toString());
+        }
+
+        // 2. Remove the coordinate of the unmeasured direction
+
+        position = new BasicHep3Vector(position.x(), 0, position.z());
+
+        if (debug) {
+            System.out.println(this.getClass().getSimpleName() + ": fixed local (sensor) hit position " + position.toString());
+        }
+
+        // 3. Transform back to global coordinates
+
+        position = ((SiSensor) electrodes.getDetectorElement()).getGeometry().getLocalToGlobal().transformed(position);
+
+        if (debug) {
+            System.out.println(this.getClass().getSimpleName() + ": fixed global hit position " + position.toString());
+        }
+
+
+
+
+        //Fill dummy versions
+        SymmetricMatrix covariance = this.getCovariance(rth_cluster, electrodes);
+        double time = this.getTime(rth_cluster);
+        double energy = this.getEnergy(rth_cluster);
+
+
+        SiTrackerHitStrip1D hit = new SiTrackerHitStrip1D(position, covariance, energy, time, rth_cluster, trackerType);
+
+        if (debug) {
+            System.out.println(this.getClass().getSimpleName() + ": created SiStrip1D at " + position.toString());
+        }
+
+
+        return hit;
+
+
+    }
+
+    /**
+     *
+     * Find the unit vector of a sensor
+     *
+     * @param sensor
+     * @return unit vector of the plane
+     */
+    private Hep3Vector getPlaneUnitVector(SiSensor sensor) {
+        /*
+         * Weird way of getting the unit vector by creating a fake raw tracker hit...must be simpler way?
+         */
+        RawTrackerHit raw_hit = this.makeRawTrackerFakeHit(sensor).get(0);
+        IIdentifier id = raw_hit.getIdentifier();
+        //Get the electrode objects
+        SiTrackerIdentifierHelper _sid_helper = (SiTrackerIdentifierHelper) sensor.getIdentifierHelper();
+        ChargeCarrier carrier = ChargeCarrier.getCarrier(_sid_helper.getSideValue(id));
+        SiSensorElectrodes electrodes = ((SiSensor) raw_hit.getDetectorElement()).getReadoutElectrodes(carrier);
+        ITransform3D local_to_global;
+        if (coordinate_system == TrackerHitType.CoordinateSystem.GLOBAL) {
+            local_to_global = new Transform3D();
+        } else if (coordinate_system == TrackerHitType.CoordinateSystem.SENSOR) {
+            local_to_global = sensor.getGeometry().getLocalToGlobal();
+        } else {
+            throw new RuntimeException(this.getClass().getSimpleName() + " problem with coord system " + coordinate_system.toString());
+        }
+        ITransform3D electrodes_to_global = electrodes.getLocalToGlobal();
+        ITransform3D global_to_hit = local_to_global.inverse();
+        ITransform3D electrodes_to_hit = Transform3D.multiply(global_to_hit, electrodes_to_global);
+
+        Hep3Vector u = electrodes_to_hit.rotated(electrodes.getMeasuredCoordinate(0));
+        Hep3Vector v = electrodes_to_hit.rotated(electrodes.getUnmeasuredCoordinate(0));
+        Hep3Vector w = VecOp.cross(u, v);
+        Hep3Vector eta = VecOp.mult(detToTrk, w);
+        return eta;
+
+    }
+
+    /**
+     *
+     * Find the origin of the sensor plane
+     *
+     * @param sensor
+     * @return origin position of the plane
+     */
+    private Hep3Vector getOrgLoc(SiSensor sensor) {
+        /*
+         * Weird way of getting the org location by creating a fake raw tracker hit...must be simpler way?
+         */
+        List<RawTrackerHit> rth_cluster = this.makeRawTrackerFakeHit(sensor);
+        if (rth_cluster.size() != 1) {
+            System.out.println(this.getClass().getSimpleName() + ": the fake raw tracker hit cluster is different than one!? " + rth_cluster.size());
+            System.exit(1);
+        }
+        //Get the electrode objects
+        IIdentifier id = rth_cluster.get(0).getIdentifier();
+        SiTrackerIdentifierHelper _sid_helper = (SiTrackerIdentifierHelper) sensor.getIdentifierHelper();
+        ChargeCarrier carrier = ChargeCarrier.getCarrier(_sid_helper.getSideValue(id));
+        SiSensorElectrodes electrodes = ((SiSensor) rth_cluster.get(0).getDetectorElement()).getReadoutElectrodes(carrier);
+        ITransform3D local_to_global;
+        if (coordinate_system == TrackerHitType.CoordinateSystem.GLOBAL) {
+            local_to_global = new Transform3D();
+        } else if (coordinate_system == TrackerHitType.CoordinateSystem.SENSOR) {
+            local_to_global = sensor.getGeometry().getLocalToGlobal();
+        } else {
+            throw new RuntimeException(this.getClass().getSimpleName() + " problem with coord system " + coordinate_system.toString());
+        }
+        ITransform3D electrodes_to_global = electrodes.getLocalToGlobal();
+        Hep3Vector _orgloc = new BasicHep3Vector(0., 0., 0.);
+        electrodes_to_global.transformed(_orgloc);
+        electrodes_to_global.getTranslation().translate(_orgloc);
+        if (debug) {
+            System.out.print(this.getClass().getSimpleName() + ": orgloc " + _orgloc.toString() + "  -> ");
+        }
+        _orgloc = VecOp.mult(detToTrk, _orgloc);
+        if (debug) {
+            System.out.println(_orgloc.toString());
+        }
+
+        return _orgloc;
+
+    }
+
+    private Hep3Vector getHelixPlaneIntercept(SiSensor sensor, WTrack wtrack) {
+        Hep3Vector eta = this.getPlaneUnitVector(sensor);
+        Hep3Vector _orgloc = this.getOrgLoc(sensor);
+        Hep3Vector h = new BasicHep3Vector(_bfield.x(), _bfield.y(), Math.abs(_bfield.z()));
+        h = VecOp.unit(h);
+        Hep3Vector position = wtrack.getHelixAndPlaneIntercept(_orgloc, eta, h);
+        if (debug) {
+            HelicalTrackFit htf = wtrack._htf;
+            List<Double> s = HelixUtils.PathToXPlane(htf, position.x(), 0, 0);
+            Hep3Vector posOnHelix = HelixUtils.PointOnHelix(htf, s.get(0));
+            Hep3Vector posdiff = VecOp.sub(position, posOnHelix);
+            System.out.println(this.getClass().getSimpleName() + ": Path length to position " + position.toString() + ": s = " + s.get(0));
+            System.out.println(this.getClass().getSimpleName() + ": Difference between W and helixutils: diffpos " + posdiff.toString() + " ( " + position.toString() + " posOnHelix " + posOnHelix.toString() + " R=" + htf.R());
+        }
+
+
+        return position;
+    }
+
+    private HelicalTrackHit makeHelicalTrackHit(SiSensor sensor, WTrack wtrack) {
+        //private SiTrackerHitStrip1D makeTrackerHit(List<HPSFittedRawTrackerHit> cluster, SiSensorElectrodes electrodes) {
+        //create fake raw tracker hit
+
+        if (debug) {
+            System.out.println(this.getClass().getSimpleName() + ": makeTrackerHit");
+        }
+
+        List<RawTrackerHit> rth_cluster = this.makeRawTrackerFakeHit(sensor);
+
+        if (debug) {
+            System.out.println(this.getClass().getSimpleName() + ": Try to find the interception point");
+        }
+
+        Hep3Vector position = this.getHelixPlaneIntercept(sensor, wtrack);
+
+
+        //Fill dummy covariance matrix with minimal uncertainties
+        //SymmetricMatrix covariance = this.getCovariance(rth_cluster, electrodes);
+        SymmetricMatrix covariance = new SymmetricMatrix(3);
+        double cov_xx = Math.pow(0.00001, 2); //1um error
+        double cov_yy = cov_xx;
+        double cov_zz = cov_xx;
+        covariance.setElement(0, 0, cov_xx);
+        covariance.setElement(1, 1, cov_yy);
+        covariance.setElement(2, 2, cov_zz);
+
+        double time = this.getTime(rth_cluster);
+        double energy = this.getEnergy(rth_cluster);
+
+
+        //IDetectorElement de = sensor;
+        String det = _ID.getName(sensor);
+        int layer = _ID.getLayer(sensor);
+        BarrelEndcapFlag beflag = _ID.getBarrelEndcapFlag(sensor);
+
+        if (layer % 2 == 0) {
+            if (debug) {
+                System.out.println(this.getClass().getSimpleName() + ": problem, trying to create a HTH for even layer? " + layer);
+            }
+            System.exit(1);
+        }
+
+        HelicalTrackHit hit = new HelicalTrackHit(position, covariance, 0.0, time, 3, rth_cluster, det, layer, beflag);
+        //SiTrackerHitStrip1D hit = new SiTrackerHitStrip1D(position, covariance, energy, time, rth_cluster, trackerType);
+
+        if (debug) {
+            System.out.println(this.getClass().getSimpleName() + ": created HelicalTrackHit at " + position.toString() + " and layer " + hit.Layer() + "(" + layer + ")");
+        }
+
+
+        return hit;
+
+
+    }
+
+    /**
+     * Create a SimTrackerHit and add it to the corresponding readout
+     *
+     * @param metaData : meta data associated with the SimTrackerHit collection
+     * @param sensor : sensor on which the hit will be created on
+     * @param trkPositionAtSensor : the position of a track at a sensor plane
+     * @param particle : MC particle associated with the track containing the
+     * hit
+     * @return SimTrackerHit
+     */
+    private SimTrackerHit makeSimTrackerHit(EventHeader.LCMetaData metaData, SiSensor sensor, Hep3Vector trkPositionAtSensor, MCParticle particle, WTrack wtrack) {
+
+        // Transform the position of the SimTrackerHit to the detector coordinates
+        // TODO: Fix the extrapolator so that it returns the position in the detector frame
+        //Hep3Vector trkPositionAtSensorDet = VecOp.mult(VecOp.inverse(detToTrk),trkPositionAtSensor);
+        //this.printDebug("The helix and sensor intercept at: " + trkPositionAtSensorDet.toString());
+
+        // Sensor to tracking frame transformation
+        ITransform3D localToGlobal = sensor.getGeometry().getLocalToGlobal();
+        // Tracking frame to sensor transformation
+        ITransform3D globalToSensor = sensor.getGeometry().getGlobalToLocal();
+
+        // Get the sensor position
+        Hep3Vector sensorPosition = sensor.getGeometry().getPosition();
+        this.printDebug("Sensor position: " + sensorPosition.toString());
+        // Transform the sensor position to the tracking frame
+        Hep3Vector transformedSensorPosition = globalToSensor.transformed(sensorPosition);
+        this.printDebug("Transformed sensor position: " + transformedSensorPosition.toString());
+
+        // Get the solid representing a sensor
+        Box sensorSolid = (Box) sensor.getGeometry().getLogicalVolume().getSolid();
+        // Get the solid faces
+        Polygon3D pSide = sensorSolid.getFacesNormalTo(new BasicHep3Vector(0, 0, 1)).get(0);
+        this.printDebug("p Side: " + pSide.toString());
+        Polygon3D nSide = sensorSolid.getFacesNormalTo(new BasicHep3Vector(0, 0, -1)).get(0);
+        this.printDebug("n Side: " + pSide.toString());
+
+        // Translate to the sensor face (p side) 
+        ITranslation3D translateToPSide = new Translation3D(VecOp.mult(-pSide.getDistance(), pSide.getNormal()));
+        this.printDebug("pSide Translation vector: " + translateToPSide.getTranslationVector().toString());
+
+        // Translate to the p side of the sensor
+        Hep3Vector pSidePosition = translateToPSide.translated(transformedSensorPosition);
+        this.printDebug("Translated sensor position at p side: " + pSidePosition.toString());
+        // Transform the sensor position to the tracking coordinates
+        localToGlobal.transform(pSidePosition);
+        this.printDebug("Translated sensor position at p side in tracking coordinates: " + pSidePosition.toString());
+        // Check if the point lies inside of the sensor
+        if (sensor.getGeometry().inside(pSidePosition) == Inside.OUTSIDE) {
+            throw new RuntimeException("Position of p side face does not lie within the sensor volume!");
+        } else {
+            this.printDebug("p side position lies within the sensor volume");
+        }
+
+        // Find the interception between the p side face and the track
+        Hep3Vector h = new BasicHep3Vector(_bfield.x(), _bfield.y(), Math.abs(_bfield.z()));
+        h = VecOp.unit(h);
+        // Transform the sensor position to the lcsim coordinates
+        pSidePosition = VecOp.mult(detToTrk, pSidePosition);
+        this.printDebug("p side position in lcsim coordinates: " + pSidePosition.toString());
+        //Hep3Vector pSideInter = wutils.getHelixAndPlaneIntercept(wtrack, pSidePosition, VecOp.unit(pSidePosition), h);
+        Hep3Vector eta = this.getPlaneUnitVector(sensor);
+        Hep3Vector pSideInter = wtrack.getHelixAndPlaneIntercept(pSidePosition, eta, h);
+        this.printDebug("Intersection between track and p side: " + pSideInter.toString());
+        // Transform back to the JLab coordinates 
+        pSideInter = VecOp.mult(VecOp.inverse(detToTrk), pSideInter);
+        this.printDebug("Intersection trasnformed to the JLab coordinates: " + pSideInter.toString());
+        if (sensor.getGeometry().inside(pSideInter) == Inside.OUTSIDE) {
+            throw new RuntimeException("Position of p side/track intercept does not lie within the sensor volume!");
+        } else {
+            this.printDebug("p side/track intercept lies within the sensor volume");
+        }
+
+        // Translate to the sensor n side
+        ITranslation3D translateToNSide = new Translation3D(VecOp.mult(-nSide.getDistance(), nSide.getNormal()));
+        this.printDebug("n side Translation vector: " + translateToNSide.getTranslationVector().toString());
+
+        // Translate to the n side of the sensor
+        Hep3Vector nSidePosition = translateToNSide.translated(transformedSensorPosition);
+        this.printDebug("Translated sensor position at n side: " + nSidePosition.toString());
+        // Transform the sensor position to the tracking coordinates
+        localToGlobal.transform(nSidePosition);
+        this.printDebug("Translated sensor position at n side in tracking coordinates: " + nSidePosition.toString());
+        // Check if the point lies inside of the sensor
+        if (sensor.getGeometry().inside(nSidePosition) == Inside.OUTSIDE) {
+            throw new RuntimeException("Position of n side face does not lie within the sensor volume!");
+        } else {
+            this.printDebug("n side position lies within the sensor volume");
+        }
+
+        // Find the interception between the p side face and the track
+        // Transform the sensor position to the lcsim coordinates
+        nSidePosition = VecOp.mult(detToTrk, nSidePosition);
+        this.printDebug("n side position in lcsim coordinates: " + nSidePosition.toString());
+        //Hep3Vector pSideInter = wutils.getHelixAndPlaneIntercept(wtrack, pSidePosition, VecOp.unit(pSidePosition), h);
+        Hep3Vector nSideInter = wtrack.getHelixAndPlaneIntercept(nSidePosition, eta, h);
+        this.printDebug("Intersection between track and n side: " + nSideInter.toString());
+        // Transform back to the JLab coordinates 
+        nSideInter = VecOp.mult(VecOp.inverse(detToTrk), nSideInter);
+        this.printDebug("Intersection trasnfored to the JLab coordinates: " + nSideInter.toString());
+        if (sensor.getGeometry().inside(nSideInter) == Inside.OUTSIDE) {
+            throw new RuntimeException("Position of n side/track intercept does not lie within the sensor volume!");
+        } else {
+            this.printDebug("n side/track intercept lies within the sensor volume");
+        }
+
+        // Find the midpoint between a straight line connecting the p side and n side intercepts 
+        Hep3Vector trkPositionAtSensorDet = VecOp.add(nSideInter, pSideInter);
+        trkPositionAtSensorDet = VecOp.mult(.5, trkPositionAtSensorDet);
+        this.printDebug("Hit will be placed at position: " + trkPositionAtSensorDet.toString());
+        if (sensor.getGeometry().inside(trkPositionAtSensorDet) == Inside.OUTSIDE) {
+            throw new RuntimeException("Midpoint does not lie within the sensor volume!");
+        } else {
+            this.printDebug("midpoint lies within the sensor volume");
+        }
+
+        // Find the length of the line. For now, this is the path length
+        // Note: The small delta parameter is to avoid ending up outside of the sensor
+        double pathLength = VecOp.sub(nSideInter, pSideInter).magnitude() - .01;
+        this.printDebug("The path length is: " + pathLength);
+
+        /* DEBUG
+         Hep3Vector midpoint = new BasicHep3Vector(trkPositionAtSensorDet.v());
+         Hep3Vector direction = VecOp.unit(new BasicHep3Vector(particle.getMomentum().v()));
+         Hep3Vector half_length = VecOp.mult(pathLength/2.0,direction);
+        
+         Hep3Vector endPoint = VecOp.add(midpoint,half_length);
+         this.printDebug("The end point is at position: " + endPoint.toString());
+        
+         Hep3Vector startPoint = VecOp.add(midpoint,VecOp.mult(-1.0,half_length));
+         this.printDebug("The start point is at position: " + startPoint.toString());
+        
+         if(sensor.getGeometry().inside(endPoint) == Inside.OUTSIDE){
+         throw new RuntimeException("Position of end point does not lie within the sensor volume!");
+         } else { 
+         this.printDebug("end point lies within the sensor volume");
+         }
+        
+         if(sensor.getGeometry().inside(startPoint) == Inside.OUTSIDE){
+         throw new RuntimeException("Position start point does not lie within the sensor volume!");
+         } else { 
+         this.printDebug("Start point lies within the sensor volume");
+         } */
+
+        double dEdx = 24000/* MIP */ * DopedSilicon.ENERGY_EHPAIR;
+        double[] momentum = particle.getMomentum().v();
+        this.printDebug("Particle Momentum: " + particle.getMomentum().toString());
+        double time = 0;
+        int cellID = (int) TrackerHitUtils.makeSimTrackerHitId(sensor).getValue();
+
+        SimTrackerHit simHit = new BaseSimTrackerHit(trkPositionAtSensorDet.v(), dEdx, momentum, pathLength, time, cellID, particle, metaData, sensor);
+        // Add it to the sensor readout
+        // sensor.getReadout().addHit(simHit);
+        return simHit;
+    }
+
+    //private SymmetricMatrix getCovariance() {     
+    private SymmetricMatrix getCovariance(List<RawTrackerHit> cluster, SiSensorElectrodes electrodes) {
+        SymmetricMatrix covariance = new SymmetricMatrix(3);
+        covariance.setElement(0, 0, Math.pow(getMeasuredResolution(cluster, electrodes), 2));
+        covariance.setElement(1, 1, Math.pow(getUnmeasuredResolution(cluster, electrodes), 2));
+        covariance.setElement(2, 2, 0.0);
+
+        SymmetricMatrix covariance_global = electrodes.getLocalToGlobal().transformed(covariance);
+
+//        System.out.println("Global covariance matrix: \n"+covariance_global);
+
+        return covariance_global;
+
+    }
+
+    private double getMeasuredResolution(List<RawTrackerHit> cluster, SiSensorElectrodes electrodes) // should replace this by a ResolutionModel class that gives expected resolution.  This could be a big job.
+    {
+        double measured_resolution;
+
+        double sense_pitch = ((SiSensor) electrodes.getDetectorElement()).getSenseElectrodes(electrodes.getChargeCarrier()).getPitch(0);
+
+//        double readout_pitch = electrodes.getPitch(0);
+//        double noise = _readout_chip.getChannel(strip_number).computeNoise(electrodes.getCapacitance(strip_number));
+//        double signal_expected = (0.000280/DopedSilicon.ENERGY_EHPAIR) *
+//                ((SiSensor)electrodes.getDetectorElement()).getThickness(); // ~280 KeV/mm for thick Si sensors
+        double _oneClusterErr = 1 / Math.sqrt(12);
+        double _twoClusterErr = 1 / 5;
+        double _threeClusterErr = 1 / 3;
+        double _fourClusterErr = 1 / 2;
+        double _fiveClusterErr = 1;
+
+        if (cluster.size() == 1) {
+            measured_resolution = sense_pitch * _oneClusterErr;
+        } else if (cluster.size() == 2) {
+            measured_resolution = sense_pitch * _twoClusterErr;
+        } else if (cluster.size() == 3) {
+            measured_resolution = sense_pitch * _threeClusterErr;
+        } else if (cluster.size() == 4) {
+            measured_resolution = sense_pitch * _fourClusterErr;
+        } else {
+            measured_resolution = sense_pitch * _fiveClusterErr;
+        }
+
+        return measured_resolution;
+    }
+
+    private double getUnmeasuredResolution(List<RawTrackerHit> cluster, SiSensorElectrodes electrodes) {
+        // Get length of longest strip in hit
+        double hit_length = 0;
+        for (RawTrackerHit hit : cluster) {
+            hit_length = Math.max(hit_length, ((SiStrips) electrodes).getStripLength(1));
+        }
+        return hit_length / Math.sqrt(12);
+    }
+
+    private double getTime(List<RawTrackerHit> cluster) {
+        return 0;
+    }
+
+    private double getEnergy(List<RawTrackerHit> cluster) {
+        double total_charge = 20000;
+//        
+//         double total_charge = 0.0;
+//        for (RawTrackerHit hit : cluster) {
+//            double signal = hit.getAmp();
+//            total_charge += signal;
+//        }
+        return total_charge * DopedSilicon.ENERGY_EHPAIR;
+    }
+
+    /**
+     * Creates a raw tracker hit at a dummy channel
+     *
+     * @param sensor that will get the hit
+     * @return list of a single raw tracker hit
+     */
+    public List<RawTrackerHit> makeRawTrackerFakeHit(SiSensor sensor) {
+    
+        //if(debug) System.out.println(this.getClass().getSimpleName() + ": makeRawTrackerFakeHit for sensor " + sensor.getName());
+        List<RawTrackerHit> raw_hits = new ArrayList<RawTrackerHit>();
+
+        // Get SimTrackerHits
+        //IReadout ro = sensor.getReadout();
+
+
+        // Loop over electrodes and digitize with readout chip
+        for (ChargeCarrier carrier : ChargeCarrier.values()) {
+            if (sensor.hasElectrodesOnSide(carrier)) {
+
+                //if(debug) System.out.println(this.getClass().getSimpleName() + ": creating a dummy hit for sensor " + sensor.getName());
+                //SortedMap<Integer,List<Integer>> digitized_hits = _readout_chip.readout(electrode_data.get(carrier),sensor.getReadoutElectrodes(carrier));
+                //if(debug) System.out.println(this.getClass().getSimpleName() + ": creating a dummy hit for sensor " + sensor.getName());
+
+                int channel = 1;
+                int time = 0;
+                long cell_id = sensor.makeStripId(channel, carrier.charge()).getValue();
+                //List<Integer> readout_data = new ArrayList<Integer>();
+                short[] adc_values = new short[6];
+                for (Integer i = 0; i < 6; ++i) {
+                    Integer adc = 50;
+                    adc_values[i] = adc.shortValue(); //ADC counts
+                }
+                IDetectorElement detector_element = sensor;
+                RawTrackerHit raw_hit = new BaseRawTrackerHit(time, cell_id, adc_values, new ArrayList<SimTrackerHit>(), detector_element);
+                //ro.addHit(raw_hit);
+                raw_hits.add(raw_hit);
+
+
+            }
+
+        }
+
+        return raw_hits;
+    }
+
+    private void makePlots() {
+
+        for (SiSensor sensor : processSensors) {
+            if (debug) {
+                System.out.println(this.getClass().getSimpleName() + ": Making plots for " + sensor.getName());
+            }
+            IProfile1D h = aida.profile1D("deltas " + sensor.getName(), 7, 0, 7);
+            this._delta_histos.put(sensor, h);
+            IHistogram1D h1 = aida.histogram1D("Number of iterations " + sensor.getName(), 7, 0, 7);
+            this._delta_itercount.put(sensor, h1);
+        }
+
+        _prf_all_deltas = aida.profile1D("alldeltas", 10, 0, 10);//,50,-20,20);
+        _prf_final_deltas = aida.profile1D("finaldeltas", 10, 0, 10);//,50,-20,20);
+
+        _h_nstriphits_top = aida.histogram1D("NstripClusters top", 11, -0.5, 10.5);
+        _h_nstriphits_bottom = aida.histogram1D("NstripClusters bottom", 11, -0.5, 10.5);
+
+        //_h_trkposodd_top = aida.histogram1D("_h_trkposodd_top", 50, -0.5, 10.5);
+
+        plotter_iter_final = af.createPlotterFactory().create();
+        plotter_iter_final.createRegions(1, 1);
+        plotter_iter_final.region(0).plot(_prf_final_deltas);
+        plotter_iter_final.region(0).style().xAxisStyle().setLabel("Final iteration");
+        plotter_iter_final.region(0).style().yAxisStyle().setLabel("<Distance to xp>");
+
+        plotter_iter_all = af.createPlotterFactory().create();
+        plotter_iter_all.createRegions(1, 1);
+        plotter_iter_all.region(0).plot(_prf_all_deltas);
+        plotter_iter_all.region(0).style().xAxisStyle().setLabel("Iteration");
+        plotter_iter_all.region(0).style().yAxisStyle().setLabel("<Distance to xp>");
+
+
+        plotter_iter = af.createPlotterFactory().create();
+        plotter_iter.createRegions(6, 4);
+        plotter_iter.style().dataStyle().fillStyle().setParameter("colorMapScheme", "rainbow");
+        plotter_iter.style().statisticsBoxStyle().setVisible(false);
+        plotter_itercount = af.createPlotterFactory().create();
+        plotter_itercount.createRegions(6, 4);
+
+        plotter_nstripclusters = af.createPlotterFactory().create();
+        plotter_nstripclusters.createRegions(2, 2);
+        plotter_nstripclusters.region(0).plot(_h_nstriphits_top);
+        plotter_nstripclusters.region(1).plot(_h_nstriphits_bottom);
+
+        plotter_trackposodd = af.createPlotterFactory().create();
+        plotter_trackposodd.createRegions(2, 2);
+        //plotter_trackposodd.region(0).plot(_h_trkposodd_top);
+
+        int i = 0;
+        for (SiSensor sensor : this.processSensors) {
+            if (debug) {
+                System.out.println(this.getClass().getSimpleName() + ": " + i + ": adding plot to plotter for " + sensor.getName());
+            }
+            plotter_iter.region(i).plot(this._delta_histos.get(sensor));
+            plotter_iter.style().setParameter("hist2DStyle", "colorMap");
+            plotter_iter.region(i).style().xAxisStyle().setLabel("Iteration");
+            plotter_iter.region(i).style().yAxisStyle().setLabel("<Distance to xp>");
+
+            plotter_itercount.region(i).plot(this._delta_itercount.get(sensor));
+            plotter_itercount.region(i).style().xAxisStyle().setLabel("# iterations");
+            ++i;
[truncated at 1000 lines; 33 more skipped]

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
DataTrackerHitDriver.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/DataTrackerHitDriver.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/DataTrackerHitDriver.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,231 @@
+package org.hps.recon.tracking;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.hps.conditions.deprecated.SvtUtils;
+import org.lcsim.detector.IDetectorElement;
+import org.lcsim.detector.tracker.silicon.SiSensor;
+import org.lcsim.event.EventHeader;
+import org.lcsim.geometry.Detector;
+import org.lcsim.lcio.LCIOUtil;
+import org.lcsim.recon.tracking.digitization.sisim.CDFSiSensorSim;
+import org.lcsim.recon.tracking.digitization.sisim.SiTrackerHit;
+import org.lcsim.recon.tracking.digitization.sisim.SiTrackerHitStrip1D;
+import org.lcsim.util.Driver;
+
+/**
+ *
+ * @author mgraham
+ */
+public class DataTrackerHitDriver extends Driver {
+    // Debug switch for development.
+
+    private boolean debug = false;
+    // Collection name.
+//    private String readoutCollectionName = "TrackerHits";
+    // Subdetector name.
+    private String subdetectorName = "Tracker";
+    // Name of RawTrackerHit output collection.
+//    private String rawTrackerHitOutputCollectionName = "RawTrackerHitMaker_RawTrackerHits";
+    // Name of StripHit1D output collection.
+    private String stripHitOutputCollectionName = "StripClusterer_SiTrackerHitStrip1D";
+    // Clustering parameters.
+    private double clusterSeedThreshold = 4.0;
+    private double clusterNeighborThreshold = 3.0;
+    private double clusterThreshold = 4.0;
+    private int clusterMaxSize = 10;
+    private int clusterCentralStripAveragingThreshold = 4;
+    // Clustering errors by number of TrackerHits.
+    private static final double clusterErrorMultiplier = 1.0;
+    private double oneClusterErr = clusterErrorMultiplier / Math.sqrt(12.);
+    private double twoClusterErr = clusterErrorMultiplier / 5.0;
+    private double threeClusterErr = clusterErrorMultiplier / 3.0;
+    private double fourClusterErr = clusterErrorMultiplier / 2.0;
+    private double fiveClusterErr = clusterErrorMultiplier / 1.0;
+    // Various data lists required by digitization.
+    private List<String> processPaths = new ArrayList<String>();
+    private List<IDetectorElement> processDEs = new ArrayList<IDetectorElement>();
+    private Set<SiSensor> processSensors = new HashSet<SiSensor>();
+    // Digi class objects.
+//    private SiDigitizer stripDigitizer;
+//    private HPSFittedRawTrackerHitMaker hitMaker;
+    private HPSStripMaker stripClusterer;
+    //  private    DumbShaperFit shaperFit;
+    int[][] counts = new int[2][10];
+
+    public void setDebug(boolean debug) {
+        this.debug = debug;
+    }
+
+//    public void setReadoutCollectionName(String readoutCollectionName) {
+//        this.readoutCollectionName = readoutCollectionName;
+//    }
+    public void setSubdetectorName(String subdetectorName) {
+        this.subdetectorName = subdetectorName;
+    }
+
+    public void setStripHitOutputCollectionName(String stripHitOutputCollectionName) {
+        this.stripHitOutputCollectionName = stripHitOutputCollectionName;
+    }
+
+    public void setClusterSeedThreshold(double clusterSeedThreshold) {
+        this.clusterSeedThreshold = clusterSeedThreshold;
+    }
+
+    public void setClusterNeighborThreshold(double clusterNeighborThreshold) {
+        this.clusterNeighborThreshold = clusterNeighborThreshold;
+    }
+
+    public void setClusterThreshold(double clusterThreshold) {
+        this.clusterThreshold = clusterThreshold;
+    }
+
+    public void setClusterMaxSize(int clusterMaxSize) {
+        this.clusterMaxSize = clusterMaxSize;
+    }
+
+    public void setClusterCentralStripAveragingThreshold(int clusterCentralStripAveragingThreshold) {
+        this.clusterCentralStripAveragingThreshold = clusterCentralStripAveragingThreshold;
+    }
+
+    public void setOneClusterErr(double oneClusterErr) {
+        this.oneClusterErr = oneClusterErr;
+    }
+
+    public void setTwoClusterErr(double twoClusterErr) {
+        this.twoClusterErr = twoClusterErr;
+    }
+
+    public void setThreeClusterErr(double threeClusterErr) {
+        this.threeClusterErr = threeClusterErr;
+    }
+
+    public void setFourClusterErr(double fourClusterErr) {
+        this.fourClusterErr = fourClusterErr;
+    }
+
+    public void setFiveClusterErr(double fiveClusterErr) {
+        this.fiveClusterErr = fiveClusterErr;
+    }
+
+    /**
+     * Creates a new instance of TrackerHitDriver.
+     */
+    public DataTrackerHitDriver() {
+    }
+
+    /**
+     * Do initialization once we get a Detector.
+     */
+    @Override
+    public void detectorChanged(Detector detector) {
+
+        // Call sub-Driver's detectorChanged methods.
+        super.detectorChanged(detector);
+
+        // Process detectors specified by path, otherwise process entire
+        // detector
+        IDetectorElement deDetector = detector.getDetectorElement();
+
+        for (String path : processPaths) {
+            processDEs.add(deDetector.findDetectorElement(path));
+        }
+
+        if (processDEs.isEmpty()) {
+            processDEs.add(deDetector);
+        }
+
+        for (IDetectorElement detectorElement : processDEs) {
+            processSensors.addAll(detectorElement.findDescendants(SiSensor.class));
+            //if (debug)
+            //    System.out.println("added " + processSensors.size() + " sensors");
+        }
+
+        // Create the sensor simulation.
+        CDFSiSensorSim stripSim = new CDFSiSensorSim();
+
+
+        // Create Strip clustering algorithm.
+        HPSNearestNeighborRMS stripClusteringAlgo = new HPSNearestNeighborRMS();
+        stripClusteringAlgo.setSeedThreshold(clusterSeedThreshold);
+        stripClusteringAlgo.setNeighborThreshold(clusterNeighborThreshold);
+        stripClusteringAlgo.setClusterThreshold(clusterThreshold);
+
+//         hitMaker=new HPSFittedRawTrackerHitMaker(shaperFit);    
+        // Create the clusterers and set hit-making parameters.
+        stripClusterer = new HPSStripMaker(stripSim, stripClusteringAlgo);
+
+        stripClusterer.setMaxClusterSize(clusterMaxSize);
+        stripClusterer.setCentralStripAveragingThreshold(clusterCentralStripAveragingThreshold);
+
+        // Set the cluster errors.
+        stripClusterer.SetOneClusterErr(oneClusterErr);
+        stripClusterer.SetTwoClusterErr(twoClusterErr);
+        stripClusterer.SetThreeClusterErr(threeClusterErr);
+        stripClusterer.SetFourClusterErr(fourClusterErr);
+        stripClusterer.SetFiveClusterErr(fiveClusterErr);
+
+        // Set the detector to process.
+        processPaths.add(subdetectorName);
+    }
+
+    /**
+     * Perform the digitization.
+     */
+    @Override
+    public void process(EventHeader event) {
+        // Call sub-Driver processing.
+//        super.process(event);
+
+        // Make new lists for output.
+//        List<HPSFittedRawTrackerHit> rawHits = new ArrayList<HPSFittedRawTrackerHit>();
+        List<SiTrackerHit> stripHits1D = new ArrayList<SiTrackerHit>();
+
+//        // Make HPS hits.
+//        for (SiSensor sensor : processSensors) {            
+//            rawHits.addAll(hitMaker.makeHits(sensor));
+//        }
+
+        // Make strip hits.
+        for (SiSensor sensor : processSensors) {
+            stripHits1D.addAll(stripClusterer.makeHits(sensor));
+        }
+
+        // Debug prints.
+        if (debug) {
+//            List<SimTrackerHit> simHits = event.get(SimTrackerHit.class, this.readoutCollectionName);
+//            System.out.println("SimTrackerHit collection " + this.readoutCollectionName + " has " + simHits.size() + " hits.");
+//            System.out.println("RawTrackerHit collection " + this.rawTrackerHitOutputCollectionName + " has " + rawHits.size() + " hits.");
+            System.out.println("TrackerHit collection " + this.stripHitOutputCollectionName + " has " + stripHits1D.size() + " hits.");
+        }
+
+        // Put output hits into collection.
+        int flag = LCIOUtil.bitSet(0, 31, true); // Turn on 64-bit cell ID.
+//        event.put(this.rawTrackerHitOutputCollectionName, rawHits, RawTrackerHit.class, flag, toString());
+        event.put(this.stripHitOutputCollectionName, stripHits1D, SiTrackerHitStrip1D.class, 0, toString());
+        if (debug) {
+            for (int mod = 0; mod < 2; mod++) {
+                for (int layer = 0; layer < 10; layer++) {
+                    counts[mod][layer] += SvtUtils.getInstance().getSensor(mod, layer).getReadout().getHits(SiTrackerHit.class).size();
+                }
+            }
+        }
+        if (debug) {
+            System.out.println("[ DataTrackerHitDriver ] - " + this.stripHitOutputCollectionName + " has " + stripHits1D.size() + " hits.");
+        }
+    }
+
+    @Override
+    public void endOfData() {
+        if (debug) {
+            for (int mod = 0; mod < 2; mod++) {
+                for (int layer = 0; layer < 10; layer++) {
+                    System.out.format("mod %d, layer %d, count %d\n", mod, layer, counts[mod][layer]);
+                }
+            }
+        }
+    }
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
DumbShaperFit.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/DumbShaperFit.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/DumbShaperFit.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,62 @@
+package org.hps.recon.tracking;
+
+import org.hps.conditions.deprecated.HPSSVTCalibrationConstants.ChannelConstants;
+import org.lcsim.event.RawTrackerHit;
+
+/**
+ *
+ * @author mgraham
+ */
+public class DumbShaperFit implements HPSShaperFitAlgorithm {
+
+    public DumbShaperFit() {
+    }    
+    
+    @Override
+    public HPSShapeFitParameters fitShape(RawTrackerHit rth, ChannelConstants constants) {
+    	short[] adcVals = rth.getADCValues();
+    	return this.fitShape(adcVals, constants);    	    	
+    }
+    
+    public HPSShapeFitParameters fitShape(short[] adcVals, ChannelConstants constants){
+    	HPSShapeFitParameters fitresults = new HPSShapeFitParameters();
+        double[] pedSub={-99.0,-99.0,-99.0,-99.0,-99.0,-99.0};
+        double maxADC=-99999;
+        int iMax=-1;
+        double t0=-999;
+        for(int i=0;i<6;i++){
+            pedSub[i]=adcVals[i]-constants.getPedestal();
+            if(pedSub[i]>maxADC){
+               maxADC=pedSub[i];
+               iMax=i;
+            }   
+        }
+        if(iMax>0&&iMax<5){           
+            t0 = (pedSub[iMax-1]*24.0*(iMax-1)+pedSub[iMax]*24.0*(iMax)+pedSub[iMax+1]*24.0*(iMax+1))/(pedSub[iMax-1]+pedSub[iMax]+pedSub[iMax+1]);
+        }else if(iMax==0){
+               t0 =(pedSub[iMax]*24.0*(iMax)+pedSub[iMax+1]*24.0*(iMax+1))/(pedSub[iMax]+pedSub[iMax+1]) ;
+        }else if(iMax==5){
+               t0 =(pedSub[iMax]*24.0*(iMax)+pedSub[iMax-1]*24.0*(iMax-1))/(pedSub[iMax-1]+pedSub[iMax]) ;
+        }
+        
+           //mg...put in a cut here to make sure pulse shape is reasonable
+        //if not, set t0 to -99 (which will fail the later t0>0 cut
+        if(iMax==0||iMax==5)
+            t0=-99;
+        //make sure it goes up below iMax
+        for(int i=0;i<iMax;i++){
+            if(pedSub[i+1]<pedSub[i])
+                t0=-99;
+        }
+        //...and down below iMax
+        for(int i=iMax;i<5;i++){
+            if(pedSub[i+1]>pedSub[i])
+                t0=-99;
+        }                       
+        
+        fitresults.setAmp(maxADC);
+        fitresults.setT0(t0);
+        
+        return fitresults;
+    }
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
EcalTrackMatch.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/EcalTrackMatch.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/EcalTrackMatch.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,142 @@
+package org.hps.recon.tracking;
+
+import hep.physics.vec.Hep3Vector;
+
+import java.util.List;
+
+import org.lcsim.event.Cluster;
+import org.lcsim.event.Track;
+
+/**
+ *
+ * @author phansson
+ */
+public class EcalTrackMatch {
+
+//    public static final double crystalSizeX = (13.3 + 16.0) / 2;
+//    public static final double crystalSizeY = (13.3 + 16.0) / 2;
+//    private double RADIUS = crystalSizeX; 
+//    private String trackCollectionName = "MatchedTracks";
+    Cluster cluster;
+    Track matchedTrack;
+    private boolean debug = false;
+
+    public EcalTrackMatch() {
+        cluster = null;
+        matchedTrack = null;
+    }
+
+    public EcalTrackMatch(boolean deb) {
+        cluster = null;
+        matchedTrack = null;
+        debug = deb;
+
+    }
+
+    public void setDebug(boolean debug) {
+        this.debug = debug;
+    }
+
+    public Track getMatchedTrack() {
+        return matchedTrack;
+    }
+
+    public void setCluster(Cluster cl) {
+        this.cluster = cl;
+    }
+
+    public double dX(Track track) {
+        return dist(track, 0);
+    }
+
+    public double dY(Track track) {
+        return dist(track, 1);
+    }
+
+    public double dist(Track track, int dir) {
+        Hep3Vector trk_pos = TrackUtils.getTrackPositionAtEcal(track);
+        double dx;
+        if (dir == 0) {
+            dx = cluster.getPosition()[0] - trk_pos.x();
+        } else {
+            dx = cluster.getPosition()[1] - trk_pos.y();
+        }
+        if (debug) {
+            System.out.println("dist = " + dx + " from cluster to track in " + (dir == 0 ? "X" : "Y") + " to track at " + trk_pos.x() + "," + trk_pos.y() + "," + trk_pos.z());
+        }
+        return dx;
+    }
+
+    public double dR(Track track) {
+        Hep3Vector trk_pos = TrackUtils.getTrackPositionAtEcal(track);
+        double dx = dX(track);
+        double dy = dY(track);
+        double dr = Math.sqrt(dx * dx + dy * dy);
+        if (debug) {
+            System.out.println("dR = " + dr + " to track at " + trk_pos.toString());
+        }
+        return dr;
+    }
+
+    public void match(List<Track> tracks) {
+        matchedTrack = null;
+        if (debug) {
+            System.out.println("Matching cluster at " + cluster.getPosition()[0] + "," + cluster.getPosition()[1] + "," + cluster.getPosition()[2] + " with " + tracks.size() + " tracks.");
+        }
+        //get the position of the cluster anc compare to tracks at the ecal face
+        double dr;
+//        SeedTrack trk;
+//        Hep3Vector trk_pos;
+        double drmin = 999999.9;
+        for (Track track : tracks) {
+            dr = dR(track);
+            if (dr < drmin) {
+                drmin = dr;
+                matchedTrack = track;
+            }
+        }
+        if (debug) {
+            if (matchedTrack == null) {
+                System.out.println("No matched track was found");
+            } else {
+                System.out.println("Matched a track with dr " + dR(matchedTrack));
+            }
+        }
+    }
+
+    public boolean match(List<Track> tracks, double drmax) {
+        match(tracks);
+        return isMatched(drmax);
+    }
+
+    public boolean isMatched(double rad_max) {
+        if (matchedTrack == null) {
+            return false;
+        }
+        double dr = dR(matchedTrack);
+        return (dr < rad_max ? true : false);
+    }
+
+    public boolean isMatchedY(double max) {
+        if (matchedTrack == null) {
+            return false;
+        }
+        double dy = dY(matchedTrack);
+        return (Math.abs(dy) < max);
+    }
+
+    public double getDistanceToTrack() {
+        return matchedTrack == null ? -1 : dR(matchedTrack);
+
+    }
+
+    public double getDistanceToTrackInX() {
+        return matchedTrack == null ? -1 : dX(matchedTrack);
+
+    }
+
+    public double getDistanceToTrackInY() {
+        return matchedTrack == null ? -1 : dY(matchedTrack);
+
+    }
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
EventQuality.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/EventQuality.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/EventQuality.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,114 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.hps.recon.tracking;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Singleton class to hold default cut values
+ * 
+ * @author Per Hansson Adrian <[log in to unmask]>
+ * @version $id: $ 
+ */
+public class EventQuality {
+    
+    
+    
+    private static EventQuality _instance = null;
+    public static enum Quality{LOOSE,MEDIUM,TIGHT}
+    public static enum Cut{
+        UNDEFINED(0),PZ(1),CHI2(2),SHAREDHIT(3),NHITS(4),TOPBOTHIT(5);
+        private int value;
+        private Cut(int value) {
+            this.value = value;
+        }
+        public int getValue() {
+            return this.value;
+        }
+    }
+    private List<CutObject> _cut_list = new ArrayList<CutObject>();
+    
+    public EventQuality() {
+        addCut(new CutObject(Cut.CHI2,"CHI2",100000.,10.,10.));
+        addCut(new CutObject(Cut.PZ,"PZ",0.000005,0.4,0.4));
+        addCut(new CutObject(Cut.SHAREDHIT,"SHAREDHIT",0,0,0));
+        addCut(new CutObject(Cut.NHITS,"NHITS",4,4,5));
+        addCut(new CutObject(Cut.TOPBOTHIT,"TOPBOTHIT",0,0,0));
+    }
+    
+    public static EventQuality instance() {
+        if(_instance==null) {
+            _instance = new EventQuality();
+        }
+        return _instance;
+    }
+        
+    private void addCut(CutObject c) {
+        _cut_list.add(c);
+    }
+    
+    private CutObject find(Cut cut) {
+        for(CutObject co : _cut_list) {
+            if (co._cut==cut) {
+                return co;
+            }
+        }
+        return null;
+    }
+    
+    public double getCutValue(Cut cut,Quality quality) {
+        CutObject co = find(cut);
+        if(co==null) {
+            System.out.printf("Cut \"%d\" didn't exist!?\n",cut);
+            System.exit(0);
+        }
+        return co.get(quality);
+    }
+    
+    @Override
+    public String toString() {
+        String s = String.format("EventQuality has %d cuts defined:\n",this._cut_list.size());
+        for (CutObject c: _cut_list) {
+            s += String.format("%s\n",c.toString());
+        }
+        return s;
+    }
+    
+    public String print(int cuts) {
+        String s = String.format("cuts=%d:\n",cuts);
+        for (CutObject cut : _cut_list) {
+            int tmp = cuts & (1<<cut._cut.getValue());
+            s += String.format("Cut %s %s\n",cut._name,tmp==0?"PASSED":"FAILED");
+        }
+        return s;
+    }
+    
+    private class CutObject {
+        String _name = "UNDEFINED";
+        Cut _cut = Cut.UNDEFINED;
+        Map<Quality,Double> _map = new HashMap<Quality,Double>();
+        public CutObject(Cut c, String name, double val1,double val2,double val3) {
+            _cut = c;
+            _name = name;
+            _map.put(Quality.LOOSE, val1);
+            _map.put(Quality.MEDIUM, val2);
+            _map.put(Quality.TIGHT, val3);
+        }
+        public void set(Quality q, double val) {
+            _map.put(q,val);
+        }
+        public double get(Quality q) {
+            return _map.get(q);
+        }
+        @Override
+        public String toString() {
+            return String.format("Name:%s cut:%d val=[%f,%f,%f]",_name,_cut.getValue(),_map.get(Quality.LOOSE),_map.get(Quality.MEDIUM),_map.get(Quality.TIGHT));
+        }
+    }
+    
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
FindableTrack.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/FindableTrack.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/FindableTrack.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,343 @@
+/*
+ * FindableTrack.java
+ *
+ * Created on October 24, 2008, 9:50 PM
+ *
+ */
+package org.hps.recon.tracking;
+
+import hep.physics.vec.BasicHep3Vector;
+import hep.physics.vec.Hep3Vector;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.lcsim.detector.DetectorElementStore;
+import org.lcsim.detector.IDetectorElement;
+import org.lcsim.detector.IDetectorElementContainer;
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.MCParticle;
+import org.lcsim.event.RelationalTable;
+import org.lcsim.event.SimTrackerHit;
+import org.lcsim.event.base.BaseRelationalTable;
+import org.lcsim.fit.helicaltrack.HelixParamCalculator;
+import org.lcsim.fit.helicaltrack.HitIdentifier;
+import org.lcsim.geometry.subdetector.BarrelEndcapFlag;
+import org.lcsim.recon.tracking.seedtracker.SeedLayer;
+import org.lcsim.recon.tracking.seedtracker.SeedLayer.SeedType;
+import org.lcsim.recon.tracking.seedtracker.SeedStrategy;
+
+/**
+ *
+ * @author Richard Partridge
+ * @version $Id: FindableTrack.java,v 1.4 2012/11/08 01:22:41 omoreno Exp $
+ */
+public class FindableTrack {
+
+    public enum Ignore {
+        NoPTCut, NoDCACut, NoZ0Cut, NoSeedCheck, NoConfirmCheck, NoMinHitCut
+    };
+    
+    private double _bfield;
+    private RelationalTable<SimTrackerHit, MCParticle> _hittomc;
+    private HitIdentifier _ID;
+    private int _nlayersTot=10;
+    
+    public FindableTrack(EventHeader event, List<SimTrackerHit> simTrackerHits){
+        
+        // Get the magnetic field
+        Hep3Vector IP = new BasicHep3Vector(0., 0., 1.);
+        _bfield = event.getDetector().getFieldMap().getField(IP).y();
+        
+        //  Instantiate the hit identifier class
+        _ID = new HitIdentifier();
+        
+        //  Create a relational table that maps SimTrackerHits to MCParticles
+        _hittomc = new BaseRelationalTable<SimTrackerHit, MCParticle>(RelationalTable.Mode.MANY_TO_MANY, RelationalTable.Weighting.UNWEIGHTED);
+        
+        List<List<SimTrackerHit>> simTrackerHitCollections = new ArrayList<List<SimTrackerHit>>();
+        
+        // If the collection of SimTrackerHits is not specified get the collection from the event.
+        // Otherwise, add the collection to the list of collections to be processed.
+        if(simTrackerHits == null) simTrackerHitCollections.addAll(event.get(SimTrackerHit.class));
+        else simTrackerHitCollections.add(simTrackerHits);
+        
+        //  Loop over the SimTrackerHits and fill in the relational table
+        for (List<SimTrackerHit> simlist : simTrackerHitCollections){
+            for (SimTrackerHit simhit : simlist)
+                if (simhit.getMCParticle() != null)
+                    _hittomc.add(simhit, simhit.getMCParticle());
+        }
+    }
+    
+    public FindableTrack(EventHeader event, List<SimTrackerHit> simTrackerHits, int nLayersTot){
+        this(event, simTrackerHits);
+        this._nlayersTot = nLayersTot;
+    }
+    
+    public FindableTrack(EventHeader event){
+        this(event, null);
+    }
+
+    public FindableTrack(EventHeader event, int nLayersTot){
+        this(event, null, nLayersTot);
+    }
+    
+    public boolean isFindable(MCParticle mcp, List<SeedStrategy> slist, Ignore ignore) {
+        List<Ignore> ignores = new ArrayList<Ignore>();
+        ignores.add(ignore);
+        return isFindable(mcp, slist, ignores);
+    }
+
+    public boolean isFindable(MCParticle mcp, List<SeedStrategy> slist) {
+        return isFindable(mcp, slist, new ArrayList<Ignore>());
+    }
+
+    public boolean isFindable(MCParticle mcp, List<SeedStrategy> slist, List<Ignore> ignores) {
+
+        //  We can't find neutral particles'
+        if (mcp.getCharge() == 0)
+            return false;
+
+        //  Find the helix parameters in the L3 convention used by org.lcsim
+        HelixParamCalculator helix = new HelixParamCalculator(mcp, _bfield);
+
+        //  We haven't yet determined the track is findable
+        boolean findable = false;
+
+        //  Loop over strategies and check if the track is findable
+        for (SeedStrategy strat : slist) {
+
+            //  Check the MC Particle's pT
+            if (!CheckPT(helix, ignores, strat))
+                continue;
+
+            //  Check the MC Particle's DCA
+            if (!CheckDCA(helix, ignores, strat))
+                continue;
+
+            //  Check the MC Particle's Z0
+            if (!CheckZ0(helix, ignores, strat))
+                continue;
+
+            //  Check that we have hits on the seed layers
+            if (!CheckSeed(mcp, ignores, strat))
+                continue;
+
+            //  Check that we have the required confirmation hits
+            if (!CheckConfirm(mcp, ignores, strat))
+                continue;
+
+            //  Check for the minimum number of hits
+            if (!CheckMinHits(mcp, ignores, strat))
+                continue;
+
+            //  Passed all the checks - track is findable
+            findable = true;
+            break;
+        }
+
+        return findable;
+    }
+
+    public int LayersHit(MCParticle mcp) {
+
+        //  Get the list of hits associated with the MCParticle
+        Set<SimTrackerHit> hitlist = _hittomc.allTo(mcp);
+
+        //  Create a set of the identifiers for the hit layers
+        Set<String> idset = new HashSet<String>();
+
+        //  Create the set of identifiers
+        for (SimTrackerHit simhit : hitlist) {
+
+            String identifier_old = _ID.Identifier(getDetectorElement(simhit));
+            String identifier = _ID.Identifier(simhit);
+            if (!idset.contains(identifier))
+                idset.add(identifier);
+        }
+
+        return idset.size();
+    }
+    
+    public boolean isTrackFindable(MCParticle mcParticle, int nLayers){
+        
+        if(nLayers%2 == 1) throw new RuntimeException(this.getClass().getSimpleName() + ": The required number of layers hit must be even");
+        
+        // A neutral particle can't be found
+        if(mcParticle.getCharge() == 0) return false;
+        
+        // Get the list of SimTrackerHits associated with the MC particle
+        Set<SimTrackerHit> simHits = _hittomc.allTo(mcParticle);
+        
+        // Find the layers hit
+        boolean[] layerHit = new boolean[_nlayersTot];
+        for(SimTrackerHit simHit : simHits){
+            layerHit[simHit.getLayer()-1] = true;
+        }
+        
+        int nLayersHit = 0;
+        // Check how many pairs of layers were hit
+        for(int index = 0; index < _nlayersTot; index += 2){
+            if(layerHit[index] && layerHit[index+1]) nLayersHit += 2; 
+        }
+        
+        return nLayersHit >= nLayers;
+    }
+    
+    public Set<SimTrackerHit> getSimTrackerHits(MCParticle mcParticle){
+        return _hittomc.allTo(mcParticle);
+    }
+    
+    public boolean InnerTrackerIsFindable(MCParticle mcp, int nlayers, boolean printout) {
+        Set<SimTrackerHit> hitlist = _hittomc.allTo(mcp);
+        boolean[] layerHit={false,false,false,false,false,false,false,false,false,false,false,false};
+        for (SimTrackerHit simhit : hitlist) {
+            layerHit[simhit.getLayer()-1]=true;
+        }
+        for(int i=0;i<nlayers;i++){
+            System.out.println(layerHit[i]);
+            if(layerHit[i]==false)return false;
+        }
+        return true;
+    }
+
+       public boolean InnerTrackerIsFindable(MCParticle mcp, int nlayers) {
+        Set<SimTrackerHit> hitlist = _hittomc.allTo(mcp);
+        boolean[] layerHit={false,false,false,false,false,false,false,false,false,false,false,false};
+        for (SimTrackerHit simhit : hitlist) {
+            layerHit[simhit.getLayer()-1]=true;
+        }
+        for(int i=0;i<nlayers;i++){
+            if(layerHit[i]==false)return false;
+        }
+        return true;
+    }
+
+      public boolean OuterTrackerIsFindable(MCParticle mcp, int start) {
+        Set<SimTrackerHit> hitlist = _hittomc.allTo(mcp);
+        boolean[] layerHit={false,false,false,false,false,false,false,false,false,false,false,false};
+        for (SimTrackerHit simhit : hitlist) {
+            layerHit[simhit.getLayer()-1]=true;
+        }
+        for(int i=start;i<_nlayersTot;i++){
+            if(layerHit[i]==false)return false;
+        }
+        return true;
+    }
+
+    private boolean CheckPT(HelixParamCalculator helix, List<Ignore> ignores, SeedStrategy strat) {
+
+        //  First see if we are skipping this check
+        if (ignores.contains(Ignore.NoPTCut))
+            return true;
+
+        return helix.getMCTransverseMomentum() >= strat.getMinPT();
+    }
+
+    private boolean CheckDCA(HelixParamCalculator helix, List<Ignore> ignores, SeedStrategy strat) {
+
+        //  First see if we are skipping this check
+        if (ignores.contains(Ignore.NoDCACut))
+            return true;
+
+        return Math.abs(helix.getDCA()) <= strat.getMaxDCA();
+    }
+
+    private boolean CheckZ0(HelixParamCalculator helix, List<Ignore> ignores, SeedStrategy strat) {
+
+        //  First see if we are skipping this check
+        if (ignores.contains(Ignore.NoZ0Cut))
+            return true;
+
+        return Math.abs(helix.getZ0()) <= strat.getMaxZ0();
+    }
+
+    private boolean CheckSeed(MCParticle mcp, List<Ignore> ignores, SeedStrategy strat) {
+
+        //  First see if we are skipping this check
+        if (ignores.contains(Ignore.NoSeedCheck))
+            return true;
+
+        return HitCount(mcp, strat.getLayers(SeedType.Seed)) == 3;
+    }
+
+    private boolean CheckConfirm(MCParticle mcp, List<Ignore> ignores, SeedStrategy strat) {
+
+        //  First see if we are skipping this check
+        if (ignores.contains(Ignore.NoConfirmCheck))
+            return true;
+
+        return HitCount(mcp, strat.getLayers(SeedType.Confirm)) >= strat.getMinConfirm();
+    }
+
+    private boolean CheckMinHits(MCParticle mcp, List<Ignore> ignores, SeedStrategy strat) {
+
+        //  First see if we are skipping this check
+        if (ignores.contains(Ignore.NoMinHitCut))
+            return true;
+
+        return HitCount(mcp, strat.getLayerList()) >= strat.getMinHits();
+    }
+
+    private int HitCount(MCParticle mcp, List<SeedLayer> lyrlist) {
+
+        //  Get the list of hits associated with the MCParticle
+        Set<SimTrackerHit> hitlist = _hittomc.allTo(mcp);
+
+        //  Count the number of layers with hits in them
+        int hitcount = 0;
+        for (SeedLayer lyr : lyrlist)
+            //  Loop over the hits for this MCParticle
+            for (SimTrackerHit simhit : hitlist) {
+
+                //  Get the detector element for this hit
+//                IDetectorElement de = getDetectorElement(simhit);
+
+                //  Check names
+//                String detname_old = _ID.getName(de);
+                String detname_new = simhit.getSubdetector().getName();
+                //               if (!detname_old.equals(detname_new)) {
+                //                   System.out.println("Detector name mismatch - old: "+detname_old+ " new: "+detname_new);
+                //               }
+                //               int layer_old = _ID.getLayer(de);
+                int layer_new = simhit.getLayer();
+                //               if (layer_old != layer_new) {
+                //                   System.out.println("Layer number mismatch - old: "+layer_old+" new: "+layer_new);
+                //               }
+//                BarrelEndcapFlag be_old = _ID.getBarrelEndcapFlag(de);
+                BarrelEndcapFlag be_new = simhit.getBarrelEndcapFlag();
+                //               if (!be_old.equals(be_new)) {
+                //                   System.out.println("BarrelEndcapFlag mismatch - old: "+be_old+" new: "+be_new);
+                //               }
+
+                //  See if this hit is on the layer we are checking
+//               if (!lyr.getDetName().equals(_ID.getName(de))) continue;
+//                if (lyr.getLayer() != _ID.getLayer(de)) continue;
+//                if (!lyr.getBarrelEndcapFlag().equals(_ID.getBarrelEndcapFlag(de)))
+//                    continue;
+                if (!lyr.getDetName().equals(detname_new))
+                    continue;
+                if (lyr.getLayer() != layer_new)
+                    continue;
+                if (!lyr.getBarrelEndcapFlag().equals(be_new))
+                    continue;
+                hitcount++;
+                break;
+            }
+
+        return hitcount;
+    }
+
+    private IDetectorElement getDetectorElement(SimTrackerHit hit) {
+        IDetectorElementContainer cont = DetectorElementStore.getInstance().find(hit.getIdentifier());
+        IDetectorElement de;
+        if (cont.isEmpty())
+            throw new RuntimeException("Detector Container is empty!");
+        else
+            de = cont.get(0);
+        return de;
+    }
+}
\ No newline at end of file

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
FpgaData.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/FpgaData.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/FpgaData.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,197 @@
+package org.hps.recon.tracking;
+
+//--- java ---//
+import static org.hps.conditions.deprecated.HPSSVTConstants.ADC_TEMP_COUNT;
+import static org.hps.conditions.deprecated.HPSSVTConstants.BETA;
+import static org.hps.conditions.deprecated.HPSSVTConstants.CONST_A;
+import static org.hps.conditions.deprecated.HPSSVTConstants.MAX_TEMP;
+import static org.hps.conditions.deprecated.HPSSVTConstants.MIN_TEMP;
+import static org.hps.conditions.deprecated.HPSSVTConstants.R_DIV;
+import static org.hps.conditions.deprecated.HPSSVTConstants.TEMP_INC;
+import static org.hps.conditions.deprecated.HPSSVTConstants.TEMP_K0;
+import static org.hps.conditions.deprecated.HPSSVTConstants.TEMP_MASK;
+import static org.hps.conditions.deprecated.HPSSVTConstants.V_MAX;
+import static org.hps.conditions.deprecated.HPSSVTConstants.V_REF;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+//--- org.lcsim ---//
+import org.lcsim.event.GenericObject;
+//-- Constants ---//
+
+/**
+ * Generic object to contain hybrid temperatures and data tail value. Converts
+ * and ADC value to a temperature in celsius
+ *
+ * @author Omar Moreno <[log in to unmask]>
+ * @version $Id: FpgaData.java,v 1.3 2012/08/16 01:06:30 meeg Exp $
+ */
+public class FpgaData implements GenericObject {
+
+    int fpgaID;
+    List<Double> temperatures = new ArrayList<Double>();
+    int tail;
+    private static double[] temperatureTable = null;
+
+    /**
+     *
+     * @param temperature : array containing hybrid temperatures
+     * @param tail : word present at the end of a FPGA data set
+     */
+    public FpgaData(int fpgaID, int[] data, int tail) {
+        this.fpgaID = fpgaID;
+
+        int[] temperature = extractTemperature(data);
+
+        // Fill the temperature lookup table
+        fillTemperatureTable();
+
+        this.tail = tail;
+
+        // Fill the temperature list
+        for (int index = 0; index < temperature.length; index++) {
+            temperatures.add(intToTemperature(temperature[index]));
+        }
+    }
+
+    public FpgaData(int fpgaID, double[] temperatures, int tail) {
+        this.fpgaID = fpgaID;
+
+        this.tail = tail;
+
+        this.temperatures.clear();
+        // Fill the temperature list
+        for (int index = 0; index < temperatures.length; index++) {
+            this.temperatures.add(temperatures[index]);
+        }
+    }
+
+    /**
+     * Extract temperatures from the SVT data stream
+     *
+     * @param data : array containing temperature data
+     * @return temperatures
+     *
+     */
+    public static int[] extractTemperature(int[] data) {
+        int[] temperatures = new int[(data.length) * 2];
+
+        int tempIndex = 0;
+        for (int index = 0; index < data.length; index++) {
+            temperatures[tempIndex] = data[index] & TEMP_MASK;
+            temperatures[tempIndex + 1] = (data[index] >>> 16) & TEMP_MASK;
+            tempIndex += 2;
+        }
+        return temperatures;
+    }
+
+    /**
+     * Temperature lookup table. Takes an ADC value and returns a temperature in
+     * Celsius
+     */
+    private static void fillTemperatureTable() {
+
+        if (temperatureTable == null) {
+            temperatureTable = new double[ADC_TEMP_COUNT];
+
+            double tempK, res, volt;
+            int idx;
+            double temp = MIN_TEMP;
+
+            while (temp < MAX_TEMP) {
+
+                tempK = TEMP_K0 + temp;
+                res = CONST_A * Math.exp(BETA / tempK);
+                volt = (res * V_MAX) / (R_DIV + res);
+                idx = (int) ((volt / V_REF) * (double) (ADC_TEMP_COUNT - 1));
+                if (idx < ADC_TEMP_COUNT) {
+                    temperatureTable[idx] = temp;
+                }
+                temp += TEMP_INC;
+            }
+        }
+    }
+
+    public static double intToTemperature(int tempIndex) {
+        fillTemperatureTable();
+        return temperatureTable[tempIndex];
+    }
+
+    public static int temperatureToInt(double temperature) {
+        fillTemperatureTable();
+        return Math.abs(Arrays.binarySearch(temperatureTable, temperature));
+    }
+
+    public int[] extractData() {
+        fillTemperatureTable();
+
+        int[] header = new int[(temperatures.size() + 1) / 2];
+        for (int i = 0; i < temperatures.size(); i++) {
+            if (i % 2 == 0) {
+                header[i / 2] = (header[i / 2] &= ~TEMP_MASK) | (temperatureToInt(temperatures.get(i)) & TEMP_MASK);
+            } else {
+                header[i / 2] = (header[i / 2] &= ~(TEMP_MASK << 16)) | ((temperatureToInt(temperatures.get(i)) & TEMP_MASK) << 16);
+            }
+        }
+        return header;
+    }
+
+    public int getFpga() {
+        return fpgaID;
+    }
+
+    public int getTail() {
+        return tail;
+    }
+
+    /**
+     * Get the temperature at a given index
+     */
+    @Override
+    public double getDoubleVal(int index) {
+        return temperatures.get(index);
+    }
+
+    @Override
+    public float getFloatVal(int index) {
+        return 0;
+    }
+
+    /**
+     * Get the tail value
+     */
+    @Override
+    public int getIntVal(int index) {
+        switch (index) {
+            case 0:
+                return getFpga();
+            case 1:
+                return getTail();
+            default:
+                throw new ArrayIndexOutOfBoundsException(index);
+        }
+    }
+
+    @Override
+    public int getNDouble() {
+        return temperatures.size();
+    }
+
+    @Override
+    public int getNFloat() {
+        return 0;
+    }
+
+    @Override
+    public int getNInt() {
+        return 2;
+    }
+
+    @Override
+    public boolean isFixedSize() {
+        return false;
+    }
+;
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
HPSClusteringAlgorithm.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/HPSClusteringAlgorithm.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/HPSClusteringAlgorithm.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,25 @@
+package org.hps.recon.tracking;
+
+import java.util.List;
+
+/**
+ *
+ * @author mgraham
+ */
+
+
+public interface HPSClusteringAlgorithm {
+
+    /**
+     * Finds the clusters given a list of RawTrackerHits on a particular
+     * silicon sensor with electrodes given by SiSensorElectrodes.  A list
+     * of clusters is returned, with each cluster being a list of RawTrackerHits
+     * the form the cluster.
+     *
+     * @param hits base hits
+     * @return list of clusters, with each cluster being a list of RawTrackerHits
+     */
+    public List<List<HPSFittedRawTrackerHit>> findClusters(
+             List<HPSFittedRawTrackerHit> hits);
+
+}
\ No newline at end of file

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
HPSFittedRawTrackerHit.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/HPSFittedRawTrackerHit.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/HPSFittedRawTrackerHit.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,37 @@
+package org.hps.recon.tracking;
+
+import org.lcsim.event.RawTrackerHit;
+import org.lcsim.event.base.BaseLCRelation;
+
+/**
+ *
+ * @author meeg
+ * @version $Id: HPSFittedRawTrackerHit.java,v 1.3 2013/04/16 22:05:43 phansson Exp $
+ */
+public class HPSFittedRawTrackerHit extends BaseLCRelation {
+
+	public HPSFittedRawTrackerHit(RawTrackerHit hit, HPSShapeFitParameters fit) {
+		super(hit, fit);
+	}
+
+	public RawTrackerHit getRawTrackerHit() {
+		return (RawTrackerHit) getFrom();
+	}
+
+	public HPSShapeFitParameters getShapeFitParameters() {
+		return (HPSShapeFitParameters) getTo();
+	}
+
+	public double getT0() {
+		return getShapeFitParameters().getT0();
+	}
+
+	public double getAmp() {
+		return getShapeFitParameters().getAmp();
+	}
+        
+        @Override
+        public String toString() {
+            return String.format("HPSFittedRawTrackerHit: hit cell id %d on sensor %s with fit %s\n",this.getRawTrackerHit().getCellID(),getRawTrackerHit().getDetectorElement().getName(),this.getShapeFitParameters().toString());
+        }
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
HPSNearestNeighborRMS.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/HPSNearestNeighborRMS.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/HPSNearestNeighborRMS.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,258 @@
+package org.hps.recon.tracking;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.hps.conditions.deprecated.HPSSVTCalibrationConstants;
+import org.hps.conditions.deprecated.HPSSVTConstants;
+import org.lcsim.detector.identifier.IIdentifier;
+import org.lcsim.detector.tracker.silicon.SiSensor;
+import org.lcsim.detector.tracker.silicon.SiTrackerIdentifierHelper;
+import org.lcsim.event.RawTrackerHit;
+
+/**
+ *
+ * @author mgraham
+ */
+public class HPSNearestNeighborRMS implements HPSClusteringAlgorithm {
+
+    private static String _NAME = "NearestNeighborRMS";
+    private double _seed_threshold;
+    private double _neighbor_threshold;
+    private double _cluster_threshold;
+    private double _meanTime = 24;
+    private double _timeWindow = 48;
+    private double _maxChisq = 20.0;
+
+    /**
+     * Instantiate NearestNeighborRMS with specified thresholds.
+     * Seed threshold is the minimum charge to initiate a cluster.  Neighbor
+     * threshold is the minimum charge to add a neighboring cell to a cluster.
+     * Cluster threshold is minimum charge of the entire cluster.
+     * All thresholds are in units of RMS noise of the channel(s).
+     *
+     * @param seed_threshold seed threshold
+     * @param neighbor_threshold neighbor threshold
+     * @param cluster_threshold cluster threshold
+     */
+    public HPSNearestNeighborRMS(double seed_threshold, double neighbor_threshold, double cluster_threshold) {
+        _seed_threshold = seed_threshold;
+        _neighbor_threshold = neighbor_threshold;
+        _cluster_threshold = cluster_threshold;
+    }
+
+    /**
+     * Instantiate NearestNeighborRMS with default thresholds:
+     *
+     * seed_threshold = 4*RMS noise
+     * neighbor_threshold = 3*RMS noise
+     * cluster_threshold = 4*RMS noise
+     */
+    public HPSNearestNeighborRMS() {
+        this(4.0, 3.0, 4.0);
+    }
+
+    /**
+     * Set the seed threshold.  Units are RMS noise.
+     *
+     * @param seed_threshold seed threshold
+     */
+    public void setSeedThreshold(double seed_threshold) {
+        _seed_threshold = seed_threshold;
+    }
+
+    /**
+     * Set the neighbor threshold.  Units are RMS noise.
+     *
+     * @param neighbor_threshold neighbor threshold
+     */
+    public void setNeighborThreshold(double neighbor_threshold) {
+        _neighbor_threshold = neighbor_threshold;
+    }
+
+    /**
+     * Set the cluster threshold.  Units are RMS noise.
+     *
+     * @param cluster_threshold cluster threshold
+     */
+    public void setClusterThreshold(double cluster_threshold) {
+        _cluster_threshold = cluster_threshold;
+    }
+
+    /**
+     * Find clusters using the nearest neighbor algorithm.
+     *    
+     * @param base_hits List of RawTrackerHits to be clustered
+     * @return list of clusters, with a cluster being a list of RawTrackerHits
+     */
+    @Override
+    public List<List<HPSFittedRawTrackerHit>> findClusters(List<HPSFittedRawTrackerHit> base_hits) {
+
+        //  Check that the seed threshold is at least as large as  the neighbor threshold
+        if (_seed_threshold < _neighbor_threshold) {
+            throw new RuntimeException("Tracker hit clustering error: seed threshold below neighbor threshold");
+        }
+
+        //  Create maps that show the channel status and relate the channel number to the raw hit and vice versa
+        int mapsize = 2 * base_hits.size();
+        Map<Integer, Boolean> clusterable = new HashMap<Integer, Boolean>(mapsize);
+        Map<HPSFittedRawTrackerHit, Integer> hit_to_channel = new HashMap<HPSFittedRawTrackerHit, Integer>(mapsize);
+        Map<Integer, HPSFittedRawTrackerHit> channel_to_hit = new HashMap<Integer, HPSFittedRawTrackerHit>(mapsize);
+
+        //  Create list of channel numbers to be used as cluster seeds
+        List<Integer> cluster_seeds = new ArrayList<Integer>();
+
+        //  Loop over the raw hits and construct the maps used to relate cells and hits, initialize the
+        //  clustering status map, and create a list of possible cluster seeds
+        for (HPSFittedRawTrackerHit base_hit : base_hits) {
+
+            RawTrackerHit rth = base_hit.getRawTrackerHit();
+            // get the channel number for this hit
+            SiTrackerIdentifierHelper sid_helper = (SiTrackerIdentifierHelper) rth.getIdentifierHelper();
+            IIdentifier id = rth.getIdentifier();
+            int channel_number = sid_helper.getElectrodeValue(id);
+
+            //  Check for duplicate RawTrackerHit
+            if (hit_to_channel.containsKey(base_hit)) {
+                throw new RuntimeException("Duplicate hit: " + id.toString());
+            }
+
+            //  Check for duplicate RawTrackerHits or channel numbers
+            if (channel_to_hit.containsKey(channel_number)) {
+//                throw new RuntimeException("Duplicate channel number: "+channel_number);
+                System.out.println("Duplicate channel number: " + channel_number);
+            }
+
+            //  Add this hit to the maps that relate channels and hits
+            hit_to_channel.put(base_hit, channel_number);
+            channel_to_hit.put(channel_number, base_hit);
+
+            //  Get the signal from the readout chip
+            double signal = base_hit.getAmp();
+            double noiseRMS = HPSSVTCalibrationConstants.getNoise((SiSensor) rth.getDetectorElement(), channel_number);
+            double time = base_hit.getT0();
+            //  Mark this hit as available for clustering if it is above the neighbor threshold
+            clusterable.put(channel_number, signal / noiseRMS >= _neighbor_threshold);
+
+            //  Add this hit to the list of seeds if it is above the seed threshold
+            if (signal / noiseRMS >= _seed_threshold && passTimingCut(base_hit) && passChisqCut(base_hit)) {
+                cluster_seeds.add(channel_number);
+            }
+        }
+
+        //  Create a list of clusters
+        List<List<HPSFittedRawTrackerHit>> cluster_list = new ArrayList<List<HPSFittedRawTrackerHit>>();
+
+        //  Now loop over the cluster seeds to form clusters
+        for (int seed_channel : cluster_seeds) {
+
+            //  First check if this hit is still available for clustering
+            if (!clusterable.get(seed_channel)) {
+                continue;
+            }
+
+            //  Create a new cluster
+            List<HPSFittedRawTrackerHit> cluster = new ArrayList<HPSFittedRawTrackerHit>();
+            double cluster_signal = 0.;
+            double cluster_noise_squared = 0.;
+
+            //  Create a queue to hold channels whose neighbors need to be checked for inclusion
+            LinkedList<Integer> unchecked = new LinkedList<Integer>();
+
+            //  Add the seed channel to the unchecked list and mark it as unavailable for clustering
+            unchecked.addLast(seed_channel);
+            clusterable.put(seed_channel, false);
+
+            //  Check the neighbors of channels added to the cluster
+            while (unchecked.size() > 0) {
+
+                //  Pull the next channel off the queue and add it's hit to the cluster
+                int clustered_cell = unchecked.removeFirst();
+                cluster.add(channel_to_hit.get(clustered_cell));
+                cluster_signal += channel_to_hit.get(clustered_cell).getAmp();
+                cluster_noise_squared += Math.pow(HPSSVTCalibrationConstants.getNoise((SiSensor) (channel_to_hit.get(clustered_cell)).getRawTrackerHit().getDetectorElement(), clustered_cell), 2);
+//                cluster_noise_squared +=0;  //need to get the noise from the calib. const. class
+                //  Get the neigbor channels
+//                Set<Integer> neighbor_channels = electrodes.getNearestNeighborCells(clustered_cell);
+                Set<Integer> neighbor_channels = getNearestNeighborCells(clustered_cell);
+
+                //   Now loop over the neighbors and see if we can add them to the cluster
+                for (int channel : neighbor_channels) {
+
+                    //  Get the status of this channel
+                    Boolean addhit = clusterable.get(channel);
+
+                    //  If the map entry is null, there is no raw hit for this channel
+                    if (addhit == null) {
+                        continue;
+                    }
+
+                    //  Check if this neighbor channel is still available for clustering
+                    if (!addhit) {
+                        continue;
+                    }
+
+                    //  Add channel to the list of unchecked clustered channels
+                    //  and mark it unavailable for clustering
+                    unchecked.addLast(channel);
+                    clusterable.put(channel, false);
+
+                }  // end of loop over neighbor cells
+            }  // end of loop over unchecked cells
+
+            //  Finished with this cluster, check cluster threshold and add it to the list of clusters
+            if (cluster.size() > 0
+                    && cluster_signal / Math.sqrt(cluster_noise_squared) > _cluster_threshold) {
+                cluster_list.add(cluster);
+            }
+
+        }  //  End of loop over seeds
+
+        //  Finished finding clusters
+        return cluster_list;
+    }
+
+    private boolean passTimingCut(HPSFittedRawTrackerHit hit) {
+
+        boolean pass = false;
+        double time = hit.getT0();
+        if (Math.abs(time - _meanTime) < _timeWindow) {
+            pass = true;
+        }
+
+        return pass;
+    }
+
+    private boolean passChisqCut(HPSFittedRawTrackerHit hit) {
+        return hit.getShapeFitParameters().getChiSq() < _maxChisq;
+    }
+
+    public int getNeighborCell(int cell, int ncells_0, int ncells_1) {
+        int neighbor_cell = cell + ncells_0;
+        if (isValidCell(neighbor_cell)) {
+            return neighbor_cell;
+        } else {
+            return -1;
+        }
+    }
+
+    public Set<Integer> getNearestNeighborCells(int cell) {
+        Set<Integer> neighbors = new HashSet<Integer>();
+        for (int ineigh = -1; ineigh <= 1; ineigh = ineigh + 2) {
+            int neighbor_cell = getNeighborCell(cell, ineigh, 0);
+            if (isValidCell(neighbor_cell)) {
+                neighbors.add(neighbor_cell);
+            }
+        }
+        return neighbors;
+    }
+
+    public boolean isValidCell(int cell) {
+        return (cell >= 0 && cell < HPSSVTConstants.TOTAL_STRIPS_PER_SENSOR);
+    }
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
HPSRawTrackerHitFitterDriver.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/HPSRawTrackerHitFitterDriver.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/HPSRawTrackerHitFitterDriver.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,116 @@
+package org.hps.recon.tracking;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.hps.conditions.deprecated.HPSSVTCalibrationConstants;
+import org.hps.conditions.deprecated.HPSSVTCalibrationConstants.ChannelConstants;
+import org.hps.conditions.deprecated.HPSSVTConstants;
+import org.hps.readout.ecal.ReadoutTimestamp;
+import org.lcsim.detector.tracker.silicon.SiSensor;
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.RawTrackerHit;
+import org.lcsim.lcio.LCIOConstants;
+import org.lcsim.util.Driver;
+
+/**
+ *
+ * @author mgraham
+ */
+public class HPSRawTrackerHitFitterDriver extends Driver {
+
+    private boolean debug = false;
+    private HPSShaperFitAlgorithm _shaper = new DumbShaperFit();
+    private String rawHitCollectionName = "SVTRawTrackerHits";
+    private String fitCollectionName = "SVTShapeFitParameters";
+    private String fittedHitCollectionName = "SVTFittedRawTrackerHits";
+    private int genericObjectFlags = 1 << LCIOConstants.GOBIT_FIXED;
+    private int relationFlags = 0;
+    private boolean correctT0Shift = false;
+    private boolean useTimestamps = false;
+
+    public void setDebug(boolean debug) {
+        this.debug = debug;
+    }
+
+    public void setCorrectT0Shift(boolean correctT0Shift) {
+        this.correctT0Shift = correctT0Shift;
+    }
+
+    public void setUseTimestamps(boolean useTimestamps) {
+        this.useTimestamps = useTimestamps;
+    }
+
+    public void setFitAlgorithm(String fitAlgorithm) {
+        if (fitAlgorithm.equals("Analytic")) {
+            _shaper = new HPSShaperAnalyticFitAlgorithm();
+        } else {
+            throw new RuntimeException("Unrecognized fitAlgorithm: " + fitAlgorithm);
+        }
+    }
+
+    public void setFitCollectionName(String fitCollectionName) {
+        this.fitCollectionName = fitCollectionName;
+    }
+
+    public void setFittedHitCollectionName(String fittedHitCollectionName) {
+        this.fittedHitCollectionName = fittedHitCollectionName;
+    }
+
+    public void setRawHitCollectionName(String rawHitCollectionName) {
+        this.rawHitCollectionName = rawHitCollectionName;
+    }
+
+    @Override
+    public void startOfData() {
+        if (rawHitCollectionName == null) {
+            throw new RuntimeException("The parameter ecalCollectionName was not set!");
+        }
+    }
+
+    @Override
+    public void process(EventHeader event) {
+        if (!event.hasCollection(RawTrackerHit.class, rawHitCollectionName)) {
+            //System.out.println(rawHitCollectionName + " does not exist; skipping event");
+            return;
+        }
+
+        List<RawTrackerHit> rawHits = event.get(RawTrackerHit.class, rawHitCollectionName);
+        if (rawHits == null) {
+            throw new RuntimeException("Event is missing SVT hits collection!");
+        }
+        List<HPSFittedRawTrackerHit> hits = new ArrayList<HPSFittedRawTrackerHit>();
+        List<HPSShapeFitParameters> fits = new ArrayList<HPSShapeFitParameters>();
+
+        //  Make a fitted hit from this cluster
+        for (RawTrackerHit hit : rawHits) {
+            int strip = hit.getIdentifierFieldValue("strip");
+            ChannelConstants constants = HPSSVTCalibrationConstants.getChannelConstants((SiSensor) hit.getDetectorElement(), strip);
+            HPSShapeFitParameters fit = _shaper.fitShape(hit, constants);
+            if (correctT0Shift) {
+                double corMod = 0;
+                if (useTimestamps) {
+                    double t0Svt = ReadoutTimestamp.getTimestamp(ReadoutTimestamp.SYSTEM_TRACKER, event);
+                    double t0Trig = ReadoutTimestamp.getTimestamp(ReadoutTimestamp.SYSTEM_TRIGGER, event);
+                    corMod += (t0Svt - t0Trig);
+                }
+                corMod -= constants.getT0Shift();
+                fit.setT0(fit.getT0() + corMod);
+//                fit.setT0(fit.getT0() - constants.getT0Shift());
+
+            }
+            if (debug) {
+                System.out.println(fit);
+            }
+            fits.add(fit);
+            HPSFittedRawTrackerHit hth = new HPSFittedRawTrackerHit(hit, fit);
+            hits.add(hth);
+            if (strip == HPSSVTConstants.TOTAL_STRIPS_PER_SENSOR) { //drop unbonded channel
+                continue;
+            }
+            hit.getDetectorElement().getReadout().addHit(hth);
+        }
+        event.put(fitCollectionName, fits, HPSShapeFitParameters.class, genericObjectFlags);
+        event.put(fittedHitCollectionName, hits, HPSFittedRawTrackerHit.class, relationFlags);
+    }
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
HPSSVTData.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/HPSSVTData.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/HPSSVTData.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,307 @@
+package org.hps.recon.tracking;
+
+//--- Constants ---//
+
+import static org.hps.conditions.deprecated.HPSSVTConstants.APV_MASK;
+import static org.hps.conditions.deprecated.HPSSVTConstants.CHANNEL_MASK;
+import static org.hps.conditions.deprecated.HPSSVTConstants.FPGA_MASK;
+import static org.hps.conditions.deprecated.HPSSVTConstants.HYBRID_MASK;
+import static org.hps.conditions.deprecated.HPSSVTConstants.SAMPLE_MASK;
+import static org.hps.conditions.deprecated.HPSSVTConstants.TEMP_MASK;
+import static org.hps.conditions.deprecated.HPSSVTConstants.TOTAL_APV25_CHANNELS;
+import static org.hps.conditions.deprecated.HPSSVTConstants.TOTAL_APV25_PER_HYBRID;
+import static org.hps.conditions.deprecated.HPSSVTConstants.TOTAL_NUMBER_OF_SAMPLES;
+
+/**
+ *
+ *
+ * @author Omar Moreno <[log in to unmask]>
+ * @version $Id: HPSSVTData.java,v 1.8 2012/08/16 01:06:30 meeg Exp $
+ */
+public class HPSSVTData {
+
+    // 4x32 
+    int[] data = new int[4];
+    // Time of the hit
+    int hitTime = 0;
+
+    /**
+     *
+     * Creates an SVT data packet from
+     *
+     * @param hybridNumber Hybrid number (0-3)
+     * @param apvNumber APV25 chip number (0-4)
+     * @param channelNumber Sensor strip number (0-127)
+     * @param fpgaAddress FPGA address
+     * @param adc ADC samples obtained by sampling the shaper output. Currently,
+     * six samples are obtained per raw hit.
+     */
+    public HPSSVTData(int hybridNumber, int apvNumber,
+            int channelNumber, int fpgaAddress, short[] adc) {
+        this.createSVTDataPacket(hybridNumber, apvNumber,
+                channelNumber, fpgaAddress, adc);
+    }
+
+    /**
+     * Creates and SVT data packet from existing SVT data
+     *
+     * @param data The packed data as int array of size 4
+     */
+    public HPSSVTData(int[] data) {
+        if (data.length != 4) {
+            throw new RuntimeException("Data sample size is not valid!");
+        }
+
+        this.data = data;
+    }
+
+    /**
+     * Get the packed data for this sample
+     *
+     * @return sample The packed data as an int array of size 4.
+     */
+    public int[] getData() {
+        return data;
+    }
+
+    /**
+     * Creates and SVT data packet
+     */
+    private void createSVTDataPacket(int hybridNumber, int apvNumber,
+            int channelNumber, int fpgaAddress, short[] adc) {
+        createSVTDataPacket(hybridNumber, apvNumber, channelNumber, fpgaAddress, adc, data);
+    }
+
+    public static void createSVTDataPacket(int hybridNumber, int apvNumber,
+            int channelNumber, int fpgaAddress, short[] adc, int[] data) {
+        /*
+         * Sample Data consists of the following: Z[xx:xx] = Zeros, O[xx:xx] =
+         * Ones data[0] = O[0], Z[0], Hybrid[1:0], Z[0], ApvChip[2:0], Z[0],
+         * Channel[6:0], FpgaAddress[15:0] data[1] = Z[1:0], Sample1[13:0]],
+         * Z[1:0], Sample0[13:0] data[2] = Z[1:0], Sample3[13:0]], Z[1:0],
+         * Sample2[13:0] data[3] = Z[1:0], Sample5[13:0]], Z[1:0], Sample4[13:0]
+         *
+         */
+
+        //--- data[0] ---//
+        //-----------------//
+
+        // The most significant digit of data[0] is set to 1
+        data[0] |= 0x80000000;
+
+        // Insert the hybrid number
+        data[0] = (data[0] &= ~(HYBRID_MASK << 28)) | ((hybridNumber & HYBRID_MASK) << 28);
+
+        // Insert the APV number
+        data[0] = (data[0] &= ~(APV_MASK << 24)) | ((apvNumber & APV_MASK) << 24);
+
+        // Insert the channel number
+        data[0] = (data[0] &= ~(CHANNEL_MASK << 16)) | ((channelNumber & CHANNEL_MASK) << 16);
+
+        // Insert the FPGA address
+        data[0] = (data[0] &= ~FPGA_MASK) | (fpgaAddress & FPGA_MASK);
+
+
+        //--- data[1] ----//
+        //------------------//
+
+        // Add data 0
+        data[1] = (data[1] &= ~SAMPLE_MASK) | (adc[0] & SAMPLE_MASK);
+
+        // Add data 1
+        data[1] = (data[1] &= ~(SAMPLE_MASK << 16)) | ((adc[1] & SAMPLE_MASK) << 16);
+
+
+
+        //--- data[2] ----//
+        //------------------//
+
+        // Add sample 2
+        data[2] = (data[2] &= ~SAMPLE_MASK) | (adc[2] & SAMPLE_MASK);
+
+
+        // Add sample 3
+        data[2] = (data[2] &= ~(SAMPLE_MASK << 16)) | ((adc[3] & SAMPLE_MASK) << 16);
+
+
+        //--- data[3] ----//
+        //------------------//
+
+        // Add sample 4
+        data[3] = (data[3] &= ~SAMPLE_MASK) | (adc[4] & SAMPLE_MASK);
+
+
+        // Add sample 5
+        data[3] = (data[3] &= ~(SAMPLE_MASK << 16)) | ((adc[5] & SAMPLE_MASK) << 16);
+    }
+
+    /**
+     * Get the hybrid number associated with this SVT data packet
+     *
+     * @return hybrid number (0-3)
+     */
+    public int getHybridNumber() {
+        return getHybridNumber(data);
+    }
+
+    public static int getHybridNumber(int[] data) {
+        return (data[0] >>> 28) & HYBRID_MASK;
+    }
+
+    /**
+     * Get the APV number associated with this SVT data packet
+     *
+     * @return APV number (0-4)
+     */
+    public int getAPVNumber() {
+        return getAPVNumber(data);
+    }
+
+    public static int getAPVNumber(int[] data) {
+        return (data[0] >>> 24) & APV_MASK;
+    }
+
+    /**
+     * Get the channel number associated with this SVT data packet
+     *
+     * @return channel number (0-127)
+     */
+    public int getChannelNumber() {
+        return getChannelNumber(data);
+    }
+
+    public static int getChannelNumber(int[] data) {
+        return (data[0] >>> 16) & CHANNEL_MASK;
+    }
+
+    /**
+     * Get the FPGA address associated with this SVT data packet
+     *
+     * @return FPGA address
+     */
+    public int getFPGAAddress() {
+        return getFPGAAddress(data);
+    }
+
+    public static int getFPGAAddress(int[] data) {
+        return data[0] & FPGA_MASK;
+    }
+
+    /**
+     * Get the nth SVT sample
+     *
+     * @param n The sample number of interest. Valid values are 0 to 5
+     * @throws RuntimeException if the sample number is out of range
+     * @return ADC value of the nth sample
+     *
+     *
+     */
+    public int getSample(int n) {
+        return getSample(n, data);
+    }
+
+    public static int getSample(int n, int[] data) {
+
+        switch (n) {
+            case 0:
+                return data[1] & SAMPLE_MASK;
+            case 1:
+                return (data[1] >>> 16) & SAMPLE_MASK;
+            case 2:
+                return data[2] & SAMPLE_MASK;
+            case 3:
+                return (data[2] >>> 16) & SAMPLE_MASK;
+            case 4:
+                return data[3] & SAMPLE_MASK;
+            case 5:
+                return (data[3] >>> 16) & SAMPLE_MASK;
+            default:
+                throw new RuntimeException("Invalid sample number! Valid range of values for n are from 0 - 5");
+        }
+    }
+
+    /**
+     * Get all SVT samples
+     *
+     * @return An array containing all SVT Shaper signal samples
+     */
+    public short[] getAllSamples() {
+        return getAllSamples(data);
+    }
+
+    public static short[] getAllSamples(int[] data) {
+        short[] samples = new short[TOTAL_NUMBER_OF_SAMPLES];
+        // Get all SVT Samples
+        for (int index = 0; index < TOTAL_NUMBER_OF_SAMPLES; index++) {
+            samples[index] = (short) getSample(index, data);
+        }
+
+        return samples;
+    }
+
+    /**
+     * Get the hit time at which the hit occurred
+     *
+     * @return The time at which the hit occurred with respect to the trigger
+     */
+    public int getHitTime() {
+        return hitTime;
+    }
+
+    /**
+     * Set the hit time at which the hit occurred
+     *
+     * @param hitTime : Time at which the hit occurred
+     */
+    public void setHitTime(int hitTime) {
+        this.hitTime = hitTime;
+    }
+
+    /**
+     *
+     */
+    public static double[] getTemperature(int[] data) {
+        double[] temperatures = new double[(data.length) * 2];
+
+        int tempIndex = 0;
+        for (int index = 0; index < data.length; index++) {
+            temperatures[tempIndex] = data[index] & TEMP_MASK;
+            temperatures[tempIndex + 1] = (data[index] >>> 16) & TEMP_MASK;
+            tempIndex += 2;
+        }
+
+        return temperatures;
+    }
+
+    /**
+     * Get the sensor (a k a physical) channel corresponding to a raw chip channel
+     *
+     * @param apv : APV25 chip number
+     * @param channel : APV25 raw channel number
+     *
+     * @return sensor channel number
+     */
+    public static int getSensorChannel(int apv, int channel) {
+        int sensorChannel = (TOTAL_APV25_PER_HYBRID - apv - 1) * TOTAL_APV25_CHANNELS + channel;
+        if (sensorChannel < 0 || sensorChannel >= TOTAL_APV25_PER_HYBRID * TOTAL_APV25_CHANNELS) {
+            throw new RuntimeException("sensor channel " + sensorChannel + " is outside of valid range! APV " + apv + ", channel " + channel);
+        }
+        return sensorChannel;
+    }
+
+    public static int getAPV(int sensorChannel) {
+        return TOTAL_APV25_PER_HYBRID - (sensorChannel / TOTAL_APV25_CHANNELS) - 1;
+    }
+
+    public static int getAPVChannel(int sensorChannel) {
+        return sensorChannel % TOTAL_APV25_CHANNELS;
+    }
+
+    public static int getSensorChannel(int[] data) {
+        return getSensorChannel(getAPVNumber(data), getChannelNumber(data));
+    }
+
+    public int getSensorChannel() {
+        return getSensorChannel(data);
+    }
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
HPSShapeFitParameters.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/HPSShapeFitParameters.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/HPSShapeFitParameters.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,144 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.hps.recon.tracking;
+
+import org.lcsim.event.GenericObject;
+
+/**
+ *
+ * @author mgraham
+ */
+public class HPSShapeFitParameters implements GenericObject {
+
+    private double _t0 = Double.NaN;
+    private double _t0Err = Double.NaN;
+    private double _amp = Double.NaN;
+    private double _ampErr = Double.NaN;
+    private double _tp = Double.NaN;
+    private double _tpErr = Double.NaN;
+    private double _chiSq = Double.NaN;
+
+    public HPSShapeFitParameters() {
+    }
+
+    public HPSShapeFitParameters(double t0, double amplitude) {
+        _t0 = t0;
+        _amp = amplitude;
+    }
+
+    public void setT0(double t0) {
+        _t0 = t0;
+    }
+
+    public void setAmp(double amp) {
+        _amp = amp;
+    }
+
+    public void setTp(double tp) {
+        _tp = tp;
+    }
+
+    public void setAmpErr(double _ampErr) {
+        this._ampErr = _ampErr;
+    }
+
+    public void setT0Err(double _t0Err) {
+        this._t0Err = _t0Err;
+    }
+
+    public void setTpErr(double _tpErr) {
+        this._tpErr = _tpErr;
+    }
+
+    public void setChiSq(double _chiSq) {
+        this._chiSq = _chiSq;
+    }
+
+    public double getT0() {
+        return _t0;
+    }
+
+    public double getAmp() {
+        return _amp;
+    }
+
+    public double getTp() {
+        return _tp;
+    }
+
+    public double getT0Err() {
+        return _t0Err;
+    }
+
+    public double getAmpErr() {
+        return _ampErr;
+    }
+
+    public double getTpErr() {
+        return _tpErr;
+    }
+
+    public double getChiSq() {
+        return _chiSq;
+    }
+
+    @Override
+    public int getNInt() {
+        return 0;
+    }
+
+    @Override
+    public int getNFloat() {
+        return 0;
+    }
+
+    @Override
+    public int getNDouble() {
+        return 7;
+    }
+
+    @Override
+    public int getIntVal(int index) {
+        throw new UnsupportedOperationException("No int values in " + this.getClass().getSimpleName());
+    }
+
+    @Override
+    public float getFloatVal(int index) {
+        throw new UnsupportedOperationException("No int values in " + this.getClass().getSimpleName());
+    }
+
+    @Override
+    public double getDoubleVal(int index) {
+        switch (index) {
+            case 0:
+                return _t0;
+            case 1:
+                return _t0Err;
+            case 2:
+                return _amp;
+            case 3:
+                return _ampErr;
+            case 4:
+                return _tp;
+            case 5:
+                return _tpErr;
+            case 6:
+                return _chiSq;
+            default:
+                throw new UnsupportedOperationException("Only 7 double values in " + this.getClass().getSimpleName());
+        }
+
+    }
+
+    @Override
+    public boolean isFixedSize() {
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("chisq=%f\tA=%f\tAerr=%f\tT0=%f\tT0err=%f", _chiSq, _amp, _ampErr, _t0, _t0Err);
+    }
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
HPSShaperAnalyticFitAlgorithm.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/HPSShaperAnalyticFitAlgorithm.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/HPSShaperAnalyticFitAlgorithm.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,106 @@
+package org.hps.recon.tracking;
+
+import org.hps.conditions.deprecated.HPSSVTCalibrationConstants.ChannelConstants;
+import org.hps.conditions.deprecated.HPSSVTConstants;
+import org.lcsim.event.RawTrackerHit;
+//import org.lcsim.math.chisq.ChisqProb;
+
+/**
+ * Fast fitter; currently only fits single hits. Uses Tp from ChannelConstants;
+ * fits values and errors for T0 and amplitude.
+ *
+ * @author meeg
+ * @version $Id: HPSShaperAnalyticFitAlgorithm.java,v 1.4 2012/04/25 18:01:32
+ * mgraham Exp $
+ */
+public class HPSShaperAnalyticFitAlgorithm implements HPSShaperFitAlgorithm {
+
+    @Override
+    public HPSShapeFitParameters fitShape(RawTrackerHit rth, ChannelConstants constants) {
+        short[] samples = rth.getADCValues();
+        return this.fitShape(samples, constants);
+    }
+
+    public HPSShapeFitParameters fitShape(short[] samples, ChannelConstants constants) {
+        double minChisq = Double.POSITIVE_INFINITY;
+        int bestStart = 0;
+        HPSShapeFitParameters fit = new HPSShapeFitParameters();
+        for (int i = 0; i < samples.length - 2; i++) {
+            double chisq = fitSection(samples, constants, fit, i);
+//            System.out.println("i = " + i + ", " + fit);
+            if (chisq < minChisq) {
+                minChisq = chisq;
+                bestStart = i;
+            }
+        }
+        fitSection(samples, constants, fit, bestStart);
+//        System.out.format("%f\t%f\t%f\t%f\t%f\t%f\n", samples[0] - constants.getPedestal(), samples[1] - constants.getPedestal(), samples[2] - constants.getPedestal(), samples[3] - constants.getPedestal(), samples[4] - constants.getPedestal(), samples[5] - constants.getPedestal());
+//        System.out.println("start = " + bestStart + ", " + fit);
+        return fit;
+    }
+
+    private double fitSection(short[] samples, ChannelConstants constants, HPSShapeFitParameters fit, int start) {
+        int length = samples.length - start;
+        double[] y = new double[length];
+        double[] t = new double[length];
+
+        for (int i = 0; i < length; i++) {
+            y[i] = samples[start + i] - constants.getPedestal();
+            t[i] = HPSSVTConstants.SAMPLING_INTERVAL * i;
+        }
+
+        double[] p = new double[length];
+        double[] a = new double[length];
+        for (int i = 0; i < length; i++) {
+            p[i] = y[i] / constants.getNoise();
+            a[i] = Math.exp(1 - t[i] / constants.getTp()) / (constants.getTp() * constants.getNoise());
+        }
+
+        double pa, aatt, pat, aat, aa;
+        pa = 0;
+        aatt = 0;
+        pat = 0;
+        aat = 0;
+        aa = 0;
+        for (int i = 0; i < length; i++) {
+            pa += p[i] * a[i];
+            aatt += a[i] * a[i] * t[i] * t[i];
+            pat += p[i] * a[i] * t[i];
+            aat += a[i] * a[i] * t[i];
+            aa += a[i] * a[i];
+        }
+
+        double t0 = (pa * aatt - pat * aat) / (pa * aat - aa * pat);
+        double A = pa / ((Math.exp(t0 / constants.getTp()) * (aat - t0 * aa)));
+
+        double time_var = 0;
+        double height_var = 0;
+        for (int i = 0; i < length; i++) {
+            double dt_dp = a[i] * (aatt - t[i] * aat - t0 * (aat - t[i] * aa)) / (pa * aat - aa * pat);
+            double dh_dp = (a[i] * Math.exp(-1.0 * t0 / constants.getTp()) + A * dt_dp * aa) / (aat - t0 * aa) - A * dt_dp / constants.getTp();
+            time_var += dt_dp * dt_dp;
+            height_var += dh_dp * dh_dp;
+        }
+        t0 += HPSSVTConstants.SAMPLING_INTERVAL * start;
+        fit.setAmp(A);
+        fit.setAmpErr(Math.sqrt(height_var));
+        fit.setT0(t0);
+        fit.setT0Err(Math.sqrt(time_var));
+        fit.setTp(constants.getTp());
+
+        double chisq = 0;
+        for (int i = 0; i < samples.length; i++) {
+            double ti = HPSSVTConstants.SAMPLING_INTERVAL * i;
+            double fit_y = A * (Math.max(0, (ti - t0)) / constants.getTp()) * Math.exp(1 - (ti - t0) / constants.getTp()) + constants.getPedestal();
+            chisq += Math.pow((fit_y - samples[i]) / constants.getNoise(), 2);
+        }
+        fit.setChiSq(chisq);
+
+        if (A > 0) {
+//			return ChisqProb.gammp(samples.length - 2, chisq);
+            return chisq / (samples.length - 2);
+        } else {
+            return Double.POSITIVE_INFINITY;
+        }
+    }
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
HPSShaperFitAlgorithm.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/HPSShaperFitAlgorithm.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/HPSShaperFitAlgorithm.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,18 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.hps.recon.tracking;
+
+import org.hps.conditions.deprecated.HPSSVTCalibrationConstants.ChannelConstants;
+import org.lcsim.event.RawTrackerHit;
+
+/**
+ *
+ * @author mgraham
+ */
+public interface HPSShaperFitAlgorithm {
+    
+    public HPSShapeFitParameters fitShape(RawTrackerHit rth, ChannelConstants constants);
+
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
HPSStripMaker.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/HPSStripMaker.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/HPSStripMaker.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,353 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.hps.recon.tracking;
+
+import hep.physics.matrix.SymmetricMatrix;
+import hep.physics.vec.BasicHep3Vector;
+import hep.physics.vec.Hep3Vector;
+import hep.physics.vec.VecOp;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.lcsim.detector.IDetectorElement;
+import org.lcsim.detector.IReadout;
+import org.lcsim.detector.identifier.IIdentifier;
+import org.lcsim.detector.tracker.silicon.ChargeCarrier;
+import org.lcsim.detector.tracker.silicon.DopedSilicon;
+import org.lcsim.detector.tracker.silicon.SiSensor;
+import org.lcsim.detector.tracker.silicon.SiSensorElectrodes;
+import org.lcsim.detector.tracker.silicon.SiStrips;
+import org.lcsim.detector.tracker.silicon.SiTrackerIdentifierHelper;
+import org.lcsim.event.RawTrackerHit;
+import org.lcsim.recon.tracking.digitization.sisim.SiSensorSim;
+import org.lcsim.recon.tracking.digitization.sisim.SiTrackerHit;
+import org.lcsim.recon.tracking.digitization.sisim.SiTrackerHitStrip1D;
+import org.lcsim.recon.tracking.digitization.sisim.TrackerHitType;
+
+/**
+ *
+ * @author mgraham
+ */
+public class HPSStripMaker {
+
+    private static String _NAME = "HPSStripClusterer";
+    // Clustering algorithm
+    HPSClusteringAlgorithm _clustering;
+    // Number of strips beyond which charge is averaged on center strips
+    int _max_noaverage_nstrips = 4;
+    // Absolute maximum cluster size
+    int _max_cluster_nstrips = 10;
+    // Sensor simulation needed to correct for Lorentz drift
+    SiSensorSim _simulation;
+    // Identifier helper (reset once per sensor)
+    SiTrackerIdentifierHelper _sid_helper;    
+    // Temporary map connecting hits to strip numbers for sake of speed (reset once per sensor)
+    Map<HPSFittedRawTrackerHit, Integer> _strip_map = new HashMap<HPSFittedRawTrackerHit, Integer>();
+    double _oneClusterErr = 1 / Math.sqrt(12);
+    double _twoClusterErr = 1 / 5;
+    double _threeClusterErr = 1 / 3;
+    double _fourClusterErr = 1 / 2;
+    double _fiveClusterErr = 1;
+    
+    boolean _debug = false;
+    
+    public HPSStripMaker(HPSClusteringAlgorithm algo) {
+        _clustering = algo;
+    }
+
+    public HPSStripMaker(SiSensorSim simulation, HPSClusteringAlgorithm algo) {
+        _clustering = algo;
+        _simulation = simulation;
+    }
+
+    public String getName() {
+        return _NAME;
+    }
+
+    // Make hits for all sensors within a DetectorElement
+    public List<SiTrackerHit> makeHits(IDetectorElement detector) {
+        System.out.println("makeHits(IDetectorElement): " + detector.getName());
+        List<SiTrackerHit> hits = new ArrayList<SiTrackerHit>();
+        List<SiSensor> sensors = detector.findDescendants(SiSensor.class);
+
+        // Loop over all sensors
+        for (SiSensor sensor : sensors) {
+            if (sensor.hasStrips()) {
+                hits.addAll(makeHits(sensor));
+            }
+        }
+
+        // Return hit list
+        return hits;
+    }
+
+    // Make hits for a sensor
+    public List<SiTrackerHit> makeHits(SiSensor sensor) {
+
+        //System.out.println("makeHits: " + sensor.getName());
+
+        List<SiTrackerHit> hits = new ArrayList<SiTrackerHit>();
+
+        // Get SiTrackerIdentifierHelper for this sensor and refresh the strip map used to increase speed
+        _sid_helper = (SiTrackerIdentifierHelper) sensor.getIdentifierHelper();
+        _strip_map.clear();
+
+        // Get hits for this sensor
+        IReadout ro = sensor.getReadout();
+        List<HPSFittedRawTrackerHit> hps_hits = ro.getHits(HPSFittedRawTrackerHit.class);
+
+        Map<SiSensorElectrodes, List<HPSFittedRawTrackerHit>> electrode_hits = new HashMap<SiSensorElectrodes, List<HPSFittedRawTrackerHit>>();
+
+        for (HPSFittedRawTrackerHit hps_hit : hps_hits) {
+
+            // get id and create strip map, get electrodes.
+            IIdentifier id = hps_hit.getRawTrackerHit().getIdentifier();
+            _strip_map.put(hps_hit, _sid_helper.getElectrodeValue(id));
+
+            // Get electrodes and check that they are strips
+            //System.out.println("proc raw hit from: " + DetectorElementStore.getInstance().find(raw_hit.getIdentifier()).get(0).getName());
+            ChargeCarrier carrier = ChargeCarrier.getCarrier(_sid_helper.getSideValue(id));
+            SiSensorElectrodes electrodes = ((SiSensor) hps_hit.getRawTrackerHit().getDetectorElement()).getReadoutElectrodes(carrier);
+            if (!(electrodes instanceof SiStrips)) {
+                continue;
+            }
+
+            if (electrode_hits.get(electrodes) == null) {
+                electrode_hits.put(electrodes, new ArrayList<HPSFittedRawTrackerHit>());
+            }
+
+            electrode_hits.get(electrodes).add(hps_hit);
+        }
+
+        for (Map.Entry entry : electrode_hits.entrySet()) {
+            hits.addAll(makeHits(sensor, (SiStrips) entry.getKey(), (List<HPSFittedRawTrackerHit>) entry.getValue()));
+        }
+
+        return hits;
+    }
+
+    public List<SiTrackerHit> makeHits(SiSensor sensor, SiSensorElectrodes electrodes, List<HPSFittedRawTrackerHit> hps_hits) {
+
+
+
+        //  Call the clustering algorithm to make clusters
+        List<List<HPSFittedRawTrackerHit>> cluster_list = _clustering.findClusters(hps_hits);
+
+        //  Create an empty list for the pixel hits to be formed from clusters
+        List<SiTrackerHit> hits = new ArrayList<SiTrackerHit>();
+
+        //  Make a pixel hit from this cluster
+        for (List<HPSFittedRawTrackerHit> cluster : cluster_list) {
+
+            // Make a TrackerHit from the cluster if it meets max cluster size requirement
+            if (cluster.size() <= _max_cluster_nstrips) {
+                SiTrackerHitStrip1D hit = makeTrackerHit(cluster, electrodes);
+                // Add to readout and to list of hits
+//                ((SiSensor) electrodes.getDetectorElement()).getReadout().addHit(hit);
+                hits.add(hit);
+                sensor.getReadout().addHit(hit);
+            }
+        }
+
+        return hits;
+    }
+
+    public void SetOneClusterErr(double err) {
+        _oneClusterErr = err;
+    }
+
+    public void SetTwoClusterErr(double err) {
+        _twoClusterErr = err;
+    }
+
+    public void SetThreeClusterErr(double err) {
+        _threeClusterErr = err;
+    }
+
+    public void SetFourClusterErr(double err) {
+        _fourClusterErr = err;
+    }
+
+    public void SetFiveClusterErr(double err) {
+        _fiveClusterErr = err;
+    }
+
+    public void setCentralStripAveragingThreshold(int max_noaverage_nstrips) {
+        _max_noaverage_nstrips = max_noaverage_nstrips;
+    }
+
+    public void setMaxClusterSize(int max_cluster_nstrips) {
+        _max_cluster_nstrips = max_cluster_nstrips;
+    }
+
+    private SiTrackerHitStrip1D makeTrackerHit(List<HPSFittedRawTrackerHit> cluster, SiSensorElectrodes electrodes) {
+        if(_debug) System.out.println(this.getClass().getSimpleName() + " makeTrackerHit ");
+        Hep3Vector position = getPosition(cluster, electrodes);
+        SymmetricMatrix covariance = getCovariance(cluster, electrodes);
+        double time = getTime(cluster);
+        double energy = getEnergy(cluster);
+        TrackerHitType type = new TrackerHitType(TrackerHitType.CoordinateSystem.GLOBAL, TrackerHitType.MeasurementType.STRIP_1D);
+        List<RawTrackerHit> rth_cluster = new ArrayList<RawTrackerHit>();
+        for (HPSFittedRawTrackerHit bth : cluster) {
+            rth_cluster.add(bth.getRawTrackerHit());
+        }
+        SiTrackerHitStrip1D hit = new SiTrackerHitStrip1D(position, covariance, energy, time, rth_cluster, type);
+        if(_debug) System.out.println(this.getClass().getSimpleName() + " SiTrackerHitStrip1D created at " + position + "(" + hit.getPositionAsVector().toString()+")" + " E " + energy + " time " + time);
+        return hit;
+    }
+
+    private Hep3Vector getPosition(List<HPSFittedRawTrackerHit> cluster, SiSensorElectrodes electrodes) {
+        if(_debug) System.out.println(this.getClass().getSimpleName() + " getPosition for cluster size " + cluster.size());
+        List<Double> signals = new ArrayList<Double>();
+        List<Hep3Vector> positions = new ArrayList<Hep3Vector>();
+
+        if(_debug) System.out.println(this.getClass().getSimpleName() + " Loop of " + cluster.size() + " and add signals and positions to vectors");
+        
+        for (HPSFittedRawTrackerHit hit : cluster) {
+            signals.add(hit.getAmp());
+            positions.add(((SiStrips) electrodes).getStripCenter(_strip_map.get(hit)));
+            if(_debug) System.out.println(this.getClass().getSimpleName() + " Added hit with signal " + hit.getAmp() + " at strip center posiiton " + (((SiStrips) electrodes).getStripCenter(_strip_map.get(hit))));
+        }
+
+        // Average charge on central strips of longer clusters
+        if (signals.size() > _max_noaverage_nstrips) {
+            int nstrips_center = signals.size() - 2;
+
+            // collect sum of charges on center strips
+            double center_charge_sum = 0.0;
+            for (int istrip = 1; istrip < signals.size() - 1; istrip++) {
+                center_charge_sum += signals.get(istrip);
+            }
+
+            // distribute evenly on center strips
+            double center_charge_strip = center_charge_sum / nstrips_center;
+            for (int istrip = 1; istrip < signals.size() - 1; istrip++) {
+                signals.set(istrip, center_charge_strip);
+            }
+        }
+
+        if(_debug) System.out.println(this.getClass().getSimpleName() + " Calculate charge weighted mean for " + signals.size() + " signals");
+        
+        double total_charge = 0;
+        Hep3Vector position = new BasicHep3Vector(0, 0, 0);
+
+        for (int istrip = 0; istrip < signals.size(); istrip++) {
+            double signal = signals.get(istrip);
+
+            total_charge += signal;
+            position = VecOp.add(position, VecOp.mult(signal, positions.get(istrip)));
+            if(_debug) System.out.println(this.getClass().getSimpleName() + "strip " + istrip+": signal " + signal + " position " + positions.get(istrip) + " -> total_position " + position.toString() + " ( total charge " + total_charge + ")");
+            
+        }
+        position = VecOp.mult(1 / total_charge, position);
+        if(_debug) System.out.println(this.getClass().getSimpleName() + " charge weighted position "+position.toString() + " (before trans)");
+        electrodes.getParentToLocal().inverse().transform(position);
+        if(_debug) System.out.println(this.getClass().getSimpleName() + " charge weighted position "+position.toString() + " (after trans)");
+        
+        // Swim position back through lorentz drift direction to midpoint between bias surfaces
+        if(_simulation!=null) {
+            _simulation.setSensor((SiSensor) electrodes.getDetectorElement());
+            _simulation.lorentzCorrect(position, electrodes.getChargeCarrier());
+            if(_debug) System.out.println(this.getClass().getSimpleName() + ": Position " + position.toString() + " ( after Lorentz)");
+        }
+        
+        // return position in global coordinates
+        Hep3Vector newpos = ((SiSensor) electrodes.getDetectorElement()).getGeometry().getLocalToGlobal().transformed(position);
+        if(_debug) System.out.println(this.getClass().getSimpleName() + " final cluster position "+newpos.toString());
+        
+        return ((SiSensor) electrodes.getDetectorElement()).getGeometry().getLocalToGlobal().transformed(position);
+//        return electrodes.getLocalToGlobal().transformed(position);
+    }
+
+    private double getTime(List<HPSFittedRawTrackerHit> cluster) {
+        int time_sum = 0;
+        int signal_sum = 0;
+
+        for (HPSFittedRawTrackerHit hit : cluster) {
+
+            double signal = hit.getAmp();
+            double time = hit.getT0();
+
+            time_sum += time * signal;
+            signal_sum += signal;
+
+        }
+        return (double) time_sum / (double) signal_sum;
+    }
+
+    private SymmetricMatrix getCovariance(List<HPSFittedRawTrackerHit> cluster, SiSensorElectrodes electrodes) {
+        SymmetricMatrix covariance = new SymmetricMatrix(3);
+        covariance.setElement(0, 0, Math.pow(getMeasuredResolution(cluster, electrodes), 2));
+        covariance.setElement(1, 1, Math.pow(getUnmeasuredResolution(cluster, electrodes), 2));
+        covariance.setElement(2, 2, 0.0);
+
+        SymmetricMatrix covariance_global = electrodes.getLocalToGlobal().transformed(covariance);
+
+//        System.out.println("Global covariance matrix: \n"+covariance_global);
+
+        return covariance_global;
+
+//        BasicHep3Matrix rotation_matrix = (BasicHep3Matrix)electrodes.getLocalToGlobal().getRotation().getRotationMatrix();
+//        BasicHep3Matrix rotation_matrix_transposed = new BasicHep3Matrix(rotation_matrix);
+//        rotation_matrix_transposed.transpose();
+//
+////        System.out.println("Rotation matrix: \n"+rotation_matrix);
+////        System.out.println("Rotation matrix transposed: \n"+rotation_matrix_transposed);
+////        System.out.println("Local covariance matrix: \n"+covariance);
+//
+//        BasicHep3Matrix covariance_global = (BasicHep3Matrix)VecOp.mult(rotation_matrix,VecOp.mult(covariance,rotation_matrix_transposed));
+//
+////        System.out.println("Global covariance matrix: \n"+covariance_global);
+//
+//        return new SymmetricMatrix((Matrix)covariance_global);
+    }
+
+    private double getMeasuredResolution(List<HPSFittedRawTrackerHit> cluster, SiSensorElectrodes electrodes) // should replace this by a ResolutionModel class that gives expected resolution.  This could be a big job.
+    {
+        double measured_resolution;
+
+        double sense_pitch = ((SiSensor) electrodes.getDetectorElement()).getSenseElectrodes(electrodes.getChargeCarrier()).getPitch(0);
+
+//        double readout_pitch = electrodes.getPitch(0);
+//        double noise = _readout_chip.getChannel(strip_number).computeNoise(electrodes.getCapacitance(strip_number));
+//        double signal_expected = (0.000280/DopedSilicon.ENERGY_EHPAIR) *
+//                ((SiSensor)electrodes.getDetectorElement()).getThickness(); // ~280 KeV/mm for thick Si sensors
+
+        if (cluster.size() == 1) {
+            measured_resolution = sense_pitch * _oneClusterErr;
+        } else if (cluster.size() == 2) {
+            measured_resolution = sense_pitch * _twoClusterErr;
+        } else if (cluster.size() == 3) {
+            measured_resolution = sense_pitch * _threeClusterErr;
+        } else if (cluster.size() == 4) {
+            measured_resolution = sense_pitch * _fourClusterErr;
+        } else {
+            measured_resolution = sense_pitch * _fiveClusterErr;
+        }
+
+        return measured_resolution;
+    }
+
+    private double getUnmeasuredResolution(List<HPSFittedRawTrackerHit> cluster, SiSensorElectrodes electrodes) {
+        // Get length of longest strip in hit
+        double hit_length = 0;
+        for (HPSFittedRawTrackerHit hit : cluster) {
+            hit_length = Math.max(hit_length, ((SiStrips) electrodes).getStripLength(_strip_map.get(hit)));
+        }
+        return hit_length / Math.sqrt(12);
+    }
+
+    private double getEnergy(List<HPSFittedRawTrackerHit> cluster) {
+        double total_charge = 0.0;
+        for (HPSFittedRawTrackerHit hit : cluster) {
+            double signal = hit.getAmp();
+            total_charge += signal;
+        }
+        return total_charge * DopedSilicon.ENERGY_EHPAIR;
+    }
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
HPSTrack.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/HPSTrack.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/HPSTrack.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,524 @@
+package org.hps.recon.tracking;
+
+import static org.lcsim.constants.Constants.fieldConversion;
+import hep.physics.matrix.SymmetricMatrix;
+import hep.physics.vec.BasicHep3Vector;
+import hep.physics.vec.Hep3Vector;
+import hep.physics.vec.VecOp;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.hps.conditions.deprecated.BeamSpot;
+import org.hps.conditions.deprecated.FieldMap;
+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;
+import org.lcsim.util.swim.Helix;
+import org.lcsim.util.swim.Line;
+import org.lcsim.util.swim.Trajectory;
+
+/**
+ * Class HPSTrack: extension of HelicalTrackFit to include HPS-specific
+ * variables other useful things.
+ *
+ * @author mgraham created on 6/27/2011
+ */
+public class HPSTrack extends HelicalTrackFit {
+
+    private BeamSpot _beam;
+    //all of the variables defined below are in the jlab (detector) frame
+    //this position & momentum are measured at the DOCA to the Y-axis,
+    //which is where the tracking returns it's parameters by default
+    private Hep3Vector _pDocaY;
+    private Hep3Vector _posDocaY;
+    //the position & momentum of the track at the intersection of the target (z=0)
+    private Hep3Vector _pTarget;
+    private Hep3Vector _posTarget;
+    //the position & momentum of the track at DOCA to the beam axis (z)
+    private Hep3Vector _pDocaZ;
+    private Hep3Vector _posDocaZ;
+    private double bField = 0.491;  //  make this set-able
+    private boolean _debug = false;
+    private boolean _debugForward = false;
+    private Trajectory _trajectory;
+    Map<Pair<Integer, Integer>, Double> _fieldMap;
+    Map<Pair<Integer, Integer>, Pair<Double, Double>> _fieldBins;
+    private MCParticle mcParticle;
+
+    public HPSTrack(double[] pars, SymmetricMatrix cov, double[] chisq, int[] ndf,
+            Map<HelicalTrackHit, Double> smap, Map<HelicalTrackHit, MultipleScatter> msmap,
+            BeamSpot beam) {
+        super(pars, cov, chisq, ndf, smap, msmap);
+        _beam = beam;
+        calculateParametersAtTarget();
+        calculateParametersAtDocaY();
+        calculateParametersAtDocaZ();
+    }
+
+    public HPSTrack(double[] pars, SymmetricMatrix cov, double[] chisq, int[] ndf,
+            Map<HelicalTrackHit, Double> smap, Map<HelicalTrackHit, MultipleScatter> msmap) {
+        super(pars, cov, chisq, ndf, smap, msmap);
+        calculateParametersAtTarget();
+        calculateParametersAtDocaY();
+        calculateParametersAtDocaZ();
+    }
+
+    public HPSTrack(HelicalTrackFit htf, BeamSpot beam) {
+        super(htf.parameters(), htf.covariance(), htf.chisq(), htf.ndf(), htf.PathMap(), htf.ScatterMap());
+        _beam = beam;
+        calculateParametersAtTarget();
+        calculateParametersAtDocaY();
+        calculateParametersAtDocaZ();
+    }
+
+    public HPSTrack(HelicalTrackFit htf) {
+        super(htf.parameters(), htf.covariance(), htf.chisq(), htf.ndf(), htf.PathMap(), htf.ScatterMap());
+        calculateParametersAtTarget();
+        calculateParametersAtDocaY();
+        calculateParametersAtDocaZ();
+    }
+
+    public HPSTrack(double[] parameters, SymmetricMatrix covariance, double[] chiSquared, int[] ndf,
+            Map<HelicalTrackHit, Double> sMap, Map<HelicalTrackHit, MultipleScatter> msMap, MCParticle mcParticle) {
+        super(parameters, covariance, chiSquared, ndf, sMap, msMap);
+
+        // Set the MC particle associated with this fit
+        this.mcParticle = mcParticle;
+    }
+
+    /**
+     * Get map of the the track trajectory within the uniform bfield
+     */
+    public Map<Integer, Double[]> trackTrajectory(double zStart, double zStop, int nSteps) {
+        Map<Integer, Double[]> traj = new HashMap<Integer, Double[]>();
+        double step = (zStop - zStart) / nSteps;
+        Double zVal = zStart;
+        Integer nstep = 0;
+        while (zVal < zStop) {
+            Double[] xyz = {0.0, 0.0, 0.0};
+            double s = HelixUtils.PathToXPlane(this, zVal, 1000.0, 1).get(0);
+            xyz[0] = HelixUtils.PointOnHelix(this, s).y();
+            xyz[1] = HelixUtils.PointOnHelix(this, s).z();
+            xyz[2] = zVal;
+            traj.put(nstep, xyz);
+            zVal += step;
+            nstep++;
+        }
+        return traj;
+    }
+
+    /**
+     * Get map of the the track direction within the uniform bfield
+     */
+    public Map<Integer, Double[]> trackDirection(double zStart, double zStop, int nSteps) {
+        Map<Integer, Double[]> traj = new HashMap<Integer, Double[]>();
+        double step = (zStop - zStart) / nSteps;
+        Double zVal = zStart;
+
+        Integer nstep = 0;
+        while (zVal < zStop) {
+            Double[] xyz = {0.0, 0.0, 0.0};
+            double s = HelixUtils.PathToXPlane(this, zVal, 1000.0, 1).get(0);
+            xyz[0] = HelixUtils.Direction(this, s).y();
+            xyz[1] = HelixUtils.Direction(this, s).z();
+            xyz[2] = zVal;
+            traj.put(nstep, xyz);
+            zVal += step;
+            nstep++;
+        }
+        return traj;
+    }
+
+    private void calculateParametersAtTarget() {
+        double pTot = this.p(bField);
+        //currently, PathToXPlane only returns a single path (no loopers!)
+        List<Double> paths = HelixUtils.PathToXPlane(this, 0.0, 100.0, 1);
+        Hep3Vector posTargetTrkSystem = HelixUtils.PointOnHelix(this, paths.get(0));
+        Hep3Vector dirTargetTrkSystem = HelixUtils.Direction(this, paths.get(0));
+        _posTarget = HPSTransformations.transformVectorToDetector(posTargetTrkSystem);
+        _pTarget = VecOp.mult(pTot, HPSTransformations.transformVectorToDetector(dirTargetTrkSystem));
+
+    }
+
+    private void calculateParametersAtDocaY() {
+        double pTot = this.p(bField);
+        Hep3Vector posDocaYTrkSystem = HelixUtils.PointOnHelix(this, 0);
+        Hep3Vector dirDocaYTrkSystem = HelixUtils.Direction(this, 0);
+        _posDocaY = HPSTransformations.transformVectorToDetector(posDocaYTrkSystem);
+        _pDocaY = VecOp.mult(pTot, HPSTransformations.transformVectorToDetector(dirDocaYTrkSystem));
+
+    }
+
+    private void calculateParametersAtDocaZ() {
+        double pTot = this.p(bField);
+        double sAtDocaZ = findPathToDocaZ();
+        Hep3Vector posDocaZTrkSystem = HelixUtils.PointOnHelix(this, sAtDocaZ);
+        Hep3Vector dirDocaZTrkSystem = HelixUtils.Direction(this, sAtDocaZ);
+        _posDocaZ = HPSTransformations.transformVectorToDetector(posDocaZTrkSystem);
+        _pDocaZ = VecOp.mult(pTot, HPSTransformations.transformVectorToDetector(dirDocaZTrkSystem));
+    }
+
+//    public Hep3Vector getPositionAtZ(double xFinal, double fringeHalfWidth, double step) {
+//        double startFringeUpstream = -2 * fringeHalfWidth;
+//        double stopFringeUpstream = 0;
+//        if (_debug)
+//            System.out.println(this.toString());
+//
+//
+//    }
+    public Hep3Vector getPositionAtZ(double xFinal, double start, double stop, double step) {
+
+        double startFringe = start;
+        double stopFringe = stop;
+        //       _debugForward = false;
+        //       if (xFinal > 900)
+        //           _debugForward = true;
+        // if looking upstream, we'll be propagating backwards
+        if (xFinal < 0) {
+            step = -step;
+            startFringe = stop;
+            stopFringe = start;
+        }
+        double fringeHalfWidth = Math.abs(stopFringe - startFringe) / 2;
+        double fringeMid = (stopFringe + startFringe) / 2;
+        if (_debugForward) {
+            System.out.println(this.toString());
+        }
+
+        double sStartFringe = HelixUtils.PathToXPlane(this, startFringe, 1000.0, 1).get(0);
+        if (_debugForward) {
+            System.out.println("path to end of fringe = " + sStartFringe + "; xFinal = " + xFinal);
+        }
+        double xtmp = startFringe;
+        double ytmp = HelixUtils.PointOnHelix(this, sStartFringe).y();
+        double ztmp = HelixUtils.PointOnHelix(this, sStartFringe).z();
+        double Rorig = this.R();
+        double xCtmp = this.xc();
+        double yCtmp = this.yc();
+        double q = Math.signum(this.curvature());
+        double phitmp = getPhi(xtmp, ytmp, xCtmp, yCtmp, q);
+        if (_debugForward) {
+            System.out.println("\nOriginal xtmp = " + xtmp
+                    + "; ytmp = " + ytmp
+                    + "; ztmp = " + ztmp
+                    + "; phitmp = " + phitmp);
+
+            System.out.println("nOriginal Rorig = " + Rorig
+                    + "; xCtmp = " + xCtmp
+                    + "; yCtmp = " + yCtmp);
+        }
+        if (_debugForward) {
+            System.out.println("Original Direction at Fringe: " + HelixUtils.Direction(this, startFringe).toString());
+        }
+        double Rtmp = Rorig;
+        // now start stepping through the fringe field
+        Hep3Vector r0Tmp = HelixUtils.PointOnHelix(this, sStartFringe);
+        SpacePoint r0 = new SpacePoint(r0Tmp);
+        double pTot = this.p(bField);
+        Hep3Vector dirOrig = HelixUtils.Direction(this, sStartFringe);
+        Hep3Vector p0 = VecOp.mult(pTot, dirOrig);
+        Hep3Vector dirTmp = dirOrig;
+        SpacePoint rTmp = r0;
+        Hep3Vector pTmp = p0;
+        double pXOrig = p0.x();
+        double pXTmp = pXOrig;
+        double totalS = sStartFringe;
+        if (_debugForward) {
+            double tmpdX = xFinal - startFringe;
+            Hep3Vector fooExt = extrapolateStraight(dirOrig, tmpdX);
+            Hep3Vector fooFinal = VecOp.add(fooExt, r0Tmp);
+            System.out.println("Extrpolating straight back from startFringe = (" + fooFinal.x() + "," + fooFinal.y() + "," + fooFinal.z() + ")");
+
+        }
+        //follow trajectory while:  in fringe field, before end point, and we don't have a looper
+        while (Math.signum(step) * xtmp < Math.signum(step) * stopFringe && Math.signum(step) * xtmp < Math.signum(step) * xFinal && Math.signum(pXOrig * pXTmp) > 0) {
+            if (_debugForward) {
+                System.out.println("New step in Fringe Field");
+                System.out.println("rTmp = " + rTmp.toString());
+                System.out.println("pTmp = " + pTmp.toString());
+                System.out.println("OriginalHelix pos = " + HelixUtils.PointOnHelix(this, totalS));
+                System.out.println("OriginalHelix Momentum = " + VecOp.mult(pTot, HelixUtils.Direction(this, totalS)));
+            }
+
+            double fringeFactor = getFringe(Math.signum(step) * (fringeMid - rTmp.x()), fringeHalfWidth);
+//            double myBField=bField * fringeFactor;
+            double myBField = FieldMap.getFieldFromMap(rTmp.x(), rTmp.y());
+            if (_debugForward) {
+                System.out.println("rTmp.x() = " + rTmp.x() + " field = " + myBField);
+            }
+            setTrack(pTmp, rTmp, q, myBField);
+            rTmp = _trajectory.getPointAtDistance(step);
+            pTmp = VecOp.mult(pTot, _trajectory.getUnitTangentAtLength(step));
+            pXTmp = pTmp.x();
+            xtmp = rTmp.x();
+            if (_debugForward) {
+                System.out.println("##############   done...    #############");
+
+                System.out.println("\n");
+            }
+            totalS += step;
+        }
+        //ok, done with field...extrapolate straight back...
+        Hep3Vector pointInTrking;
+        if (Math.signum(step) * xtmp < Math.signum(step) * xFinal) {
+            //get direction of the track before it hits fringe field
+            double deltaX = xFinal - xtmp;
+            Hep3Vector dir = _trajectory.getUnitTangentAtLength(0);
+//            double deltaY = deltaX * dir.y();
+//            double deltaZ = deltaX * dir.z();
+            Hep3Vector delta = extrapolateStraight(dir, deltaX);
+//            double deltaZ = Math.sqrt(deltaX*deltaX+deltaY*deltaY)* dir.z();
+            pointInTrking = new BasicHep3Vector(xFinal, delta.y() + ytmp, delta.z() + ztmp);
+
+            if (_debugForward) {
+                System.out.println("Pointing straight forward from xtmp = " + xtmp
+                        + "; ytmp = " + ytmp
+                        + "; ztmp = " + ztmp
+                        + "; deltaX= " + deltaX);
+                System.out.println("Directions:  " + dir.toString());
+                System.out.println("Position at ECal:  x = " + xFinal + "; y = " + pointInTrking.y() + "; z = " + pointInTrking.z());
+
+            }
+        } else {  // still in the fringe field...just return the current position
+//            pointInTrking = new BasicHep3Vector(xFinal, ytmp, ztmp);
+            pointInTrking = new BasicHep3Vector(rTmp.x(), rTmp.y(), rTmp.z());
+        }
+        return HPSTransformations.transformVectorToDetector(pointInTrking);
+    }
+
+    /**
+     * Get the position and direction on the track using B-field map for
+     * extrapolation
+     *
+     * @param start = starting z-position of extrapolation
+     * @param zFinal = final z-position
+     * @param step = step size
+     * @return position[0] and direction[1] at Z=zfinal
+     */
+    public Hep3Vector[] getPositionAtZMap(double start, double xFinal, double step) {
+        return this.getPositionAtZMap(start, xFinal, step, true);
+    }
+
+    public Hep3Vector[] getPositionAtZMap(double start, double xFinal, double step, boolean debugOk) {
+
+        double startFringe = start;
+
+        _debugForward = false;
+        if (xFinal > 900) {
+            _debugForward = debugOk ? true : false;
+        }
+        // if looking upstream, we'll be propagating backwards
+        if (xFinal < 0) {
+            step = -step;
+        }
+        if (_debugForward) {
+            System.out.println(this.toString());
+        }
+
+        double sStartFringe = HelixUtils.PathToXPlane(this, startFringe, 1000.0, 1).get(0);
+        if (_debugForward) {
+            System.out.println("path to end of fringe = " + sStartFringe + "; xFinal = " + xFinal);
+        }
+        double xtmp = startFringe;
+        double ytmp = HelixUtils.PointOnHelix(this, sStartFringe).y();
+        double ztmp = HelixUtils.PointOnHelix(this, sStartFringe).z();
+        double Rorig = this.R();
+        double xCtmp = this.xc();
+        double yCtmp = this.yc();
+        double q = Math.signum(this.curvature());
+        double phitmp = getPhi(xtmp, ytmp, xCtmp, yCtmp, q);
+        if (_debugForward) {
+            System.out.println("\nOriginal xtmp = " + xtmp
+                    + "; ytmp = " + ytmp
+                    + "; ztmp = " + ztmp
+                    + "; phitmp = " + phitmp);
+
+            System.out.println("nOriginal Rorig = " + Rorig
+                    + "; xCtmp = " + xCtmp
+                    + "; yCtmp = " + yCtmp);
+        }
+        if (_debugForward) {
+            System.out.println("Original Direction at Fringe: " + HelixUtils.Direction(this, startFringe).toString());
+        }
+        double Rtmp = Rorig;
+        // now start stepping through the fringe field
+        Hep3Vector r0Tmp = HelixUtils.PointOnHelix(this, sStartFringe);
+        SpacePoint r0 = new SpacePoint(r0Tmp);
+        double pTot = this.p(bField);
+        Hep3Vector dirOrig = HelixUtils.Direction(this, sStartFringe);
+        Hep3Vector p0 = VecOp.mult(pTot, dirOrig);
+        Hep3Vector dirTmp = dirOrig;
+        SpacePoint rTmp = r0;
+        Hep3Vector pTmp = p0;
+        double pXOrig = p0.x();
+        double pXTmp = pXOrig;
+        double totalS = sStartFringe;
+        if (_debugForward) {
+            double tmpdX = xFinal - startFringe;
+            Hep3Vector fooExt = extrapolateStraight(dirOrig, tmpdX);
+            Hep3Vector fooFinal = VecOp.add(fooExt, r0Tmp);
+            System.out.println("Extrpolating straight back from startFringe = (" + fooFinal.x() + "," + fooFinal.y() + "," + fooFinal.z() + ")");
+
+        }
+        //follow trajectory while:  in fringe field, before end point, and we don't have a looper
+        while (Math.signum(step) * xtmp < Math.signum(step) * xFinal && Math.signum(pXOrig * pXTmp) > 0) {
+            if (_debugForward) {
+                System.out.println("New step in Fringe Field");
+                System.out.println("rTmp = " + rTmp.toString());
+                System.out.println("pTmp = " + pTmp.toString());
+                System.out.println("OriginalHelix pos = " + HelixUtils.PointOnHelix(this, totalS));
+                System.out.println("OriginalHelix Momentum = " + VecOp.mult(pTot, HelixUtils.Direction(this, totalS)));
+            }
+
+            double myBField = FieldMap.getFieldFromMap(rTmp.x(), rTmp.y());
+            if (_debugForward) {
+                System.out.println("rTmp.x() = " + rTmp.x() + " field = " + myBField);
+            }
+            setTrack(pTmp, rTmp, q, myBField);
+            rTmp = _trajectory.getPointAtDistance(step);
+            pTmp = VecOp.mult(pTot, _trajectory.getUnitTangentAtLength(step));
+            pXTmp = pTmp.x();
+            xtmp = rTmp.x();
+            if (_debugForward) {
+                System.out.println("##############   done...    #############");
+
+                System.out.println("\n");
+            }
+            totalS += step;
+        }
+
+        //Go with finer granularity in the end
+        rTmp = _trajectory.getPointAtDistance(0);
+        xtmp = rTmp.x();
+        pTmp = VecOp.mult(pTot, _trajectory.getUnitTangentAtLength(step));
+        pXTmp = pTmp.x();
+        step = step / 10.0;
+
+        while (Math.signum(step) * xtmp < Math.signum(step) * xFinal && Math.signum(pXOrig * pXTmp) > 0) {
+            if (_debugForward) {
+                System.out.println("New step in Fringe Field");
+                System.out.println("rTmp = " + rTmp.toString());
+                System.out.println("pTmp = " + pTmp.toString());
+                System.out.println("OriginalHelix pos = " + HelixUtils.PointOnHelix(this, totalS));
+                System.out.println("OriginalHelix Momentum = " + VecOp.mult(pTot, HelixUtils.Direction(this, totalS)));
+            }
+
+            double myBField = FieldMap.getFieldFromMap(rTmp.x(), rTmp.y());
+            if (_debugForward) {
+                System.out.println("rTmp.x() = " + rTmp.x() + " field = " + myBField);
+            }
+            setTrack(pTmp, rTmp, q, myBField);
+            rTmp = _trajectory.getPointAtDistance(step);
+            pTmp = VecOp.mult(pTot, _trajectory.getUnitTangentAtLength(step));
+            pXTmp = pTmp.x();
+            xtmp = rTmp.x();
+            if (_debugForward) {
+                System.out.println("##############   done...    #############");
+
+                System.out.println("\n");
+            }
+            totalS += step;
+        }
+
+        //ok, done with field.
+        Hep3Vector pointInTrking = new BasicHep3Vector(rTmp.x(), rTmp.y(), rTmp.z());
+        if (_debugForward) {
+            System.out.println("Position xfinal (tracking) :  x = " + xFinal + "; y = " + pointInTrking.y() + "; z = " + pointInTrking.z());
+        }
+        Hep3Vector[] out = {HPSTransformations.transformVectorToDetector(pointInTrking), HPSTransformations.transformVectorToDetector(pTmp)};
+
+        return out;
+    }
+
+    private double getPhi(double x, double y, double xc, double yc, double sign) {
+        //      System.out.println("Math.atan2(y - yc, x - xc)="+Math.atan2(y - yc, x - xc));
+        return Math.atan2(y - yc, x - xc) - sign * Math.PI / 2;
+    }
+
+    private Hep3Vector extrapolateStraight(Hep3Vector dir, double deltaX) {
+        double deltaY = deltaX * dir.y();
+        double deltaZ = deltaX * dir.z();
+        return new BasicHep3Vector(deltaX, deltaY, deltaZ);
+    }
+
+    //field that changes linearly from Bmax->0
+    private double getFringe(double x, double halfWidth) {
+//        System.out.println("x = " + x + "; halfWidth = " + halfWidth);
+        if (x / halfWidth > 1) {
+            return 1;
+        }
+        if (x / halfWidth < -1) {
+            return 0;
+        }
+
+        return (1.0 / 2.0) * (1 + x / halfWidth);
+    }
+
+    private Hep3Vector getDirection(double phi, double sign) {
+        double ux = Math.cos(phi) * this.sth();
+        double uy = Math.sin(phi) * this.sth();
+        double uz = this.cth();
+        //  Return the direction unit vector
+        return new BasicHep3Vector(ux, uy, uz);
+    }
+
+    private double findPathToDocaZ() {
+        double step = 0.1;//100 um step size
+        double maxS = 100.0; //go to 10cm
+        double s = -30;
+        double minDist = 999999;
+        double minS = s;
+        double dist = 999998;
+        //once the distance starts increasing, quit and return
+        while (dist < minDist) {
+            Hep3Vector pos = HelixUtils.PointOnHelix(this, s);
+            dist = pos.y() * pos.y() + pos.z() * pos.z();
+            s += step;
+        }
+        return minS;
+    }
+
+    private void setTrack(Hep3Vector p0, SpacePoint r0, double q, double B) {
+        SpaceVector p = new CartesianVector(p0.v());
+        double phi = Math.atan2(p.y(), p.x());
+        double lambda = Math.atan2(p.z(), p.rxy());
+        double field = B * fieldConversion;
+
+        if (q != 0 && field != 0) {
+            double radius = p.rxy() / (q * field);
+            _trajectory = new Helix(r0, radius, phi, lambda);
+        } else {
+            _trajectory = new Line(r0, phi, lambda);
+        }
+    }
+
+    public Trajectory getTrajectory() {
+        return this._trajectory;
+    }
+
+    /**
+     * Get the MC Particle associated with the HelicalTrackFit
+     *
+     * @return mcParticle :
+     */
+    public MCParticle getMCParticle() {
+        return this.mcParticle;
+    }
+
+    /**
+     * Set the MC Particle associated with the HelicalTrackFit
+     *
+     * @param mcParticle :
+     */
+    public void setMCParticle(MCParticle mcParticle) {
+        this.mcParticle = mcParticle;
+    }
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
HPSTransformations.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/HPSTransformations.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/HPSTransformations.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,66 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.hps.recon.tracking;
+
+import hep.physics.matrix.SymmetricMatrix;
+import hep.physics.vec.BasicHep3Matrix;
+import hep.physics.vec.Hep3Matrix;
+import hep.physics.vec.Hep3Vector;
+
+import org.lcsim.detector.Rotation3D;
+import org.lcsim.detector.Transform3D;
+
+/**
+ *  Class that contains the transformations between the JLAB and lcsim tracking coordinate systems
+ * @author mgraham, phansson
+ * created 6/27/2011
+ * made static 10/14/2013
+ * 
+ */
+public class HPSTransformations {
+
+    private static final Transform3D _detToTrk = HPSTransformations.initialize();
+
+    /**
+     * Private constructor to prevent initialization
+     */
+    private HPSTransformations() {
+    }
+
+    /**
+     * Static private initialization of transform
+     * @return transform
+     */
+    private static Transform3D initialize() {
+    	BasicHep3Matrix tmp = new BasicHep3Matrix();
+        tmp.setElement(0, 2, 1);
+        tmp.setElement(1, 0, 1);
+        tmp.setElement(2, 1, 1);
+        return new Transform3D(new Rotation3D(tmp));
+    }
+    
+    public static Hep3Vector transformVectorToTracking(Hep3Vector vec) {
+        return _detToTrk.transformed(vec);
+    }
+
+    public static SymmetricMatrix transformCovarianceToTracking(SymmetricMatrix cov) {
+        return _detToTrk.transformed(cov);
+    }
+
+    public static Hep3Vector transformVectorToDetector(Hep3Vector vec) {
+        return (_detToTrk.inverse()).transformed(vec);
+    }
+
+    public static SymmetricMatrix transformCovarianceToDetector(SymmetricMatrix cov) {
+        return (_detToTrk.inverse()).transformed(cov);
+    }
+    public static Transform3D getTransform(){
+        return _detToTrk;
+    }
+    public static Hep3Matrix getMatrix(){
+        return _detToTrk.getRotation().getRotationMatrix();
+    }
+    
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
HelicalTrackHitDriver.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/HelicalTrackHitDriver.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/HelicalTrackHitDriver.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,571 @@
+package org.hps.recon.tracking;
+
+import hep.physics.vec.Hep3Vector;
+import hep.physics.vec.VecOp;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+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.SvtUtils;
+import org.lcsim.detector.IDetectorElement;
+import org.lcsim.detector.ITransform3D;
+import org.lcsim.detector.tracker.silicon.SiSensor;
+import org.lcsim.detector.tracker.silicon.SiTrackerModule;
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.LCRelation;
+import org.lcsim.event.MCParticle;
+import org.lcsim.event.RawTrackerHit;
+import org.lcsim.event.RelationalTable;
+import org.lcsim.event.SimTrackerHit;
+import org.lcsim.event.base.BaseRelationalTable;
+import org.lcsim.event.base.MyLCRelation;
+import org.lcsim.fit.helicaltrack.HelicalTrackCross;
+import org.lcsim.fit.helicaltrack.HelicalTrackHit;
+import org.lcsim.fit.helicaltrack.HelicalTrackStrip;
+import org.lcsim.geometry.Detector;
+import org.lcsim.geometry.subdetector.BarrelEndcapFlag;
+import org.lcsim.recon.tracking.digitization.sisim.SiTrackerHit;
+import org.lcsim.recon.tracking.digitization.sisim.SiTrackerHitStrip1D;
+import org.lcsim.recon.tracking.digitization.sisim.TrackerHitType;
+
+/**
+ * 
+ * @author Mathew Graham <[log in to unmask]>
+ * @author Per Hansson <[log in to unmask]>
+ * @author Omar Moreno <[log in to unmask]>
+ * @version $Id: HelicalTrackHitDriver.java,v 1.10 2013/10/17 22:08:33 omoreno Exp $          
+ */
+public class HelicalTrackHitDriver extends org.lcsim.fit.helicaltrack.HelicalTrackHitDriver {
+
+    private boolean _debug = false;
+    private double _clusterTimeCut = -99; // if negative, don't cut..otherwise,
+                                          // dt cut time in ns
+    private String _subdetectorName = "Tracker";
+    private String _clusterCollectionName = "StripClusterer_SiTrackerHitStrip1D";
+
+    private Map<String, String> _stereomap = new HashMap<String, String>();
+    private List<String> _colnames = new ArrayList<String>();
+    private boolean _doTransformToTracking = true;
+
+    public enum LayerGeometryType {
+        Split, Common
+    }
+
+    private LayerGeometryType _layerGeometryType = LayerGeometryType.Split;
+
+    /**
+     * Default Ctor
+     */
+    public HelicalTrackHitDriver() {
+        this.addCollection("StripClusterer_SiTrackerHitStrip1D");
+    }
+
+    // --- Setters ---//
+    // ---------------//
+
+    /**
+     * 
+     * @param geomType
+     */
+    public void setLayerGeometryType(String geomType) {
+        this._layerGeometryType = LayerGeometryType.valueOf(geomType);
+    }
+
+    /**
+     * 
+     * @param dtCut
+     */
+    public void setClusterTimeCut(double dtCut) {
+        this._clusterTimeCut = dtCut;
+    }
+
+    /**
+     * 
+     * @param subdetectorName
+     */
+    public void setSubdetectorName(String subdetectorName) {
+        this._subdetectorName = subdetectorName;
+    }
+
+    /**
+     * 
+     * @param debug
+     */
+    public void setDebug(boolean debug) {
+        this._debug = debug;
+    }
+
+    /**
+     * 
+     * @param trans
+     */
+    public void setTransformToTracking(boolean trans) {
+        this._doTransformToTracking = trans;
+    }
+
+    /**
+     * 
+     * @param stripHitsCollectionName
+     */
+    public void setStripHitsCollectionName(String stripHitsCollectionName) {
+        HitRelationName(stripHitsCollectionName);
+    }
+
+    /**
+     * 
+     * @param helicalTrackHitRelationsCollectionName
+     */
+    public void setHelicalTrackHitRelationsCollectionName(String helicalTrackHitRelationsCollectionName) {
+        HitRelationName(helicalTrackHitRelationsCollectionName);
+    }
+
+    /**
+     * 
+     * @param helicalTrackMCRelationsCollectionName
+     */
+    public void setHelicalTrackMCRelationsCollectionName(String helicalTrackMCRelationsCollectionName) {
+        MCRelationName(helicalTrackMCRelationsCollectionName);
+    }
+
+    /**
+     * 
+     * @param outputHitCollectionName
+     */
+    public void setOutputHitCollectionName(String outputHitCollectionName) {
+        OutputCollection(outputHitCollectionName);
+    }
+
+    @Override
+    public void process(EventHeader event) {
+
+        // Instantiate the list of HelicalTrackCrosses and HelicalTrackHits
+        List<HelicalTrackCross> stereoCrosses = new ArrayList<HelicalTrackCross>();
+        List<HelicalTrackHit> helhits = new ArrayList<HelicalTrackHit>();
+
+        // Create an LCRelation from a HelicalTrackHit to
+        List<LCRelation> hitrelations = new ArrayList<LCRelation>();
+
+        // Create an LCRelation from a HelicalTrackHit to an MC particle used to
+        // create it
+        List<LCRelation> mcrelations = new ArrayList<LCRelation>();
+
+        RelationalTable hittomc = new BaseRelationalTable(RelationalTable.Mode.ONE_TO_MANY, RelationalTable.Weighting.UNWEIGHTED);
+        if (event.hasCollection(LCRelation.class, "SVTTrueHitRelations")) {
+            List<LCRelation> trueHitRelations = event.get(LCRelation.class, "SVTTrueHitRelations");
+            for (LCRelation relation : trueHitRelations) {
+                if (relation != null && relation.getFrom() != null && relation.getTo() != null) {
+                    hittomc.add(relation.getFrom(), relation.getTo());
+                }
+            }
+        }
+
+        if (LayerGeometryType.Common == _layerGeometryType) {
+
+            for (String _colname : this._colnames) {
+
+                if (!event.hasCollection(SiTrackerHit.class, _colname))
+                    continue;
+
+                // Get the list of SiTrackerHits for this collection
+                List<SiTrackerHit> hitlist = event.get(SiTrackerHit.class, _colname);
+
+                if (_debug) {
+                    System.out.printf("%s: found %d SiTrackerHits\n", this.getClass().getSimpleName(), hitlist.size());
+                }
+
+                // Create collections for strip hits by layer and hit cross
+                // references
+                Map<String, List<HelicalTrackStrip>> striplistmap = new HashMap<String, List<HelicalTrackStrip>>();
+                Map<HelicalTrackStrip, SiTrackerHitStrip1D> stripmap = new HashMap<HelicalTrackStrip, SiTrackerHitStrip1D>();
+
+                for (SiTrackerHit hit : hitlist) {
+
+                    if (hit instanceof SiTrackerHitStrip1D) {
+
+                        // Cast the hit as a 1D strip hit and find the
+                        // identifier for the detector/layer combo
+                        SiTrackerHitStrip1D h = (SiTrackerHitStrip1D) hit;
+                        IDetectorElement de = h.getSensor();
+                        String id = this.makeID(_ID.getName(de), _ID.getLayer(de));
+
+                        // This hit should be a on a stereo pair!
+                        // With our detector setup, when is this not true?
+                        if (!_stereomap.containsKey(id) && !_stereomap.containsValue(id)) {
+                            throw new RuntimeException(this.getClass().getSimpleName() + ": this " + id + " was not among the stereo modules!");
+                        }
+
+                        // Create a HelicalTrackStrip for this hit
+                        HelicalTrackStrip strip = makeDigiStrip(h);
+                        for (RawTrackerHit rth : h.getRawHits()) {
+                            for (Object simHit : hittomc.allFrom(rth)) {
+                                strip.addMCParticle(((SimTrackerHit) simHit).getMCParticle());
+                            }
+                        }
+
+                        // Get the list of strips for this layer - create a new
+                        // list if one doesn't already exist
+                        List<HelicalTrackStrip> lyrhits = striplistmap.get(id);
+                        if (lyrhits == null) {
+                            lyrhits = new ArrayList<HelicalTrackStrip>();
+                            striplistmap.put(id, lyrhits);
+                        }
+
+                        if ((_clusterTimeCut > 0 && Math.abs(h.getTime()) < _clusterTimeCut) || _clusterTimeCut < 0) {
+                            // Add the strip to the list of strips on this
+                            // sensor
+                            lyrhits.add(strip);
+
+                            // Map a reference back to the hit needed to create
+                            // the stereo hit LC relations
+                            stripmap.put(strip, h);
+
+                            if (_debug) {
+                                System.out.printf("%s: added strip org %s layer %d\n", this.getClass().getSimpleName(), strip.origin().toString(), strip.layer());
+                            }
+                        }
+                    } else {
+
+                        // If not a 1D strip hit, make a pixel hit
+                        // This should be removed as it is never used.
+                        HelicalTrackHit hit3d = this.makeDigi3DHit(hit);
+                        helhits.add(hit3d);
+                        hitrelations.add(new MyLCRelation(hit3d, hit));
+                    }
+
+                } // Loop over SiTrackerHits
+
+
+                if (_debug)
+                    System.out.printf("%s: Create stereo hits from %d strips \n", this.getClass().getSimpleName(), striplistmap.size());
+
+                // Loop over the stereo layer pairs
+                // TODO: Change this so that it makes use of StereoPairs
+                for (String id1 : _stereomap.keySet()) {
+
+                    // Get the second layer
+                    String id2 = _stereomap.get(id1);
+
+                    if (_debug) {
+                        System.out.printf("%s: Form stereo hits from sensor id %s with %d hits and %s with %d hits\n", this.getClass().getSimpleName(), id1, striplistmap.get(id1) == null ? 0
+                                : striplistmap.get(id1).size(), id2, striplistmap.get(id2) == null ? 0 : striplistmap.get(id2).size());
+                    }
+
+                    /*
+                     * Form the stereo hits and add them to our hit list Add LC
+                     * relations for stereo hit to SiTrackHitStrip1D object Add
+                     * LC relation between MC particle and stereo hit
+                     */
+                    List<HelicalTrackCross> cross_list = _crosser.MakeHits(striplistmap.get(id1), striplistmap.get(id2));
+
+                    for (HelicalTrackCross cross : cross_list) {
+                        stereoCrosses.add(cross);
+                        if (cross.getMCParticles() != null) {
+                            for (MCParticle mcp : cross.getMCParticles()) {
+                                mcrelations.add(new MyLCRelation((HelicalTrackHit) cross, mcp));
+                            }
+                        }
+                        for (HelicalTrackStrip strip : cross.getStrips()) {
+                            hitrelations.add(new MyLCRelation(cross, stripmap.get(strip)));
+                        }
+                    }
+
+                } // End of loop over stereo pairs
+
+                if (_debug) {
+                    System.out.printf("%s: added %d stereo hits from %s collection \n", this.getClass().getSimpleName(), stereoCrosses.size(), _colname);
+                }
+
+            } // End of loop over collection names
+
+            if (_debug) {
+                System.out.printf("%s: totally added %d stereo hits:\n", this.getClass().getSimpleName(), stereoCrosses.size());
+                for (HelicalTrackCross cross : stereoCrosses) {
+                    System.out.printf("%s: %.2f,%.2f,%.2f \n", this.getClass().getSimpleName(), cross.getPosition()[0], cross.getPosition()[1], cross.getPosition()[2]);
+                }
+            }
+
+            // Add things to the event
+            // Cast crosses to HTH
+            helhits.addAll(stereoCrosses);
+            event.put(_outname, helhits, HelicalTrackHit.class, 0);
+            event.put(_hitrelname, hitrelations, LCRelation.class, 0);
+            event.put(_mcrelname, mcrelations, LCRelation.class, 0);
+            if (_doTransformToTracking) {
+                addRotatedHitsToEvent(event, stereoCrosses);
+            }
+
+        } else if (LayerGeometryType.Split == _layerGeometryType) {
+
+        	
+            // If the event does not have hit clusters, skip it.
+            if (!event.hasCollection(SiTrackerHit.class, _clusterCollectionName)){
+                if(_debug){
+                    System.out.println("Event: " + event.getRunNumber() + " does not contain the collection " + _clusterCollectionName);
+                }
+                return;
+            }
+
+            // Get the list of SiTrackerHits for this collection
+            List<SiTrackerHit> hitlist = event.get(SiTrackerHit.class, _clusterCollectionName);
+
+
+            if (_debug) {
+                System.out.printf("%s: found %d SiTrackerHits\n", this.getClass().getSimpleName(), hitlist.size());
+            }
+
+            Map<HelicalTrackStrip, SiTrackerHitStrip1D> stripmap = new HashMap<HelicalTrackStrip, SiTrackerHitStrip1D>();
+            Map<SiSensor, List<HelicalTrackStrip>> striplistmap = new HashMap<SiSensor, List<HelicalTrackStrip>>();
+            for (SiTrackerHit hit : hitlist) {
+
+                    // Cast the hit as a 1D strip hit and find the identifier
+                    // for the detector/layer combo
+                    SiTrackerHitStrip1D h = (SiTrackerHitStrip1D) hit;
+                    SiSensor sensor = h.getSensor();
+
+                    List<HelicalTrackStrip> hitsOnSensor = striplistmap.get(sensor);
+
+                    // If no hits on that sensor yet -> create the list
+                    if (hitsOnSensor == null) {
+                        hitsOnSensor = new ArrayList<HelicalTrackStrip>();
+                        striplistmap.put(sensor, hitsOnSensor);
+                    }
+
+                    // Create a HelicalTrackStrip for this hit
+                    HelicalTrackStrip strip = makeDigiStrip(h);
+                    for (RawTrackerHit rth : h.getRawHits()) {
+                        for (Object simHit : hittomc.allFrom(rth)) {
+                            strip.addMCParticle(((SimTrackerHit) simHit).getMCParticle());
+                        }
+                    }
+
+                    if ((_clusterTimeCut > 0 && Math.abs(h.getTime()) < _clusterTimeCut) || _clusterTimeCut < 0) {
+                        // Add the strip to the list of strips on this sensor
+                        hitsOnSensor.add(strip);
+
+                        // Map a reference back to the hit needed to create the
+                        // stereo hit LC relations
+                        stripmap.put(strip, h);
+
+                        if (_debug)
+                            System.out.printf("%s: added strip org %s layer %d\n", this.getClass().getSimpleName(), strip.origin().toString(), strip.layer());
+                    }
+            } // Loop over SiTrackerHits
+
+
+            // for(StereoPair pair : _det.getStereoPairs()) {
+            for (StereoPair stereoPair : SvtUtils.getInstance().getStereoPairs()) {
+
+                /*
+                 * Form the stereo hits and add them to our hit list Add LC
+                 * relations for stereo hit to SiTrackHitStrip1D object Add LC
+                 * relation between MC particle and stereo hit
+                 */
+
+                List<HelicalTrackCross> helicalTrackCrosses = null;
+                if (stereoPair.getDetectorVolume() == detectorVolume.Top) {
+                    helicalTrackCrosses = _crosser.MakeHits(striplistmap.get(stereoPair.getAxialSensor()), striplistmap.get(stereoPair.getStereoSensor()));
+                } else if (stereoPair.getDetectorVolume() == detectorVolume.Bottom) {
+                    helicalTrackCrosses = _crosser.MakeHits(striplistmap.get(stereoPair.getStereoSensor()), striplistmap.get(stereoPair.getAxialSensor()));
+                }
+
+                if (_debug)
+                    System.out.printf("%s: Found %d stereo hits from sensors\n%s: %s : %d hits\n%s: %s with %d hits\n", this.getClass().getSimpleName(), helicalTrackCrosses.size(), this.getClass()
+                            .getSimpleName(), stereoPair.getAxialSensor().getName(), striplistmap.get(stereoPair.getAxialSensor()) == null ? 0 : striplistmap.get(stereoPair.getAxialSensor()).size(),
+                            this.getClass().getSimpleName(), stereoPair.getStereoSensor().getName(),
+                            striplistmap.get(stereoPair.getStereoSensor()) == null ? 0 : striplistmap.get(stereoPair.getStereoSensor()).size());
+
+                for (HelicalTrackCross cross : helicalTrackCrosses) {
+                    stereoCrosses.add(cross);
+                    if (cross.getMCParticles() != null) {
+                        for (MCParticle mcp : cross.getMCParticles()) {
+                            mcrelations.add(new MyLCRelation((HelicalTrackHit) cross, mcp));
+                        }
+                    }
+                    for (HelicalTrackStrip strip : cross.getStrips()) {
+                        hitrelations.add(new MyLCRelation(cross, stripmap.get(strip)));
+                    }
+                    if (_debug)
+                        System.out.printf("%s: cross at %.2f,%.2f,%.2f \n", this.getClass().getSimpleName(), cross.getPosition()[0], cross.getPosition()[1], cross.getPosition()[2]);
+
+                }
+
+            } // Loop over stereo pairs
+
+            if (_debug) {
+                System.out.printf("%s: totally added %d stereo hits:\n", this.getClass().getSimpleName(), stereoCrosses.size());
+                for (HelicalTrackCross cross : stereoCrosses) {
+                    System.out.printf("%s: %.2f,%.2f,%.2f \n", this.getClass().getSimpleName(), cross.getPosition()[0], cross.getPosition()[1], cross.getPosition()[2]);
+                }
+            }
+
+            // Add things to the event
+            // Cast crosses to HTH
+            helhits.addAll(stereoCrosses);
+            event.put(_outname, helhits, HelicalTrackHit.class, 0);
+            event.put(_hitrelname, hitrelations, LCRelation.class, 0);
+            event.put(_mcrelname, mcrelations, LCRelation.class, 0);
+            if (_doTransformToTracking) {
+                addRotatedHitsToEvent(event, stereoCrosses);
+            }
+
+        } 
+        
+    } // Process()
+
+    public void addCollection(String colname) {
+        _colnames.add(colname);
+    }
+
+    public void setCollection(String colname) {
+        _colnames.clear();
+        this.addCollection(colname);
+    }
+
+    private String makeID(String detname, int lyr) {
+        return detname + lyr;
+    }
+
+    public void setStereoPair(String detname, int lyr1, int lyr2) {
+        this._stereomap.put(this.makeID(detname, lyr1), this.makeID(detname, lyr2));
+    }
+
+    @Override
+    protected void detectorChanged(Detector detector) {
+
+        /*
+         * Setup default pairing
+         */
+        if (_debug)
+            System.out.printf("%s: Setup stereo hit pair modules \n", this.getClass().getSimpleName());
+
+        List<SiTrackerModule> modules = detector.getSubdetector(this._subdetectorName).getDetectorElement().findDescendants(SiTrackerModule.class);
+
+        if (modules.isEmpty()) {
+            throw new RuntimeException(this.getClass().getName() + ": No SiTrackerModules found in detector.");
+        }
+
+
+       if (LayerGeometryType.Common == this._layerGeometryType) {
+
+            int nLayersTotal = detector.getSubdetector(_subdetectorName).getLayering().getLayers().getNumberOfLayers();
+            if (_debug) {
+                System.out.printf("%s: %d layers \n", this.getClass().getSimpleName(), nLayersTotal);
+            }
+            if (nLayersTotal % 2 != 0) {
+                throw new RuntimeException(this.getClass().getName() + ": Don't know how to do stereo pairing for odd number of modules.");
+            }
+            List<int[]> pairs = new ArrayList<int[]>();
+            for (int i = 1; i <= (nLayersTotal) - 1; i += 2) {
+                int[] pair = { i, i + 1 };
+                if (_debug)
+                    System.out.printf("%s: Adding stereo pair: %d,%d\n", this.getClass().getSimpleName(), pair[0], pair[1]);
+                pairs.add(pair);
+            }
+            for (int[] pair : pairs) {
+                if (_debug)
+                    System.out.printf("%s: adding stereo pair from layer %d and %d \n", this.getClass().getSimpleName(), pair[0], pair[1]);
+                setStereoPair(_subdetectorName, pair[0], pair[1]);
+            }
+
+        }
+
+        if (_debug)
+            System.out.printf("%s: %d stereo modules added", this.getClass().getSimpleName(), this._stereomap.size());
+
+    }
+
+    private HelicalTrackStrip makeDigiStrip(SiTrackerHitStrip1D h) {
+
+        SiTrackerHitStrip1D local = h.getTransformedHit(TrackerHitType.CoordinateSystem.SENSOR);
+        SiTrackerHitStrip1D global = h.getTransformedHit(TrackerHitType.CoordinateSystem.GLOBAL);
+
+        ITransform3D trans = local.getLocalToGlobal();
+        Hep3Vector org = trans.transformed(_orgloc);
+        Hep3Vector u = global.getMeasuredCoordinate();
+        Hep3Vector v = global.getUnmeasuredCoordinate();
+
+        double umeas = local.getPosition()[0];
+        double vmin = VecOp.dot(local.getUnmeasuredCoordinate(), local.getHitSegment().getStartPoint());
+        double vmax = VecOp.dot(local.getUnmeasuredCoordinate(), local.getHitSegment().getEndPoint());
+        double du = Math.sqrt(local.getCovarianceAsMatrix().diagonal(0));
+
+        IDetectorElement de = h.getSensor();
+        String det = _ID.getName(de);
+        int lyr = _ID.getLayer(de);
+        BarrelEndcapFlag be = _ID.getBarrelEndcapFlag(de);
+
+        double dEdx = h.getdEdx();
+        double time = h.getTime();
+        List<RawTrackerHit> rawhits = h.getRawHits();
+        HelicalTrackStrip strip = new HelicalTrackStrip(org, u, v, umeas, du, vmin, vmax, dEdx, time, rawhits, det, lyr, be);
+
+        try {
+            if (h.getMCParticles() != null) {
+                for (MCParticle p : h.getMCParticles()) {
+                    strip.addMCParticle(p);
+                }
+            }
+        } catch (RuntimeException e) {
+            // Okay when MC info not present.
+        }
+
+        if (_debug) {
+            System.out.println(this.getClass().getSimpleName() + ": produced HelicalTrackStrip with origin " + strip.origin().toString());
+        }
+
+        return strip;
+    }
+
+    private void addRotatedHitsToEvent(EventHeader event, List<HelicalTrackCross> stereohits) {
+
+        List<HelicalTrackHit> rotatedhits = new ArrayList<HelicalTrackHit>();
+        List<LCRelation> hthrelations = new ArrayList<LCRelation>();
+        List<LCRelation> mcrelations = new ArrayList<LCRelation>();
+        for (HelicalTrackCross cross : stereohits) {
+            List<HelicalTrackStrip> rotatedstriphits = new ArrayList<HelicalTrackStrip>();
+            for (HelicalTrackStrip strip : cross.getStrips()) {
+
+                Hep3Vector origin = strip.origin();
+                Hep3Vector u = strip.u();
+                Hep3Vector v = strip.v();
+                double umeas = strip.umeas();
+                double du = strip.du();
+                double vmin = strip.vmin();
+                double vmax = strip.vmax();
+                double dedx = strip.dEdx();
+                double time = strip.time();
+                List<RawTrackerHit> rthList = strip.rawhits();
+                String detname = strip.detector();
+                int layer = strip.layer();
+                BarrelEndcapFlag bec = strip.BarrelEndcapFlag();
+                Hep3Vector neworigin = HPSTransformations.transformVectorToTracking(origin);
+                Hep3Vector newu = HPSTransformations.transformVectorToTracking(u);
+                Hep3Vector newv = HPSTransformations.transformVectorToTracking(v);
+                HelicalTrackStrip newstrip = new HelicalTrackStrip(neworigin, newu, newv, umeas, du, vmin, vmax, dedx, time, rthList, detname, layer, bec);
+                for (MCParticle p : strip.MCParticles()) {
+                    newstrip.addMCParticle(p);
+                }
+                rotatedstriphits.add(newstrip);
+            }
+            HelicalTrackCross newhit = new HelicalTrackCross(rotatedstriphits.get(0), rotatedstriphits.get(1));
+            for (MCParticle mcp : cross.getMCParticles()) {
+                newhit.addMCParticle(mcp);
+            }
+            rotatedhits.add(newhit);
+            hthrelations.add(new MyLCRelation(cross, newhit));
+            for (MCParticle mcp : newhit.getMCParticles()) {
+                mcrelations.add(new MyLCRelation(newhit, mcp));
+            }
+        }
+
+        event.put("Rotated" + _outname, rotatedhits, HelicalTrackHit.class, 0);
+        event.put("Rotated" + _hitrelname, hthrelations, LCRelation.class, 0);
+        event.put("Rotated" + _mcrelname, mcrelations, LCRelation.class, 0);
+
+    }
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
HelixConverter.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/HelixConverter.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/HelixConverter.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,142 @@
+    
+package org.hps.recon.tracking;
+
+import hep.physics.matrix.BasicMatrix;
+import hep.physics.matrix.Matrix;
+import hep.physics.matrix.MatrixOp;
+import hep.physics.matrix.MutableMatrix;
+import hep.physics.matrix.SymmetricMatrix;
+import hep.physics.vec.Hep3Vector;
+
+import org.lcsim.fit.helicaltrack.HelicalTrackFit;
+import org.lcsim.util.swim.Helix;
+
+/**
+ * Convert a helix to a straight line track at a specified reference plane normal to the x axis.
+ * This code was developed for simulating the Heavy Photon Search experiment where the target is
+ * located outside the magnetic field volume.
+ *
+ * @author Richard Partridge
+ */
+public class HelixConverter {
+
+    private double _xref;
+
+    /**
+     * Constructor for the HelixConverter used to convert helices to StraightLineTracks
+     * at the magnetic field boundary.  The reference point xref identifies
+     * the x coordinate that specifies the magnetic field boundary.  The StraightLineTracks
+     * produced by this class will use xref as their reference point.
+     *
+     * @param xref x coordinate that specifies the magnetic field boundary
+     */
+    public HelixConverter(double xref) {
+        _xref = xref;
+    }
+
+    /**
+     * Convert a helix to a StraightLineTrack.
+     *
+     * @param helix helix to be converted
+     * @return resulting StraightLineTrack
+     */
+    public StraightLineTrack Convert(HelicalTrackFit helix) {
+
+        //  Get helix parameters used in this calculation
+        double RC = helix.R();
+        double xc = helix.xc();
+        double yc = helix.yc();
+        double phi0 = helix.phi0();
+        double d0 = helix.dca();
+        double slope = helix.slope();
+        double z0 = helix.z0();
+
+        //  First find path length to reference point
+        double arg = (xc - _xref) / RC;
+        if (Math.abs(arg) > 1.0) return null;
+        double phi = Math.asin(arg);
+        double dphi = phi0 - phi;
+        if (dphi > Math.PI) dphi -= 2. * Math.PI;
+        if (dphi < -Math.PI) dphi += 2. * Math.PI;
+        double s = RC * dphi;
+        double cphi = Math.cos(phi);
+        double sphi = Math.sin(phi);
+        double cphi0 = Math.cos(phi0);
+        double sphi0 = Math.sin(phi0);
+
+        //  Get the track position at the reference point
+        double xref = xc - RC * sphi;
+        if (Math.abs(xref - _xref) > 1.e-10) System.out.println("Bad path length - x0: "+xref+" xref: "+_xref);
+        double yref = yc + RC * cphi;
+        double zref = z0 + s * slope;
+
+        //  Get dy/dx and dz/dx for the straight-line track
+        double dydx = sphi / cphi;
+        double dzdx = slope / cphi;
+
+        //  Calculate the Jacobian between the straight line track parameters and the helix parameters
+        MutableMatrix deriv = new BasicMatrix(4,5);
+        double dydcurv = (cphi0 + s / RC * sphi - cphi) * RC*RC;
+        deriv.setElement(StraightLineTrack.y0Index, HelicalTrackFit.curvatureIndex, dydcurv);
+        deriv.setElement(StraightLineTrack.y0Index, HelicalTrackFit.dcaIndex, cphi0);
+        double dydphi0 = (RC - d0) * sphi0 - RC * sphi;
+        deriv.setElement(StraightLineTrack.y0Index, HelicalTrackFit.phi0Index, dydphi0);
+        deriv.setElement(StraightLineTrack.z0Index, HelicalTrackFit.z0Index, 1.);
+        deriv.setElement(StraightLineTrack.z0Index, HelicalTrackFit.slopeIndex, s);
+        deriv.setElement(StraightLineTrack.dydxIndex, HelicalTrackFit.curvatureIndex, -s / (cphi*cphi));
+        deriv.setElement(StraightLineTrack.dydxIndex, HelicalTrackFit.phi0Index, 1. / (cphi*cphi));
+        double dzslopedphi0 = sphi * slope / (cphi*cphi);
+        deriv.setElement(StraightLineTrack.dzdxIndex, HelicalTrackFit.curvatureIndex, -s * dzslopedphi0);
+        deriv.setElement(StraightLineTrack.dzdxIndex, HelicalTrackFit.phi0Index, dzslopedphi0);
+        deriv.setElement(StraightLineTrack.dzdxIndex, HelicalTrackFit.slopeIndex, 1. / cphi);
+
+        //  Calculate the covariance matrix
+        Matrix derivT = MatrixTranspose(deriv);
+        SymmetricMatrix hcov = helix.covariance();
+        Matrix cov = MatrixOp.mult(deriv, MatrixOp.mult(hcov, derivT));
+        SymmetricMatrix scov = new SymmetricMatrix(cov);
+      
+        return new StraightLineTrack(xref, yref, zref, dydx, dzdx, scov);
+    }
+
+     /**
+     * Convert a helix to a StraightLineTrack.
+     *
+     * @param helix helix to be converted
+     * @return resulting StraightLineTrack
+     */
+    public StraightLineTrack Convert(Helix helix) {
+
+        Hep3Vector unitVec = helix.getUnitTangentAtLength(0);
+        Hep3Vector posVec = helix.getPointAtDistance(0);
+        double dzdx = unitVec.z()/unitVec.x();
+        double dydx = unitVec.y()/unitVec.x();
+        double zref = posVec.z() - dzdx*(posVec.x()-_xref); 
+        double yref = posVec.y() - dydx*(posVec.x()-_xref); 
+        SymmetricMatrix scov = null;
+        StraightLineTrack slt = new StraightLineTrack(_xref, yref, zref, dydx, dzdx, scov);
+        //System.out.printf("%s: unitVec %s posVec %s\n",this.getClass().getSimpleName(),unitVec.toString(),posVec.toString());
+        //System.out.printf("%s: dzdx=%f dydx=%s\n",this.getClass().getSimpleName(),dzdx,dydx);
+        //System.out.printf("%s: ref = %f,%f,%f\n",this.getClass().getSimpleName(),_xref,yref,zref);
+        return slt;
+    }
+
+    
+    
+    /**
+     * Returns the transpose of the matrix (inexplicably not handled by
+     * the matrix package for non-square matrices).
+     *
+     * @param m matrix to be transposed
+     * @return transposed matrix
+     */
+    private Matrix MatrixTranspose(Matrix m) {
+        MutableMatrix mt = new BasicMatrix(m.getNColumns(), m.getNRows());
+        for (int i = 0; i < m.getNRows(); i++) {
+            for (int j = 0; j < m.getNColumns(); j++) {
+                mt.setElement(j, i, m.e(i, j));
+            }
+        }
+        return mt;
+    }
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
HelixFitter.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/HelixFitter.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/HelixFitter.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,29 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.hps.recon.tracking;
+
+
+/**
+ * HPS extension of the fitter algorithm to enable the use of local classes
+ * @author Per Hansson Adrian <[log in to unmask]>
+ * @version $Id: HelixFitter.java,v 1.2 2013/11/07 03:54:58 phansson Exp $ $Date: 2013/11/07 03:54:58 $ $Author: phansson $ 
+ */
+public class HelixFitter extends org.lcsim.recon.tracking.seedtracker.HelixFitter {
+    
+    public HelixFitter(MaterialManager materialManager) {
+        super(materialManager);
+        //replace the multiple scattering to that given as parameter to be able to use a local version and not lcsim one
+        _scattering = new MultipleScattering(materialManager);
+
+    }
+    
+    public void setDebug(boolean debug) {
+        super.setDebug(debug);
+        _scattering.setDebug(debug);
+    } 
+    
+
+
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
LCIOTrackAnalysis.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/LCIOTrackAnalysis.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/LCIOTrackAnalysis.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,169 @@
+package org.hps.recon.tracking;
+
+import hep.physics.vec.BasicHep3Vector;
+import hep.physics.vec.Hep3Vector;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.hps.conditions.deprecated.SvtUtils;
+import org.lcsim.detector.identifier.IIdentifier;
+import org.lcsim.detector.identifier.Identifier;
+import org.lcsim.event.MCParticle;
+import org.lcsim.event.RawTrackerHit;
+import org.lcsim.event.RelationalTable;
+import org.lcsim.event.Track;
+import org.lcsim.event.TrackerHit;
+
+/**
+ *
+ * @author Sho Uemura <[log in to unmask]>
+ * @version $Id: LCIOTrackAnalysis.java,v 1.3 2013/10/24 18:11:43 meeg Exp $
+ */
+public class LCIOTrackAnalysis {
+
+    protected Track track;
+    protected MCParticle _mcp = null;
+    protected double _purity;
+    protected int _nhits;
+    protected int _nbadhits;
+    private int _nAxialhits;
+    private int _nZhits;
+    protected boolean _hasLayerOne;
+    private int[] _nStripHitsPerLayer = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    protected Map<Integer, Hep3Vector> _hitLocationPerLayer = new HashMap<Integer, Hep3Vector>();
+    protected int _nhitsNew;
+
+    public Track getTrack() {
+        return track;
+    }
+
+    public LCIOTrackAnalysis(Track trk, RelationalTable hittomc, RelationalTable hittostrip, RelationalTable hittorotated) {
+        track = trk;
+
+        //  Get the number of hits on the track
+        _nhits = trk.getTrackerHits().size();
+
+        //  Create a map containing the number of hits for each MCParticle associated with the track
+        Map<MCParticle, Integer> mcmap = new HashMap<MCParticle, Integer>();
+        _hasLayerOne = false;
+        //  Loop over the hits on the track (HelicalTrackHits)
+        for (TrackerHit rotatedHit : trk.getTrackerHits()) {
+            TrackerHit hit = (TrackerHit) hittorotated.from(rotatedHit);
+            //  get the set of MCParticles associated with this hit and update the hit count for each MCParticle
+            Set<MCParticle> mclist = hittomc.allFrom(hit);
+//            System.out.println("MCParticle count: " + mclist.size());
+            for (MCParticle mcp : mclist) {
+                if (mcp != null) {
+//                System.out.println(mcp.getOrigin());
+                    Integer mchits = 0;
+                    if (mcmap.containsKey(mcp)) {
+                        mchits = mcmap.get(mcp);
+                    }
+                    mchits++;
+                    mcmap.put(mcp, mchits);
+                }
+            }
+
+            Set<TrackerHit> hitlist = hittostrip.allFrom(hit);
+            for (TrackerHit cl : hitlist) {
+                int layer = -1;
+                int module = -1;
+                List<RawTrackerHit> rawHits = cl.getRawHits();
+//                System.out.println("RawHits: " + rawHits.size());
+                for (RawTrackerHit rawHit : rawHits) {
+//                    System.out.println(rawHit.getCellID());
+                    IIdentifier id = new Identifier(rawHit.getCellID());
+                    int newLayer = SvtUtils.getInstance().getHelper().getValue(id, "layer");
+                    if (layer != -1 && layer != newLayer) {
+                        System.out.format("TrackerHit has hits from multiple layers: %d and %d\n", layer, newLayer);
+                    }
+                    layer = newLayer;
+                    int newModule = SvtUtils.getInstance().getHelper().getValue(id, "module");
+                    if (module != -1 && module != newModule) {
+                        System.out.format("TrackerHit has hits from multiple modules: %d and %d\n", module, newModule);
+                    }
+                    module = newModule;
+//                    System.out.println(SvtUtils.getInstance().getHelper().getValue(id, "strip"));
+                }
+//                System.out.format("layer %d, module %d\n", layer, module);
+                if (layer == 1) {
+                    _hasLayerOne = true;
+                }
+
+
+                _nStripHitsPerLayer[layer - 1] = rawHits.size();
+                _hitLocationPerLayer.put(layer, new BasicHep3Vector(cl.getPosition()));
+                _nhitsNew++;
+
+                boolean isAxial = SvtUtils.getInstance().isAxial(SvtUtils.getInstance().getSensor(module, layer - 1));
+                if (isAxial) {
+                    _nAxialhits++;
+                } else {
+                    _nZhits++;
+
+                }
+            }
+        }
+
+        //  Find the MCParticle that has the most hits on the track
+
+        int nbest = 0;
+        MCParticle mcbest = null;
+        for (MCParticle mcp : mcmap.keySet()) {
+            int count = mcmap.get(mcp);
+            if (count > nbest) {
+                nbest = count;
+                mcbest = mcp;
+            }
+        }
+
+        if (nbest > 0) {
+            _mcp = mcbest;
+        }
+        _purity = (double) nbest / (double) _nhits;
+        _nbadhits = _nhits - nbest;
+    }
+
+    public MCParticle getMCParticle() {
+        return _mcp;
+    }
+
+    public int getNHits() {
+        return _nhits;
+    }
+
+    public int getNBadHits() {
+        return _nbadhits;
+    }
+
+    public double getPurity() {
+        return _purity;
+    }
+
+    public int getNHitsNew() {
+        return _nhitsNew;
+    }
+
+    public int getNAxialHits() {
+        return _nAxialhits;
+    }
+
+    public int getNZHits() {
+        return _nZhits;
+    }
+
+    public boolean hasLayerOne() {
+        return _hasLayerOne;
+    }
+
+    public Hep3Vector getClusterPosition(Integer layer) {
+        return _hitLocationPerLayer.get(layer);
+    }
+
+    public int getNumberOfStripHits(int layer) {
+        return _nStripHitsPerLayer[layer - 1];
+    }
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
MaterialManager.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/MaterialManager.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/MaterialManager.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,43 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.hps.recon.tracking;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.lcsim.recon.tracking.seedtracker.MaterialXPlane;
+
+
+
+/**
+ *
+ * Extension to lcsim MaterialManager to allow more flexibility in track reconstruction
+ *
+ * @author Per Hansson Adrian <[log in to unmask]>
+ * @version $Id: MaterialManager.java,v 1.3 2013/11/07 03:54:58 phansson Exp $ $Date: 2013/11/07 03:54:58 $ $Author: phansson $ 
+ */
+public class MaterialManager extends org.lcsim.recon.tracking.seedtracker.MaterialManager {
+    
+    protected boolean _includeMS = true;
+    private final static List<MaterialXPlane> _emptyMaterialXPlaneList = new ArrayList<MaterialXPlane>();
+    public MaterialManager() {
+        super();
+    }
+    public MaterialManager(boolean includeMS) {
+        super();
+        this._includeMS = includeMS;
+    }
+    @Override
+    public List<MaterialXPlane> getMaterialXPlanes() {
+        return this._includeMS ? super.getMaterialXPlanes() : _emptyMaterialXPlaneList;
+    }
+
+    @Override
+    public void setDebug(boolean debug) {
+        super.setDebug(debug);
+    }
+    
+    
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
MaterialSupervisor.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/MaterialSupervisor.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/MaterialSupervisor.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,421 @@
+package org.hps.recon.tracking;
+
+import hep.physics.vec.Hep3Vector;
+import hep.physics.vec.VecOp;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.hps.conditions.deprecated.SvtUtils;
+import org.lcsim.detector.IDetectorElement;
+import org.lcsim.detector.IGeometryInfo;
+import org.lcsim.detector.ILogicalVolume;
+import org.lcsim.detector.IPhysicalVolume;
+import org.lcsim.detector.IPhysicalVolumeContainer;
+import org.lcsim.detector.ITransform3D;
+import org.lcsim.detector.Translation3D;
+import org.lcsim.detector.material.IMaterial;
+import org.lcsim.detector.solids.Box;
+import org.lcsim.detector.solids.ISolid;
+import org.lcsim.detector.solids.Polygon3D;
+import org.lcsim.detector.tracker.silicon.ChargeCarrier;
+import org.lcsim.detector.tracker.silicon.SiSensor;
+import org.lcsim.detector.tracker.silicon.SiTrackerModule;
+import org.lcsim.geometry.Detector;
+
+
+
+/**
+ * Material manager using the detector geometry. 
+
+ * Uses a private class to set up detector volumes. 
+ * This can probably make use of the DetectorGeometry classes from lcsim instead for the model.
+ * Something to consider in the future.
+ *  
+ * @author Per Hansson Adrian <[log in to unmask]>
+ * @version $Id: MaterialSupervisor.java,v 1.4 2013/11/07 03:54:58 phansson Exp $ $Date: 2013/11/07 03:54:58 $ $Author: phansson $ 
+ */
+public class MaterialSupervisor extends MaterialManager {
+    
+    private List<ScatteringDetectorVolume> _detectorVolumes = new ArrayList<ScatteringDetectorVolume>();
+    
+
+    public MaterialSupervisor() {
+        super();
+        this._includeMS = true;
+    }
+    public MaterialSupervisor(boolean includeMS) {
+        super(includeMS);
+    }
+    
+    @Override
+    public void setDebug(boolean debug) {
+        super.setDebug(debug);
+    }
+    
+    public List<ScatteringDetectorVolume> getMaterialVolumes() {
+        return _detectorVolumes;
+    }
+
+    @Override
+    public void buildModel(Detector det) {
+        //super.buildModel(det);
+        //if(DEBUG) 
+        System.out.printf("%s: ###########################################################\n",this.getClass().getSimpleName());
+        System.out.printf("%s: Build detector model\n",this.getClass().getSimpleName());
+        List<SiSensor> sensors = det.getSubdetector("Tracker").getDetectorElement().findDescendants(SiSensor.class);
+        //List<SiTrackerModule> modules = det.getDetectorElement().findDescendants(SiTrackerModule.class);
+        System.out.printf("%s: %d sensors\n",this.getClass().getSimpleName(),sensors.size());
+        System.out.printf("%s: %5s %32s %22s %15s %10s %10s\n",this.getClass().getSimpleName(),"ID","Pos (mm)","size(mm)","t(mm)","t(%R.L)","type");
+        for (SiSensor module: sensors) {
+            
+            SiStripPlane plane = new SiStripPlane(module);
+                    
+            System.out.printf("%s: %5d %32s %15.2fx%.2f %10.2f %10.3f %10s\n",this.getClass().getSimpleName(),plane.getId(),plane.origin().toString(),
+                                                                                plane.getUnmeasuredDimension(),plane.getMeasuredDimension(),
+                                                                                plane.getThickness(),plane.getThicknessInRL()*100,
+                                                                                SvtUtils.getInstance().isAxial(module) ? "axial" : "stereo");            
+            _detectorVolumes.add(plane);     
+        }
+        System.out.printf("%s: ###########################################################\n",this.getClass().getSimpleName());
+    }
+    
+    
+    
+    public interface ScatteringDetectorVolume {
+        public String getName();
+        public double getMaterialTraversed(Hep3Vector dir);
+        public double getMaterialTraversedInRL(Hep3Vector dir);
+        public void print();
+        public IDetectorElement getDetectorElement();
+    }
+    
+    //public abstract class DetectorPlane extends SiSensor {
+    public interface DetectorPlane  extends ScatteringDetectorVolume{
+        public double getThickness();
+        public double getThicknessInRL();
+        public double getLength();
+        public double getWidth();
+        public Hep3Vector origin();
+        public Hep3Vector normal();
+        public int getId();
+
+    }
+    
+    private abstract class SiPlane implements DetectorPlane {
+        abstract void addMaterial();
+    }
+    
+    public class SiStripPlane extends SiPlane {
+        private Hep3Vector _org = null; // origin
+        private Hep3Vector _w = null;   // normal to plane
+        private Hep3Vector _u = null;
+        private Hep3Vector _v = null;
+        private Materials _materials = new Materials();
+        private SiSensor _sensor;
+        private double _length;
+        private double _width;
+
+        public SiStripPlane(SiSensor module) {
+            _sensor = module;
+            setOrigin();
+            setNormal();
+            setMeasuredCoordinate();
+            setUnmeasuredCoordinate();
+            setDimensions();
+            addMaterial();
+            
+        }
+        
+        @Override
+        public IDetectorElement getDetectorElement() {
+            return getSensor();
+        }
+        
+        private SiTrackerModule getModule() {
+            return (SiTrackerModule)getGeometry().getDetectorElement().getParent();
+        }
+        
+     
+        private  IGeometryInfo getGeometry() {
+            return getSensor().getGeometry();
+        }
+        
+        SiSensor getSensor() {
+            return _sensor;
+        }
+        
+        Polygon3D getPsidePlane() {
+            return getSensor().getBiasSurface(ChargeCarrier.HOLE);
+        }
+
+        Polygon3D getNsidePlane() {
+            return getSensor().getBiasSurface(ChargeCarrier.ELECTRON);
+        }
+    
+       
+        
+        @Override
+        public double getMaterialTraversed(Hep3Vector dir) {
+            //the distance inside the plane (note I don't care about sign of unit vector only projection distance)
+            double cth = Math.abs(VecOp.dot(dir, _w));
+            double t = _materials.getThickness();
+            return t/cth;
+        }
+
+        @Override
+        public double getMaterialTraversedInRL(Hep3Vector dir) {
+            //the distance inside the plane (note I don't care about sign of unit vector only projection distance)
+            double cth = Math.abs(VecOp.dot(dir, _w));
+            double t = _materials.getThicknessInRL();
+            return t/cth;
+        }
+
+        @Override
+        protected void addMaterial() {
+            
+            IPhysicalVolume parent = getModule().getGeometry().getPhysicalVolume();
+            IPhysicalVolumeContainer daughters = parent.getLogicalVolume().getDaughters();
+            //System.out.printf("%s found %d daugters to SiTrackerModule\n",this.getClass().getSimpleName(),daughters.size());
+            for(IPhysicalVolume daughter : daughters) {
+                ILogicalVolume logicalVolume = daughter.getLogicalVolume();
+                IMaterial material = logicalVolume.getMaterial();
+                String name = material.getName();
+                double X0 = 10.0* material.getRadiationLength()/material.getDensity();
+                Box solid = (Box) logicalVolume.getSolid();
+                //System.out.printf("%s x %f y %f z %f box\n",this.getClass().getSimpleName(),solid.getXHalfLength(),solid.getYHalfLength(),solid.getZHalfLength());
+                double halfThickness = solid.getZHalfLength();
+                addMaterial(name, material.getDensity()/1000.0, X0,2.0*halfThickness);
+            }
+        }
+        
+        public void addMaterial(String type, double density, double radLen, double t) {
+            _materials.add(type, density, radLen, t);
+        }
+        
+        
+        @Override
+        public double getThickness() {
+            return _materials.getThickness();
+        }
+
+        @Override
+        public double getThicknessInRL() {
+            return _materials.getThicknessInRL();
+        }
+
+        private void setDimensions() {
+            // The dimensions are taken from the full module
+            IPhysicalVolume physVol_parent = getModule().getGeometry().getPhysicalVolume();
+            ILogicalVolume logVol_parent = physVol_parent.getLogicalVolume();
+            ISolid solid_parent = logVol_parent.getSolid();
+            Box box_parent;
+            if(Box.class.isInstance(solid_parent)) {
+                box_parent = (Box) solid_parent;
+            } else {
+                throw new RuntimeException("Couldn't cast the module volume to a box!?");
+            }
+            _length = box_parent.getXHalfLength()*2.0;
+            _width = box_parent.getYHalfLength()*2.0;
+            
+        }
+        
+        @Override
+        public Hep3Vector origin() {
+            
+            return _org;
+        }
+
+        public void setOrigin(Hep3Vector org) {
+             
+            this._org = org;
+        }
+
+        private void setOrigin() {
+            // Use origin of p-side surface
+            Hep3Vector origin = VecOp.mult(HPSTransformations.getMatrix(),_sensor.getGeometry().getPosition());
+            //transform to p-side
+            Polygon3D psidePlane = this.getPsidePlane();
+            Translation3D transformToPside = new Translation3D(VecOp.mult(-1*psidePlane.getDistance(), psidePlane.getNormal()));
+            this._org = transformToPside.translated(origin);
+        }
+        
+        @Override
+        public Hep3Vector normal() {
+            if(_w==null) {
+                _w = this.getPsidePlane().getNormal();
+                System.out.printf("setting normal from pside normal %s\n",_w.toString());
+                _w = VecOp.mult(VecOp.mult(HPSTransformations.getMatrix(),getSensor().getReadoutElectrodes(ChargeCarrier.HOLE).getLocalToGlobal().getRotation().getRotationMatrix()), _w);
+                System.out.printf("normal after local to global to tracking rotation %s\n",_w.toString());
+            }
+            return this._w;
+        }
+        
+        private void setNormal() {
+            _w = this.getPsidePlane().getNormal();
+            _w = VecOp.mult(VecOp.mult(HPSTransformations.getMatrix(),getSensor().getReadoutElectrodes(ChargeCarrier.HOLE).getLocalToGlobal().getRotation().getRotationMatrix()), _w);
+        }
+        
+        public void setNormal(Hep3Vector w) {
+            this._w = w;
+        }
+
+        @Override
+        public void print() {
+            System.out.printf("DetectorPlane:  org %s normal vector %s %.2fx%.2fmm  thickness %f R.L. (%fmm)\n",
+                                origin().toString(),normal().toString(),getLength(),getWidth(),
+                                getThicknessInRL(),getThickness());
+        }
+        
+        @Override
+        public int getId() {
+            return _sensor.getSensorID();
+        }
+
+        @Override
+        public String getName() {
+            return _sensor.getName();
+        }
+
+        @Override
+        public double getLength() {
+            return _length;
+        }
+
+        @Override
+        public double getWidth() {
+            return _width;
+        }
+        
+        double getMeasuredDimension() {
+            return getLength();
+        }
+
+        double getUnmeasuredDimension() {
+            return getWidth();
+        }
+        
+        Hep3Vector getUnmeasuredCoordinate() {
+            return _v;
+        }
+        Hep3Vector getMeasuredCoordinate() {
+            return _u;
+        }
+        
+        private  void setMeasuredCoordinate()
+        {
+            // p-side unit vector
+            ITransform3D electrodes_to_global = getSensor().getReadoutElectrodes(ChargeCarrier.HOLE).getLocalToGlobal();
+            Hep3Vector measuredCoordinate = getSensor().getReadoutElectrodes(ChargeCarrier.HOLE).getMeasuredCoordinate(0);
+            measuredCoordinate = VecOp.mult(VecOp.mult(HPSTransformations.getMatrix(),electrodes_to_global.getRotation().getRotationMatrix()), measuredCoordinate);
+            _u = measuredCoordinate;
+        }
+        
+        private  void setUnmeasuredCoordinate()
+        {
+            // p-side unit vector
+            ITransform3D electrodes_to_global = getSensor().getReadoutElectrodes(ChargeCarrier.HOLE).getLocalToGlobal();
+            Hep3Vector unmeasuredCoordinate = getSensor().getReadoutElectrodes(ChargeCarrier.HOLE).getUnmeasuredCoordinate(0);
+            unmeasuredCoordinate = VecOp.mult(VecOp.mult(HPSTransformations.getMatrix(),electrodes_to_global.getRotation().getRotationMatrix()), unmeasuredCoordinate);
+            _v = unmeasuredCoordinate;
+        }
+
+        
+        
+
+    }
+    
+    
+    
+    
+    
+    
+    private static class Material {
+        private String _name;
+        private double _X0;
+        private double _density;
+        private double _thickness;
+        public Material(String _name, double _X0, double _density, double _thickness) {
+            this._name = _name;
+            this._X0 = _X0;
+            this._density = _density;
+            this._thickness = _thickness;
+        }
+        private void add(double t) {
+            _thickness+=t;
+        }
+
+        public double getThickness() {
+            return _thickness;
+        }
+
+        public double getDensity() {
+            return _density;
+        }
+
+        public double getX0() {
+            return _X0;
+        }
+        
+    }
+    
+    private static class Materials {
+        private List<Material> _materials = new ArrayList<Material>();
+        private double _tot_X0 = -1;
+        public Materials() {
+        }
+        public int numberOfMaterials() {
+            return _materials.size();
+        }
+        public void add(String mat,double density, double radLen, double t) {
+            boolean found = false;
+            for(Material m : _materials) {
+                if(m._name==mat) {
+                    m.add(t);
+                    found=true;
+                    break;
+                } 
+            }
+            if (!found) {
+                //System.out.printf("%s: Adding %.2fmm of %s \n",this.getClass().getSimpleName(),t,mat);
+                _materials.add(new Material(mat,radLen,density,t));
+            }
+            
+        }
+        public double getThicknessInRL() {
+            if(_materials.isEmpty()) return 0;
+            if(_tot_X0<0) {
+                double sum = 0.;
+                for(Material m : _materials) {
+                    sum += m.getDensity()*m.getThickness();
+                }
+                //System.out.printf("sum = %f\n",sum);
+                double tot_X0 = 0.;
+                for(Material m : _materials) {
+                    double w_j = m._density*m.getThickness()/(numberOfMaterials()*sum);
+                    tot_X0 += w_j/(m.getThickness()/m.getX0());
+                }
+                //System.out.printf("tot_X0 = %f\n",tot_X0);
+                _tot_X0 = 1.0/tot_X0;
+            }
+            return _tot_X0;
+        }
+
+        private double getThickness() {
+            double t_tot = 0.;
+            for(Material m : _materials) {
+                t_tot += m.getThickness();
+            }
+            return t_tot;
+        }
+        
+    }
+    
+
+
+    
+
+    
+    
+    
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
MultipleScattering.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/MultipleScattering.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/MultipleScattering.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,455 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.hps.recon.tracking;
+
+import hep.physics.vec.Hep3Vector;
+import hep.physics.vec.VecOp;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.hps.recon.tracking.MaterialSupervisor.ScatteringDetectorVolume;
+import org.hps.recon.tracking.MaterialSupervisor.SiStripPlane;
+import org.lcsim.detector.IDetectorElement;
+import org.lcsim.detector.solids.Inside;
+import org.lcsim.detector.tracker.silicon.ChargeCarrier;
+import org.lcsim.fit.helicaltrack.HelicalTrackFit;
+import org.lcsim.fit.helicaltrack.HelixUtils;
+import org.lcsim.recon.tracking.seedtracker.ScatterAngle;
+
+
+/**
+ * Extention of lcsim class to allow use of local classes.
+ * Finds scatter points and magnitude from detector geometry directly.
+ * @author Per Hansson Adrian <[log in to unmask]>
+ * @version $Id: MultipleScattering.java,v 1.7 2013/11/07 03:54:58 phansson Exp $ $Date: 2013/11/07 03:54:58 $ $Author: phansson $ 
+ */
+public class MultipleScattering extends org.lcsim.recon.tracking.seedtracker.MultipleScattering {
+
+
+    
+    //public MultipleScattering(MaterialSupervisor materialmanager) {
+    //    super(materialmanager);
+    //}
+    
+    public MultipleScattering(MaterialManager materialmanager) {
+        super(materialmanager);
+    }
+
+    /**
+     * Override lcsim version and select material manager depending on object type. This allows to use a local extension of the material manager in teh lcsim track fitting code. 
+     * 
+     * @param helix
+     * @return a list of ScatterAngle. 
+     */
+    public List<ScatterAngle> FindScatters(HelicalTrackFit helix) {
+        if(_debug) System.out.printf("\n%s: FindScatters() for helix:\n%s\n",this.getClass().getSimpleName(),helix.toString());        
+        
+        if(MaterialSupervisor.class.isInstance(this._materialmanager)) {
+            if(_debug) System.out.printf("%s: use HPS scattering model",this.getClass().getSimpleName());    
+            return this.FindHPSScatters(helix);
+        } else {
+            if(_debug) System.out.printf("%s: use default lcsim material manager to find scatters\n",this.getClass().getSimpleName());    
+            return super.FindScatters(helix);
+        }
+    }
+
+    /**
+     * Extra interface to keep a function returning the same type as the lcsim version
+     * 
+     * @param helix
+     * @return a list of ScatterAngle. 
+     */
+    private List<ScatterAngle> FindHPSScatters(HelicalTrackFit helix) {
+        ScatterPoints scatterPoints = this.FindHPSScatterPoints(helix);
+        return scatterPoints.getScatterAngleList();
+    }
+
+
+    
+    /**
+     * Find scatter points along helix using the local material manager
+     * 
+     * @param helix
+     * @return the points of scatter along the helix 
+     */
+    public ScatterPoints FindHPSScatterPoints(HelicalTrackFit helix) {
+        if(_debug) System.out.printf("\n%s: FindHPSScatters() for helix:\n%s\n",this.getClass().getSimpleName(),helix.toString());  
+        
+        //  Check that B Field is set
+        if (_bfield == 0.) throw new RuntimeException("B Field must be set before calling FindScatters method");
+
+        //  Create a new list to contain the mutliple scatters
+        //List<ScatterAngle> scatters = new ArrayList<ScatterAngle>();
+        ScatterPoints scatters = new ScatterPoints();
+        
+        MaterialSupervisor materialSupervisor = (MaterialSupervisor) this._materialmanager;
+        
+        List<ScatteringDetectorVolume> materialVols = materialSupervisor.getMaterialVolumes();
+        
+        if(_debug) System.out.printf("%s: there are %d detector volumes in the model\n",this.getClass().getSimpleName(),materialVols.size());
+        
+        for(ScatteringDetectorVolume vol : materialVols) {
+        
+            if(_debug) System.out.printf("\n%s: found detector volume \"%s\"\n",this.getClass().getSimpleName(),vol.getName());
+                    
+            // find intersection pathpoint with helix
+            Hep3Vector pos = getHelixIntersection(helix,vol);
+
+            if(pos!=null) {
+
+                if(_debug) System.out.printf("%s: intersection position %s\n",this.getClass().getSimpleName(),pos.toString());
+
+                // find the track direction at the plane
+
+                double s = HelixUtils.PathToXPlane(helix, pos.x(), 0.,0).get(0);
+
+                if(_debug) System.out.printf("%s: path length %f\n",this.getClass().getSimpleName(),s);
+
+                Hep3Vector dir = HelixUtils.Direction(helix, s);
+
+                if(_debug) System.out.printf("%s: track dir %s\n",this.getClass().getSimpleName(),dir.toString());
+
+
+                //Calculate the material the track will traverse
+                double radlen = vol.getMaterialTraversedInRL(dir);
+
+                if(_debug) System.out.printf("%s: material traversed: %f R.L. (%fmm) \n",
+                                            this.getClass().getSimpleName(),radlen,vol.getMaterialTraversed(dir));
+
+                double p = helix.p(this._bfield);
+                double msangle = this.msangle(p, radlen);
+
+                ScatterAngle scat = new ScatterAngle(s,msangle);
+
+                if(_debug) System.out.printf("%s: scatter angle %f rad for p %f GeV at path length %f\n",
+                                            this.getClass().getSimpleName(),scat.Angle(),p,scat.PathLen());
+
+                ScatterPoint scatterPoint = new ScatterPoint(vol.getDetectorElement(),scat);
+                scatters.addPoint(scatterPoint);
+                
+            } else {
+                
+                if(_debug) System.out.printf("\n%s: helix did not intersect this volume \n",this.getClass().getSimpleName());
+                
+            }
+                                           
+        }
+        
+        //  Sort the multiple scatters by their path length
+        Collections.sort(scatters._points);
+
+        if(_debug) {
+            System.out.printf("\n%s: found %d scatters for this helix:\n",this.getClass().getSimpleName(),scatters.getPoints().size());
+            System.out.printf("%s: %10s %10s\n",this.getClass().getSimpleName(),"s (mm)","theta(rad)");
+            for (ScatterPoint p : scatters.getPoints()) {
+                System.out.printf("%s: %10.2f %10f\n",this.getClass().getSimpleName(),p.getScatterAngle().PathLen(),p.getScatterAngle().Angle());
+            }
+        }
+        return scatters;
+   
+    }
+    
+    
+    public Hep3Vector getHelixIntersection(HelicalTrackFit helix, ScatteringDetectorVolume plane) {
+        
+        if(SiStripPlane.class.isInstance(plane)) {
+            return getHelixIntersection( helix,  (SiStripPlane)plane);            
+        } else {
+            throw new UnsupportedOperationException("This det volume type is not supported yet.");
+        }
+    }
+
+    /*
+     * Returns interception between helix and plane
+     * Uses the origin x posiution of the plane
+     * and extrapolates linearly to find teh intersection
+     * If inside use an iterative "exact" way to determine the final position
+     */
+    
+    public Hep3Vector getHelixIntersection(HelicalTrackFit helix, SiStripPlane plane) {
+        
+        if(this._debug) {
+            System.out.printf("%s: calculate simple helix intercept\n",this.getClass().getSimpleName());
+            System.out.printf("%s: StripSensorPlane:\n",this.getClass().getSimpleName());
+            plane.print();
+        }
+        
+        
+        double s_origin = HelixUtils.PathToXPlane(helix, plane.origin().x(),0.,0).get(0);
+
+        if(Double.isNaN(s_origin)) {
+            if(this._debug) System.out.printf("%s: could not extrapolate to XPlane, too large curvature: origin is at %s \n", this.getClass().getSimpleName(),plane.origin().toString());
+            return null;
+        }
+        
+        Hep3Vector pos = HelixUtils.PointOnHelix(helix, s_origin);
+        Hep3Vector direction = HelixUtils.Direction(helix, s_origin);
+
+        if(this._debug) System.out.printf("%s: position at x=origin is %s with path length %f and direction %s\n",
+                                        this.getClass().getSimpleName(),pos.toString(),s_origin,direction.toString());
+                                        
+        // Use this approximate position to get a first estimate if the helix intercepted the plane
+        // This is only because the real intercept position is an iterative procedure and we'd 
+        // like to avoid using it if possible
+        // Consider the plane as pure x-plane i.e. no rotations 
+        //-> this is not very general, as it assumes that strips are (mostly) along y -> FIX THIS!?
+
+        
+        // Transformation from tracking to detector frame
+        Hep3Vector pos_det = VecOp.mult(VecOp.inverse(HPSTransformations.getMatrix()),pos);
+        Hep3Vector direction_det = VecOp.mult(VecOp.inverse(HPSTransformations.getMatrix()),direction);
+        
+        
+        if(this._debug) System.out.printf("%s: position in det frame %s and direction %s\n",
+                                        this.getClass().getSimpleName(),pos_det.toString(),direction_det.toString());
+        
+        // Transformation from detector frame to sensor frame
+        Hep3Vector pos_sensor = plane.getSensor().getReadoutElectrodes(ChargeCarrier.HOLE).getGlobalToLocal().transformed(pos_det);
+        Hep3Vector direction_sensor = plane.getSensor().getReadoutElectrodes(ChargeCarrier.HOLE).getGlobalToLocal().rotated(direction_det);
+        
+        
+        if(this._debug) System.out.printf("%s: position in sensor frame %s and direction %s\n",
+                                        this.getClass().getSimpleName(),pos_sensor.toString(),direction_sensor.toString());
+        
+        
+        // find step in w to cross sensor plane
+        double delta_w = -1.0*pos_sensor.z()/direction_sensor.z();
+        
+        // find the point where it crossed the plane
+        
+        Hep3Vector pos_int = VecOp.add(pos_sensor, VecOp.mult(delta_w, direction_sensor));
+        Hep3Vector pos_int_det = plane.getSensor().getReadoutElectrodes(ChargeCarrier.HOLE).getLocalToGlobal().transformed(pos_int);
+        // find the intercept in the tracking frame
+        Hep3Vector pos_int_trk = VecOp.mult(HPSTransformations.getMatrix(),pos_int_det);
+ 
+        
+        if(this._debug) System.out.printf("%s: take step %f to get intercept position in sensor frame %s (det: %s trk: %s)\n",
+                                        this.getClass().getSimpleName(), delta_w, pos_int, pos_int_det.toString(), pos_int_trk.toString());
+        
+        // check if it's inside the sensor
+        Inside result_inside = plane.getDetectorElement().getGeometry().getPhysicalVolume().getMotherLogicalVolume().getSolid().inside(pos_int);
+        Inside result_inside_module = plane.getSensor().getGeometry().getDetectorElement().getParent().getGeometry().inside(pos_int_det);
+        
+        if(this._debug) System.out.printf("%s: Inside result sensor: %s module: %s\n",
+                                this.getClass().getSimpleName(), 
+                                result_inside.toString(),
+                                result_inside_module.toString());
+
+        
+        
+        boolean isInsideSolid = false;
+        if(result_inside.equals(Inside.INSIDE) || result_inside.equals(Inside.SURFACE)) {
+            isInsideSolid = true;
+        }
+        
+        boolean isInsideSolidModule = false;
+        if(result_inside_module.equals(Inside.INSIDE) || result_inside_module.equals(Inside.SURFACE)) {
+            isInsideSolidModule = true;
+        }
+
+        
+        boolean isInside = true;
+        if(Math.abs(pos_int.x()) > plane.getMeasuredDimension()/2.0) {
+            if(this._debug) System.out.printf("%s: intercept is outside in u\n", this.getClass().getSimpleName());
+            isInside = false;
+        }
+        
+        if(Math.abs(pos_int.y()) > plane.getUnmeasuredDimension()/2.0) {
+            if(this._debug) System.out.printf("%s: intercept is outside in v\n", this.getClass().getSimpleName());
+            isInside = false;
+        }
+        
+        
+        if(!isInside) return null;
+        
+        if(this._debug) {
+            System.out.printf("%s: found intercept at %s \n",this.getClass().getSimpleName(),pos_int_trk.toString());
+        }
+
+        
+        // Check if it's inside sensor and module and if it contradicts the manual calculation
+        // For now: trust manual calculation and output warning if it's outside BOTH sensor AND module -> FIX THIS!?
+        
+        if(!isInsideSolid ) {
+            if(_debug) System.out.printf("%s: manual calculation says inside sensor, inside solid says outside -> contradiction \n", this.getClass().getSimpleName());
+            if(isInsideSolidModule) {
+                if(_debug) System.out.printf("%s: this intercept is outside sensor but inside module\n", this.getClass().getSimpleName());
+            } else {
+                if(_debug) System.out.printf("%s: warning: this intercept at %s, in sensor frame %s, (sensor origin at %s ) is outside sensor and module!\n", 
+                                            this.getClass().getSimpleName(),pos_int_trk.toString(),pos_int.toString(),plane.origin().toString());
+            }
+        }
+
+        
+       
+
+        // Catch special cases where the incidental iteration procedure seem to fail -> FIX THIS!
+        if(helix.p(Math.abs(_bfield)) < 0.3) {
+
+            if(this._debug) System.out.printf("%s: momentum is low skip the iterative calculation\n",this.getClass().getSimpleName());
+            
+            return pos_int_trk;
+        }
+
+        if(this._debug) System.out.printf("%s: calculate iterative helix intercept\n",this.getClass().getSimpleName());
+
+        
+        pos = TrackUtils.getHelixPlaneIntercept(helix, plane.normal(), plane.origin(), _bfield);
+        
+        if(pos==null) {
+            
+//            throw new RuntimeException(String.format("%s: iterative intercept failed for helix \n%s\n with org=%s,w=%s, B=%f\n pdef=%f and pdef_pos=%s",
+//                                        this.getClass().getSimpleName(),helix.toString(),plane.origin().toString(),plane.normal().toString(),_bfield,s_origin,pos));                
+//            
+            System.out.printf("%s: iterative intercept failed for helix \n%s\n at sensor with org=%s, unit w=%s => use approx intercept pos=%s at path %f\n",
+                             this.getClass().getSimpleName(),helix.toString(),plane.origin().toString(),plane.normal().toString(),pos, s_origin);                
+            
+            return pos_int_trk;
+            
+        }   
+        
+        
+        if(this._debug) {
+            System.out.printf("%s: iterative helix intercept point at %s (diff to approx: %s) \n",this.getClass().getSimpleName(),pos.toString(),VecOp.sub(pos, pos_int_trk).toString());
+        }
+        
+        
+        
+        // find position in sensor frame
+        pos_int_det = VecOp.mult(VecOp.inverse(HPSTransformations.getMatrix()), pos);
+        Hep3Vector pos_int_sensor = plane.getSensor().getGeometry().getGlobalToLocal().transformed(VecOp.mult(VecOp.inverse(HPSTransformations.getMatrix()), pos));
+        
+        if(this._debug) System.out.printf("%s: found iterative helix intercept in sensor coordinates at %s\n",
+                this.getClass().getSimpleName(),pos_int_sensor.toString());
+        result_inside = plane.getDetectorElement().getGeometry().getPhysicalVolume().getMotherLogicalVolume().getSolid().inside(pos_int_sensor);
+        result_inside_module = plane.getSensor().getGeometry().getDetectorElement().getParent().getGeometry().inside(pos_int_det);
+        
+        if(this._debug) System.out.printf("%s: Inside result sensor: %s module: %s\n",
+                                this.getClass().getSimpleName(), 
+                                result_inside.toString(),
+                                result_inside_module.toString());
+
+        
+        
+        isInsideSolid = false;
+        if(result_inside.equals(Inside.INSIDE) || result_inside.equals(Inside.SURFACE)) {
+            isInsideSolid = true;
+        }
+        
+        isInsideSolidModule = false;
+        if(result_inside_module.equals(Inside.INSIDE) || result_inside_module.equals(Inside.SURFACE)) {
+            isInsideSolidModule = true;
+        }
+
+
+        isInside = true;
+        if(Math.abs(pos_int.x()) > plane.getMeasuredDimension()/2.0) {
+            if(this._debug) System.out.printf("%s: intercept is outside in u\n", this.getClass().getSimpleName());
+            isInside = false;
+        }
+        
+        if(Math.abs(pos_int.y()) > plane.getUnmeasuredDimension()/2.0) {
+            if(this._debug) System.out.printf("%s: intercept is outside in v\n", this.getClass().getSimpleName());
+            isInside = false;
+        }
+        
+        
+        
+         
+        // Check if it's inside sensor and module and if it contradicts the manual calculation
+        // For now: trust manual calculation and output warning if it's outside BOTH sensor AND module -> FIX THIS!?
+        
+        if(!isInsideSolid ) {
+            if(_debug) System.out.printf("%s: manual iterative calculation says inside sensor, inside solid says outside -> contradiction \n", this.getClass().getSimpleName());
+            if(isInsideSolidModule) {
+                if(_debug) System.out.printf("%s: this iterative intercept is outside sensor but inside module\n", this.getClass().getSimpleName());
+            } else {
+                if(_debug) System.out.printf("%s: warning: this iterative intercept %s, sensor frame %s, (sensor origin %s ) is outside sensor and module!\n", 
+                            this.getClass().getSimpleName(),pos_int_trk.toString(),pos_int.toString(),plane.origin().toString());
+            }
+        }
+        
+        if(!isInside) return null;
+        
+        if(this._debug) {
+            System.out.printf("%s: found intercept at %s \n",this.getClass().getSimpleName(),pos_int_trk.toString());
+        }
+        
+        return pos_int_trk;
+        
+      
+    
+    }
+    
+    @Override
+    public void setDebug(boolean debug) {
+        _debug = debug;
+    }
+
+    public MaterialManager getMaterialManager() {
+        // Should be safe to cast here
+        return (MaterialManager)_materialmanager;
+    }
+    
+    /**
+     * Nested class to encapsulate the scatter angles and which detector element it is related to
+     */
+    public class ScatterPoint implements Comparable<ScatterPoint> {
+        IDetectorElement _det;
+        ScatterAngle _scatterAngle;
+        public ScatterPoint(IDetectorElement det, ScatterAngle scatterAngle) {
+            _det = det;
+            _scatterAngle = scatterAngle;
+        }
+        public IDetectorElement getDet() {
+            return _det;
+        }
+        public ScatterAngle getScatterAngle() {
+            return _scatterAngle;
+        }
+
+        @Override
+        public int compareTo(ScatterPoint p) {
+                return p.getScatterAngle().PathLen() > this._scatterAngle.PathLen() ? -1 : 1;
+        }
+    }
+    
+    /**
+     * Nested class to encapsulate a list of scatters
+     * 
+     */
+    public class ScatterPoints {
+        private List<ScatterPoint> _points;
+        public ScatterPoints(List<ScatterPoint> _points) {
+            this._points = _points;
+        }
+        private ScatterPoints() {
+            _points = new ArrayList<ScatterPoint>();
+        }
+        public List<ScatterPoint> getPoints() {
+            return _points;
+        }
+        public void addPoint(ScatterPoint point) {
+            _points.add(point);
+        }
+        private List<ScatterAngle> getScatterAngleList() {
+            List<ScatterAngle> scatters = new ArrayList<ScatterAngle>();
+            for(ScatterPoint p : _points) scatters.add(p._scatterAngle);
+            return scatters;
+        }
+
+        public ScatterPoint getScatterPoint(IDetectorElement detectorElement) {
+            for(ScatterPoint p : _points) {
+                if(p.getDet().equals(detectorElement)) {
+                    return p;
+                }
+            }
+            return null;
+        }
+    }
+    
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
NoiselessReadoutChip.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/NoiselessReadoutChip.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/NoiselessReadoutChip.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,318 @@
+/*
+ * Class BasicReadoutChip
+ */
+package org.hps.recon.tracking;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.hps.conditions.deprecated.HPSSVTCalibrationConstants;
+import org.lcsim.detector.tracker.silicon.SiSensor;
+import org.lcsim.detector.tracker.silicon.SiSensorElectrodes;
+import org.lcsim.event.RawTrackerHit;
+import org.lcsim.recon.tracking.digitization.sisim.ReadoutChip;
+import org.lcsim.recon.tracking.digitization.sisim.SiElectrodeData;
+import org.lcsim.recon.tracking.digitization.sisim.SiElectrodeDataCollection;
+
+/**
+ * Basic readout chip class.  This class supports the minimal functions expected of
+ * a readout chip.  The charge on a strip/pixel is digitized as an integer number
+ * with a simple ADC with programmable resolution and dynamic range.  A chip with
+ * 1-bit ADC resolution (binary readout) is treated as a special case.
+ * 
+ * Noise is added to strips with charge and random noise hits are generated as well.
+ * Methods are provided to decode the charge and time (although the current
+ * implementation always returns a time of 0).
+ *
+ * This implementation has thresholds that are settable in units of RMS noise of
+ * each channel to enable simluation of highly optimized readout chains.  If
+ * absolute thresholds are desired, GenericReadoutChip should be used instead.
+ *
+ * @author Tim Nelson
+ */
+public class NoiselessReadoutChip implements ReadoutChip {
+
+    private BasicChannel _channel = new BasicChannel();
+    private ADC _adc = new ADC();
+    private boolean dropBadChannels = false;
+
+    /** Creates a new instance of BasicReadoutChip */
+    public NoiselessReadoutChip() {
+    }
+
+    public void setDropBadChannels(boolean dropBadChannels) {
+        this.dropBadChannels = dropBadChannels;
+    }
+
+    /**
+     * Set the noise intercept (i.e., the noise for 0 strip/pixel capacitance).
+     * Units are electrons of noise.
+     *
+     * @param noise_intercept noise for 0 capacitance
+     */
+    public void setNoiseIntercept(double noise_intercept) {
+        _channel.setNoiseIntercept(noise_intercept);
+    }
+
+    /**
+     * Set the noise slope (i.e., the proportionality between noise and capacitance).
+     * Units are electrons of noise per fF of capacitance.
+     *
+     * @param noise_slope noise slope per unit capacitance
+     */
+    public void setNoiseSlope(double noise_slope) {
+        _channel.setNoiseSlope(noise_slope);
+    }
+
+    /**
+     * Set the number of bits of ADC resolution
+     *
+     * @param nbits
+     */
+    public void setNbits(int nbits) {
+        getADC().setNbits(nbits);
+    }
+
+    /**
+     * Set the dynamic range of the ADC
+     *
+     * @param dynamic_range in fC
+     */
+    public void setDynamicRange(double dynamic_range) {
+        getADC().setDynamicRange(dynamic_range);
+    }
+
+    /**
+     * Return the BasicChannel associated with a given channel number.
+     * For the basic readout, there is a single instance of BasicChannel
+     * and thus the channel number is ignored.
+     *
+     * @param channel_number channel number
+     * @return associated BasicReadoutChannel
+     */
+    @Override
+    public BasicChannel getChannel(int channel_number) {
+        return _channel;
+    }
+
+    private ADC getADC() {
+        return _adc;
+    }
+
+    /**
+     * Given a collection of electrode data (i.e., charge on strips/pixels),
+     * return a map associating the channel and it's list of raw data.
+     *
+     * @param data  electrode data from the charge distribution
+     * @param electrodes  strip or pixel electrodes
+     * @return  map containing the ADC counts for this sensor
+     */
+    @Override
+    public SortedMap<Integer, List<Integer>> readout(SiElectrodeDataCollection data, SiSensorElectrodes electrodes) {
+
+        //  If there is no electrode data for this readout chip,  create an empty
+        //  electrode data collection
+        if (data == null) {
+            data = new SiElectrodeDataCollection();
+        }
+
+        //  Add noise hits to the electrode data collection
+//        addNoise(data, electrodes);
+
+        //  return the digitized charge data as a map that associates a hit
+        //  channel with a list of raw data for the channel
+        return digitize(data, electrodes);
+    }
+
+    /**
+     * Decode the hit charge stored in the RawTrackerHit
+     *
+     * @param hit raw hit
+     * @return hit charge in units of electrons
+     */
+    @Override
+    public double decodeCharge(RawTrackerHit hit) {
+        return getADC().decodeCharge(hit.getADCValues()[0]);
+    }
+
+    /**
+     * Decode the hit time.  Currently, the basic readout chip ignores the
+     * hit time and returns 0.
+     *
+     * @param hit raw hit data
+     * @return hit time
+     */
+    @Override
+    public int decodeTime(RawTrackerHit hit) {
+        return 0;
+    }
+
+    /**
+     * Digitizes the hit channels in a SiElectrodeDataCollection.
+     *
+     * The SiElectrodeDataCollection is a map that associates a given channel with
+     * it's SiElectrodeData.  The SiElectrodeData encapsulates the deposited charge
+     * on an strip/pixel and any associated SimTrackerHits.
+     *
+     * The output of this class is a map that associates a channel number with
+     * a list of raw data
+     *
+     * @param data electrode data collection
+     * @return map associating channels with a list of raw data
+     */
+    private SortedMap<Integer, List<Integer>> digitize(SiElectrodeDataCollection data,
+            SiSensorElectrodes electrodes) {
+        //  Create the map that associates a given sensor channel with it's list of raw data
+        SortedMap<Integer, List<Integer>> chip_data = new TreeMap<Integer, List<Integer>>();
+
+        //  Loop over the channels contained in the SiElectrodeDataCollection
+        for (Integer channel : data.keySet()) {
+            if (dropBadChannels && HPSSVTCalibrationConstants.isBadChannel((SiSensor) electrodes.getDetectorElement(), channel)) {
+//                System.out.format("%d bad\n", channel);
+                continue;
+            }
+//                System.out.format("%d OK\n", channel);
+            //  Fetch the electrode data for this channel
+            SiElectrodeData eldata = data.get(channel);
+
+            //  Get the charge in units of electrons
+            double charge = eldata.getCharge();
+
+            //  Calculate the ADC value for this channel and make sure it is positive
+            int adc = getADC().convert(charge);
+            if (adc <= 0) {
+                continue;
+            }
+
+            //  Create a list containing the adc value - for the basic readout
+            //  there is only 1 word of raw data
+            List<Integer> channel_data = new ArrayList<Integer>();
+            channel_data.add(adc);
+
+            //  Save the list of raw data in the chip_data map
+            chip_data.put(channel, channel_data);
+        }
+
+        return chip_data;
+    }
+
+    /**
+     * BasicChannel class representing a single channel's behavior
+     *
+     * Note that binary readout is a special case.  Anything positive value
+     * passed to a binary ADC for digitization is assumed to have crossed t
+     * hreshold and is assigned a value of 1.  Decoding binary readout results
+     * in either 0 or dynamic_range.
+     */
+    private class BasicChannel implements ReadoutChannel {
+
+        private double _noise_intercept = 0.;
+        private double _noise_slope = 0.;
+
+        /**
+         * Set the noise (in electrons) for 0 capacitance
+         *
+         * @param noise_intercept noise intercept
+         */
+        private void setNoiseIntercept(double noise_intercept) {
+            _noise_intercept = noise_intercept;
+        }
+
+        /**
+         * Set the capacitative noise slope (in electrons / pF)
+         *
+         * @param noise_slope noise slope
+         */
+        private void setNoiseSlope(double noise_slope) {
+            _noise_slope = noise_slope;
+        }
+
+        /**
+         * Return the noise in electrons for a given strip/pixel capacitance
+         *
+         * @param capacitance capacitance in pF
+         * @return noise in electrons
+         */
+        public double computeNoise(double capacitance) {
+            return _noise_intercept + _noise_slope * capacitance;
+        }
+    }
+
+    /**
+     * ADC class representing analog to digital converter.
+     */
+    private class ADC {
+
+        private int _nbits = 8;
+        private double _dynamic_range = 20.;
+
+        /**
+         * Set the ADC resolution in number of bits.
+         *
+         * @param nbits number of bits
+         */
+        private void setNbits(int nbits) {
+            _nbits = nbits;
+        }
+
+        /**
+         * Set the dynamic range in fC
+         *
+         * @param dynamic range
+         */
+        private void setDynamicRange(double dynamic_range) {
+            _dynamic_range = dynamic_range;
+        }
+
+        /**
+         * Compute the maximum ADC value
+         *
+         * @return largest possible ADC value according to # of bits
+         */
+        private int maxADCValue() {
+            return (int) Math.pow(2, _nbits) - 1;
+        }
+
+        /**
+         * Compute the conversion constant in ADC/fC
+         *
+         * @return conversion constant for ADC
+         */
+        private double conversionConstant() {
+            return maxADCValue() / _dynamic_range;
+        }
+
+        /**
+         * Perform analog to digital conversion
+         *
+         * @return digital ADC output between 0 and maxADCValue
+         */
+        public int convert(double charge) {
+            if (_nbits != 1) {
+                return Math.max(0, Math.min(maxADCValue(), (int) Math.floor(charge * 1.602e-4 * conversionConstant())));
+            } else {
+                if (charge <= 0.0) {
+                    return 0;
+                } else {
+                    return 1;
+                }
+            }
+        }
+
+        /**
+         * Decode charge from ADC value
+         *
+         * @return charge specified by a given ADC value
+         */
+        public double decodeCharge(int adc_value) {
+            if (_nbits != 1) {
+                return (adc_value + 0.5) / (1.602e-4 * conversionConstant());
+            } else {
+                return adc_value * _dynamic_range;
+            }
+
+        }
+    }
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
RunAlignment.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/RunAlignment.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/RunAlignment.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,96 @@
+package org.hps.recon.tracking;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.Track;
+import org.lcsim.util.Driver;
+import org.lcsim.util.aida.AIDA;
+
+/**
+ *
+ * @author mgraham
+ */
+public class RunAlignment extends Driver {
+
+    private AIDA aida = AIDA.defaultInstance();
+    String[] detNames = {"Tracker"};
+    Integer _minLayers = 8;
+    Integer[] nlayers = {8};
+    int nevt = 0;
+    double[] beamsize = {0.001, 0.02, 0.02};
+    String _config = "1pt8";
+    AlignmentParameters ap;
+    int totalTracks=0;
+// flipSign is a kludge...
+//  HelicalTrackFitter doesn't deal with B-fields in -ive Z correctly
+//  so we set the B-field in +iveZ and flip signs of fitted tracks
+//  note:  this should be -1 for Test configurations and +1 for Full (v3.X and lower) configurations
+//  this is set by the _config variable (detType in HeavyPhotonDriver)
+    int flipSign = 1;
+
+    public RunAlignment(int trackerLayers, int mintrkLayers, String config) {
+        nlayers[0] = trackerLayers;
+        _minLayers = mintrkLayers;
+        _config = config;
+        if (_config.contains("Test"))
+            flipSign = -1;
+        ap = new AlignmentParameters("/Users/mgraham/HPS/align.txt");
+
+    }
+
+    public void process(
+            EventHeader event) {
+
+
+        //  Create a map between tracks and the associated MCParticle
+        List<Track> tracklist = event.get(Track.class, "MatchedTracks");
+//        System.out.println("Number of Tracks = " + tracklist.size());
+        double duRange=0.1;
+         for (Track trk : tracklist) {
+            totalTracks++;
+            ap.PrintResidualsAndDerivatives(trk);
+
+            if(1==1){
+                aida.histogram1D("Track d0",50,-0.5,0.5).fill(trk.getTrackParameter(0));
+                aida.histogram1D("Track sin(phi0)",50,-0.5,0.5).fill(Math.sin(trk.getTrackParameter(1)));
+                aida.histogram1D("Track z0",50,-0.1,0.1).fill(Math.sin(trk.getTrackParameter(3)));
+                aida.histogram1D("Track chi^2",50,0,25).fill(trk.getChi2());
+                for (int i = 1; i < 11; i++) {
+                double[] res = ap.getResidual(trk, i);
+                int mylayer=(int)res[6];
+                if(mylayer<11){
+                     aida.histogram1D("Track chi^2 Positive Side",50,0,25).fill(trk.getChi2());
+                }else{
+                     aida.histogram1D("Track chi^2 Negative Side",50,0,25).fill(trk.getChi2());
+                }
+
+                aida.histogram1D("deltaU -- Layer " + mylayer,50,-duRange,duRange).fill(res[0]);
+                aida.histogram1D("deltaU Pull-- Layer " + mylayer,50,-3,3).fill(res[0]/res[3]);
+                if(i==3&&Math.sin(trk.getTrackParameter(1))>0){
+                    aida.histogram1D("Positive phi0  deltaU -- Layer " + mylayer,50,-duRange,duRange).fill(res[0]);
+                aida.histogram1D("Positive phi0 deltaU Pull-- Layer " + mylayer,50,-3,3).fill(res[0]/res[3]);
+                }
+                if(i==3&&Math.sin(trk.getTrackParameter(1))<0){
+                    aida.histogram1D("Negative phi0  deltaU -- Layer " + mylayer,50,-duRange,duRange).fill(res[0]);
+                aida.histogram1D("Negative phi0 deltaU Pull-- Layer " + mylayer,50,-3,3).fill(res[0]/res[3]);
+                }
+ 
+             }
+            }
+ }
+
+    }
+
+    public void endOfData() {
+        try {
+            System.out.println("Total Number of Tracks Found = "+totalTracks);
+            ap.closeFile();
+        } catch (IOException ex) {
+            Logger.getLogger(RunAlignment.class.getName()).log(Level.SEVERE, null, ex);
+        }
+    }
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
SVTBadChannelFilterDriver.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/SVTBadChannelFilterDriver.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/SVTBadChannelFilterDriver.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,45 @@
+package org.hps.recon.tracking;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.hps.conditions.deprecated.HPSSVTCalibrationConstants;
+import org.lcsim.detector.tracker.silicon.SiSensor;
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.EventHeader.LCMetaData;
+import org.lcsim.event.RawTrackerHit;
+import org.lcsim.util.Driver;
+
+/**
+ *
+ * @author Sho Uemura <[log in to unmask]>
+ * @version $Id: SVTBadChannelFilterDriver.java,v 1.2 2012/08/29 21:02:46 meeg Exp $
+ */
+public class SVTBadChannelFilterDriver extends Driver {
+
+    private String rawTrackerHitCollection = "SVTRawTrackerHits";
+
+    @Override
+    public void process(EventHeader event) {
+        if (event.hasCollection(RawTrackerHit.class, rawTrackerHitCollection)) {
+            List<RawTrackerHit> hits = event.get(RawTrackerHit.class, rawTrackerHitCollection);
+            LCMetaData meta = event.getMetaData(hits);
+            Iterator<RawTrackerHit> i = hits.iterator();
+            while (i.hasNext()) {
+                RawTrackerHit hit = i.next();
+                hit.setMetaData(meta);
+                int strip = hit.getIdentifierFieldValue("strip");
+                SiSensor sensor = (SiSensor) hit.getDetectorElement();
+
+//                System.out.format("module %d, layer %d, strip %d\n", hit.getIdentifierFieldValue("module"), hit.getIdentifierFieldValue("layer"), hit.getIdentifierFieldValue("strip"));
+                if (HPSSVTCalibrationConstants.isBadChannel(sensor, strip)) {
+                    i.remove();
+                }
+
+                if (!sensor.getReadout().getHits(RawTrackerHit.class).isEmpty()) {
+                    throw new RuntimeException(this.getClass().getSimpleName() + " must be run before any SVT readout drivers.");
+                }
+            }
+        }
+    }
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
SVTRawTrackerHitThresholdDriver.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/SVTRawTrackerHitThresholdDriver.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/SVTRawTrackerHitThresholdDriver.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,80 @@
+package org.hps.recon.tracking;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.hps.conditions.deprecated.HPSSVTCalibrationConstants;
+import org.lcsim.detector.tracker.silicon.SiSensor;
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.RawTrackerHit;
+import org.lcsim.geometry.Detector;
+import org.lcsim.util.Driver;
+
+/**
+ *
+ * @author mgraham
+ */
+public class SVTRawTrackerHitThresholdDriver extends Driver {
+
+    private String rawTrackerHitCollectionName = "RawTrackerHitMaker_RawTrackerHits";
+    private String outputHitCollectionName = "RawTrackerHitsThreshold";
+    private String calibFileName = "foobar";
+    private String trackerName = "Tracker";
+    private Detector detector;
+    private List<SiSensor> sensors;
+    private double noiseThreshold = 3;
+    private int nhitsAboveNoise = 2;
+
+    public SVTRawTrackerHitThresholdDriver() {
+    }
+
+    public void setRawTrackerHitCollectionName(String rawTrackerHitCollectionName) {
+        this.rawTrackerHitCollectionName = rawTrackerHitCollectionName;
+    }
+    
+    public void setOutputHitCollectionName(String outputHitCollectionName) {
+        this.outputHitCollectionName = outputHitCollectionName;
+    }
+    
+    public void setCalibFileName(String calibFileName) {
+        this.calibFileName = calibFileName;
+    }
+    
+    public void setNoiseThreshold(double thres){
+        this.noiseThreshold=thres;
+    }
+    
+    public void setNhitsAboveNoise(int nhits){
+        this.nhitsAboveNoise=nhits;
+    }
+
+    protected void detectorChanged(Detector detector) {
+    }
+
+    public void process(EventHeader event) {
+        if (event.hasCollection(RawTrackerHit.class, rawTrackerHitCollectionName)) {
+            // Get RawTrackerHit collection from event.
+            List<RawTrackerHit> rawTrackerHits = event.get(RawTrackerHit.class, rawTrackerHitCollectionName);
+            List<RawTrackerHit> outputHits = new ArrayList<RawTrackerHit>();
+            
+            // Increment strip hit count.
+            for (RawTrackerHit hit : rawTrackerHits) {
+                SiSensor sensor=(SiSensor) hit.getDetectorElement();
+                int strip=hit.getIdentifierFieldValue("strip");
+                short[] adcVal=hit.getADCValues();                
+                double ped=HPSSVTCalibrationConstants.getPedestal(sensor, strip);
+                double noise=HPSSVTCalibrationConstants.getNoise(sensor, strip);
+                int nAbove=0;
+                for(int i=0;i<6;i++){
+                    double pedSubNorm=(adcVal[i]-ped)/noise;
+                    if(pedSubNorm>noiseThreshold)
+                        nAbove++;                    
+                }
+                if(nAbove>=nhitsAboveNoise)
+                    outputHits.add(hit);
+            }
+
+            event.put(outputHitCollectionName, outputHits, RawTrackerHit.class, 0);
+        }
+    }
+}
\ No newline at end of file

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
SeedTracker.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/SeedTracker.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/SeedTracker.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,76 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.hps.recon.tracking;
+
+import java.util.List;
+
+import org.lcsim.recon.tracking.seedtracker.SeedStrategy;
+import org.lcsim.recon.tracking.seedtracker.SeedTrackFinder;
+
+/**
+ * Class extending lcsim version to allow extra flexibility
+ * @author Per Hansson Adrian <[log in to unmask]>
+ * @version $Id: SeedTracker.java,v 1.4 2013/11/07 03:54:58 phansson Exp $ $Date: 2013/11/07 03:54:58 $ $Author: phansson $ 
+ */
+public class SeedTracker extends org.lcsim.recon.tracking.seedtracker.SeedTracker  {
+
+    public SeedTracker(List<SeedStrategy> strategylist) {
+        // use base class only if this constructor is called!
+        super(strategylist);
+    }
+
+    public SeedTracker(List<SeedStrategy> strategylist,boolean includeMS) {
+        super(strategylist);
+        initialize(strategylist, true, includeMS);
+    }
+
+    public SeedTracker(List<SeedStrategy> strategylist,boolean useHPSMaterialManager, boolean includeMS) {
+        super(strategylist);
+        initialize(strategylist, useHPSMaterialManager, includeMS);
+    }
+    
+    private void initialize(List<SeedStrategy> strategylist,boolean useHPSMaterialManager, boolean includeMS) {
+            
+            // Explicitly only replace the objects that might change to avoid getting the lcsim versions
+            
+            //  Instantiate the material manager for HPS,  the helix fitter and seed track finder as tey depends on the material manager
+            if(useHPSMaterialManager) {
+                MaterialSupervisor materialSupervisor = new MaterialSupervisor(includeMS);
+                _materialmanager = materialSupervisor;
+                _helixfitter = new HelixFitter(materialSupervisor);
+            } else {
+                MaterialManager materialmanager = new MaterialManager(includeMS);
+                _materialmanager = materialmanager; //mess around with types here...
+                _helixfitter = new HelixFitter(materialmanager);
+            }
+            //  Instantiate the helix finder since it depends on the material manager
+            _finder = new SeedTrackFinder(_hitmanager, _helixfitter);
+    } 
+
+     /**
+     * Set to enable debug output
+     * 
+     * @param debug switch
+     */
+    @Override
+    public void setDebug(boolean debug) {
+        super.setDebug(debug);
+        _materialmanager.setDebug(debug);
+        _helixfitter.setDebug(debug);
+    }
+
+     /**
+     * Set to enable the sectoring to use the sector bins in checking for consistent hits.
+     *
+     * @param applySectorBinning apply sector binning switch
+     */
+    public void setApplySectorBinning(boolean applySectorBinning) {
+        _finder.setApplySectorBinning(applySectorBinning);
+        _finder.getConfirmer().setApplySectorBinning(applySectorBinning);
+        
+    }
+
+
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
SimpleSvtReadout.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/SimpleSvtReadout.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/SimpleSvtReadout.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,425 @@
+package org.hps.recon.tracking;
+
+//--- java ---//
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.PriorityQueue;
+import java.util.Set;
+
+import org.hps.conditions.deprecated.HPSSVTCalibrationConstants;
+import org.hps.conditions.deprecated.HPSSVTConstants;
+import org.hps.conditions.deprecated.SvtUtils;
+import org.hps.readout.ecal.ReadoutTimestamp;
+import org.hps.readout.ecal.TriggerableDriver;
+//--- lcsim ---//
+import org.lcsim.detector.tracker.silicon.ChargeCarrier;
+import org.lcsim.detector.tracker.silicon.SiSensor;
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.LCRelation;
+import org.lcsim.event.RawTrackerHit;
+import org.lcsim.event.SimTrackerHit;
+import org.lcsim.event.base.BaseLCRelation;
+import org.lcsim.event.base.BaseRawTrackerHit;
+import org.lcsim.geometry.Detector;
+import org.lcsim.hps.util.ClockSingleton;
+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;
+import org.lcsim.recon.tracking.digitization.sisim.SiElectrodeDataCollection;
+import org.lcsim.recon.tracking.digitization.sisim.SiSensorSim;
+import org.lcsim.recon.tracking.digitization.sisim.config.SimTrackerHitReadoutDriver;
+
+/**
+ *
+ * @author Sho Uemura <[log in to unmask]>
+ * @version $Id: SimpleSvtReadout.java,v 1.19 2013/08/07 23:38:32 meeg Exp $
+ */
+public class SimpleSvtReadout extends TriggerableDriver {
+
+    private SimTrackerHitReadoutDriver readoutDriver = new SimTrackerHitReadoutDriver();
+    private SiSensorSim siSimulation = new CDFSiSensorSim();
+    private String outputCollection = "SVTRawTrackerHits";
+    private String relationCollection = "SVTTrueHitRelations";
+    private Map<SiSensor, PriorityQueue<StripHit>[]> hitMap = new HashMap<SiSensor, PriorityQueue<StripHit>[]>();
+    //readout period time offset in ns
+    private double readoutOffset = 0.0;
+    private double readoutLatency = 240.0;
+    private double pileupCutoff = 300.0;
+    private String readout = "TrackerHits";
+    private double timeOffset = 30.0;
+    private boolean noPileup = false;
+    private boolean addNoise = true;
+    //cut settings
+    private boolean enableThresholdCut = true;
+    private int samplesAboveThreshold = 3;
+    private double noiseThreshold = 2.0;
+    private boolean enablePileupCut = true;
+    private boolean dropBadChannels = true;
+
+    public SimpleSvtReadout() {
+        add(readoutDriver);
+        triggerDelay = 100.0;
+    }
+
+    public void setAddNoise(boolean addNoise) {
+        this.addNoise = addNoise;
+    }
+
+    public void setEnablePileupCut(boolean enablePileupCut) {
+        this.enablePileupCut = enablePileupCut;
+    }
+
+    public void setEnableThresholdCut(boolean enableThresholdCut) {
+        this.enableThresholdCut = enableThresholdCut;
+    }
+
+    public void setNoiseThreshold(double noiseThreshold) {
+        this.noiseThreshold = noiseThreshold;
+    }
+
+    public void setSamplesAboveThreshold(int samplesAboveThreshold) {
+        this.samplesAboveThreshold = samplesAboveThreshold;
+    }
+
+    public void setNoPileup(boolean noPileup) {
+        this.noPileup = noPileup;
+    }
+
+    public void setDropBadChannels(boolean dropBadChannels) {
+        this.dropBadChannels = dropBadChannels;
+    }
+
+    /**
+     *
+     */
+    @Override
+    public void detectorChanged(Detector detector) {
+        super.detectorChanged(detector);
+
+        String[] readouts = {readout};
+        readoutDriver.setCollections(readouts);
+
+        if (!noPileup) {
+            for (SiSensor sensor : SvtUtils.getInstance().getSensors()) {
+                PriorityQueue<StripHit>[] hitQueues = new PriorityQueue[HPSSVTConstants.TOTAL_STRIPS_PER_SENSOR];
+                hitMap.put(sensor, hitQueues);
+            }
+        }
+    }
+
+    /**
+     *
+     */
+    @Override
+    public void process(EventHeader event) {
+        super.process(event);
+
+        List<StripHit> stripHits = doSiSimulation();
+
+        if (!noPileup) {
+            for (StripHit stripHit : stripHits) {
+                SiSensor sensor = stripHit.sensor;
+                int channel = stripHit.channel;
+
+                PriorityQueue<StripHit>[] hitQueues = hitMap.get(sensor);
+                if (hitQueues[channel] == null) {
+                    hitQueues[channel] = new PriorityQueue<StripHit>();
+                }
+                hitQueues[channel].add(stripHit);
+            }
+
+            // dump stale hits
+            for (SiSensor sensor : SvtUtils.getInstance().getSensors()) {
+                PriorityQueue<StripHit>[] hitQueues = hitMap.get(sensor);
+                for (int i = 0; i < hitQueues.length; i++) {
+                    if (hitQueues[i] != null) {
+                        while (!hitQueues[i].isEmpty() && hitQueues[i].peek().time < ClockSingleton.getTime() - (readoutLatency + pileupCutoff)) {
+//                                System.out.format("Time %f: Dump stale hit with time %f\n",ClockSingleton.getTime(),hitQueues[i].peek().time);
+                            hitQueues[i].poll();
+                        }
+                        if (hitQueues[i].isEmpty()) {
+                            hitQueues[i] = null;
+                        }
+                    }
+                }
+            }
+
+            // If an ECal trigger is received, make hits from pipelines
+            checkTrigger(event);
+        } else {
+            // Create a list to hold the analog data
+            List<RawTrackerHit> hits = new ArrayList<RawTrackerHit>();
+
+            for (StripHit stripHit : stripHits) {
+                SiSensor sensor = stripHit.sensor;
+                int channel = stripHit.channel;
+                double amplitude = stripHit.amplitude;
+                short[] samples = new short[6];
+
+                double[] signal = new double[6];
+                for (int i = 0; i < 6; i++) {
+                    signal[i] = HPSSVTCalibrationConstants.getPedestal(sensor, channel);
+                }
+                if (addNoise) {
+                    addNoise(sensor, channel, signal);
+                }
+
+                for (int i = 0; i < 6; i++) {
+                    double time = i * HPSSVTConstants.SAMPLING_INTERVAL - timeOffset;
+                    signal[i] += amplitude * pulseAmplitude(time, HPSSVTCalibrationConstants.getTShaping(sensor, channel));
+//                    signal[i] += amplitude * pulseAmplitude(time, HPSSVTCalibrationConstants.getTShaping(sensor, channel)) + HPSSVTCalibrationConstants.getPedestal(sensor, channel);
+                    samples[i] = (short) Math.round(signal[i]);
+                }
+
+                long cell_id = SvtUtils.makeCellID(sensor, channel);
+
+                RawTrackerHit hit = new BaseRawTrackerHit(0, cell_id, samples, new ArrayList<SimTrackerHit>(stripHit.simHits), sensor);
+//                        System.out.println("Making RTH");
+                if (readoutCuts(hit)) {
+//                    System.out.println("RTH passed cuts");
+                    hits.add(hit);
+                }
+            }
+
+            int flags = 1 << LCIOConstants.TRAWBIT_ID1;
+//            flags += 1 << LCIOConstants.RTHBIT_HITS;
+            event.put(outputCollection, hits, RawTrackerHit.class, flags, readout);
+//            System.out.println("Made " + hits.size() + " RawTrackerHits");
+        }
+    }
+
+    private List<StripHit> doSiSimulation() {
+        List<StripHit> stripHits = new ArrayList<StripHit>();
+        for (SiSensor sensor : SvtUtils.getInstance().getSensors()) {
+
+            // Set the sensor to be used in the charge deposition simulation
+            siSimulation.setSensor(sensor);
+
+            // Perform the charge deposition simulation
+            Map<ChargeCarrier, SiElectrodeDataCollection> electrodeDataMap = siSimulation.computeElectrodeData();
+
+            for (ChargeCarrier carrier : ChargeCarrier.values()) {
+
+                // If the sensor is capable of collecting the given charge carrier
+                // then obtain the electrode data for the sensor
+                if (sensor.hasElectrodesOnSide(carrier)) {
+
+                    SiElectrodeDataCollection electrodeDataCol = electrodeDataMap.get(carrier);
+
+                    // If there is no electrode data available create a new instance of electrode data
+                    if (electrodeDataCol == null) {
+                        electrodeDataCol = new SiElectrodeDataCollection();
+                    }
+
+                    // Loop over all sensor channels
+                    for (Integer channel : electrodeDataCol.keySet()) {
+
+                        // Get the electrode data for this channel
+                        SiElectrodeData electrodeData = electrodeDataCol.get(channel);
+                        Set<SimTrackerHit> simHits = electrodeData.getSimulatedHits();
+
+                        // compute hit time as the unweighted average of SimTrackerHit times; this is dumb but okay since there's generally only one SimTrackerHit
+                        double time = 0.0;
+                        for (SimTrackerHit hit : simHits) {
+                            time += hit.getTime();
+                        }
+                        time /= simHits.size();
+                        time += ClockSingleton.getTime();
+
+                        // Get the charge in units of electrons
+                        double charge = electrodeData.getCharge();
+
+                        double resistorValue = 100;  // Ohms
+                        double inputStageGain = 1.5;
+                        double amplitude = (charge / HPSSVTConstants.MIP) * resistorValue * inputStageGain * Math.pow(2, 14) / 2000;
+
+                        stripHits.add(new StripHit(sensor, channel, amplitude, time, simHits));
+                    }
+                }
+            }
+            // Clear the sensors of all deposited charge
+            siSimulation.clearReadout();
+        }
+        return stripHits;
+    }
+
+    private void addNoise(SiSensor sensor, int channel, double[] signal) {
+        double noise = HPSSVTCalibrationConstants.getNoise(sensor, channel);
+        for (int i = 0; i < 6; i++) {
+            signal[i] += RandomGaussian.getGaussian(0, noise);
+        }
+    }
+
+    private boolean readoutCuts(RawTrackerHit hit) {
+        if (enableThresholdCut && !samplesAboveThreshold(hit)) {
+//            System.out.println("Failed threshold cut");
+            return false;
+        }
+        if (enablePileupCut && !pileupCut(hit)) {
+//            System.out.println("Failed pileup cut");
+            return false;
+        }
+        if (dropBadChannels && !badChannelCut(hit)) {
+//            System.out.println("Failed bad channel cut");
+            return false;
+        }
+        return true;
+    }
+
+    private boolean badChannelCut(RawTrackerHit hit) {
+        SiSensor sensor = (SiSensor) hit.getDetectorElement();
+        int channel = hit.getIdentifierFieldValue("strip");
+        return !HPSSVTCalibrationConstants.isBadChannel(sensor, channel);
+    }
+
+    private boolean pileupCut(RawTrackerHit hit) {
+        short[] samples = hit.getADCValues();
+        return (samples[2] > samples[1] || samples[3] > samples[2]);
+    }
+
+    private boolean samplesAboveThreshold(RawTrackerHit hit) {
+        SiSensor sensor = (SiSensor) hit.getDetectorElement();
+        int channel = hit.getIdentifierFieldValue("strip");
+        HPSSVTCalibrationConstants.getChannelConstants(sensor, channel);
+        double pedestal = HPSSVTCalibrationConstants.getPedestal(sensor, channel);
+        double noise = HPSSVTCalibrationConstants.getNoise(sensor, channel);
+        int count = 0;
+        short[] samples = hit.getADCValues();
+        for (int i = 0; i < samples.length; i++) {
+//            System.out.format("%d, %d\n", samples[i] - pedestal, noise * 3.0);
+            if (samples[i] - pedestal > noise * noiseThreshold) {
+                count++;
+            }
+        }
+        return count >= samplesAboveThreshold;
+    }
+
+    @Override
+    protected void processTrigger(EventHeader event) {
+        if (noPileup) {
+            return;
+        }
+//            System.out.println("Got trigger");
+
+        // Create a list to hold the analog data
+        List<RawTrackerHit> hits = new ArrayList<RawTrackerHit>();
+        List<LCRelation> trueHitRelations = new ArrayList<LCRelation>();
+        // Calculate time of first sample
+        double firstSample = Math.floor((ClockSingleton.getTime() - readoutLatency - readoutOffset) / HPSSVTConstants.SAMPLING_INTERVAL) * HPSSVTConstants.SAMPLING_INTERVAL + readoutOffset;
+
+        for (SiSensor sensor : SvtUtils.getInstance().getSensors()) {
+            PriorityQueue<StripHit>[] hitQueues = hitMap.get(sensor);
+            for (int channel = 0; channel < hitQueues.length; channel++) {
+                if (!addNoise && (hitQueues[channel] == null || hitQueues[channel].isEmpty())) {
+                    continue;
+                }
+                double[] signal = new double[6];
+                for (int i = 0; i < 6; i++) {
+                    signal[i] = HPSSVTCalibrationConstants.getPedestal(sensor, channel);
+                }
+                if (addNoise) {
+                    addNoise(sensor, channel, signal);
+                }
+
+                List<SimTrackerHit> simHits = new ArrayList<SimTrackerHit>();
+
+                if (hitQueues[channel] != null) {
+                    for (StripHit hit : hitQueues[channel]) {
+                        double totalContrib = 0;
+                        for (int i = 0; i < 6; i++) {
+                            double sampleTime = firstSample + i * HPSSVTConstants.SAMPLING_INTERVAL;
+                            double signalAtTime = hit.amplitude * pulseAmplitude(sampleTime - hit.time, HPSSVTCalibrationConstants.getTShaping(sensor, channel));
+                            totalContrib += signalAtTime;
+                            signal[i] += signalAtTime;
+//                                    System.out.format("new value of signal[%d] = %f\n", i, signal[i]);
+                        }
+                        if (totalContrib > 4.0 * HPSSVTCalibrationConstants.getNoise(sensor, channel)) {
+//                            System.out.format("adding %d simHits\n", hit.simHits.size());
+                            simHits.addAll(hit.simHits);
+                        }
+                    }
+                }
+
+                short[] samples = new short[6];
+                for (int i = 0; i < 6; i++) {
+                    samples[i] = (short) Math.round(signal[i]);
+                }
+//                        if (hitQueues[channel] != null && !hitQueues[channel].isEmpty()) {
+//                            for (int i = 0; i < 6; i++) {
+//                                System.out.format("samples[%d] = %d\n", i, samples[i]);
+//                            }
+//                        }
+                long cell_id = SvtUtils.makeCellID(sensor, channel);
+                RawTrackerHit hit = new BaseRawTrackerHit(0, cell_id, samples, simHits, sensor);
+                if (readoutCuts(hit)) {
+                    hits.add(hit);
+//                    System.out.format("simHits: %d\n", simHits.size());
+                    for (SimTrackerHit simHit : hit.getSimTrackerHits()) {
+                        LCRelation hitRelation = new BaseLCRelation(hit, simHit);
+                        trueHitRelations.add(hitRelation);
+                    }
+                }
+            }
+        }
+
+        int flags = 1 << LCIOConstants.TRAWBIT_ID1;
+//            flags += 1 << LCIOConstants.RTHBIT_HITS;
+        event.put(outputCollection, hits, RawTrackerHit.class, flags, readout);
+        event.put(relationCollection, trueHitRelations, LCRelation.class, 0);
+        System.out.println("Made " + hits.size() + " RawTrackerHits");
+        System.out.println("Made " + trueHitRelations.size() + " LCRelations");
+    }
+
+    @Override
+    public double readoutDeltaT() {
+        double triggerTime = ClockSingleton.getTime() + triggerDelay;
+//        int cycle = (int) Math.floor((triggerTime - readoutOffset + ClockSingleton.getDt()) / Apv25Constants.SAMPLING_INTERVAL);
+        // Calculate time of first sample
+        double firstSample = Math.floor((triggerTime - readoutLatency - readoutOffset) / HPSSVTConstants.SAMPLING_INTERVAL) * HPSSVTConstants.SAMPLING_INTERVAL + readoutOffset;
+
+        return firstSample;
+    }
+
+    private class StripHit implements Comparable {
+
+        SiSensor sensor;
+        int channel;
+        double amplitude;
+        double time;
+        Set<SimTrackerHit> simHits;
+
+        public StripHit(SiSensor sensor, int channel, double amplitude, double time, Set<SimTrackerHit> simHits) {
+            this.sensor = sensor;
+            this.channel = channel;
+            this.amplitude = amplitude;
+            this.time = time;
+            this.simHits = simHits;
+        }
+
+        @Override
+        public int compareTo(Object o) {
+            double deltaT = time - ((StripHit) o).time;
+            if (deltaT > 0) {
+                return 1;
+            } else if (deltaT < 0) {
+                return -1;
+            } else {
+                return 0;
+            }
+        }
+    }
+
+    private double pulseAmplitude(double time, double tp) {
+        if (time <= 0.0) {
+            return 0.0;
+        }
+        return (time / tp) * Math.exp(1.0 - time / tp);
+    }
+    
+    public int getTimestampType() {
+        return ReadoutTimestamp.SYSTEM_TRACKER;
+    }
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
SimpleTrackerDigiDriver.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/SimpleTrackerDigiDriver.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/SimpleTrackerDigiDriver.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,70 @@
+package org.hps.recon.tracking;
+
+import org.lcsim.recon.tracking.digitization.sisim.CDFSiSensorSim;
+import org.lcsim.recon.tracking.digitization.sisim.NearestNeighborRMS;
+import org.lcsim.recon.tracking.digitization.sisim.RawTrackerHitMaker;
+import org.lcsim.recon.tracking.digitization.sisim.StripHitMaker;
+
+/**
+ * This Driver runs the tracker digitization to create raw hits and strip hits
+ * from simulated data. The output can be used by a track reconstruction
+ * algorithm like Seed Tracker.
+ * 
+ * Copied from org.lcsim.hps.recon.tracking.TrackerDigiDriver, with the difference that this driver does not make noise hits or add noise to hits, and drops bad channels.
+ * 
+ * @author [log in to unmask]
+ * @version $Id: SimpleTrackerDigiDriver.java,v 1.3 2012/11/20 19:59:35 meeg Exp $
+ */
+public class SimpleTrackerDigiDriver extends TrackerDigiDriver {
+
+    private boolean dropBadChannels = false;
+
+    public void setDropBadChannels(boolean dropBadChannels) {
+        this.dropBadChannels = dropBadChannels;
+    }
+
+    /**
+     * Initializes this Driver's objects with the job parameters.
+     */
+    @Override
+    protected void initialize() {
+
+        // Create the sensor simulation.
+        CDFSiSensorSim stripSim = new CDFSiSensorSim();
+
+        // Create the readout chips and set the noise parameters.
+        NoiselessReadoutChip stripReadout = new NoiselessReadoutChip();
+        stripReadout.setDropBadChannels(dropBadChannels);
+        stripReadout.setNoiseIntercept(readoutNoiseIntercept);
+        stripReadout.setNoiseSlope(readoutNoiseSlope);
+        stripReadout.setNbits(readoutNBits);
+        stripReadout.setDynamicRange(readoutDynamicRange);
+
+        // Create the digitizer that produces the raw hits
+        stripDigitizer = new RawTrackerHitMaker(stripSim, stripReadout);
+
+        // Create Strip clustering algorithm.
+        NearestNeighborRMS stripClusteringAlgo = new NearestNeighborRMS();
+        stripClusteringAlgo.setSeedThreshold(clusterSeedThreshold);
+        stripClusteringAlgo.setNeighborThreshold(clusterNeighborThreshold);
+        stripClusteringAlgo.setClusterThreshold(clusterThreshold);
+
+        // Create the clusterers and set hit-making parameters.
+        stripClusterer = new StripHitMaker(stripSim, stripReadout, stripClusteringAlgo);
+        stripClusterer.setMaxClusterSize(clusterMaxSize);
+        stripClusterer.setCentralStripAveragingThreshold(clusterCentralStripAveragingThreshold);
+
+        // Set the cluster errors.
+        stripClusterer.SetOneClusterErr(oneClusterErr);
+        stripClusterer.SetTwoClusterErr(twoClusterErr);
+        stripClusterer.SetThreeClusterErr(threeClusterErr);
+        stripClusterer.SetFourClusterErr(fourClusterErr);
+        stripClusterer.SetFiveClusterErr(fiveClusterErr);
+
+        // Set the readout to process.
+        readouts.add(readoutCollectionName);
+
+        // Set the detector to process.
+        processPaths.add(subdetectorName);
+    }
+}
\ No newline at end of file

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
StraightLineTrack.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/StraightLineTrack.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/StraightLineTrack.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,193 @@
+package org.hps.recon.tracking;
+
+import hep.physics.matrix.SymmetricMatrix;
+
+/**
+ * Encapsulate position, direction, and covariance matrix for a straight-line track
+ *
+ * @author Richard Partridge
+ */
+public class StraightLineTrack {
+
+    public static int y0Index = 0;
+    public static int z0Index = 1;
+    public static int dydxIndex = 2;
+    public static int dzdxIndex = 3;
+    private double _x0;
+    private double _y0;
+    private double _z0;
+    private double _dydx;
+    private double _dzdx;
+    private SymmetricMatrix _cov;
+    private double[] _poca = {0, 0, 0};
+    private double[] _yzT = {0, 0};
+
+    /**
+     * Fully qualified constructor for the StraightLineTrack class.  A StraightLineTrack
+     * is specified by providing a position and the direction derivatives dydx and dzdx used
+     * in the vertex fitting.  It is assumed that the track is traveling in the +x direction
+     * (i.e., from the field-free region into the magnetized region).
+     *
+     * @param x0 x coordinate of the reference plane
+     * @param y0 y coordinate at the reference plane
+     * @param z0 z coordinate at the reference plane
+     * @param dydx dy/dx for the track
+     * @param dzdx dz/dx for the track
+     * @param cov covariance matrix for the track parameters (y0, z0, dy/dx, and dz/dx)
+     */
+    public StraightLineTrack(double x0, double y0, double z0, double dydx, double dzdx, SymmetricMatrix cov) {
+        _x0 = x0;
+        _y0 = y0;
+        _z0 = z0;
+        _dydx = dydx;
+        _dzdx = dzdx;
+        _cov = cov;
+        calculatePoca();
+        calculateTargetYZ();
+    }
+
+    /**
+     * Return the x coordinate of the reference plane.
+     *
+     * @return x coordinate of the reference plane
+     */
+    public double x0() {
+        return _x0;
+    }
+
+    /**
+     * Return the y coordinate at the reference plane.
+     *
+     * @return y coordinate
+     */
+    public double y0() {
+        return _y0;
+    }
+
+    /**
+     * Return the z coordinate at the reference plane.
+     *
+     * @return z coordinate
+     */
+    public double z0() {
+        return _z0;
+    }
+
+    /**
+     * Return the direction derivative dy/dx.
+     *
+     * @return dy/dx
+     */
+    public double dydx() {
+        return _dydx;
+    }
+
+    /**
+     * Return the direction derivative dz/dx.
+     *
+     * @return dz/dx
+     */
+    public double dzdx() {
+        return _dzdx;
+    }
+
+    /**
+     * Return the xPoca .
+     *
+     * @return xPoca
+     */
+    public double xPoca() {
+        return _poca[0];
+    }
+
+    /**
+     * Return the yPoca .
+     *
+     * @return yPoca
+     */
+    public double yPoca() {
+        return _poca[1];
+    }
+
+    /**
+     * Return the zPoca .
+     *
+     * @return zPoca
+     */
+    public double zPoca() {
+        return _poca[2];
+    }
+
+    /**
+     * Return the Doca .
+     *
+     * @return Doca
+     */
+    public double Doca() {
+        return Math.sqrt(_poca[1] * _poca[1] + _poca[2] * _poca[2]);
+    }
+
+    /**
+     * Return the Poca .
+     *
+     * @return Poca
+     */
+    public double[] Poca() {
+        return _poca;
+    }
+
+    /**
+     * Return the Y and Z positions of the track at X=0 (target).
+     *
+     * @return yzT
+     */
+    public double[] TargetYZ() {
+        return _yzT;
+    }
+    
+    public double[] getYZAtX(double xVal){
+        return calculateYZAtX(xVal);
+    }   
+    
+    /**
+     * Return the covariance matrix.
+     *
+     * @return covariance matrix
+     */
+    public SymmetricMatrix cov() {
+        return _cov;
+    }
+
+    //  mg--for now just calculate the simple POCA (to the x-axis)...no errors
+    private void calculatePoca() {
+        _poca[0] = _x0-(_y0 * _dydx + _z0 * _dzdx) / (_dydx * _dydx + _dzdx * _dzdx);
+        _poca[1] = _y0 + _dydx * (_poca[0]-_x0);
+        _poca[2] = _z0 + _dzdx * (_poca[0]-_x0);
+    }
+
+    private void calculateTargetYZ() {
+        _yzT[0] = _y0 - _x0 * _dydx;
+        _yzT[1] = _z0 - _x0 * _dzdx;
+    }
+    
+    private double[] calculateYZAtX(double xVal) {
+        double[] yzAtX={-66,-66};
+        if(xVal>_x0)   //_x0 is where the field region starts...if xVal is bigger than this, need to get position on helix
+            return yzAtX;
+        yzAtX[0] = _y0 + (xVal-_x0) * _dydx;
+        yzAtX[1] = _z0 + (xVal-_x0) * _dzdx;
+        return yzAtX;
+    }
+    
+    public double calculateXAtZEquals0() {       
+        return _x0-_z0/_dzdx;
+    }
+    
+    public double[] calculateXYAtZ(double zVal) {       
+        double[] xyAtZ = {-99999,-99999};
+        xyAtZ[0] = (zVal-_z0)/(_dzdx)+_x0;
+        xyAtZ[1] = this.calculateYZAtX(xyAtZ[0])[0];
+        return xyAtZ;
+    }
+    
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
TrackAnalysis.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/TrackAnalysis.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/TrackAnalysis.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,298 @@
+/*
+ * TrackAnalysis.java
+ *
+ * Created on October 16, 2008, 6:09 PM
+ *
+ */
+package org.hps.recon.tracking;
+
+import hep.physics.vec.BasicHep3Vector;
+import hep.physics.vec.Hep3Vector;
+import hep.physics.vec.VecOp;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.lcsim.event.MCParticle;
+import org.lcsim.event.RelationalTable;
+import org.lcsim.event.Track;
+import org.lcsim.event.TrackerHit;
+import org.lcsim.fit.helicaltrack.HelicalTrack2DHit;
+import org.lcsim.fit.helicaltrack.HelicalTrackCross;
+import org.lcsim.fit.helicaltrack.HelicalTrackHit;
+import org.lcsim.fit.helicaltrack.HelicalTrackStrip;
+
+/**
+ *
+ * @author Richard Partridge & Matt Graham
+ */
+public class TrackAnalysis {
+
+    private enum HelixPar {
+        Curvature, Phi0, DCA, Z0, Slope
+    };
+    private MCParticle _mcp = null;
+    private int _nhits;
+    private int _nbadhits;
+    private double _purity;
+    private MCParticle _mcpNew = null;
+    private int _nhitsNew;
+    private int _nbadhitsNew;
+    private double _purityNew;
+    private int _nAxialhits;
+    private int _nZhits;
+    private int _nbadAxialhits;
+    private int _nbadZhits;
+    private boolean _hasLayerOne;
+    List<Integer> badHitList = new ArrayList();
+    List<Integer> sharedHitList = new ArrayList();
+    List<Integer> trackLayerList = new ArrayList();
+    Map<MCParticle, HelicalTrackCross> badhits = new HashMap<MCParticle, HelicalTrackCross>();
+    private int[] _nMCHitsPerLayer={0,0,0,0,0,0,0,0,0,0,0,0};
+    private int[] _nStripHitsPerLayer={0,0,0,0,0,0,0,0,0,0,0,0};
+     Map<Integer, Hep3Vector> _hitLocationPerLayer = new HashMap<Integer,Hep3Vector>();
+
+    /** Creates a new instance of TrackAnalysis */
+    public TrackAnalysis(Track trk, RelationalTable hittomc) {
+
+        //  Get the number of hits on the track
+        _nhits = trk.getTrackerHits().size();
+
+        //  Create a map containing the number of hits for each MCParticle associated with the track
+        Map<MCParticle, Integer> mcmap = new HashMap<MCParticle, Integer>();
+        Map<MCParticle, Integer> mcmapAll = new HashMap<MCParticle, Integer>();
+        Map<MCParticle, Integer> mcmapAxial = new HashMap<MCParticle, Integer>();
+        Map<MCParticle, Integer> mcmapZ = new HashMap<MCParticle, Integer>();
+        _hasLayerOne = false;
+        //  Loop over the hits on the track and make sure we have HelicalTrackHits (which contain the MC particle)
+        for (TrackerHit hit : trk.getTrackerHits()) {
+            //  get the set of MCParticles associated with this hit and update the hit count for each MCParticle
+            Set<MCParticle> mclist = hittomc.allFrom(hit);
+            for (MCParticle mcp : mclist) {
+                Integer mchits = 0;
+                if (mcmap.containsKey(mcp))
+                    mchits = mcmap.get(mcp);
+                mchits++;
+                mcmap.put(mcp, mchits);
+            }
+
+            BasicHep3Vector axial = new BasicHep3Vector();
+            axial.setV(0, 1, 0);
+            HelicalTrackHit htc = (HelicalTrackHit) hit;
+            if (hit instanceof HelicalTrackCross) {
+                HelicalTrackCross cross = (HelicalTrackCross) hit;
+                List<HelicalTrackStrip> clusterlist = cross.getStrips();
+
+                for (HelicalTrackStrip cl : clusterlist) {
+                    int layer = cl.layer();
+                    if (layer == 1) _hasLayerOne = true;
+
+                    _nStripHitsPerLayer[layer - 1] = cl.rawhits().size();
+                    _hitLocationPerLayer.put(layer,clusterPosition(cl));
+                    _nhitsNew++;
+                    double axdotu = VecOp.dot(cl.u(), axial);
+                    boolean isAxial = false;
+                    if (axdotu > 0.5) {
+                        isAxial = true;
+                        _nAxialhits++;
+                    } else _nZhits++;
+                    List<MCParticle> mcPartList = cl.MCParticles();
+                    _nMCHitsPerLayer[layer-1] = mcPartList.size();
+                    for (MCParticle mcp : mcPartList) {
+                        Integer mchits = 0;
+                        if (mcmapAll.containsKey(mcp))
+                            mchits = mcmapAll.get(mcp);
+                        mchits++;
+                        mcmapAll.put(mcp, mchits);
+                        if (isAxial) {
+                            Integer mchitsAxial = 0;
+                            if (mcmapAxial.containsKey(mcp))
+                                mchitsAxial = mcmapAxial.get(mcp);
+                            mchitsAxial++;
+                            mcmapAxial.put(mcp, mchitsAxial);
+                        } else {
+                            Integer mchitsZ = 0;
+                            if (mcmapZ.containsKey(mcp))
+                                mchitsZ = mcmapZ.get(mcp);
+                            mchitsZ++;
+                            mcmapZ.put(mcp, mchitsZ);
+                        }
+                    }
+                }
+            } else {
+                _nhitsNew++;
+                _nAxialhits++;
+                HelicalTrack2DHit hit2d = (HelicalTrack2DHit) hit;
+                List<MCParticle> mcPartList = hit2d.getMCParticles();
+                //assume that lone hits are all axial
+                boolean isAxial = true;
+                for (MCParticle mcp : mcPartList) {
+                    Integer mchits = 0;
+                    if (mcmapAll.containsKey(mcp))
+                        mchits = mcmapAll.get(mcp);
+                    mchits++;
+                    mcmapAll.put(mcp, mchits);
+                    Integer mchitsAxial = 0;
+                    if (mcmapAxial.containsKey(mcp))
+                        mchitsAxial = mcmapAxial.get(mcp);
+                    mchitsAxial++;
+                    mcmapAxial.put(mcp, mchitsAxial);
+                }
+            }
+        }
+
+        //  Find the MCParticle that has the most hits on the track
+
+        int nbest = 0;
+        MCParticle mcbest = null;
+        for (MCParticle mcp : mcmap.keySet()) {
+            int count = mcmap.get(mcp);
+            if (count > nbest) {
+                nbest = count;
+                mcbest = mcp;
+            }
+        }
+
+        if (nbest > 0)
+            _mcp = mcbest;
+        _purity = (double) nbest / (double) _nhits;
+        _nbadhits = _nhits - nbest;
+
+
+//single strip layer accounting.
+        int nbestAll = 0;
+        MCParticle mcbestAll = null;
+        for (MCParticle mcp : mcmapAll.keySet()) {
+            int count = mcmapAll.get(mcp);
+            if (count > nbestAll) {
+                nbestAll = count;
+                mcbestAll = mcp;
+            }
+        }
+
+        if (nbestAll > 0)
+            _mcpNew = mcbestAll;
+        _purityNew = (double) nbestAll / (double) _nhitsNew;
+        _nbadhitsNew = _nhitsNew - nbestAll;
+
+        for (TrackerHit hit : trk.getTrackerHits()) {
+            HelicalTrackHit htc = (HelicalTrackHit) hit;
+            if (hit instanceof HelicalTrackCross) {
+                HelicalTrackCross cross = (HelicalTrackCross) hit;
+                List<HelicalTrackStrip> clusterlist = cross.getStrips();
+                for (HelicalTrackStrip cl : clusterlist){
+                    trackLayerList.add(cl.layer());
+                    if (!(cl.MCParticles().contains(_mcpNew))) {
+                        badHitList.add(cl.layer());
+                        badhits.put(_mcpNew, cross);
+                    }
+                    if(cl.MCParticles().size()>1)
+                        sharedHitList.add(cl.layer());
+                }
+            }
+        }
+
+
+
+        if (_nAxialhits > 0)
+            if (mcmapAxial.containsKey(_mcpNew))
+                _nbadAxialhits = _nAxialhits - mcmapAxial.get(_mcpNew);
+            else _nbadAxialhits = _nAxialhits;
+        if (_nZhits > 0)
+            if (mcmapZ.containsKey(_mcpNew))
+                _nbadZhits = _nZhits - mcmapZ.get(_mcpNew);
+            else _nbadZhits = _nZhits;
+
+    }
+
+    public Hep3Vector clusterPosition(HelicalTrackStrip cl) {
+        Hep3Vector corigin = cl.origin();
+        Hep3Vector u = cl.u();
+        double umeas = cl.umeas();
+        Hep3Vector uvec = VecOp.mult(umeas, u);
+        return VecOp.add(corigin, uvec);
+
+    }
+
+    public MCParticle getMCParticle() {
+        return _mcp;
+    }
+
+    public int getNHits() {
+        return _nhits;
+    }
+
+    public int getNBadHits() {
+        return _nbadhits;
+    }
+
+    public double getPurity() {
+        return _purity;
+    }
+
+    public MCParticle getMCParticleNew() {
+        return _mcpNew;
+    }
+
+    public int getNHitsNew() {
+        return _nhitsNew;
+    }
+
+    public int getNAxialHits() {
+        return _nAxialhits;
+    }
+
+    public int getNZHits() {
+        return _nZhits;
+    }
+
+    public int getNBadHitsNew() {
+        return _nbadhitsNew;
+    }
+
+    public double getPurityNew() {
+        return _purityNew;
+    }
+
+    public int getNBadAxialHits() {
+        return _nbadAxialhits;
+    }
+
+    public int getNBadZHits() {
+        return _nbadZhits;
+    }
+
+    public boolean hasLayerOne() {
+        return _hasLayerOne;
+    }
+
+    public Hep3Vector getClusterPosition(Integer layer) {
+        return _hitLocationPerLayer.get(layer);
+    }
+
+    public int getNumberOfMCParticles(int layer) {
+        return _nMCHitsPerLayer[layer - 1];
+    }
+
+    public int getNumberOfStripHits(int layer) {
+        return _nStripHitsPerLayer[layer - 1];
+    }
+
+    public List<Integer> getBadHitList() {
+        return badHitList;
+    }
+     public List<Integer> getSharedHitList() {
+        return sharedHitList;
+    }
+     
+       public List<Integer> getTrackLayerList() {
+        return trackLayerList;
+    }
+
+    public Map<MCParticle, HelicalTrackCross> getBadHits() {
+        return badhits;
+    }
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
TrackUtils.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/TrackUtils.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/TrackUtils.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,735 @@
+package org.hps.recon.tracking;
+
+//--- hep ---//
+import hep.physics.matrix.SymmetricMatrix;
+import hep.physics.vec.BasicHep3Vector;
+import hep.physics.vec.Hep3Matrix;
+import hep.physics.vec.Hep3Vector;
+import hep.physics.vec.SpacePoint;
+import hep.physics.vec.VecOp;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.hps.conditions.deprecated.BeamlineConstants;
+import org.hps.conditions.deprecated.SvtUtils;
+import org.lcsim.detector.ITransform3D;
+import org.lcsim.detector.solids.Box;
+import org.lcsim.detector.solids.Point3D;
+import org.lcsim.detector.solids.Polygon3D;
+import org.lcsim.detector.tracker.silicon.SiSensor;
+import org.lcsim.event.MCParticle;
+import org.lcsim.event.RawTrackerHit;
+//--- org.lcsim ---//
+import org.lcsim.event.Track;
+import org.lcsim.event.TrackerHit;
+import org.lcsim.fit.helicaltrack.HelicalTrackFit;
+import org.lcsim.fit.helicaltrack.HelicalTrackHit;
+import org.lcsim.fit.helicaltrack.HelicalTrackStrip;
+import org.lcsim.fit.helicaltrack.HelixParamCalculator;
+import org.lcsim.fit.helicaltrack.HelixUtils;
+import org.lcsim.fit.helicaltrack.HitUtils;
+import org.lcsim.fit.helicaltrack.MultipleScatter;
+import org.lcsim.recon.tracking.seedtracker.SeedCandidate;
+import org.lcsim.recon.tracking.seedtracker.SeedTrack;
+import org.lcsim.util.swim.Helix;
+
+/**
+ * Assorted helper functions for the track and helix objects in lcsim.
+ * Re-use as much of HelixUtils as possible.
+ * 
+ * @author Omar Moreno <[log in to unmask]>
+ * @version $Id: TrackUtils.java,v 1.34 2013/11/14 01:50:43 phansson Exp $
+ * TODO: Switch to tracking/LCsim coordinates for the extrapolation output!
+ */
+
+public class TrackUtils {
+
+	/**
+	 * Private constructor to make class static only
+	 */
+	private TrackUtils(){
+	}
+	
+	/**
+	 * Extrapolate track to a position along the x-axis. Turn the track into a helix object in order to use HelixUtils.
+	 * @param track
+	 * @param x
+	 * @return
+	 */
+	public static Hep3Vector extrapolateHelixToXPlane(Track track, double x){
+		return extrapolateHelixToXPlane(getHTF(track),x);
+	}
+
+	/**
+	 * Extrapolate helix to a position along the x-axis. Re-use HelixUtils.
+	 * @param track
+	 * @param x
+	 * @return
+	 */
+	public static Hep3Vector extrapolateHelixToXPlane(HelicalTrackFit htf, double x){
+		double s = HelixUtils.PathToXPlane(htf, x, 0., 0).get(0);
+		return HelixUtils.PointOnHelix(htf, s);
+	}
+	
+	// ==========================================================================
+	// Helper functions for track parameters and commonly used derived variables
+
+	public static double getPhi(Track track, Hep3Vector position){ 
+		double x = Math.sin(getPhi0(track)) - (1/getR(track))*(position.x() - getX0(track));
+		double y = Math.cos(getPhi0(track)) + (1/getR(track))*(position.y() - getY0(track));
+		return Math.atan2(x, y);
+	}
+	public static double getX0(Track track) {
+		return -1*getDoca(track)*Math.sin(getPhi0(track));
+	}
+	public static double getR(Track track) {
+		return 1.0/track.getTrackStates().get(0).getOmega();
+	}
+	public static double getY0(Track track) {
+		return getDoca(track)*Math.cos(getPhi0(track));
+	}
+	public static double getDoca(Track track) {
+		return track.getTrackStates().get(0).getD0();
+	}
+	public static double getPhi0(Track track) {
+		return track.getTrackStates().get(0).getPhi();
+	}
+	public static double getZ0(Track track) {
+		return track.getTrackStates().get(0).getZ0();
+	}
+	public static double getTanLambda(Track track) {
+		return track.getTrackStates().get(0).getTanLambda();
+	}
+	public static double getSinTheta(Track track){
+		return 1/Math.sqrt(1 + Math.pow(getTanLambda(track), 2));
+	}
+	public static double getCosTheta(Track track){
+		return getTanLambda(track)/Math.sqrt(1 + Math.pow(getTanLambda(track), 2));
+	}
+	// ==========================================================================
+
+       
+
+	/**
+	 * Calculate the point of interception between the helix and a plane in space. Uses an iterative procedure. 
+	 * @param helfit - helix 
+	 * @param unit_vec_normal_to_plane - unit vector normal to the plane
+	 * @param point_on_plane - point on the plane
+	 * @param bfield - magnetic field value
+	 * @return point at intercept
+	 */
+	public static Hep3Vector getHelixPlaneIntercept(HelicalTrackFit helfit, Hep3Vector unit_vec_normal_to_plane,Hep3Vector point_on_plane, double bfield) {
+            boolean debug = false;
+            boolean flipBfield = true; // be careful
+            Hep3Vector B = new BasicHep3Vector(0,0,flipBfield?-1:1);
+            WTrack wtrack = new WTrack(helfit,bfield,flipBfield); //
+            if(debug) System.out.printf("getHelixPlaneIntercept:find intercept between plane defined by point on plane %s, unit vec %s, bfield %.3f, h=%s and WTrack \n%s \n",point_on_plane.toString(),unit_vec_normal_to_plane.toString(), bfield, B.toString(),wtrack.toString());
+            Hep3Vector intercept_point =  wtrack.getHelixAndPlaneIntercept(point_on_plane, unit_vec_normal_to_plane, B);
+            if(debug) System.out.printf("getHelixPlaneIntercept: found intercept point at %s\n",intercept_point.toString());
+            return intercept_point;
+        }
+        
+        /**
+         * Calculate the point of interception between the helix and a plane in space. Uses an iterative procedure. 
+         * @param helfit - helix
+         * @param strip - strip cluster that will define the plane
+         * @param bfield - magnetic field value
+         * @return point at intercept
+         */
+        public static Hep3Vector getHelixPlaneIntercept(HelicalTrackFit helfit, HelicalTrackStrip strip, double bfield) {
+            Hep3Vector point_on_plane = strip.origin();
+            Hep3Vector unit_vec_normal_to_plane = VecOp.cross(strip.u(),strip.v());//strip.w();
+            Hep3Vector intercept_point = getHelixPlaneIntercept(helfit, unit_vec_normal_to_plane, point_on_plane, bfield);
+            return intercept_point;
+        }
+ 
+        
+        /*
+    	 *  Calculates the point on the helix in the x-y plane at the intercept with plane
+    	 *  The normal of the plane is in the same x-y plane as the circle.
+    	 * 
+    	 * @param helix
+    	 * @param vector normal to plane
+    	 * @param origin of plane
+    	 * @return point in the x-y plane of the intercept
+    	 * 
+    	 */
+    	public Hep3Vector getHelixXPlaneIntercept(HelicalTrackFit helix, Hep3Vector w, Hep3Vector origin) {
+    		throw new RuntimeException("this function is not working properly; don't use it");
+    		
+    		// FInd the intercept point x_int,y_int, between the circle and sensor, which becomes a line in the x-y plane in this case.
+    	    // y_int = k*x_int + m 
+    	    // R^2 = (y_int-y_c)^2 + (x_int-x_c)^2
+    	    // solve for x_int
+
+    	}
+
+        
+        
+        
+        /**
+         * Get position of a track extrapolated to the HARP in the HPS test run 2012
+         * @param track 
+         * @return position at HARP
+         */
+        public static Hep3Vector getTrackPositionAtHarp(Track track){
+			return extrapolateTrack(track, BeamlineConstants.HARP_POSITION_TESTRUN);
+		}
+
+        /**
+         * Get position of a track extrapolated to the ECAL face in the HPS test run 2012
+         * @param track 
+         * @return position at ECAL
+         */
+		public static Hep3Vector getTrackPositionAtEcal(Track track){
+			return extrapolateTrack(track, BeamlineConstants.ECAL_FACE_TESTRUN);
+		}
+
+		/**
+		 * Extrapolate track to given position.
+		 * @param helix - to be extrapolated
+		 * @param track - position along the x-axis of the helix in lcsim coordiantes
+		 * @return
+		 */
+		public static Hep3Vector extrapolateTrack(Track track, double z){
+		
+			Hep3Vector trackPosition = null;
+			double dz = 0;
+			if(z >= BeamlineConstants.DIPOLE_EDGE_TESTRUN){
+				trackPosition = extrapolateHelixToXPlane(track, BeamlineConstants.DIPOLE_EDGE_TESTRUN);
+				dz = z - BeamlineConstants.DIPOLE_EDGE_TESTRUN;
+			} else if(z <= BeamlineConstants.DIPOLE_EDGELOW_TESTRUN){
+				trackPosition  = extrapolateHelixToXPlane(track, BeamlineConstants.DIPOLE_EDGELOW_TESTRUN);
+				dz = z - trackPosition.x();
+			} else {
+				Hep3Vector detVecTracking = extrapolateHelixToXPlane(track,z);
+				//System.out.printf("detVec %s\n", detVecTracking.toString());
+				return new BasicHep3Vector(detVecTracking.y(),detVecTracking.z(),detVecTracking.x());
+			}
+			
+			// Get the track azimuthal angle
+			double phi = getPhi(track, trackPosition);
+		
+			// Find the distance to the point of interest
+			double r = dz/(getSinTheta(track)*Math.cos(phi));
+			double dx = r*getSinTheta(track)*Math.sin(phi);
+			double dy = r*getCosTheta(track);
+			
+			// Find the track position at the point of interest
+			double x = trackPosition.y() + dx;
+			double y = trackPosition.z() + dy;
+			
+			return new BasicHep3Vector(x, y, z);
+		}
+
+		/**
+		 * Extrapolate helix to given position
+		 * @param helix - to be extrapolated
+		 * @param z - position along the x-axis of the helix in lcsim coordiantes
+		 * @return
+		 */
+		public static Hep3Vector extrapolateTrack(HelicalTrackFit helix, double z){
+		    SeedTrack trk = new SeedTrack();
+		    //bfield = Math.abs((detector.getFieldMap().getField(new BasicHep3Vector(0, 0, 0)).y()));
+		    double bfield = 0.;        
+		    // Here we aren't really using anything related to momentum so B-field is not important
+		    trk.setTrackParameters(helix.parameters(), bfield); // Sets first TrackState.
+		    trk.setCovarianceMatrix(helix.covariance()); // Modifies first TrackState.
+		    trk.setChisq(helix.chisqtot());
+		    trk.setNDF(helix.ndf()[0]+helix.ndf()[1]);        
+		    return TrackUtils.extrapolateTrack(trk,z);
+		}
+
+		/**
+         * @param helix input helix object
+         * @param origin of the plane to intercept
+         * @param normal of the plane to intercept
+         * @param eps  criteria on the distance to the plane before stopping iteration
+         * @return position in space at the intercept of the plane
+         */
+        public static Hep3Vector getHelixPlanePositionIter(HelicalTrackFit helix, Hep3Vector origin, Hep3Vector normal, double eps) {
+        	boolean debug = false;
+        	if(debug) {
+        	System.out.printf("--- getHelixPlanePositionIter ---\n");
+        	System.out.printf("Target origin [%.10f %.10f %.10f] normal [%.10f %.10f %.10f]\n",origin.x(),origin.y(),origin.z(),normal.x(),normal.y(),normal.z());
+        	System.out.printf("%.10f %.10f %.10f %.10f %.10f\n",helix.dca(),helix.z0(),helix.phi0(),helix.slope(),helix.R());
+        	}
+        	double x = origin.x();
+        	double d = 9999.9;
+        	double dx = 0.0;
+        	int nIter = 0;
+        	Hep3Vector pos = null;
+        	while( Math.abs(d) > eps && nIter < 50) {
+        		// Calculate position on helix at x
+        		pos = getHelixPosAtX(helix, x + dx);
+        		//	 Check if we are on the plane
+        		d =  VecOp.dot(VecOp.sub(pos, origin), normal);
+        		dx += -1.0 * d / 2.0;
+        	    if(debug) System.out.printf("%d d %.10f pos [%.10f %.10f %.10f] dx %.10f\n", nIter, d, pos.x(),pos.y(),pos.z(), dx);
+        	    nIter +=  1;
+        	}
+    	    return pos;
+        }
+        
+        /*
+         *  Calculates the point on the helix at a given point along the x-axis
+         *  The normal of the plane is in the same x-y plane as the circle.
+         * 
+         * @param helix
+         * @param x point along x-axis 
+         * @return point on helix at x-coordinate
+         * 
+         */
+        private static Hep3Vector getHelixPosAtX(HelicalTrackFit helix, double x) {
+        	//double C = (double)Math.round(helix.curvature()*1000000)/1000000;
+        	//double R = 1.0/C;
+        	double R = helix.R();
+    	    double dca = helix.dca();
+    	    double z0 = helix.z0();
+    	    double phi0 = helix.phi0();
+    	    double slope = helix.slope();    
+        	//System.out.printf("%.10f %.10f %.10f %.10f %.10f\n",dca,z0,phi0,slope,R);
+    	    
+    	    double xc = (R - dca) * Math.sin(phi0);
+    	    double sinPhi = (xc - x)/R;
+    	    double phi_at_x = Math.asin(sinPhi);
+    	    double dphi_at_x = phi_at_x - phi0;
+    	    if (dphi_at_x > Math.PI) dphi_at_x -= 2.0 * Math.PI;
+    	    if (dphi_at_x < -Math.PI) dphi_at_x += 2.0 * Math.PI;
+    	    double s_at_x = -1.0 * dphi_at_x * R;    
+    	    double y = dca * Math.cos(phi0) - R * Math.cos(phi0) + R * Math.cos(phi_at_x);
+    	    double z = z0 + s_at_x * slope;
+    	    BasicHep3Vector pos = new BasicHep3Vector(x,y,z);
+    	    //System.out.printf("pos %s xc %f phi_at_x %f dphi_at_x %f s_at_x %f\n", pos.toString(),xc,phi_at_x,dphi_at_x,s_at_x);
+    	    Hep3Vector posXCheck =TrackUtils.extrapolateHelixToXPlane(helix, x);
+    	    if(VecOp.sub(pos,posXCheck).magnitude()>0.0000001) {
+    	    	throw new RuntimeException(String.format("ERROR the helix propagation equations do not agree? (%f,%f,%f) vs (%f,%f,%f) in HelixUtils",pos.x(),pos.y(),pos.z(),posXCheck.x(),posXCheck.y(),posXCheck.z()));
+    	    }
+    	    return pos;
+        }
+        
+
+        
+        /**
+        *
+        */
+        public static double findTriangleArea(double x0, double y0, double x1, double y1, double x2, double y2){
+            return .5*(x1*y2 - y1*x2 -x0*y2 + y0*x2 + x0*y1 - y0*x1); 
+        }
+
+        
+        /**
+        *
+        */
+        public static boolean sensorContainsTrack(Hep3Vector trackPosition, SiSensor sensor){
+            boolean debug = false;
+            ITransform3D localToGlobal = sensor.getGeometry().getLocalToGlobal();
+
+            Box sensorSolid = (Box) sensor.getGeometry().getLogicalVolume().getSolid();
+            Polygon3D sensorFace = sensorSolid.getFacesNormalTo(new BasicHep3Vector(0, 0, 1)).get(0);
+            if(debug){
+                    System.out.println("sensorContainsTrack:  Sensor: " + SvtUtils.getInstance().getDescription(sensor));
+                    System.out.println("sensorContainsTrack:  Track Position: " + trackPosition.toString());
+            }
+
+            List<Point3D> vertices = new ArrayList<Point3D>();
+            for(int index = 0; index < 4; index++){
+                    vertices.add(new Point3D());
+            }
+            for(Point3D vertex : sensorFace.getVertices()){
+                if(vertex.y() < 0 && vertex.x() > 0){
+                    localToGlobal.transform(vertex);
+                    //vertices.set(0, new Point3D(vertex.y() + sensorPos.x(), vertex.x() + sensorPos.y(), vertex.z() + sensorPos.z()));
+                    vertices.set(0, new Point3D(vertex.x(), vertex.y(), vertex.z()));
+                    if(debug){
+                            System.out.println("sensorContainsTrack:  Vertex 1 Position: " + vertices.get(0).toString());
+                            //System.out.println("sensorContainsTrack:  Transformed Vertex 1 Position: " + localToGlobal.transformed(vertex).toString());
+                    }
+                } 
+                else if(vertex.y() > 0 && vertex.x() > 0){
+                    localToGlobal.transform(vertex);
+                    //vertices.set(1, new Point3D(vertex.y() + sensorPos.x(), vertex.x() + sensorPos.y(), vertex.z() + sensorPos.z()));
+                    vertices.set(1, new Point3D(vertex.x(), vertex.y(), vertex.z()));
+                    if(debug){
+                    System.out.println("sensorContainsTrack:  Vertex 2 Position: " + vertices.get(1).toString());
+                    //System.out.println("sensorContainsTrack:  Transformed Vertex 2 Position: " + localToGlobal.transformed(vertex).toString());
+                    }
+                } 
+                else if(vertex.y() > 0 && vertex.x() < 0){
+                    localToGlobal.transform(vertex);
+                    //vertices.set(2, new Point3D(vertex.y() + sensorPos.x(), vertex.x() + sensorPos.y(), vertex.z() + sensorPos.z()));
+                    vertices.set(2, new Point3D(vertex.x(), vertex.y(), vertex.z()));
+                    if(debug){
+                    System.out.println("sensorContainsTrack:  Vertex 3 Position: " + vertices.get(2).toString());
+                    //System.out.println("sensorContainsTrack:  Transformed Vertex 3 Position: " + localToGlobal.transformed(vertex).toString());
+                    }
+                }             
+                else if(vertex.y() < 0 && vertex.x() < 0){
+                    localToGlobal.transform(vertex);
+                    //vertices.set(3, new Point3D(vertex.y() + sensorPos.x(), vertex.x() + sensorPos.y(), vertex.z() + sensorPos.z()));
+                    vertices.set(3, new Point3D(vertex.x(), vertex.y(), vertex.z()));
+                    if(debug){
+                    System.out.println("sensorContainsTrack:  Vertex 4 Position: " + vertices.get(3).toString());
+                    //System.out.println("sensorContainsTrack:  Transformed Vertex 4 Position: " + localToGlobal.transformed(vertex).toString());
+                    }
+                } 
+            }
+
+            double area1 = TrackUtils.findTriangleArea(vertices.get(0).x(), vertices.get(0).y(), vertices.get(1).x(), vertices.get(1).y(), trackPosition.y(), trackPosition.z()); 
+            double area2 = TrackUtils.findTriangleArea(vertices.get(1).x(), vertices.get(1).y(), vertices.get(2).x(), vertices.get(2).y(), trackPosition.y(), trackPosition.z()); 
+            double area3 = TrackUtils.findTriangleArea(vertices.get(2).x(), vertices.get(2).y(), vertices.get(3).x(), vertices.get(3).y(), trackPosition.y(), trackPosition.z()); 
+            double area4 = TrackUtils.findTriangleArea(vertices.get(3).x(), vertices.get(3).y(), vertices.get(0).x(), vertices.get(0).y(), trackPosition.y(), trackPosition.z()); 
+
+            if((area1 > 0 && area2 > 0 && area3 > 0 && area4 > 0) || (area1 < 0 && area2 < 0 && area3 < 0 && area4 < 0)) return true;
+
+            return false;
+        } 
+
+        
+        public static Map<String,Double> calculateTrackHitResidual(HelicalTrackHit hth,HelicalTrackFit track, boolean includeMS ) {
+            
+            boolean debug = false;
+            Map<String,Double> residuals = new HashMap<String,Double>();
+
+            Map<HelicalTrackHit, MultipleScatter> msmap = track.ScatterMap();
+            double msdrphi = 0;
+            double msdz = 0; 
+
+            if(includeMS) {
+                msdrphi = msmap.get(hth).drphi();
+                msdz = msmap.get(hth).dz();
+            }
+            
+            //Calculate the residuals that are being used in the track fit
+
+            //Start with the bendplane y
+            double drphi_res = hth.drphi();
+            double wrphi = Math.sqrt(drphi_res*drphi_res + msdrphi*msdrphi);
+            //This is the normal way to get s
+            double s_wrong = track.PathMap().get(hth);
+            //This is how I do it with HelicalTrackFits
+            double s = HelixUtils.PathToXPlane(track, hth.x(), 0, 0).get(0);
+            //System.out.printf("x %f s %f smap %f\n",hth.x(),s,s_wrong);
+            if(Double.isNaN(s)) {
+                double xc=track.xc();
+                double RC = track.R();
+                System.out.printf("calculateTrackHitResidual: s is NaN. p=%.3f RC=%.3f, x=%.3f, xc=%.3f\n",track.p(-0.491),RC,hth.x(),xc);
+                return residuals;
+            }         
+            
+            Hep3Vector posOnHelix = HelixUtils.PointOnHelix(track, s);
+            double resy = hth.y() - posOnHelix.y();
+            double erry = includeMS ? wrphi : drphi_res;
+            
+            //Now the residual for the "measurement" direction z
+            double resz = hth.z() - posOnHelix.z();
+            double dz_res = HitUtils.zres(hth, msmap, track);
+            double dz_res2 = hth.getCorrectedCovMatrix().diagonal(2);
+
+            if(Double.isNaN(resy)) {
+                System.out.printf("calculateTrackHitResidual: resy is NaN. hit at %s posOnHelix=%s path=%.3f wrong_path=%.3f helix:\n%s\n",hth.getCorrectedPosition().toString(),posOnHelix.toString(),s,s_wrong,track.toString());
+                return residuals;            
+            }
+
+            
+            residuals.put("resy", resy);
+            residuals.put("erry", erry);
+            residuals.put("drphi", drphi_res);
+            residuals.put("msdrphi",msdrphi);
+
+            residuals.put("resz",resz);
+            residuals.put("errz",dz_res);
+            residuals.put("dz_res",Math.sqrt(dz_res2));
+            residuals.put("msdz",msdz);
+            
+            
+            if(debug) {
+                System.out.printf("calculateTrackHitResidual: HTH hit at (%f,%f,%f)\n",hth.x(),hth.y(),hth.z());
+                System.out.printf("calculateTrackHitResidual: helix params d0=%f phi0=%f R=%f z0=%f slope=%f chi2=%f/%f chi2tot=%f\n",track.dca(),track.phi0(),track.R(),track.z0(),track.slope(),track.chisq()[0],track.chisq()[1],track.chisqtot());
+                System.out.printf("calculateTrackHitResidual: => resz=%f resy=%f at s=%f\n",resz,resy,s);
+                //System.out.printf("calculateTrackHitResidual: resy=%f eresy=%f drphi=%f msdrphi=%f \n",resy,erry,drphi_res,msdrphi);
+                //System.out.printf("calculateTrackHitResidual: resz=%f eresz=%f dz_res=%f msdz=%f \n",resz,dz_res,Math.sqrt(dz_res2),msdz);
+            }          
+            
+        
+            return residuals;
+        }
+        
+
+        public static Map<String,Double> calculateLocalTrackHitResiduals(Track track, HelicalTrackHit hth, HelicalTrackStrip strip, double bFieldInZ) {
+            
+            SeedTrack st = (SeedTrack) track;
+            SeedCandidate seed = st.getSeedCandidate();
+            HelicalTrackFit _trk = seed.getHelix();
+            Map<HelicalTrackHit,MultipleScatter> msmap = seed.getMSMap();
+            double msdrdphi = msmap.get(hth).drphi();
+            double msdz = msmap.get(hth).dz();
+            return calculateLocalTrackHitResiduals(_trk, strip,  msdrdphi,  msdz,  bFieldInZ);
+        }
+        
+        public static Map<String,Double> calculateLocalTrackHitResiduals(HelicalTrackFit _trk, HelicalTrackStrip strip, double msdrdphi, double msdz, double bFieldInZ) {
+        
+        
+            boolean debug = false;
+            boolean includeMS = true;
+            
+            
+            Hep3Vector u = strip.u();
+            Hep3Vector corigin = strip.origin();
+
+            //Find interception with plane that the strips belongs to
+            Hep3Vector trkpos = TrackUtils.getHelixPlaneIntercept(_trk, strip, bFieldInZ);
+        
+            if(debug) {
+                System.out.printf("calculateLocalTrackHitResiduals: found interception point at %s \n",trkpos.toString());
+            }
+        
+
+            if(Double.isNaN(trkpos.x()) || Double.isNaN(trkpos.y()) || Double.isNaN(trkpos.z())) {
+                System.out.printf("calculateLocalTrackHitResiduals: failed to get interception point (%s) \n",trkpos.toString());
+                System.out.printf("calculateLocalTrackHitResiduals: track params\n%s\n",_trk.toString());
+                System.out.printf("calculateLocalTrackHitResiduals: track pT=%.3f chi2=[%.3f][%.3f] \n",_trk.pT(bFieldInZ),_trk.chisq()[0],_trk.chisq()[1]);
+                trkpos = TrackUtils.getHelixPlaneIntercept(_trk, strip, bFieldInZ);
+                System.exit(1);
+            }
+        
+            double xint = trkpos.x();
+            double phi0 = _trk.phi0();
+            double R = _trk.R();
+            double s = HelixUtils.PathToXPlane(_trk, xint, 0, 0).get(0);
+            double phi = -s/R + phi0;
+
+            
+            Hep3Vector mserr = new BasicHep3Vector(msdrdphi * Math.sin(phi), msdrdphi * Math.sin(phi), msdz);
+            double msuError = VecOp.dot(mserr, u);
+
+            Hep3Vector vdiffTrk = VecOp.sub(trkpos, corigin);
+            TrackerHitUtils thu = new TrackerHitUtils(debug);
+            Hep3Matrix trkToStrip = thu.getTrackToStripRotation(strip);
+            Hep3Vector vdiff = VecOp.mult(trkToStrip, vdiffTrk);
+
+
+            double umc = vdiff.x();
+            double vmc = vdiff.y();
+            double wmc = vdiff.z();
+            double umeas = strip.umeas();
+            double uError = strip.du();
+            double vmeas = 0;
+            double vError = (strip.vmax() - strip.vmin()) / Math.sqrt(12);
+            double wmeas = 0;
+            double wError = 10.0/Math.sqrt(12); //0.001;
+
+            Map<String,Double> res = new HashMap<String,Double>();
+            res.put("ures", umeas-umc);
+            res.put("ureserr", includeMS ? Math.sqrt(uError * uError + msuError * msuError) : uError);
+            res.put("vres", vmeas-vmc);
+            res.put("vreserr", vError);
+            res.put("wres", wmeas-wmc);
+            res.put("wreserr", wError);
+            
+            res.put("vdiffTrky",vdiffTrk.y());
+
+            return res;
+        }
+        
+        
+    public static int[] getHitsInTopBottom(Track track) {
+        int n[] = {0,0};
+        List<TrackerHit> hitsOnTrack = track.getTrackerHits();
+        for(TrackerHit hit : hitsOnTrack) {
+            HelicalTrackHit hth = (HelicalTrackHit) hit;
+            if(SvtUtils.getInstance().isTopLayer((SiSensor)((RawTrackerHit)hth.getRawHits().get(0)).getDetectorElement())) {
+                n[0] = n[0] + 1;
+            } else {
+                n[1] = n[1] + 1;
+            }
+        }
+        return n;
+    }
+    
+    public static boolean isTopTrack(Track track,int minhits) {
+        return isTopOrBottomTrack(track,minhits)==1?true:false;
+    }
+
+    public static boolean isBottomTrack(Track track,int minhits) {
+        return isTopOrBottomTrack(track,minhits)==0?true:false;
+    }
+
+    public static int isTopOrBottomTrack(Track track,int minhits) {
+        int nhits[] = getHitsInTopBottom(track);
+        if (nhits[0]>=minhits && nhits[1]==0) {
+            return 1;
+        } else if (nhits[1]>=minhits && nhits[0]==0) {
+            return 0;
+        } else {
+            return -1;
+        }
+    }
+    
+    public static boolean hasTopBotHit(Track track) {
+        int nhits[] = getHitsInTopBottom(track);
+        if (nhits[0]>0 && nhits[1]>0) return true;
+        else return false;
+    }
+
+    public static boolean isSharedHit(TrackerHit hit, List<Track> othertracks) {
+        HelicalTrackHit hth = (HelicalTrackHit) hit;
+        for(Track track : othertracks) {
+            List<TrackerHit> hitsOnTrack = track.getTrackerHits();
+            for(TrackerHit loop_hit : hitsOnTrack) {
+                HelicalTrackHit loop_hth = (HelicalTrackHit) loop_hit;
+                if(hth.equals(loop_hth)) {
+                    //System.out.printf("share hit at layer %d at %s (%s) with track w/ chi2=%f\n",hth.Layer(),hth.getCorrectedPosition().toString(),loop_hth.getCorrectedPosition().toString(),track.getChi2());
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+    
+    public static int numberOfSharedHits(Track track, List<Track> tracklist) {
+        List<Track> tracks = new ArrayList<Track>();
+        //System.out.printf("%d tracks in event\n",tracklist.size());
+        //System.out.printf("look for another track with chi2=%f and px=%f \n",track.getChi2(),track.getTrackStates().get(0).getMomentum()[0]);
+        for(Track t: tracklist) {
+            //System.out.printf("add track with chi2=%f and px=%f ?\n",t.getChi2(),t.getTrackStates().get(0).getMomentum()[0]);
+            if(t.equals(track)) {
+                //System.out.printf("NOPE\n");
+                continue;
+            }
+            //System.out.printf("YEPP\n");
+            tracks.add(t);
+        }
+        List<TrackerHit> hitsOnTrack = track.getTrackerHits();
+        int n_shared = 0;
+        for(TrackerHit hit : hitsOnTrack) {
+            if (isSharedHit(hit,tracks)) {
+                ++n_shared;
+            }
+        }
+        return n_shared;
+    }
+    
+    public static boolean hasSharedHits(Track track,List<Track> tracklist) {
+        return numberOfSharedHits( track, tracklist)==0?false:true;
+    }
+    
+    public static void cut(int cuts[],EventQuality.Cut bit) {
+            cuts[0] = cuts[0] | (1 << bit.getValue());
+    }
+    
+    
+    public static boolean isGoodTrack(Track track, List<Track> tracklist, EventQuality.Quality trk_quality) {
+        int cuts = passTrackSelections(track, tracklist, trk_quality);
+        return cuts==0?true:false;
+    }
+
+    public static int passTrackSelections(Track track, List<Track> tracklist, EventQuality.Quality trk_quality) {
+        int cuts[] = {0};
+        if(track.getTrackStates().get(0).getMomentum()[0] < EventQuality.instance().getCutValue(EventQuality.Cut.PZ, trk_quality)) 
+            cut(cuts,EventQuality.Cut.PZ);
+        if(track.getChi2()>= EventQuality.instance().getCutValue(EventQuality.Cut.CHI2, trk_quality)) 
+            cut(cuts,EventQuality.Cut.CHI2);
+        if(numberOfSharedHits(track,tracklist) > ((int)Math.round(EventQuality.instance().getCutValue(EventQuality.Cut.SHAREDHIT, trk_quality))))
+            cut(cuts,EventQuality.Cut.SHAREDHIT);
+        if(hasTopBotHit(track))
+            cut(cuts,EventQuality.Cut.TOPBOTHIT);
+        if(track.getTrackerHits().size()< ((int)Math.round(EventQuality.instance().getCutValue(EventQuality.Cut.NHITS, trk_quality))))
+            cut(cuts,EventQuality.Cut.NHITS);
+        return cuts[0];
+    }
+
+    public static boolean isTopTrack(HelicalTrackFit htf) {
+        return htf.slope()>0;
+    }
+
+    public static boolean isBottomTrack(HelicalTrackFit htf) {
+        return !isTopTrack(htf);
+    }
+        
+    /**
+     * Transform MCParticle into a Helix object.
+     * Note that it produces the helix parameters at nominal x=0 and assumes that there is no field at x<0
+     * 
+     * @param mcp MC particle to be transformed
+     * @return helix object based on the MC particle
+     */
+    public static HelicalTrackFit getHTF(MCParticle mcp, double Bz) {
+    	Hep3Vector org = HPSTransformations.transformVectorToTracking(mcp.getOrigin());
+        Hep3Vector p = HPSTransformations.transformVectorToTracking(mcp.getMomentum());
+        // Move to x=0 if needed
+        double targetX = BeamlineConstants.DIPOLE_EDGELOW_TESTRUN;
+        if(org.x() < targetX) { 
+        	double dydx = p.y()/p.x();
+        	double dzdx = p.z()/p.x();
+        	double delta_x = targetX - org.x(); 
+        	double y = delta_x * dydx + org.y();
+        	double z = delta_x * dzdx + org.z();
+        	double x = org.x() + delta_x;
+        	if( Math.abs(x-targetX) > 1e-8) throw new RuntimeException("Error: origin is not zero!");
+        	org = new BasicHep3Vector(x,y,z);
+        	//System.out.printf("org %s p %s -> org %s\n", old.toString(),p.toString(),org.toString());
+        } 
+        
+        //System.out.printf("outside org %s p %s \n",p.toString(),org.toString());
+    
+        
+        
+        HelixParamCalculator helixParamCalculator = new HelixParamCalculator(p, org, -1*((int)mcp.getCharge()), Bz);
+        double par[] = new double[5];
+        par[HelicalTrackFit.dcaIndex] = helixParamCalculator.getDCA();
+        par[HelicalTrackFit.slopeIndex] = helixParamCalculator.getSlopeSZPlane();
+        par[HelicalTrackFit.phi0Index] = helixParamCalculator.getPhi0();
+        par[HelicalTrackFit.curvatureIndex] = 1.0/helixParamCalculator.getRadius();
+        par[HelicalTrackFit.z0Index] = helixParamCalculator.getZ0();
+        HelicalTrackFit htf = getHTF(par);
+        //System.out.printf("d0 %f z0 %f R %f phi %f lambda %s\n", htf.dca(),htf.z0(),htf.R(),htf.phi0(),htf.slope() );
+        return htf;
+    }
+    
+    public static HelicalTrackFit getHTF(Track track) {
+    	if( track.getClass().isInstance(SeedTrack.class) ) {
+    		return ((SeedTrack) track).getSeedCandidate().getHelix();
+    	} else {
+    		return getHTF(track.getTrackStates().get(0).getParameters());
+    	}
+    }
+    
+    public static HelicalTrackFit getHTF(double par[]) {
+    	// need to have matrix that makes sense? Really?
+    	SymmetricMatrix cov = new SymmetricMatrix(5);
+        for(int i=0;i<cov.getNRows();++i) cov.setElement(i, i, 1.);
+        HelicalTrackFit htf = new HelicalTrackFit(par, cov, new double[2], new int[2], null, null);
+        return htf;
+    }
+    
+    public static StraightLineTrack findSLTAtZ(Track trk1, double zVal, boolean useFringe) {
+        SeedTrack s1 = (SeedTrack) trk1;
+        HelicalTrackFit htf1 = s1.getSeedCandidate().getHelix();
+        HPSTrack hpstrk1 = new HPSTrack(htf1);
+        Hep3Vector pos1;
+        if(useFringe) {
+            pos1 = hpstrk1.getPositionAtZMap(100.0, zVal, 5.0)[0];
+        } else {
+            pos1 = TrackUtils.extrapolateTrack(trk1,zVal);
+        }
+        //System.out.printf("%s: Position1 at edge of fringe %s\n",this.getClass().getSimpleName(),pos1.toString());
+        Helix traj = (Helix)hpstrk1.getTrajectory();
+        if(traj==null) {
+            SpacePoint r0 = new SpacePoint(HelixUtils.PointOnHelix(htf1,0));
+            traj = new Helix(r0,htf1.R(), htf1.phi0(), Math.atan(htf1.slope()));
+        }
+        HelixConverter converter = new HelixConverter(0.);
+        StraightLineTrack slt1 =converter.Convert(traj);
+        //System.out.printf("%s: straight line track: x0=%f,y0=%f,z0=%f dz/dx=%f dydx=%f targetY=%f targetZ=%f \n",this.getClass().getSimpleName(),slt1.x0(),slt1.y0(),slt1.z0(),slt1.dzdx(),slt1.dydx(),slt1.TargetYZ()[0],slt1.TargetYZ()[1]);
+        return slt1;
+    }
+    
+}
+
+
+    
+

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
TrackerDigiDriver.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/TrackerDigiDriver.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/TrackerDigiDriver.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,299 @@
+package org.hps.recon.tracking;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.lcsim.detector.IDetectorElement;
+import org.lcsim.detector.tracker.silicon.SiSensor;
+import org.lcsim.detector.tracker.silicon.SiTrackerModule;
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.RawTrackerHit;
+import org.lcsim.event.SimTrackerHit;
+import org.lcsim.geometry.Detector;
+import org.lcsim.lcio.LCIOUtil;
+import org.lcsim.recon.tracking.digitization.sisim.BasicReadoutChip;
+import org.lcsim.recon.tracking.digitization.sisim.CDFSiSensorSim;
+import org.lcsim.recon.tracking.digitization.sisim.NearestNeighborRMS;
+import org.lcsim.recon.tracking.digitization.sisim.RawTrackerHitMaker;
+import org.lcsim.recon.tracking.digitization.sisim.SiDigitizer;
+import org.lcsim.recon.tracking.digitization.sisim.SiTrackerHit;
+import org.lcsim.recon.tracking.digitization.sisim.SiTrackerHitStrip1D;
+import org.lcsim.recon.tracking.digitization.sisim.StripHitMaker;
+import org.lcsim.recon.tracking.digitization.sisim.config.SimTrackerHitReadoutDriver;
+import org.lcsim.util.Driver;
+
+/**
+ * This Driver runs the tracker digitization to create raw hits and strip hits
+ * from simulated data. The output can be used by a track reconstruction
+ * algorithm like Seed Tracker.
+ * 
+ * @author jeremym
+ * @version $Id: TrackerDigiDriver.java,v 1.12 2012/11/20 19:59:35 meeg Exp $
+ */
+public class TrackerDigiDriver extends Driver {
+    // Debug switch for development.
+
+    private boolean debug = false;
+    // Collection name.
+    protected String readoutCollectionName = "TrackerHits";
+    // Subdetector name.
+    protected String subdetectorName = "Tracker";
+    // Name of RawTrackerHit output collection.
+    private String rawTrackerHitOutputCollectionName = "RawTrackerHitMaker_RawTrackerHits";
+    // Name of StripHit1D output collection.
+    private String stripHitOutputCollectionName = "StripClusterer_SiTrackerHitStrip1D";
+    // Readout parameters.
+    protected double readoutNoiseIntercept = 270.0;
+    protected double readoutNoiseSlope = 36.0;
+    protected double readoutNoiseThreshold = 4.0;
+    protected double readoutNeighborThreshold = 4.0;
+    protected int readoutNBits = 10;
+    protected int readoutDynamicRange = 40;
+    // Clustering parameters.
+    protected double clusterSeedThreshold = 4.0;
+    protected double clusterNeighborThreshold = 3.0;
+    protected double clusterThreshold = 4.0;
+    protected int clusterMaxSize = 10;
+    protected int clusterCentralStripAveragingThreshold = 4;
+    // Clustering errors by number of TrackerHits.
+    private static final double clusterErrorMultiplier = 1.0;
+    protected double oneClusterErr = clusterErrorMultiplier / Math.sqrt(12.);
+    protected double twoClusterErr = clusterErrorMultiplier / 5.0;
+    protected double threeClusterErr = clusterErrorMultiplier / 3.0;
+    protected double fourClusterErr = clusterErrorMultiplier / 2.0;
+    protected double fiveClusterErr = clusterErrorMultiplier / 1.0;
+    // Various data lists required by digitization.
+    protected List<String> readouts = new ArrayList<String>();
+    protected List<String> processPaths = new ArrayList<String>();
+    private List<IDetectorElement> processDEs = new ArrayList<IDetectorElement>();
+    private Set<SiSensor> processSensors = new HashSet<SiSensor>();
+    private Set<SiTrackerModule> processModules = new HashSet<SiTrackerModule>();
+    // Digi class objects.
+    protected SiDigitizer stripDigitizer;
+    protected StripHitMaker stripClusterer;
+
+    public void setDebug(boolean debug) {
+        this.debug = debug;
+    }
+
+    public void setReadoutCollectionName(String readoutCollectionName) {
+        this.readoutCollectionName = readoutCollectionName;
+    }
+
+    public void setSubdetectorName(String subdetectorName) {
+        this.subdetectorName = subdetectorName;
+    }
+
+    public void setRawTrackerHitOutputCollectionName(String rawTrackerHitOutputCollectionName) {
+        this.rawTrackerHitOutputCollectionName = rawTrackerHitOutputCollectionName;
+    }
+
+    public void setStripHitOutputCollectionName(String stripHitOutputCollectionName) {
+        this.stripHitOutputCollectionName = stripHitOutputCollectionName;
+    }
+
+    public void setReadoutNoiseIntercept(double readoutNoiseIntercept) {
+        this.readoutNoiseIntercept = readoutNoiseIntercept;
+    }
+
+    public void setReadoutNoiseSlope(double readoutNoiseSlope) {
+        this.readoutNoiseSlope = readoutNoiseSlope;
+    }
+
+    public void setReadoutNeighborThreshold(double readoutNeighborThreshold) {
+        this.readoutNeighborThreshold = readoutNeighborThreshold;
+    }
+
+    public void setReadoutNBits(int readoutNBits) {
+        this.readoutNBits = readoutNBits;
+    }
+
+    public void setReadoutDynamicRange(int readoutDynamicRange) {
+        this.readoutDynamicRange = readoutDynamicRange;
+    }
+
+    public void setClusterSeedThreshold(double clusterSeedThreshold) {
+        this.clusterSeedThreshold = clusterSeedThreshold;
+    }
+
+    public void setClusterNeighborThreshold(double clusterNeighborThreshold) {
+        this.clusterNeighborThreshold = clusterNeighborThreshold;
+    }
+
+    public void setClusterThreshold(double clusterThreshold) {
+        this.clusterThreshold = clusterThreshold;
+    }
+
+    public void setClusterMaxSize(int clusterMaxSize) {
+        this.clusterMaxSize = clusterMaxSize;
+    }
+
+    public void setClusterCentralStripAveragingThreshold(int clusterCentralStripAveragingThreshold) {
+        this.clusterCentralStripAveragingThreshold = clusterCentralStripAveragingThreshold;
+    }
+
+    public void setOneClusterErr(double oneClusterErr) {
+        this.oneClusterErr = oneClusterErr;
+    }
+
+    public void setTwoClusterErr(double twoClusterErr) {
+        this.twoClusterErr = twoClusterErr;
+    }
+
+    public void setThreeClusterErr(double threeClusterErr) {
+        this.threeClusterErr = threeClusterErr;
+    }
+
+    public void setFourClusterErr(double fourClusterErr) {
+        this.fourClusterErr = fourClusterErr;
+    }
+
+    public void setFiveClusterErr(double fiveClusterErr) {
+        this.fiveClusterErr = fiveClusterErr;
+    }
+
+    /**
+     * Creates a new instance of TrackerHitDriver.
+     */
+    public TrackerDigiDriver() {
+    }
+
+    /**
+     * Initializes this Driver's objects with the job parameters.
+     */
+    protected void initialize() {
+
+        // Create the sensor simulation.
+        CDFSiSensorSim stripSim = new CDFSiSensorSim();
+
+        // Create the readout chips and set the noise parameters.
+        BasicReadoutChip stripReadout = new BasicReadoutChip();
+        stripReadout.setNoiseIntercept(readoutNoiseIntercept);
+        stripReadout.setNoiseSlope(readoutNoiseSlope);
+        stripReadout.setNoiseThreshold(readoutNoiseThreshold);
+        stripReadout.setNeighborThreshold(readoutNeighborThreshold);
+        stripReadout.setNbits(readoutNBits);
+        stripReadout.setDynamicRange(readoutDynamicRange);
+
+        // Create the digitizer that produces the raw hits
+        stripDigitizer = new RawTrackerHitMaker(stripSim, stripReadout);
+
+        // Create Strip clustering algorithm.
+        NearestNeighborRMS stripClusteringAlgo = new NearestNeighborRMS();
+        stripClusteringAlgo.setSeedThreshold(clusterSeedThreshold);
+        stripClusteringAlgo.setNeighborThreshold(clusterNeighborThreshold);
+        stripClusteringAlgo.setClusterThreshold(clusterThreshold);
+
+        // Create the clusterers and set hit-making parameters.
+        stripClusterer = new StripHitMaker(stripSim, stripReadout, stripClusteringAlgo);
+        stripClusterer.setMaxClusterSize(clusterMaxSize);
+        stripClusterer.setCentralStripAveragingThreshold(clusterCentralStripAveragingThreshold);
+
+        // Set the cluster errors.
+        stripClusterer.SetOneClusterErr(oneClusterErr);
+        stripClusterer.SetTwoClusterErr(twoClusterErr);
+        stripClusterer.SetThreeClusterErr(threeClusterErr);
+        stripClusterer.SetFourClusterErr(fourClusterErr);
+        stripClusterer.SetFiveClusterErr(fiveClusterErr);
+
+        // Set the readout to process.
+        readouts.add(readoutCollectionName);
+
+        // Set the detector to process.
+        processPaths.add(subdetectorName);
+    }
+
+    /**
+     * This is executed before detectorChanged and initialization of
+     * digitization objects is done here.
+     */
+    @Override
+    public void startOfData() {
+
+        // At start of job, setup digitization objects needed by this Driver.
+        initialize();
+
+        // If readouts not already set, set them up.
+        if (!readouts.isEmpty()) {
+            System.out.println("Adding SimTrackerHitIdentifierReadoutDriver with readouts: " + readouts);
+            super.add(new SimTrackerHitReadoutDriver(readouts));
+        }
+        super.startOfData();
+        readouts.clear(); // FIXME Is this needed?
+    }
+
+    /**
+     * Do initialization once we get a Detector.
+     */
+    @Override
+    public void detectorChanged(Detector detector) {
+
+        // Call sub-Driver's detectorChanged methods.
+        super.detectorChanged(detector);
+
+        // Process detectors specified by path, otherwise process entire
+        // detector
+        IDetectorElement deDetector = detector.getDetectorElement();
+
+        for (String path : processPaths) {
+            processDEs.add(deDetector.findDetectorElement(path));
+        }
+
+        if (processDEs.isEmpty()) {
+            processDEs.add(deDetector);
+        }
+
+        for (IDetectorElement detectorElement : processDEs) {
+            processSensors.addAll(detectorElement.findDescendants(SiSensor.class));
+            //if (debug)
+            //    System.out.println("added " + processSensors.size() + " sensors");
+            processModules.addAll(detectorElement.findDescendants(SiTrackerModule.class));
+            //if (debug)
+            //    System.out.println("added " + processModules.size() + " modules");
+        }
+    }
+
+    /**
+     * Perform the digitization.
+     */
+    @Override
+    public void process(EventHeader event) {
+        // Call sub-Driver processing.
+        super.process(event);
+
+        // Make new lists for output.
+        List<RawTrackerHit> rawHits = new ArrayList<RawTrackerHit>();
+        List<SiTrackerHit> stripHits1D = new ArrayList<SiTrackerHit>();
+
+        if (event.hasCollection(SimTrackerHit.class, this.readoutCollectionName)) {
+            // Make raw hits.
+            for (SiSensor sensor : processSensors) {
+                rawHits.addAll(stripDigitizer.makeHits(sensor));
+            }
+
+            // Make strip hits.
+            for (SiSensor sensor : processSensors) {
+                stripHits1D.addAll(stripClusterer.makeHits(sensor));
+            }
+
+            // Debug prints.
+            if (debug) {
+                if (event.hasCollection(SimTrackerHit.class, this.readoutCollectionName)) {
+                    List<SimTrackerHit> simHits = event.get(SimTrackerHit.class, this.readoutCollectionName);
+                    System.out.println("SimTrackerHit collection " + this.readoutCollectionName + " has " + simHits.size() + " hits.");
+                    System.out.println("RawTrackerHit collection " + this.rawTrackerHitOutputCollectionName + " has " + rawHits.size() + " hits.");
+                    System.out.println("TrackerHit collection " + this.stripHitOutputCollectionName + " has " + stripHits1D.size() + " hits.");
+                } else {
+                    System.out.println("SimTrackerHit collection " + this.readoutCollectionName + " not found.");
+                }
+            }
+        }
+
+        // Put output hits into collection.
+        int flag = LCIOUtil.bitSet(0, 31, true); // Turn on 64-bit cell ID.
+        event.put(this.rawTrackerHitOutputCollectionName, rawHits, RawTrackerHit.class, flag, toString());
+        event.put(this.stripHitOutputCollectionName, stripHits1D, SiTrackerHitStrip1D.class, 0, toString());
+    }
+}
\ No newline at end of file

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
TrackerHitUtils.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/TrackerHitUtils.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/TrackerHitUtils.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,280 @@
+package org.hps.recon.tracking;
+
+import hep.physics.vec.BasicHep3Matrix;
+import hep.physics.vec.BasicHep3Vector;
+import hep.physics.vec.Hep3Matrix;
+import hep.physics.vec.Hep3Vector;
+import hep.physics.vec.VecOp;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.hps.conditions.deprecated.SvtUtils;
+import org.lcsim.detector.IDetectorElement;
+import org.lcsim.detector.ITransform3D;
+import org.lcsim.detector.identifier.ExpandedIdentifier;
+import org.lcsim.detector.identifier.IExpandedIdentifier;
+import org.lcsim.detector.identifier.IIdentifier;
+import org.lcsim.detector.identifier.IIdentifierDictionary;
+import org.lcsim.detector.identifier.IIdentifierHelper;
+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.SimTrackerHit;
+import org.lcsim.fit.helicaltrack.HelicalTrackFit;
+import org.lcsim.fit.helicaltrack.HelicalTrackStrip;
+import org.lcsim.fit.helicaltrack.HelixUtils;
+
+/**
+ *
+ * @author Per Hansson <[log in to unmask]>
+ * @version $Id: TrackerHitUtils.java,v 1.4 2013/10/15 00:33:53 phansson Exp $
+ */
+public class TrackerHitUtils {
+
+    private boolean _DEBUG = false;
+
+    public TrackerHitUtils() {
+    }
+
+    public TrackerHitUtils(boolean debug) {
+        _DEBUG = debug;
+    }
+
+    public void setDebug(boolean debug) {
+        _DEBUG = debug;
+    }
+
+
+    public Hep3Matrix detToTrackRotationMatrix() {
+        return (BasicHep3Matrix) HPSTransformations.getMatrix();
+    }
+
+    public 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();
+    }
+
+    public Hep3Matrix getStripToTrackRotation(HelicalTrackStrip strip) {
+        //This function transforms the hit to the tracking 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 (_DEBUG) {
+            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(detToTrackMatrix,VecOp.inverse(detToStripMatrix));
+    }
+
+    public 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 = this.GetGlobalToLocal(strip);
+        //Get rotation matrix
+        Hep3Matrix detToStripMatrix = (BasicHep3Matrix) detToStrip.getRotation().getRotationMatrix();
+        //Transformation between the JLAB and tracking coordinate systems
+        Hep3Matrix detToTrackMatrix = this.detToTrackRotationMatrix();
+
+        if (_DEBUG) {
+            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));
+    }
+
+
+
+    public Hep3Vector getClusterPosition(HelicalTrackStrip strip, boolean stripInTrackingFrame) {
+        if(_DEBUG) System.out.println(this.getClass().getSimpleName() + " getClusterPosition--");
+        Hep3Vector origin = stripInTrackingFrame ? strip.origin() : VecOp.mult(HPSTransformations.getMatrix(),strip.origin());
+        if(_DEBUG) System.out.println(this.getClass().getSimpleName() + " origin " + origin.toString());
+        Hep3Vector hit_vec_LOCAL = new BasicHep3Vector(strip.umeas(),0,0);
+        if(_DEBUG) System.out.println(this.getClass().getSimpleName() + " hit_vec_LOCAL " + hit_vec_LOCAL.toString());
+        Hep3Matrix stripToTrack = this.getStripToTrackRotation(strip);
+        if(_DEBUG) System.out.println(this.getClass().getSimpleName() + " stripToTrack " + stripToTrack.toString());
+        Hep3Vector hit_vec_TRACK = VecOp.mult(stripToTrack, hit_vec_LOCAL); 
+        if(_DEBUG) System.out.println(this.getClass().getSimpleName() + " hit_vec_TRACK " + hit_vec_TRACK.toString());
+        Hep3Vector strip_pos = VecOp.add(origin, hit_vec_TRACK);
+        if(_DEBUG) System.out.println(this.getClass().getSimpleName() + " strip_pos " + strip_pos.toString());
+
+        //        Hep3Vector hit_vec_LOCAL_dep = new BasicHep3Vector(strip.umeas(),0,0.16);
+        //        if(_DEBUG) System.out.println(this.getClass().getSimpleName() + " hit_vec_LOCAL_dep " + hit_vec_LOCAL_dep.toString());
+        //        Hep3Vector hit_vec_TRACK_dep = VecOp.mult(stripToTrack, hit_vec_LOCAL_dep); 
+        //        Hep3Vector strip_pos_dep = VecOp.add(origin, hit_vec_TRACK_dep);
+        //        if(_DEBUG) System.out.println(this.getClass().getSimpleName() + " strip_pos ALTERNATE " + strip_pos_dep.toString());
+
+        return strip_pos;
+    }
+
+    public Hep3Vector CalculateStripUncertaintyInGlobalFrame(HelicalTrackStrip strip, HelicalTrackFit trk, double msdrdphi, double msdz) {
+
+        if(_DEBUG) System.out.println("--- CalculateStripUncertainyInGlobalFrame ---");
+        if(_DEBUG) System.out.println("Strip origin = " + strip.origin().toString());
+        Hep3Vector u = strip.u();
+        Hep3Vector v = strip.v();
+        Hep3Vector w = strip.w();
+        Hep3Vector corigin = strip.origin();
+
+        double phi0 = trk.phi0();
+        double R = trk.R();
+        double xint = strip.origin().x();
+        //double xint = this.calculateHelixInterceptXPlane(_trk, strip);
+        double s = HelixUtils.PathToXPlane(trk, xint, 0,0).get(0);
+        double phi = -s/R + phi0;
+        if(_DEBUG) System.out.println("phi0 " + phi0 + " R " + R + " xint " + xint + " s " + s + " phi " + phi);
+        //if(_DEBUG) System.out.println("trkpos = "+trkpos.toString());
+        //if(_DEBUG) System.out.println("origin = "+corigin.toString());
+
+        Hep3Vector mserr = new BasicHep3Vector(msdrdphi * Math.sin(phi), msdrdphi * Math.sin(phi), msdz);
+        if(_DEBUG) System.out.println("msdrdphi = " + msdrdphi + " msdz = " + msdz);
+        if(_DEBUG) System.out.println("mserr = " + mserr.toString());
+        double uHitError = strip.du();
+        double msuError = VecOp.dot(mserr, u);
+        double uError = Math.sqrt(uHitError * uHitError + msuError * msuError);
+        if(_DEBUG) System.out.println("uError = " + uError + "(MS "+msuError  + ",u=" + u.toString()+")");
+        double vHitError = (strip.vmax() - strip.vmin()) / Math.sqrt(12);
+        double msvError = VecOp.dot(mserr, v);
+        double vError = Math.sqrt(vHitError * vHitError + msvError * msvError);
+        if(_DEBUG) System.out.println("vError = " + vError + "(MS "+msvError  + ",v=" + v.toString()+")");
+
+        double wHitError = 10.0/Math.sqrt(12); //0.001;
+        double mswError = VecOp.dot(mserr, w);
+        double wError = Math.sqrt(wHitError * wHitError + mswError * mswError);
+        if(_DEBUG) System.out.println("wError = " + wError + "(MS "+mswError  + ",w=" + w.toString()+")");
+
+        Hep3Vector dq_local = new BasicHep3Vector(uError,vError,wError);
+        if(_DEBUG) System.out.println("dq_local = " + dq_local.toString());
+        Hep3Matrix trackToStripRot = getTrackToStripRotation(strip);
+        if(_DEBUG) System.out.println("trackToStripRot:\n " + trackToStripRot.toString());
+        Hep3Matrix stripToTrackRot = VecOp.inverse(trackToStripRot);
+        if(_DEBUG) System.out.println("stripToTrackRot:\n " + stripToTrackRot.toString());
+        Hep3Vector dq_global = VecOp.mult(stripToTrackRot, dq_local);
+        if(_DEBUG) System.out.println("q_global = " + dq_global.toString());
+        return dq_global;
+    }
+
+    public List<SimTrackerHit> stripClusterToSimHits(HelicalTrackStrip strip, List<SimTrackerHit> simTrackerHits, boolean stripsInTrackingFrame){
+
+        int layer = strip.layer();
+        Hep3Vector stripPosition = this.getClusterPosition(strip,stripsInTrackingFrame);
+
+        // Sort the SimTrackerHits by Layer
+        Map<Integer, List<SimTrackerHit>> layerToSimTrackerHit = new HashMap<Integer, List<SimTrackerHit>>();
+        for(SimTrackerHit simTrackerHit : simTrackerHits){
+            if(!layerToSimTrackerHit.containsKey(simTrackerHit.getLayer()))
+                layerToSimTrackerHit.put(simTrackerHit.getLayer(), new ArrayList<SimTrackerHit>());
+            layerToSimTrackerHit.get(simTrackerHit.getLayer()).add(simTrackerHit);
+        }
+
+        // 
+        List<SimTrackerHit> simhits = new ArrayList<SimTrackerHit>();
+
+        if(layerToSimTrackerHit.get(strip.layer()) == null) {
+            System.out.println(this.getClass().getSimpleName() + ": WARNING there is a strip in layer " + strip.layer() + " but no SimTrackerHits");
+            return simhits;
+        }
+
+        // If there is only a single SimTrackerHit on a layer and it's in the same volume as the
+        // strip hit then they likely match to each other
+        if(layerToSimTrackerHit.get(strip.layer()).size() == 1){
+            Hep3Vector simTrackerHitPosition = layerToSimTrackerHit.get(strip.layer()).get(0).getPositionVec();
+            if(Math.signum(simTrackerHitPosition.y()) == Math.signum(stripPosition.z())){            
+                simhits.add(layerToSimTrackerHit.get(strip.layer()).get(0));
+                layerToSimTrackerHit.remove(strip.layer());
+                if(_DEBUG) {
+                    System.out.println(this.getClass().getSimpleName() + ": SimTrackerHit position: " + simTrackerHitPosition.toString());
+                    System.out.println(this.getClass().getSimpleName() + ": Cluster position: " + stripPosition.toString());
+                }
+            } else {
+                System.out.println(this.getClass().getSimpleName() + ": Cluster and SimTrackerHit are on different volumes");
+            }
+        }
+        else if(layerToSimTrackerHit.get(strip.layer()).size() > 1){
+            if(_DEBUG) System.out.println(this.getClass().getSimpleName() + ": found " + layerToSimTrackerHit.get(strip.layer()).size() + " SimTrackerHits to match to strip in layer " + strip.layer());
+            //System.exit(1);
+            double deltaZ = Double.MAX_VALUE;
+            SimTrackerHit simTrackerHitMatch = null;
+            for(SimTrackerHit simTrackerHit : layerToSimTrackerHit.get(strip.layer())){
+                if(Math.abs(simTrackerHit.getPositionVec().y() - stripPosition.z()) < deltaZ){
+                    deltaZ = Math.abs(simTrackerHit.getPositionVec().y() - stripPosition.z());
+                    simTrackerHitMatch = simTrackerHit;
+                }
+            }
+            simhits.add(simTrackerHitMatch);
+            layerToSimTrackerHit.remove(strip.layer()).remove(simTrackerHitMatch);
+            if(_DEBUG) {
+                System.out.println(this.getClass().getSimpleName() + ": SimTrackerHit position: " + simTrackerHitMatch.getPositionVec().toString());
+                System.out.println(this.getClass().getSimpleName() + ": Cluster position: " + stripPosition);
+            }
+        }
+
+
+
+        return simhits;
+    }
+
+    /**
+     * Make a SimTrackerHit {@link IIdentifier} for a given layer number
+     * 
+     * @param sensor : The sensor on which the SimTrackerHit is created on
+     * @return A 32-bit SimTrackerHit identifier
+     */
+    public static IIdentifier makeSimTrackerHitId(SiSensor sensor){
+
+        // Get the sensors identifier
+        IExpandedIdentifier id = new ExpandedIdentifier(sensor.getExpandedIdentifier());
+
+        // Get the helper and dictionary
+        IIdentifierHelper helper = sensor.getIdentifierHelper();
+        IIdentifierDictionary dictionary = helper.getIdentifierDictionary();
+
+        // Fill in the layer number
+        id.setValue(dictionary.getFieldIndex("layer"), SvtUtils.getInstance().getLayerNumber(sensor));
+
+        // Pack and return the identifier
+        return helper.pack(id);
+
+    }
+
+    //   public List<SiTrackerHit> stripClusterToSiHits(HelicalTrackStrip strip, List<SiTrackerHit> siTrackerHits, boolean stripsInTrackingFrame)
+    //    {
+    //     
+    //        //Should be a one to one match with a strip!
+    //        Hep3Vector stripPosition = this.getClusterPosition(strip,stripsInTrackingFrame);
+    //        if(_DEBUG) System.out.println("Strip position " + stripPosition.toString() + " ( " + strip.origin().toString() + ")");
+    //        
+    //        for(SiTrackerHit siTrackerHit : siTrackerHits){
+    //            SiTrackerHitStrip1D h = (SiTrackerHitStrip1D) siTrackerHit;
+    //            if(_DEBUG) System.out.println("SiTrackerHit origin position " + h.getPositionAsVector().toString());
+    //            
+    //        }
+    //            
+    //        List<SiTrackerHit> hits = new ArrayList<SiTrackerHit>();
+    //        return hits;
+    //          
+    //    }
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
TrackerReconDriver.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/TrackerReconDriver.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/TrackerReconDriver.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,202 @@
+package org.hps.recon.tracking;
+
+import hep.physics.vec.BasicHep3Vector;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.Track;
+import org.lcsim.fit.helicaltrack.HelicalTrackHit;
+import org.lcsim.geometry.Detector;
+import org.lcsim.recon.tracking.digitization.sisim.config.ReadoutCleanupDriver;
+import org.lcsim.recon.tracking.seedtracker.SeedStrategy;
+import org.lcsim.recon.tracking.seedtracker.StrategyXMLUtils;
+import org.lcsim.recon.tracking.seedtracker.diagnostic.SeedTrackerDiagnostics;
+import org.lcsim.util.Driver;
+
+/**
+ * This class runs the Track Reconstruction for the HPS Test Proposal detector.
+ * The tracker digitization must be run in front of it. It is intended to work
+ * with the {@link TrackerDigiDriver} digitization Driver.
+ *
+ * @author jeremym
+ * @version $Id: TrackerReconDriver.java,v 1.18 2012/05/03 20:50:29 mgraham Exp
+ * $
+ */
+public final class TrackerReconDriver extends Driver {
+
+    // Debug flag.
+    private boolean debug = false;
+    // Tracks found across all events.
+    int ntracks = 0;
+    // Number of events processed.
+    int nevents = 0;
+    // Cache detector object.
+    Detector detector = null;
+    // Default B-field value.
+    private double bfield = 0.5;
+    // TrackerHit readout name for readout cleanup.
+    private String trackerReadoutName = "TrackerHits";
+    // Tracking strategies resource path.
+    private String strategyResource = "HPS-Test-4pt1.xml";
+    // Output track collection.
+    private String trackCollectionName = "MatchedTracks";
+    // HelicalTrackHit input collection.
+    private String stInputCollectionName = "RotatedHelicalTrackHits";
+    // Include MS (done by removing XPlanes from the material manager results)
+    private boolean includeMS = true;
+    // number of repetitive fits on confirmed/extended tracks
+    private int _iterativeConfirmed = 3;
+    // use HPS implementation of material manager
+    private boolean _useHPSMaterialManager = true;
+    // enable the use of sectoring using sector binning in SeedTracker
+    private boolean _applySectorBinning = true;
+    
+    public TrackerReconDriver() {
+    }
+
+    public void setDebug(boolean debug) {
+        this.debug = debug;
+    }
+
+    /**
+     * Set the tracking strategy resource.
+     *
+     * @param strategyResource The absolute path to the strategy resource in the
+     * hps-java jar.
+     */
+    public void setStrategyResource(String strategyResource) {
+        this.strategyResource = strategyResource;
+    }
+
+    public void setInputHitCollectionName(String inputHitCollectionName) {
+        this.stInputCollectionName = inputHitCollectionName;
+    }
+
+    public void setTrackCollectionName(String trackCollectionName) {
+        this.trackCollectionName = trackCollectionName;
+    }
+
+    public void setIncludeMS(boolean incMS) {
+        this.includeMS = incMS;
+    }
+    
+     /**
+     * Set to enable the use of the HPS material manager implementation 
+     * 
+     * @param useHPSMaterialManager switch
+     */
+    public void setUseHPSMaterialManager(boolean useHPSMaterialManager) {
+        this._useHPSMaterialManager = useHPSMaterialManager;
+    }
+    
+    public void setIterativeFits(int val) {
+        this._iterativeConfirmed = val;
+    }
+    
+     /**
+     * Set to enable the sectoring to use the sector bins in checking for consistent hits.
+     *
+     * @param applySectorBinning apply sector binning switch
+     */
+    public void setApplySectorBinning(boolean applySectorBinning) {
+        this._applySectorBinning = applySectorBinning;
+    }
+   
+    /**
+     * This is used to setup the Drivers after XML config.
+     */
+    @Override
+    public void detectorChanged(Detector detector) {
+        // Cache Detector object.
+        this.detector = detector;
+
+        // Get B-field Y with no sign. Seed Tracker doesn't like signed B-field components.
+        // FIXME Is this always right?
+        this.bfield = Math.abs((detector.getFieldMap().getField(new BasicHep3Vector(0, 0, 0)).y()));
+        if (debug) {
+            System.out.printf("%s: Set B-field to %.3f\n",this.getClass().getSimpleName(),this.bfield);
+        }
+
+        initialize();
+
+        super.detectorChanged(detector);
+    }
+
+    /**
+     * Setup all the child Drivers necessary for track reconstruction.
+     */
+    private void initialize() {
+
+        //
+        // 1) Driver to run Seed Tracker.
+        //
+
+        if (!strategyResource.startsWith("/")) {
+            strategyResource = "/org/lcsim/hps/recon/tracking/strategies/" + strategyResource;
+        }
+        List<SeedStrategy> sFinallist = StrategyXMLUtils.getStrategyListFromInputStream(this.getClass().getResourceAsStream(strategyResource));
+        SeedTracker stFinal = new SeedTracker(sFinallist,this._useHPSMaterialManager,this.includeMS);
+        stFinal.setApplySectorBinning(_applySectorBinning);
+        stFinal.setUseDefaultXPlane(false);
+        stFinal.setDebug(this.debug);
+        stFinal.setIterativeConfirmed(_iterativeConfirmed);
+        stFinal.setMaterialManagerTransform(HPSTransformations.getTransform());
+        stFinal.setInputCollectionName(stInputCollectionName);
+        stFinal.setTrkCollectionName(trackCollectionName);
+        stFinal.setBField(bfield);
+        stFinal.setDiagnostics(new SeedTrackerDiagnostics());
+//        stFinal.setSectorParams(false); //this doesn't actually seem to do anything
+        stFinal.setSectorParams(1, 10000);
+        add(stFinal);
+
+        //
+        // 2) Cleanup the readouts for next event.
+        //
+        add(new ReadoutCleanupDriver(Arrays.asList(this.trackerReadoutName)));
+    }
+
+    /**
+     * This method is used to run the reconstruction and print debug
+     * information.
+     */
+    @Override
+    public void process(EventHeader event) {
+        // This call runs the track reconstruction using the sub-Drivers.
+        super.process(event);
+
+        // Debug printouts.
+        if (debug) {
+            if(event.hasCollection(HelicalTrackHit.class,stInputCollectionName)) {
+                System.out.println(this.getClass().getSimpleName() + ": The HelicalTrackHit collection " + stInputCollectionName + " has " + event.get(HelicalTrackHit.class, stInputCollectionName).size() + " hits.");
+            } else {
+                System.out.println(this.getClass().getSimpleName() + ": No HelicalTrackHit collection for this event");
+            }
+            // Check for Tracks.
+            List<Track> tracks = event.get(Track.class, trackCollectionName);
+            System.out.println(this.getClass().getSimpleName() + ": The Track collection " + trackCollectionName + " has " + tracks.size() + " tracks.");
+
+            // Print out track info.
+            for (Track track : tracks) {
+                System.out.println(this.getClass().getSimpleName() + ": " + track.toString());
+                System.out.println(this.getClass().getSimpleName() + ": number of layers = " + track.getTrackerHits().size());
+                System.out.println(this.getClass().getSimpleName() + ": chi2 = " + track.getChi2());
+            }
+        }
+
+        // Increment number of events.
+        ++nevents;
+
+        // Add to tracks found.
+        ntracks += event.get(Track.class, trackCollectionName).size();
+    }
+
+    @Override
+    public void endOfData() {
+        if (debug) {
+            System.out.println("-------------------------------------------");
+            System.out.println(this.getName() + " found " + ntracks + " tracks in " + nevents + " events which is " + ((double) ntracks / (double) nevents) + " tracks per event.");
+        }
+    }
+}
\ No newline at end of file

java/sandbox/tracking/src/main/java/org/hps/recon/tracking
WTrack.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/WTrack.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/WTrack.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,338 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.hps.recon.tracking;
+
+import hep.physics.vec.BasicHep3Vector;
+import hep.physics.vec.Hep3Vector;
+import hep.physics.vec.VecOp;
+
+import org.lcsim.constants.Constants;
+import org.lcsim.fit.helicaltrack.HelicalTrackFit;
+
+/**
+ *
+ * @author phansson
+ */
+public class WTrack {
+
+    private boolean _debug = false;
+    public enum PARAM{TEST;}
+    private double[] _parameters = new double[7];
+    public HelicalTrackFit _htf = null;
+    private double _bfield;
+    private double _a;
+    
+    static int max_iterations_intercept = 10;
+    static double epsilon_intercept = 1e-4;
+    
+    public WTrack(WTrack trk) {
+        _bfield = trk._bfield;
+        _a = trk._a;
+        _parameters = trk._parameters;
+        _htf = trk._htf;
+        _debug = trk._debug;
+    }
+    
+    public WTrack(HelicalTrackFit track, double bfield) {
+        initWithTrack(track, bfield, false);
+    }
+    
+    public WTrack(HelicalTrackFit track, double bfield, boolean flip) {
+        initWithTrack(track, bfield, flip);
+    }
+    public void initWithTrack(HelicalTrackFit track, double bfield, boolean flip) {
+        _htf = track;
+        _bfield = flip ? -1.0*bfield : bfield; // flip if needed
+        _a = -1*Constants.fieldConversion*_bfield*Math.signum(track.R());
+        double p = track.p(Math.abs(_bfield));
+        double theta = Math.PI/2.0 - Math.atan(track.slope());
+        double phi = track.phi0();
+        _parameters[0] = p*Math.cos(phi)*Math.sin(theta);
+        _parameters[1] = p*Math.sin(phi)*Math.sin(theta);
+        _parameters[2] = p*Math.cos(theta); 
+        _parameters[3] = Math.sqrt(_parameters[0]*_parameters[0]+_parameters[1]*_parameters[1]+_parameters[2]*_parameters[2]);
+        _parameters[4] = -1*track.dca()*Math.sin(phi); //x0
+        _parameters[5] = track.dca()*Math.cos(phi); //y0
+        _parameters[6] = track.z0(); //z0
+        if(_debug) {
+            System.out.printf("%s: WTrack initialized (p=%f,bfield=%f,theta=%f,phi=%f) from HelicalTrackFit:\n%s:%s\n",this.getClass().getSimpleName(),
+                    p,_bfield,theta,phi,
+                    this.getClass().getSimpleName(),this.toString());
+        }
+    }
+    public void setTrackParameters(double [] params) {
+        _parameters = params;
+    }
+    
+    public double[] getParameters() {
+        return _parameters;
+    }
+    
+    private boolean goingForward() {
+        // assuming the track should go in the x-direction --> not very general -> FIX THIS!?
+        return getP0().x()>0 ? true : false;
+    }
+    
+    
+    public double a() {
+        return _a;
+
+    }
+    
+    private int getCharge() {
+        return (int) Math.signum(_htf.R());
+    }
+    
+    public Hep3Vector getP0() {
+        return ( new BasicHep3Vector(_parameters[0],_parameters[1],_parameters[2]));
+    }
+    
+    public Hep3Vector getX0() {
+        return ( new BasicHep3Vector(_parameters[4],_parameters[5],_parameters[6]));
+    }
+        
+    public String paramsToString() {
+        String str = "";
+        for(int i=0;i<7;++i) str += _parameters[i] + ", ";
+        return str;
+    }
+    public String toString() {
+        
+        String str = "WTrack params [" + paramsToString() + "]";
+        if(this._htf!=null) {
+            str += "\n with corresponding HelicalTrackFit:\n";
+            str += this._htf.toString(); 
+        }
+       return str;
+    }
+    
+    
+    
+    
+    
+    
+     private Hep3Vector getMomentumOnHelix(double s) {
+        WTrack track = this;
+        double a = track.a();
+        Hep3Vector p0 = track.getP0();
+        double rho = a / p0.magnitude();
+        double px = p0.x()*Math.cos(rho*s) - p0.y()*Math.sin(rho*s);
+        double py = p0.y()*Math.cos(rho*s) + p0.x()*Math.sin(rho*s);
+        double pz = p0.z(); 
+        return (new BasicHep3Vector(px,py,pz));
+    }
+    
+    private Hep3Vector getPointOnHelix(double s) {
+        WTrack track = this;
+        double a = track.a();
+        Hep3Vector p0 = track.getP0();
+        Hep3Vector x0 = track.getX0();
+        double rho = a / p0.magnitude();
+        double x = x0.x() + p0.x()/a*Math.sin(rho*s) - p0.y()/a*(1-Math.cos(rho*s));
+        double y = x0.y() + p0.y()/a*Math.sin(rho*s) + p0.x()/a*(1-Math.cos(rho*s));
+        double z = x0.z() + p0.z()/p0.magnitude()*s;
+        return (new BasicHep3Vector(x,y,z));
+    }
+    
+    private double getPathLengthToPlaneApprox(Hep3Vector xp, Hep3Vector eta, Hep3Vector h) {
+        /*
+         * Find the approximate path length to the point xp 
+         * in arbitrary oriented, constant magnetic field with unit vector h
+         */
+        WTrack track = this;
+        double a = track.a();
+        Hep3Vector p0 = track.getP0();
+        Hep3Vector x0 = track.getX0();
+        double p = p0.magnitude();
+        double rho = a / p;
+        double A = VecOp.dot(eta,VecOp.cross(p0, h))/p*0.5*rho;
+        double B = VecOp.dot(p0,eta)/p;
+        double C = VecOp.dot(VecOp.sub(x0,xp),eta);
+        double t = B*B-4*A*C;
+        if(t<0) {
+            System.out.println(" getPathLengthToPlaneApprox ERROR t is negative (" + t + ")!" );
+            System.out.println(" p " + p + " rho " + rho + " a " + a + " A " + A + " B " + B + " C " + C);
+            System.out.println(" track params: " + track.paramsToString());
+            System.out.println(" xp " + xp.toString());
+            System.out.println(" eta " + eta.toString());
+            System.out.println(" h " + h.toString());
+            System.exit(1);
+        }
+        double root1 = (-B + Math.sqrt(t)) /(2*A);
+        double root2 = (-B - Math.sqrt(t)) /(2*A);
+
+        // choose the smallest positive solution
+        // if both negative choose the smallest negative ???
+        //if(root1==0 || root2==0) root=0;
+        double root = Math.abs(root1) <= Math.abs(root2) ? root1 : root2;
+//        else if(Math.signum(root1)>0 && Math.signum(root2)<0) root = root1;
+//        else if(Math.signum(root2)>0 && Math.signum(root1)<0) root = root2;
+//        else if(Math.signum(root1)>0 && Math.signum(root2)>0) root =  root1 > root2 ? root2 : root1;
+//        else if(Math.signum(root1)<0 && Math.signum(root2)<0) root =  root1 < root2 ? root2 : root1;
+//        else {
+//            System.out.println(" I should never get here! (root1=" + root1 + " root2=" + root2+")");
+//            System.exit(1);
+//        }
+        if(_debug) {
+                System.out.println(" getPathLengthToPlaneApprox ");
+                System.out.println(" " + track.paramsToString());
+                System.out.println(" xp " + xp.toString());
+                System.out.println(" eta " + eta.toString());
+                System.out.println(" h " + h.toString());
+                System.out.println(" p " + p + " rho " + rho + " t " + t + " A " + A + " B " + B + " C " + C);
+                System.out.println(" root1 " + root1 + " root2 " + root2 + " -> root " + root);
+        }
+        return root;
+    
+    }
+    
+    
+    private Hep3Vector getPointOnHelix(double s, Hep3Vector h) {
+        /*
+         * Get point on helix at path lenght s 
+         * in arbitrary oriented, constant magnetic field with unit vector h
+         */
+        WTrack track = this;
+        double a = track.a();
+        Hep3Vector p0 = track.getP0();
+        double p = p0.magnitude();
+        Hep3Vector x0 = track.getX0();
+        double rho = a / p0.magnitude();
+        double srho = s*rho;
+        Hep3Vector a1 = VecOp.mult(1/a*Math.sin(srho), p0);
+        Hep3Vector a2 = VecOp.mult(1/a*(1-Math.cos(srho)),VecOp.cross(p0,h));
+        Hep3Vector a3 = VecOp.mult(VecOp.dot(p0, h)/p,h);
+        Hep3Vector a4 = VecOp.mult(s-Math.sin(srho)/rho, a3);
+        Hep3Vector x = VecOp.add(x0,a1);
+        x = VecOp.sub(x,a2);
+        x = VecOp.add(x,a4);
+        return x;
+    }
+    
+    private Hep3Vector getMomentumOnHelix(double s, Hep3Vector h) {
+        /*
+         * Get point on helix at path lenght s 
+         * in arbitrary oriented, constant magnetic field with unit vector h
+         */
+        WTrack track = this;
+        double a = track.a();
+        Hep3Vector p0 = track.getP0();
+        double rho = a / p0.magnitude();
+        double srho = s*rho;
+        Hep3Vector a1 = VecOp.mult(Math.cos(srho), p0);
+        Hep3Vector a2 = VecOp.cross(p0, VecOp.mult(Math.sin(srho),h));
+        Hep3Vector a3 = VecOp.mult(VecOp.dot(p0,h),VecOp.mult(1-Math.cos(srho),h));
+        Hep3Vector p  = VecOp.sub(a1,a2);
+        p = VecOp.add(p,a3);
+        return p;
+    }
+    
+    
+    private double[] getHelixParametersAtPathLength(double s, Hep3Vector h) {
+        /*
+         * Calculate the exact position of the new helix parameters at path length s
+         * in an arbitrarily oriented, constant magnetic field
+         * 
+         * point xp is the point 
+         * h is a unit vector in the direction of the magnetic field
+         */
+        
+        // Find track parameters at that path length
+        Hep3Vector p = getMomentumOnHelix(s, h);
+        Hep3Vector x = getPointOnHelix(s, h);
+        
+        Hep3Vector p_tmp = getMomentumOnHelix(s);
+        Hep3Vector x_tmp = getPointOnHelix(s);
+        
+        if(_debug) {
+            System.out.println(" point on helix at s");
+            System.out.println(" p  " + p.toString() + "   p_tmp " + p_tmp.toString());
+            System.out.println(" x  " + x.toString() + "   x_tmp " + x_tmp.toString());
+        }
+        
+        
+        //Create the new parameter array
+        double [] pars = new double[7];
+        pars[0] = p.x();
+        pars[1] = p.y();
+        pars[2] = p.z();
+        pars[3] = getParameters()[3]; //E is unchanged
+        pars[4] = x.x();
+        pars[5] = x.y();
+        pars[6] = x.z();
+        return pars;
+    }
+    
+    
+    public Hep3Vector getHelixAndPlaneIntercept(Hep3Vector xp, Hep3Vector eta, Hep3Vector h) {
+    
+        /*
+         * Find the interception point between the helix and plane
+         * xp: point on the plane
+         * eta: unit vector of the plane
+         * h: unit vector of magnetic field
+         */
+        
+        
+        int iteration = 1;
+        double s_total = 0.;
+        double step = 9999999.9;
+        //List<WTrack> tracks = new ArrayList<WTrack>();
+        WTrack trk = this;
+        while(iteration<=max_iterations_intercept && Math.abs(step)>epsilon_intercept) {
+            
+            if(_debug) {
+                System.out.printf("%s: Iteration %d\n", this.getClass().getSimpleName(),iteration);
+                System.out.printf("%s: s_total %f prev_step %.3f current trk params: %s \n",
+                                        this.getClass().getSimpleName(),s_total,step,trk.paramsToString());
+            }
+            
+            // check that the track is not looping
+            
+            if(trk.goingForward()) {
+                
+
+                // Start by approximating the path length to the point
+                step = getPathLengthToPlaneApprox(xp, eta, h);
+
+                if(_debug) System.out.printf("%s: path length step s=%.3f\n",this.getClass().getSimpleName(),step);
+
+                // Find the track parameters at this point
+                double[] params = getHelixParametersAtPathLength(step, h);
+
+                // update the track parameters           
+                trk.setTrackParameters(params);
+
+                if(_debug) System.out.printf("%s: updated track params: [%s]\n",this.getClass().getSimpleName(),trk.paramsToString());
+
+                //tracks.add(trk);
+                iteration++;
+                s_total += step;
+
+                //Save distance between point and estimate
+                //Hep3Vector dpoint = VecOp.sub(xp, trk.getX0());
+            
+            } else {
+                //if(_debug) 
+                    System.out.printf("%s: this track started to go backwards?! params [%s]\n",this.getClass().getSimpleName(),trk.toString());
+                return null;
+            }
+            
+            
+        }
+        
+        if(_debug) System.out.printf("%s: final total_s=%f with final step %f after %d iterations gave track params: %s\n",
+                                        this.getClass().getSimpleName(),s_total,step,iteration,trk.paramsToString());
+        
+        return trk.getX0();
+    
+    }
+    
+   
+    
+  
+    
+    
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking/apv25
Apv25AnalogData.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/apv25/Apv25AnalogData.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/apv25/Apv25AnalogData.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,123 @@
+package org.hps.recon.tracking.apv25;
+
+//--- org.lcsim ---//
+import org.lcsim.detector.tracker.silicon.SiSensor;
+
+/**
+ * 
+ * @author Omar Moreno <[log in to unmask]>
+ * @version $Id: Apv25AnalogData.java,v 1.3 2012/08/17 01:17:08 omoreno Exp $ 
+ */
+public class Apv25AnalogData {
+    
+    private SiSensor sensor = null;
+    private int apv25;
+    
+    // APV25 output stream
+    private double[] apv25AnalogOutput = new double[140];
+    private double[] header = {4.0, 4.0, 4.0};
+    private double[] address = {-4.0, -4.0, -4.0, -4.0, -4.0, -4.0, -4.0, -4.0};
+    private double   error = 4.0;
+    private double[] samples = new double[128];
+    
+    /**
+     * Default Ctor
+     */
+    public Apv25AnalogData(){
+        
+
+
+        // Copy the header, address, error and samples
+        System.arraycopy(header, 0, apv25AnalogOutput, 0, header.length);
+        System.arraycopy(address, 0, apv25AnalogOutput, 3, address.length);
+        apv25AnalogOutput[11] = error;
+        
+        // Create the array which will contain the output.  The array values will range
+        // from -4 microAmps to 4 microAmps
+        for(int index = 12; index < apv25AnalogOutput.length; index++){
+            apv25AnalogOutput[index] = -4.0; // microAmps
+        }
+    }
+    
+    /**
+     * 
+     */
+    public Apv25AnalogData(SiSensor sensor, int apv25){
+        this();
+        
+        // Set the sensor and APV number associated with this data
+        this.sensor = sensor;
+        this.apv25 = apv25;
+    }
+    
+    /**
+     * 
+     */
+    public void setChannelData(int channel, double data){
+        apv25AnalogOutput[12 + channel] += data;
+    }
+    
+    /**
+     * 
+     */
+    public void setSensor(SiSensor sensor){
+        this.sensor = sensor;
+    }
+    
+    /**
+     * 
+     */
+    public void setApv(int apv25){
+        this.apv25 = apv25;
+    }
+    
+    /**
+     * 
+     */
+    public double[] getHeader(){
+        return header;
+    }
+    
+    /**
+     * 
+     */
+    public double[] getAddress(){
+        return address;
+    }
+    
+    /**
+     * 
+     */
+    public double getErrorBit(){
+        return error;
+    }
+    
+    /**
+     * 
+     */
+    public double[] getSamples(){
+        System.arraycopy(apv25AnalogOutput, 12, samples, 0, samples.length);
+        return samples;
+    }
+    
+    /**
+     * 
+     */
+    public double[] getApv25AnalogOutput(){
+        return this.apv25AnalogOutput;
+    }
+    
+    /**
+     * 
+     */
+    public SiSensor getSensor(){
+        return this.sensor;
+    }
+    
+    /**
+     * 
+     */
+    public int getApvNumber(){
+        return this.apv25;
+    }
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking/apv25
Apv25DigitalData.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/apv25/Apv25DigitalData.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/apv25/Apv25DigitalData.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,92 @@
+package org.hps.recon.tracking.apv25;
+
+//--- org.lcsim ---//
+import org.lcsim.detector.tracker.silicon.SiSensor;
+
+/**
+ * 
+ * @author Omar Moreno <[log in to unmask]>
+ * @version $Id: Apv25DigitalData.java,v 1.3 2012/08/17 01:17:08 omoreno Exp $  
+ */
+public class Apv25DigitalData {
+    
+    // TODO: Add ability to associate the analog data to a SiSensor and APV25
+    private SiSensor sensor = null;
+    private int apv25;
+    
+    // APV25 output stream
+    private double[] apv25DigitalOutput = new double[140];
+    private double[] header = new double[3];
+    private double[] address = new double[8];
+    private double   error;
+    private double[] samples = new double[128];
+    
+    /**
+     * Default Ctor
+     */
+    public Apv25DigitalData(SiSensor sensor, int apv25, double[] apv25DigitalOutput){
+        
+        // Check if the output format is valid
+        if(apv25DigitalOutput.length != this.apv25DigitalOutput.length) 
+            throw new RuntimeException("APV25 output format is invalid!");
+        
+        System.arraycopy(apv25DigitalOutput, 0, this.apv25DigitalOutput, 0, apv25DigitalOutput.length);
+        System.arraycopy(apv25DigitalOutput, 0, header, 0, header.length);
+        System.arraycopy(apv25DigitalOutput, 3, address, 0, address.length);
+        error   = apv25DigitalOutput[11];
+        System.arraycopy(apv25DigitalOutput, 12, samples, 0, samples.length);
+        
+        // Set the sensor and APV number associated with this data
+        this.sensor = sensor;
+        this.apv25 = apv25;
+    }
+    
+    /**
+     * 
+     */
+    public double[] getHeader(){
+        return header;
+    }
+    
+    /**
+     * 
+     */
+    public double[] getAddress(){
+        return address;
+    }
+    
+    /**
+     * 
+     */
+    public double getErrorBit(){
+        return error;
+    }
+    
+    /**
+     * 
+     */
+    public double[] getSamples(){
+        return samples;
+    }
+    
+    /**
+     * 
+     */
+    public double[] getApv25DigitalOutput(){
+        return apv25DigitalOutput;
+    }
+    
+    /**
+     * 
+     */
+    public SiSensor getSensor(){
+        return this.sensor;
+    }
+    
+    /**
+     * 
+     */
+    public int getApv(){
+        return this.apv25;
+    }
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking/apv25
Apv25Full.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/apv25/Apv25Full.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/apv25/Apv25Full.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,290 @@
+package org.hps.recon.tracking.apv25;
+
+//--- Constants ---//
+import org.hps.conditions.deprecated.HPSSVTConstants;
+//--- hps-java ---//
+import org.lcsim.hps.util.ClockSingleton;
+import org.lcsim.hps.util.RingBuffer;
+
+/**
+ * 
+ * @author Omar Moreno <[log in to unmask]>
+ * @version $Id: Apv25Full.java,v 1.9 2013/04/25 22:11:14 meeg Exp $
+ */
+public class Apv25Full {
+    
+    // APV25 trigger bit
+    public static boolean readoutBit = false;
+    protected int triggerLatency = 0;	// Clock cycles
+    protected int triggerLatencyTime = 240; // ns
+    
+    // APV25 Channels; An APV25 Readout Chip contains a total of 128 channels
+    private Apv25Channel[] channels = new Apv25Channel[HPSSVTConstants.CHANNELS];
+  
+    /**
+     * Default Ctor
+     */
+    public Apv25Full(){
+        
+        // Instantiate all APV25 channels
+        for(int channelN = 0; channelN < HPSSVTConstants.CHANNELS; channelN++){
+            channels[channelN] = new Apv25Channel();
+        }
+        // Set the trigger latency
+        this.setLatency(triggerLatencyTime);
+    }
+    
+    /**
+     * 
+     */
+    public void setLatency(int triggerLatencyTime /*ns*/){
+        this.triggerLatency = (int) Math.floor(triggerLatencyTime/HPSSVTConstants.SAMPLING_INTERVAL);
+        for(int channelN = 0; channelN < HPSSVTConstants.CHANNELS; channelN++) channels[channelN].getPipeline().resetPointerPositions();
+    }
+    
+    /**
+     * Return an instance of an APV25 channel
+     * 
+     * @param channel: APV25 channel of interest (0-127)
+     * @return an instance of an Apv25Channel
+     */
+    public Apv25Channel getChannel(int channel){
+        if(channel >= HPSSVTConstants.CHANNELS) throw new RuntimeException();
+        return channels[channel];
+    }
+    
+    /**
+     * Inject charge into a channel and shape the signal.  The resulting 
+     * shaper signal is then sampled into the analog pipeline
+     * 
+     * @param charge   : Total charge being injected
+     * @param pipeline : Analog pipeline associated with a channel
+     */
+    public void injectCharge(int channel, double charge) {
+        
+        	// Shape the injected charge
+            this.getChannel(channel).shapeSignal(charge);
+
+            // Sample the resulting shaper signal
+            this.getChannel(channel).sampleShaperSignal();
+    }
+    
+    /**
+     * 
+     */
+    public void incrementPointerPositions(){
+        for(int channel = 0; channel < channels.length; channel++){
+            channels[channel].pipeline.step();
+        }
+    }
+    
+    /**
+     * 
+     */
+    public Apv25AnalogData readOut(){
+        
+        Apv25AnalogData data = new Apv25AnalogData();
+        for(int channel = 0; channel < HPSSVTConstants.CHANNELS; channel++){
+            
+            // Only readout the channel if the channel isn't bad
+            if(!this.getChannel(channel).isBadChannel()){
+                // Readout the value stored in the buffer
+                double sample = (this.getChannel(channel).getPipeline().readout()/HPSSVTConstants.FRONT_END_GAIN)*HPSSVTConstants.MULTIPLEXER_GAIN;
+                data.setChannelData(channel, sample);
+            }
+        }
+        return data;
+    }
+    
+    //------------------------------------------//
+    //               APV25 Channel              //
+    //------------------------------------------//
+    public class Apv25Channel {
+        
+        private Apv25ShaperSignal shaperSignal;
+        private Apv25Pipeline pipeline = new Apv25Pipeline();
+        
+        private double shapingTime = 50; // [ns]
+        boolean badChannel = false;
+        
+        /**
+         * Default Constructor
+         */
+        public Apv25Channel(){
+        }
+        
+        /**
+         * Set the shaping time
+         * 
+         * @param shapingTime : APV25 shaping time. The default Tp is set to 50 ns.
+         */
+        public void setShapingTime(double shapingTime) {
+            this.shapingTime = shapingTime;
+        }
+        
+        /**
+         * 
+         */
+        public void markAsBadChannel(){
+            badChannel = true;
+        }
+        
+        /**
+         * 
+         */
+        public boolean isBadChannel(){
+            return badChannel;
+        }
+        
+        /**
+         * 
+         */
+        public Apv25Pipeline getPipeline(){
+        	return pipeline;
+        }
+                
+        /**
+         * Shape the injected charge
+         * 
+         * @param charge 
+         */
+        public void shapeSignal(double charge){
+            shaperSignal = new Apv25ShaperSignal(charge);
+        }
+        
+        /**
+         *
+         */
+        public void sampleShaperSignal(){
+            
+            // Obtain the beam time
+            double beamTime = ClockSingleton.getTime();
+            
+            // Fill the analog pipeline starting with the cell to which the writer pointer is pointing 
+            // to. Signals arriving within the same bucket of length <samplingTime> will be shifted in
+            // time depending on when they arrive.
+            for(int cell = 0; cell < HPSSVTConstants.ANALOG_PIPELINE_LENGTH; cell++){
+                
+                // Time at which the shaper signal will be sampled
+            	int sampleTime = cell*((int) HPSSVTConstants.SAMPLING_INTERVAL) - (int) (beamTime%HPSSVTConstants.SAMPLING_INTERVAL);
+                
+                // Sample the shaper signal
+                double sample = shaperSignal.getAmplitudeAtTime(sampleTime, shapingTime);
+                
+                // Add the value to the pipeline
+                pipeline.addToCell(cell, sample);
+            }
+        }
+    }
+    
+    //-------------------------------------//
+    //       APV25 Analog Pipeline         //
+    //-------------------------------------//
+    public class Apv25Pipeline extends RingBuffer {
+
+        // TODO: Possibly store the pipeline in the event
+        
+        // Note: ptr gives the position of the trigger pointer
+        private int writerPointer = 0;
+        
+        /**
+         * Constructor
+         */
+        public Apv25Pipeline(){
+             
+            // Initialize the pipeline to the APV25 pipeline length
+            super(HPSSVTConstants.ANALOG_PIPELINE_LENGTH);
+            
+            // Initialize the position of the trigger pointer to a random position
+            this.ptr = (int) (Math.random()*HPSSVTConstants.ANALOG_PIPELINE_LENGTH);
+        }        
+        
+        /**
+         * 
+         */
+        public void resetPointerPositions(){
+        	writerPointer = (ptr + triggerLatency)%HPSSVTConstants.ANALOG_PIPELINE_LENGTH;
+        }
+        
+        /**
+         * 
+         */
+        @Override
+        public void addToCell(int position, double element){
+            int writePosition = (writerPointer + position)%HPSSVTConstants.ANALOG_PIPELINE_LENGTH;
+            if(writePosition == this.ptr) return;
+            array[writePosition] += element;
+        }
+        
+        /**
+         * 
+         */
+        public double readout(){
+            double triggerPointerValue = this.currentValue();
+            array[ptr] = 0;
+            return triggerPointerValue;
+        }
+        
+        /**
+         * 
+         */
+        @Override
+        public void step(){
+            super.step();
+            writerPointer = (ptr + triggerLatency)%HPSSVTConstants.ANALOG_PIPELINE_LENGTH;
+        }
+        
+        /**
+         * 
+         */
+        @Override
+        public String toString(){
+            String analogPipeline = "[ ";
+            for(int element = 0; element < HPSSVTConstants.ANALOG_PIPELINE_LENGTH; element++){
+                if(element == ptr) analogPipeline += " TP ===>";
+                else if(element == writerPointer) analogPipeline += " WP ===>";
+                analogPipeline += (array[element] + ", ");
+            }
+            analogPipeline += "] ";
+            return analogPipeline;
+        }
+        
+        /**
+         * 
+         */
+        public double getWriterPointerValue(){
+        	return array[writerPointer];
+        }
+    }
+
+    //-----------------------------------//
+    //        APV25 Shaper Signal        //
+    //-----------------------------------//
+    public class Apv25ShaperSignal {
+
+        // Shaper signal maximum amplitude
+        private double maxAmp = 0;
+
+        /**
+         * Constructor
+         * 
+         * @param charge: Charge injected into a channel
+         */
+        Apv25ShaperSignal(double charge) {
+            // Find the maximum amplitude of the shaper signal
+            maxAmp = (charge/HPSSVTConstants.MIP)*HPSSVTConstants.FRONT_END_GAIN;  // mV
+        }
+
+        /**
+         * Get the amplitude at a time t
+         * 
+         * @param time: time at which the shaper signal is to be sampled
+         */
+        public double getAmplitudeAtTime(double time, double shapingTime) {
+            return maxAmp * (Math.max(0, time) / shapingTime) * Math.exp(1 - (time / shapingTime));
+        }
+
+    }
+    
+
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking/apv25
DataProcessingModule.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/apv25/DataProcessingModule.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/apv25/DataProcessingModule.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,117 @@
+package org.hps.recon.tracking.apv25;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.hps.conditions.deprecated.SvtUtils;
+import org.lcsim.detector.tracker.silicon.SiSensor;
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.RawTrackerHit;
+import org.lcsim.geometry.Detector;
+import org.lcsim.util.Driver;
+/**
+ * 
+ * @author Omar Moreno
+ * @version $Id: DataProcessingModule.java,v 1.1 2013/03/15 21:05:28 meeg Exp $
+ */
+public abstract class DataProcessingModule extends Driver{
+
+    Map<SiSensor, SvtDataBlocks> sensorToDataBlocks = new HashMap<SiSensor, SvtDataBlocks>();
+	
+	// Collection Names
+    String apv25DigitalDataCollectionName = "AVP25DigitalData";
+    String rawTrackerHitsCollectionName = "SVTRawTrackerHits";
+    
+    int nSamples = 0;  // Number of samples which have been processed
+    int totalSamples = 6; // Number of samples which are read out
+    
+    /**
+     * Set the number of shaper signal samples to be readout
+     */
+    public void setNumberOfSamplesToReadOut(int totalSamples){
+    	this.totalSamples = totalSamples;
+    }
+    
+    protected abstract List<RawTrackerHit> findRawHits();
+	
+    @Override
+    public void detectorChanged(Detector detector){
+        for(SiSensor sensor : SvtUtils.getInstance().getSensors()){
+            sensorToDataBlocks.put(sensor, new SvtDataBlocks());
+        }
+    }
+    
+	@Override
+	public void process(EventHeader event){
+		
+		// If the event does not contain any data to process, skip it
+		if(!event.hasCollection(Apv25DigitalData.class, apv25DigitalDataCollectionName)) return;
+		
+		// Get the digital data from the event
+		List<Apv25DigitalData> digitalData = event.get(Apv25DigitalData.class, apv25DigitalDataCollectionName);
+		
+		// Block the data together
+		for(Apv25DigitalData digitalDatum : digitalData){
+			SiSensor sensor = digitalDatum.getSensor();
+            int apvN = digitalDatum.getApv();
+
+            double[] apv25DigitalOutput = new double[128];
+            System.arraycopy(digitalDatum.getSamples(), 0, apv25DigitalOutput, 0, apv25DigitalOutput.length);
+
+            for(int channel = 0; channel < apv25DigitalOutput.length; channel++){
+
+                // Calculate the physical number
+                int physicalChannel = 639 - (apvN*128 + 127 - channel);
+
+                sensorToDataBlocks.get(sensor).addSample(physicalChannel, nSamples, (short) apv25DigitalOutput[channel]);
+            }
+		}
+		nSamples++;
+		
+		// If the expected number of samples has been collected, process the data
+        if(nSamples == totalSamples){
+
+            // Add RawTrackerHits to the event
+            event.put(rawTrackerHitsCollectionName, this.findRawHits(), RawTrackerHit.class, 0);
+            nSamples = 0;
+        }
+	}
+	
+	protected class SvtDataBlocks {
+		
+		Map<Integer /* sample number */, short[]> channelToSamples = new HashMap<Integer, short[]>();
+		
+		/**
+		 * 
+		 */
+		public SvtDataBlocks(){
+		}
+		
+		public void addSample(Integer physicalChannel, int sampleN, short value){
+            if(!channelToSamples.containsKey(physicalChannel)) channelToSamples.put(physicalChannel, new short[6]);
+            channelToSamples.get(physicalChannel)[sampleN] = value;
+		}
+		
+	       /**
+         * 
+         */
+        public short[] getSamples(int physicalChannel){
+            return channelToSamples.get(physicalChannel);
+        }
+        
+        /**
+         * 
+         */
+        public String printSamples(int physicalChannel){
+        	String sampleString = "[ ";
+        	short[] samples = this.getSamples(physicalChannel);
+        	for(int index = 0; index < samples.length -1; index++){
+        		sampleString +=  samples[index] + ", ";
+        	}
+        	sampleString += samples[samples.length - 1] + "]";
+			return sampleString;
+        }
+	}
+	
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking/apv25
HPSAPV25.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/apv25/HPSAPV25.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/apv25/HPSAPV25.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,353 @@
+package org.hps.recon.tracking.apv25;
+
+//--- Java ---//
+import java.util.HashMap;
+import java.util.Map;
+
+//--- org.lcsim ---//
+import org.hps.recon.tracking.apv25.HPSAPV25.APV25Channel.APV25AnalogPipeline;
+//--- hps-java ---//
+import org.lcsim.hps.util.ClockSingleton;
+import org.lcsim.hps.util.RingBuffer;
+import org.lcsim.util.aida.AIDA;
+
+/**
+ *
+ * @author Omar Moreno <[log in to unmask]>
+ * @version $Id: HPSAPV25.java,v 1.8 2012/08/03 00:05:26 meeg Exp $
+ */
+public class HPSAPV25 {
+
+	//--- APV25 parameters ---//
+	//------------------------//
+	private static final double APV25_FRONT_END_GAIN = 100.0; // [mV/MIP]
+	private static final double APV25_MULTIPLEXER_GAIN = 1;   // mA/MIP
+	private static final double APV25_NOISE_INTERCEPT_PEAK = 270; // e- RMS
+	private static final double APV25_NOISE_INTERCEPT_DECON = 396;  //e- RMS
+	private static final double APV25_NOISE_SLOPE_PEAK = 36;       // e- rms/pF
+	private static final double APV25_NOISE_SLOPE_DECON = 59.4;       // e- rms/pF
+	
+	// Number of electron-hole pairs created by a min. ionizing particle 
+	// in 300 micrometers of Si
+	private static final int MIP = 25000;  // electron-hole pairs
+	
+	// Total number of channels per APV25 chip
+	private static final int APV25_CHANNELS = 128;
+	
+	// APV25 trigger bit
+	public static boolean readoutBit = false;
+	
+	// 
+	private int apv25ShapingTime = 35; // [ns] 
+	private int apv25SamplingTime = 24; // [ns]
+	private double analogDCLevel = 0;  // [mA] (Pedestal)
+	public int apv25ClockCycle = 0;
+	private String apv25Mode = "multi-peak";
+	
+	// APV25 Channel
+	private APV25Channel channel;
+	
+	// Histograms
+	protected AIDA aida = AIDA.defaultInstance();
+
+	/**
+	 * Constructor
+	 */
+	public HPSAPV25() {
+		// Create a single instance of an APV25 channel
+		channel = new APV25Channel();
+
+	}
+
+	//--- Methods ---//
+	//---------------//
+	/**
+	 * Set the APV25 shaping time
+	 * 
+	 * @param shapingTime : APV25 shaping time
+	 */
+	public void setShapingTime(int shapingTime) {
+		apv25ShapingTime = shapingTime;
+	}
+
+	/**
+	 * Set the operating mode of the APV25 to either "peak", 
+	 * "deconvolution", or "multi-peak".
+	 * 
+	 * @param mode : APV25 operating mode 
+	 */
+	public void setAPV25Mode(String mode) {
+		apv25Mode = mode;
+	}
+
+	/**
+	 * Set the time interval at which the shaper output is sampled
+	 * 
+	 * @param sampleTime : time interval
+	 */
+	public void setSamplingTime(int sampleTime) {
+		apv25SamplingTime = sampleTime;
+	}
+
+	/**
+	 * 
+	 */
+	public void setAnalogDCLevel(double dcLevel) {
+		analogDCLevel = dcLevel;
+	}
+
+	/**
+	 * Return an instance of an APV25 channel. Currently, there is only a 
+	 * single instance of the channel ( instead of 128 that the actual chip
+	 * has).  However, the analog buffers of each channels are distinct and 
+	 * are stored in a sorted map for later use.
+	 *
+	 * @return an instance of APV25Channel
+	 */
+	public APV25Channel getChannel() {
+		return channel;
+	}
+
+	/**
+	 * Inject charge into a channel and shape the signal.  The resulting 
+	 * shaper signal is then sampled into the analog pipeline
+	 * 
+	 * @param charge   : Total charge being injected
+	 * @param pipeline : Analog pipeline associated with a channel
+	 */
+	public void injectCharge(double charge, double noiseRMS, APV25AnalogPipeline pipeline) {
+		
+		// Shape the injected charge
+		getChannel().shapeSignal(charge);
+
+		// Sample the resulting shaper signal
+		getChannel().sampleShaperSignal(pipeline, noiseRMS);
+	}
+
+	/**
+	 * Increment the position of the trigger and writer pointers of all
+	 * channels
+	 * 
+	 * @param analogPipelineMap : 
+	 */
+	public void incrementAllPointerPositions(Map<Integer, APV25AnalogPipeline> analogPipelineMap) {
+		// Loop through all of the channels and increment the position of
+		// all the trigger and writer pointers
+		for (Map.Entry<Integer, APV25AnalogPipeline> entry : analogPipelineMap.entrySet()) {
+			entry.getValue().step();
+		}
+	}
+
+	/**
+	 * 
+	 */
+	public int getSamplingTime() {
+		return apv25SamplingTime;
+	}
+
+	/**
+	 * Increment the APV25 clock cycle by one
+	 */
+	public void stepAPV25Clock() {
+		apv25ClockCycle += 1;
+	}
+
+	/**
+	 * 
+	 */
+	public Map<Integer, double[]> APV25Multiplexer(
+			Map<Integer, APV25AnalogPipeline> pipelineMap) {
+
+		Map<Integer /* chip */, double[]> apv25Map = new HashMap<Integer, double[]>();
+
+		// The address of the APV25.  There is only a single address for all
+		// chips
+		double[] apv25Address = {4.0, 4.0, 4.0, 4.0, 4.0, 4.0, 4.0, 4.0};
+		double[] output;
+
+		// Create the data streams
+		for (int chipIndex = 0; chipIndex < Math.ceil((double) pipelineMap.size() / APV25_CHANNELS); chipIndex++) {
+			apv25Map.put(chipIndex, createOutputArray(apv25Address, -4));
+		}
+
+		// Loop over all channels and readout the cells which the
+		// trigger pointer points to
+		for (int channelN = 0; channelN < pipelineMap.size(); channelN++) {
+			output = apv25Map.get((int) Math.floor(channelN / APV25_CHANNELS));
+			output[channelN % 128 + 12] += (pipelineMap.get(channelN).readOut() / APV25_FRONT_END_GAIN) * APV25_MULTIPLEXER_GAIN + analogDCLevel;
+		}
+		return apv25Map;
+	}
+
+	/**
+	 * 
+	 */
+	private double[] createOutputArray(double[] address, double error) {
+
+		// Create the array which will contain the output format. The array values
+		// will range from -4 microAmps to 4 microAmps.
+		double[] output = new double[141];
+		for (int index = 0; index < output.length; index++) {
+			output[ index] = -4.0;  // microAmps
+		}
+
+		// Header
+		double[] header = {4.0, 4.0, 4.0};
+
+		// Fill the array with the header, address and error bit and tick
+		System.arraycopy(header, 0, output, 0, 3);
+		output[header.length] = error;
+		System.arraycopy(address, 0, output, 4, 8);
+		output[ output.length - 1] = 4.0;
+
+		return output;
+	}
+
+	//------------------------------------------//
+	//               APV25 Channel            //
+	//-----------------------------------------//
+	public class APV25Channel {
+
+		// Analog pipeline length
+		private static final int ANALOG_PIPELINE_LENGTH = 192;
+		// Shaper signal
+		private APV25ShaperSignal shaperSignal;
+
+		/**
+		 * Constructor 
+		 */
+		public APV25Channel() {
+		}
+
+		/**
+		 * Shape the injected charge
+		 * 
+		 * @param charge 
+		 */
+		private void shapeSignal(double charge) {
+			shaperSignal = new APV25ShaperSignal(charge);
+		}
+
+		/**
+		 * Return the noise in electrons for a given strip capacitance
+		 * 
+		 * @param capacitance : strip capacitance in pF
+		 * @return noise in electrons
+		 */
+		public double computeNoise(double capacitance) {
+			if (apv25Mode.equals("peak") || apv25Mode.equals("multi-peak"))
+				return APV25_NOISE_INTERCEPT_PEAK + APV25_NOISE_SLOPE_PEAK * capacitance;
+			else return APV25_NOISE_INTERCEPT_DECON + APV25_NOISE_SLOPE_DECON * capacitance;
+		}
+
+		/**
+		 * Sample the shaper signal and fill the analog pipeline.
+		 * 
+		 * @param channel : Channel number
+		 */
+		private void sampleShaperSignal(
+				APV25AnalogPipeline pipeline, double noiseRMS) {
+
+			// Obtain the beam time
+			double beam_time = ClockSingleton.getTime();
+
+			// Fill the analog pipeline starting with the cell to which 
+			// the writer pointer is pointing to.  Signals arriving within 
+			// the same bucket of length apv25SamplingTime will be shifted
+			// in time depending on when they arrive.
+			for (int cell = 0; cell < ANALOG_PIPELINE_LENGTH; cell++) {
+
+				// Time at which the shaper signal will be sampled
+				int sample_time = cell * apv25SamplingTime
+						- ((int) beam_time) % apv25SamplingTime;
+				// Sample the shaper signal
+				double sample = shaperSignal.getAmplitudeAtTime(sample_time);
+
+				pipeline.addToCell(cell, sample);
+			}
+		}
+
+		//-----------------------------------//
+		//---     APV25 Shaper Signal     ---//
+		//-----------------------------------//
+		/**
+		 * 
+		 */
+		private class APV25ShaperSignal {
+
+			// Shaper signal maximum amplitude
+			private double maxAmp = 0;
+
+			/**
+			 * Constructor
+			 * 
+			 * @param charge : input charge into the channel
+			 */
+			APV25ShaperSignal(double charge) {
+
+				maxAmp = (charge / MIP) * APV25_FRONT_END_GAIN;  // mV
+
+				//--->
+				aida.histogram1D("Shaper Signal Max Amplitude", 100, 0, 500).fill(maxAmp);
+				//--->
+			}
+
+			/**
+			 * Get the amplitude at a time t
+			 * 
+			 * @param time : time at which the shaper signal is to be
+			 *               sampled
+			 */
+			private double getAmplitudeAtTime(double time) {
+				return maxAmp * (Math.max(0, time) / apv25ShapingTime) * Math.exp(1 - (time / apv25ShapingTime));
+			}
+		}
+
+		//-------------------------------------//
+		//---    APV25 Analog Pipeline      ---//
+		//-------------------------------------//
+		// Note that the buffer is modeled after a circular buffer
+		public class APV25AnalogPipeline extends RingBuffer {
+			private int _trigger_latency = (int) Math.floor(270 / apv25SamplingTime);
+
+			public APV25AnalogPipeline() { super(ANALOG_PIPELINE_LENGTH); }
+
+			/**
+			 * Set the trigger latency
+			 * 
+			 * @param latency : trigger latency in [ns]
+			 */
+			public void setTriggerLatency(int latency) {
+				_trigger_latency = (int) Math.floor(latency / apv25SamplingTime);
+			}
+
+			private double readOut() {
+				double pipelineValue = currentValue();
+				array[0] = 0;
+				return pipelineValue;
+			}
+
+			@Override
+			public void addToCell(int position, double element) {
+				if (position + _trigger_latency > array.length) {
+					return;
+				}
+				super.addToCell(position + _trigger_latency, element);
+			}
+
+			public void printAnalogPipeline() {
+				System.out.print("[ ");
+				for (int index = 0; index < array.length; index++) {
+					if (index == ptr) {
+						System.out.print("TP====>");
+					}
+					if (index == ptr + _trigger_latency) {
+						System.out.print("WP====>");
+					}
+					System.out.print(array[index] + ", ");
+				}
+				System.out.println("] ");
+			}
+		}
+	}
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking/apv25
HPSDataProcessingModule.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/apv25/HPSDataProcessingModule.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/apv25/HPSDataProcessingModule.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,398 @@
+package org.hps.recon.tracking.apv25;
+
+//--- Java ---//
+import static org.hps.conditions.deprecated.HPSSVTConstants.SVT_TOTAL_FPGAS;
+import static org.hps.conditions.deprecated.HPSSVTConstants.TOTAL_APV25_CHANNELS;
+import static org.hps.conditions.deprecated.HPSSVTConstants.TOTAL_APV25_PER_HYBRID;
+import static org.hps.conditions.deprecated.HPSSVTConstants.TOTAL_HYBRIDS_PER_FPGA;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+//--- org.lcsim ---//
+import java.util.Set;
+
+import org.hps.conditions.deprecated.SvtUtils;
+import org.hps.recon.tracking.HPSSVTData;
+import org.lcsim.detector.IReadout;
+import org.lcsim.detector.tracker.silicon.SiSensor;
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.RawTrackerHit;
+import org.lcsim.event.SimTrackerHit;
+import org.lcsim.event.base.BaseRawTrackerHit;
+import org.lcsim.geometry.Detector;
+import org.lcsim.util.Driver;
+//--- Constants ---//
+
+/**
+ *
+ * @author Omar Moreno <[log in to unmask]>
+ * @version $Id: HPSDataProcessingModule.java,v 1.3 2013/03/15 21:05:28 meeg Exp $
+ */
+public class HPSDataProcessingModule extends Driver {
+	
+	// A map relating a sensor to all sample blocks collected from that sensor
+	Map<SiSensor, Map<Integer, List<Double>>> sensorToSamplesMap;
+
+	// Relate a channel to its six samples
+	Map<Integer, List<Double>> channelToBlock;
+	
+	// Relate a sensor Identifier to the actual sensor
+	Map<Long, SiSensor> sensorMap = new HashMap<Long, SiSensor>();
+	
+	// Collection of all sensors
+	Set<SiSensor> sensorSet = new HashSet<SiSensor>();
+	
+	// Collections of RawTrackerHits
+	List<RawTrackerHit> rawHits;        // Cuts are applied
+	List<RawTrackerHit> rawHitsNoCuts;  // No cuts are applied to samples
+	
+	// Collection of all SVT data
+	List<HPSSVTData> svtData;
+	List<HPSSVTData> svtFpgaData;
+	List<Double> samples;
+
+	int numberOfSamples = 0;        // Total number of APV25 samples
+	int nSamplesAboveThresh = 3;    // Number of samples above noise threshold
+	int pedestal = 1638;            // [ADC counts] For now, all channels have the same pedestal
+	int flags = 0;                  //
+	int noise = 18;                 // [ADC Counts] RMS noise 
+	int noiseThreshold = 3;         // Units of RMS noise
+	int physicalChannel;
+	
+	private boolean thresholdCut = false;       // Apply threshold cut?
+	private boolean tailCut = false;            // Apply tail cut?
+	private boolean noiseSuppression = false;   // Apply noise suppression?
+	boolean debug = false;
+	
+	double[] apv25DataStream;
+	
+	String RawTrackerHitsCollectionName = "RawTrackerHits";
+	String RawTrackerHitsNoCutsCollectionName = "RawTrackerHitsNoCuts";
+	String svtCollectionName = "SVTData";
+
+	/**
+	 * Default Constructor
+	 */
+	public HPSDataProcessingModule() {
+		channelToBlock = new HashMap<Integer, List<Double>>();
+		sensorToSamplesMap = new HashMap<SiSensor, Map<Integer, List<Double>>>();
+		rawHits = new ArrayList<RawTrackerHit>();
+		rawHitsNoCuts = new ArrayList<RawTrackerHit>();
+		svtData = new ArrayList<HPSSVTData>();
+		svtFpgaData = new ArrayList<HPSSVTData>();
+	}
+
+	/**
+	 * 
+	 */
+	@Override
+	public void detectorChanged(Detector detector) {
+
+		for (SiSensor sensor : SvtUtils.getInstance().getSensors()) {
+			// Map a sensor to its corresponding samples
+			sensorToSamplesMap.put(sensor, new HashMap<Integer, List<Double>>());
+		}
+	}
+
+	/**
+	 * Set the SVT collection name
+	 */
+	public void setSvtCollectionName(String svtCollectionName) {
+		this.svtCollectionName = svtCollectionName;
+	}
+
+	/**
+	 * Set the number of samples above threshold a signal must have
+	 */
+	public void setSamplesAboveThresh(int nSamplesAboveThresh) {
+		this.nSamplesAboveThresh = nSamplesAboveThresh;
+	}
+
+	/**
+	 * Set the noise RMS [ADC Counts]
+	 */
+	public void setNoise(int noise) {
+		this.noise = noise;
+	}
+
+	/**
+	 * Set the noise threshold in units of RMS noise
+	 */
+	public void setNoiseThreshold(int noiseThreshold) {
+		this.noiseThreshold = noiseThreshold;
+	}
+
+	/**
+	 * Set the pedestal value for all channels
+	 */
+	public void setPedestal(int pedestal) {
+		this.pedestal = pedestal;
+	}
+
+	/**
+	 * Enable the threshold cut.  The threshold cut requires a certain number
+	 * of samples per hit to be above a noise threshold.
+	 */
+	public void enableThresholdCut() {
+		this.thresholdCut = true;
+	}
+
+	/**
+	 * Enable the tail cut.  The tail cut requires sample 1 to be greater than
+	 * sample 0 or sample 2 to be greater than sample 1. This eliminates 
+	 * hits that may arise due to shaper signal tails.
+	 */
+	public void enableTailCut() {
+		this.tailCut = true;
+	}
+
+	/**
+	 * Enable noise suppression cut.  Requires samples 2 or 3 to be above a
+	 * threshold noiseThreshold + noise. 
+	 */
+	public void enableNoiseSuppressionCut() {
+		this.noiseSuppression = true;
+	}
+
+	/**
+	 * Buffer a sample that has been readout from a sensor.
+	 * 
+	 * @param sensorToDigitalMap
+	 *      A map relating a sensor to the digital samples readout from the 
+	 *      sensor
+	 */
+	public void addSample(Map<SiSensor, Map<Integer, double[]>> sensorToDigitalMap) {
+
+		/*
+		 * Integer:  Chip Number
+		 * double[]: APV25 Data Analog Data 
+		 */
+
+		int physicalChannel;
+
+		// Loop through the list of all sensors
+		for (Map.Entry<SiSensor, Map<Integer, double[]>> sensor : sensorToDigitalMap.entrySet()) {
+
+			// Loop through all APV25s
+			for (Map.Entry<Integer, double[]> chipData : sensor.getValue().entrySet()) {
+
+				// Copy the sample to avoid concurrent modification
+				apv25DataStream = chipData.getValue();
+
+				// Strip the APV25 data stream of all header information
+				apv25DataStream = Arrays.copyOfRange(apv25DataStream, 12, apv25DataStream.length - 1);
+
+				// Loop through all channels
+				for (int channel = 0; channel < apv25DataStream.length; channel++) {
+
+					physicalChannel = channel + chipData.getKey() * 128;
+
+					// Check if a block has been created for this channel. If not create it
+					if (!sensorToSamplesMap.get(sensor.getKey()).containsKey(physicalChannel)) {
+						sensorToSamplesMap.get(sensor.getKey()).put(physicalChannel, new ArrayList<Double>(6));
+					}
+					sensorToSamplesMap.get(sensor.getKey()).get(physicalChannel).add(apv25DataStream[channel]);
+				}
+			}
+		}
+		numberOfSamples++;
+	}
+
+	/**
+	 *  Finds hits that satisfied all required cuts and creates both
+	 *  RawTrackerHits and SVTData
+	 */
+	public void findHits() {
+
+		int fpgaNumber, hybridNumber, apvNumber, rawChannel;
+		
+		// Clear the list of raw tracker hits
+		rawHits.clear();
+		rawHitsNoCuts.clear();
+		svtData.clear();
+		
+		// Loop through all sensors and the corresponding blocks
+		for (Map.Entry<SiSensor, Map<Integer, List<Double>>> sensor : sensorToSamplesMap.entrySet()) {
+
+			// Get the FPGA number
+			fpgaNumber = SvtUtils.getInstance().getFPGA(sensor.getKey());
+			if(fpgaNumber > SVT_TOTAL_FPGAS || fpgaNumber < 0)
+				throw new RuntimeException("FPGA Number out of range!");
+			if(debug) System.out.println(this.getClass().getSimpleName() + ": FPGA Number: " + fpgaNumber);
+
+			// Clear the temporary list
+			svtFpgaData.clear();
+			
+			for (Map.Entry<Integer, List<Double>> samples : sensor.getValue().entrySet()) {
+				short[] adc = new short[6];
+
+				// Convert ADC value to a short
+				for (int index = 0; index < adc.length; index++) 
+					adc[index] = samples.getValue().get(index).shortValue();
+
+				// If a strip had any charge deposited on it, create a RawTrackerHit
+				if(!(samplesAboveThreshold(adc) >= 1)){
+					samples.getValue().clear();
+					continue;
+				}
+					
+				RawTrackerHit rawHit = makeRawTrackerHit(samples.getKey(), sensor.getKey(), adc);
+				rawHitsNoCuts.add(rawHit);
+				
+				// Check if a block has the appropriate number of blocks above threshold
+				if (thresholdCut && !(samplesAboveThreshold(adc) >= nSamplesAboveThresh)) {
+					samples.getValue().clear();
+					continue;
+				}
+
+				// Apply the tail cut
+				if (tailCut && !tailCut(adc)) {
+					samples.getValue().clear();
+					continue;
+				}
+
+				// Apply noise suppression cut
+				if (noiseSuppression && !noiseSuppressionCut(adc)) {
+					samples.getValue().clear();
+					continue;
+				}
+
+				// If all cuts are satisfied, add the hit to the list of hits to be saved
+				rawHits.add(rawHit);
+
+				// Get the hybrid number
+				hybridNumber = SvtUtils.getInstance().getHybrid(sensor.getKey());
+				if(hybridNumber > TOTAL_HYBRIDS_PER_FPGA || hybridNumber < 0)
+					throw new RuntimeException("Hybrid number is out of range!");
+				//if(debug) System.out.println(this.getClass().getSimpleName() + ": Hybrid Number: " + hybridNumber);
+
+				// Find the APV number. Note that strip numbering is from 639 to 0
+				apvNumber = (TOTAL_APV25_PER_HYBRID - 1) - (int) Math.floor(samples.getKey()/128);
+				if(apvNumber > TOTAL_APV25_PER_HYBRID || apvNumber < 0) 
+					throw new RuntimeException("APV25 Number out of range!");
+				//if(debug) System.out.println(this.getClass().getSimpleName() + ": APV Number: " + apvNumber);
+
+				// Find the raw channel number from the physical channel
+				rawChannel = samples.getKey() - (TOTAL_APV25_CHANNELS*TOTAL_APV25_PER_HYBRID - 1) 
+						+ apvNumber*TOTAL_APV25_CHANNELS + (TOTAL_APV25_CHANNELS - 1); 
+				if(rawChannel > TOTAL_APV25_CHANNELS || rawChannel < 0)
+					throw new RuntimeException("APV25 Channel " + rawChannel + " out of range!");
+				//if(debug) System.out.println(this.getClass().getSimpleName() + ": Raw Channel Number: " + rawChannel);
+				
+				// Create an svtData packet
+				HPSSVTData data = new HPSSVTData(hybridNumber, apvNumber, rawChannel, fpgaNumber, adc);
+				svtData.add(data);
+				svtFpgaData.add(data);
+				
+				samples.getValue().clear();
+			}
+
+			HPSSVTDataBuffer.addToBuffer(svtFpgaData, fpgaNumber);
+		}
+		if(debug) System.out.println(this.getClass().getName() + ": Total RawTrackerHits before cuts: " + rawHitsNoCuts.size());
+		if(debug) System.out.println(this.getClass().getName() + ": Total RawTrackerHits: " + rawHits.size());
+		if(debug) System.out.println(this.getClass().getName() + ": Total SVTData: " + svtData.size());
+	}
+
+	/**
+	 * Creates a rawTrackerHit
+	 * 
+	 * @param channelNumber
+	 *      Si Strip from which the hit originates from
+	 * @param sensor
+	 *      Sensor from which the hit originates from
+	 * @param adcValues
+	 *      Shaper signal samples
+	 * @return RawTrackerHit
+	 */
+	private RawTrackerHit makeRawTrackerHit(Integer channelNumber, SiSensor sensor, short[] adcValues) {
+		IReadout ro = sensor.getReadout();
+
+		// No time yet
+		int time = 0;
+		long cell_id = sensor.makeStripId(channelNumber, 1).getValue();
+
+		RawTrackerHit rawHit = new BaseRawTrackerHit(time, cell_id, adcValues, new ArrayList<SimTrackerHit>(), sensor);
+
+		ro.addHit(rawHit);
+
+		return rawHit;
+	}
+
+	/**
+	 * Finds how many samples are above a given threshold
+	 * 
+	 * @param adc
+	 *      Shaper signal samples
+	 * @return Number of samples above threshold
+	 */
+	private int samplesAboveThreshold(short[] adc) {
+		// Number of samples above threshold
+		int nSamplesAboveThreshold = 0;
+
+		for (int sample = 0; sample < adc.length; sample++) {
+			if (adc[sample] >= pedestal + noiseThreshold * noise) {
+				nSamplesAboveThreshold++;
+			}
+		}
+		return nSamplesAboveThreshold;
+	}
+
+	/**
+	 * Applies tail cut
+	 * 
+	 * @param adc
+	 *      Shaper signal samples
+	 * @return true if the cut is satisfied, false otherwise
+	 */
+	private boolean tailCut(short[] adc) {
+		if (adc[3] > adc[2] || adc[4] > adc[3]) {
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Applies noise suppression cut
+	 * 
+	 * @param adc 
+	 *      Shaper signal samples
+	 * @return true if the cut is satisfied, false otherwise
+	 */
+	private boolean noiseSuppressionCut(short[] adc) {
+		if (adc[3] > pedestal + noiseThreshold * noise || adc[4] > pedestal + noiseThreshold * noise) {
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * 
+	 */
+	@Override
+	public void process(EventHeader event) {
+		super.process(event);
+
+		// If six samples have been collected process the data
+		if (numberOfSamples == 6) {
+
+			// Find hits
+			findHits();
+
+			// Add RawTrackerHits to the event
+			event.put(RawTrackerHitsCollectionName, rawHits, RawTrackerHit.class, flags);
+
+			// Add SVTData to event
+			System.out.println("Adding SVTData Collection of size: " + svtData.size() + " to the Event");
+			event.put(this.svtCollectionName, this.svtData, HPSSVTData.class, 0);
+
+			
+			//
+			numberOfSamples = 0;
+		}
+	}
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking/apv25
HPSRTM.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/apv25/HPSRTM.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/apv25/HPSRTM.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,127 @@
+
+package org.hps.recon.tracking.apv25;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ *
+ * @author Omar Moreno <[log in to unmask]>
+ * @version  $Id: HPSRTM.java,v 1.3 2013/03/15 21:05:28 meeg Exp $
+ */
+public class HPSRTM {
+    
+    private Map<Integer, double[]> analogData;
+    private Map<Integer, double[]> digitalData;
+
+    private static double INPUT_STAGE_GAIN = 2;
+    private static double RESISTOR_VALUE = 100; // Ohms
+    
+    double adcHighRef = 1000;   // mVolts
+    double adcLowRef = -1000;   // mVolts
+    double adcResolution = 0;  //bits
+    double adcVoltageResolution = 0; // Volts
+    int voltageIntervals;
+    
+    
+    /**
+     * Constructor
+     */
+    public HPSRTM(int bits)
+    {
+        // To do: In order to increase speed, HashMap should be initialized
+        // to a specified capacity
+        digitalData = new HashMap<Integer, double[]>();
+        
+        adcResolution = bits;
+        voltageIntervals = (int) Math.pow(2, bits);
+
+        adcVoltageResolution 
+           =  (adcHighRef - adcLowRef)/voltageIntervals; // mV
+        
+    }
+    
+    //--- Methods ---//
+    //---------------//
+    
+    
+    /**
+     * 
+     * @param data 
+     */
+    public Map<Integer, double[]> digitize( Map<Integer, double[]> data )
+    {
+        digitalData = data;
+
+        // Amplify the incoming analog signal
+        amplifySignal();
+        
+        // Loop over all apv25 analog signals and digitize them
+        for(Map.Entry<Integer, double[]> entry : digitalData.entrySet()){
+            
+            
+            
+            // Aquire the amplified signal
+            double[] digitalSignal = entry.getValue();
+
+            // Digitize the apv25 output
+            for(int index = 0; index < digitalSignal.length; index++){
+                
+                digitalSignal[index]
+                   = Math.floor((digitalSignal[index] 
+                                    - adcLowRef)/adcVoltageResolution);
+            }
+
+            digitalData.put(entry.getKey(), digitalSignal);
+            
+        }
+
+        return digitalData;
+    }
+    
+    /**
+     * 
+     */
+    public void amplifySignal()
+    {
+        
+        // Loop over all apv25 analog data
+        for(Map.Entry<Integer, double[]> entry : digitalData.entrySet() )
+        {
+            // Obtain the apv25 output
+            double[] apv25Output = entry.getValue();
+            
+            for(int index = 0; index < apv25Output.length; index++ ){
+                
+                // Convert input current to voltage
+                apv25Output[index] *= RESISTOR_VALUE;
+                
+                // Amplify the input signal
+                apv25Output[index] *= INPUT_STAGE_GAIN;
+            }
+
+            // Store the amplified APV25 output
+            digitalData.put(entry.getKey(), apv25Output);
+            
+        }
+    }
+    
+    /**
+     * 
+     */
+    public void setResolution( int bits )
+    {
+        adcResolution = bits;
+    }
+    
+    /**
+     * 
+     */
+   public void printData()
+   {
+       
+       double[] data = digitalData.get("1");
+       System.out.println(data.length);
+       System.out.println(" ]");
+   }
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking/apv25
HPSSVTDataBuffer.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/apv25/HPSSVTDataBuffer.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/apv25/HPSSVTDataBuffer.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,158 @@
+
+package org.hps.recon.tracking.apv25;
+
+import static org.hps.conditions.deprecated.HPSSVTConstants.SVT_TOTAL_FPGAS;
+import static org.hps.conditions.deprecated.HPSSVTConstants.TEMP_MASK;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+// Constants
+import org.hps.recon.tracking.FpgaData;
+import org.hps.recon.tracking.HPSSVTData;
+
+/**
+ *
+ * @author Omar Moreno <[log in to unmask]>
+ * @version $Id: HPSSVTDataBuffer.java,v 1.1 2013/03/15 21:05:28 meeg Exp $ 
+ */
+public class HPSSVTDataBuffer {
+    
+    // Map the FPGA to the data emerging from it
+    private Map<Integer, List<Integer>> fpgaToData = new HashMap<Integer, List<Integer>>();
+	
+    // Singleton
+    private static final HPSSVTDataBuffer instance = new HPSSVTDataBuffer();
+    private static int eventNumber = 0;
+    
+    int[] header = new int[6];
+    int temp = FpgaData.temperatureToInt(23.0); // C
+    
+    boolean debug = false;
+        
+    /**
+     * Default constructor; Set to private to prevent instantiation
+     */
+    private HPSSVTDataBuffer(){
+        //
+        for(int fpgaNumber = 0; fpgaNumber <= SVT_TOTAL_FPGAS; fpgaNumber++) 
+        	fpgaToData.put(fpgaNumber, new ArrayList<Integer>());
+    }
+    
+    /**
+     * Add data to SVT buffer
+     * 
+     * @param svtData : List of SVT data packets
+     * @param fpga : FPGA from which the data emerges from
+     */
+    public static void addToBuffer(List<HPSSVTData> svtData, int fpga){
+        // If the FPGA data block is empty, add header information and data, otherwise
+    	// just add the data
+    	instance.encapsulateSVTData(svtData, fpga);        
+    }
+    
+    /**
+     * Readout data stored in the SVT buffer
+     * 
+     * @param fpga : FPGA from which data is to be read from
+     * @return data : An FPGA data packet 
+     *
+     */
+    public static int[] readoutBuffer(int fpga){
+    	// Add the event number to the beginning
+    	instance.addEventNumber(fpga);
+    	
+    	// Add the tail to the data
+    	instance.addTail(fpga);
+    	
+    	// Copy the data in the map so that the buffer can be cleared
+    	int[] data = new int[instance.fpgaToData.get(fpga).size()]; 
+    	int index = 0;
+    	for(Integer datum : instance.fpgaToData.get(fpga)){
+    		data[index] = datum;
+    		index++;
+    	}
+    	
+    	// Clear the buffer
+        instance.fpgaToData.get(fpga).clear();
+        
+        // Return the 
+        return data;
+    }
+    
+    /**
+     * Encapsulate SVT data by FPGA
+     * 
+     * @param svtData : List of SVT data packets
+     * @param fpga : FPGA from which the data emerges from
+     */
+    private void encapsulateSVTData(List<HPSSVTData> svtData, int fpga){
+    	// Ignore FPGA 7 for now 
+    	if(fpga == 7) return;
+    	
+    	// If the FPGA data block is empty, add the header information and increment the event number
+    	if(instance.fpgaToData.get(fpga).isEmpty()){
+    		
+    		// Insert the temperature information. All temperatures are currently
+    		// set to 23 C
+    		header[0] = (header[0] &= ~TEMP_MASK) | (temp & TEMP_MASK);
+    		header[0] = (header[0] &= ~(TEMP_MASK << 16)) | ((temp & TEMP_MASK) << 16);
+        
+    		header[1] = (header[1] &= ~TEMP_MASK) | (temp & TEMP_MASK);
+    		header[1] = (header[1] &= ~(TEMP_MASK << 16)) | ((temp & TEMP_MASK) << 16);
+        
+    		header[2] = (header[2] &= ~TEMP_MASK) | (temp & TEMP_MASK);
+    		header[2] = (header[2] &= ~(TEMP_MASK << 16)) | ((temp & TEMP_MASK) << 16);
+       
+    		header[3] = (header[3] &= ~TEMP_MASK) | (temp & TEMP_MASK);
+    		header[3] = (header[3] &= ~(TEMP_MASK << 16)) | ((temp & TEMP_MASK) << 16);
+     
+    		header[4] = (header[4] &= ~TEMP_MASK) | (temp & TEMP_MASK);
+    		header[4] = (header[4] &= ~(TEMP_MASK << 16)) | ((temp & TEMP_MASK) << 16);
+        
+    		header[5] = (header[5] &= ~TEMP_MASK) | (temp & TEMP_MASK);
+    		header[5] = (header[5] &= ~(TEMP_MASK << 16)) | ((temp & TEMP_MASK) << 16);
+        
+    		for(int index = 0; index < header.length; index++) fpgaToData.get(fpga).add(header[index]);
+    	
+    		eventNumber++;
+    	}
+
+        // Add all samples emerging from this FPGA
+        if(!svtData.isEmpty()){
+        	for(HPSSVTData svtDatum : svtData){ 
+            	if(debug){
+            		System.out.println("FPGA: " + svtDatum.getFPGAAddress() + " Hybrid: " + svtDatum.getHybridNumber() + " APV: " 
+            							+ svtDatum.getAPVNumber() + " Channel: " + svtDatum.getChannelNumber());
+            	}
+        		for(int index = 0; index < svtDatum.getData().length; index++){
+        			fpgaToData.get(fpga).add(svtDatum.getData()[index]);
+        		}
+        	}
+        }
+    }
+    
+    /**
+     * Add a tail to the FPGA data packet.  In real data, this may be 
+     * non-zero which would indicate an error.
+     * 
+     * @param fpga : FPGA from which the data emerges from
+     */
+    private void addTail(int fpga){
+    	
+    	// For now just make it zero
+    	instance.fpgaToData.get(fpga).add(0);
+    }
+    
+    /**
+     * Add an SVT event number to the top of the FPGA data packet.
+     * 
+     * @param fpga : FPGA from which the data emerges from
+     */
+    private void addEventNumber(int fpga){
+    	
+    	instance.fpgaToData.get(fpga).add(0, eventNumber);
+    }
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking/apv25
HPSSiSensorReadout.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/apv25/HPSSiSensorReadout.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/apv25/HPSSiSensorReadout.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,474 @@
+package org.hps.recon.tracking.apv25;
+
+//--- Java ---//
+import hep.aida.ref.histogram.Profile1D;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Queue;
+import java.util.Random;
+import java.util.Set;
+
+//--- apache ---//
+import org.apache.commons.math.MathException;
+import org.apache.commons.math.distribution.BinomialDistribution;
+import org.apache.commons.math.distribution.BinomialDistributionImpl;
+import org.apache.commons.math.distribution.NormalDistribution;
+import org.apache.commons.math.distribution.NormalDistributionImpl;
+import org.hps.conditions.deprecated.SvtUtils;
+//--- hps-java ---//
+import org.hps.recon.tracking.apv25.HPSAPV25.APV25Channel.APV25AnalogPipeline;
+//--- org.lcsim ---//
+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.EventHeader;
+import org.lcsim.geometry.Detector;
+import org.lcsim.hps.util.ClockSingleton;
+import org.lcsim.math.probability.Erf;
+import org.lcsim.recon.tracking.digitization.sisim.CDFSiSensorSim;
+import org.lcsim.recon.tracking.digitization.sisim.SiElectrodeData;
+import org.lcsim.recon.tracking.digitization.sisim.SiElectrodeDataCollection;
+import org.lcsim.recon.tracking.digitization.sisim.SiSensorSim;
+import org.lcsim.recon.tracking.digitization.sisim.config.SimTrackerHitReadoutDriver;
+import org.lcsim.util.Driver;
+import org.lcsim.util.aida.AIDA;
+
+/**
+ * Class used to Readout HPS APV25's
+ *
+ * @author Omar Moreno <[log in to unmask]>
+ * @version $Id: HPSSiSensorReadout.java,v 1.12 2013/03/15 21:05:28 meeg Exp $
+ */
+public class HPSSiSensorReadout extends Driver {
+
+    //
+    boolean debug = true;
+    String subdetectorName = "tracker";
+    // Array to store the trigger time
+    public static final List<Double> triggerTimeStamp = new ArrayList<Double>();
+    //
+    List<String> readouts = new ArrayList<String>();
+    // FIFO queue to store trigger times
+    public Queue<Integer> triggerQueue;
+    private HPSAPV25 apv25;
+    private SiSensorSim siSimulation;
+    private HPSRTM rtm;
+    private HPSDataProcessingModule dpm;
+    private static Random random = new Random();
+    private static BinomialDistribution binomial = new BinomialDistributionImpl(1, 1);
+    private static NormalDistribution gaussian = new NormalDistributionImpl(0.0, 1.0);
+    private double noiseThreshold = 4;  // e- RMS
+    private boolean addNoise = false;
+    // A map used to associate a sensor to the channels and analog pipelines 
+    // of the APV25s being used to readout the sensor
+    public Map<SiSensor /* sensor */, Map<Integer /* channel */, APV25AnalogPipeline>> sensorToPipelineMap;
+    // A map used to associate an APV25 channel to its analog pipeline
+    public Map<Integer /* channel */, APV25AnalogPipeline> analogPipelineMap;
+    // A map used to associate a sensor to the output of the APV25s being 
+    // used to readout the sensor
+    public Map<SiSensor, Map<Integer /* chip # */, double[]>> sensorToAnalogDataMap;
+    // A map used to associate a sensor to the digitized output of the APV25s
+    // being used to readout the sensor
+    public Map<SiSensor, Map<Integer /*chip # */, double[]>> sensorToDigitalDataMap;
+    //
+    public Map<Integer, double[]> analogData;
+    public Map<Integer, double[]> digitalData;
+    //
+    protected AIDA aida = AIDA.defaultInstance();
+    public Profile1D pipe;
+    int n_events = 0;
+
+    /**
+     * Constructor
+     */
+    public HPSSiSensorReadout() {
+
+        sensorToPipelineMap = new HashMap<SiSensor, Map<Integer, APV25AnalogPipeline>>();
+        sensorToAnalogDataMap = new HashMap<SiSensor, Map<Integer, double[]>>();
+        sensorToDigitalDataMap = new HashMap<SiSensor, Map<Integer, double[]>>();
+
+        //--- Sensor Simulation ---//
+        //-------------------------//
+        siSimulation = new CDFSiSensorSim();
+
+        //--- APV25 Simulation ---//
+        //------------------------//
+        apv25 = new HPSAPV25();
+        // Set the APV25 Shaping time [ns]
+        apv25.setShapingTime(35);
+        // Set the APV25 operating mode
+        apv25.setAPV25Mode("multi-peak");
+        // Set the APV25 analog pipeline sampling time
+        apv25.setSamplingTime(24);
+
+        // 
+        rtm = new HPSRTM(14);
+
+        // Instantiate the DPM
+        dpm = new HPSDataProcessingModule();
+        dpm.setNoise(18);
+        dpm.setNoiseThreshold(2);
+        dpm.setSamplesAboveThresh(3);
+        dpm.setPedestal(1638);
+        dpm.enableThresholdCut();
+        dpm.enableTailCut();
+
+        add(dpm);
+
+        // Instantiate trigger time queue
+        triggerQueue = new LinkedList<Integer>();
+
+        // Specify the readouts to process
+        readouts.add("TrackerHits");
+
+    }
+
+    public void setAddNoise(boolean addNoise) {
+        this.addNoise = addNoise;
+    }
+
+    /**
+     * 
+     */
+    @Override
+    public void detectorChanged(Detector detector) {
+        // Call the sub-Drivfer's detectorChanged methods
+        super.detectorChanged(detector);
+
+        // Instantiate all maps
+        for (SiSensor sensor : SvtUtils.getInstance().getSensors()) {
+
+            sensorToPipelineMap.put(sensor, new HashMap<Integer, APV25AnalogPipeline>());
+
+            // Instantiate all analog pipelines
+            for (int channel = 0; channel < sensor.getReadoutElectrodes(ChargeCarrier.HOLE).getNCells(); channel++) {
+                sensorToPipelineMap.get(sensor).put(channel, apv25.getChannel().new APV25AnalogPipeline());
+            }
+
+            if (debug) {
+                System.out.println(this.getClass().getSimpleName() + ": Sensor: " + sensor.getName()
+                        + ": Number of Analog Pipelines: " + sensorToPipelineMap.get(sensor).size());
+            }
+
+            sensorToAnalogDataMap.put(sensor, new HashMap<Integer, double[]>());
+            sensorToDigitalDataMap.put(sensor, new HashMap<Integer, double[]>());
+        }
+    }
+
+    /**
+     * 
+     */
+    @Override
+    public void startOfData() {
+        // Set up readouts if they haven't been set
+        if (!readouts.isEmpty()) {
+            super.add(new SimTrackerHitReadoutDriver(readouts));
+        }
+
+        super.startOfData();
+        readouts.clear();
+
+    }
+
+    /**
+     * 
+     */
+    @Override
+    public void process(EventHeader event) {
+
+
+        super.process(event);
+
+        if ((ClockSingleton.getTime() + ClockSingleton.getDt()) % 24 == 0) {
+            for (Map.Entry<SiSensor, Map<Integer, APV25AnalogPipeline>> sensor : sensorToPipelineMap.entrySet()) {
+                apv25.incrementAllPointerPositions(sensor.getValue());
+            }
+            apv25.stepAPV25Clock();
+        }
+
+        // Loop over all sensors
+        for (SiSensor sensor : SvtUtils.getInstance().getSensors()) {
+            // Readout the sensors
+            readoutSensor(sensor);
+        }
+
+        // If a trigger is received readout the APV25 and digitize all hits
+        if (HPSAPV25.readoutBit) {
+
+            triggerTimeStamp.add(ClockSingleton.getTime());
+
+            // Only add the trigger if there isn't another trigger being 
+            // processed
+            if (!triggerQueue.contains(apv25.apv25ClockCycle)) {
+                // Add the time at which each of the six samples should be 
+                // collected to the trigger queue
+                for (int sample = 0; sample < 6; sample++) {
+                    triggerQueue.offer(apv25.apv25ClockCycle + sample);
+                }
+            }
+            // Reset the APV25 trigger bit
+            HPSAPV25.readoutBit = false;
+        }
+
+        // Process any triggers in the queue
+        if (triggerQueue.peek() != null) {
+
+            // Remove any samples that might have already been processed
+            if (triggerQueue.peek() < apv25.apv25ClockCycle) {
+                for (int sample = 0; sample < 6; sample++) {
+                    triggerQueue.remove();
+                }
+            } else if (triggerQueue.peek() == apv25.apv25ClockCycle) {
+                readoutAPV25();
+                triggerQueue.remove();
+            }
+        }
+    }
+
+    /**
+     * Readout the electrodes of an HPS Si sensor and inject the charge into 
+     * the APV25 readout chip.
+     * 
+     * @param sensor : HPS Si sensor
+     */
+    public void readoutSensor(SiSensor sensor) {
+        // Set the sensor to be used in the charge deposition simulation
+        siSimulation.setSensor(sensor);
+
+        // Perform the charge deposition simulation
+        Map<ChargeCarrier, SiElectrodeDataCollection> electrodeDataMap = siSimulation.computeElectrodeData();
+
+        // Loop over each charge carrier (electron or hole)
+        for (ChargeCarrier carrier : ChargeCarrier.values()) {
+
+            // If the sensor is capable of collecting the given charge carrier
+            // then obtain the electrode data for the sensor
+            if (sensor.hasElectrodesOnSide(carrier)) {
+
+                SiElectrodeDataCollection electrodeDataCol = electrodeDataMap.get(carrier);
+
+                // If there is no electrode data available create a new instance of electrode data
+                if (electrodeDataCol == null) {
+                    electrodeDataCol = new SiElectrodeDataCollection();
+                }
+
+                // Get the readout electrodes
+                SiSensorElectrodes readoutElectrodes = sensor.getReadoutElectrodes(carrier);
+
+                // Add noise to the electrodes
+                if (addNoise) {
+                    addNoise(electrodeDataCol, readoutElectrodes);
+                }
+
+                // Get the analog pipeline map associated with this sensor
+                analogPipelineMap = sensorToPipelineMap.get(sensor);
+
+                // Loop over all channels
+                for (Integer channel : electrodeDataCol.keySet()) {
+
+                    // Get the electrode data for this channel
+                    SiElectrodeData electrodeData = electrodeDataCol.get(channel);
+
+                    // Get the charge in units of electrons
+                    double charge = electrodeData.getCharge();
+
+                    //====> Charge deposition on electrode 
+                    aida.histogram1D("Charge", 100, 0, 200000).fill(charge);
+                    //====>
+
+                    // Get the RMS noise for this channel
+                    double noise = apv25.getChannel().computeNoise(
+                            readoutElectrodes.getCapacitance(channel));
+
+                    //===>
+                    aida.histogram1D(this.getClass().getName() + " - RMS Noise - All Channels", 1000, 3500, 4500).fill(noise);
+                    //===>
+
+                    // Check to see if an analog pipeline for this channel
+                    // exist.  If it doesn't, create one.
+                    if (!analogPipelineMap.containsKey(channel)) {
+                        analogPipelineMap.put(channel,
+                                apv25.getChannel().new APV25AnalogPipeline());
+                    }
+
+                    // Get the analog pipeline associated with this channel
+                    APV25AnalogPipeline pipeline = analogPipelineMap.get(channel);
+
+                    // Inject the charge into the APV25 amplifier chain
+                    apv25.injectCharge(charge, noise, pipeline);
+                }
+            }
+        }
+
+        // Place the analog pipeline back into the sensor map
+        sensorToPipelineMap.put(sensor, analogPipelineMap);
+
+        // Clear the sensors of all deposited charge
+        siSimulation.clearReadout();
+    }
+
+    /**
+     * 
+     */
+    public void readoutAPV25() {
+        // Readout all apv25s
+        for (Map.Entry<SiSensor, Map<Integer, APV25AnalogPipeline>> sensor : sensorToPipelineMap.entrySet()) {
+            sensorToAnalogDataMap.put(sensor.getKey(), apv25.APV25Multiplexer(sensor.getValue()));
+        }
+
+        // Digitize all signals
+        for (Map.Entry<SiSensor, Map<Integer, double[]>> sensor : sensorToAnalogDataMap.entrySet()) {
+            sensorToDigitalDataMap.put(sensor.getKey(), rtm.digitize(sensor.getValue()));
+        }
+
+        // Buffer the samples for further processing
+        //---> Needs to change!
+        dpm.addSample(sensorToDigitalDataMap);
+        //--->
+    }
+
+    /**
+     * 
+     * @param electrodeDataCol
+     * @param electrodes 
+     */
+    public void addNoise(SiElectrodeDataCollection electrodeDataCol,
+            SiSensorElectrodes electrodes) {
+        // First add readout noise to the strips in the 
+        // SiElectrodeDataCollection.
+
+        // Loop over the entries in the SiElectrodeDataCollection
+        for (Entry electrodeDatum : electrodeDataCol.entrySet()) {
+
+            // Get the channel number and electrode data for this entry
+            int channel = (Integer) electrodeDatum.getKey();
+            SiElectrodeData electrodeData = (SiElectrodeData) electrodeDatum.getValue();
+
+            // Get the RMS noise for this channel in units of electrons
+            double noise = apv25.getChannel().computeNoise(
+                    electrodes.getCapacitance(channel));
+
+            // Add readout noise to the deposited charge
+            int noiseCharge = (int) Math.round(random.nextGaussian() * noise);
+            electrodeData.addCharge(noiseCharge);
+        }
+
+        // Find the number of strips that are not currently hit
+        int nElectrodes = electrodes.getNCells();
+        int nElectrodesEmpty = nElectrodes - electrodeDataCol.size();
+
+        // Get the noise threshold in units of the noise charge
+
+        // Calculate how many channels should get noise hits
+        double integral = Erf.phic(noiseThreshold);
+        int nChannelsThrow = drawBinomial(nElectrodesEmpty, integral);
+
+        // Now throw Gaussian randoms above the seed threshold and put signals
+        // on unoccupied channels
+        for (int ithrow = 0; ithrow < nChannelsThrow; ithrow++) {
+            // Throw to get a channel number
+            int channel = random.nextInt(nElectrodes);
+            while (electrodeDataCol.keySet().contains(channel)) {
+                channel = random.nextInt(nElectrodes);
+            }
+
+            // Calculate the noise for this channel in units of electrons
+            double noise = apv25.getChannel().computeNoise(
+                    electrodes.getCapacitance(channel));
+
+            // Throw Gaussian above threshold
+            int charge = (int) Math.round(drawGaussianAboveThreshold(integral) * noise);
+
+            // Add the noise hit to the electrode data collection
+            electrodeDataCol.add(channel, new SiElectrodeData(charge));
+        }
+
+        // Now throw to lower threshold on channels that neighbor hits until
+        // we are exhausted
+
+        nChannelsThrow = 1;
+        while (nChannelsThrow > 0) {
+
+            // Get neighbor channels
+            Set<Integer> neighbors = new HashSet<Integer>();
+            for (int channel : electrodeDataCol.keySet()) {
+                neighbors.addAll(electrodes.getNearestNeighborCells(channel));
+            }
+            neighbors.removeAll(electrodeDataCol.keySet());
+
+            nElectrodesEmpty = neighbors.size();
+
+            integral = Erf.phic(noiseThreshold);
+            nChannelsThrow = drawBinomial(nElectrodesEmpty, integral);
+
+            // Now throw Gaussian randoms above a threshold and put signals on
+            // unoccopied channels
+            for (int ithrow = 0; ithrow < nChannelsThrow; ithrow++) {
+
+                // Throw to get a channel number
+                List<Integer> neighborList = new ArrayList<Integer>(neighbors);
+
+                int channel = neighborList.get(random.nextInt(nElectrodesEmpty));
+
+                while (electrodeDataCol.keySet().contains(channel)) {
+                    channel = neighborList.get(random.nextInt(nElectrodesEmpty));
+
+                }
+
+                // Calculate the noise for this channel in units of electrons
+                double noise = apv25.getChannel().computeNoise(
+                        electrodes.getCapacitance(channel));
+
+                // Throw Gaussian above threshold
+                int charge = (int) Math.round(drawGaussianAboveThreshold(integral) * noise);
+
+                // Add the noise hit to the electrode data collection
+                electrodeDataCol.add(channel, new SiElectrodeData(charge));
+            }
+        }
+    }
+
+    /**
+     * 
+     */
+    public static int drawBinomial(int ntrials, double probability) {
+        binomial.setNumberOfTrials(ntrials);
+        binomial.setProbabilityOfSuccess(probability);
+
+        int nsuccess = 0;
+        try {
+            nsuccess = binomial.inverseCumulativeProbability(random.nextDouble());
+        } catch (MathException exception) {
+            throw new RuntimeException("APV25 failed to calculate inverse cumulative probability of binomial!");
+        }
+        return nsuccess;
+    }
+
+    /**
+     * Return a random variable following normal distribution, but beyond
+     * threshold provided during initialization.
+     */
+    public static double drawGaussianAboveThreshold(double prob_above_threshold) {
+        double cumulative_probability;
+
+        cumulative_probability = 1.0 + prob_above_threshold * (random.nextDouble() - 1.0);
+
+        assert cumulative_probability < 1.0 : "cumulProb=" + cumulative_probability + ", probAboveThreshold=" + prob_above_threshold;
+        assert cumulative_probability >= 0.0 : "cumulProb=" + cumulative_probability + ", probAboveThreshold=" + prob_above_threshold;
+
+        double gaussian_random = 0;
+        try {
+            gaussian_random = gaussian.inverseCumulativeProbability(cumulative_probability);
+        } catch (MathException e) {
+            System.out.println("MathException caught: " + e);
+        }
+
+        return gaussian_random;
+    }
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking/apv25
RearTransitionModule.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/apv25/RearTransitionModule.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/apv25/RearTransitionModule.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,135 @@
+package org.hps.recon.tracking.apv25;
+
+//--- java ---//
+//--- Constants ---//
+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;
+//--- org.lcsim ---//
+import org.lcsim.event.EventHeader;
+import org.lcsim.hps.util.RandomGaussian;
+import org.lcsim.util.Driver;
+//--- hps-java ---//
+
+/**
+ * 
+ * @author Omar Moreno <[log in to unmask]>
+ * @version $Id: RearTransitionModule.java,v 1.2 2013/04/25 22:11:14 meeg Exp $
+ */
+public class RearTransitionModule extends Driver {
+
+    String apv25AnalogDataCollectionName = "APV25AnalogData";
+    String apv25DigitalDataCollectionName = "AVP25DigitalData";
+
+    double adcVHighRef = 1000;   // mVolts
+    double adcVLowRef = -1000;   // mVolts
+    int    adcResolution = 14;   // bits
+    double adcVoltageResolution = 1;  // mV
+    int quantizationLevels = 256; 
+
+    double resistorValue = 100;  // Ohms
+    double inputStageGain = 1.5;
+    
+    boolean noiseless = false;
+
+    /**
+     * Default Ctor
+     */
+    public RearTransitionModule(){
+
+        // Find the number of quantization levels
+        int quantizationLevels = (int) Math.pow(2, adcResolution);
+
+        // Find the ADC voltage resolution
+        adcVoltageResolution = (adcVHighRef - adcVLowRef)/quantizationLevels; // mV
+    }    
+
+    /**
+     * 
+     */
+    public void setResolution(int bits){
+        adcResolution = bits;
+
+        // Find the number of quantization levels
+        quantizationLevels = (int) Math.pow(2, adcResolution);
+
+
+        // Find the ADC voltage resolution
+        adcVoltageResolution = (adcVHighRef - adcVLowRef)/quantizationLevels; // mV
+    }
+
+    /**
+     * 
+     */
+    public void setADCSpan(double adcVHighRef, double adcVLowRef){
+        this.adcVHighRef = adcVHighRef;
+        this.adcVLowRef = adcVLowRef;
+
+        // Find the ADC voltage resolution
+        adcVoltageResolution = (adcVHighRef - adcVLowRef)/quantizationLevels; // mV
+    }
+    
+    /**
+     * Turn readout noise on/off
+     */
+    public void setNoiseless(boolean noiseless){
+        this.noiseless = noiseless;
+    }
+
+    /**
+     * 
+     */
+    @Override
+        protected void process(EventHeader event){
+            super.process(event);
+
+            // If the event does not contain any analog data that needs to be digitized, skip the event
+            if(!event.hasCollection(Apv25AnalogData.class, apv25AnalogDataCollectionName)) return;
+
+            // Get the analog data from the event
+            List<Apv25AnalogData> analogData = event.get(Apv25AnalogData.class, apv25AnalogDataCollectionName);
+
+            // Create a list hold the digital data
+            List<Apv25DigitalData> digitalData = new ArrayList<Apv25DigitalData>();
+
+            // Amplify the analog data
+            for(Apv25AnalogData analogDatum : analogData){
+
+                // Make a hard copy of the APV25 analog output to avoid modification of the original
+                double[] apv25Output = new double[140];
+                System.arraycopy(analogDatum.getApv25AnalogOutput(), 0, apv25Output, 0, apv25Output.length);        
+
+                for(int index = 0; index < apv25Output.length; index++){
+
+                    // For now, don't digitize the header
+                    if(index < 12) continue;
+
+                    // Get the physical channel 
+                    int physicalChannel = TOTAL_STRIPS_PER_SENSOR 
+                        - (analogDatum.getApvNumber()*HPSSVTConstants.CHANNELS + (HPSSVTConstants.CHANNELS - 1) - (index - 12));
+
+                    apv25Output[index] += 4; // mA
+                    apv25Output[index] *= (HPSSVTConstants.MIP/HPSSVTConstants.MULTIPLEXER_GAIN);
+
+                    // Digitize the signal 
+                    apv25Output[index] *= HPSSVTCalibrationConstants.getGain(analogDatum.getSensor(), physicalChannel);
+
+                    // Add pedestal and noise
+                    double pedestal = HPSSVTCalibrationConstants.getPedestal(analogDatum.getSensor(), physicalChannel);
+                    double noise = HPSSVTCalibrationConstants.getNoise(analogDatum.getSensor(), physicalChannel);
+                    if(!noiseless)
+                        apv25Output[index] += RandomGaussian.getGaussian(pedestal, noise);            
+                    else
+                        apv25Output[index] += pedestal;
+                }
+
+                // Add the digital data to the list
+                digitalData.add(new Apv25DigitalData(analogDatum.getSensor(), analogDatum.getApvNumber(), apv25Output));
+            }
+
+            event.put(apv25DigitalDataCollectionName, digitalData, Apv25DigitalData.class, 0);
+        }
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking/apv25
SvtHalfModule.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/apv25/SvtHalfModule.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/apv25/SvtHalfModule.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,59 @@
+package org.hps.recon.tracking.apv25;
+
+//--- constants ---//
+import static org.hps.conditions.deprecated.HPSSVTConstants.TOTAL_APV25_PER_HYBRID;
+
+import org.hps.conditions.deprecated.HPSSVTCalibrationConstants;
+import org.hps.conditions.deprecated.HPSSVTConstants;
+//--- lcsim ---//
+import org.lcsim.detector.tracker.silicon.SiSensor;
+
+/**
+ * 
+ * @author Omar Moreno
+ * @version $Id: SvtHalfModule.java,v 1.7 2013/04/25 22:11:14 meeg Exp $
+ */
+public class SvtHalfModule {
+
+    private SiSensor sensor;
+    private Apv25Full[] apv25 = new Apv25Full[5];
+    
+    public SvtHalfModule(SiSensor sensor){
+        
+        // Set the sensor associated with this half-module
+        this.sensor = sensor;
+        
+        // Instantiate the APV25's
+        for(int chip = 0; chip < TOTAL_APV25_PER_HYBRID; chip++){
+            apv25[chip] = new Apv25Full();
+            for(int channel = 0; channel < HPSSVTConstants.CHANNELS; channel++){
+                int physicalChannel = 639 - (chip*128 + 127 - channel);
+                
+                // Mark all bad channels which were found during QA
+                if(HPSSVTCalibrationConstants.isBadChannel(sensor, physicalChannel)){
+                    apv25[chip].getChannel(channel).markAsBadChannel();
+                }
+
+                // Set the shaping time
+                double tp = HPSSVTCalibrationConstants.getTShaping(sensor, physicalChannel);
+                apv25[chip].getChannel(channel).setShapingTime(tp);
+            }
+        }
+    }
+    
+    public SiSensor getSensor(){
+        return sensor;
+    }
+    
+    public Apv25Full getAPV25(int physicalChannel){
+        return apv25[this.getAPV25Number(physicalChannel)];
+    }
+    
+    public int getAPV25Number(int physicalChannel){
+    	return (int) ((TOTAL_APV25_PER_HYBRID - 1) - Math.floor(physicalChannel/HPSSVTConstants.CHANNELS));
+    }
+    
+    public Apv25Full[] getAllApv25s(){
+        return apv25;
+    }
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking/apv25
SvtReadout.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/apv25/SvtReadout.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/apv25/SvtReadout.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,318 @@
+
+package org.hps.recon.tracking.apv25;
+
+//--- java ---//
+import static org.hps.conditions.deprecated.HPSSVTConstants.TOTAL_APV25_CHANNELS;
+import static org.hps.conditions.deprecated.HPSSVTConstants.TOTAL_NUMBER_OF_SAMPLES;
+import static org.hps.conditions.deprecated.HPSSVTConstants.TOTAL_STRIPS_PER_SENSOR;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Queue;
+import java.util.Set;
+
+import org.hps.conditions.deprecated.HPSSVTConstants;
+import org.hps.conditions.deprecated.SvtUtils;
+//--- lcsim ---//
+import org.lcsim.detector.tracker.silicon.ChargeCarrier;
+import org.lcsim.detector.tracker.silicon.SiSensor;
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.RawTrackerHit;
+import org.lcsim.geometry.Detector;
+import org.lcsim.hps.util.ClockSingleton;
+import org.lcsim.recon.tracking.digitization.sisim.CDFSiSensorSim;
+import org.lcsim.recon.tracking.digitization.sisim.SiElectrodeData;
+import org.lcsim.recon.tracking.digitization.sisim.SiElectrodeDataCollection;
+import org.lcsim.recon.tracking.digitization.sisim.SiSensorSim;
+import org.lcsim.recon.tracking.digitization.sisim.config.SimTrackerHitReadoutDriver;
+import org.lcsim.util.Driver;
+//--- Constants ---//
+//--- hps-java ---//
+
+/**
+ * 
+ * @author Omar Moreno <[log in to unmask]>
+ * @version $Id: SvtReadout.java,v 1.12 2013/04/25 22:11:14 meeg Exp $
+ */
+public class SvtReadout extends Driver {
+
+    private Set<SvtHalfModule> halfModules = new HashSet<SvtHalfModule>();
+    private SiSensorSim siSimulation = new CDFSiSensorSim(); 
+    SimTrackerHitReadoutDriver readout = null;
+    // FIFO queue used to store readout times
+    private Queue<Double> fifo = new LinkedList<Double>();
+    
+    List<String> readouts = new ArrayList<String>();
+    Map<SiSensor, List<Integer>> sensorToChannel = new HashMap<SiSensor, List<Integer>>();
+    
+    // Assuming at 41.6 MHz clock, minimum readout time per sample is 3.36 us
+    // For now, a dead time of 250 ns is fine
+    double readoutDeadTimePerSample = 250; // ns
+    double lastTriggerTime = 0;
+    
+    static private int nTriggers = 0;
+    int nTriggersDropped = 0;
+    int triggerLatencyTime = 0; // ns
+    int eventNumber = 0;
+    
+    boolean debug = false;
+    boolean pedestalRun = false;
+    
+    // Collection Names
+    String apv25AnalogDataCollectioName = "APV25AnalogData";
+    String simTrackerHitCollectionName = "TrackerHits";
+    
+    /**
+     * Default Ctor
+     */
+    public SvtReadout(){
+    }
+    
+    /**
+     * 
+     */
+    public void setDebug(boolean debug){
+    	this.debug = debug;
+    }
+    
+    /**
+     * 
+     */
+    public void setPedestalRun(boolean pedestalRun){
+    	this.pedestalRun = pedestalRun;
+    }
+    
+    /**
+     * 
+     */
+    public void setTriggerLatencyTime(int triggerLatencyTime /* ns */){
+    	this.triggerLatencyTime = triggerLatencyTime;
+    }
+    
+    /**
+     * 
+     */
+    static public int getNumberOfTriggers(){
+    	return nTriggers;
+    }
+    
+    /**
+     * 
+     */
+    public void setReadoutDeadTime(int readoutDeadTimePerSample){
+    	this.readoutDeadTimePerSample = readoutDeadTimePerSample;
+    }
+    
+    /**
+     * Set the SimTrackerHit collection name
+     */
+    public void setSimTrackerHitCollectionName(String simTrackerHitCollectionName){
+        this.simTrackerHitCollectionName = simTrackerHitCollectionName;
+    }
+    
+    /**
+     * 
+     */
+    @Override
+    public void detectorChanged(Detector detector){
+        super.detectorChanged(detector);
+        
+        // Instantiate all SVT Half modules
+        for(SiSensor sensor : SvtUtils.getInstance().getSensors()){
+            halfModules.add(new SvtHalfModule(sensor));
+        }
+        
+        // Set the trigger latency
+        for(SvtHalfModule halfModule : halfModules){
+        	for(Apv25Full apv : halfModule.getAllApv25s()){
+        		apv.setLatency(triggerLatencyTime);
+        	}
+        	sensorToChannel.put(halfModule.getSensor(), new ArrayList<Integer>());
+        }
+        
+    	// Load the driver which transfers SimTrackerHits to their 
+    	// corresponding sensor readout
+        if(readout == null){
+        	add(new SimTrackerHitReadoutDriver(readouts));
+        }
+    }
+    
+    /**
+     * 
+     */
+    @Override
+    public void process(EventHeader event){
+        super.process(event);
+        
+        eventNumber++;
+        
+        // Increment all trigger pointer and writer positions when necessary
+        if((ClockSingleton.getTime() + ClockSingleton.getDt()) % HPSSVTConstants.SAMPLING_INTERVAL == 0){
+        	for(SvtHalfModule halfModule : halfModules){
+                for(Apv25Full apv : halfModule.getAllApv25s()){
+                	apv.incrementPointerPositions();
+                }
+            }
+        }
+        
+        // Create a list to hold the analog data
+        List<Apv25AnalogData> analogData = new ArrayList<Apv25AnalogData>();
+
+        // Loop over all half-modules, perform charge deposition simulation and read them out
+        for(SvtHalfModule halfModule : halfModules){
+            this.readoutSensor(halfModule);
+        }
+            
+        // If an Ecal trigger is received, readout six samples from each APV25
+        if(Apv25Full.readoutBit){
+
+            nTriggers++;
+            Apv25Full.readoutBit = false;
+
+            // An APV25 cannot receive a trigger while it's still reading out samples; 
+            // drop the trigger 
+            if(ClockSingleton.getTime() >= (lastTriggerTime + readoutDeadTimePerSample*TOTAL_NUMBER_OF_SAMPLES)){
+            
+            	if(debug) System.out.println(this.getClass().getSimpleName() + ": APVs have been triggered on event " + eventNumber);
+            	
+                lastTriggerTime = ClockSingleton.getTime();
+            
+                for(int sample = 0; sample < TOTAL_NUMBER_OF_SAMPLES; sample++){
+                
+                    // Add the time at which each of the six samples should be collected 
+                    // the trigger queue
+                    fifo.offer(ClockSingleton.getTime() + sample*24);
+                }
+            } else {
+            	if(debug) System.out.println(this.getClass().getSimpleName() + ": Trigger has been dropped!");
+                //make an empty hit collection to make the DAQ happy
+                //TODO: block the event builder from making an event
+                event.put("SVTRawTrackerHits", new ArrayList<RawTrackerHit>(), RawTrackerHit.class, 0);
+            	nTriggersDropped++;
+            	nTriggers--;
+            }
+        }
+
+        // Process any triggers in the queue
+        if(fifo.peek() != null){
+            
+            if(fifo.peek() == ClockSingleton.getTime()){
+
+            	// Clear the analog data and readout all APV25's
+                analogData.addAll(this.readoutAPV25s());
+                fifo.remove();
+            }
+        }
+
+        if(!analogData.isEmpty())
+            event.put(apv25AnalogDataCollectioName, analogData, Apv25AnalogData.class, 0);
+    }
+    
+    /**
+     * Readout the electrodes of an HPS Si sensor and inject the charge into 
+     * the APV25 readout chip.
+     * 
+     * @param halfModule : SVT Half Module
+     */
+    public void readoutSensor(SvtHalfModule halfModule){
+        
+        // Set the sensor to be used in the charge deposition simulation
+        siSimulation.setSensor(halfModule.getSensor());
+        
+        // Perform the charge deposition simulation
+        Map<ChargeCarrier, SiElectrodeDataCollection> electrodeDataMap = siSimulation.computeElectrodeData();
+        
+        for (ChargeCarrier carrier : ChargeCarrier.values()) {
+            
+            // If the sensor is capable of collecting the given charge carrier
+            // then obtain the electrode data for the sensor
+            if (halfModule.getSensor().hasElectrodesOnSide(carrier)) {
+                
+                SiElectrodeDataCollection electrodeDataCol = electrodeDataMap.get(carrier);
+                
+                // If there is no electrode data available create a new instance of electrode data
+                if (electrodeDataCol == null) {
+                    electrodeDataCol = new SiElectrodeDataCollection();
+                }
+                
+                // Loop over all sensor channels
+                for(Integer physicalChannel : electrodeDataCol.keySet()){
+                    
+                    // find the APV channel number from the physical channel
+                    int channel = physicalChannel - TOTAL_STRIPS_PER_SENSOR
+                            + halfModule.getAPV25Number(physicalChannel)*TOTAL_APV25_CHANNELS + (TOTAL_APV25_CHANNELS - 1); 
+                    
+                    // Only inject charge if the channels isn't considered bad
+                    if(halfModule.getAPV25(physicalChannel).getChannel(channel).isBadChannel()) continue;
+                    
+                    // Get the electrode data for this channel
+                    SiElectrodeData electrodeData = electrodeDataCol.get(physicalChannel);
+                    
+                    // Get the charge in units of electrons
+                    double charge = pedestalRun ? 0 : electrodeData.getCharge();
+                    
+                    if(debug){
+                        if(charge > 0){ 
+                        	System.out.println(this.getClass().getSimpleName() 
+                        		+ ": Sensor: " + SvtUtils.getInstance().getDescription(halfModule.getSensor()) 
+                        		+ ": Injecting charge " + charge + " into channel " + physicalChannel);
+                        	sensorToChannel.get(halfModule.getSensor()).add(physicalChannel);
+                        }
+                    }
+                    
+                    // Inject the charge into the APV25 amplifier chain
+                    halfModule.getAPV25(physicalChannel).injectCharge(channel, charge);
+                }
+            }
+        }
+        
+        // Clear the sensors of all deposited charge
+        siSimulation.clearReadout();
+    }
+    
+    /**
+     * 
+     */
+    public List<Apv25AnalogData> readoutAPV25s(){
+        
+        // Create a list to hold the analog data
+        List<Apv25AnalogData> analogData = new ArrayList<Apv25AnalogData>();
+
+        for(SvtHalfModule halfModule : halfModules){
+            
+            // Get the sensor associated with this half-module
+            SiSensor sensor = halfModule.getSensor();
+            
+            // Get all of the APVs associated with the sensor
+            Apv25Full[] apv25 = halfModule.getAllApv25s();
+        
+            if(debug){
+            	for(int physicalChannel = 0; physicalChannel < TOTAL_APV25_CHANNELS; physicalChannel++){
+            		if(sensorToChannel.get(halfModule.getSensor()).contains(physicalChannel)){
+            			int channel = physicalChannel - TOTAL_STRIPS_PER_SENSOR
+                                + halfModule.getAPV25Number(physicalChannel)*TOTAL_APV25_CHANNELS + (TOTAL_APV25_CHANNELS - 1); 
+            			System.out.println("\nPhysical Channel: " + physicalChannel 
+            					+ " Sensor: " + SvtUtils.getInstance().getDescription(halfModule.getSensor())
+            					+ apv25[halfModule.getAPV25Number(physicalChannel)].getChannel(channel).getPipeline().toString() + "\n");
+            		}
+            	}
+            }
+
+            // Readout all APV25's 
+            for(int apvN = 0; apvN < apv25.length; apvN++){
+                Apv25AnalogData analogDatum = apv25[apvN].readOut();
+                analogDatum.setSensor(sensor);
+                analogDatum.setApv(apvN);
+                analogData.add(analogDatum);
+
+            }
+            sensorToChannel.get(halfModule.getSensor()).clear();
+        }
+        
+        return analogData;
+    }
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking/apv25
TestRunDataProcessingModule.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/apv25/TestRunDataProcessingModule.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/apv25/TestRunDataProcessingModule.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,134 @@
+package org.hps.recon.tracking.apv25;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.hps.conditions.deprecated.HPSSVTCalibrationConstants;
+import org.lcsim.detector.IReadout;
+import org.lcsim.detector.tracker.silicon.ChargeCarrier;
+import org.lcsim.detector.tracker.silicon.SiSensor;
+import org.lcsim.event.RawTrackerHit;
+import org.lcsim.event.SimTrackerHit;
+import org.lcsim.event.base.BaseRawTrackerHit;
+
+
+/**
+ * 
+ * @author Omar Moreno <[log in to unmask]>
+ * @version $Id: TestRunDataProcessingModule.java,v 1.1 2013/03/15 21:05:28 meeg Exp $
+ */
+public class TestRunDataProcessingModule extends DataProcessingModule {
+
+    int nSamplesAboveThreshold = 1;    // Number of samples above noise threshold 
+    int noiseThreshold = 3;            // Units of RMS noise
+
+    boolean enablePileUpCut = true;
+    boolean enableThresholdCut = true;
+
+    /**
+     * Default Ctor
+     */
+    public TestRunDataProcessingModule(){
+    };
+
+    /**
+     * 
+     */
+    public void setNumberOfSamplesAboveThreshold(int nSamplesAboveThreshold){
+        this.nSamplesAboveThreshold = nSamplesAboveThreshold;
+    }
+
+    /**
+     * 
+     */
+    public void setNoiseThreshold(int noiseThreshold /* Noise RMS */){
+        this.noiseThreshold = noiseThreshold;
+    }
+
+    /**
+     *
+     */
+    public void setEnablePileUpCut(boolean enablePileUpCut){
+        this.enablePileUpCut = enablePileUpCut;
+    }
+
+    /**
+     *
+     */
+    public void setEnableThresholdCut(boolean enableThresholdCut){
+        this.enableThresholdCut = enableThresholdCut;
+    }
+
+    protected List<RawTrackerHit> findRawHits(){
+
+        List<RawTrackerHit> rawHits = new ArrayList<RawTrackerHit>();
+
+        // Loop through all blocked data
+        for(Map.Entry<SiSensor, SvtDataBlocks> sensor : sensorToDataBlocks.entrySet()){
+
+            SvtDataBlocks blocks = sensor.getValue();
+
+            for(int channel = 0; channel < 639; channel++){
+            	
+            	if(HPSSVTCalibrationConstants.isBadChannel(sensor.getKey(), channel)) continue;
+            	
+                short[] samples = blocks.getSamples(channel);  
+
+                if(enableThresholdCut && !this.samplesAboveThreshold(sensor.getKey(), channel, samples)) continue;
+
+                if(enablePileUpCut && !this.pileUpCut(samples)) continue;
+
+                // Create a RawTrackerHit
+                int sideNumber;
+                int time = 0;
+                if(sensor.getKey().hasElectrodesOnSide(ChargeCarrier.HOLE)){
+                    sideNumber = ChargeCarrier.HOLE.charge();
+                } else {
+                    sideNumber = ChargeCarrier.ELECTRON.charge();
+                }
+                long cellID = sensor.getKey().makeStripId(channel, sideNumber).getValue();
+                RawTrackerHit rawHit = new BaseRawTrackerHit(time, cellID, samples, new ArrayList<SimTrackerHit>(), sensor.getKey());
+                rawHits.add(rawHit);
+                
+                // Add the raw hit to the sensor readout
+        		IReadout readOut = sensor.getKey().getReadout();
+        		readOut.addHit(rawHit);
+            }
+        }
+
+        System.out.println(this.getClass().getSimpleName() + ": Number of RawTrackerHits created: " + rawHits.size());
+        return rawHits;
+    }
+
+    /**
+     * 
+     */
+    private boolean samplesAboveThreshold(SiSensor sensor, int channel, short[] samples){
+        // Number of samples above threshold
+        int nSamplesAboveThreshold = 0;
+
+        // Get the pedestal and noise for this channel
+        double pedestal = HPSSVTCalibrationConstants.getPedestal(sensor, channel);
+        double noise = HPSSVTCalibrationConstants.getNoise(sensor, channel);
+
+        // Calculate the threshold
+        int threshold = (int) (pedestal + noise*this.noiseThreshold);
+
+        for(int index = 0; index < 6; index++){
+            if(samples[index] >= threshold) nSamplesAboveThreshold++;
+        }
+
+        // If the prerequisite number of samples are above threshold return true
+        if(nSamplesAboveThreshold >= this.nSamplesAboveThreshold ) return true;
+        return false;
+    }
+
+    /**
+     *
+     */
+    private boolean pileUpCut(short[] sample){
+        if(sample[2] > sample[1] || sample[3] > sample[2]) return true;
+        return false; 
+    }
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking/gbl
GBLEventData.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/gbl/GBLEventData.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/gbl/GBLEventData.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,89 @@
+package org.hps.recon.tracking.gbl;
+
+import org.lcsim.event.GenericObject;
+
+public class GBLEventData implements GenericObject {
+	
+	/*
+	 * 
+	 * Interface enumerator to access the correct data
+	 * 
+	 */
+	private static class GBLINT {
+		public static final int RUNNR = 0;
+		public static final int BANK_INT_SIZE = 1;
+	}
+	private static class GBLDOUBLE {
+		public static final int BFIELD = 0;
+		public static final int BANK_DOUBLE_SIZE = 1;
+	}
+	// array holding the integer data
+	private int bank_int[] = new int[GBLINT.BANK_INT_SIZE];
+	private double bank_double[] = new double[GBLDOUBLE.BANK_DOUBLE_SIZE];
+	
+
+	/**
+	 * Constructor with event number as parameter
+	 * @param eventNumber the event number
+	 * 
+	 */
+	public GBLEventData(int eventNumber,double Bz) {
+		setRunNr(eventNumber);
+		setBfield(Bz);
+	}
+	
+	public void setRunNr(int val) {
+		bank_int[GBLINT.RUNNR] = val;
+	}
+	
+	public int getRunNr() {
+		return this.getIntVal(GBLINT.RUNNR);
+	}
+	
+	public void setBfield(double val) {
+		bank_double[GBLDOUBLE.BFIELD] = val;
+	}
+	
+	public double getBfield() {
+		return this.getDoubleVal(GBLDOUBLE.BFIELD);
+	}
+	
+	
+	@Override
+	public int getNInt() {
+		return GBLINT.BANK_INT_SIZE;
+	}
+
+	@Override
+	public int getNFloat() {
+		return 0;
+	}
+
+	@Override
+	public int getNDouble() {
+		return GBLDOUBLE.BANK_DOUBLE_SIZE;
+	}
+
+	@Override
+	public int getIntVal(int index) {
+		return bank_int[index];
+	}
+
+	@Override
+	public float getFloatVal(int index) {
+		// TODO Auto-generated method stub
+		return 0;
+	}
+
+	@Override
+	public double getDoubleVal(int index) {
+		return bank_double[index];
+	}
+
+	@Override
+	public boolean isFixedSize() {
+		// TODO Auto-generated method stub
+		return false;
+	}
+
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking/gbl
GBLFileIO.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/gbl/GBLFileIO.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/gbl/GBLFileIO.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,255 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.hps.recon.tracking.gbl;
+
+import hep.physics.matrix.BasicMatrix;
+import hep.physics.matrix.SymmetricMatrix;
+import hep.physics.vec.Hep3Matrix;
+import hep.physics.vec.Hep3Vector;
+
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.hps.recon.tracking.RunAlignment;
+import org.hps.recon.tracking.gbl.GBLOutput.ClParams;
+import org.hps.recon.tracking.gbl.GBLOutput.PerigeeParams;
+import org.lcsim.fit.helicaltrack.HelicalTrackFit;
+
+/**
+ * Handles text file printing for the GBL text file
+ * @author Per Hansson Adrian <[log in to unmask]>
+ * @version $Id: GBLFileIO.java,v 1.9 2013/11/07 03:54:58 phansson Exp $ $Date: 2013/11/07 03:54:58 $ $Author: phansson $ 
+ */
+public class GBLFileIO {
+
+    PrintWriter _pWriter;
+    FileWriter _fWriter;
+    
+    GBLFileIO(String fileName) {
+        openFile(fileName);    
+    }
+    
+    public void printEventInfo(int evtnr, double Bz) {
+        addLine(String.format("New Event %d %.12f", evtnr, Bz));
+    }
+    
+    protected void addLine(String line) {
+        this._pWriter.println(line);
+    }
+
+    public void closeFile() {
+        try {
+            _pWriter.close();
+            _fWriter.close();
+        } catch(IOException ex) {
+             Logger.getLogger(RunAlignment.class.getName()).log(Level.SEVERE, null, ex);
+        }
+    }
+    private void openFile(String fileName) {
+    	if(fileName.equalsIgnoreCase("")) {
+    		System.out.printf("%s: no file name specified \n", this.getClass().getSimpleName());
+    		System.exit(1);
+    	}
+    	try {
+            _fWriter = new FileWriter(fileName);
+            _pWriter = new PrintWriter(_fWriter);
+        } catch (IOException ex) {
+            Logger.getLogger(RunAlignment.class.getName()).log(Level.SEVERE, null, ex);
+        }
+    }
+
+    void printTrackID(int iTrack) {
+        addLine(String.format("New Track %d", iTrack));
+    }
+
+    void printOldPerTrackParam(HelicalTrackFit htf) {
+        addLine(String.format("Track perPar (R phi0 slope d0 z0) %.12f %.12f %.12f %.12f %.12f",htf.R(),htf.phi0(),htf.slope(),htf.dca(),htf.z0()));
+    }
+    
+    String getPerTrackParamStr(PerigeeParams perPar) {
+        return String.format("Track perPar (R theta phi d0 z0) %.12f %.12f %.12f %.12f %.12f",1.0/perPar.getKappa(),perPar.getTheta(),perPar.getPhi(),perPar.getD0(),perPar.getZ0());
+    }
+    
+    void printPerTrackParam(PerigeeParams perPar) {
+        addLine(this.getPerTrackParamStr(perPar));
+    }
+
+    String getPerTrackParamTruthStr(PerigeeParams perPar) {
+        return String.format("Truth perPar (kappa theta phi d0 z0) %.12f %.12f %.12f %.12f %.12f",perPar.getKappa(),perPar.getTheta(),perPar.getPhi(),perPar.getD0(),perPar.getZ0());
+    }
+
+    void printPerTrackParamTruth(PerigeeParams perPar) {
+        addLine(this.getPerTrackParamTruthStr(perPar));
+    }
+
+    String getClTrackParamTruthStr(ClParams perPar) {
+        return String.format("Truth clPar (q/p lambda phi xT yT) %.12f %.12f %.12f %.12f %.12f",perPar.getQoverP(),perPar.getLambda(),perPar.getPhi(),perPar.getXt(),perPar.getYt());
+    }
+
+    void printClTrackParamTruth(ClParams perPar) {
+        addLine(this.getClTrackParamTruthStr(perPar));
+    }
+
+    String getClTrackParamStr(ClParams perPar) {
+        return String.format("Track clPar (q/p lambda phi xT yT) %.12f %.12f %.12f %.12f %.12f",perPar.getQoverP(),perPar.getLambda(),perPar.getPhi(),perPar.getXt(),perPar.getYt());
+    }
+    void printClTrackParam(ClParams perPar) {
+        addLine(String.format("%s",this.getClTrackParamStr(perPar)));
+    }
+
+    void printNrHits(int n) {
+        addLine(String.format("Track nr hits <%d>",n));
+    }
+    
+    void printStripJacPointToPoint(int id, int layer, double s, BasicMatrix jac) {
+        String str = String.format("Strip id <%d> layer <%d> s <%.10f> jac <",id,layer,s);
+        for(int r=0;r<jac.getNRows();++r) {
+            for(int c=0;c<jac.getNColumns();++c) {
+                str += String.format("%.10f ", jac.e(r, c));
+            }
+        }
+        str += ">";
+        addLine(str);
+    }
+
+    
+    void printStripScatJacPointToPoint(int id, int layer, double s, BasicMatrix jac) {
+        String str = String.format("Strip scat id <%d> layer <%d> s <%.10f> jac <",id,layer,s);
+        for(int r=0;r<jac.getNRows();++r) {
+            for(int c=0;c<jac.getNColumns();++c) {
+                str += String.format("%.10f ", jac.e(r, c));
+            }
+        }
+        str += ">";
+        addLine(str);
+    }
+
+    void printStripL2m(int id, int layer, double s, BasicMatrix jac) {
+        String str = String.format("Strip LocalToMeas id <%d> layer <%d> s <%.10f> L2m <",id,layer,s);
+        for(int r=0;r<jac.getNRows();++r) {
+            for(int c=0;c<jac.getNColumns();++c) {
+                str += String.format("%.10f ", jac.e(r, c));
+            }
+        }
+        str += ">";
+        addLine(str);
+    }
+
+    void printPerTrackCov(HelicalTrackFit htf) {
+        String str = "Track perCov (idx: dca,phi0,curv,z0,slope) ";
+        SymmetricMatrix cov = htf.covariance();
+        for(int irow=0;irow<cov.getNRows();++irow) {
+            for(int icol=0;icol<cov.getNColumns();++icol) {
+                str += String.format("%e ", cov.e(irow, icol));
+            }    
+        }
+        addLine(str);
+    }
+
+    void printCLTrackCov(BasicMatrix cov) {
+        String str = "Track clCov ";
+        for(int irow=0;irow<cov.getNRows();++irow) {
+            for(int icol=0;icol<cov.getNColumns();++icol) {
+                str += String.format("%.10f ", cov.e(irow, icol));
+            }    
+        }
+        addLine(str);
+    }
+
+    
+    void printStripTrackDir(double sinPhi, double sinLambda) {
+        String str = String.format("Strip sinPhi sinLambda %.10f %.10f",sinPhi,sinLambda);
+        addLine(str);
+    }
+    
+    void printStripTrackDirFull(Hep3Vector dir) {
+        addLine(String.format("Strip track dir %.10f %.10f %.10f",dir.x(),dir.y(),dir.z()));
+    }
+    
+    void printStripTrackPos(Hep3Vector pos) {
+        addLine(String.format("Strip track pos %.10f %.10f %.10f",pos.x(),pos.y(),pos.z()));
+    }
+
+    void printStrip(int id, int layer) {
+        addLine(String.format("New Strip id layer %d %d", id,layer));
+    }
+
+    void printStripPathLen(double s) {
+        addLine(String.format("Strip pathLen %.10f", s));
+    }
+
+     void printStripPathLen3D(double s) {
+        addLine(String.format("Strip pathLen3D %.10f", s));
+    }
+    
+    void printStereoAngle(double stereoAngle) {
+        addLine(String.format("Strip stereo angle %.10f", stereoAngle));
+    }
+
+    void printStripMeas(double u) {
+        addLine(String.format("Strip u %.10f", u));
+    }
+
+    void printStripMeasRes(double ures, double uresErr) {
+        addLine(String.format("Strip ures %.10f %.10f", ures, uresErr));
+    }
+
+    void printStripMeasResTruth(double ures, double uresErr) {
+        addLine(String.format("Strip truth ures %.10f %.10f", ures, uresErr));
+    }
+    
+    void printStripMeasResSimHit(double ures, double uresErr) {
+        addLine(String.format("Strip simhit ures %.10f %.10f", ures, uresErr));
+    }
+    
+    void printStripScat(double scatAngle) {
+        addLine(String.format("Strip scatangle %.10f",scatAngle));
+    }
+
+    void printMeasDir(Hep3Vector u) {
+        addLine(String.format("Strip meas dir %.10f %.10f %.10f", u.x(), u.y(), u.z()));
+    }
+
+    void printNonMeasDir(Hep3Vector u) {
+        addLine(String.format("Strip non-meas dir %.10f %.10f %.10f", u.x(), u.y(), u.z()));
+    }
+
+    void printNormalDir(Hep3Vector u) {
+        addLine(String.format("Strip normal dir %.10f %.10f %.10f", u.x(), u.y(), u.z()));
+    }
+
+    
+    void printMomentum(double p, double p_truth) {
+        addLine(String.format("Track mom %.10f %.10f", p, p_truth));
+    }
+
+    void printPerToClPrj(Hep3Matrix perToClPrj) {
+        String str = "Track perToClPrj ";
+        for(int irow=0;irow<perToClPrj.getNRows();++irow) {
+            for(int icol=0;icol<perToClPrj.getNColumns();++icol) {
+                str += String.format("%.10f ", perToClPrj.e(irow, icol));
+            }    
+        }
+        addLine(str);
+    }
+
+    void printChi2(double[] chisq, int[] ndf) {
+        addLine(String.format("Track chi2/ndf (circle,zfit) %.10f %d %.10f %d",chisq[0],ndf[0],chisq[1],ndf[1]));
+    }
+
+    void printOrigin(Hep3Vector pos) {
+        addLine(String.format("Strip origin pos %.10f %.10f %.10f",pos.x(),pos.y(),pos.z()));
+    }
+
+    void printHitPos3D(Hep3Vector pos) {
+        addLine(String.format("Strip 3D hit pos %.10f %.10f %.10f",pos.x(),pos.y(),pos.z()));
+    }
+
+
+
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking/gbl
GBLOutput.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/gbl/GBLOutput.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/gbl/GBLOutput.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,943 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.hps.recon.tracking.gbl;
+import hep.physics.matrix.BasicMatrix;
+import hep.physics.matrix.Matrix;
+import hep.physics.matrix.MatrixOp;
+import hep.physics.matrix.SymmetricMatrix;
+import hep.physics.vec.BasicHep3Matrix;
+import hep.physics.vec.BasicHep3Vector;
+import hep.physics.vec.Hep3Matrix;
+import hep.physics.vec.Hep3Vector;
+import hep.physics.vec.VecOp;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.hps.recon.tracking.HPSTransformations;
+import org.hps.recon.tracking.MaterialSupervisor;
+import org.hps.recon.tracking.MaterialSupervisor.DetectorPlane;
+import org.hps.recon.tracking.MaterialSupervisor.ScatteringDetectorVolume;
+import org.hps.recon.tracking.MultipleScattering;
+import org.hps.recon.tracking.MultipleScattering.ScatterPoint;
+import org.hps.recon.tracking.MultipleScattering.ScatterPoints;
+import org.hps.recon.tracking.TrackUtils;
+import org.hps.recon.tracking.TrackerHitUtils;
+import org.lcsim.constants.Constants;
+import org.lcsim.event.MCParticle;
+import org.lcsim.event.RawTrackerHit;
+import org.lcsim.event.SimTrackerHit;
+import org.lcsim.event.Track;
+import org.lcsim.event.TrackerHit;
+import org.lcsim.fit.helicaltrack.HelicalTrackCross;
+import org.lcsim.fit.helicaltrack.HelicalTrackFit;
+import org.lcsim.fit.helicaltrack.HelicalTrackHit;
+import org.lcsim.fit.helicaltrack.HelicalTrackStrip;
+import org.lcsim.fit.helicaltrack.HelixUtils;
+import org.lcsim.geometry.Detector;
+import org.lcsim.recon.tracking.seedtracker.ScatterAngle;
+import org.lcsim.recon.tracking.seedtracker.SeedCandidate;
+import org.lcsim.recon.tracking.seedtracker.SeedTrack;
+
+/**
+
+* 
+* @author Per Hansson Adrian <[log in to unmask]>
+* @version $Id: GBLOutput.java,v 1.17 2013/11/07 03:30:18 phansson Exp $ $Date: 2013/11/07 03:30:18 $ $Author: phansson $  
+* 
+*/
+/**
+ * @author phansson
+ *
+ */
+public class GBLOutput {
+    
+    private int _debug = 0;
+    private GBLFileIO textFile = null;
+    private Hep3Vector _B;
+	private TrackerHitUtils _trackerHitUtils = new TrackerHitUtils();
+    private MaterialSupervisor _materialmanager;
+    private MultipleScattering _scattering;
+    private double _beamEnergy = 2.2; //GeV
+	private boolean AprimeEvent = false; // do extra checks
+	private boolean hasXPlanes = false;
+    
+    
+
+    
+    /**
+     * Constructor
+     * @param outputFileName is the filename given to the text-based output file. If empty no output file is written
+     * @param bfield magnetic field in Tesla
+     */
+    GBLOutput(String outputFileName,Hep3Vector bfield) {
+    	System.out.printf("name \"%s\" \n", outputFileName);
+    	if(!outputFileName.equalsIgnoreCase("")) {
+    		textFile = new GBLFileIO(outputFileName);
+    	}
+        _materialmanager = new MaterialSupervisor();
+        _scattering = new MultipleScattering(_materialmanager);
+        _B = HPSTransformations.transformVectorToTracking(bfield);
+        _scattering.setBField(Math.abs(_B.z())); // only absolute of B is needed as it's used for momentum calculation only
+    }
+
+    public void setDebug(int debug) {
+        _debug = debug;
+        _scattering.setDebug(_debug>0?true:false);
+    }
+    public void buildModel(Detector detector) {
+        _materialmanager.buildModel(detector);
+    }
+    void printNewEvent(int eventNumber,double Bz) {
+    	if(textFile != null) {
+    		textFile.printEventInfo(eventNumber,Bz);
+    	}
+    }
+    void printTrackID(int iTrack) {
+    	if(textFile != null) {
+    		textFile.printTrackID(iTrack);
+    	}
+    }
+    void close() {
+    	if(textFile != null) {
+    		textFile.closeFile();
+    	}
+    }
+    void setAPrimeEventFlag(boolean flag) {
+    	this.AprimeEvent = flag;
+    }
+    void setXPlaneFlag(boolean flag) {
+    	this.hasXPlanes = flag;
+    }
+    public Hep3Vector get_B() {
+		return _B;
+	}
+	public void set_B(Hep3Vector _B) {
+		this._B = _B;
+	}
+
+
+    
+    void printGBL(Track trk, GBLTrackData gtd, List<GBLStripClusterData> stripClusterDataList, List<MCParticle> mcParticles, List<SimTrackerHit> simTrackerHits, boolean isMC) {
+
+        SeedTrack st = (SeedTrack)trk;
+        SeedCandidate seed = st.getSeedCandidate();
+        HelicalTrackFit htf = seed.getHelix();          
+
+        // Find scatter points along the path
+        ScatterPoints scatters = _scattering.FindHPSScatterPoints(htf);
+        
+        // Hits on track
+        List<HelicalTrackHit> hits = seed.getHits();
+
+        // Find the truth particle of the track
+        MCParticle mcp = null;
+        
+        if(isMC) {
+        	mcp = getMatchedTruthParticle(trk);
+        
+        	if(mcp==null) {
+        		System.out.printf("%s: no truth particle found in event!\n",this.getClass().getSimpleName());
+        		this.printMCParticles(mcParticles);
+        		System.exit(1);
+        	} else {
+        		if(_debug>0) System.out.printf("%s: truth particle (pdgif %d ) found in event!\n",this.getClass().getSimpleName(),mcp.getPDGID());
+        	}
+        
+        	if(AprimeEvent ) {
+        		checkAprimeTruth(mcp,mcParticles);
+        	}
+        }
+        
+        // Get track parameters from MC particle 
+        HelicalTrackFit htfTruth = isMC ? TrackUtils.getHTF(mcp,-1.0*this._B.z()) : null;
+        
+        // Use the truth helix as the initial track for GBL?
+        //htf = htfTruth;
+                
+        
+        // Get perigee parameters to curvilinear frame
+        PerigeeParams perPar = new PerigeeParams(htf);
+        PerigeeParams perParTruth = new PerigeeParams(htfTruth);
+        if(textFile != null) {
+        	textFile.printPerTrackParam(perPar);
+        	textFile.printPerTrackParamTruth(perParTruth);
+        }
+        
+        //GBLDATA
+        gtd.setPerigeeTrackParameters(perPar);
+
+        // Get curvilinear parameters
+        ClParams clPar = new ClParams(htf);
+        ClParams clParTruth = new ClParams(htfTruth);
+        if(textFile != null) {
+        	textFile.printClTrackParam(clPar);
+        	textFile.printClTrackParamTruth(clParTruth);
+        
+        	if(_debug>0) {
+        		System.out.printf("%s\n",textFile.getClTrackParamStr(clPar));
+        		System.out.printf("%s\n",textFile.getPerTrackParamStr(perPar));
+        	}
+        }
+        
+        
+        // find the projection from the I,J,K to U,V,T curvilinear coordinates
+        Hep3Matrix perToClPrj = getPerToClPrj(htf);
+        
+        if(textFile != null) {
+        	textFile.printPerToClPrj(perToClPrj);
+        }    
+        
+        //GBLDATA
+        for(int row=0; row<perToClPrj.getNRows();++row) {
+        	for(int col=0; col<perToClPrj.getNColumns();++col) {
+        		gtd.setPrjPerToCl(row, col, perToClPrj.e(row, col));
+        	}
+        }
+        
+        
+        
+        //GBLDATA
+        for(int row=0; row<perToClPrj.getNRows();++row) {
+        	for(int col=0; col<perToClPrj.getNColumns();++col) {
+        		gtd.setPrjPerToCl(row, col, perToClPrj.e(row, col));
+        	}
+        }
+        
+        
+        // print chi2 of fit
+        if(textFile != null) {
+        	textFile.printChi2(htf.chisq(),htf.ndf());
+        }
+        
+        // build map of layer to SimTrackerHits that belongs to the MC particle
+        Map<Integer, SimTrackerHit> simHitsLayerMap = new HashMap<Integer, SimTrackerHit >(); 
+        for (SimTrackerHit sh : simTrackerHits) {
+            if(sh.getMCParticle()==mcp) {
+            	int layer  = sh.getIdentifierFieldValue("layer");
+                if(!simHitsLayerMap.containsKey(layer) || (sh.getPathLength() < simHitsLayerMap.get(layer).getPathLength()) ) {
+                    simHitsLayerMap.put(layer, sh);
+                }
+            }
+        }
+        
+        
+        // covariance matrix from the fit
+        if(textFile != null) {
+        	textFile.printPerTrackCov(htf);
+        }
+        
+        // dummy cov matrix for CL parameters
+        BasicMatrix clCov = new BasicMatrix(5,5);
+        initUnit(clCov);
+        clCov = (BasicMatrix) MatrixOp.mult(0.1*0.1,clCov);
+        
+        if(textFile != null) {
+        	textFile.printCLTrackCov(clCov);
+        }
+        
+        if(_debug>0) {
+            System.out.printf("%s: perPar covariance matrix\n%s\n",this.getClass().getSimpleName(),htf.covariance().toString());
+            double chi2_truth = truthTrackFitChi2(perPar,perParTruth,htf.covariance());
+            System.out.printf("%s: truth perPar chi2 %f\n",this.getClass().getSimpleName(),chi2_truth);
+        }
+        
+        if(_debug>0) System.out.printf("%d hits\n",hits.size());
+        
+
+        int istrip = 0;
+        for(int ihit=0;ihit!=hits.size();++ihit) {
+            
+            HelicalTrackHit hit = hits.get(ihit);
+            HelicalTrackCross htc = (HelicalTrackCross) hit;
+            List<HelicalTrackStrip> strips = htc.getStrips();
+            
+            for(HelicalTrackStrip strip : strips) {
+                
+                if(_debug>0) System.out.printf("%s: layer %d\n",this.getClass().getSimpleName(),strip.layer());
+                
+                if(textFile != null) {
+                	textFile.printStrip(istrip,strip.layer());
+                }
+                
+                //GBLDATA
+                GBLStripClusterData stripData = new GBLStripClusterData(strip.layer());
+                //Add to output list
+                stripClusterDataList.add(stripData);
+                
+                
+                
+                //Center of the sensor
+                Hep3Vector origin = strip.origin();                
+                
+                if(textFile != null) {
+                	textFile.printOrigin(origin);
+                }
+                
+                // associated 3D position of the crossing of this and it's stereo partner sensor
+                if(textFile != null) {
+                	textFile.printHitPos3D(hit.getCorrectedPosition());
+                }
+                
+                //Find intercept point with sensor in tracking frame
+                Hep3Vector trkpos = TrackUtils.getHelixPlaneIntercept(htf, strip, Math.abs(_B.z()));
+                Hep3Vector trkposTruth = isMC ? TrackUtils.getHelixPlaneIntercept(htfTruth, strip, Math.abs(_B.z())) : new BasicHep3Vector(-999999.9,-999999.9,-999999.9);
+                if(textFile != null) {
+                	textFile.printStripTrackPos(trkpos);
+                }
+                if(_debug>0) {
+                	System.out.printf("trkpos at intercept [%.10f %.10f %.10f]\n",trkpos.x(),trkpos.y(),trkpos.z());
+                    System.out.printf("trkposTruth at intercept %s\n",trkposTruth.toString());
+                }
+                
+                // cross-check intercept point
+                if(hasXPlanes ) {
+                	Hep3Vector trkposXPlaneIter = TrackUtils.getHelixPlanePositionIter(htf, strip.origin(), strip.w(), 1.0e-8);
+	                Hep3Vector trkposDiff = VecOp.sub(trkposXPlaneIter, trkpos);
+	                if(trkposDiff.magnitude() > 1.0e-7) {
+	                	System.out.printf("WARNING trkposDiff mag = %.10f [%.10f %.10f %.10f]\n",trkposDiff.magnitude(),trkposDiff.x(),trkposDiff.y(),trkposDiff.z());
+	                	System.exit(1);
+	                }	
+	                if(_debug>0) System.out.printf("trkposXPlaneIter at intercept [%.10f %.10f %.10f]\n",trkposXPlaneIter.x(),trkposXPlaneIter.y(),trkposXPlaneIter.z());
+                }
+                
+                
+                // Find the sim tracker hit for this layer
+                SimTrackerHit simHit = simHitsLayerMap.get(strip.layer());
+
+                if( isMC ) {
+                	if(simHit==null) {
+                		System.out.printf("%s: no sim hit for strip hit at layer %d\n",this.getClass().getSimpleName(),strip.layer());
+                		System.out.printf("%s: it as %d mc particles associated with it:\n",this.getClass().getSimpleName(),hit.getMCParticles().size());
+                		for (MCParticle particle : hit.getMCParticles())  System.out.printf("%s: %d p %s \n",this.getClass().getSimpleName(),particle.getPDGID(),particle.getMomentum().toString());
+                		System.out.printf("%s: these are sim hits in the event:\n",this.getClass().getSimpleName());
+                		for (SimTrackerHit simhit : simTrackerHits) System.out.printf("%s sim hit at %s with MC particle pdgid %d with p %s \n",this.getClass().getSimpleName(),simhit.getPositionVec().toString(),simhit.getMCParticle().getPDGID(),simhit.getMCParticle().getMomentum().toString());
+                		System.out.printf("%s: these are all the MC particles in the event:\n",this.getClass().getSimpleName());
+                		System.exit(1);
+                	}
+
+                	if(_debug>0) {
+                		double s_truthSimHit = HelixUtils.PathToXPlane(htfTruth, simHit.getPositionVec().z(), 0, 0).get(0);
+                		Hep3Vector trkposTruthSimHit = HelixUtils.PointOnHelix(htfTruth, s_truthSimHit);
+                		Hep3Vector resTruthSimHit = VecOp.sub(HPSTransformations.transformVectorToTracking(simHit.getPositionVec()),trkposTruthSimHit);
+                		System.out.printf("TruthSimHit residual %s for layer %d\n",resTruthSimHit.toString(),strip.layer());
+                	}
+                }
+                
+                //path length to intercept
+                double s = HelixUtils.PathToXPlane(htf,trkpos.x(),0,0).get(0); 
+                double s3D = s / Math.cos(Math.atan(htf.slope()));
+                if(textFile != null) {
+                	textFile.printStripPathLen(s);
+                	textFile.printStripPathLen3D(s3D);
+                }
+                
+                //GBLDATA
+                stripData.setPath(s);
+                stripData.setPath3D(s3D);
+                
+                
+                
+                //print stereo angle in YZ plane
+                if(textFile != null) {
+                	textFile.printMeasDir(strip.u());
+                	textFile.printNonMeasDir(strip.v());
+                	textFile.printNormalDir(strip.w());
+                }
+                
+                //GBLDATA
+                stripData.setU(strip.u());
+                stripData.setV(strip.v());
+                stripData.setW(strip.w());
+                
+                
+                //Print track direction at intercept
+                Hep3Vector tDir = HelixUtils.Direction(htf, s);
+                double phi = htf.phi0() - s/htf.R();
+                double lambda = Math.atan(htf.slope());
+                if(textFile != null) {
+                	textFile.printStripTrackDir(Math.sin(phi),Math.sin(lambda));
+                	textFile.printStripTrackDirFull(tDir);
+                }
+                
+                //GBLDATA
+                stripData.setTrackDir(tDir);
+                stripData.setTrackPhi(phi);
+                stripData.setTrackLambda(lambda);
+                
+                
+                
+                
+                //Print residual in measurement system
+                
+                // start by find the distance vector between the center and the track position
+                Hep3Vector vdiffTrk = VecOp.sub(trkpos, origin);
+                Hep3Vector vdiffTrkTruth = VecOp.sub(trkposTruth, origin);
+                
+                // then find the rotation from tracking to measurement frame
+                Hep3Matrix trkToStripRot = _trackerHitUtils.getTrackToStripRotation(strip);
+                
+                // then rotate that vector into the measurement frame to get the predicted measurement position
+                Hep3Vector trkpos_meas = VecOp.mult(trkToStripRot, vdiffTrk);
+                Hep3Vector trkposTruth_meas = VecOp.mult(trkToStripRot, vdiffTrkTruth);
+                
+                
+                // hit measurement and uncertainty in measurement frame
+                Hep3Vector m_meas = new BasicHep3Vector(strip.umeas(),0.,0.);
+                Hep3Vector res_err_meas = new BasicHep3Vector(strip.du(),(strip.vmax() - strip.vmin()) / Math.sqrt(12),10.0/Math.sqrt(12));
+                
+                if(textFile != null) {
+                	textFile.printStripMeas(m_meas.x());
+                }
+                
+                //GBLDATA
+                stripData.setMeas(strip.umeas());
+                stripData.setTrackPos(trkpos_meas);
+                
+                // residual in measurement frame
+                Hep3Vector res_meas = VecOp.sub(m_meas, trkpos_meas);
+                Hep3Vector resTruth_meas = VecOp.sub(m_meas, trkposTruth_meas);
+                if(textFile != null) {
+                	textFile.printStripMeasRes(res_meas.x(),res_err_meas.x());
+                	textFile.printStripMeasResTruth(resTruth_meas.x(),res_err_meas.x());
+                }
+                
+                //GBLDATA
+                stripData.setMeasErr(res_err_meas.x());
+                
+                
+                
+                if(_debug>0) System.out.printf("layer %d uRes %.10f\n",strip.layer(),res_meas.x());
+                
+                // sim hit residual
+                
+                if(simHit!=null) { 
+                    Hep3Vector simHitPos = HPSTransformations.transformVectorToTracking(simHit.getPositionVec());
+                    if(_debug>0) System.out.printf("simHitPos  %s\n",simHitPos.toString());
+                    Hep3Vector vdiffSimHit = VecOp.sub(simHitPos, trkpos);
+                    Hep3Vector simHitPos_meas = VecOp.mult(trkToStripRot, vdiffSimHit);
+                    if(textFile != null) {
+                    	textFile.printStripMeasResSimHit(simHitPos_meas.x(),res_err_meas.x());
+                    }
+                } else {
+                	if(textFile != null) {
+                		textFile.printStripMeasResSimHit(-999999.9,-999999.9);
+                	}
+                }	
+                
+                // find scattering angle
+                ScatterPoint scatter = scatters.getScatterPoint(((RawTrackerHit)strip.rawhits().get(0)).getDetectorElement());
+                double scatAngle;
+                
+                if(scatter != null) {
+                    scatAngle = scatter.getScatterAngle().Angle();
+                }
+                else {
+                    System.out.printf("%s: WARNING cannot find scatter for detector %s with strip cluster at %s\n",this.getClass(),((RawTrackerHit)strip.rawhits().get(0)).getDetectorElement().getName(),strip.origin().toString());
+                    //can be edge case where helix is outside, but close to sensor, so use hack with the sensor origin closest to hit -> FIX THIS!
+                    DetectorPlane closest = null;
+                    double dx = 999999.9;
+                    if(MaterialSupervisor.class.isInstance(_scattering.getMaterialManager())) {
+                        MaterialSupervisor matSup = (MaterialSupervisor)_scattering.getMaterialManager();
+                        for(ScatteringDetectorVolume vol : matSup.getMaterialVolumes()) {
+                            DetectorPlane plane = (DetectorPlane)vol;
+                            double dx_loop = Math.abs(strip.origin().x() - plane.origin().x());
+                            if(dx_loop<dx) {
+                                dx = dx_loop;
+                                closest = plane;
+                            }
+                        }
+                        if(closest==null) {
+                            throw new RuntimeException("cannot find any plane that is close to strip!");
+                        } else {
+                            // find scatterlength
+                            double s_closest = HelixUtils.PathToXPlane(htf,closest.origin().x(), 0., 0).get(0);
+                            double X0 = closest.getMaterialTraversedInRL(HelixUtils.Direction(htf, s_closest));
+                            ScatterAngle scatterAngle = new ScatterAngle(s_closest, _scattering.msangle(htf.p(this._B.magnitude()),X0));
+                            scatAngle = scatterAngle.Angle();
+                        }
+                    } 
+                    else {
+                        throw new UnsupportedOperationException("Should not happen. This problem is only solved with the MaterialSupervisor.");
+                    }
+                } 
+                
+                
+                //print scatterer to file
+                if(textFile != null) {
+                	textFile.printStripScat(scatAngle);
+                }
+                
+                //GBLDATA
+                stripData.setScatterAngle(scatAngle);
+                
+                ++istrip;
+                
+                
+              
+            }
+            
+        }
+        
+        
+        
+    }
+    
+    
+    private void checkAprimeTruth(MCParticle mcp, List<MCParticle> mcParticles) {
+    	List<MCParticle> mcp_pair = getAprimeDecayProducts(mcParticles);
+        
+    	if(_debug>0) {
+    		double invMassTruth = Math.sqrt( Math.pow(mcp_pair.get(0).getEnergy()+mcp_pair.get(1).getEnergy(),2) - VecOp.add(mcp_pair.get(0).getMomentum(), mcp_pair.get(1).getMomentum()).magnitudeSquared() );
+    		double invMassTruthTrks = getInvMassTracks(TrackUtils.getHTF(mcp_pair.get(0),-1.0*this._B.z()),TrackUtils.getHTF(mcp_pair.get(1),-1.0*this._B.z()));
+    		System.out.printf("%s: invM = %f\n",this.getClass().getSimpleName(),invMassTruth);
+    		System.out.printf("%s: invMTracks = %f\n",this.getClass().getSimpleName(),invMassTruthTrks);
+    	}
+    
+	    // cross-check
+	    if(!mcp_pair.contains(mcp)) {
+	        boolean hasBeamElectronParent = false;
+	        for(MCParticle parent : mcp.getParents()) {
+	            if(parent.getGeneratorStatus()!=MCParticle.FINAL_STATE && parent.getPDGID()==11 && parent.getMomentum().y()==0.0 && Math.abs(parent.getMomentum().magnitude() - _beamEnergy)<0.01) {
+	                hasBeamElectronParent = true;
+	            }
+	        }
+	        if(!hasBeamElectronParent) {
+	            System.out.printf("%s: the matched MC particle is not an A' daughter and not a the recoil electrons!?\n",this.getClass().getSimpleName());
+	            System.out.printf("%s: %s %d p %s org %s\n",this.getClass().getSimpleName(),mcp.getGeneratorStatus()==MCParticle.FINAL_STATE?"F":"I",mcp.getPDGID(),mcp.getMomentum().toString(),mcp.getOrigin().toString());
+	            printMCParticles(mcParticles);
+	            System.exit(1);
+	        } else {
+	            if(_debug>0) System.out.printf("%s: the matched MC particle is the recoil electron\n",this.getClass().getSimpleName());
+	        }
+	    }
+		
+	}
+    
+
+    MCParticle getMatchedTruthParticle(Track track) {
+        boolean debug = false;
+        
+        Map<MCParticle,Integer> particlesOnTrack = new HashMap<MCParticle,Integer>();
+        
+        if(debug) System.out.printf("getmatched mc particle from %d tracker hits on the track \n",track.getTrackerHits().size());
+        
+        
+        for(TrackerHit hit : track.getTrackerHits()) {
+            List<MCParticle> mcps = ((HelicalTrackHit)hit).getMCParticles();
+            if(mcps==null) {
+                System.out.printf("%s: warning, this hit (layer %d pos=%s) has no mc particles.\n",this.getClass().getSimpleName(),((HelicalTrackHit)hit).Layer(),((HelicalTrackHit)hit).getCorrectedPosition().toString());
+            } 
+            else {
+            	if( debug ) System.out.printf("%s: this hit (layer %d pos=%s) has %d mc particles.\n",this.getClass().getSimpleName(),((HelicalTrackHit)hit).Layer(),((HelicalTrackHit)hit).getCorrectedPosition().toString(),mcps.size());
+                for(MCParticle mcp : mcps) {
+                    if( !particlesOnTrack.containsKey(mcp) ) {
+                        particlesOnTrack.put(mcp, 0);
+                    }
+                    int c = particlesOnTrack.get(mcp);
+                    particlesOnTrack.put(mcp, c+1);
+                }
+            }
+        }
+        if(debug) {
+            System.out.printf("Track p=[ %f, %f, %f] \n",track.getTrackStates().get(0).getMomentum()[0],track.getTrackStates().get(0).getMomentum()[1],track.getTrackStates().get(0).getMomentum()[1]);
+            System.out.printf("FOund %d particles\n",particlesOnTrack.size());
+            for(Map.Entry<MCParticle, Integer> entry : particlesOnTrack.entrySet()) {
+                System.out.printf("%d hits assigned to %d p=%s \n",entry.getValue(),entry.getKey().getPDGID(),entry.getKey().getMomentum().toString());
+            }
+        }
+        Map.Entry<MCParticle,Integer> maxEntry = null;
+        for(Map.Entry<MCParticle,Integer> entry : particlesOnTrack.entrySet()) {
+            if ( maxEntry == null || entry.getValue().compareTo(maxEntry.getValue()) > 0 ) maxEntry = entry;
+            //if ( maxEntry != null ) {
+            //    if(entry.getValue().compareTo(maxEntry.getValue()) < 0) continue;
+            //}
+            //maxEntry = entry;
+        }
+        if(debug) {
+        	if (maxEntry != null ) {
+        		System.out.printf("Matched particle with pdgId=%d and mom %s to track with charge %d and momentum [%f %f %f]\n",
+        				maxEntry.getKey().getPDGID(),maxEntry.getKey().getMomentum().toString(),
+        				track.getCharge(),track.getTrackStates().get(0).getMomentum()[0],track.getTrackStates().get(0).getMomentum()[1],track.getTrackStates().get(0).getMomentum()[2]);
+        	} else {
+        		System.out.printf("No truth particle found on this track\n");
+        	}
+        }
+        return maxEntry == null ? null : maxEntry.getKey();
+    }
+    
+    
+    private BasicMatrix getPerParVector(HelicalTrackFit htf) {
+        BasicMatrix perPar = new BasicMatrix(1,5);
+        if( htf != null) {
+        	double kappa = -1.0*Math.signum(htf.R())*Constants.fieldConversion*this._B.z()/htf.pT(Math.abs(_B.z()));
+        	double theta = Math.PI/2.0 - Math.atan(htf.slope());
+        	perPar.setElement(0,0,kappa);
+        	perPar.setElement(0,1,theta);
+        	perPar.setElement(0,2,htf.phi0());
+        	perPar.setElement(0,3,htf.dca());
+        	perPar.setElement(0,4,htf.z0());
+        }
+        return perPar;
+        
+    }
+
+
+    
+    
+    private BasicMatrix getJacPerToCl(HelicalTrackFit htf) {
+        System.out.printf("%s: getJacPerToCl\n",this.getClass().getSimpleName());        
+        //use propoerly normalized B-field
+        Hep3Vector Bnorm = VecOp.mult(Constants.fieldConversion, _B);
+        //init jacobian to zero
+        BasicMatrix j = new BasicMatrix(5,5);
+        initZero(j);
+        double lambda = Math.atan(htf.slope());
+        double q = Math.signum(htf.R());
+        double theta = Math.PI/2.0 - lambda;
+        Hep3Vector T = HelixUtils.Direction(htf, 0.);
+        Hep3Vector p = VecOp.mult(htf.p(Math.abs(_B.z())), T);
+        double pT = htf.pT(Math.abs(_B.z()));
+        Hep3Vector H = VecOp.mult(1./(Bnorm.magnitude()), Bnorm); 
+        Hep3Vector Z = new BasicHep3Vector(0,0,1);
+        Hep3Vector J = VecOp.mult(1./VecOp.cross(T,Z).magnitude(), VecOp.cross(T, Z));
+        Hep3Vector U = VecOp.mult(-1, J);
+        Hep3Vector V = VecOp.cross(T, U);
+        double alpha = VecOp.cross(H,T).magnitude();
+        Hep3Vector N = VecOp.mult(1./alpha,VecOp.cross(H, T));
+        Hep3Vector K = Z;
+        double Q = -Bnorm.magnitude()*q/p.magnitude();
+        double kappa = -1.0*q*Bnorm.z()/pT;
+        
+        if (this._debug!=0) {
+            System.out.printf("%s: Bnorm=%s mag(Bnorm)=%f\n",this.getClass().getSimpleName(),Bnorm.toString(),Bnorm.magnitude());
+            System.out.printf("%s: p=%s |p|=%f pT=%f\n",this.getClass().getSimpleName(),p.toString(),p.magnitude(),pT);
+            System.out.printf("%s: q=%f\n",this.getClass().getSimpleName(),q);
+            System.out.printf("%s: q/p=%f\n",this.getClass().getSimpleName(),q/p.magnitude());
+            System.out.printf("%s: T=%s\n",this.getClass().getSimpleName(),T.toString());
+            System.out.printf("%s: H=%s\n",this.getClass().getSimpleName(),H.toString());
+            System.out.printf("%s: kappa=%f\n",this.getClass().getSimpleName(),kappa);
+            System.out.printf("%s: alpha=%f Q=%f \n",this.getClass().getSimpleName(),alpha,Q);
+            System.out.printf("%s: J=%s \n",this.getClass().getSimpleName(),J.toString());
+            System.out.printf("%s: V=%s \n",this.getClass().getSimpleName(),V.toString());
+            System.out.printf("%s: N=%s \n",this.getClass().getSimpleName(),N.toString());
+            System.out.printf("%s: TdotJ=%f \n",this.getClass().getSimpleName(),VecOp.dot(T, J));
+            System.out.printf("%s: VdotN=%f \n",this.getClass().getSimpleName(),VecOp.dot(V, N));
+            System.out.printf("%s: TdotK=%f \n",this.getClass().getSimpleName(),VecOp.dot(T, K));
+            System.out.printf("%s: UdotN=%f \n",this.getClass().getSimpleName(),VecOp.dot(U, N));
+        }
+        
+
+        
+        
+        
+        j.setElement(0,0,-1.0*Math.sin(theta)/Bnorm.z());
+        
+        j.setElement(0,1,q/(p.magnitude()*Math.tan(theta)));
+        
+        j.setElement(1,1,-1);
+        
+        j.setElement(1,3,-alpha*Q*VecOp.dot(T, J)*VecOp.dot(V, N));
+                
+        j.setElement(1,4,-alpha*Q*VecOp.dot(T, K)*VecOp.dot(V, N));
+
+        j.setElement(2,2,1);
+        
+        j.setElement(2,3,-alpha*Q*VecOp.dot(T,J)*VecOp.dot(U, N)/Math.cos(lambda));
+
+        j.setElement(2,4,-alpha*Q*VecOp.dot(T,K)*VecOp.dot(U, N)/Math.cos(lambda));
+
+        j.setElement(3,3,-1);
+        
+        j.setElement(4,4,VecOp.dot(V, K));
+
+        
+        if(_debug>0) {
+                System.out.printf("%s: lambda= J(1,1)=%f  * theta + J(1,3)=%f * eps + J(1,4)=%f * z0 \n",
+                this.getClass().getSimpleName(),
+                j.e(1, 1),j.e(1,3),j.e(1,4));
+
+        }
+        
+        
+        return j;
+        
+    }
+    
+    
+   
+
+    
+    
+    private void initUnit(BasicMatrix mat) {
+        for(int row=0;row!=mat.getNRows();row++) {
+            for(int col=0;col!=mat.getNColumns();col++) {
+                if(row!=col) mat.setElement(row, col, 0);
+                else mat.setElement(row, col, 1);
+            }
+        }
+    }
+
+    private void initZero(BasicMatrix mat) {
+        for(int row=0;row!=mat.getNRows();row++) {
+            for(int col=0;col!=mat.getNColumns();col++) {
+                mat.setElement(row, col, 0);
+            }
+        }
+    }
+
+
+    
+    /**
+     * Transform MCParticle into a Helix object.
+     * Note that it produces the helix parameters at nominal x=0 and assumes that there is no field at x<0
+     * 
+     * @param mcp MC particle to be transformed
+     * @return helix object based on the MC particle
+     */
+//    private HelicalTrackFit getHTF(MCParticle mcp) {
+//        Hep3Vector org = this._hpstrans.transformVectorToTracking(mcp.getOrigin());
+//        Hep3Vector p = this._hpstrans.transformVectorToTracking(mcp.getMomentum());
+//        // Move to x=0 if needed
+//        if(org.x() < 0.) { 
+//        	double dydx = p.y()/p.x();
+//        	double dzdx = p.z()/p.x();
+//        	double delta_x = -1. * org.x(); 
+//        	double y = delta_x * dydx;
+//        	double z = delta_x * dzdx;
+//        	double x = org.x() + delta_x;
+//        	if( Math.abs(x) > 1e-8) throw new RuntimeException("Error: origin is not zero!");
+//        	Hep3Vector old = org;
+//        	org = new BasicHep3Vector(x,y,z);
+//        	System.out.printf("org %s p %s -> org %s\n", old.toString(),p.toString(),org.toString());
+//        } else {
+//        	org = this._hpstrans.transformVectorToTracking(mcp.getOrigin());
+//        }
+//        
+//        
+//        
+//        HelixParamCalculator helixParamCalculator = new HelixParamCalculator(p, org, -1*((int)mcp.getCharge()), -1.0*this._B.z());
+//        double par[] = new double[5];
+//        par[HelicalTrackFit.dcaIndex] = helixParamCalculator.getDCA();
+//        par[HelicalTrackFit.slopeIndex] = helixParamCalculator.getSlopeSZPlane();
+//        par[HelicalTrackFit.phi0Index] = helixParamCalculator.getPhi0();
+//        par[HelicalTrackFit.curvatureIndex] = 1.0/helixParamCalculator.getRadius();
+//        par[HelicalTrackFit.z0Index] = helixParamCalculator.getZ0();
+//        SymmetricMatrix cov = new SymmetricMatrix(5);
+//        for(int i=0;i<cov.getNRows();++i) cov.setElement(i, i, 1.);
+//        HelicalTrackFit htf = new HelicalTrackFit(par, cov, new double[2], new int[2], null, null);
+//        return htf;
+//    }
+
+    private double truthTrackFitChi2(PerigeeParams perPar, PerigeeParams perParTruth, SymmetricMatrix covariance) {
+        //re-shuffle the param vector to match the covariance order of parameters
+        BasicMatrix p = new BasicMatrix(1,5);
+        p.setElement(0, 0, perPar.getD0());
+        p.setElement(0, 1, perPar.getPhi());
+        p.setElement(0, 2, perPar.getKappa());
+        p.setElement(0, 0, perPar.getZ0());
+        p.setElement(0, 4, Math.tan(Math.PI/2.0-perPar.getTheta()));
+        BasicMatrix pt = new BasicMatrix(1,5);
+        pt.setElement(0, 0, perParTruth.getD0());
+        pt.setElement(0, 1, perParTruth.getPhi());
+        pt.setElement(0, 2, perParTruth.getKappa());
+        pt.setElement(0, 0, perParTruth.getZ0());
+        pt.setElement(0, 4, Math.tan(Math.PI/2.0-perParTruth.getTheta()));
+        Matrix error_matrix = MatrixOp.inverse(covariance);
+        BasicMatrix res = (BasicMatrix) MatrixOp.sub(p, pt);
+        BasicMatrix chi2 = (BasicMatrix) MatrixOp.mult(res,MatrixOp.mult(error_matrix, MatrixOp.transposed(res)));
+        if(chi2.getNColumns()!=1 ||chi2.getNRows()!=1) {
+            throw new RuntimeException("matrix dim is screwed up!");
+        }
+        return chi2.e(0, 0);
+    }
+
+    
+    
+    private List<MCParticle> getAprimeDecayProducts(List<MCParticle> mcParticles) {
+        List<MCParticle> pair = new ArrayList<MCParticle>();
+        for(MCParticle mcp : mcParticles) {
+            if(mcp.getGeneratorStatus()!=MCParticle.FINAL_STATE) continue;
+            boolean hasAprimeParent = false;
+            for(MCParticle parent : mcp.getParents()) {
+                if(Math.abs(parent.getPDGID())==622) hasAprimeParent = true;
+            }
+            if(hasAprimeParent)  pair.add(mcp);
+        }
+        if(pair.size()!=2) {
+            System.out.printf("%s: ERROR this event has %d mcp with 622 as parent!!??  \n",this.getClass().getSimpleName(),pair.size());
+            this.printMCParticles(mcParticles);
+            System.exit(1);
+        }
+        if( Math.abs(pair.get(0).getPDGID()) != 11 || Math.abs(pair.get(1).getPDGID()) != 11 ) {
+            System.out.printf("%s: ERROR decay products are not e+e-? \n",this.getClass().getSimpleName());
+            this.printMCParticles(mcParticles);
+            System.exit(1);
+        }
+        if(pair.get(0).getPDGID()*pair.get(1).getPDGID() > 0) {
+            System.out.printf("%s: ERROR decay products have the same sign? \n",this.getClass().getSimpleName());
+            this.printMCParticles(mcParticles);
+            System.exit(1);
+        }
+        return pair;
+        
+    }
+
+    private void printMCParticles(List<MCParticle> mcParticles) {      
+        System.out.printf("%s: printMCParticles \n",this.getClass().getSimpleName());
+        System.out.printf("%s: %d mc particles \n",this.getClass().getSimpleName(),mcParticles.size());
+        for(MCParticle mcp : mcParticles) {
+            if(mcp.getGeneratorStatus()!=MCParticle.FINAL_STATE) continue;
+            System.out.printf("\n%s: (%s) %d  p %s org %s  %s \n",this.getClass().getSimpleName(),
+                                mcp.getGeneratorStatus()==MCParticle.FINAL_STATE?"F":"I",mcp.getPDGID(),mcp.getMomentum().toString(),mcp.getOrigin().toString(),
+                                mcp.getParents().size()>0?"parents:":"");
+            for(MCParticle parent : mcp.getParents()) {
+                System.out.printf("%s:       (%s) %d  p %s org %s %s \n",this.getClass().getSimpleName(),
+                                parent.getGeneratorStatus()==MCParticle.FINAL_STATE?"F":"I",parent.getPDGID(),parent.getMomentum().toString(),parent.getOrigin().toString(),
+                                parent.getParents().size()>0?"parents:":"");
+                for(MCParticle grparent : parent.getParents()) {
+                    System.out.printf("%s:            (%s) %d  p %s org %s  %s \n",this.getClass().getSimpleName(),
+                                    grparent.getGeneratorStatus()==MCParticle.FINAL_STATE?"F":"I",grparent.getPDGID(),grparent.getMomentum().toString(),grparent.getOrigin().toString(),
+                                    grparent.getParents().size()>0?"parents:":"");
+                }
+            
+            }
+        }
+        return;
+     }
+
+    private double getInvMassTracks(HelicalTrackFit htf1, HelicalTrackFit htf2) {
+        double p1 = htf1.p(this._B.magnitude());
+        double p2 = htf2.p(this._B.magnitude());
+        Hep3Vector p1vec = VecOp.mult(p1, HelixUtils.Direction(htf1, 0));
+        Hep3Vector p2vec = VecOp.mult(p2, HelixUtils.Direction(htf2, 0));
+        double me = 0.000510998910;
+        double E1 = Math.sqrt(p1*p1 + me*me);
+        double E2 = Math.sqrt(p2*p2 + me*me);
+        //System.out.printf("p1 %f %s E1 %f\n",p1,p1vec.toString(),E1);
+        //System.out.printf("p2 %f %s E2 %f\n",p2,p2vec.toString(),E2);
+        return Math.sqrt( Math.pow(E1+E2,2) - VecOp.add(p1vec, p2vec).magnitudeSquared() );
+    }
+
+    
+    public class PerigeeParams {
+        private BasicMatrix _params;
+
+        private PerigeeParams(HelicalTrackFit htf) {
+            _params = GBLOutput.this.getPerParVector(htf);
+        }
+        public BasicMatrix getParams() {
+            return _params;
+        }
+        public double getKappa() {
+            return _params.e(0, 0);
+        }
+        public double getTheta() {
+            return _params.e(0, 1);
+        }
+        public double getPhi() {
+            return _params.e(0, 2);
+        }
+        public double getD0() {
+            return _params.e(0, 3);
+        }
+        public double getZ0() {
+            return _params.e(0, 4);
+        }
+    }
+
+    /**
+     * Computes the projection matrix from the perigee XY plane variables 
+     * dca and z0 into the curvilinear xT,yT,zT frame (U,V,T)
+     * @param htf input helix to find the track direction
+     * @return 3x3 projection matrix
+     */
+    Hep3Matrix getPerToClPrj(HelicalTrackFit htf) {
+        Hep3Vector Z = new BasicHep3Vector(0,0,1);
+        Hep3Vector T = HelixUtils.Direction(htf, 0.);
+        Hep3Vector J = VecOp.mult(1./VecOp.cross(T,Z).magnitude(), VecOp.cross(T, Z));
+        Hep3Vector K = Z;
+        Hep3Vector U = VecOp.mult(-1, J);
+        Hep3Vector V = VecOp.cross(T, U);
+        Hep3Vector I = VecOp.cross(J, K);
+           
+        BasicHep3Matrix trans = new BasicHep3Matrix();
+        trans.setElement(0, 0, VecOp.dot(I, U));
+        trans.setElement(0, 1, VecOp.dot(J, U));
+        trans.setElement(0, 2, VecOp.dot(K, U));
+        trans.setElement(1, 0, VecOp.dot(I, V));
+        trans.setElement(1, 1, VecOp.dot(J, V));
+        trans.setElement(1, 2, VecOp.dot(K, V));
+        trans.setElement(2, 0, VecOp.dot(I, T));
+        trans.setElement(2, 1, VecOp.dot(J, T));
+        trans.setElement(2, 2, VecOp.dot(K, T));
+        return trans;
+        
+    }
+    
+
+    
+
+	public class ClParams {
+        private BasicMatrix _params = new BasicMatrix(1,5);
+        private ClParams(HelicalTrackFit htf) {
+            
+        	if (htf == null) return;
+
+            Hep3Matrix perToClPrj = GBLOutput.this.getPerToClPrj(htf);
+            
+            double d0 = -1 * htf.dca(); //sign convention for curvilinear frame
+            double z0 = htf.z0();
+            Hep3Vector vecPer = new BasicHep3Vector(0.,d0,z0);
+            //System.out.printf("%s: vecPer=%s\n",this.getClass().getSimpleName(),vecPer.toString());
+            
+            Hep3Vector vecCl = VecOp.mult(perToClPrj, vecPer);
+            //System.out.printf("%s: vecCl=%s\n",this.getClass().getSimpleName(),vecCl.toString());
+            double xT = vecCl.x();
+            double yT = vecCl.y();
+            //double zT = vecCl.z();
+            
+            Hep3Vector T = HelixUtils.Direction(htf, 0.);
+            Hep3Vector p = VecOp.mult(htf.p(Math.abs(_B.z())), T);
+            double lambda = Math.atan(htf.slope());
+            double q = Math.signum(htf.R());
+            double qOverP = q/p.magnitude();
+            double phi = htf.phi0();
+            
+            _params.setElement(0, 0, qOverP);
+            _params.setElement(0, 1, lambda);
+            _params.setElement(0, 2, phi);
+            _params.setElement(0, 3, xT);
+            _params.setElement(0, 4, yT);
+            
+        }
+
+        public BasicMatrix getParams() {
+            return _params;
+        }
+        
+        double getLambda() {
+            return _params.e(0,1);
+        }
+        double getQoverP() {
+            return _params.e(0,0);
+        }
+        double getPhi() {
+            return _params.e(0,2);
+        }
+        double getXt() {
+            return _params.e(0,3);
+        }
+        double getYt() {
+            return _params.e(0,4);
+        }
+        
+    }
+
+
+
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking/gbl
GBLOutputDriver.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/gbl/GBLOutputDriver.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/gbl/GBLOutputDriver.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,199 @@
+package org.hps.recon.tracking.gbl;
+
+import hep.physics.vec.BasicHep3Vector;
+import hep.physics.vec.Hep3Vector;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.hps.recon.tracking.EventQuality;
+import org.hps.recon.tracking.TrackUtils;
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.LCRelation;
+import org.lcsim.event.MCParticle;
+import org.lcsim.event.SimTrackerHit;
+import org.lcsim.event.Track;
+import org.lcsim.event.base.MyLCRelation;
+import org.lcsim.geometry.Detector;
+import org.lcsim.util.Driver;
+import org.lcsim.util.aida.AIDA;
+
+/**
+* This driver class is used to 
+* 1) write lcio collection of GBL info objects OR
+* 2) write GBL info into a unstructures text-based output
+* 
+* It uses a helper class that does the actual work. We will port GBL to java and that will replace this driver.
+* 
+* @author Per Hansson Adrian <[log in to unmask]>
+* @version $Id: GBLOutputDriver.java,v 1.9 2013/11/07 03:54:58 phansson Exp $ $Date: 2013/11/07 03:54:58 $ $Author: phansson $ 
+* 
+*/
+public class GBLOutputDriver extends Driver {
+
+    private AIDA aida = AIDA.defaultInstance();
+    int nevt = 0;
+    GBLOutput gbl;
+    TruthResiduals truthRes = null;
+    private String gblFileName = "";
+    private String outputPlotFileName="";
+    private String MCParticleCollectionName = "MCParticle";
+    private int _debug = 0;
+    private boolean isMC = true;
+    private int totalTracks=0;
+    private int totalTracksProcessed=0;
+    private int iTrack = 0;
+    private int iEvent = 0;
+    
+    
+    
+    public GBLOutputDriver() {
+    }
+
+    
+    @Override
+    public void detectorChanged(Detector detector) {
+        Hep3Vector bfield = detector.getFieldMap().getField(new BasicHep3Vector(0., 0., 1.));
+        
+        // Create the class that handles all the GBL output
+        gbl = new GBLOutput(gblFileName,bfield); // if filename is empty no text file is written
+        gbl.setDebug(_debug);
+        gbl.buildModel(detector);
+        gbl.setAPrimeEventFlag(false);
+        gbl.setXPlaneFlag(false);
+
+        //Create the class that makes residual plots for cross-checking
+        //truthRes = new TruthResiduals(bfield);
+        //truthRes.setDebug(_debug);
+        //truthRes.setHideFrame(hideFrame);
+    }
+    
+    
+    
+    @Override
+    public void process(EventHeader event) {
+
+        
+        List<Track> tracklist = null;
+        if(event.hasCollection(Track.class,"MatchedTracks")) {        
+            tracklist = event.get(Track.class, "MatchedTracks");
+             if(_debug>0) {
+                System.out.printf("%s: Event %d has %d tracks\n", this.getClass().getSimpleName(),event.getEventNumber(),tracklist.size());
+             }
+        }
+
+
+        List<MCParticle> mcParticles = new ArrayList<MCParticle>();
+        if(event.hasCollection(MCParticle.class,this.MCParticleCollectionName)) {
+        	mcParticles = event.get(MCParticle.class,this.MCParticleCollectionName);
+        }
+
+        List<SimTrackerHit> simTrackerHits = new ArrayList<SimTrackerHit>();
+        if (event.hasCollection(SimTrackerHit.class, "TrackerHits")) {
+        	simTrackerHits = event.getSimTrackerHits("TrackerHits");
+        }
+        
+        if(isMC) {
+        	if(truthRes != null) {
+        		truthRes.processSim(mcParticles, simTrackerHits);
+        	}	
+        }
+        
+        
+        List<Track> selected_tracks = new ArrayList<Track>();
+        for (Track trk : tracklist) {
+            totalTracks++;            
+            if(TrackUtils.isGoodTrack(trk, tracklist, EventQuality.Quality.MEDIUM)) {
+                if(_debug>0) System.out.printf("%s: Track failed selection\n", this.getClass().getSimpleName());
+                selected_tracks.add(trk);
+            }
+        }
+
+        // GBLData 
+        // containers and data
+        List<GBLEventData> gblEventData =  new ArrayList<GBLEventData>(); 
+        gblEventData.add(new GBLEventData(event.getEventNumber(),gbl.get_B().z()));
+        List<GBLTrackData> gblTrackDataList =  new ArrayList<GBLTrackData>(); 
+        List<GBLStripClusterData> gblStripDataListAll  = new ArrayList<GBLStripClusterData>();
+        List<GBLStripClusterData> gblStripDataList  = new ArrayList<GBLStripClusterData>();
+        List<LCRelation> gblTrackToStripClusterRelationListAll = new ArrayList<LCRelation>();
+        List<LCRelation> trackToGBLTrackRelationListAll = new ArrayList<LCRelation>();
+        
+        gbl.printNewEvent(iEvent,gbl.get_B().z());
+
+        iTrack = 0;
+        for (Track trk : selected_tracks) {
+            if(_debug>0) System.out.printf("%s: Print GBL output for this track\n", this.getClass().getSimpleName());
+            
+            //GBLDATA
+            GBLTrackData gblTrackData = new GBLTrackData(iTrack);
+            gblTrackDataList.add(gblTrackData);            
+            
+            //print to text file
+            gbl.printTrackID(iTrack);
+            gbl.printGBL(trk,gblTrackData,gblStripDataList,mcParticles,simTrackerHits,this.isMC);
+            
+            //GBLDATA
+            //add relation to normal track object
+            trackToGBLTrackRelationListAll.add(new MyLCRelation(trk,gblTrackData));
+            // add strip clusters to lists
+            for(GBLStripClusterData gblStripClusterData : gblStripDataList) {
+                // add all strip clusters from this track to output list
+                gblStripDataListAll.add(gblStripClusterData);
+                // add LC relations between cluster and track
+                gblTrackToStripClusterRelationListAll.add(new MyLCRelation(gblTrackData,gblStripClusterData));
+            }
+            // clear list of strips for next track
+            gblStripDataList.clear();
+
+            totalTracksProcessed++;
+            ++iTrack;
+        }
+        
+        // Put GBL info into event
+        event.put("GBLEventData", gblEventData, GBLEventData.class, 0);
+        event.put("GBLTrackData", gblTrackDataList, GBLTrackData.class, 0);
+        event.put("GBLStripClusterData", gblStripDataListAll, GBLStripClusterData.class, 0);
+        event.put("GBLTrackToStripData", gblTrackToStripClusterRelationListAll, LCRelation.class, 0);
+        event.put("TrackToGBLTrack", trackToGBLTrackRelationListAll, LCRelation.class, 0);
+
+        ++iEvent;
+        
+    }
+
+    @Override
+    public void endOfData() {
+        gbl.close();
+        if (!"".equals(outputPlotFileName)) {
+            try {
+                aida.saveAs(outputPlotFileName);
+            } catch (IOException ex) {
+                Logger.getLogger(GBLOutputDriver.class.getName()).log(Level.SEVERE, "Couldn't save aida plots to file " + outputPlotFileName, ex);
+            }
+        }
+        System.out.println(this.getClass().getSimpleName() + ": Total Number of Events           = "+iEvent);
+        System.out.println(this.getClass().getSimpleName() + ": Total Number of Tracks           = "+totalTracks);
+        System.out.println(this.getClass().getSimpleName() + ": Total Number of Tracks Processed = "+totalTracksProcessed);
+        
+        
+    }
+    
+    public void setDebug(int v) {
+        this._debug = v;
+    }
+    public void setGblFileName(String filename) {
+        gblFileName = filename;
+    }
+    public void setOutputPlotFileName(String filename) {
+        outputPlotFileName = filename;
+    }    
+    public void setIsMC(boolean isMC) {
+        this.isMC = isMC;
+    }
+
+    
+    
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking/gbl
GBLStripClusterData.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/gbl/GBLStripClusterData.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/gbl/GBLStripClusterData.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,307 @@
+package org.hps.recon.tracking.gbl;
+
+import hep.physics.vec.BasicHep3Vector;
+import hep.physics.vec.Hep3Vector;
+
+import org.lcsim.event.GenericObject;
+
+/**
+ * A class providing for storing strip clusters for GBL
+ * 
+ * @author phansson
+ *
+ */
+public class GBLStripClusterData implements GenericObject {
+	
+	/*
+	 * 
+	 * Interface enumerator to access the correct data
+	 * 
+	 */
+	private static class GBLINT {
+		public static final int ID = 0;
+		public static final int BANK_INT_SIZE = 1;
+	}
+	private static class GBLDOUBLE {
+		public static final int PATH3D = 0;
+		public static final int PATH = 1;
+		public static final int UX = 2;
+		public static final int UY = 3;
+		public static final int UZ = 4;
+		public static final int VX = 5;
+		public static final int VY = 6;
+		public static final int VZ = 7;
+		public static final int WX = 8;
+		public static final int WY = 9;
+		public static final int WZ = 10;	
+		public static final int TDIRX = 11;	
+		public static final int TDIRY = 12;	
+		public static final int TDIRZ = 13;	
+		public static final int TPHI = 14;	
+		public static final int UMEAS = 15;	
+		public static final int TPOSU = 16	;	
+		public static final int TPOSV = 17;	
+		public static final int TPOSW = 18;	
+		public static final int UMEASERR = 19;	
+		public static final int MSANGLE = 20;
+		public static final int TLAMBDA = 21;
+		
+		
+		public static final int BANK_DOUBLE_SIZE = 22;
+		
+	}
+	// array holding the integer data
+	private int bank_int[] = new int[GBLINT.BANK_INT_SIZE];
+	// array holding the double data
+	private double bank_double[] = new double[GBLDOUBLE.BANK_DOUBLE_SIZE];
+	
+	/**
+	 * Default constructor
+	 */
+	public GBLStripClusterData(int id) {
+		setId(id);
+	}
+	
+	/**
+	 * @param set track id to val
+	 */
+	public void setId(int val) {
+		bank_int[GBLINT.ID] = val;
+	}
+	
+	/**
+	 * @return track id for this object
+	 */
+	public int getId() {
+		return this.getIntVal(GBLINT.ID);
+	}
+	
+	/**
+	 * Set path length to this strip cluster
+	 * @param val
+	 */
+	public void setPath(double val) {
+		bank_double[GBLDOUBLE.PATH] = val;
+	}
+	
+	/**
+	 * Get path length to this strip cluster
+	 */
+	public double getPath() {
+		return getDoubleVal(GBLDOUBLE.PATH);
+	}
+
+	/**
+	 * Set path length to this strip cluster
+	 * @param val
+	 */
+	public void setPath3D(double val) {
+		bank_double[GBLDOUBLE.PATH3D] = val;
+	}
+	
+	/**
+	 * Get path length to this strip cluster
+	 */
+	public double getPath3D() {
+		return getDoubleVal(GBLDOUBLE.PATH3D);
+	}
+
+
+	/**
+	 *  Set and get u vector for this strip sensor
+	 */
+	public void setU(Hep3Vector u) {
+		bank_double[GBLDOUBLE.UX] = u.x();
+		bank_double[GBLDOUBLE.UY] = u.y();
+		bank_double[GBLDOUBLE.UZ] = u.z();		
+	}
+	public Hep3Vector getU() {
+		return new BasicHep3Vector(getUx(),getUy(),getUz());
+	}
+	public double getUx() {
+		return getDoubleVal(GBLDOUBLE.UX);
+	}
+	public double getUy() {
+		return getDoubleVal(GBLDOUBLE.UY);
+	}
+	public double getUz() {
+		return getDoubleVal(GBLDOUBLE.UZ);
+	}
+	
+	/**
+	 *  Set and get v vector for this strip sensor
+	 */
+
+	public void setV(Hep3Vector v) {
+		bank_double[GBLDOUBLE.VX] = v.x();
+		bank_double[GBLDOUBLE.VY] = v.y();
+		bank_double[GBLDOUBLE.VZ] = v.z();		
+	}
+	public Hep3Vector getV() {
+		return new BasicHep3Vector(getVx(),getVy(),getVz());
+	}
+	public double getVx() {
+		return getDoubleVal(GBLDOUBLE.VX);
+	}
+	public double getVy() {
+		return getDoubleVal(GBLDOUBLE.VY);
+	}
+	public double getVz() {
+		return getDoubleVal(GBLDOUBLE.VZ);
+	}
+
+	/**
+	 *  Set and get w vector for this strip sensor
+	 */
+
+	public void setW(Hep3Vector v) {
+		bank_double[GBLDOUBLE.WX] = v.x();
+		bank_double[GBLDOUBLE.WY] = v.y();
+		bank_double[GBLDOUBLE.WZ] = v.z();		
+	}
+	public Hep3Vector getW() {
+		return new BasicHep3Vector(getWx(),getWy(),getWz());
+	}
+	public double getWx() {
+		return getDoubleVal(GBLDOUBLE.WX);
+	}
+	public double getWy() {
+		return getDoubleVal(GBLDOUBLE.WY);
+	}
+	public double getWz() {
+		return getDoubleVal(GBLDOUBLE.WZ);
+	}
+
+	/**
+	 * Set track direction at this cluster
+	 * 
+	 * @param tDir
+	 */
+	public void setTrackDir(Hep3Vector v) {
+		bank_double[GBLDOUBLE.TDIRX] = v.x();
+		bank_double[GBLDOUBLE.TDIRY] = v.y();
+		bank_double[GBLDOUBLE.TDIRZ] = v.z();		
+	}
+	public Hep3Vector getTrackDirection() {
+		return new BasicHep3Vector(getTx(),getTy(),getTz());
+	}
+	public double getTx() {
+		return getDoubleVal(GBLDOUBLE.TDIRX);
+	}
+	public double getTy() {
+		return getDoubleVal(GBLDOUBLE.TDIRY);
+	}
+	public double getTz() {
+		return getDoubleVal(GBLDOUBLE.TDIRY);
+	}
+
+	public void setTrackPhi(double phi) {
+		bank_double[GBLDOUBLE.TPHI] = phi;
+	}
+	
+	public double getTrackPhi() {
+		return getDoubleVal(GBLDOUBLE.TPHI);
+	}
+
+	public void setTrackLambda(double lambda) {
+		bank_double[GBLDOUBLE.TLAMBDA] = lambda;
+	}
+	
+	public double getTrackLambda() {
+		return getDoubleVal(GBLDOUBLE.TLAMBDA);
+	}
+
+	
+	public void setMeas(double umeas) {
+		bank_double[GBLDOUBLE.UMEAS] = umeas;
+	}
+	
+	public double getMeas() {
+		return getDoubleVal(GBLDOUBLE.UMEAS);
+	}
+	
+	public void setMeasErr(double x) {
+		bank_double[GBLDOUBLE.UMEASERR] = x;
+	}
+
+	public double getMeasErr() {
+		return getDoubleVal(GBLDOUBLE.UMEASERR);
+	}
+
+	
+	/**
+	 * Set track position in local frame
+	 * @param trkpos_meas
+	 */
+	public void setTrackPos(Hep3Vector trkpos_meas) {
+		bank_double[GBLDOUBLE.TPOSU] = trkpos_meas.x();
+		bank_double[GBLDOUBLE.TPOSV] = trkpos_meas.y();
+		bank_double[GBLDOUBLE.TPOSW] = trkpos_meas.z();
+	}
+
+	public Hep3Vector getTrackPos() {
+		return new BasicHep3Vector(getTrackPosU(),getTrackPosV(),getTrackPosW());
+	}
+	
+	public double getTrackPosU() {
+		return getDoubleVal(GBLDOUBLE.TPOSU);
+	}
+
+	public double getTrackPosV() {
+		return getDoubleVal(GBLDOUBLE.TPOSV);
+	}
+
+	public double getTrackPosW() {
+		return getDoubleVal(GBLDOUBLE.TPOSW);
+	}
+
+	public void setScatterAngle(double scatAngle) {
+		bank_double[GBLDOUBLE.MSANGLE] = scatAngle;
+	}
+	
+	public double getScatterAngle() {
+		return getDoubleVal(GBLDOUBLE.MSANGLE);
+	}
+	
+
+	
+
+
+
+	/*
+	 * The functions below are all overide from 
+	 * @see org.lcsim.event.GenericObject#getNInt()
+	 */
+	
+	public int getNInt() {
+		return GBLINT.BANK_INT_SIZE;
+	}
+
+	public int getNFloat() {
+		return 0;
+	}
+
+	public int getNDouble() {
+		return GBLDOUBLE.BANK_DOUBLE_SIZE;
+	}
+
+	public int getIntVal(int index) {
+		return bank_int[index];
+	}
+
+	public float getFloatVal(int index) {
+		return 0;
+	}
+
+	public double getDoubleVal(int index) {
+		return bank_double[index];
+	}
+
+	public boolean isFixedSize() {
+		return false;
+	}
+
+	
+
+
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking/gbl
GBLTrackData.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/gbl/GBLTrackData.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/gbl/GBLTrackData.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,108 @@
+package org.hps.recon.tracking.gbl;
+
+import org.hps.recon.tracking.gbl.GBLOutput.PerigeeParams;
+import org.lcsim.event.GenericObject;
+
+public class GBLTrackData implements GenericObject {
+	
+	/*
+	 * 
+	 * Interface enumerator to access the correct data
+	 * 
+	 */
+	private static class GBLINT {
+		public static final int ID = 0;
+		public static final int BANK_INT_SIZE = 1;
+	}
+	private static class GBLDOUBLE {
+		public static final int PERKAPPA =0;
+		public static final int PERTHETA = 1;
+		public static final int PERPHI = 2;
+		public static final int PERD0 = 3;
+		public static final int PERZ0 = 4;
+		// 9 entries from projection matrix from perigee to curvilinear frame
+		public static final int BANK_DOUBLE_SIZE = 5+9;
+	}
+	// array holding the integer data
+	private int bank_int[] = new int[GBLINT.BANK_INT_SIZE];
+	// array holding the double data
+	private double bank_double[] = new double[GBLDOUBLE.BANK_DOUBLE_SIZE];
+	
+	/**
+	 * Default constructor
+	 */
+	public GBLTrackData(int id) {	
+		setTrackId(id);
+	}
+	
+	/**
+	 * @param set track id to val
+	 */
+	public void setTrackId(int val) {
+		bank_int[GBLINT.ID] = val;
+	}
+	
+	/**
+	 * @return track id for this object
+	 */
+	public int getTrackId() {
+		return this.getIntVal(GBLINT.ID);
+	}
+	
+	/**
+	 * @param perPar is the perigee parameters that is added to object
+	 */
+	public void setPerigeeTrackParameters(PerigeeParams perPar) {
+		this.bank_double[GBLDOUBLE.PERKAPPA] = perPar.getKappa();
+		this.bank_double[GBLDOUBLE.PERTHETA] = perPar.getTheta();
+		this.bank_double[GBLDOUBLE.PERPHI] = perPar.getPhi();
+		this.bank_double[GBLDOUBLE.PERD0] = perPar.getD0();
+		this.bank_double[GBLDOUBLE.PERZ0] = perPar.getZ0();
+	}
+
+	
+	public void setPrjPerToCl(int row, int col, double val) {
+		int idx = col + row*3;
+		if(idx>8) {
+			System.out.printf("%s: ERROR to large matrix\n", this.getClass().getSimpleName());
+			System.exit(1);
+		}
+		this.bank_double[idx+5] = val;
+	}
+	
+
+	/*
+	 * The functions below are all overide from 
+	 * @see org.lcsim.event.GenericObject#getNInt()
+	 */
+	
+	public int getNInt() {
+		return GBLINT.BANK_INT_SIZE;
+	}
+
+	public int getNFloat() {
+		return 0;
+	}
+
+	public int getNDouble() {
+		return GBLDOUBLE.BANK_DOUBLE_SIZE;
+	}
+
+	public int getIntVal(int index) {
+		return bank_int[index];
+	}
+
+	public float getFloatVal(int index) {
+		return 0;
+	}
+
+	public double getDoubleVal(int index) {
+		return bank_double[index];
+	}
+
+	public boolean isFixedSize() {
+		return false;
+	}
+
+
+}

java/sandbox/tracking/src/main/java/org/hps/recon/tracking/gbl
TruthResiduals.java added at 348
--- java/sandbox/tracking/src/main/java/org/hps/recon/tracking/gbl/TruthResiduals.java	                        (rev 0)
+++ java/sandbox/tracking/src/main/java/org/hps/recon/tracking/gbl/TruthResiduals.java	2014-03-26 00:20:42 UTC (rev 348)
@@ -0,0 +1,349 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.hps.recon.tracking.gbl;
+
+import hep.aida.IAnalysisFactory;
+import hep.aida.IHistogram;
+import hep.aida.IHistogram1D;
+import hep.aida.IHistogram2D;
+import hep.aida.IHistogramFactory;
+import hep.aida.IPlotter;
+import hep.physics.vec.Hep3Vector;
+import hep.physics.vec.VecOp;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.hps.recon.tracking.HPSTransformations;
+import org.hps.recon.tracking.TrackUtils;
+import org.lcsim.event.MCParticle;
+import org.lcsim.event.SimTrackerHit;
+import org.lcsim.fit.helicaltrack.HelicalTrackFit;
+import org.lcsim.util.aida.AIDA;
+
+/**
+ * Calculates and plots truth residuals for track 
+ * @author Per Hansson Adrian <[log in to unmask]>
+ * @version $Id: TruthResiduals.java,v 1.10 2013/11/07 03:54:58 phansson Exp $ $Date: 2013/11/07 03:54:58 $ $Author: phansson $ 
+ */
+public class TruthResiduals {
+    
+    private int _debug;
+    private boolean _hideFrame = true;
+    private Hep3Vector _B;
+    private AIDA aida = AIDA.defaultInstance();
+    private IAnalysisFactory af = aida.analysisFactory();
+    private Map<Integer, List<IHistogram1D> > res_truthsimhit = null;
+    private Map<Integer, List<IHistogram1D> > res_truthsimhit_top_plus = null;
+    private Map<Integer, List<IHistogram1D> > res_truthsimhit_bot_plus = null;
+    private Map<Integer, List<IHistogram1D> > res_truthsimhit_top_minus = null;
+    private Map<Integer, List<IHistogram1D> > res_truthsimhit_bot_minus = null;
+    private IHistogram2D h_mcp_org;
+    private IHistogram2D trkpos_y_vs_x;
+    private boolean firstWeirdTrack = true;
+    
+    
+
+    /*
+     * file name
+     * Bz in Tesla
+     */
+    public TruthResiduals(Hep3Vector bfield) {
+        _B = HPSTransformations.transformVectorToTracking(bfield);
+        System.out.printf("%s: B field %s\n",this.getClass().getSimpleName(),_B.toString());
+    }
+    public void setDebug(int debug) {
+        _debug = debug;
+    }
+    public void setHideFrame(boolean hide) {
+        _hideFrame = hide;
+    }
+    
+    
+    public void processSim(List<MCParticle> mcParticles, List<SimTrackerHit> simTrackerHits) {
+        
+        if(res_truthsimhit == null) makePlots();
+        
+        
+        // map layer, mcparticles and sim hits
+        Map<Integer, List<SimTrackerHit>> simHitsLayerMap = new HashMap<Integer, List<SimTrackerHit> >();
+        Map<MCParticle, List<SimTrackerHit> > mcPartSimHitsMap = new HashMap<MCParticle, List<SimTrackerHit > >();
+        for(SimTrackerHit sh : simTrackerHits) {
+        	 Hep3Vector shpos = HPSTransformations.transformVectorToTracking(sh.getPositionVec());
+        	if(Math.abs(shpos.x()) < 50.0) {
+        		 System.out.printf("%s: Weird hit at %s (%s) in layer %d for MC part %d org %s p %s\n",
+                         this.getClass().getSimpleName(),sh.getPositionVec().toString(),shpos.toString(),sh.getIdentifierFieldValue("layer"),
+                         sh.getMCParticle().getPDGID(),sh.getMCParticle().getOrigin().toString(),sh.getMCParticle().getMomentum().toString());
+        		 System.exit(1);
+        	}
+        	
+            int layer  = sh.getIdentifierFieldValue("layer");
+            if(!simHitsLayerMap.containsKey(layer)) {
+                simHitsLayerMap.put(layer, new ArrayList<SimTrackerHit>());
+            }
+            simHitsLayerMap.get(layer).add(sh);
+            
+            MCParticle part = sh.getMCParticle();
+            if(!mcPartSimHitsMap.containsKey(part)) {
+                mcPartSimHitsMap.put(part, new ArrayList<SimTrackerHit>());
+            }
+            mcPartSimHitsMap.get(part).add(sh);
+        }
+
+        
+        for(MCParticle mcp : mcPartSimHitsMap.keySet()) {
+        	this.h_mcp_org.fill(mcp.getOriginX(), mcp.getOriginY());
+        }
+
+        // Find the particle responsible for the hit in each layer and compute the residual
+        
+        for(int layer=1;layer<13;++layer) {
+        	//System.out.printf("layer %d: \n",layer);
+            
+            List<SimTrackerHit> simHitsLayer = simHitsLayerMap.get(layer);
+        	
+            
+            if(simHitsLayer != null ) {
+            	
+            	if(simHitsLayer.size()==2) continue;
+            	
+                for(SimTrackerHit simHit : simHitsLayer) {
+                	
+                	 // Find the MC particle
+                    MCParticle mcp = simHit.getMCParticle();
+                    
+                    if(mcp.getMomentum().magnitude()<0.5) continue;
+                	
+                    // Position in tracking coord
+                    Hep3Vector simHitPosTracking = HPSTransformations.transformVectorToTracking(simHit.getPositionVec());
+                    
+                    if(_debug>0) {
+                        System.out.printf("%s: simHit for layer %d at %s (%s) from MC part %d org %s p %s\n",
+                                        this.getClass().getSimpleName(),layer,simHit.getPositionVec().toString(),simHitPosTracking.toString(),
+                                        simHit.getMCParticle().getPDGID(),simHit.getMCParticle().getOrigin().toString(),simHit.getMCParticle().getMomentum().toString());
+                    
+                        if(simHitPosTracking.x()<50.) System.exit(1);
+                    
+                    }    
+                    
+                   
+                    
+                    // Get track parameters from MC particle 
+                    //HelicalTrackFit htfTruth = TrackUtils.getHTF(mcp, -1*this._B.z());
+                    HelicalTrackFit htfTruth = TrackUtils.getHTF(mcp, -1*this._B.z());
+                    
+                    Hep3Vector trkposExtraPolator = TrackUtils.extrapolateTrack(htfTruth,simHitPosTracking.x());
+                    //System.out.printf("trkposextrapol (det) %s\n",trkposExtraPolator.toString());
+                    
+                    trkposExtraPolator = HPSTransformations.transformVectorToTracking(trkposExtraPolator);
+                    
+                    // Calculate residuals
+                    Hep3Vector res = VecOp.sub(simHitPosTracking, trkposExtraPolator);
+                
+                    //System.out.printf("trkpos %s trkposextrapol %s res %s\n",trkpos.toString(),trkposExtraPolator.toString(),res.toString());
+                    
+                    // Fill residuals
+                    this.res_truthsimhit.get(layer).get(0).fill(res.y());
+                    this.res_truthsimhit.get(layer).get(1).fill(res.z());
+                    if(simHit.getPositionVec().y()>0) {
+                        if(simHit.getMCParticle().getPDGID()<0) {
+                            this.res_truthsimhit_top_plus.get(layer).get(0).fill(res.y());
+                            this.res_truthsimhit_top_plus.get(layer).get(1).fill(res.z());
+                        }
+                        else {
+                            this.res_truthsimhit_top_minus.get(layer).get(0).fill(res.y());
+                            this.res_truthsimhit_top_minus.get(layer).get(1).fill(res.z());
+                        }
+                    }
+                    else {
+                        if(simHit.getMCParticle().getPDGID()<0) {
+                            this.res_truthsimhit_bot_plus.get(layer).get(0).fill(res.y());
+                            this.res_truthsimhit_bot_plus.get(layer).get(1).fill(res.z());
+                        }
+                        else {
+                            this.res_truthsimhit_bot_minus.get(layer).get(0).fill(res.y());
+                            this.res_truthsimhit_bot_minus.get(layer).get(1).fill(res.z());
+                        }
+                    }
+                    
+                    if(layer == 1 && res.y() > 0.1 && this.firstWeirdTrack) {
+                    	double dx = 1.0;
+                    	double xpos = mcp.getOriginZ();
+                    	while(xpos< 100.) {
+                    		xpos += dx;
+                    		trkposExtraPolator = HPSTransformations.transformVectorToTracking(TrackUtils.extrapolateTrack(htfTruth,xpos));
+                    		double ypos = trkposExtraPolator.y();
+                    		trkpos_y_vs_x.fill(xpos,ypos);
+                    	}
+                    	
+                    	int idummy = 0;
+                    	while(idummy<2) {
+                    		trkpos_y_vs_x.fill(simHitPosTracking.x(),simHitPosTracking.y());
+                    		idummy++;
+                    		//System.out.printf("weird simhit res pos %s \n", simHitPosTracking.toString());
+                    	}
+                    	
+                    	this.firstWeirdTrack = false;
+                    	
+                    }
+                    
+                
+                }
+            }
+        }
+        
+    }
+
+  
+    public IHistogram getResidual(int layer,String coord) {
+    	if( !this.res_truthsimhit.containsKey(layer) ) 
+    		throw new RuntimeException("Error the layer number is not valid");
+    	if( coord!="x" || coord!="y")
+    		throw new RuntimeException("Error the coord is not valid");
+    	IHistogram1D h = this.res_truthsimhit.get(layer).get(coord=="x"?0:1);
+    	return h;
+    }
+    
+
+    
+    private void makePlots() {
+        
+        
+        res_truthsimhit = new HashMap<Integer, List<IHistogram1D> >();
+        res_truthsimhit_top_plus = new HashMap<Integer, List<IHistogram1D> >();
+        res_truthsimhit_bot_plus = new HashMap<Integer, List<IHistogram1D> >();
+        res_truthsimhit_top_minus = new HashMap<Integer, List<IHistogram1D> >();
+        res_truthsimhit_bot_minus = new HashMap<Integer, List<IHistogram1D> >();
+
+        
+        
+        
+        
+        IHistogramFactory hf = aida.histogramFactory();
+        double min=-1.;
+        double max=1.;
+        
+        List<IPlotter> plotter1 = new ArrayList<IPlotter>();
+        List<IPlotter> plotter2 = new ArrayList<IPlotter>();
+        List<IPlotter> plotter3 = new ArrayList<IPlotter>();
+        List<IPlotter> plotter4 = new ArrayList<IPlotter>();
+        List<IPlotter> plotter5 = new ArrayList<IPlotter>();
+
+
+        for(int idir=0;idir<2;++idir) {
+           String dir = idir==0?"x":"y";
+           IPlotter pl1 =  af.createPlotterFactory().create(String.format("SimHit-Truth Track Residual %s",dir));
+           pl1.createRegions(3, 4);
+           IPlotter pl2 =  af.createPlotterFactory().create(String.format("SimHit-Truth Track Residual %s",dir));
+           pl2.createRegions(3, 4);
+           IPlotter pl3 =  af.createPlotterFactory().create(String.format("SimHit-Truth Track Residual %s",dir));
+           pl3.createRegions(3, 4);
+           IPlotter pl4 =  af.createPlotterFactory().create(String.format("SimHit-Truth Track Residual %s",dir));
+           pl4.createRegions(3, 4);
+           IPlotter pl5 =  af.createPlotterFactory().create(String.format("SimHit-Truth Track Residual %s",dir));
+           pl5.createRegions(3, 4);
+           
+           for(int layer=1;layer<13;++layer) {
+                
+               if(!res_truthsimhit.containsKey(layer)) {
+                   res_truthsimhit.put(layer, new ArrayList<IHistogram1D>());
+                   res_truthsimhit_top_plus.put(layer, new ArrayList<IHistogram1D>());
+                   res_truthsimhit_bot_plus.put(layer, new ArrayList<IHistogram1D>());
+                   res_truthsimhit_top_minus.put(layer, new ArrayList<IHistogram1D>());
+                   res_truthsimhit_bot_minus.put(layer, new ArrayList<IHistogram1D>());
+               } 
+     
+               if(layer<2) {
+                   max = 0.05;//0.07;
+                   min = -0.05;//-0.07;
+               } else if(layer<3) {
+                       max = 0.3;//0.07;
+                       min = -0.3;//-0.07;
+               } else {
+                   max = 0.5 * layer;
+                   min = -1.0*max;
+               }
+               
+               IHistogram1D h = hf.createHistogram1D(String.format("dres_truthsimhit_layer%d_%s",layer,dir),50, min, max);
+               h.setTitle(String.format("L%d SimHit-Truth Track Residual in %s",layer , dir));
+               res_truthsimhit.get(layer).add(h);
+               pl1.region(layer-1).plot(h);
+               
+               h = hf.createHistogram1D(String.format("res_truthsimhit_top_plus_layer%d_%s",layer,dir),50, min, max);
+               h.setTitle(String.format("L%d SimHit-Truth Track (top,q=+1) Residual in %s",layer , dir));
+               res_truthsimhit_top_plus.get(layer).add(h);
+               pl2.region(layer-1).plot(h);
+               
+               h = hf.createHistogram1D(String.format("res_truthsimhit_top_minus_layer%d_%s",layer,dir),50, min, max);
+               h.setTitle(String.format("L%d SimHit-Truth Track (top,q=-1) Residual in %s",layer , dir));
+               res_truthsimhit_top_minus.get(layer).add(h);
+               pl3.region(layer-1).plot(h);
+
+               h = hf.createHistogram1D(String.format("res_truthsimhit_bot_minus_layer%d_%s",layer,dir),50, min, max);
+               h.setTitle(String.format("L%d SimHit-Truth Track (bot,q=-1) Residual in %s",layer , dir));
+               res_truthsimhit_bot_minus.get(layer).add(h);
+               pl4.region(layer-1).plot(h);
+               
+               h = hf.createHistogram1D(String.format("res_truthsimhit_bot_plus_layer%d_%s",layer,dir),50, min, max);
+               h.setTitle(String.format("L%d SimHit-Truth Track (bot,q=+1) Residual in %s",layer , dir));
+               res_truthsimhit_bot_plus.get(layer).add(h);
+               pl5.region(layer-1).plot(h);
+               
+               
+            }
+            plotter1.add(pl1);
+            plotter2.add(pl2);
+            plotter3.add(pl3);
+            plotter4.add(pl4);
+            plotter5.add(pl5);
+
+            if(!this._hideFrame) {
+                pl1.show();
+                pl2.show();
+                pl3.show();
+                pl4.show();
+                pl5.show();
+            }
+            else {
+                pl1.hide();
+                pl2.hide();
+                pl3.hide();
+                pl4.hide();
+                pl5.hide();
+            }
+        
+        }
+        
+        
+        this.h_mcp_org = hf.createHistogram2D("MC particle origin", 50, -0.2,0.2,50,-0.2,0.2);
+        IPlotter pl_org = af.createPlotterFactory().create("MC particle origin");
+        pl_org.createRegions(1, 1);
+        pl_org.region(0).plot(h_mcp_org);
+        pl_org.region(0).style().setParameter("hist2DStyle", "colorMap");
+        pl_org.region(0).style().dataStyle().fillStyle().setParameter("colorMapScheme", "rainbow");
+        if(this._hideFrame) pl_org.hide();
+        else pl_org.show();
+        
+        
+        trkpos_y_vs_x = hf.createHistogram2D("Track pos y vs x", 300, -150,150,100,-4,4);
+        IPlotter pl_pos_y_vs_x = af.createPlotterFactory().create("Track pos y vs x");
+        pl_pos_y_vs_x.createRegions(1, 1);
+        pl_pos_y_vs_x.region(0).plot(trkpos_y_vs_x);
+        pl_pos_y_vs_x.region(0).style().setParameter("hist2DStyle", "colorMap");
+        pl_pos_y_vs_x.region(0).style().dataStyle().fillStyle().setParameter("colorMapScheme", "rainbow");
+        if(this._hideFrame) pl_pos_y_vs_x.hide();
+        else pl_pos_y_vs_x.show();
+        
+        
+        
+        
+    }
+
+   
+
+
+}
SVNspam 0.1