Print

Print


Author: [log in to unmask]
Date: Mon Jun 22 16:20:30 2015
New Revision: 3181

Log:
clean up FSMonitoring

Modified:
    java/trunk/analysis/src/main/java/org/hps/analysis/dataquality/FinalStateMonitoring.java
    java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/ClusterUtilities.java
    java/trunk/tracking/src/main/java/org/hps/recon/tracking/TrackUtils.java

Modified: java/trunk/analysis/src/main/java/org/hps/analysis/dataquality/FinalStateMonitoring.java
 =============================================================================
--- java/trunk/analysis/src/main/java/org/hps/analysis/dataquality/FinalStateMonitoring.java	(original)
+++ java/trunk/analysis/src/main/java/org/hps/analysis/dataquality/FinalStateMonitoring.java	Mon Jun 22 16:20:30 2015
@@ -15,13 +15,12 @@
 import java.util.Map.Entry;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import org.hps.recon.ecal.triggerbank.AbstractIntData;
-import org.hps.recon.ecal.triggerbank.TIData;
+import org.hps.recon.ecal.cluster.ClusterUtilities;
 import org.hps.recon.tracking.TrackUtils;
 import org.lcsim.event.Cluster;
 import org.lcsim.event.EventHeader;
-import org.lcsim.event.GenericObject;
 import org.lcsim.event.ReconstructedParticle;
+import org.lcsim.event.RelationalTable;
 import org.lcsim.event.Track;
 import org.lcsim.geometry.Detector;
 
@@ -34,8 +33,8 @@
  * output is crap; no charge<0 tracks & the track momentum isn't filled; likely
  * a problem with ReconParticle
  *
- * May 20, 2014: this was fixed by a) Omar's changes to ReconParticle and
- * b) making sure I run ECal clustering before this
+ * May 20, 2014: this was fixed by a) Omar's changes to ReconParticle and b)
+ * making sure I run ECal clustering before this
  *
  *
  */
@@ -55,15 +54,47 @@
     double sumdelX = 0.0;
     double sumdelY = 0.0;
     double sumEoverP = 0.0;
-    private String plotDir = "FinalStateParticles/";
+    private final String plotDir = "FinalStateParticles/";
     double beamEnergy = 1.05; //GeV
     double maxFactor = 2.5;
     double feeMomentumCut = 0.8; //GeV
 
