Print

Print


Author: mgraham
Date: Thu Oct 30 08:16:13 2014
New Revision: 1342

Log:
Straight track fitting

Added:
    java/trunk/tracking/src/main/java/org/hps/recon/tracking/nobfield/StraightTrack2DFitter.java
    java/trunk/tracking/src/main/java/org/hps/recon/tracking/nobfield/StraightTrackConfirmerExtender.java
    java/trunk/tracking/src/main/java/org/hps/recon/tracking/nobfield/StraightTrackFitter.java
    java/trunk/tracking/src/main/java/org/hps/recon/tracking/nobfield/StraightTrackReconDriver.java
      - copied, changed from r1321, java/trunk/tracking/src/main/java/org/hps/recon/tracking/TrackerReconDriver.java
    java/trunk/tracking/src/main/java/org/hps/recon/tracking/nobfield/StraightTracker.java
Removed:
    java/trunk/tracking/src/main/java/org/hps/recon/tracking/nobfield/HitOnTrackChecker.java
    java/trunk/tracking/src/main/java/org/hps/recon/tracking/nobfield/StraightTrack.java
    java/trunk/tracking/src/main/java/org/hps/recon/tracking/nobfield/TrackChecker.java
    java/trunk/tracking/src/main/java/org/hps/recon/tracking/nobfield/TrackCollectionUtilities.java
Modified:
    java/trunk/tracking/src/main/java/org/hps/recon/tracking/nobfield/StraightTrackFinder.java

Added: java/trunk/tracking/src/main/java/org/hps/recon/tracking/nobfield/StraightTrack2DFitter.java
 =============================================================================
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/nobfield/StraightTrack2DFitter.java	(added)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/nobfield/StraightTrack2DFitter.java	Thu Oct 30 08:16:13 2014
@@ -0,0 +1,131 @@
+package org.hps.recon.tracking.nobfield;
+
+import hep.physics.matrix.SymmetricMatrix;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.lcsim.fit.helicaltrack.HelicalTrackFit;
+import org.lcsim.fit.helicaltrack.HelicalTrackHit;
+import org.lcsim.fit.helicaltrack.HitUtils;
+import org.lcsim.fit.helicaltrack.MultipleScatter;
+import org.lcsim.fit.line.SlopeInterceptLineFit;
+import org.lcsim.fit.line.SlopeInterceptLineFitter;
+
+/**
+ *
+ * @author mgraham
+ */
+public class StraightTrack2DFitter {
+
+    SlopeInterceptLineFitter _lfitter = new SlopeInterceptLineFitter();
+    HelicalTrackFit _fit;
+
+    /**
+     * Status of the HelicalTrackFit.
+     */
+    public enum FitStatus {
+
+        /**
+         * Successful Fit.
+         */
+        Success,
+        /**
+         * Inconsistent seed hits
+         */
+        InconsistentSeed,
+        /**
+         * s-z line fit failed.
+         */
+        SZLineFitFailed,
+        /**
+         * ZSegmentFit failed.
+         */
+        XYLineFitFailed
+    };
+
+    public void StraightTrack2DFitter() {
+
+    }
+
+    public FitStatus fit(List<HelicalTrackHit> hits) {
+        Map<HelicalTrackHit, MultipleScatter> msmap = new HashMap<HelicalTrackHit, MultipleScatter>();
+        return fit(hits, msmap, null);
+    }
+
+    public FitStatus fit(List<HelicalTrackHit> hits, Map<HelicalTrackHit, MultipleScatter> msmap, HelicalTrackFit oldfit) {
+        //  Check that we have at least 3 hits
+        boolean success = false;
+        int nhit = hits.size();
+        if (nhit < 3)
+            return FitStatus.InconsistentSeed;
+
+        //  Create the objects that will hold the fit output
+        double[] chisq = new double[2];
+        int[] ndof = new int[2];
+        double[] par = new double[5];
+        SymmetricMatrix cov = new SymmetricMatrix(5);
+
+        //  Setup for the line fit
+        double[] s = new double[nhit];
+        double[] z = new double[nhit];
+        double[] y = new double[nhit];
+        double[] x = new double[nhit];
+        double[] dz = new double[nhit];
+        double[] dy = new double[nhit];
+        Map<HelicalTrackHit, Double> smap = new HashMap<>();
+
+        //  Store the coordinates and errors for the XY line fit
+        for (int i = 0; i < nhit; i++) {
+            HelicalTrackHit hit = hits.get(i);
+            y[i] = hit.y();
+            dy[i] = HitUtils.zres(hit, msmap, oldfit);
+            double drphi_ms = 0;
+            if (msmap.containsKey(hit))
+                drphi_ms = msmap.get(hit).drphi();
+            double dyHitSq = hit.getCorrectedCovMatrix().e(1, 1);
+            dy[i] = Math.sqrt(dyHitSq + drphi_ms * drphi_ms);
+            x[i] = hit.x();
+        }
+        //  Call the line fitter and check for success
+        success = _lfitter.fit(x, y, dy, nhit);
+        if (!success)
+            return FitStatus.XYLineFitFailed;
+        SlopeInterceptLineFit xyFit = _lfitter.getFit();        
+        par[0] = xyFit.intercept();
+        par[1] = xyFit.slope();
+        cov.setElement(0, 0, Math.pow(xyFit.interceptUncertainty(), 2));
+        cov.setElement(1, 1, Math.pow(xyFit.slopeUncertainty(), 2));
+        cov.setElement(0, 1, Math.pow(xyFit.covariance(), 2));
+        chisq[0] = xyFit.chisquared();
+        ndof[0] = xyFit.ndf();
+        //  Store the coordinates and errors for the SZ line fit
+        for (int i = 0; i < nhit; i++) {
+            HelicalTrackHit hit = hits.get(i);
+            z[i] = hit.z();
+            dz[i] = HitUtils.zres(hit, msmap, oldfit); //MG  this works even in msmap is null
+            s[i] = Math.sqrt(hit.x() * hit.x() + hit.y() * hit.y());
+            smap.put(hit, s[i]);
+        }
+        //  Call the line fitter and check for success
+        success = _lfitter.fit(s, z, dz, nhit);
+        if (!success)
+            return FitStatus.SZLineFitFailed;
+        SlopeInterceptLineFit szFit = _lfitter.getFit();
+        par[3] = szFit.intercept();
+        par[4] = szFit.slope();
+        cov.setElement(3, 3, Math.pow(szFit.interceptUncertainty(), 2));
+        cov.setElement(4, 4, Math.pow(szFit.slopeUncertainty(), 2));
+        cov.setElement(3, 4, Math.pow(szFit.covariance(), 2));
+        chisq[1] = szFit.chisquared();
+        ndof[1] = szFit.ndf();        
+        par[2] = 1e-50;
+        //  Create the HelicalTrackFit for this helix
+        _fit = new HelicalTrackFit(par, cov, chisq, ndof, smap, msmap);
+        return FitStatus.Success;
+    }
+
+    public HelicalTrackFit getFit() {
+        return _fit;
+    }
+
+}

