Print

Print


Author: [log in to unmask]
Date: Tue Jul 26 14:16:03 2016
New Revision: 4434

Log:
Update single hit efficiency analysis so it can handle multiple track collections.

Modified:
    java/trunk/users/src/main/java/org/hps/users/omoreno/SvtHitEfficiency.java

Modified: java/trunk/users/src/main/java/org/hps/users/omoreno/SvtHitEfficiency.java
 =============================================================================
--- java/trunk/users/src/main/java/org/hps/users/omoreno/SvtHitEfficiency.java	(original)
+++ java/trunk/users/src/main/java/org/hps/users/omoreno/SvtHitEfficiency.java	Tue Jul 26 14:16:03 2016
@@ -8,9 +8,8 @@
 
 import hep.aida.IAnalysisFactory;
 import hep.aida.IHistogramFactory;
-import hep.aida.IPlotterFactory;
-import hep.aida.IPlotter;
 import hep.aida.IHistogram1D;
+import hep.aida.IHistogram2D;
 import hep.aida.ITree;
 import hep.aida.ref.rootwriter.RootFileStore;
 import hep.physics.vec.BasicHep3Vector;
@@ -34,6 +33,7 @@
 import org.lcsim.event.TrackerHit;
 import org.lcsim.geometry.Detector;
 import org.lcsim.util.Driver;
+
 import org.hps.recon.tracking.TrackUtils;
 import org.hps.recon.tracking.TrackerHitUtils;
 