-   public void setFinalStateParticlesColName(String fsp){
-       this.finalStateParticlesColName=fsp;
-   }
-    
+    IHistogram1D elePx;
+    IHistogram1D elePy;
+    IHistogram1D elePz;
+    IHistogram1D elePzBeam;
+    IHistogram1D elePzBeamTop;
+    IHistogram1D elePzBeamBottom;
+    IHistogram1D elePTop;
+    IHistogram1D elePBottom;
+
+    IHistogram1D posPx;
+    IHistogram1D posPy;
+    IHistogram1D posPz;
+    IHistogram1D posPTop;
+    IHistogram1D posPBottom;
+
+    /*  photon quanties (...right now, just unassociated clusters) */
+    IHistogram1D nPhotonsHisto;
+    IHistogram1D enePhoton;
+    IHistogram1D xPhoton;
+    IHistogram1D yPhoton;
+
+    /*  tracks with associated clusters */
+    IHistogram1D eneOverp;
+    IHistogram1D deltaXAtCal;
+    IHistogram1D deltaYAtCal;
+    //IHistogram2D trackXvsECalX = aida.histogram2D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "track X vs ECal X", 50, -300, 300.0, 50, -300, 300.0);
+    //IHistogram2D trackYvsECalY = aida.histogram2D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "track Y vs ECal Y", 50, -100, 100.0, 50, -100, 100.0);
+    IHistogram2D trackPvsECalE;
+    IHistogram2D trackTvsECalT;
+    /* number of unassocaited tracks/event */
+    IHistogram1D nUnAssTracksHisto;
+
+    public void setFinalStateParticlesColName(String fsp) {
+        this.finalStateParticlesColName = fsp;
+    }
+
     @Override
     protected void detectorChanged(Detector detector) {
         System.out.println("FinalStateMonitoring::detectorChanged  Setting up the plotter");
@@ -71,36 +102,37 @@
 
         /*  Final State Particle Quantities   */
         /*  plot electron & positron momentum separately  */
-        IHistogram1D elePx = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType + "/" + "Electron Px (GeV)", 100, -0.1, 0.200);
-        IHistogram1D elePy = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "Electron Py (GeV)", 100, -0.1, 0.1);
-        IHistogram1D elePz = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "Electron Pz (GeV)", 100, 0, beamEnergy * maxFactor);
-        IHistogram1D elePzBeam = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "Beam Electrons Total P (GeV)", 100, feeMomentumCut, beamEnergy * maxFactor);
-        IHistogram1D elePzBeamTop = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "Beam Electrons Total P (GeV):  Top", 100, feeMomentumCut, beamEnergy * maxFactor);
-        IHistogram1D elePzBeamBottom = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "Beam Electrons Total P (GeV):  Bottom", 100, feeMomentumCut, beamEnergy * maxFactor);
-        IHistogram1D elePTop = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "Electron Total P (GeV):  Top", 100, 0, beamEnergy * maxFactor);
-        IHistogram1D elePBottom = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "Electron Total P (GeV):  Bottom", 100, 0, beamEnergy * maxFactor);
-
-        IHistogram1D posPx = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "Positron Px (GeV)", 50, -0.1, 0.200);
-        IHistogram1D posPy = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "Positron Py (GeV)", 50, -0.1, 0.1);
-        IHistogram1D posPz = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "Positron Pz (GeV)", 50, 0, beamEnergy * maxFactor);
-       IHistogram1D posPTop = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "Positron Total P (GeV):  Top", 100, 0, beamEnergy * maxFactor);
-        IHistogram1D posPBottom = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "Positron Total P (GeV):  Bottom", 100, 0, beamEnergy * maxFactor);
+        elePx = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType + "/" + "Electron Px (GeV)", 100, -0.1, 0.200);
+        elePy = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType + "/" + "Electron Py (GeV)", 100, -0.1, 0.1);
+        elePz = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType + "/" + "Electron Pz (GeV)", 100, 0, beamEnergy * maxFactor);
+        elePzBeam = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType + "/" + "Beam Electrons Total P (GeV)", 100, feeMomentumCut, beamEnergy * maxFactor);
+        elePzBeamTop = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType + "/" + "Beam Electrons Total P (GeV):  Top", 100, feeMomentumCut, beamEnergy * maxFactor);
+        elePzBeamBottom = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType + "/" + "Beam Electrons Total P (GeV):  Bottom", 100, feeMomentumCut, beamEnergy * maxFactor);
+        elePTop = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType + "/" + "Electron Total P (GeV):  Top", 100, 0, beamEnergy * maxFactor);
+        elePBottom = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType + "/" + "Electron Total P (GeV):  Bottom", 100, 0, beamEnergy * maxFactor);
+
+        posPx = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType + "/" + "Positron Px (GeV)", 50, -0.1, 0.200);
+        posPy = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType + "/" + "Positron Py (GeV)", 50, -0.1, 0.1);
+        posPz = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType + "/" + "Positron Pz (GeV)", 50, 0, beamEnergy * maxFactor);
+        posPTop = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType + "/" + "Positron Total P (GeV):  Top", 100, 0, beamEnergy * maxFactor);
+        posPBottom = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType + "/" + "Positron Total P (GeV):  Bottom", 100, 0, beamEnergy * maxFactor);
 
         /*  photon quanties (...right now, just unassociated clusters) */
-        IHistogram1D nPhotonsHisto = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "Number of photons per event", 15, 0, 15);
-        IHistogram1D enePhoton = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "Photon Energy (GeV)", 50, 0, 2.4);
-        IHistogram1D xPhoton = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "Photon X position (mm)", 50, -200, 200);
-        IHistogram1D yPhoton = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "Photon Y position (mm)", 50, -100, 100);
+        nPhotonsHisto = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType + "/" + "Number of photons per event", 15, 0, 15);
+        enePhoton = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType + "/" + "Photon Energy (GeV)", 50, 0, 2.4);
+        xPhoton = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType + "/" + "Photon X position (mm)", 50, -200, 200);
+        yPhoton = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType + "/" + "Photon Y position (mm)", 50, -100, 100);
 
         /*  tracks with associated clusters */