Added: java/trunk/tracking/src/main/java/org/hps/recon/tracking/nobfield/StraightTrackConfirmerExtender.java
 =============================================================================
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/nobfield/StraightTrackConfirmerExtender.java	(added)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/nobfield/StraightTrackConfirmerExtender.java	Thu Oct 30 08:16:13 2014
@@ -0,0 +1,356 @@
+/*
+ * StraightTrackConfirmerExtender.java
+ */
+package org.hps.recon.tracking.nobfield;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import org.lcsim.fit.helicaltrack.HelicalTrackFit;
+import org.lcsim.fit.helicaltrack.HelicalTrackHit;
+import org.lcsim.recon.tracking.seedtracker.HitManager;
+import org.lcsim.recon.tracking.seedtracker.MergeSeedLists;
+import org.lcsim.recon.tracking.seedtracker.SeedCandidate;
+import org.lcsim.recon.tracking.seedtracker.SeedLayer;
+import org.lcsim.recon.tracking.seedtracker.SeedStrategy;
+import org.lcsim.recon.tracking.seedtracker.SortHits;
+import org.lcsim.recon.tracking.seedtracker.SortLayers;
+import org.lcsim.recon.tracking.seedtracker.diagnostic.ISeedTrackerDiagnostics;
+
+/**
+ * The StraightTrackConfirmerExtender class attempts to add hits to an input seed.  While the
+ * algorithms used for the confirm and extend phases are identical, there are
+ * small differences in procedures when there are no more tracker layers to check.
+ * The confirm phase simply outputs a list of SeedCandidates that have at least
+ * the minimum number of confirm hits added to the track.  The extend phases
+ * completes track finding and imposes the merge criteria to eliminate inferior
+ * track candidates when a pair of candidates shares more than one hit.
+ *
+ * @author cozzy, Richard Partridge
+ * Modified for HPS straight track fitting by Matt Graham 10/29/2014
+ */
+public class StraightTrackConfirmerExtender {
+
+    public enum Task {
+
+        CONFIRM,
+        EXTEND;
+    }
+    private int _nfit;
+    private int _maxfit = 1000000000;  // initialize maximum number of fits to 10^9
+    private HitManager _hmanager;
+    private StraightTrackFitter _fitter;
+    private MergeSeedLists _merger;
+    private List<SeedCandidate> _result;
+    private ISeedTrackerDiagnostics _diag = null;
+
+
+    /**
+     * Constructor for the ConfirmerExtender class.
+     *
+     * @param hitmanager hit manager that provides access to hits sorted by layer / sector
+     * @param helixfitter helix fitter
+     */
+    public StraightTrackConfirmerExtender(HitManager hitmanager, StraightTrackFitter helixfitter) {
+
+        _hmanager = hitmanager;
+        _fitter = helixfitter;
+        _merger = new MergeSeedLists();
+    }
+
+    /**
+     * Retrieves the result of the confirmation or extension.
+     *
+     * @return result The list of confirmed/extended seeds..
+     */
+    public List<SeedCandidate> getResult() {
+
+        return _result;
+    }
+    /**
+     * Set the maximum number of fit trials for a given seed to be confirmed/extended.
+     *
+     * @param maxfit maximum number of trials
+     */
+    public void setMaxFit(int maxfit) {
+        _maxfit = maxfit;
+    }
+
+    /**
+     * Get the number of fit trials for the last confirm/extend.
+     *
+     * @return number of helix fits
+     */
+    public int getNFit() {
+        return _nfit;
+    }
+
+    /**
+     * Set the diagnostic class to be used (null for no diagnostics).
+     *
+     * @param d diagnostic class
+     */
+    public void setDiagnostics(ISeedTrackerDiagnostics d) {
+        _diag = d;
+        _merger.setDiagnostic(_diag);
+    }
+
+    /**
+     * Try to confirm a seed using a specified strategy.  The strategy specifies
+     * the layers to use in trying to confirm the seed as well as the minimum number
+     * of confirm layers that were added to the seed.  Typically, there will be a
+     * single confirm layer that is required for a seed to be confirmed.  Confirmed
+     * seeds must also pass the chisq cut and other constraints specified in the strategy.
+     *
+     * @param seed seed to be confirmed
+     * @param strategy strategy to use for confirming this seed
+     * @param bfield magnetic field
+     * @return true if seed was confirmed
+     */
+    public boolean Confirm(SeedCandidate seed, SeedStrategy strategy, double bfield) {
+
+        //  Create a list to hold the confirmed / extended seeds
+        _result = new ArrayList<SeedCandidate>();
+
+        //  Establish which layers are to be checked
+        seed.setUncheckedLayers(strategy.getLayers(SeedLayer.SeedType.Confirm));
+
+        //  Process the seed
+        doTask(seed, Task.CONFIRM, strategy, bfield);
+
+        //  Return true if we found at least one confirming seed candidate
+        return _result.size() > 0;
+    }
+
+    /**
+     * Try to extend a seed using a specified strategy.  The strategy specifies
+     * the layers to use in extending the seed as well as the minimum number of
+     * layers required for a seed to be a track candidate.  Any track candidates
+     * found as a result of the extend operation are merged with the list of
+     * track candidates found so far to eliminate inferior fits when a pair of
+     * track candidates shares more than one hit.
+     *
+     * @param seed seed to be extended
+     * @param strategy strategy to use
+     * @param bfield magnetic field
+     * @param foundseeds list of track candidates found so far
+     */
+    public void Extend(SeedCandidate seed, SeedStrategy strategy, double bfield,
+            List<SeedCandidate> foundseeds) {
+
+        //  Initialize the list of extended seed candidates to those already found
+        _result = foundseeds;
+
+        //  Establish which layers are to be checked
+        seed.setUncheckedLayers(strategy.getLayers(SeedLayer.SeedType.Extend));
+
+        //  Extend the seed and return
+        doTask(seed, Task.EXTEND, strategy, bfield);
+        return;
+    }
+
+    /**
+     * Perform the confirm or extend step.
+     *
+     * @param inputseed seed to be confirmed/extended
+     * @param task confirm or extend (enum)
+     * @param strategy strategy to use
+     * @param bfield magnetic field
+     */
+    private void doTask(SeedCandidate inputseed, Task task, SeedStrategy strategy, double bfield) {
+
+        //  Initialize the counter for the number of fits performed on this seed
+        _nfit = 0;
+
+//        //  Instantiate the fast hit checker
+//        FastCheck checker = new FastCheck(strategy, bfield, _diag);
+//        if(this._applySectorBinning) checker.setDoSectorBinCheck(this._hmanager.getSectorManager());
+
+        //  Calculate the minimum number of hits to succeed, retrieve the chisq cuts
+        int minhits = strategy.getMinHits();
+        if (task == Task.CONFIRM) minhits = strategy.getMinConfirm() + 3;
+        double badhitchisq = strategy.getBadHitChisq();
+        double maxchisq = strategy.getMaxChisq();
+
+        //  Create a LIFO queue of seeds to be searched for a confirmation/extension
+        // hit (note that a LIFO queue is used to minimize memory usage)
+        LinkedList<SeedCandidate> seedlist = new LinkedList<SeedCandidate>();
+
+        //  The bestseed is a SeedCandidate the meets the requirements for becoming
+        //  a track, shares at least one hit with the inputseed, and has been deemed
+        //  the best such seed by the track merging criteria
+        //
+        //  Initialize the best seed to null
+        SeedCandidate bestseed = null;
+        
+        //  If we have already found track candidates, check for duplicates
+        //  that share hits with the seed, finding the best such duplicate candidate.
+        for (SeedCandidate trkcand : _result) {
+            if (_merger.isDuplicate(inputseed, trkcand))
+                bestseed = findBestCandidate(trkcand, bestseed, strategy);
+        }
+
+        //  Create a map between the SeedLayers to be checked and a list of hits on the layer to check
+        Map<SeedLayer, List<HelicalTrackHit>> hitmap = new HashMap<SeedLayer, List<HelicalTrackHit>>();
+
+        //  Loop over the layers to be checked
+        for (SeedLayer lyr : inputseed.getUncheckedLayers()) {
+
+           hitmap.put(lyr, _hmanager.getTrackerHits(lyr));
+        }
+
+        //  Create a list of layers that have hits to check
+        List<SeedLayer> lyrlist = new ArrayList<SeedLayer>();
+        lyrlist.addAll(hitmap.keySet());
+
+        //  Sort the layers in order of increasing number of hits
+        SortLayers lyrsort = new SortLayers(hitmap);
+        Collections.sort(lyrlist, lyrsort);
+
+        //  Store the layers to check in the seed
+        inputseed.setUncheckedLayers(lyrlist);
+
+        //  Start with the input seed
+        seedlist.add(inputseed);
+
+        //  Keep looping until we have fully processed all seed candidates
+        while (seedlist.size() > 0) {
+
+            //  If we have exceeded the maximum number of fits, print warning and stop processing seed candidates
+            if (_nfit > _maxfit) {
+                System.out.println("Maximum number of fits exceeded in "+task.toString()+" step");
+                if (bestseed == null) {
+                    System.out.println("No track candidates are associated with the seed hits");
+                } else {
+                    System.out.println("Track candidate with "+bestseed.getHits().size()+
+                            " hits and chisq of "+bestseed.getHelix().chisqtot()+
+                            " associated with the seed hits");
+                }
+                break;
+            }
+
+            //  Pull the last seed off the queue (use a LIFO queue to minimize queue length)
+            SeedCandidate seed = seedlist.poll();
+
+            //  Check if there are enough unchecked layers to meet the minimum number of hits
+            int lyrsleft = seed.getUncheckedLayers().size();
+            int possiblehits = lyrsleft + seed.getHits().size();
+            if (possiblehits < minhits) continue;
+
+            //  If there is a best fit candidate, see if there is still a chance of beating it
+            if (bestseed != null) {
+
+                //  If the maximimum hits we can achieve is >1 fewer than the best fit, skip this candidate
+                int besthits = bestseed.getHits().size();
+                if (possiblehits < besthits - 1) continue;
+
+                //  If the maximum hits we can achieve equals the best fit, skip if we have a worse chi2
+                double chisq = seed.getHelix().chisqtot();
+                double bestchisq = seed.getHelix().chisqtot();
+                if ((possiblehits == besthits) && chisq > bestchisq) continue;
+
+                //  If the maximum hits we can achieve is 1 fewer than the best fit, skip if the bad hit criteria can't be met
+                if ((possiblehits == besthits - 1) && (chisq > bestchisq - badhitchisq)) continue;
+            }
+
+            //  See if there are any layers left for confirm/extend
+            if (lyrsleft == 0) {
+
+                //  Take final action on this seed
+                if (task == Task.CONFIRM) {
+
+                    //  No more layers and min hit requirement is met, seed is confirmed
+                    _result.add(seed);
+                    
+                } else if (task == Task.EXTEND) {
+
+                    //  Merge the seed into the list of extended seeds
+                    boolean merged = _merger.Merge(_result, seed, strategy);
+
+                    //  If the seed survived the merge, make it our new best candidate
+                    if (merged) bestseed = findBestCandidate(seed, bestseed, strategy);
+                    }
+
+                //  Done with this seed
+                continue;
+            }
+
+            //  Pull the next layer off the queue
+            SeedLayer lyr = seed.getNextLayer();
+            HelicalTrackFit helix = seed.getHelix();
+
+            //  Retrieve the chisq for the last fit and initialize the best fit chisq for this layer
+            double oldchisq = helix.chisqtot();
+            double oldcirclechisq = helix.chisq()[0];
+            double chisqbest = 1.e99;
+
+            //  Get the list of hits to check for this layer and sort them by x-y distance from current helix
+            List<HelicalTrackHit> hitlist = hitmap.get(lyr);
+            SortHits comp = new SortHits(helix);
+            Collections.sort(hitlist, comp);
+
+            //  Loop over the sorted hits in this layer
+            for (HelicalTrackHit hit : hitlist) {
+
+                //  Make a test seed including the new hit
+                SeedCandidate test = new SeedCandidate(seed);
+                test.addHit(hit);
+
+//                //  Check that this hit is potentially viable
+//                if (!checker.CheckHitSeed(hit, seed)) {
+//                    if (_diag != null) _diag.fireCheckHitFailed(hit, test);
+//                    continue;
+//                }
+
+                //  Fit the test seed
+                boolean success = _fitter.FitCandidate(test, strategy);
+                _nfit++;
+
+
+                //  Check if the fit was successful
+                if (success) {
+
+                    //  Success - attach the fit to the test seed
+                    HelicalTrackFit newhelix = _fitter.getHelix();
+                    test.setHelix(newhelix);
+
+                    //  Add the seed to the LIFO queue of seed candidates and update the best chisq
+                    seedlist.addFirst(test);
+                    chisqbest = Math.min(chisqbest, newhelix.chisqtot());
+
+                } 
+            }
+
+            //  Finished checking hits in the current layer.  If all the fit trials for
+            //  this layer are potentially bad hits, include the starting seed (less the
+            //  current layer, which was popped off the layer queue) in the seed list.
+            if (chisqbest - oldchisq > strategy.getBadHitChisq()) seedlist.addFirst(seed);
+        }
+
+        //  Finished looping over the seeds in the LIFO candidate queue - we are done!
+        return;
+    }
+
+    /**
+     * Check two track candidates and return the best one subject to the merging criteria.
+     *
+     * @param trial new candidate to try
+     * @param oldbest previous best candidate (or null if no best candidate has been found)
+     * @param strategy strategy in use
+     * @return best track candidate
+     */
+    private SeedCandidate findBestCandidate(SeedCandidate trial, SeedCandidate oldbest, SeedStrategy strategy) {
+
+        //  If the old best candidate is null, return the trial candidate
+        if (oldbest == null) return trial;
+        
+        //  If the trial candidate is better, return it
+        if (_merger.isBetter(trial, oldbest, strategy)) return trial;
+
+        //  If no improvement, return the old candidate
+        return oldbest;
+    }
+}