@@ -41,42 +41,71 @@
 /**
  * Analysis driver used to calculate the hit efficiency of the SVT.
  * 
- * @author Omar Moreno <[log in to unmask]>
- *
+ * @author <a href="mailto:[log in to unmask]">Omar Moreno</a> 
  */
 public class SvtHitEfficiency extends Driver {
 
-
-    // Use JFreeChart as the default plotting backend
-    static { 
-        hep.aida.jfree.AnalysisFactory.register();
-    }
-
-    // Plotting
-    ITree tree; 
-    IHistogramFactory histogramFactory; 
-    IPlotterFactory plotterFactory = IAnalysisFactory.create().createPlotterFactory();
-    protected Map<String, IPlotter> plotters = new HashMap<String, IPlotter>(); 
-    private Map<String, IHistogram1D> trackMomentumPlots = new HashMap<String, IHistogram1D>(); 
-    private Map<String, IHistogram1D> trackPlots = new HashMap<String, IHistogram1D>();
-
+    //--------------//
+    //   Plotting   //
+    //--------------//
+    private ITree tree = null; 
+    private IHistogramFactory histogramFactory = null; 
+    
+    //--------------------//
+    //   Histogram maps   //
+    //--------------------//
+    
+    private Map<Integer, IHistogram1D> trackMomentumAllTopPlots = new HashMap<Integer, IHistogram1D>();
+    private Map<Integer, IHistogram1D> trackMomentumWithinAcceptanceTopPlots = new HashMap<Integer, IHistogram1D>();
+    private Map<Integer, IHistogram1D> trackMomentumAllLayersHitTopPlots = new HashMap<Integer, IHistogram1D>(); 
+    private Map<Integer, IHistogram1D> trackMomentumAllBotPlots = new HashMap<Integer, IHistogram1D>();
+    private Map<Integer, IHistogram1D> trackMomentumWithinAcceptanceBotPlots = new HashMap<Integer, IHistogram1D>();
+    private Map<Integer, IHistogram1D> trackMomentumAllLayersHitBotPlots = new HashMap<Integer, IHistogram1D>();
+    
+    private Map<Integer, IHistogram2D> trackPositionWithinAcceptanceTopPlots = new HashMap<Integer, IHistogram2D>();
+    private Map<Integer, IHistogram2D> trackPositionAllLayersHitTopPlots = new HashMap<Integer, IHistogram2D>(); 
+    private Map<Integer, IHistogram2D> trackPositionWithinAcceptanceBotPlots = new HashMap<Integer, IHistogram2D>();
+    private Map<Integer, IHistogram2D> trackPositionAllLayersHitBotPlots = new HashMap<Integer, IHistogram2D>(); 
+    
+    private Map<Integer, IHistogram1D> electronMomentumAllTopPlots = new HashMap<Integer, IHistogram1D>();
+    private Map<Integer, IHistogram1D> electronMomentumWithinAcceptanceTopPlots = new HashMap<Integer, IHistogram1D>();
+    private Map<Integer, IHistogram1D> electronMomentumAllLayersHitTopPlots = new HashMap<Integer, IHistogram1D>(); 
+    private Map<Integer, IHistogram1D> electronMomentumAllBotPlots = new HashMap<Integer, IHistogram1D>();
+    private Map<Integer, IHistogram1D> electronMomentumWithinAcceptanceBotPlots = new HashMap<Integer, IHistogram1D>();
+    private Map<Integer, IHistogram1D> electronMomentumAllLayersHitBotPlots = new HashMap<Integer, IHistogram1D>();
+    
+    private Map<Integer, IHistogram1D> positronMomentumAllTopPlots = new HashMap<Integer, IHistogram1D>();
+    private Map<Integer, IHistogram1D> positronMomentumWithinAcceptanceTopPlots = new HashMap<Integer, IHistogram1D>();
+    private Map<Integer, IHistogram1D> positronMomentumAllLayersHitTopPlots = new HashMap<Integer, IHistogram1D>(); 
+    private Map<Integer, IHistogram1D> positronMomentumAllBotPlots = new HashMap<Integer, IHistogram1D>();
+    private Map<Integer, IHistogram1D> positronMomentumWithinAcceptanceBotPlots = new HashMap<Integer, IHistogram1D>();
+    private Map<Integer, IHistogram1D> positronMomentumAllLayersHitBotPlots = new HashMap<Integer, IHistogram1D>(); 
+
+    private Map<Integer, IHistogram1D> unbiasedXResTopPlots = new HashMap<Integer, IHistogram1D>();
+    private Map<Integer, IHistogram1D> unbiasedXResBotPlots = new HashMap<Integer, IHistogram1D>();
+    private Map<Integer, IHistogram1D> unbiasedYResTopPlots = new HashMap<Integer, IHistogram1D>();
+    private Map<Integer, IHistogram1D> unbiasedYResBotPlots = new HashMap<Integer, IHistogram1D>();
+    
     //private Map<SiSensor, Map<Integer, Hep3Vector>> stripPositions = new HashMap<SiSensor, Map<Integer, Hep3Vector>>(); 
     private List<HpsSiSensor> sensors = null;
-    private Map<Track, ReconstructedParticle> reconParticleMap = new HashMap<Track, ReconstructedParticle>();
     private Map<Integer, List<SvtStereoLayer>> topStereoLayers = new HashMap<Integer, List<SvtStereoLayer>>();
     private Map<Integer, List<SvtStereoLayer>> bottomStereoLayers = new HashMap<Integer, List<SvtStereoLayer>>();
+    
+    // Mappings between a collection of hits and the associated layer.
+    private Map<Integer, List<TrackerHit>> topHitMap = new HashMap<Integer, List<TrackerHit>>();
+    private Map<Integer, List<TrackerHit>> botHitMap = new HashMap<Integer, List<TrackerHit>>();
 
     TrackerHitUtils trackerHitUtils = new TrackerHitUtils();
-    
+
     boolean debug = false;
     boolean ecalClusterTrackMatch = false;
-    
+
     // Plot flags
     boolean enableMomentumPlots = true;
     boolean enableChiSquaredPlots = true;
     boolean enableTrackPositionPlots = true;
     boolean maskBadChannels = false;
-    
+
     double numberOfTopTracks = 0;
     double numberOfBottomTracks = 0;
     double numberOfTopTracksWithHitOnMissingLayer = 0; 
@@ -85,58 +114,86 @@
     double[] topTracksWithHitOnMissingLayer = new double[5];
     double[] bottomTracksPerMissingLayer = new double[5];
     double[] bottomTracksWithHitOnMissingLayer = new double[5];
-    
-    Hep3Vector trackPos = null;
-    Hep3Vector frontTrackPos = null;
-    Hep3Vector rearTrackPos = null;
-    
+
     // Collections
-    private String trackCollectionName = "MatchedTracks";
-    private String fsParticlesCollectionName = "FinalStateParticles";
     private String stereoHitCollectionName = "HelicalTrackHits";
     private String ecalClustersCollectionName = "EcalClusters";
-   
+
     // Constants
     public static final double SENSOR_LENGTH = 98.33; // mm
     public static final double SENSOR_WIDTH = 38.3399; // mm
     private static final String SUBDETECTOR_NAME = "Tracker";
 
-    // By default, require that all tracks have 5 hits
-    int hitsOnTrack = 5;
-
-    
-    // Layer 1
-    /*double topXResidualOffset = .153060; 
-    double topYResidualOffset = -.0153772; 
-    double botXResidualOffset = -.42722;; 
-    double botYResidualOffset = -.042571; 
-    
-    double topXResidualCut = .60168;
-    double topYResidualCut = .222750;
-    double botXResidualCut = .57399;
-    double botYResidualCut = .20142;*/
-
-    
-    // Layer 2
-    /*double topXResidualOffset = .110117; 
-    double topYResidualOffset = .004153; 
-    double botXResidualOffset = .141392;; 
-    double botYResidualOffset = .0016898; 
-    
-    double topXResidualCut = .30105;
-    double topYResidualCut = .14859;
-    double botXResidualCut = .30523;
-    double botYResidualCut = .142789;*/
-    
-    double topXResidualOffset = .151985; 
-    double topYResidualOffset = .02071; 
-    double botXResidualOffset = -.260434; 
-    double botYResidualOffset = -.000359426; 
-    
-    double topXResidualCut = .349872;
-    double topYResidualCut = .143411;
-    double botXResidualCut = .343664;
-    double botYResidualCut = .143596;
+
+    private double[] topXUnbiasedResidualMean = {
+            0.136630076605, 
+            -0.0372865518579, 
+            0.0721381727508, 
+            0.0509403980777, 
+            0.0686801299522, 
+            -0.252740627354
+    };
+    private double[] topXUnbiasedResidualSigma = {
+            0.757111057485,
+            0.445695560721,
+            0.471524764148,
+            0.691259310815,
+            0.653186050157,
+            1.67592292474
+    };
+    
+    private double[] botXUnbiasedResidualMean = {
+            -0.050062437621, 
+            -0.0284269138592,
+            -0.0185082041728,
+            0.0187179831998,
+            0.0718635793646,
+            0.0785929625563
+    };
+    
+    private double[] botXUnbiasedResidualSigma = {
+            0.721833719938,
+            0.459258383079,
+            0.461651708305,
+            0.669558021294,
+            0.646307506985,
+            1.70833919409
+    };
+    
+    private double[] topYUnbiasedResidualMean = {
+            0.0154282282709,
+            0.0186347388904,
+            0.0156961379185,
+            -0.00238475652854,
+            -0.0174100106177,
+            -0.0440662300552
+    };
+    private double[] topYUnbiasedResidualSigma = {
+            0.325752777676,
+            0.24950521257,
+            0.242532547574,
+            0.420941281086,
+            0.781453174046,
+            1.16834668832
+    };
+    
+    private double[] botYUnbiasedResidualMean = {
+            -0.0277169063966,
+            -0.0108234881129,
+            -0.00852130805205,
+            -0.0104129564111,
+            0.00547904118153,
+            0.00547904118153
+    };
+    
+    private double[] botYUnbiasedResidualSigma = {
+            0.389851962915,
+            0.275056692408,
+            0.24870417303,
+            0.402831487607,
+            0.694039536013,
+            0.995938084198
+    };
     
     /**
      * Default Constructor
@@ -144,38 +201,30 @@
     public SvtHitEfficiency(){
     }
 
-    /**
-     *  Set the number of stereo hits associated with a track fit.
-     *
-     *  @param hitsOnTrack : Number of stereo hits associated with a track fit.
-     */
-    public void setHitsOnTrack(int hitsOnTrack) { 
-        this.hitsOnTrack = hitsOnTrack;
-    }
-    
     /**
      *  Enable/Disable debug 
      */
     public void  setDebug(boolean debug){
         this.debug = debug;
     }
-    
+
     /**
      * Enable/Disable masking of bad channels
      */
     public void setMaskBadChannels(boolean maskBadChannels){
         this.maskBadChannels = maskBadChannels; 
     }
-    
-    public void detectorChanged(Detector detector){
-    
+
+    protected void detectorChanged(Detector detector){
+
+        // Instantiate the tree and histogram factory
         tree = IAnalysisFactory.create().createTreeFactory().create();
         histogramFactory = IAnalysisFactory.create().createHistogramFactory(tree);
-        
+
         // Get the HpsSiSensor objects from the tracker detector element
         sensors = detector.getSubdetector(SUBDETECTOR_NAME)
                           .getDetectorElement().findDescendants(HpsSiSensor.class);
-   
+
         // If the detector element had no sensors associated with it, throw
         // an exception
         if (sensors.size() == 0) {
@@ -187,327 +236,398 @@
         List<SvtStereoLayer> stereoLayers 
             = ((HpsTracker2) detector.getSubdetector(SUBDETECTOR_NAME).getDetectorElement()).getStereoPairs();
         for (SvtStereoLayer stereoLayer : stereoLayers) { 
+            
+            HpsSiSensor axialSensor = stereoLayer.getAxialSensor();
+            HpsSiSensor stereoSensor = stereoLayer.getStereoSensor();
+            double axialZ = axialSensor.getGeometry().getPosition().z();
+            double stereoZ = stereoSensor.getGeometry().getPosition().z(); 
+            
             if (stereoLayer.getAxialSensor().isTopLayer()) {
-                //System.out.println("Adding stereo layer " + stereoLayer.getLayerNumber());
+            
+                System.out.println("Top Z Midpoint: " + (stereoZ + axialZ)/2);
+                
                 if (!topStereoLayers.containsKey(stereoLayer.getLayerNumber())) { 
                     topStereoLayers.put(stereoLayer.getLayerNumber(), new ArrayList<SvtStereoLayer>());
-                } 
+                }
+                
                 topStereoLayers.get(stereoLayer.getLayerNumber()).add(stereoLayer);
+                
             } else { 
+
+                System.out.println("Bot Z Midpoint: " + (axialZ + stereoZ)/2);
+                
                 if (!bottomStereoLayers.containsKey(stereoLayer.getLayerNumber())) { 
                     bottomStereoLayers.put(stereoLayer.getLayerNumber(), new ArrayList<SvtStereoLayer>());
-                } 
+                }
+                
                 bottomStereoLayers.get(stereoLayer.getLayerNumber()).add(stereoLayer);
             }
         }
-    
-        plotters.put("Event Information", plotterFactory.create("Event information"));
-        plotters.get("Event Information").createRegions(3, 3);
-
-        trackPlots.put("Number of tracks", histogramFactory.createHistogram1D("Number of tracks", 10, 0, 10));
-        plotters.get("Event Information").region(0).plot(trackPlots.get("Number of tracks"));
-
-        trackPlots.put("Unused Layer", histogramFactory.createHistogram1D("Unused Layer", 6, 1, 7));
-        plotters.get("Event Information").region(1).plot(trackPlots.get("Unused Layer"));
+
+        for (int layer = 1; layer < 7; layer++) { 
+            
+            this.trackMomentumAllTopPlots.put(layer, histogramFactory.createHistogram1D("Layer " + layer + " - Top Track Momentum - All Tracks", 50, 0, 1.5));
+            this.trackMomentumWithinAcceptanceTopPlots.put(layer, histogramFactory.createHistogram1D("Layer " + layer + " - Top Track Momentum - Within Acceptance", 50, 0, 1.5));
+            this.trackMomentumAllLayersHitTopPlots.put(layer, histogramFactory.createHistogram1D("Layer " + layer + " - Top Track Momentum - All Layers Hit", 50, 0, 1.5));
+            
+            this.trackMomentumAllBotPlots.put(layer, histogramFactory.createHistogram1D("Layer " + layer + " - Bot Track Momentum - All Tracks", 50, 0, 1.5));
+            this.trackMomentumWithinAcceptanceBotPlots.put(layer, histogramFactory.createHistogram1D("Layer " + layer + " - Bot Track Momentum - Within Acceptance", 50, 0, 1.5));
+            this.trackMomentumAllLayersHitBotPlots.put(layer, histogramFactory.createHistogram1D("Layer " + layer + " - Bot Track Momentum - All Layers Hit", 50, 0, 1.5));
+            
+            this.trackPositionWithinAcceptanceTopPlots.put(layer, histogramFactory.createHistogram2D("Layer " + layer + " - Top Track Position - Within Acceptance", 260, -100, 160, 80, -5, 70));
+            this.trackPositionAllLayersHitTopPlots.put(layer, histogramFactory.createHistogram2D("Layer " + layer + " - Top Track Position - All Layers Hit", 260, -100, 160, 80, -5, 70));
+            
+            this.trackPositionWithinAcceptanceBotPlots.put(layer, histogramFactory.createHistogram2D("Layer " + layer + " - Bot Track Position - Within Acceptance", 260, -100, 160, 80, -70, 5));
+            this.trackPositionAllLayersHitBotPlots.put(layer, histogramFactory.createHistogram2D("Layer " + layer + " - Bot Track Position - All Layers Hit", 260, -100, 160, 80, -70, 5));
+            
+            this.electronMomentumAllTopPlots.put(layer, histogramFactory.createHistogram1D("Layer " + layer + " - Top Electron Momentum - All Tracks", 50, 0, 1.5));
+            this.electronMomentumWithinAcceptanceTopPlots.put(layer, histogramFactory.createHistogram1D("Layer " + layer + " - Top Electron Momentum - Within Acceptance", 50, 0, 1.5));
+            this.electronMomentumAllLayersHitTopPlots.put(layer, histogramFactory.createHistogram1D("Layer " + layer + " - Top Electron Momentum - All Layers Hit", 50, 0, 1.5));
+            
+            this.electronMomentumAllBotPlots.put(layer, histogramFactory.createHistogram1D("Layer " + layer + " - Bot Electron Momentum - All Tracks", 50, 0, 1.5));
+            this.electronMomentumWithinAcceptanceBotPlots.put(layer, histogramFactory.createHistogram1D("Layer " + layer + " - Bot Electron Momentum - Within Acceptance", 50, 0, 1.5));
+            this.electronMomentumAllLayersHitBotPlots.put(layer, histogramFactory.createHistogram1D("Layer " + layer + " - Bot Electron Momentum - All Layers Hit", 50, 0, 1.5));
+            
+            this.positronMomentumAllTopPlots.put(layer, histogramFactory.createHistogram1D("Layer " + layer + " - Top Positron Momentum - All Tracks", 50, 0, 1.5));
+            this.positronMomentumWithinAcceptanceTopPlots.put(layer, histogramFactory.createHistogram1D("Layer " + layer + " - Top Positron Momentum - Within Acceptance", 50, 0, 1.5));
+            this.positronMomentumAllLayersHitTopPlots.put(layer, histogramFactory.createHistogram1D("Layer " + layer + " - Top Positron Momentum - All Layers Hit", 50, 0, 1.5));
+            
+            this.positronMomentumAllBotPlots.put(layer, histogramFactory.createHistogram1D("Layer " + layer + " - Bot Positron Momentum - All Tracks", 50, 0, 1.5));
+            this.positronMomentumWithinAcceptanceBotPlots.put(layer, histogramFactory.createHistogram1D("Layer " + layer + " - Bot Positron Momentum - Within Acceptance", 50, 0, 1.5));
+            this.positronMomentumAllLayersHitBotPlots.put(layer, histogramFactory.createHistogram1D("Layer " + layer + " - Bot Positron Momentum - All Layers Hit", 50, 0, 1.5)); 
         
-        trackPlots.put("Unbiased Residual x - Top", histogramFactory.createHistogram1D("Unbiased Residual x - Top", 100, -10, 10));
-        plotters.get("Event Information").region(2).plot(trackPlots.get("Unbiased Residual x - Top"));
-
-        trackPlots.put("Unbiased Residual x - Bottom", histogramFactory.createHistogram1D("Unbiased Residual x - Bottom", 100, -10, 10));
-        plotters.get("Event Information").region(3).plot(trackPlots.get("Unbiased Residual x - Bottom"));
-
-        trackPlots.put("Unbiased Residual y - Top", histogramFactory.createHistogram1D("Unbiased Residual y - Top", 100, -10, 10));
-        plotters.get("Event Information").region(4).plot(trackPlots.get("Unbiased Residual y - Top"));
-
-        trackPlots.put("Unbiased Residual y - Bottom", histogramFactory.createHistogram1D("Unbiased Residual y - Bottom", 100, -10, 10));
-        plotters.get("Event Information").region(5).plot(trackPlots.get("Unbiased Residual y - Bottom"));
-        
-        plotters.put("Track Momentum", plotterFactory.create("Track Momentum"));
-        plotters.get("Track Momentum").createRegions(2, 2);
-
-        trackMomentumPlots.put("Track Momentum", histogramFactory.createHistogram1D("Track Momentum", 50, 0, 1.5));
-        plotters.get("Track Momentum").region(0).plot(trackMomentumPlots.get("Track Momentum"));
-           
-        trackMomentumPlots.put("Track Momentum - Tracks Within Acceptance",
-                histogramFactory.createHistogram1D("Track Momentum - Tracks Within Acceptance", 50, 0, 1.5));
-        plotters.get("Track Momentum").region(1)
-                                      .plot(trackMomentumPlots.get("Track Momentum - Tracks Within Acceptance"));
-
-        trackMomentumPlots.put("Track Momentum - All Layers Hit", 
-                histogramFactory.createHistogram1D("Track Momentum - All Layers Hit", 50, 0, 1.5));
-        plotters.get("Track Momentum").region(2)
-                                      .plot(trackMomentumPlots.get("Track Momentum - All Layers Hit"));
-        
+            this.unbiasedXResTopPlots.put(layer, histogramFactory.createHistogram1D("Layer " + layer + " - Top - Unbiased Residual x", 200, -10, 10));
+            this.unbiasedYResTopPlots.put(layer, histogramFactory.createHistogram1D("Layer " + layer + " - Top - Unbiased Residual y", 200, -10, 10));
+
+            this.unbiasedXResBotPlots.put(layer, histogramFactory.createHistogram1D("Layer " + layer + " - Bot - Unbiased Residual x", 200, -10, 10));
+            this.unbiasedYResBotPlots.put(layer, histogramFactory.createHistogram1D("Layer " + layer + " - Bot - Unbiased Residual y", 200, -10, 10));
+        }
+
         // Create a Map from sensor to bad channels and from bad channels to
         // strip position
         /*
-        for(ChargeCarrier carrier : ChargeCarrier.values()){
-            for(SiSensor sensor : sensors){ 
-                if(sensor.hasElectrodesOnSide(carrier)){ 
-                    stripPositions.put(sensor, new HashMap<Integer, Hep3Vector>());
-                    SiStrips strips = (SiStrips) sensor.getReadoutElectrodes(carrier);     
-                    ITransform3D parentToLocal = sensor.getReadoutElectrodes(carrier).getParentToLocal();
-                    ITransform3D localToGlobal = sensor.getReadoutElectrodes(carrier).getLocalToGlobal();
-                    for(int physicalChannel = 0; physicalChannel < 640; physicalChannel++){
-                        Hep3Vector localStripPosition = strips.getCellPosition(physicalChannel);
-                        Hep3Vector stripPosition = parentToLocal.transformed(localStripPosition);
-                        Hep3Vector globalStripPosition = localToGlobal.transformed(stripPosition);
-                        //this.printDebug(SvtUtils.getInstance().getDescription(sensor) + " : Channel " + physicalChannel + " : Local Strip Position " + localStripPosition.toString());
-                        //this.printDebug(SvtUtils.getInstance().getDescription(sensor) + " : Channel " + physicalChannel + " : Strip Position " + stripPosition.toString());
-                        //this.printDebug(SvtUtils.getInstance().getDescription(sensor) + " : Channel " + physicalChannel + " : Strip Position " + globalStripPosition.toString());
-                        stripPositions.get(sensor).put(physicalChannel, stripPosition);
+           for(ChargeCarrier carrier : ChargeCarrier.values()){
+           for(SiSensor sensor : sensors){ 
+           if(sensor.hasElectrodesOnSide(carrier)){ 
+           stripPositions.put(sensor, new HashMap<Integer, Hep3Vector>());
+           SiStrips strips = (SiStrips) sensor.getReadoutElectrodes(carrier);     
+           ITransform3D parentToLocal = sensor.getReadoutElectrodes(carrier).getParentToLocal();
+           ITransform3D localToGlobal = sensor.getReadoutElectrodes(carrier).getLocalToGlobal();
+           for(int physicalChannel = 0; physicalChannel < 640; physicalChannel++){
+           Hep3Vector localStripPosition = strips.getCellPosition(physicalChannel);
+           Hep3Vector stripPosition = parentToLocal.transformed(localStripPosition);
+           Hep3Vector globalStripPosition = localToGlobal.transformed(stripPosition);
+        //this.printDebug(SvtUtils.getInstance().getDescription(sensor) + " : Channel " + physicalChannel + " : Local Strip Position " + localStripPosition.toString());
+        //this.printDebug(SvtUtils.getInstance().getDescription(sensor) + " : Channel " + physicalChannel + " : Strip Position " + stripPosition.toString());
+        //this.printDebug(SvtUtils.getInstance().getDescription(sensor) + " : Channel " + physicalChannel + " : Strip Position " + globalStripPosition.toString());
+        stripPositions.get(sensor).put(physicalChannel, stripPosition);
+           }
+           }
+           }
+           }*/
+
+
+        //--- Track Fit Chi Squared ---//
+        //-----------------------------//
+        /*if(enableChiSquaredPlots){
+          plotters.add(PlotUtils.setupPlotter("Track Chi Squared", 0, 0));
+          title = "Chi Squared - All Tracks";
+          histo1D = aida.histogram1D(title, 50, 0, 50);
+          PlotUtils.setup1DRegion(plotters.get(plotterIndex), title, 0, "Chi Squared", histo1D);
+          title = "Chi Squared - Tracks Within Acceptance";
+          histo1D = aida.histogram1D(title, 50, 0, 50);
+          plotters.get(plotterIndex).region(0).plot(histo1D);
+          title = "Chi Squared - Tracks With All Layers Hit";
+          histo1D = aida.histogram1D(title, 50, 0, 50);
+          plotters.get(plotterIndex).region(0).plot(histo1D);
+          plotterIndex++;
+          }*/
+
+        //--- Track Position Plots ---//
+        //----------------------------//
+        /*if(enableTrackPositionPlots){
+          int layerNumber = 1; 
+          SiSensor sensor = null;
+          IPlotterStyle style = aida.analysisFactory().createPlotterFactory().createPlotterStyle();
+          for(int index = 1; index < 6; index++){
+          plotters.add(PlotUtils.setupPlotter("Track Position - Layer " + index, 2, 3));
+          title = "Track Position - Layer " + index + " - Tracks Within Acceptance";
+          cloud2D = aida.cloud2D(title);
+          PlotUtils.setup2DRegion(plotters.get(plotterIndex), title, 0, "x [mm]", "y [mm]", cloud2D, style);
+          title = "Track Position - Layer " + index + " - Tracks With All Layers Hit";
+          cloud2D = aida.cloud2D(title);
+          plotters.get(plotterIndex).region(0).plot(cloud2D, style);
+          title = "Track Position - Layer " + index + " - Difference";
+          cloud2D = aida.cloud2D(title);
+          PlotUtils.setup2DRegion(plotters.get(plotterIndex), title, 1, "x [mm]", "y [mm]", cloud2D, style);
+        //sensor = SvtUtils.getInstance().getBottomSensor(layerNumber, 0);
+        //title = SvtUtils.getInstance().getDescription(sensor) + " - Occupancy";
+        histo1D = aida.histogram1D(title, 640, 0, 639);
+
+        histos1D.add(histo1D);
+        PlotUtils.setup1DRegion(plotters.get(plotterIndex), title, 2, "Channel #", histo1D);
+        //sensor = SvtUtils.getInstance().getTopSensor(layerNumber, 0);
+        //title = SvtUtils.getInstance().getDescription(sensor) + " - Occupancy";
+        histo1D = aida.histogram1D(title, 640, 0, 639);
+        histos1D.add(histo1D);
+        PlotUtils.setup1DRegion(plotters.get(plotterIndex), title, 4, "Channel #", histo1D);
+        layerNumber++;
+        //sensor = SvtUtils.getInstance().getBottomSensor(layerNumber, 0);
+        //title = SvtUtils.getInstance().getDescription(sensor) + " - Occupancy";
+        histo1D = aida.histogram1D(title, 640, 0, 639);
+        histos1D.add(histo1D);
+        PlotUtils.setup1DRegion(plotters.get(plotterIndex), title, 3, "Channel #", histo1D);
+        //sensor = SvtUtils.getInstance().getTopSensor(layerNumber, 0);
+        //title = SvtUtils.getInstance().getDescription(sensor) + " - Occupancy";
+        histo1D = aida.histogram1D(title, 640, 0, 639);
+        histos1D.add(histo1D);
+        PlotUtils.setup1DRegion(plotters.get(plotterIndex), title, 5, "Channel #", histo1D);
+        layerNumber++;
+        plotterIndex++;
+          }
+          }*/
+
+    }
+
+    /**
+     * .
+     */
+    /* private Hep3Vector getStripPosition(SiSensor sensor, int physicalChannel){ 
+       return stripPositions.get(sensor).get(physicalChannel);
+       }*/
+
+    public void process(EventHeader event) {
+
+        // If the event does not contain a collection of tracks, skip it.
+        if(!event.hasCollection(Track.class)) return;
+
+        // Get all collections of tracks from the event.
+        List<List<Track>> track_collections = event.get(Track.class);
+
+        // Get the collection of 3D hits from the event. This collection
+        // contains all 3D hits in the event and not just those associated
+        // with a track.
+        List<TrackerHit> hits = event.get(TrackerHit.class, stereoHitCollectionName);
+       
+        // Map all 3D hits in the event to their corresponding layer.
+        this.mapHitsToLayers(hits);
+
+        // Loop over all available track collections.  Each track collection 
+        // should have tracks where one of the layers is missing.
+        for (List<Track> tracks : track_collections) { 
+
+            // Check that the event has a good pair of tracks
+            if (!this.hasGoodTrackPair(tracks)) continue; 
+
+            // Loop over all tracks in the event
+            for (Track track : tracks) {
+
+                // Get one of the sensors associated with the track.  This will be used
+                // to determine which hit map to use.
+                HpsSiSensor sensor = (HpsSiSensor) ( (RawTrackerHit) track.getTrackerHits().get(0).getRawHits().get(0)).getDetectorElement();
+                
+                // Calculate the track momentum
+                double p = this.getTrackMomentum(track, -.24);
+                 
+                // Find which of the layers isn't being used in the track fit.  
+                int unusedLayer = this.getUnusedSvtLayer(track.getTrackerHits());
+
+                if (sensor.isTopLayer()) {
+                    this.trackMomentumAllTopPlots.get(unusedLayer).fill(p);
+                    if (track.getTrackStates().get(0).getOmega() > 0) { 
+                        this.electronMomentumAllTopPlots.get(unusedLayer).fill(p);
+                    } else { 
+                        this.positronMomentumAllTopPlots.get(unusedLayer).fill(p);
+                    }
+                } else { 
+                    this.trackMomentumAllBotPlots.get(unusedLayer).fill(p);
+                    if (track.getTrackStates().get(0).getOmega() > 0) { 
+                        this.electronMomentumAllBotPlots.get(unusedLayer).fill(p);
+                    } else { 
+                        this.positronMomentumAllBotPlots.get(unusedLayer).fill(p);
+                    }
+                }
+                
+                // Extrapolate the track to the unused layer and check that it lies
+                // within the acceptance of that layer.  If it doesn't, move on
+                // to the next track.
+                double z = this.isWithinAcceptance(track, unusedLayer);
+                if (z <= 0) continue;
+                
+                Hep3Vector trackPos = TrackUtils.extrapolateTrack(track, z);
+           
+                if (sensor.isTopLayer()) {
+                    this.trackMomentumWithinAcceptanceTopPlots.get(unusedLayer).fill(p);
+                    this.trackPositionWithinAcceptanceTopPlots.get(unusedLayer).fill(trackPos.x(), trackPos.y());
+                    if (track.getTrackStates().get(0).getOmega() > 0) { 
+                        this.electronMomentumWithinAcceptanceTopPlots.get(unusedLayer).fill(p);
+                    } else { 
+                        this.positronMomentumWithinAcceptanceTopPlots.get(unusedLayer).fill(p);
+                    }
+                } else { 
+                    this.trackMomentumWithinAcceptanceBotPlots.get(unusedLayer).fill(p);
+                    this.trackPositionWithinAcceptanceBotPlots.get(unusedLayer).fill(trackPos.x(), trackPos.y());
+                    if (track.getTrackStates().get(0).getOmega() > 0) { 
+                        this.electronMomentumWithinAcceptanceBotPlots.get(unusedLayer).fill(p);
+                    } else { 
+                        this.positronMomentumWithinAcceptanceBotPlots.get(unusedLayer).fill(p);
+                    }
+                }
+
+                // Check if the unused layer has a 3D hit associated with a 
+                // track
+                if (!this.hasGood3DHit(track, unusedLayer)) continue;
+
+                if (sensor.isTopLayer()) {
+                    this.trackMomentumAllLayersHitTopPlots.get(unusedLayer).fill(p);
+                    this.trackPositionAllLayersHitTopPlots.get(unusedLayer).fill(trackPos.x(), trackPos.y());
+                    if (track.getTrackStates().get(0).getOmega() > 0) { 
+                        this.electronMomentumAllLayersHitTopPlots.get(unusedLayer).fill(p);
+                    } else { 
+                        this.positronMomentumAllLayersHitTopPlots.get(unusedLayer).fill(p);
+                    }
+                } else { 
+                    this.trackMomentumAllLayersHitBotPlots.get(unusedLayer).fill(p);
+                    this.trackPositionAllLayersHitBotPlots.get(unusedLayer).fill(trackPos.x(), trackPos.y());
+                    if (track.getTrackStates().get(0).getOmega() > 0) { 
+                        this.electronMomentumAllLayersHitBotPlots.get(unusedLayer).fill(p);
+                    } else { 
+                        this.positronMomentumAllLayersHitBotPlots.get(unusedLayer).fill(p);
                     }
                 }
             }
-        }*/
+        }        
+    }
+
+    /**
+     *
+     *
+     */
+    private boolean hasGood3DHit(Track track, int unusedLayer) {
+    
+        // Get one of the sensors associated with the track.  This will be used
+        // to determine which hit map to use.
+        HpsSiSensor sensor = (HpsSiSensor) ( (RawTrackerHit) track.getTrackerHits().get(0).getRawHits().get(0)).getDetectorElement();
         
+        // Get the hit map that will be used to search for hits in the
+        // unused layer.
+        Map<Integer, List<TrackerHit>> hitMap = null;
+        hitMap = (sensor.isTopLayer()) ? this.topHitMap : this.botHitMap;
         
-        //--- Track Fit Chi Squared ---//
-        //-----------------------------//
-        /*if(enableChiSquaredPlots){
-            plotters.add(PlotUtils.setupPlotter("Track Chi Squared", 0, 0));
-            title = "Chi Squared - All Tracks";
-            histo1D = aida.histogram1D(title, 50, 0, 50);
-            PlotUtils.setup1DRegion(plotters.get(plotterIndex), title, 0, "Chi Squared", histo1D);
-            title = "Chi Squared - Tracks Within Acceptance";
-            histo1D = aida.histogram1D(title, 50, 0, 50);
-            plotters.get(plotterIndex).region(0).plot(histo1D);
-            title = "Chi Squared - Tracks With All Layers Hit";
-            histo1D = aida.histogram1D(title, 50, 0, 50);
-            plotters.get(plotterIndex).region(0).plot(histo1D);
-            plotterIndex++;
-        }*/
-                
-        //--- Track Position Plots ---//
-        //----------------------------//
-        /*if(enableTrackPositionPlots){
-            int layerNumber = 1; 
-            SiSensor sensor = null;
-            IPlotterStyle style = aida.analysisFactory().createPlotterFactory().createPlotterStyle();
-            for(int index = 1; index < 6; index++){
-                plotters.add(PlotUtils.setupPlotter("Track Position - Layer " + index, 2, 3));
-                title = "Track Position - Layer " + index + " - Tracks Within Acceptance";
-                cloud2D = aida.cloud2D(title);
-                PlotUtils.setup2DRegion(plotters.get(plotterIndex), title, 0, "x [mm]", "y [mm]", cloud2D, style);
-                title = "Track Position - Layer " + index + " - Tracks With All Layers Hit";
-                cloud2D = aida.cloud2D(title);
-                plotters.get(plotterIndex).region(0).plot(cloud2D, style);
-                title = "Track Position - Layer " + index + " - Difference";
-                cloud2D = aida.cloud2D(title);
-                PlotUtils.setup2DRegion(plotters.get(plotterIndex), title, 1, "x [mm]", "y [mm]", cloud2D, style);
-                //sensor = SvtUtils.getInstance().getBottomSensor(layerNumber, 0);
-                //title = SvtUtils.getInstance().getDescription(sensor) + " - Occupancy";
-                histo1D = aida.histogram1D(title, 640, 0, 639);
-    
-                histos1D.add(histo1D);
-                PlotUtils.setup1DRegion(plotters.get(plotterIndex), title, 2, "Channel #", histo1D);
-                //sensor = SvtUtils.getInstance().getTopSensor(layerNumber, 0);
-                //title = SvtUtils.getInstance().getDescription(sensor) + " - Occupancy";
-                histo1D = aida.histogram1D(title, 640, 0, 639);
-                histos1D.add(histo1D);
-                PlotUtils.setup1DRegion(plotters.get(plotterIndex), title, 4, "Channel #", histo1D);
-                layerNumber++;
-                //sensor = SvtUtils.getInstance().getBottomSensor(layerNumber, 0);
-                //title = SvtUtils.getInstance().getDescription(sensor) + " - Occupancy";
-                histo1D = aida.histogram1D(title, 640, 0, 639);
-                histos1D.add(histo1D);
-                PlotUtils.setup1DRegion(plotters.get(plotterIndex), title, 3, "Channel #", histo1D);
-                //sensor = SvtUtils.getInstance().getTopSensor(layerNumber, 0);
-                //title = SvtUtils.getInstance().getDescription(sensor) + " - Occupancy";
-                histo1D = aida.histogram1D(title, 640, 0, 639);
-                histos1D.add(histo1D);
-                PlotUtils.setup1DRegion(plotters.get(plotterIndex), title, 5, "Channel #", histo1D);
-                layerNumber++;
-                plotterIndex++;
-            }
-        }*/
-       
-        for (IPlotter plotter : plotters.values()) { 
-            plotter.show();
-        }
-    }
-
-    /**
-     * .
-     */
-   /* private Hep3Vector getStripPosition(SiSensor sensor, int physicalChannel){ 
-        return stripPositions.get(sensor).get(physicalChannel);
-    }*/
-
-    public void process(EventHeader event){
+        // Get the hits associated with the layer not used to fit the track
+        List<TrackerHit> hits = hitMap.get(unusedLayer);
         
-        // If the event does not have tracks, skip it
-        if(!event.hasCollection(Track.class, trackCollectionName)) return;
-    
-        // Get the list of tracks from the event
-        List<Track> tracks = event.get(Track.class, trackCollectionName);
+        // Check if there are any 3D hits in the unused layer
+        if ((hits == null) || (hits.size() == 0)) return false;
         
-        // For now, only look at events with a single track
-        if(tracks.size() != 1 ) return;
-       
-        // Get the list of final state particles from the event.  These will
-        // be used to obtain the track momentum.
-        List<ReconstructedParticle> fsParticles = event.get(ReconstructedParticle.class, fsParticlesCollectionName);
-      
-        this.mapReconstructedParticlesToTracks(tracks, fsParticles);
-        
-        trackPlots.get("Number of tracks").fill(tracks.size());
-        
-        //  Get all of the stereo hits in the event
-        List<TrackerHit> stereoHits = event.get(TrackerHit.class, stereoHitCollectionName);
-        
-        // Get the list of Ecal clusters from the event
-        //List<Cluster> ecalClusters = event.get(Cluster.class, ecalClustersCollectionName);
-
-        for(Track track : tracks){
-          
-            // Check that the track has the required number of hits.  The number of hits
-            // required to make a track is set in the tracking strategy.
-            if(track.getTrackerHits().size() != this.hitsOnTrack){
-                System.out.println("This track doesn't have the required number of hits.");
-                continue;
-            }
+        for (TrackerHit hit : hits) { 
            
-            // Calculate the momentum of the track
-            double p = this.getReconstructedParticle(track).getMomentum().magnitude();
-
-            trackMomentumPlots.get("Track Momentum").fill(p); 
-            
-            // Find which of the layers isn't being used in the track fit
-            int unusedLayer = this.getUnusedSvtLayer(track.getTrackerHits());
-            
-            trackPlots.get("Unused Layer").fill(unusedLayer);
-
-            // Extrapolate the track to the unused layer and check that it lies
-            // within the acceptance of that layer.  If it doesn't, move on
-            // to the next event
-            if(!isWithinAcceptance(track, unusedLayer)) continue;
-
-            HpsSiSensor trackSensor = (HpsSiSensor) ((RawTrackerHit)track.getTrackerHits().get(0).getRawHits().get(0)).getDetectorElement();
-            
-            if (trackSensor.isTopLayer()) {
-                numberOfTopTracks++;
-            } else { 
-                numberOfBottomTracks++;
-            }
-            
-            trackMomentumPlots.get("Track Momentum - Tracks Within Acceptance").fill(p); 
-          
-            
-            // Check if there is a stereo hit within some distance of the track 
-            // in the unused layer
-            for (TrackerHit stereoHit : stereoHits) {
-                
-                // Retrieve the sensor associated with one of the hits.  This will
-                // be used to retrieve the layer number
-                HpsSiSensor hitSensor = (HpsSiSensor) ((RawTrackerHit) stereoHit.getRawHits().get(0)).getDetectorElement();
-           
-                if ((trackSensor.isTopLayer() && hitSensor.isBottomLayer()) 
-                        || (trackSensor.isBottomLayer() && hitSensor.isTopLayer())) continue;
-            
-               
-                // Retrieve the layer number by using the sensor
-                int layer = (hitSensor.getLayerNumber() + 1)/2;
-                
-                if (unusedLayer == layer) { 
-              
-                Hep3Vector stereoHitPosition = new BasicHep3Vector(stereoHit.getPosition());
-                Hep3Vector trackPosition = TrackUtils.extrapolateTrack(track, stereoHitPosition.z());
-                double xResidual = trackPosition.x() - stereoHitPosition.x();
-                double yResidual = trackPosition.y() - stereoHitPosition.y();
-                
-                
-                    if (hitSensor.isTopLayer()) { 
-                        trackPlots.get("Unbiased Residual x - Top").fill(xResidual);
-                        trackPlots.get("Unbiased Residual y - Top").fill(yResidual);
-                        if (Math.abs(xResidual+this.topXResidualOffset) > 3*this.topXResidualCut 
-                                && Math.abs(yResidual + this.topYResidualOffset) > 3*this.topYResidualCut) continue;
-                        trackMomentumPlots.get("Track Momentum - All Layers Hit").fill(p);
-                        numberOfTopTracksWithHitOnMissingLayer++;
-                    } else { 
-                        trackPlots.get("Unbiased Residual x - Bottom").fill(xResidual);
-                        trackPlots.get("Unbiased Residual y - Bottom").fill(yResidual);
-                        if (Math.abs(xResidual+this.botXResidualOffset) > 3*this.botXResidualCut 
-                                && Math.abs(yResidual + this.botYResidualOffset) > 3*this.botYResidualCut) continue;
-                        trackMomentumPlots.get("Track Momentum - All Layers Hit").fill(p);
-                        numberOfBottomTracksWithHitOnMissingLayer++;
-                    }
-                    
-                    return;
+            Hep3Vector hitPosition = new BasicHep3Vector(hit.getPosition());
+            Hep3Vector trackPosition = TrackUtils.extrapolateTrack(track, hitPosition.z());
+            double xResidual = trackPosition.x() - hitPosition.x();
+            double yResidual = trackPosition.y() - hitPosition.y();
+
+            if (sensor.isTopLayer()) { 
+                this.unbiasedXResTopPlots.get(unusedLayer).fill(xResidual);
+                this.unbiasedYResTopPlots.get(unusedLayer).fill(yResidual);
+                if ((xResidual > this.topXUnbiasedResidualMean[unusedLayer - 1] - 5*this.topXUnbiasedResidualSigma[unusedLayer - 1]) &&
+                        (xResidual < this.topXUnbiasedResidualMean[unusedLayer - 1] + 5*this.topXUnbiasedResidualSigma[unusedLayer - 1]) && 
+                        (yResidual > this.topYUnbiasedResidualMean[unusedLayer - 1] - 5*this.topYUnbiasedResidualSigma[unusedLayer - 1]) &&
+                        (yResidual < this.topYUnbiasedResidualMean[unusedLayer - 1] + 5*this.topYUnbiasedResidualSigma[unusedLayer - 1])) { 
+                    return true;
+                }
+            } else {
+                this.unbiasedXResBotPlots.get(unusedLayer).fill(xResidual);
+                this.unbiasedYResBotPlots.get(unusedLayer).fill(yResidual);
+                if ((xResidual > this.botXUnbiasedResidualMean[unusedLayer - 1] - 5*this.botXUnbiasedResidualSigma[unusedLayer - 1]) &&
+                        (xResidual < this.botXUnbiasedResidualMean[unusedLayer - 1] + 5*this.botXUnbiasedResidualSigma[unusedLayer - 1]) && 
+                        (yResidual > this.botYUnbiasedResidualMean[unusedLayer - 1] - 5*this.botYUnbiasedResidualSigma[unusedLayer - 1]) &&
+                        (yResidual < this.botYUnbiasedResidualMean[unusedLayer - 1] + 5*this.botYUnbiasedResidualSigma[unusedLayer - 1])) { 
+                    return true;
                 }
             }
-            
-            /* 
-            for(HelicalTrackHit stereoHit : stereoHits){
-                if(layer == stereoHit.Layer()){
-                    if(debug) System.out.println(this.getClass().getSimpleName() + ": Track has five layers hit");
-                    if(TrackUtils.getZ0(track) > 0){
-                        topTracksWithHitOnMissingLayer[arrayPosition]++;
-                    } else {
-                        bottomTracksWithHitOnMissingLayer[arrayPosition]++;
-                    }
-                    if(enableMomentumPlots)
-                        aida.histogram1D("Track Momentum - Tracks With All Layers Hit").fill(momentum);
-                    if(enableChiSquaredPlots)
-                        aida.histogram1D("Chi Squared - Tracks With All Layers Hit").fill(track.getChi2());
-                    
-                    return;
-                }
-            }*/
-            
-            
-            //ecalClusterTrackMatch = false;
-            
-            // Check if there is an Ecal cluster in the same detector volume as the track
-            /*for(Cluster ecalCluster : ecalClusters){
-                if(ecalCluster.getPosition()[1] > 0 && trkUtil.getZ0() > 0){
-                    ecalClusterTrackMatch = true;
-                    break;
-                }
-                else if(ecalCluster.getPosition()[1] < 0 && trkUtil.getZ0() < 0){
-                    ecalClusterTrackMatch = true;
-                    break;
-                }
-            }*/
-            
-            /*
-            if(!ecalClusterTrackMatch){
-                if(debug) System.out.println(this.getClass().getSimpleName() + ": No matching Ecal cluster found");
-                continue;
-            }*/
-            
-            
-            //if(enableChiSquaredPlots)
-            //    aida.histogram1D("Chi Squared - Tracks Within Acceptance").fill(track.getChi2());
-            
-            
-            /*int layerNumber = (layer - 1)/2 + 1;
-            if(enableTrackPositionPlots){
-                String title = "Track Position - Layer " + layerNumber + " - Difference";
-                //aida.histogram2D(title).fill(trackPos.y(), trackPos.z());
-                aida.cloud2D(title).fill(frontTrackPos.y(), frontTrackPos.z());
-
-                title = "Track Position - Layer " + layerNumber + " - Tracks With All Layers Hit";
-                //aida.histogram2D(title).fill(trackPos.y(), trackPos.z());
-                aida.cloud2D(title).fill(frontTrackPos.y(), frontTrackPos.z());
+        }
+        return true;
+    }
+    
+    /**
+     * Method to check if an event has:
+     * <p><ul>
+     *  <li> At most two tracks
+     *  <li> The two tracks are in opposite volumes
+     *  <li> The two tracks are oppositely charged
+     * </ul>
+     *
+     * @param tracks Collection of tracks in an event
+     * @return True if an event satisfies the above criteria, false otherwise.
+     */
+    private boolean hasGoodTrackPair(List<Track> tracks) {
+        
+        // Require an event to have exactly two tracks
+        if (tracks.size() != 2) return false;
+
+        // Require the two tracks to be in opposite volumes
+        if (tracks.get(0).getTrackStates().get(0).getTanLambda()*tracks.get(1).getTrackStates().get(0).getTanLambda() >= 0) return false;
+
+        // Require the two tracks to be oppositely charged
+        if (tracks.get(0).getTrackStates().get(0).getOmega()*tracks.get(1).getTrackStates().get(0).getOmega() >= 0) return false;
+
+        // If all criteria are satisfied, return true.
+        return true;
+    }
+    
+    /**
+     * 
+     * @param track
+     * @return
+     */
+    private double getTrackMomentum(Track track, double b_field) { 
+       
+        double param = 2.99792458e-04; 
+        double pt = Math.abs((1/track.getTrackStates().get(0).getOmega())*b_field*param);
+        double px = pt*Math.cos(track.getTrackStates().get(0).getPhi());
+        double py = pt*Math.sin(track.getTrackStates().get(0).getPhi());
+        double pz = pt*track.getTrackStates().get(0).getTanLambda();
+        
+        return (new BasicHep3Vector(px, py, pz)).magnitude();  
+    }
+    
+    /**
+     * Create a mapping between a layer number and a collection of 3D hits
+     * associated with the layer.  The mappings are split by SVT volume.
+     *
+     * @param hits Collection of all 3D hits in the event.
+     */
+    private void mapHitsToLayers(List<TrackerHit> hits) { 
+        
+        // Clear all hit maps of all previous mappings.
+        this.topHitMap.clear(); this.botHitMap.clear();
+        
+        // Loop over the collection of 3D hits in the event and map them to 
+        // their corresponding layer.
+        for (TrackerHit hit : hits) {
+            
+            // Retrieve the sensor associated with one of the hits.  This will
+            // be used to retrieve the layer number
+            HpsSiSensor sensor = (HpsSiSensor) ((RawTrackerHit) hit.getRawHits().get(0)).getDetectorElement();
+
+            // Retrieve the layer number by using the sensor
+            int layer = (sensor.getLayerNumber() + 1)/2;
+
+            // Get the hit map corresponding to this layer
+            Map<Integer, List<TrackerHit>> hitMap = null; 
+            hitMap = (sensor.isTopLayer()) ? this.topHitMap : this.botHitMap; 
+            
+            // If a container of hits associated with a layer does not exist, 
+            // create it.
+            if (hitMap.get(layer) == null) { 
+                hitMap.put(layer, new ArrayList<TrackerHit>()); 
             }
             
-            List<SiSensor> sensors = new ArrayList<SiSensor>();
-            if(TrackUtils.getZ0(track) > 0){
-                //sensors.add(SvtUtils.getInstance().getTopSensor(layer, 0));
-                //sensors.add(SvtUtils.getInstance().getTopSensor(layer+1, 0));
-            } else { 
-                //sensors.add(SvtUtils.getInstance().getBottomSensor(layer, 0));
-                //sensors.add(SvtUtils.getInstance().getBottomSensor(layer+1, 0));
-            }
-            //aida.histogram1D(SvtUtils.getInstance().getDescription(sensors.get(0)) + " - Occupancy").fill(this.findIntersectingChannel(frontTrackPos, sensors.get(0)));
-            //aida.histogram1D(SvtUtils.getInstance().getDescription(sensors.get(1)) + " - Occupancy").fill(this.findIntersectingChannel(rearTrackPos, sensors.get(1)));
-            
-           if(debug)
-               System.out.println(this.getClass().getSimpleName() + ": Stereo hit was not found.");*/
-        }
-    }
-    
+            hitMap.get(layer).add(hit);
+        }
+    } 
+
     /**
      *  Find which of the layers is not being used in the track fit
      *
@@ -515,40 +635,39 @@
      *  @return Layer not used in the track fit
      */
     private int getUnusedSvtLayer(List<TrackerHit> stereoHits) {
-        
+
         int[] svtLayer = new int[6];
-        
+
         // Loop over all of the stereo hits associated with the track
         for (TrackerHit stereoHit : stereoHits) {
-            
+
             // Retrieve the sensor associated with one of the hits.  This will
             // be used to retrieve the layer number
             HpsSiSensor sensor = (HpsSiSensor) ((RawTrackerHit) stereoHit.getRawHits().get(0)).getDetectorElement();
-            
+
             // Retrieve the layer number by using the sensor
             int layer = (sensor.getLayerNumber() + 1)/2;
-           
+
             // If a hit is associated with that layer, increment its 
             // corresponding counter
             svtLayer[layer - 1]++;
         }
-        
+
         // Loop through the layer counters and find which layer has not been
         // incremented i.e. is unused by the track
         for(int layer = 0; layer < svtLayer.length; layer++){
             if(svtLayer[layer] == 0) { 
-                System.out.println("Layer number " + (layer+1) + " is not used");
                 return (layer + 1);
             }
         }
-      
+
         // If all of the layers are being used, this track can't be used to 
         // in the single hit efficiency calculation.  This means that something
         // is wrong with the file
         // TODO: This should probably throw an exception
         return -1;
     }
-   
+
     /**
      * Extrapolate a track to a layer and check that it lies within its 
      * acceptance.
@@ -557,69 +676,66 @@
      * @param layer The layer number to extrapolate to
      * @return true if the track lies within the sensor acceptance, false otherwise
      */
-    private boolean isWithinAcceptance(Track track, int layer) {
-       
+    private double isWithinAcceptance(Track track, int layer) {
+
         // TODO: Move this to a utility class 
-       
+
         //System.out.println("Retrieving sensors for layer: " + layer);
-        
+
         // Since TrackUtils.isTop/BottomTrack does not work when running off 
         // a recon file, get the detector volume that a track is associated 
         // with by using the sensor.  This assumes that a track is always
         // composed by stereo hits that lie within a single detector volume
         HpsSiSensor sensor = (HpsSiSensor) ((RawTrackerHit)track.getTrackerHits().get(0).getRawHits().get(0)).getDetectorElement();
-        
+
         // Get the sensors associated with the layer that the track
         // will be extrapolated to
         List<SvtStereoLayer> stereoLayers = null;
-        
+
         // if (TrackUtils.isTopTrack(track, track.getTrackerHits().size())) {
         if (sensor.isTopLayer()) {
             //System.out.println("Top track found.");
             stereoLayers = this.topStereoLayers.get(layer);
-        //} else if (TrackUtils.isBottomTrack(track, track.getTrackerHits().size())) {
+            //} else if (TrackUtils.isBottomTrack(track, track.getTrackerHits().size())) {
         } else {
             //System.out.println("Bottom track found.");
             stereoLayers = this.bottomStereoLayers.get(layer);
         }
-        
-        for (SvtStereoLayer stereoLayer : stereoLayers) { 
-            Hep3Vector axialSensorPosition = stereoLayer.getAxialSensor().getGeometry().getPosition();
-            Hep3Vector stereoSensorPosition = stereoLayer.getStereoSensor().getGeometry().getPosition();
-       
-            //System.out.println("Axial sensor position: " + axialSensorPosition.toString());
-            //System.out.println("Stereo sensor position: " + stereoSensorPosition.toString());
-            
-            Hep3Vector axialTrackPos = TrackUtils.extrapolateTrack(track,  axialSensorPosition.z());
-            Hep3Vector stereoTrackPos = TrackUtils.extrapolateTrack(track, stereoSensorPosition.z());
-      
-            //System.out.println("Track position at axial sensor: " + axialTrackPos.toString());
-            //System.out.println("Track position at stereo sensor: " + stereoTrackPos.toString());
-            
-            if(this.sensorContainsTrack(axialTrackPos, stereoLayer.getAxialSensor()) 
-                    && this.sensorContainsTrack(stereoTrackPos, stereoLayer.getStereoSensor())){
-                //System.out.println("Track lies within layer acceptance.");
-                return true;
-            }
-        }
-        
-        return false;
-        
-        /*int layerNumber = (layer - 1)/2 + 1;
-        String title = "Track Position - Layer " + layerNumber + " - Tracks Within Acceptance";
-        //aida.histogram2D(title).fill(trackPos.y(), trackPos.z());
-        //aida.cloud2D(title).fill(frontTrackPos.y(), frontTrackPos.z()); */
-        
-    }
-    
+
+    for (SvtStereoLayer stereoLayer : stereoLayers) { 
+        Hep3Vector axialSensorPosition = stereoLayer.getAxialSensor().getGeometry().getPosition();
+        Hep3Vector stereoSensorPosition = stereoLayer.getStereoSensor().getGeometry().getPosition();
+
+        //System.out.println("Axial sensor position: " + axialSensorPosition.toString());
+        //System.out.println("Stereo sensor position: " + stereoSensorPosition.toString());
+
+        Hep3Vector axialTrackPos = TrackUtils.extrapolateTrack(track,  axialSensorPosition.z());
+        Hep3Vector stereoTrackPos = TrackUtils.extrapolateTrack(track, stereoSensorPosition.z());
+
+        //System.out.println("Track position at axial sensor: " + axialTrackPos.toString());
+        //System.out.println("Track position at stereo sensor: " + stereoTrackPos.toString());
+
+        if (this.sensorContainsTrack(axialTrackPos, stereoLayer.getAxialSensor()) 
+                && this.sensorContainsTrack(stereoTrackPos, stereoLayer.getStereoSensor())) {
+            
+            double z = (axialTrackPos.z() + stereoTrackPos.z())/2;
+            
+            return z;        
+        }
+    }
+
+    return -9999;
+    
+    }
+
     /**
      * 
      */
     public int findIntersectingChannel(Hep3Vector trackPosition, SiSensor sensor){
-        
+
         //--- Check that the track doesn't pass through a region of bad channels ---//
         //--------------------------------------------------------------------------//
-    
+
         //Rotate the track position to the JLab coordinate system
         //this.printDebug("Track position in tracking frame: " + trackPosition.toString());
         Hep3Vector trackPositionDet = VecOp.mult(VecOp.inverse(this.trackerHitUtils.detToTrackRotationMatrix()), trackPosition);
@@ -634,16 +750,16 @@
         int intersectingChannel = 0;
         for(int physicalChannel= 0; physicalChannel < 639; physicalChannel++){ 
             /*this.printDebug(SvtUtils.getInstance().getDescription(sensor) + " : Channel " + physicalChannel 
-                    + " : Strip Position " + stripPositions.get(sensor).get(physicalChannel));
-            this.printDebug(SvtUtils.getInstance().getDescription(sensor) + ": Channel " + physicalChannel
-                    + " : Delta Y: " + Math.abs(trackPositionDet.x() - stripPositions.get(sensor).get(physicalChannel).x()));*/
+              + " : Strip Position " + stripPositions.get(sensor).get(physicalChannel));
+              this.printDebug(SvtUtils.getInstance().getDescription(sensor) + ": Channel " + physicalChannel
+              + " : Delta Y: " + Math.abs(trackPositionDet.x() - stripPositions.get(sensor).get(physicalChannel).x()));*/
             /*if(Math.abs(trackPositionDet.x() - stripPositions.get(sensor).get(physicalChannel).x()) < deltaY ){
-                deltaY = Math.abs(trackPositionDet.x() - stripPositions.get(sensor).get(physicalChannel).x()); 
-                intersectingChannel = physicalChannel;
-            }*/
-        }
-    
-        
+              deltaY = Math.abs(trackPositionDet.x() - stripPositions.get(sensor).get(physicalChannel).x()); 
+              intersectingChannel = physicalChannel;
+              }*/
+        }
+
+
         return intersectingChannel;
     }
 