-        IHistogram1D eneOverp = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "Cluster Energy Over TrackMomentum", 50, 0, 2.0);
-        IHistogram1D deltaXAtCal = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "delta X @ ECal (mm)", 50, -50, 50.0);
-        IHistogram1D deltaYAtCal = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "delta Y @ ECal (mm)", 50, -50, 50.0);
+        eneOverp = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType + "/" + "Cluster Energy Over TrackMomentum", 50, 0, 2.0);
+        deltaXAtCal = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType + "/" + "delta X @ ECal (mm)", 50, -50, 50.0);
+        deltaYAtCal = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType + "/" + "delta Y @ ECal (mm)", 50, -50, 50.0);
         //IHistogram2D trackXvsECalX = aida.histogram2D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "track X vs ECal X", 50, -300, 300.0, 50, -300, 300.0);
         //IHistogram2D trackYvsECalY = aida.histogram2D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "track Y vs ECal Y", 50, -100, 100.0, 50, -100, 100.0);
-        IHistogram2D trackPvsECalE = aida.histogram2D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "track mom vs ECal E", 50, 0.1, beamEnergy * maxFactor, 50, 0.1, beamEnergy * maxFactor);
+        trackPvsECalE = aida.histogram2D(plotDir + finalStateParticlesColName + "/" + triggerType + "/" + "track mom vs ECal E", 50, 0.1, beamEnergy * maxFactor, 50, 0.1, beamEnergy * maxFactor);
+        trackTvsECalT = aida.histogram2D(plotDir + finalStateParticlesColName + "/" + triggerType + "/" + "track T vs ECal T", 200, 0.0, 200.0, 100, -25.0, 25.0);
         /* number of unassocaited tracks/event */
-        IHistogram1D nUnAssTracksHisto = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "Number of unassociated tracks per event", 5, 0, 5);
+        nUnAssTracksHisto = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType + "/" + "Number of unassociated tracks per event", 5, 0, 5);
     }
 
     @Override
@@ -108,24 +140,31 @@
         /*  make sure everything is there */
 
         if (!event.hasCollection(ReconstructedParticle.class, finalStateParticlesColName)) {
-            if (debug)
+            if (debug) {
                 System.out.println(finalStateParticlesColName + " collection not found???");
+            }
             return;
         }
 
+        RelationalTable hitToStrips = TrackUtils.getHitToStripsTable(event);
+        RelationalTable hitToRotated = TrackUtils.getHitToRotatedTable(event);
+
         //check to see if this event is from the correct trigger (or "all");
-        if (!matchTrigger(event))
+        if (!matchTrigger(event)) {
             return;
+        }
 
         nRecoEvents++;
         int nPhotons = 0;  //number of photons 
         int nUnAssTracks = 0; //number of tracks w/o clusters
         List<ReconstructedParticle> finalStateParticles = event.get(ReconstructedParticle.class, finalStateParticlesColName);