Modified: java/trunk/tracking/src/main/java/org/hps/recon/tracking/nobfield/StraightTrackFinder.java
 =============================================================================
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/nobfield/StraightTrackFinder.java	(original)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/nobfield/StraightTrackFinder.java	Thu Oct 30 08:16:13 2014
@@ -1,272 +1,252 @@
+/*
+ * SeedTrackFinder.java
+ *
+ * Created on January 22, 2008, 9:39 AM
+ *
+ */
 package org.hps.recon.tracking.nobfield;
 
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
-import org.hps.recon.tracking.HitCollectionUtilites;
-import org.hps.recon.tracking.nobfield.TrackCollectionUtilities;
-import org.lcsim.event.EventHeader;
-import org.lcsim.event.Track;
-import org.lcsim.event.TrackerHit;
+import java.util.Set;
+import org.lcsim.event.MCParticle;
 import org.lcsim.fit.helicaltrack.HelicalTrackHit;
-import org.lcsim.fit.line.SlopeInterceptLineFit;
-import org.lcsim.fit.line.SlopeInterceptLineFitter;
-import org.lcsim.geometry.Detector;
-import org.lcsim.util.Driver;
+import org.lcsim.recon.tracking.seedtracker.HitManager;
+import org.lcsim.recon.tracking.seedtracker.SeedCandidate;
+import org.lcsim.recon.tracking.seedtracker.SeedLayer;
+import org.lcsim.recon.tracking.seedtracker.SeedStrategy;
+import org.lcsim.recon.tracking.seedtracker.TrackCheck;
+import org.lcsim.recon.tracking.seedtracker.diagnostic.ISeedTrackerDiagnostics;
 
 /**
  *
- * @author mgraham
+ * @author Richard Partridge
+ * @version 1.0
  */