@@ -652,25 +768,25 @@
      */
     public boolean sensorContainsTrack(Hep3Vector trackPosition, HpsSiSensor sensor){
 
-        
+
         if(maskBadChannels){
             int intersectingChannel = this.findIntersectingChannel(trackPosition, sensor);
             if(intersectingChannel == 0 || intersectingChannel == 638) return false;
-            
+
             if(sensor.isBadChannel(intersectingChannel) 
                     || sensor.isBadChannel(intersectingChannel+1) 
                     || sensor.isBadChannel(intersectingChannel-1)){
                 //this.printDebug("Track intersects a bad channel!");
                 return false;
-            }
-        }
-        
+                    }
+        }
+
         ITransform3D localToGlobal = sensor.getGeometry().getLocalToGlobal();
-        
+
         Hep3Vector sensorPos = sensor.getGeometry().getPosition();   
         Box sensorSolid = (Box) sensor.getGeometry().getLogicalVolume().getSolid();
         Polygon3D sensorFace = sensorSolid.getFacesNormalTo(new BasicHep3Vector(0, 0, 1)).get(0);
-        
+
         List<Point3D> vertices = new ArrayList<Point3D>();
         for(int index = 0; index < 4; index++){
             vertices.add(new Point3D());
@@ -680,8 +796,8 @@
                 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()));