-        if (debug)
+        if (debug) {
             System.out.println("This events has " + finalStateParticles.size() + " final state particles");
+        }
         for (ReconstructedParticle fsPart : finalStateParticles) {
-            if (debug)
+            if (debug) {
                 System.out.println("PDGID = " + fsPart.getParticleIDUsed() + "; charge = " + fsPart.getCharge() + "; pz = " + fsPart.getMomentum().x());
+            }
 
             // Extrapolate the track to the Ecal cluster position
             boolean isPhoton = false;
@@ -134,14 +173,17 @@
             Cluster fsCluster = null;
             //TODO:  mg-May 14, 2014 use PID to do this instead...not sure if that's implemented yet
             if (fsPart.getTracks().size() == 1)//should always be 1 or zero for final state particles
+            {
                 fsTrack = fsPart.getTracks().get(0);
-            else
+            } else {
                 isPhoton = true;
+            }
             //get the cluster
-            if (fsPart.getClusters().size() == 1)
+            if (fsPart.getClusters().size() == 1) {
                 fsCluster = fsPart.getClusters().get(0);
-            else
+            } else {
                 hasCluster = false;
+            }
 
             //deal with electrons & positrons first
             if (!isPhoton) {
@@ -149,32 +191,35 @@
                 Hep3Vector mom = fsPart.getMomentum();
                 if (charge < 0) {
                     nTotEle++;
-                    aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "Electron Px (GeV)").fill(mom.x());
-                    aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "Electron Py (GeV)").fill(mom.y());
-                    aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "Electron Pz (GeV)").fill(mom.z());
-                    aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "Beam Electrons Total P (GeV)").fill(mom.magnitude());
-                    if (mom.y() > 0){
-                        aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "Beam Electrons Total P (GeV):  Top").fill(mom.magnitude());
-                        aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "Electron Total P (GeV):  Top").fill(mom.magnitude());
-                }            else{
-                        aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "Beam Electrons Total P (GeV):  Bottom").fill(mom.magnitude());
-                        aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "Electron Total P (GeV):  Bottom").fill(mom.magnitude());
-                }
+                    elePx.fill(mom.x());
+                    elePy.fill(mom.y());
+                    elePz.fill(mom.z());
+                    elePzBeam.fill(mom.magnitude());
+                    if (mom.y() > 0) {
+                        elePzBeamTop.fill(mom.magnitude());
+                        elePTop.fill(mom.magnitude());
+                    } else {
+                        elePzBeamBottom.fill(mom.magnitude());
+                        elePBottom.fill(mom.magnitude());
+                    }
                 } else {
                     nTotPos++;
-                    aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "Positron Px (GeV)").fill(mom.x());
-                    aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "Positron Py (GeV)").fill(mom.y());
-                    aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "Positron Pz (GeV)").fill(mom.z());
-                      if (mom.y() > 0){
-                        aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "Positron Total P (GeV):  Top").fill(mom.magnitude());
-                }            else{
-                        aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "Positron Total P (GeV):  Bottom").fill(mom.magnitude());
-                }
+                    posPx.fill(mom.x());
+                    posPy.fill(mom.y());
+                    posPz.fill(mom.z());
+                    if (mom.y() > 0) {
+                        posPTop.fill(mom.magnitude());
+                    } else {
+                        posPBottom.fill(mom.magnitude());
+                    }
                 }
 
             }
             //now, the photons
             if (isPhoton) {
+                if (fsCluster == null) {
+                    throw new RuntimeException("isPhoton==true but no cluster found: should never happen");
+                }
                 double ene = fsPart.getEnergy();
                 //TODO:  mg-May 14, 2014....I would like to do this!!!!
                 //double xpos = fsCluster.getPositionAtShowerMax(false)[0];// false-->assume a photon instead of electron from calculating shower depth
@@ -185,12 +230,15 @@
                 double ypos = clusterPosition.y();
                 nPhotons++;
                 nTotPhotons++;
-                aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "Photon Energy (GeV)").fill(ene);
-                aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "Photon X position (mm)").fill(xpos);
-                aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "Photon Y position (mm)").fill(ypos);
+                enePhoton.fill(ene);
+                xPhoton.fill(xpos);
+                yPhoton.fill(ypos);
             }
 
             if (hasCluster && !isPhoton) {
+                if (fsCluster == null) {
+                    throw new RuntimeException("hasCluster==true but no cluster found: should never happen");
+                }
                 nTotAss++;
                 Hep3Vector mom = fsPart.getMomentum();
                 double ene = fsPart.getEnergy();
@@ -204,13 +252,14 @@
                 sumdelY += dy;
                 sumEoverP += eOverP;
 
-                aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "Cluster Energy Over TrackMomentum").fill(eOverP);
-                aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "delta X @ ECal (mm)").fill(dx);
-                aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "delta Y @ ECal (mm)").fill(dy);
+                eneOverp.fill(eOverP);
+                deltaXAtCal.fill(dx);
+                deltaYAtCal.fill(dy);
                 /* here are some plots for debugging track-cluster matching */
                 // aida.histogram2D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "track X vs ECal X").fill(trackPosAtEcal.x(), clusterPosition.x());
                 // aida.histogram2D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "track Y vs ECal Y").fill(trackPosAtEcal.y(), clusterPosition.y());