-public class StraightTrackFinder extends Driver {
-
-    // Debug flag.
-    private boolean debug = true;
-    // Tracks found across all events.
-    int ntracks = 0;
-    // Number of events processed.
-    int nevents = 0;
-    // Cache detector object.
-    Detector detector = null;
-    // Tracking strategies resource path.
-    private String strategyResource = "HPS-Test-4pt1.xml";
-    // Output track collection.
-    private String trackCollectionName = "StraightTracks";
-    // HelicalTrackHit input collection.
-    private String stInputCollectionName = "HelicalTrackHits";
-    // 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;
-
-    private TrackChecker checkerTrack = new TrackChecker();
-    private HitOnTrackChecker checkerHOT = new HitOnTrackChecker();
-
-    private SlopeInterceptLineFitter _lfitter = new SlopeInterceptLineFitter();
-
-    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;
-    }
-
-    @Override
-    public void detectorChanged(Detector detector) {
-        // Cache Detector object.
-        this.detector = detector;
-//        initialize();
-        super.detectorChanged(detector);
-    }
-
-    @Override
-    public void process(EventHeader event) {
-        if (!event.hasCollection(HelicalTrackHit.class, stInputCollectionName))
-            return;
-
-        List<HelicalTrackHit> allHits = event.get(HelicalTrackHit.class, stInputCollectionName);
-
-        List<List<HelicalTrackHit>> splitTopBot = HitCollectionUtilites.SplitTopBottomHits(allHits);
-        // will always have top(=0) and bottom(=1) lists (though they may be empty)
-        List<HelicalTrackHit> topHits = splitTopBot.get(0);
-        List<HelicalTrackHit> bottomHits = splitTopBot.get(1);
-        //a simple strategy...eventually implement SeedTracker strategies?
-        int nTotLayers = 6;
-        int nSeed = 3;
-        int nExtra = nTotLayers - nSeed;
-        int[] seedStrategy = {1, 3, 5};
-        int[] extendStrategy = {7, 9, 11};
-        int minHits = 4;
-
-        TrackChecker checkerTrack = new TrackChecker();
-        HitOnTrackChecker checkerHOT = new HitOnTrackChecker();
-
-//        List<StraightTrack> seeds = getSeeds(seedStrategy, topHits);
-        List<StraightTrack> seeds = getSeeds(seedStrategy, allHits);
-        System.out.println("Found " + seeds.size() + " seeds");
-
-        List<StraightTrack> extendedSeeds = new ArrayList<>();
-        for (StraightTrack seed : seeds)
-            extendTrack(extendStrategy, 0, seed, allHits, extendedSeeds);
-//            extendTrack(extendStrategy, 0, seed, topHits, extendedSeeds);
-
-        System.out.println("Prepruning  :Found " + extendedSeeds.size() + " extended seeds");
-
-        //remove tracks with more than m overlaping hits...pick best chi2
-        //...
-        List<StraightTrack> finalTracks = new ArrayList<>();
-        for (StraightTrack track : extendedSeeds) {
-            boolean isbest = TrackCollectionUtilities.pruneTrackList((ArrayList<Track>) (ArrayList) extendedSeeds, track, 1);
-            if (isbest)
-                finalTracks.add(track);
-        }
-
-        System.out.println("Postpruning  :Found " + finalTracks.size() + " extended seeds");
-        event.put(trackCollectionName, finalTracks);
-    }
-
-    public SlopeInterceptLineFit FitToLine(List<HelicalTrackHit> hits, int projection) {
-        SlopeInterceptLineFit _lfit;
-        int npix = hits.size();
-        double[] s = new double[npix];
-        double[] q = new double[npix];
-        double[] dq = new double[npix];
-
-        //  Store the coordinates and errors for the line fit
-        for (int i = 0; i < npix; i++) {
-            HelicalTrackHit hit = hits.get(i);
-            s[i] = hit.z();//probably isn't quite right...track length is not z
-            if (projection == 0) { //do x vs z;
-                q[i] = hit.x();
-                dq[i] = Math.sqrt(hit.getCorrectedCovMatrix().e(0, 0));
-            } else {
-                q[i] = hit.y();
-                dq[i] = Math.sqrt(hit.getCorrectedCovMatrix().e(1, 1));
-            }
-        }
-
-        //  Call the line fitter and check for success
-        boolean success = _lfitter.fit(s, q, dq, npix);
-
-        if (!success)
-            System.out.println("Something is broken in the line fit");
-        //  Save the line fit, chi^2, and DOF
-        _lfit = _lfitter.getFit();
-        return _lfit;
-
-    }
-
-    private StraightTrack makeTrack(List<HelicalTrackHit> hits, SlopeInterceptLineFit xfit, SlopeInterceptLineFit yfit) {
-        StraightTrack track = new StraightTrack();
-        double[] pars = {-99, -99, -99, -99, -99};//this needs to have 5 fields to implement Track
-        pars[0] = xfit.intercept();
-        pars[1] = xfit.slope();
-        pars[2] = yfit.intercept();
-        pars[3] = yfit.slope();
-        track.setTrackParameters(pars);
-        track.setChi2(xfit.chisquared(), yfit.chisquared());
-        track.setNDF(xfit.ndf()+yfit.ndf());
-        for (TrackerHit hit : hits)
-            track.addHit(hit);        
-        // TODO:  set convariance, 
-        return track;
-    }
-
-    private StraightTrack makeTrack(List<HelicalTrackHit> hits) {
-        SlopeInterceptLineFit xfit = FitToLine(hits, 0);
-        SlopeInterceptLineFit yfit = FitToLine(hits, 1);
-        if (debug)
-            System.out.println("xfit = " + xfit.toString());
-        if (debug)
-            System.out.println("yfit = " + yfit.toString());        
-        return makeTrack(hits, xfit, yfit);
-    }
-
-    /*
-     *   Get all seed combinations that make sense (pass checkSeed)
-     *   currently, just assume there are 3 seed layers (don't have to be first 3 though.  
-     */
-    private List<StraightTrack> getSeeds(int[] seedLayers, List<HelicalTrackHit> hits) {
-        List<StraightTrack> seeds = new ArrayList<>();
-        int nseeds = seedLayers.length;
-        if (nseeds == 3)//TODO ... set this up so that this works for arbitrary nseeds...use recursion
-            for (HelicalTrackHit h1 : HitCollectionUtilites.GetSortedHits(hits, seedLayers[0])) {
-                if (debug)
-                    System.out.println(h1.toString());
-                for (HelicalTrackHit h2 : HitCollectionUtilites.GetSortedHits(hits, seedLayers[1])) {
-                    if (debug)
-                        System.out.println(h2.toString());
-                    for (HelicalTrackHit h3 : HitCollectionUtilites.GetSortedHits(hits, seedLayers[2])) {
-                        if (debug)
-                            System.out.println(h3.toString());
-                        //make a 3-hit test track...see if it passes CheckTrack 
-                        List<HelicalTrackHit> testTrack = new ArrayList<HelicalTrackHit>();
-                        testTrack.add(h1);
-                        testTrack.add(h2);
-                        testTrack.add(h3);                       
-                        StraightTrack trk = makeTrack(testTrack);
-                        if (!checkerTrack.checkSeed(trk))
-                            break;
-                        seeds.add(trk);
+public class StraightTrackFinder {
+
+    private HitManager _hitmanager;
+    private StraightTrackFitter _helixfitter;
+    private StraightTrackConfirmerExtender _confirmer;
+    private List<SeedCandidate> _trackseeds;
+    private ISeedTrackerDiagnostics _diag = null;
+    private Set<MCParticle> _seededmcp;
+    private Set<MCParticle> _confirmedmcp;
+    TrackCheck _trackCheck; // set by SeedTracker
+    private boolean _debug = false;
+   
+
+    /**
+     * Creates a new instance of SeedTrackFinder
+     */
+    public StraightTrackFinder(HitManager hitmanager, StraightTrackFitter helixfitter) {
+
+        //  Save the pointers to the hit manager and helix fitter classes
+        _hitmanager = hitmanager;
+        _helixfitter = helixfitter;
+
+        //  Instantiate the Confirmer/Extender and Seed Candidate merging classes
+        _confirmer = new StraightTrackConfirmerExtender(_hitmanager, _helixfitter);
+
+        //  Create a list of track seeds that have been found
+        _trackseeds = new ArrayList<SeedCandidate>();
+
+        //  Create a set of MC Particles that have been seeded, confirmed
+        _seededmcp = new HashSet<MCParticle>();
+        _confirmedmcp = new HashSet<MCParticle>();
+
+    }
+
+    public void setDiagnostic(ISeedTrackerDiagnostics d) {
+
+        //  Setup the diagnostics for this class and the classes used by this class
+        _diag = d;
+        _confirmer.setDiagnostics(_diag);
+    }
+
+    public boolean FindTracks(SeedStrategy strategy, double bfield) {
+
+        //  Instantiate the fast hit checker
+        //   FastCheck checker = new FastCheck(strategy, bfield, _diag);
+        //   if(_applySectorBinning) checker.setDoSectorBinCheck(_hitmanager.getSectorManager());
+//        SeedSectoring ss = new SeedSectoring(_hitmanager, strategy, bfield, _applySectorBinning);
+        List<SeedLayer> seeds = strategy.getLayers(SeedLayer.SeedType.Seed);
+
+//        List<List<Sector>> sslist = ss.SeedSectors();
+//        if(_debug)
+//            System.out.println(this.getClass().getSimpleName()+": number of SeedSectors="+sslist.size());
+        //  Loop over the valid sector combinations
+        //      for (List<Sector> slist : sslist) {
+            //  Loop over the first seed layer
+        for (HelicalTrackHit hit1 : _hitmanager.getTrackerHits(seeds.get(0)))
+
+            //  Loop over the second seed layer and check that we have a hit pair consistent with our strategy
+            for (HelicalTrackHit hit2 : _hitmanager.getTrackerHits(seeds.get(1))) {
+
+                //  Call _trackCheck if set
+                if (_trackCheck != null) {
+                    SeedCandidate tempseed = new SeedCandidate(strategy, bfield);
+                    tempseed.addHit(hit1);
+                    tempseed.addHit(hit2);
+                    if (!_trackCheck.checkSeed(tempseed))
+                        continue;
+                }
+
+//                    //  Check if the pair of hits is consistent with the current strategy
+//                    if (!checker.TwoPointCircleCheck(hit1, hit2, null)) {
+//                        if (_diag != null) _diag.fireCheckHitPairFailed(hit1, hit2);
+//                        continue;
+//                    }
+                //  Loop over the third seed layer and check that we have a hit triplet consistent with our strategy
+                for (HelicalTrackHit hit3 : _hitmanager.getTrackerHits(seeds.get(2))) {
+                    //  Call _trackCheck if set
+                    if (_trackCheck != null) {
+                        SeedCandidate tempseed2 = new SeedCandidate(strategy, bfield);
+                        tempseed2.addHit(hit1);
+                        tempseed2.addHit(hit3);
+                        if (!_trackCheck.checkSeed(tempseed2))
+                            continue;
+
+                        SeedCandidate tempseed3 = new SeedCandidate(strategy, bfield);
+                        tempseed3.addHit(hit2);
+                        tempseed3.addHit(hit3);
+                        if (!_trackCheck.checkSeed(tempseed3))
+                            continue;
                     }
+
+                    //  Form a seed candidate from the seed hits
+                    SeedCandidate seed = new SeedCandidate(strategy, bfield);
+                    seed.addHit(hit1);
+                    seed.addHit(hit2);
+                    seed.addHit(hit3);
+
+//                        //  Check if the triplet of hits is consistent with the current strategy
+//                        if (!checker.ThreePointHelixCheck(hit1, hit2, hit3)) {
+//
+//                            if (_diag != null) {
+//                                if (seed.isTrueSeed())
+//                                _diag.fireCheckHitTripletFailed(hit1, hit2, hit3);
+//                            }
+//                            continue;
+//                        }
+                        //  Form a seed candidate from the seed hits
+                    //  If it's a true seed, add the MC Particle to those that were seeded
+                    if (_diag != null)
+                        if (seed.isTrueSeed())
+                            _seededmcp.addAll(seed.getMCParticles());
+
+                    if (_debug)
+                        System.out.println(this.getClass().getSimpleName() + ": fit the candidate");
+
+                    //  See if we can fit a helix to this seed candidate
+                    boolean success = _helixfitter.FitCandidate(seed, strategy);
+
+                    if (!success)
+                        continue;
+
+                    if (_debug)
+                        System.out.println(this.getClass().getSimpleName() + ": fit success");
+
+                    //  Save the helix fit
+                    seed.setHelix(_helixfitter.getHelix());
+
+                    // Check the seed - hook for plugging in external constraint
+                    if (_trackCheck != null)
+                        if (!_trackCheck.checkSeed(seed))
+                            continue;
+
+                    //  See if we can confirm this seed candidate
+                    success = _confirmer.Confirm(seed, strategy, bfield);
+                    if (!success)
+                        continue;
+
+                    if (_debug)
+                        System.out.println(this.getClass().getSimpleName() + ": confirmed seed");
+
+                    //  Confirmed a seed - if it's a true seed, add the MC Particle to those that were confirmed
+                    if (_diag != null)
+                        if (seed.isTrueSeed())
+                            _confirmedmcp.addAll(seed.getMCParticles());
+
+                    if (_debug)
+                        System.out.println(this.getClass().getSimpleName() + ": try to extend");
+
+                    //  Try to extend each confirmed seed candidates to make a track candidate
+                    List<SeedCandidate> confirmedlist = _confirmer.getResult();
+                    for (SeedCandidate confirmedseed : confirmedlist)
+
+                        //  See if we can extend this seed candidate
+                        _confirmer.Extend(confirmedseed, strategy, bfield, _trackseeds);
                 }
             }
-        return seeds;
-    }
-
-    /*
-     * recursively extend the seeds through all of the extend layers..
-     * ...I think this should work...
-     */
-    private void extendTrack(int[] extendLayers, int n, StraightTrack origTrack, List<HelicalTrackHit> hits, List<StraightTrack> trackList) {
-        if (n >= extendLayers.length) {
-            if (debug)
-                System.out.println("Done finding this track through all " + n + " extra layers");
-            trackList.add(origTrack);
-            return;
-        }
-
-        boolean cannotExtendThisLayer = true;
-        if (debug)
-            System.out.println("Extending to layer " + extendLayers[n]);
-        for (HelicalTrackHit h : HitCollectionUtilites.GetSortedHits(hits, extendLayers[n])) {
-            //let's see if this hit makes sense to add to original track
-            if (!checkerHOT.checkNewHit(origTrack, h))
-                continue;
-
-            List<TrackerHit> origHits = origTrack.getTrackerHits();
-            //make a new list and cast them as HelicalTrackHits (Track only stores TrackerHits)
-            List<HelicalTrackHit> newHits = new ArrayList<>();
-            for (TrackerHit oh : origHits) {
-                HelicalTrackHit hoh = (HelicalTrackHit) oh;
-                System.out.println(hoh.getPosition()[0]);
-                newHits.add(hoh);
-            }
-            //add the new hit to the list & make new track
-            newHits.add(h);
-            StraightTrack newTrack = makeTrack(newHits);
-            //check the new track after we've added this hit
-            if (!checkerTrack.checkTrack(newTrack))
-                continue;
-            cannotExtendThisLayer = false;
-            //extend again to the next layer
-            extendTrack(extendLayers, n + 1, newTrack, hits, trackList);
-        }
-
-        //didn't find any hits in this layer that match the track...but let's try the next one
-        if (cannotExtendThisLayer)
-            extendTrack(extendLayers, n + 1, origTrack, hits, trackList);
-
-        return;
+
+//        //  Done with track finding for this strategy
+//        if (_diag != null)
+//            _diag.fireFinderDone(_trackseeds, _seededmcp);
+        return _trackseeds.size() > 0;
+    }
+
+    /**
+     * Return the list of track candidates.
+     *
+     * @return track candidates
+     */
+    public List<SeedCandidate> getTrackSeeds() {
+        return _trackseeds;
+    }
+
+    /**
+     * Clear the list of track candidates accumulated from previous calls to
+     * SeedTrackFinder (typically done before starting a new event).
+     */
+    public void clearTrackSeedList() {
+        _trackseeds.clear();
+        _seededmcp.clear();
+        _confirmedmcp.clear();
+    }
+
+    /**
+     * Set the maximum number of fits for a given seed in a confirm or extend
+     * step.
+     *
+     * @param maxfits maximum number of fits
+     */
+    public void setMaxFit(int maxfits) {
+        _confirmer.setMaxFit(maxfits);
+    }
+
+    /**
+     * Return the list of MCParticles that formed valid 3-hit seeds.
+     *
+     * @return list of seeded MCParticles
+     */
+    public Set<MCParticle> getSeededMCParticles() {
+        return _seededmcp;
+    }
+
+    /**
+     * Return the list of confirmed MCParticles.
+     *
+     * @return confirmed MCParticles
+     */
+    public Set<MCParticle> getConfirmedMCParticles() {
+        return _confirmedmcp;
+    }
+
+    /**
+     * Return the StraightTrackConfirmerExtender
+     *
+     * @return confirmer/extender object
+     *
+     */
+    public StraightTrackConfirmerExtender getConfirmer() {
+        return _confirmer;
+    }
+
+    public void setDebug(boolean debug) {
+        System.out.println("Setting " + this.getClass().getSimpleName() + " debug to " + debug);
+        _debug = debug;
     }
 
 }

Added: java/trunk/tracking/src/main/java/org/hps/recon/tracking/nobfield/StraightTrackFitter.java
 =============================================================================
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/nobfield/StraightTrackFitter.java	(added)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/nobfield/StraightTrackFitter.java	Thu Oct 30 08:16:13 2014
@@ -0,0 +1,261 @@
+/*
+ * HelixFitter.java
+ *
+ * Created on January 22, 2008, 9:25 AM
+ *
+ */
+package org.hps.recon.tracking.nobfield;
+
+import java.util.List;
+import java.util.Map;
+import org.hps.recon.tracking.MaterialManager;
+import org.hps.recon.tracking.MultipleScattering;
+import org.hps.recon.tracking.nobfield.StraightTrack2DFitter.FitStatus;
+import org.lcsim.fit.circle.CircleFit;
+import org.lcsim.fit.helicaltrack.HelicalTrackCross;
+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.fit.zsegment.ZSegmentFit;
+import org.lcsim.recon.tracking.seedtracker.ConstrainHelix;
+import org.lcsim.recon.tracking.seedtracker.SeedCandidate;
+import org.lcsim.recon.tracking.seedtracker.SeedStrategy;
+import org.lcsim.recon.tracking.seedtracker.TrackCheck;
+import org.lcsim.recon.tracking.seedtracker.diagnostic.ISeedTrackerDiagnostics;
+
+/**
+ *
+ * @author Richard Partridge
+ * @version 1.0
+ */
+public class StraightTrackFitter {
+
+    private StraightTrack2DFitter _fitter = new StraightTrack2DFitter();
+    protected MultipleScattering _scattering;
+    private HelicalTrackFit _helix;//still use HelicalTrackFit...
+    private MaterialManager _materialmanager;
+    //private ConstrainHelix _constrain;
+    private double _bfield = 0.;
+    private CircleFit _circlefit;
+    private SlopeInterceptLineFit _linefit;
+    private ZSegmentFit _zsegmentfit;
+    private FitStatus _status;
+    private ISeedTrackerDiagnostics _diag = null;
+    TrackCheck _trackCheck; // set by SeedTracker
+    private boolean _debug = false;
+
+    /**
+     * Creates a new instance of StraightTrackFitter
+     */
+    public StraightTrackFitter(MaterialManager materialmanager) {
+        _materialmanager = materialmanager;
+
+        _scattering = new MultipleScattering(_materialmanager);
+
+        //   _constrain = new ConstrainHelix();
+    }
+
+    //   public boolean FitCandidate(SeedCandidate seed, SeedStrategy strategy) {
+    public boolean FitCandidate(SeedCandidate seed, SeedStrategy strategy) {// change this to something reasonable
+        if (_debug)
+            System.out.printf("%s: FitCandidate() with strategy: \"%s\"\n", this.getClass().getSimpleName(), strategy.getName());
+
+        //  Initialize fit results to null objects
+        _helix = null;
+
+        //  Check that we have set the magnetic field
+        if (_bfield != 0.)
+            throw new RuntimeException("B Field should be zero for the straight track fitter");
+
+        //  Set the tolerance in the fitter
+        //  _fitter.setTolerance(Math.sqrt(strategy.getMaxChisq()));
+        //  Retrieve list of hits to be fit
+        List<HelicalTrackHit> hitlist = seed.getHits();
+
+        if (_debug) {
+            System.out.println(this.getClass().getSimpleName() + ": hitlist size " + hitlist.size() + ":");
+            double z_prev = -99999999.9;
+            for (HelicalTrackHit hit : hitlist) {
+                System.out.printf("%s: (%.2f,%.2f,%.2f) corrected  %s\n",
+                        this.getClass().getSimpleName(), hit.getPosition()[0], hit.getPosition()[1], hit.getPosition()[2],
+                        hit.getCorrectedPosition().toString());
+                if (z_prev < -99999999.0)
+                    z_prev = hit.getPosition()[2];
+                else {
+                    if (Math.signum(z_prev) != Math.signum(hit.getPosition()[2]))
+                        System.out.printf("%s: topBotHits in event\n", this.getClass().getSimpleName());
+                    z_prev = hit.getPosition()[2];
+                }
+            }
+        }
+        //  Retrieve the old helix
+        HelicalTrackFit oldhelix = seed.getHelix();
+
+        //  If this is the candidate's first helix fit, first do a fit without MS errors
+        if (oldhelix == null) {
+
+            if (_debug)
+                System.out.println(this.getClass().getSimpleName() + ": no old helix do the fit without MS scattering map");
+
+            //  Reset the stereo hit positions to their nominal value
+            for (HelicalTrackHit hit : hitlist)
+                if (hit instanceof HelicalTrackCross)
+                    ((HelicalTrackCross) hit).resetTrackDirection();
+            //  Do the fit
+            _status = _fitter.fit(hitlist);
+            SaveFit();
+
+            //  Retrieve the helix parameters from this fit and save them in the seed
+            oldhelix = _fitter.getFit();
+            seed.setHelix(oldhelix);
+
+            if (_debug)
+                System.out.printf("%s: fit succeeded, will be used as seed, with chi2=%.3f and helix:\n%s \n", this.getClass().getSimpleName(), oldhelix.chisqtot(), oldhelix.toString());
+
+            //  Calculate the multiple scattering angles for this helix
+            try {
+               seed.setScatterAngles(_scattering.FindScatters(oldhelix)); 
+            } catch (Exception e) {
+               System.err.println(e);
+               if(_debug)
+               {
+                   e.printStackTrace();
+               }
+               return false;
+            }
+            
+            if(_debug) {
+                System.out.printf("%s: after calculating the MS map it has %d size:\n",this.getClass().getSimpleName(),seed.getMSMap().size());
+                for(Map.Entry<HelicalTrackHit, MultipleScatter> ms : seed.getMSMap().entrySet()) {
+                    System.out.printf("%s: Hit at layer %d and position %s has MS drpdhi=%f and dz=%f\n",
+                                    this.getClass().getSimpleName(),ms.getKey().Layer(),ms.getKey().getCorrectedPosition().toString(),ms.getValue().drphi(),ms.getValue().dz());
+                }
+            }
+
+        }
+
+        if (_debug)
+            System.out.printf("%s: update the stereo hit positions with the old helix:\n%s \n", this.getClass().getSimpleName(), oldhelix.toString());
+
+        //  Update the stereo hit positions and covariance matrices
+        CorrectStereoHits(hitlist, oldhelix);
+
+        //  Do a helix fit including MS errors
+        if(_debug) {
+            System.out.printf("%s: do the helix fit including MS map this time: \n",this.getClass().getSimpleName());
+            for(Map.Entry<HelicalTrackHit, MultipleScatter> ms : seed.getMSMap().entrySet()) {
+                    System.out.printf("%s: Hit at layer %d and position %s has MS drpdhi=%f and dz=%f\n",
+                                    this.getClass().getSimpleName(),ms.getKey().Layer(),ms.getKey().getCorrectedPosition().toString(),ms.getValue().drphi(),ms.getValue().dz());
+            }
+        }
+        _status = _fitter.fit(hitlist, seed.getMSMap(), oldhelix);
+        SaveFit();
+
+        //  Retrieve and save the new helix fit
+        _helix = _fitter.getFit();
+        seed.setHelix(_helix);
+        if ((_trackCheck != null) && (!_trackCheck.checkSeed(seed)))
+            return false;
+
+        //  Set the non-holonomic constraint chi square...don't worry about this for now-- MG 10/29/2014
+        //       _constrain.setConstraintChisq(strategy, _helix, hitlist);
+        //  If the total chi square is below the cut, we have a successful fit
+        boolean success = _helix.chisqtot() <= strategy.getMaxChisq();
+        if (!success)
+            if (_diag != null)
+                _diag.fireFailedChisqCut(seed);
+
+//        //  If fit was successful, set the new multiple scattering angles
+        if (success) {
+            seed.setScatterAngles(_scattering.FindScatters(_helix));
+            if (_debug)
+                System.out.printf("%s: this fit was successful, chi2=%f with resulting helix paramaters:\n%s\n", this.getClass().getSimpleName(), _helix.chisqtot(), _helix.toString()); //                System.out.printf("%s: updated MS map before returning from fitCandidate():\n",this.getClass().getSimpleName());       
+            //                for(Map.Entry<HelicalTrackHit, MultipleScatter> ms : seed.getMSMap().entrySet()) {
+            //                    System.out.printf("%s: Hit at layer %d and position %s has MS drpdhi=%f and dz=%f\n",
+            //                                    this.getClass().getSimpleName(),ms.getKey().Layer(),ms.getKey().getCorrectedPosition().toString(),ms.getValue().drphi(),ms.getValue().dz());
+
+        } else if (_debug)
+            System.out.printf("%s: this fit with chi2=%f failed!\n", this.getClass().getSimpleName(), _helix.chisqtot());
+
+        return success;
+    }
+
+    public void setDiagnostics(ISeedTrackerDiagnostics d) {
+        _diag = d;
+        return;
+    }
+
+    public HelicalTrackFit getHelix() {
+        return _helix;
+    }
+
+    public FitStatus getFitStatus() {
+        return _status;
+    }
+
+    public CircleFit getCircleFit() {
+        return _circlefit;
+    }
+
+    public SlopeInterceptLineFit getLineFit() {
+        return _linefit;
+    }
+
+    public ZSegmentFit getZSegmentFit() {
+        return _zsegmentfit;
+    }
+
+    public void setBField(double bfield) {
+        _bfield = bfield;
+        _scattering.setBField(_bfield);
+        //   _constrain.setBField(_bfield);
+        return;
+    }
+
+    public void setReferencePoint(double x, double y) {
+        //      _fitter.setReferencePoint(x, y);
+        return;
+    }
+
+    private void SaveFit() {
+
+        //  Default to no fit results when circle fit fails
+        _circlefit = null;
+        _linefit = null;
+        _zsegmentfit = null;
+
+        //  If we have a circle fit, try to save the line fit / zsegment fit results
+        if (_status == FitStatus.InconsistentSeed)
+            return;
+        if (_status == FitStatus.XYLineFitFailed)
+            return;
+        if (_status == FitStatus.SZLineFitFailed)
+            return;
+        //     _linefit = _fitter.getLineFit();
+//        _zsegmentfit = _fitter.getZSegmentFit();
+
+        return;
+    }
+
+    private void CorrectStereoHits(List<HelicalTrackHit> hitlist, HelicalTrackFit helix) {
+
+        //  Get the PathMap - used to find the track direction at the hit location
+        Map<HelicalTrackHit, Double> pathmap = helix.PathMap();
+
+        //  Loop over the hits and look for stereo hits
+        for (HelicalTrackHit hit : hitlist)
+            if (hit instanceof HelicalTrackCross)
+                if (pathmap.containsKey(hit)) {                   
+                    //  Found a stereo hit - calculate the track direction and pass it to the hit
+                    ((HelicalTrackCross) hit).setTrackDirection(helix);
+                }
+        return;
+    }
+
+    public void setDebug(boolean debug) {
+        this._debug = debug;
+        _scattering.setDebug(true);
+    }
+}

Copied: java/trunk/tracking/src/main/java/org/hps/recon/tracking/nobfield/StraightTrackReconDriver.java (from r1321, java/trunk/tracking/src/main/java/org/hps/recon/tracking/TrackerReconDriver.java)
 =============================================================================
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/TrackerReconDriver.java	(original)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/nobfield/StraightTrackReconDriver.java	Thu Oct 30 08:16:13 2014
@@ -1,9 +1,9 @@
-package org.hps.recon.tracking;
+package org.hps.recon.tracking.nobfield;
 
 import hep.physics.vec.BasicHep3Vector;
-
 import java.util.List;
-
+import org.hps.recon.tracking.CoordinateTransformations;
+import org.hps.recon.tracking.nobfield.StraightTracker;
 import org.lcsim.event.EventHeader;
 import org.lcsim.event.Track;
 import org.lcsim.event.base.BaseTrack;
@@ -21,7 +21,7 @@
  *
  * @author Matt Graham
  */
-public final class TrackerReconDriver extends Driver {
+public final class StraightTrackReconDriver extends Driver {
 
     // Debug flag.
     private boolean debug = false;
@@ -34,9 +34,9 @@
     // Default B-field value.
     private double bfield = 0.5;
     // Tracking strategies resource path.
-    private String strategyResource = "HPS-Test-4pt1.xml";
+    private String strategyResource = "HPS-Full.xml";
     // Output track collection.
-    private String trackCollectionName = "MatchedTracks";
+    private String trackCollectionName = "StraightTracks";
     // HelicalTrackHit input collection.
     private String stInputCollectionName = "RotatedHelicalTrackHits";
     // Include MS (done by removing XPlanes from the material manager results)
@@ -49,7 +49,7 @@
     private boolean _applySectorBinning = true;
     private double rmsTimeCut = -1;
 
-    public TrackerReconDriver() {
+    public StraightTrackReconDriver() {
     }
 
     public void setDebug(boolean debug) {
@@ -134,15 +134,15 @@
      */
     private void initialize() {
 
-        //
+        // 
         // 1) Driver to run Seed Tracker.
         //
         if (!strategyResource.startsWith("/")) {
             strategyResource = "/org/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);
+        StraightTracker stFinal = new StraightTracker(sFinallist, this._useHPSMaterialManager, this.includeMS);
+//        stFinal.setApplySectorBinning(_applySectorBinning);
         stFinal.setUseDefaultXPlane(false);
         stFinal.setDebug(this.debug);
         stFinal.setIterativeConfirmed(_iterativeConfirmed);
@@ -156,10 +156,10 @@
         // stFinal.setSectorParams(false); //this doesn't actually seem to do anything
         stFinal.setSectorParams(1, 10000);
         add(stFinal);
-
-        if (rmsTimeCut > 0) {
-            stFinal.setTrackCheck(new HitTimeTrackCheck(rmsTimeCut));
-        }
+//
+//        if (rmsTimeCut > 0) {
+//            stFinal.setTrackCheck(new HitTimeTrackCheck(rmsTimeCut));
+//        }
     }
 
     /**

Added: java/trunk/tracking/src/main/java/org/hps/recon/tracking/nobfield/StraightTracker.java
 =============================================================================
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/nobfield/StraightTracker.java	(added)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/nobfield/StraightTracker.java	Thu Oct 30 08:16:13 2014
@@ -0,0 +1,328 @@
+/*
+ * SeedTracker.java
+ *
+ * Created on August 16, 2005, 8:54 AM
+ *
+ */
+package org.hps.recon.tracking.nobfield;
+
+import hep.physics.vec.BasicHep3Vector;
+import hep.physics.vec.Hep3Vector;
+
+import java.util.*;
+import org.hps.recon.tracking.MaterialManager;
+import org.hps.recon.tracking.MaterialSupervisor;
+import org.lcsim.detector.ITransform3D;
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.MCParticle;
+import org.lcsim.fit.helicaltrack.HelicalTrackHit;
+import org.lcsim.geometry.Detector;
+import org.lcsim.recon.tracking.seedtracker.DefaultStrategy;
+import org.lcsim.recon.tracking.seedtracker.HitManager;
+import org.lcsim.recon.tracking.seedtracker.MakeTracks;
+import org.lcsim.recon.tracking.seedtracker.SeedCandidate;
+import org.lcsim.recon.tracking.seedtracker.SeedStrategy;
+import org.lcsim.recon.tracking.seedtracker.TrackCheck;
+import org.lcsim.recon.tracking.seedtracker.diagnostic.ISeedTrackerDiagnostics;
+import org.lcsim.util.Driver;
+import org.lcsim.util.aida.AIDA;
+
+/**
+ * Tracking algorithm based on forming track seeds from all 3-hit combinations,
+ * confirming this tentantive helix by requiring additional hits, and extending
+ * the track to additional layers. The operation of the algorithm is controlled
+ * by a list of SeedStrategy that define the tracker layers to be used and the
+ * cuts on the tracking algorithm.
+ *
+ * @author Richard Partridge
+ * @version 1.0
+ */
+public class StraightTracker extends Driver {
+
+    protected List<SeedStrategy> _strategylist;
+    protected ISeedTrackerDiagnostics _diag = null;
+    protected MaterialManager _materialmanager = new MaterialManager();
+    protected HitManager _hitmanager;
+    protected StraightTrackFitter _helixfitter;
+    protected StraightTrackFinder _finder;
+    protected MakeTracks _maketracks;
+    protected Hep3Vector _IP = new BasicHep3Vector(0., 0., 0.);
+    protected double _bfield = 0.;
+    protected boolean _forceBField = false;
+    protected double _rtrk = 1000.;
+    protected boolean _autosectoring = false;
+    protected AIDA aida = AIDA.defaultInstance();
+    protected boolean _timing = false;
+    protected String _inputCol = "HelicalTrackHits";
+    private int _iterativeConfirmedFits = 0;
+    private boolean _debug = false;
+
+    /**
+     * Creates a new instance of SeedTracker
+     */
+    public StraightTracker() {
+        this(new DefaultStrategy().getStrategyList(), true, true);
+    }
+
+    public StraightTracker(List<SeedStrategy> strategylist, boolean includeMS) {
+        initialize(strategylist, true, includeMS);
+    }
+
+    public StraightTracker(List<SeedStrategy> strategylist, boolean useHPSMaterialManager, boolean includeMS) {
+        initialize(strategylist, useHPSMaterialManager, includeMS);
+    }
+
+    private void initialize(List<SeedStrategy> strategylist, boolean useHPSMaterialManager, boolean includeMS) {
+        _strategylist = strategylist;
+        //  Instantiate the hit manager
+        _hitmanager = new HitManager();
+        //  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 StraightTrackFitter(materialSupervisor);
+        } else {
+            MaterialManager materialmanager = new MaterialManager(includeMS);
+            _materialmanager = materialmanager; //mess around with types here...
+            _helixfitter = new StraightTrackFitter(materialmanager);
+        }
+        //  Instantiate the Seed Finder
+        _finder = new StraightTrackFinder(_hitmanager, _helixfitter);
+        //  Instantiate the Track Maker
+        _maketracks = new MakeTracks();
+    }
+
+    /**
+     * Set to enable debug output
+     *
+     * @param debug switch
+     */
+    public void setDebug(boolean debug) {
+        _debug = true;
+        _materialmanager.setDebug(debug);
+        _helixfitter.setDebug(debug);
+        _finder.setDebug(debug);
+    }
+
+    @Override
+    protected void process(EventHeader event) {
+
+//        System.out.println("New event");
+        //  Pass the event to the diagnostics package
+        if (_diag != null)
+            _diag.setEvent(event);
+
+        //  Initialize timing
+        long last_time = System.currentTimeMillis();
+
+        //  Get the hit collection from the event
+        List<HelicalTrackHit> hitcol = event.get(HelicalTrackHit.class, _inputCol);
+        if (_debug)
+            System.out.println("In " + this.getClass().getSimpleName() + ":  Number of HelicalTrackHits=" + hitcol.size());
+        //  Sort the hits for this event
+        _hitmanager.OrganizeHits(hitcol);
+
+        //  Make the timing plots if requested
+        long start_time = System.currentTimeMillis();
+        double dtime = ((double) (start_time - last_time)) / 1000.;
+        last_time = start_time;
+        if (_timing)
+            aida.cloud1D("Organize Hits").fill(dtime);
+
+        //  Make sure that we have cleared the list of track seeds in the finder
+        _finder.clearTrackSeedList();
+
+        //  Loop over strategies and perform track finding
+        for (SeedStrategy strategy : _strategylist) {
+
+            //  Set the strategy for the diagnostics
+            if (_diag != null)
+                _diag.fireStrategyChanged(strategy);
+
+            //  Perform track finding under this strategy
+            _finder.FindTracks(strategy, _bfield);
+            if (_debug)
+                System.out.println("In " + this.getClass().getSimpleName() + ":  Number of Tracks Found=" + _finder.getTrackSeeds().size());
+            //  Make the timing plots if requested
+            long time = System.currentTimeMillis();
+            dtime = ((double) (time - last_time)) / 1000.;
+            last_time = time;
+            if (_timing)
+                aida.cloud1D("Tracking time for strategy " + strategy.getName()).fill(dtime);
+        }
+
+        //  Get the list of final list of SeedCandidates
+        List<SeedCandidate> trackseeds = _finder.getTrackSeeds();
+
+        if (_iterativeConfirmedFits > 0) {
+            // Iteratively re-fit tracks to take into account helix and hit position correlations
+            if (_debug)
+                System.out.printf("%s: Iteratively improve %d seeds\n", this.getClass().getSimpleName(), trackseeds.size());
+            List<SeedCandidate> seedsToRemove = new ArrayList<SeedCandidate>();
+            for (SeedCandidate seed : trackseeds) {
+                SeedStrategy strategy = seed.getSeedStrategy();
+                boolean success = false;
+                for (int iterFit = 0; iterFit < _iterativeConfirmedFits; ++iterFit)
+                    success = _helixfitter.FitCandidate(seed, strategy);
+                if (!success)
+                    seedsToRemove.add(seed);
+//                else if (_debug)
+//                    System.out.printf("%s: done iterating, this seed will be added to event:\n%s\n", this.getClass().getSimpleName(), seed.toString());
+            }
+            for (SeedCandidate badseed : seedsToRemove)
+                trackseeds.remove(badseed);
+        }
+
+        //  Make tracks from the final list of track seeds
+        _maketracks.Process(event, trackseeds, _bfield);
+
+        //  Save the MC Particles that have been seeded / confirmed if diagnostics are enabled
+        if (_diag != null) {
+            Set<MCParticle> seededmcpset = _finder.getSeededMCParticles();
+            List<MCParticle> seededmcp = new ArrayList<MCParticle>(seededmcpset);
+            event.put("SeededMCParticles", seededmcp, MCParticle.class, 0);
+            Set<MCParticle> confirmedmcpset = _finder.getConfirmedMCParticles();
+            List<MCParticle> confirmedmcp = new ArrayList<MCParticle>(confirmedmcpset);
+            event.put("ConfirmedMCParticles", confirmedmcp, MCParticle.class, 0);
+        }
+
+        //  Clear the list of track seeds accumulated in the track finder
+        _finder.clearTrackSeedList();
+
+        //  Make the total time plot if requested
+        long end_time = System.currentTimeMillis();
+        dtime = ((double) (end_time - start_time)) / 1000.;
+        if (_timing)
+            aida.cloud1D("Total tracking time").fill(dtime);
+
+        return;
+    }
+
+    @Override
+    protected void detectorChanged(Detector detector) {
+
+        //  Only build the model when the detector is changed
+        _materialmanager.buildModel(detector);
+
+        //  Find the bfield and pass it to the helix fitter and diagnostic package
+        if (!_forceBField)
+            _bfield = detector.getFieldMap().getField(_IP).z();
+
+        if (_diag != null)
+            _diag.setBField(_bfield);
+        _helixfitter.setBField(_bfield);
+
+        //  Get the tracking radius
+        _rtrk = _materialmanager.getRMax();
+
+        //  Set the sectoring parameters
+        if (_autosectoring)
+            _hitmanager.setSectorParams(_strategylist, _bfield, _rtrk);
+    }
+
+    /**
+     * Specifiy the strategies to be used by the SeedTracker algorithm. Invoking
+     * this
+     * method will override the default strategies defined by the
+     * DefaultStrategy
+     * class.
+     *
+     * @param strategylist List of strategies to be used
+     */
+    public void putStrategyList(List<SeedStrategy> strategylist) {
+
+        //  Save the strategy list
+        _strategylist = strategylist;
+
+        //  Set the sectoring parameters
+        if (_autosectoring)
+            _hitmanager.setSectorParams(strategylist, _bfield, _rtrk);
+
+        return;
+    }
+
+    public void setSectorParams(int nphi, double dz) {
+        _hitmanager.setSectorParams(nphi, dz);
+        _autosectoring = false;
+        return;
+    }
+
+    public void setDiagnostics(ISeedTrackerDiagnostics d) {
+
+        //  Set the diagnostic package
+        _diag = d;
+        _helixfitter.setDiagnostics(_diag);
+        _finder.setDiagnostic(_diag);
+
+        //  Pass the hit manager, material manager, and bfield to the diagnostic package
+        if (_diag != null) {
+            _diag.setMaterialManager(_materialmanager);
+            _diag.setHitManager(_hitmanager);
+            _diag.setBField(_bfield);
+        }
+    }
+
+    public void setTimingPlots(boolean timing) {
+        _timing = timing;
+    }
+
+    public void setTrkCollectionName(String name) {
+        _maketracks.setTrkCollectionName(name);
+    }
+
+    public void setInputCollectionName(String name) {
+        _inputCol = name;
+    }
+
+    public void setMaterialManagerTransform(ITransform3D _detToTrk) {
+        _materialmanager.setTransform(_detToTrk);
+    }
+
+    /**
+     * Set the maximum number of fits used to confirm or extend a seed.
+     *
+     * @param maxfit maximum number of fits
+     */
+    public void setMaxFit(int maxfit) {
+        _finder.setMaxFit(maxfit);
+    }
+
+    public void setBField(double bfield) {
+        _forceBField = true;
+        _bfield = bfield;
+    }
+
+    public void setReferencePoint(double xref, double yref) {
+        _helixfitter.setReferencePoint(xref, yref);
+    }
+
+    public void setSectorParams(boolean sector) {
+        _hitmanager.setDoSectoring(sector);
+    }
+
+    /**
+     * Set {@link TrackCheck} object to be used by the track finding algorithm.
+     * If this method is never called, no external checking of seeds and tracks
+     * is performed.
+     */
+    public void setTrackCheck(TrackCheck trackCheck) {
+        _finder._trackCheck = trackCheck;
+        _maketracks._trackCheck = trackCheck;
+    }
+
+    /**
+     * Set the maximum number of iterative fits on a confirmed/extended
+     * candidate.
+     *
+     * @param maxfits maximum number of fits
+     */
+    public void setIterativeConfirmed(int maxfits) {
+        this._iterativeConfirmedFits = maxfits;
+    }
+
+    public void setUseDefaultXPlane(boolean useDefault) {
+        _materialmanager.setDefaultXPlaneUsage(useDefault);
+
+    }
+
+}