-               //System.out.println(this.getClass().getSimpleName() + ": Vertex 1 Position: " + vertices.get(0).toString());
-               //System.out.println(this.getClass().getSimpleName() + ": Transformed Vertex 1 Position: " + localToGlobal.transformed(vertex).toString());
+                //System.out.println(this.getClass().getSimpleName() + ": Vertex 1 Position: " + vertices.get(0).toString());
+                //System.out.println(this.getClass().getSimpleName() + ": Transformed Vertex 1 Position: " + localToGlobal.transformed(vertex).toString());
             } 
             else if(vertex.y() > 0 && vertex.x() > 0){
                 localToGlobal.transform(vertex);
@@ -707,12 +823,12 @@
         }
 
         /*
-        double area1 = this.findTriangleArea(vertices.get(0).x(), vertices.get(0).y(), vertices.get(1).x(), vertices.get(1).y(), trackPosition.y(), trackPosition.z()); 
-        double area2 = this.findTriangleArea(vertices.get(1).x(), vertices.get(1).y(), vertices.get(2).x(), vertices.get(2).y(), trackPosition.y(), trackPosition.z()); 
-        double area3 = this.findTriangleArea(vertices.get(2).x(), vertices.get(2).y(), vertices.get(3).x(), vertices.get(3).y(), trackPosition.y(), trackPosition.z()); 
-        double area4 = this.findTriangleArea(vertices.get(3).x(), vertices.get(3).y(), vertices.get(0).x(), vertices.get(0).y(), trackPosition.y(), trackPosition.z()); 
-        */
-        
+           double area1 = this.findTriangleArea(vertices.get(0).x(), vertices.get(0).y(), vertices.get(1).x(), vertices.get(1).y(), trackPosition.y(), trackPosition.z()); 
+           double area2 = this.findTriangleArea(vertices.get(1).x(), vertices.get(1).y(), vertices.get(2).x(), vertices.get(2).y(), trackPosition.y(), trackPosition.z()); 
+           double area3 = this.findTriangleArea(vertices.get(2).x(), vertices.get(2).y(), vertices.get(3).x(), vertices.get(3).y(), trackPosition.y(), trackPosition.z()); 
+           double area4 = this.findTriangleArea(vertices.get(3).x(), vertices.get(3).y(), vertices.get(0).x(), vertices.get(0).y(), trackPosition.y(), trackPosition.z()); 
+           */
+
         double area1 = this.findTriangleArea(vertices.get(0).x(), vertices.get(0).y(), vertices.get(1).x(), vertices.get(1).y(), trackPosition.x(), trackPosition.y()); 
         double area2 = this.findTriangleArea(vertices.get(1).x(), vertices.get(1).y(), vertices.get(2).x(), vertices.get(2).y(), trackPosition.x(), trackPosition.y()); 
         double area3 = this.findTriangleArea(vertices.get(2).x(), vertices.get(2).y(), vertices.get(3).x(), vertices.get(3).y(), trackPosition.x(), trackPosition.y()); 