-                aida.histogram2D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "track mom vs ECal E").fill(fsPart.getMomentum().magnitude(), fsPart.getEnergy());
+                trackPvsECalE.fill(fsPart.getMomentum().magnitude(), fsPart.getEnergy());
+                trackTvsECalT.fill(ClusterUtilities.getSeedHitTime(fsCluster), TrackUtils.getTrackTime(fsTrack, hitToStrips, hitToRotated));
                 //          if(dy<-20)
                 //              System.out.println("Big deltaY...")
 
@@ -220,15 +269,16 @@
                 nTotUnAss++; //and keep a running total for averaging
             }
         }
-        aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "Number of unassociated tracks per event").fill(nUnAssTracks);
-        aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "Number of photons per event").fill(nPhotons);
+        nUnAssTracksHisto.fill(nUnAssTracks);
+        nPhotonsHisto.fill(nPhotons);
     }
 
     @Override
     public void printDQMData() {
         System.out.println("FinalStateMonitoring::printDQMData");
-        for (Entry<String, Double> entry : monitoredQuantityMap.entrySet())
+        for (Entry<String, Double> entry : monitoredQuantityMap.entrySet()) {
             System.out.println(entry.getKey() + " = " + entry.getValue());
+        }
         System.out.println("*******************************");
     }
 
@@ -240,12 +290,12 @@
         IAnalysisFactory analysisFactory = IAnalysisFactory.create();
         IFitFactory fitFactory = analysisFactory.createFitFactory();
         IFitter fitter = fitFactory.createFitter("chi2");
-        IHistogram1D beamE = aida.histogram1D(plotDir + finalStateParticlesColName + "/" + triggerType+ "/" + "Beam Electrons Total P (GeV)");
-        IFitResult result = fitBeamEnergyPeak(beamE, fitter, "range=\"(-10.0,10.0)\"");
+        IFitResult result = fitBeamEnergyPeak(elePzBeam, fitter, "range=\"(-10.0,10.0)\"");
         if (result != null) {
             double[] pars = result.fittedParameters();
-            for (int i = 0; i < 5; i++)
+            for (int i = 0; i < 5; i++) {
                 System.out.println("Beam Energy Peak:  " + result.fittedParameterNames()[i] + " = " + pars[i]);
+            }
             monitoredQuantityMap.put(finalStateParticlesColName + " " + triggerType + " " + fpQuantNames[7], (double) pars[1]);
             monitoredQuantityMap.put(finalStateParticlesColName + " " + triggerType + " " + fpQuantNames[8], (double) pars[2]);
         }
@@ -263,20 +313,23 @@
         pstyle.legendBoxStyle().setVisible(false);
         pstyle.dataStyle().fillStyle().setColor("green");
         pstyle.dataStyle().lineStyle().setColor("black");
-        plotter.region(0).plot(beamE);
+        plotter.region(0).plot(elePzBeam);
 //        plotter.region(0).plot(result.fittedFunction());
-        if (outputPlots)
+        if (outputPlots) {
             try {
                 plotter.writeToFile(outputPlotDir + "beamEnergyElectrons.png");
             } catch (IOException ex) {
                 Logger.getLogger(FinalStateMonitoring.class.getName()).log(Level.SEVERE, null, ex);
             }
+        }
     }
 
     @Override
     public void printDQMStrings() {
         for (int i = 0; i < 9; i++)//TODO:  do this in a smarter way...loop over the map
+        {
             System.out.println("ALTER TABLE dqm ADD " + fpQuantNames[i] + " double;");
+        }
     }
 
     IFitResult fitBeamEnergyPeak(IHistogram1D h1d, IFitter fitter, String range) {

Modified: java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/ClusterUtilities.java
 =============================================================================
--- java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/ClusterUtilities.java	(original)
+++ java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/ClusterUtilities.java	Mon Jun 22 16:20:30 2015
@@ -531,4 +531,13 @@
         }
         return sort(clusters, new ClusterEnergyComparator(), true, true).get(0);
     }
+    
+    /**
+     * Return the time of the seed hit.
+     * @param cluster
+     * @return the seed hit time
+     */
+    public static double getSeedHitTime(Cluster cluster) {
+        return findSeedHit(cluster).getTime();
+    }
 }

Modified: java/trunk/tracking/src/main/java/org/hps/recon/tracking/TrackUtils.java
 =============================================================================
--- java/trunk/tracking/src/main/java/org/hps/recon/tracking/TrackUtils.java	(original)
+++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/TrackUtils.java	Mon Jun 22 16:20:30 2015
@@ -6,12 +6,12 @@
 import hep.physics.vec.Hep3Vector;
 import hep.physics.vec.SpacePoint;
 import hep.physics.vec.VecOp;
-
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
-
+import java.util.Set;
 import org.hps.recon.tracking.EventQuality.Quality;
 import org.hps.recon.tracking.gbl.HelicalTrackStripGbl;
 import org.lcsim.detector.ITransform3D;
@@ -20,11 +20,15 @@
 import org.lcsim.detector.solids.Polygon3D;
 import org.lcsim.detector.tracker.silicon.HpsSiSensor;
 import org.lcsim.detector.tracker.silicon.SiSensor;
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.LCRelation;
 import org.lcsim.event.MCParticle;
 import org.lcsim.event.RawTrackerHit;
+import org.lcsim.event.RelationalTable;
 import org.lcsim.event.Track;
 import org.lcsim.event.TrackState;
 import org.lcsim.event.TrackerHit;
+import org.lcsim.event.base.BaseRelationalTable;
 import org.lcsim.fit.helicaltrack.HelicalTrackFit;
 import org.lcsim.fit.helicaltrack.HelicalTrackHit;
 import org.lcsim.fit.helicaltrack.HelicalTrackStrip;
@@ -859,5 +863,57 @@
         BarrelEndcapFlag beflag = BarrelEndcapFlag.BARREL;
         return new HelicalTrackHit(pos, hitcov, dedx, time, type, rhits, detname, layer, beflag);
     }
-
+    
+    public static RelationalTable getHitToStripsTable(EventHeader event) {
+        RelationalTable hitToStrips = new BaseRelationalTable(RelationalTable.Mode.MANY_TO_MANY, RelationalTable.Weighting.UNWEIGHTED);
+        List<LCRelation> hitrelations = event.get(LCRelation.class, "HelicalTrackHitRelations");
+        for (LCRelation relation : hitrelations) {
+            if (relation != null && relation.getFrom() != null && relation.getTo() != null) {
+                hitToStrips.add(relation.getFrom(), relation.getTo());
+            }
+        }
+
+        return hitToStrips;
+    }
+
+    public static RelationalTable getHitToRotatedTable(EventHeader event) {
+
+        RelationalTable hitToRotated = new BaseRelationalTable(RelationalTable.Mode.ONE_TO_ONE, RelationalTable.Weighting.UNWEIGHTED);
+        List<LCRelation> rotaterelations = event.get(LCRelation.class, "RotatedHelicalTrackHitRelations");
+        for (LCRelation relation : rotaterelations) {
+            if (relation != null && relation.getFrom() != null && relation.getTo() != null) {
+                hitToRotated.add(relation.getFrom(), relation.getTo());
+            }
+        }
+        return hitToRotated;
+    }
+
+    public static double getTrackTime(Track track, RelationalTable hitToStrips, RelationalTable hitToRotated) {
+        int nStrips = 0;
+        double meanTime = 0;
+        for (TrackerHit hit : track.getTrackerHits()) {
+            Set<TrackerHit> htsList = hitToStrips.allFrom(hitToRotated.from(hit));
+            for (TrackerHit hts : htsList) {
+                nStrips++;
+                meanTime += hts.getTime();
+            }
+        }
+        meanTime /= nStrips;
+        return meanTime;
+    }
+    
+    public static boolean hasSharedStrips(Track track1, Track track2, RelationalTable hitToStrips, RelationalTable hitToRotated) {
+        Set<TrackerHit> track1hits = new HashSet<TrackerHit>();
+        for (TrackerHit hit : track1.getTrackerHits()) {
+            track1hits.addAll(hitToStrips.allFrom(hitToRotated.from(hit)));
+        }
+        for (TrackerHit hit : track2.getTrackerHits()) {
+            for (TrackerHit hts : (Set<TrackerHit>) hitToStrips.allFrom(hitToRotated.from(hit))) {
+                if (track1hits.contains(hts)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
 }