@@ -725,10 +841,10 @@
     /**
      *
      */
-   public 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 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); 
+    }
+
     @Override
     public void endOfData(){
         System.out.println("%===================================================================%");
@@ -737,32 +853,32 @@
         if(numberOfTopTracks > 0){
             double topEfficiency = numberOfTopTracksWithHitOnMissingLayer/numberOfTopTracks;
             System.out.println("% Top Hit Efficiency: " + numberOfTopTracksWithHitOnMissingLayer + "/" + 
-                                numberOfTopTracks + " = " + topEfficiency*100 + "%");
+                    numberOfTopTracks + " = " + topEfficiency*100 + "%");
             System.out.println("% Top Hit Efficiency Error: sigma poisson = " 
-                                + topEfficiency*Math.sqrt((1/numberOfTopTracksWithHitOnMissingLayer) + (1/numberOfTopTracks))*100 + "%");
+                    + topEfficiency*Math.sqrt((1/numberOfTopTracksWithHitOnMissingLayer) + (1/numberOfTopTracks))*100 + "%");
             System.out.println("% Top Hit Efficiency Error: sigma binomial = " 
-                                + (1/numberOfTopTracks)*Math.sqrt(numberOfTopTracksWithHitOnMissingLayer*(1-topEfficiency))*100 + "%");
+                    + (1/numberOfTopTracks)*Math.sqrt(numberOfTopTracksWithHitOnMissingLayer*(1-topEfficiency))*100 + "%");
         }
         if(numberOfBottomTracks > 0){
             double bottomEfficiency = numberOfBottomTracksWithHitOnMissingLayer/numberOfBottomTracks;
             System.out.println("% Bottom Hit Efficiency: " + numberOfBottomTracksWithHitOnMissingLayer + "/" 
-                                + numberOfBottomTracks + " = " + bottomEfficiency*100 + "%");
+                    + numberOfBottomTracks + " = " + bottomEfficiency*100 + "%");
             System.out.println("% Bottom Hit Efficiency Error: sigma poisson= " 
-                                + bottomEfficiency*Math.sqrt((1/numberOfBottomTracksWithHitOnMissingLayer) + (1/numberOfBottomTracks))*100 + "%");
+                    + bottomEfficiency*Math.sqrt((1/numberOfBottomTracksWithHitOnMissingLayer) + (1/numberOfBottomTracks))*100 + "%");
             System.out.println("% Top Hit Efficiency Error: sigma binomial = " 
-                                + (1/numberOfBottomTracks)*Math.sqrt(numberOfBottomTracksWithHitOnMissingLayer*(1-bottomEfficiency))*100 + "%");
-        }
-/*        for(int index = 0; index < topTracksWithHitOnMissingLayer.length; index++){
-            if(topTracksPerMissingLayer[index] > 0)
-                System.out.println("% Top Layer " + (index+1) + ": " + (topTracksWithHitOnMissingLayer[index]/topTracksPerMissingLayer[index])*100 + "%");
+                    + (1/numberOfBottomTracks)*Math.sqrt(numberOfBottomTracksWithHitOnMissingLayer*(1-bottomEfficiency))*100 + "%");
+        }
+        /*        for(int index = 0; index < topTracksWithHitOnMissingLayer.length; index++){
+                  if(topTracksPerMissingLayer[index] > 0)
+                  System.out.println("% Top Layer " + (index+1) + ": " + (topTracksWithHitOnMissingLayer[index]/topTracksPerMissingLayer[index])*100 + "%");
         }
         for(int index = 0; index < bottomTracksWithHitOnMissingLayer.length; index++){
-            if(bottomTracksPerMissingLayer[index] > 0)
-                System.out.println("% Bottom Layer " + (index+1) + ": " + (bottomTracksWithHitOnMissingLayer[index]/bottomTracksPerMissingLayer[index])*100 + "%");
+        if(bottomTracksPerMissingLayer[index] > 0)
+        System.out.println("% Bottom Layer " + (index+1) + ": " + (bottomTracksWithHitOnMissingLayer[index]/bottomTracksPerMissingLayer[index])*100 + "%");
         }*/
         System.out.println("% \n%===================================================================%");
-        
-        
+
+
         String rootFile = "run" + "_cluster_analysis.root";
         RootFileStore store = new RootFileStore(rootFile);
         try {
@@ -772,34 +888,7 @@
         } catch (IOException e) {
             e.printStackTrace();
         }
-        
-        
-    }
-
-    /**
-     * 
-     * @param tracks
-     * @param particles
-     */
-    private void mapReconstructedParticlesToTracks(List<Track> tracks, List<ReconstructedParticle> particles) {
-        
-       reconParticleMap.clear();
-       for (ReconstructedParticle particle : particles) {
-           for (Track track : tracks) {
-               if (!particle.getTracks().isEmpty() && particle.getTracks().get(0) == track) {
-                   reconParticleMap.put(track, particle);
-               }
-           }
-       }
-    }
-   
-    /**
-     * 
-     * @param track
-     * @return
-     */
-    private ReconstructedParticle getReconstructedParticle(Track track) {
-        return reconParticleMap.get(track);
-    }
-
+
+
+    }    
 }