Print

Print


Author: [log in to unmask]
Date: Tue Apr 19 14:25:49 2016
New Revision: 4342

Log:
option to write tuples

Added:
    java/trunk/analysis/src/main/java/org/hps/analysis/dataquality/MollerMonitoring.java
      - copied, changed from r4339, java/trunk/analysis/src/main/java/org/hps/analysis/dataquality/TridentMonitoring.java
Modified:
    java/trunk/analysis/src/main/java/org/hps/analysis/dataquality/DataQualityMonitor.java
    java/trunk/analysis/src/main/java/org/hps/analysis/dataquality/TrackingMonitoring.java
    java/trunk/analysis/src/main/java/org/hps/analysis/dataquality/TridentMonitoring.java

Modified: java/trunk/analysis/src/main/java/org/hps/analysis/dataquality/DataQualityMonitor.java
 =============================================================================
--- java/trunk/analysis/src/main/java/org/hps/analysis/dataquality/DataQualityMonitor.java	(original)
+++ java/trunk/analysis/src/main/java/org/hps/analysis/dataquality/DataQualityMonitor.java	Tue Apr 19 14:25:49 2016
@@ -1,5 +1,7 @@
 package org.hps.analysis.dataquality;
 
+import java.io.FileNotFoundException;
+import java.io.PrintWriter;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.util.HashMap;
@@ -7,7 +9,7 @@
 import java.util.Map;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-
+import org.apache.commons.lang3.StringUtils;
 import org.hps.record.triggerbank.AbstractIntData;
 import org.hps.record.triggerbank.TIData;
 import org.lcsim.event.EventHeader;
@@ -23,8 +25,8 @@
  * calculateEndOfRunQuantities & printDQMData i.e. useful methods
  */
 public class DataQualityMonitor extends Driver {
-    
-    private static Logger LOGGER = Logger.getLogger(DataQualityMonitor.class.getPackage().getName());
+
+    private static final Logger LOGGER = Logger.getLogger(DataQualityMonitor.class.getPackage().getName());
 
     protected AIDA aida = AIDA.defaultInstance();
     protected DQMDatabaseManager manager;
@@ -38,6 +40,11 @@
     protected boolean outputPlots = false;
     protected String outputPlotDir = "DQMOutputPlots/";
 
+    protected PrintWriter tupleWriter = null;
+    protected String[] tupleVariables = {};
+    protected final Map<String, Double> tupleMap = new HashMap<String, Double>();
+    protected boolean cutTuple = false;
+
     String triggerType = "all";//allowed types are "" (blank) or "all", singles0, singles1, pairs0,pairs1
     public boolean isGBL = false;
 
@@ -58,7 +65,7 @@
     }
 
     public void setRunNumber(int run) {
-        this.runNumber = run;
+        DataQualityMonitor.runNumber = run;
     }
 
     public void setOverwriteDB(boolean overwrite) {
@@ -81,16 +88,14 @@
         this.outputPlotDir = dir;
     }
 
-    public void DataQualityMonitor() {
-
-    }
-
+    @Override
     public void endOfData() {
         calculateEndOfRunQuantities();
         fillEndOfRunPlots();
         printDQMData();
-        if (printDQMStrings)
+        if (printDQMStrings) {
             printDQMStrings();
+        }
         LOGGER.info("Write to database =  " + connectToDB);
         if (connectToDB) {
             LOGGER.info("Connecting To Database...getting DQMDBManager");
@@ -99,17 +104,21 @@
             boolean entryExists = false;
             try {
                 entryExists = checkRowExists();
-                if (entryExists)
+                if (entryExists) {
                     LOGGER.info("Found an existing run/reco entry in the dqm database; overwrite = " + overwriteDB);
+                }
             } catch (SQLException ex) {
                 Logger.getLogger(DataQualityMonitor.class.getName()).log(Level.SEVERE, null, ex);
             }
 
-            if (!entryExists)
+            if (!entryExists) {
                 makeNewRow();
+            }
             dumpDQMData();
         }
-
+        if (tupleWriter != null) {
+            tupleWriter.close();
+        }
     }
 
     private void makeNewRow() {
@@ -127,9 +136,7 @@
     private boolean checkRowExists() throws SQLException {
         String ins = "select * from dqm where " + getRunRecoString();
         ResultSet res = manager.selectQuery(ins);
-        if (res.next()) //this is a funny way of determining if the ResultSet has any entries
-            return true;
-        return false;
+        return res.next(); //this is a funny way of determining if the ResultSet has any entries
     }
 
     public boolean checkSelectionIsNULL(String var) throws SQLException {
@@ -137,8 +144,9 @@
         ResultSet res = manager.selectQuery(ins);
         res.next();
         double result = res.getDouble(var);
-        if (res.wasNull())
-            return true;
+        if (res.wasNull()) {
+            return true;
+        }
         LOGGER.info("checkSelectionIsNULL::" + var + " = " + result);
         return false;
     }
@@ -183,16 +191,21 @@
     }
 
     public boolean matchTriggerType(TIData triggerData) {
-        if (triggerType.contentEquals("") || triggerType.contentEquals("all"))
-            return true;
-        if (triggerData.isSingle0Trigger() && triggerType.contentEquals("singles0"))
-            return true;
-        if (triggerData.isSingle1Trigger() && triggerType.contentEquals("singles1"))
-            return true;
-        if (triggerData.isPair0Trigger() && triggerType.contentEquals("pairs0"))
-            return true;
-        if (triggerData.isPair1Trigger() && triggerType.contentEquals("pairs1"))
-            return true;
+        if (triggerType.contentEquals("") || triggerType.contentEquals("all")) {
+            return true;
+        }
+        if (triggerData.isSingle0Trigger() && triggerType.contentEquals("singles0")) {
+            return true;
+        }
+        if (triggerData.isSingle1Trigger() && triggerType.contentEquals("singles1")) {
+            return true;
+        }
+        if (triggerData.isPair0Trigger() && triggerType.contentEquals("pairs0")) {
+            return true;
+        }
+        if (triggerData.isPair1Trigger() && triggerType.contentEquals("pairs1")) {
+            return true;
+        }
         return false;
 
     }
@@ -201,14 +214,18 @@
         boolean match = true;
         if (event.hasCollection(GenericObject.class, "TriggerBank")) {
             List<GenericObject> triggerList = event.get(GenericObject.class, "TriggerBank");
-            for (GenericObject data : triggerList)
+            for (GenericObject data : triggerList) {
                 if (AbstractIntData.getTag(data) == TIData.BANK_TAG) {
                     TIData triggerData = new TIData(data);
                     if (!matchTriggerType(triggerData))//only process singles0 triggers...
+                    {
                         match = false;
+                    }
                 }
-        } else if (debug)
+            }
+        } else if (debug) {
             LOGGER.info(this.getClass().getSimpleName() + ":  No trigger bank found...running over all trigger types");
+        }
         return match;
     }
 
@@ -223,4 +240,42 @@
     public void printDQMStrings() {
     }
 
+    protected void writeTuple() {
+        for (String variable : tupleVariables) {
+            Double value = tupleMap.get(variable);
+            if (value == null) {
+                value = -9999.0;
+            }
+            if (variable.endsWith("/I") || variable.endsWith("/B")) {
+                tupleWriter.format("%d\t", Math.round(value));
+            } else {
+                tupleWriter.format("%f\t", value);
+            }
+        }
+        tupleWriter.println();
+        tupleMap.clear();
+    }
+
+    public void setTupleFile(String tupleFile) {
+        try {
+            tupleWriter = new PrintWriter(tupleFile);
+        } catch (FileNotFoundException e) {
+            tupleWriter = null;
+        }
+        tupleWriter.println(StringUtils.join(tupleVariables, ":"));
+//        for (String variable : tupleVariables) {
+//            tupleWriter.format("%s:", variable);
+//        }
+//        tupleWriter.println();
+    }
+
+    /**
+     * apply loose cuts to the tuple (cuts to be defined in the specific DQM
+     * driver)
+     *
+     * @param cutTuple
+     */
+    public void setCutTuple(boolean cutTuple) {
+        this.cutTuple = cutTuple;
+    }
 }

Copied: java/trunk/analysis/src/main/java/org/hps/analysis/dataquality/MollerMonitoring.java (from r4339, java/trunk/analysis/src/main/java/org/hps/analysis/dataquality/TridentMonitoring.java)
 =============================================================================
--- java/trunk/analysis/src/main/java/org/hps/analysis/dataquality/TridentMonitoring.java	(original)
+++ java/trunk/analysis/src/main/java/org/hps/analysis/dataquality/MollerMonitoring.java	Tue Apr 19 14:25:49 2016
@@ -1,9 +1,5 @@
 package org.hps.analysis.dataquality;
 
-import hep.aida.IAnalysisFactory;
-import hep.aida.IFitFactory;
-import hep.aida.IFitResult;
-import hep.aida.IFitter;
 import hep.aida.IHistogram1D;
 import hep.aida.IHistogram2D;
 import hep.physics.vec.BasicHep3Matrix;
@@ -12,22 +8,21 @@
 import java.util.ArrayList;
 import java.util.EnumSet;
 import java.util.List;
-import java.util.Map.Entry;
 import java.util.logging.Logger;
-
 import org.hps.conditions.beam.BeamEnergy.BeamEnergyCollection;
 import org.hps.recon.ecal.cluster.ClusterUtilities;
+import org.hps.recon.particle.HpsReconParticleDriver;
 import org.hps.recon.particle.ReconParticleDriver;
 import org.hps.recon.tracking.TrackType;
 import org.hps.recon.tracking.TrackUtils;
 import org.hps.recon.vertexing.BilliorTrack;
 import org.hps.recon.vertexing.BilliorVertex;
 import org.hps.recon.vertexing.BilliorVertexer;
+import org.lcsim.event.Cluster;
 import org.lcsim.event.EventHeader;
 import org.lcsim.event.ReconstructedParticle;
 import org.lcsim.event.RelationalTable;
 import org.lcsim.event.Track;
-import org.lcsim.event.TrackerHit;
 import org.lcsim.event.Vertex;
 import org.lcsim.geometry.Detector;
 
@@ -38,7 +33,7 @@
  * @author mgraham on May 14, 2014
  *
  */
-public class TridentMonitoring extends DataQualityMonitor {
+public class MollerMonitoring extends DataQualityMonitor {
 
     private enum Cut {
 
@@ -47,13 +42,10 @@
         VERTEX_CUTS("Vtx Cuts"),
         TIMING("Timing"),
         TRACK_CUTS("Trk Cuts"),
-        CLUSTER_CUTS("Cluster"),
         EVENT_QUALITY("Evt Quality"),
-        FRONT_HITS("Front Hits"),
-        ISOLATION("Isolation");
+        FRONT_HITS("Front Hits");
         private final String name;
-        private final static int nCuts = 9;
-        private final static int firstVertexingCut = 7;
+        private final static int firstVertexingCut = 6;
 
         Cut(String name) {
             this.name = name;
@@ -73,7 +65,7 @@
         }
     }
 
-    private final static Logger LOGGER = Logger.getLogger(TridentMonitoring.class.getPackage().getName());
+    private final static Logger LOGGER = Logger.getLogger(MollerMonitoring.class.getPackage().getName());
 
     private final BasicHep3Matrix beamAxisRotation = new BasicHep3Matrix();
 //    private static final int nCuts = 9;
@@ -87,17 +79,15 @@
 //        "Front Hits",
 //        "Isolation"};
 //    private int firstVertexingCut = 0;
-    private static final int TRIDENT = 0;
-    private static final int VERTEX = 1;
 
     private final String finalStateParticlesColName = "FinalStateParticles";
-    private final String unconstrainedV0CandidatesColName = "UnconstrainedV0Candidates";
+    private final String unconstrainedV0CandidatesColName = "UnconstrainedMollerCandidates";
 //    private final String beamConV0CandidatesColName = "BeamspotConstrainedV0Candidates";
 //    private final String targetV0ConCandidatesColName = "TargetConstrainedV0Candidates";
 //    private final String trackListName = "MatchedTracks";
     private final String[] fpQuantNames = {"nV0_per_Event", "avg_BSCon_mass", "avg_BSCon_Vx", "avg_BSCon_Vy", "avg_BSCon_Vz", "sig_BSCon_Vx", "sig_BSCon_Vy", "sig_BSCon_Vz", "avg_BSCon_Chi2"};
 
-    private final String plotDir = "TridentMonitoring/";
+    private final String plotDir = "MollerMonitoring/";
 
 //    private IHistogram2D triTrackTime2D;
 //    private IHistogram1D triTrackTimeDiff;
@@ -115,35 +105,12 @@
 //    private IHistogram1D triZ;
 //    private IHistogram2D triZY;
 //    private IHistogram2D triXY;
-//    private IHistogram1D triPx;
-//    private IHistogram1D triPy;
-//    private IHistogram1D triPz;
-//    private IHistogram2D triPxPy;
-//    private IHistogram1D triU;
-//    private IHistogram1D triV;
-
-    private IHistogram2D triRadTrackTime2D;
-    private IHistogram1D triRadTrackTimeDiff;
-//    private IHistogram2D triRadMassMomentum;
-//    private IHistogram2D triRadZVsMomentum;
-    private IHistogram2D triRadTrackMomentum2D;
-    private IHistogram2D triRadPyEleVsPyPos;
-    private IHistogram2D triRadPxEleVsPxPos;
-    private IHistogram1D triRadDeltaP;
-    private IHistogram1D triRadSumP;
-    private IHistogram1D triRadMass;
-    private IHistogram2D triRadZVsMass;
-//    private IHistogram1D triRadX;
-//    private IHistogram1D triRadY;
-//    private IHistogram1D triRadZ;
-//    private IHistogram2D triRadZY;
-//    private IHistogram2D triRadXY;
-    private IHistogram1D triRadPx;
-    private IHistogram1D triRadPy;
-    private IHistogram1D triRadPz;
-    private IHistogram2D triRadPxPy;
-    private IHistogram1D triRadU;
-    private IHistogram1D triRadV;
+    private IHistogram1D triPx;
+    private IHistogram1D triPy;
+    private IHistogram1D triPz;
+    private IHistogram2D triPxPy;
+    private IHistogram1D triU;
+    private IHistogram1D triV;
 
 //    private IHistogram2D vertTrackTime2D;
 //    private IHistogram1D vertTrackTimeDiff;
@@ -156,121 +123,93 @@
     private IHistogram1D vertSumP;
     private IHistogram1D vertMass;
     private IHistogram2D vertZVsMass;
-//    private IHistogram1D vertX;
+    private IHistogram1D vertX;
     private IHistogram1D vertY;
 //    private IHistogram1D vertZ;
     private IHistogram2D vertZY;
     private IHistogram2D vertXY;
-//    private IHistogram1D vertPx;
-//    private IHistogram1D vertPy;
-//    private IHistogram1D vertPz;
-//    private IHistogram2D vertPxPy;
-//    private IHistogram1D vertU;
-//    private IHistogram1D vertV;
-
-    private IHistogram2D vertRadTrackTime2D;
-    private IHistogram1D vertRadTrackTimeDiff;
-    private IHistogram2D vertRadMassMomentum;
-    private IHistogram2D vertRadZVsMomentum;
-    private IHistogram2D vertRadTrackMomentum2D;
-    private IHistogram2D vertRadPyEleVsPyPos;
-    private IHistogram2D vertRadPxEleVsPxPos;
-    private IHistogram1D vertRadDeltaP;
-    private IHistogram1D vertRadSumP;
-    private IHistogram1D vertRadMass;
-    private IHistogram2D vertRadZVsMass;
-    private IHistogram1D vertRadX;
-    private IHistogram1D vertRadY;
-    private IHistogram1D vertRadZ;
-    private IHistogram2D vertRadZY;
-    private IHistogram2D vertRadXY;
-    private IHistogram1D vertRadPx;
-    private IHistogram1D vertRadPy;
-    private IHistogram1D vertRadPz;
-    private IHistogram2D vertRadPxPy;
-    private IHistogram1D vertRadU;
-    private IHistogram1D vertRadV;
-
-    private IHistogram2D vertRadUnconBsconChi2;
+    private IHistogram1D vertPx;
+    private IHistogram1D vertPy;
+    private IHistogram1D vertPz;
+    private IHistogram2D vertPxPy;
+    private IHistogram1D vertU;
+    private IHistogram1D vertV;
 
     private IHistogram1D nTriCand;
     private IHistogram1D nVtxCand;
 //    IHistogram1D vertexW;
 //    IHistogram2D vertexVZ;
 
-    private IHistogram1D maxTrkChi2;
-    private IHistogram2D zVsMaxTrkChi2;
-    private IHistogram1D v0Chi2;
-    private IHistogram2D zVsV0Chi2;
-    private IHistogram1D trackTimeDiff;
-    private IHistogram2D zVsTrackTimeDiff;
-    private IHistogram1D hitTimeStdDev;
-    private IHistogram2D zVsHitTimeStdDev;
-    private IHistogram1D eventTrkCount;
-    private IHistogram1D eventPosCount;
-    private IHistogram2D zVsEventTrkCount;
-    private IHistogram2D zVsEventPosCount;
-    private IHistogram1D l1Iso;
-    private IHistogram2D zVsL1Iso;
-
-    private final IHistogram1D[][] cutVertexMass = new IHistogram1D[Cut.nCuts][2];
-    private final IHistogram1D[][] cutVertexZ = new IHistogram1D[Cut.nCuts][2];
-    private final IHistogram2D[][] cutVertexZVsMass = new IHistogram2D[Cut.nCuts][2];
-
-    private final double plotsMinMass = 0.03;
-    private final double plotsMaxMass = 0.04;
-
     //clean up event first
     private final int nTrkMax = 5;
     private final int nPosMax = 1;
 
     private final double maxChi2SeedTrack = 7.0;
     private double maxChi2GBLTrack = 15.0;
-    private double maxUnconVertChi2 = 7.0;
+    private double maxUnconVertChi2 = 10.0;
     private double maxBsconVertChi2 = 1000.0; //disable by default
 
     //v0 plot ranges
     private final double v0PzMax = 1.25;//GeV 
     private final double v0PzMin = 0.1;// GeV
-    private final double v0PyMax = 0.04;//GeV absolute value
-    private final double v0PxMax = 0.04;//GeV absolute value
+    private final double v0PyMax = 0.01;//GeV absolute value
+    private final double v0PxMax = 0.02;//GeV absolute value
     private final double v0VzMax = 50.0;// mm from target...someday make mass dependent
     private final double v0VyMax = 2.0;// mm from target...someday make mass dependent
     private final double v0VxMax = 2.0;// mm from target...someday make mass dependent
 
     //v0 cuts
     private final double v0PzMaxCut = 1.25;//GeV 
-    private final double v0PzMinCut = 0.1;// GeV
-    private final double v0PyCut = 0.04;//GeV absolute value
-    private final double v0PxCut = 0.04;//GeV absolute value
+    private final double v0PzMinCut = 0.8;// GeV
+    private final double v0PyCut = 0.01;//GeV absolute value
+    private final double v0PxCut = 0.02;//GeV absolute value
     private final double v0UnconVzCut = 50.0;// mm from target...someday make mass dependent
-    private double v0UnconVyCut = 2.0;// mm from target...someday make mass dependent
-    private double v0UnconVxCut = 2.0;// mm from target...someday make mass dependent
+    private double v0UnconVyCut = 10.0;// mm from target...someday make mass dependent
+    private double v0UnconVxCut = 10.0;// mm from target...someday make mass dependent
     private double v0BsconVyCut = 10.0; //disable by default
     private double v0BsconVxCut = 10.0; //disable by default
 
 //  track quality cuts
-    private final double beamPCut = 0.85;
-    private final double minPCut = 0.05;
+    private final double maxTrkPCut = 0.85;
+//    private final double minTrkPCut = 0.05;
 //    private double trkPyMax = 0.2;
 //    private double trkPxMax = 0.2;
-    private final double radCut = 0.8;
     private final double trkTimeDiff = 5.0;
-    private final double clusterTimeDiffCut = 2.5;
-
-    private double l1IsoMin = 0.5;
-
-    private double[] beamSize = {0.001, 0.130, 0.050}; //rough estimate from harp scans during engineering run production running
-
-//cluster matching
-//    private boolean reqCluster = false;
-//    private int nClustMax = 3;
-//    private double eneLossFactor = 0.7; //average E/p roughly
-//    private double eneOverPCut = 0.3; //|(E/p)_meas - (E/p)_mean|<eneOverPCut
-//counters
-    private float nEvents = 0;
-    private float nRecoV0 = 0;
-    private final float[] nPassCut = new float[Cut.nCuts];
+//    private final double clusterTimeDiffCut = 2.5;
+
+    private final double tupleTrkPCut = 0.9;
+    private final double tupleMinSumCut = 0.7;
+    private final double tupleMaxSumCut = 1.3;
+
+//    private double l1IsoMin = 0.5;
+    private final double[] beamSize = {0.001, 0.130, 0.050}; //rough estimate from harp scans during engineering run production running
+    private final double[] beamPos = {0.0, 0.0, 0.0};
+    private final double[] vzcBeamSize = {0.001, 100, 100};
+
+    public MollerMonitoring() {
+        this.tupleVariables = new String[]{"run/I", "event/I",
+            "nTrk/I", "nPos/I",
+            "uncPX/D", "uncPY/D", "uncPZ/D", "uncP/D",
+            "uncVX/D", "uncVY/D", "uncVZ/D", "uncChisq/D", "uncM/D",
+            "bscPX/D", "bscPY/D", "bscPZ/D", "bscP/D",
+            "bscVX/D", "bscVY/D", "bscVZ/D", "bscChisq/D", "bscM/D",
+            "tarPX/D", "tarPY/D", "tarPZ/D", "tarP/D",
+            "tarVX/D", "tarVY/D", "tarVZ/D", "tarChisq/D", "tarM/D",
+            "vzcPX/D", "vzcPY/D", "vzcPZ/D", "vzcP/D",
+            "vzcVX/D", "vzcVY/D", "vzcVZ/D", "vzcChisq/D", "vzcM/D",
+            "topPX/D", "topPY/D", "topPZ/D", "topP/D",
+            "topTrkChisq/D", "topTrkHits/I", "topTrkType/I", "topTrkT/D",
+            "topTrkD0/D", "topTrkZ0/D", "topTrkEcalX/D", "topTrkEcalY/D",
+            "topHasL1/B", "topHasL2/B",
+            "topMatchChisq/D", "topClT/D", "topClE/D", "topClX/D", "topClY/D", "topClZ/D", "topClHits/I",
+            "botPX/D", "botPY/D", "botPZ/D", "botP/D",
+            "botTrkChisq/D", "botTrkHits/I", "botTrkType/I", "botTrkT/D",
+            "botTrkD0/D", "botTrkZ0/D", "botTrkEcalX/D", "botTrkEcalY/D",
+            "botHasL1/B", "botHasL2/B",
+            "botMatchChisq/D", "botClT/D", "botClE/D", "botClX/D", "botClY/D", "botClZ/D", "botClHits/I",
+            "minL1Iso/D"
+        };
+    }
 
     public void setMaxChi2GBLTrack(double maxChi2GBLTrack) {
         this.maxChi2GBLTrack = maxChi2GBLTrack;
@@ -300,10 +239,6 @@
         this.v0BsconVxCut = v0BsconVxCut;
     }
 
-    public void setL1IsoMin(double l1IsoMin) {
-        this.l1IsoMin = l1IsoMin;
-    }
-
     public void setBeamSizeX(double beamSizeX) {
         this.beamSize[1] = beamSizeX;
     }
@@ -312,15 +247,23 @@
         this.beamSize[2] = beamSizeY;
     }
 
+    public void setBeamPosX(double beamPosX) {
+        this.beamPos[1] = beamPosX;
+    }
+
+    public void setBeamPosY(double beamPosY) {
+        this.beamPos[2] = beamPosY;
+    }
+
     double ebeam;
 
     @Override
     protected void detectorChanged(Detector detector) {
-        LOGGER.info("TridendMonitoring::detectorChanged  Setting up the plotter");
+        LOGGER.info("MollerMonitoring::detectorChanged  Setting up the plotter");
         beamAxisRotation.setActiveEuler(Math.PI / 2, -0.0305, -Math.PI / 2);
 
-        BeamEnergyCollection beamEnergyCollection = 
-            this.getConditionsManager().getCachedConditions(BeamEnergyCollection.class, "beam_energies").getCachedData();        
+        BeamEnergyCollection beamEnergyCollection
+                = this.getConditionsManager().getCachedConditions(BeamEnergyCollection.class, "beam_energies").getCachedData();
         ebeam = beamEnergyCollection.get(0).getBeamEnergy();
         aida.tree().cd("/");
         String trkType = "SeedTrack/";
@@ -342,139 +285,57 @@
 //        IHistogram1D tarconVy = aida.histogram1D(plotDir +  triggerType + "/"+ triggerType + "/"+"Target Constrained Vy (mm)", 50, -1, 1);
 //        IHistogram1D tarconVz = aida.histogram1D(plotDir +  triggerType + "/"+ triggerType + "/"+"Target Constrained Vz (mm)", 50, -10, 10);
 //        IHistogram1D tarconChi2 = aida.histogram1D(plotDir +  triggerType + "/"+ triggerType + "/"+"Target Constrained Chi2", 25, 0, 25);
-        nTriCand = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Number of Trident Candidates", 5, 0, 4);
+        nTriCand = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Number of Moller Candidates", 5, 0, 4);
 
 //        triTrackTimeDiff = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Trident: Track time difference", 100, -10, 10);
 //        triTrackTime2D = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Trident: Track time vs. track time", 100, -10, 10, 100, -10, 10);
-        triTrackMomentum2D = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Trident: Positron vs. electron momentum", 100, 0, v0PzMax * ebeam, 100, 0, v0PzMax * ebeam);
-        triDeltaP = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Trident: Positron - electron momentum", 100, -ebeam, ebeam);
-        triSumP = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Trident: Positron + electron momentum", 100, v0PzMin * ebeam, v0PzMax * ebeam);
-        triPyEleVsPyPos = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Trident: Py(e) vs Py(p)", 50, -v0PyMax * ebeam, v0PyMax * ebeam, 50, -v0PyMax * ebeam, v0PyMax * ebeam);
-        triPxEleVsPxPos = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Trident: Px(e) vs Px(p)", 50, -v0PxMax * ebeam, v0PxMax * ebeam, 50, -v0PxMax * ebeam, v0PxMax * ebeam);
-
-        triMassMomentum = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Trident: Vertex mass vs. vertex momentum", 100, v0PzMin * ebeam, v0PzMax * ebeam, 100, 0, 0.1 * ebeam);
-        triZVsMomentum = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Trident: Vertex Z vs. vertex momentum", 100, v0PzMin * ebeam, v0PzMax * ebeam, 100, -v0VzMax, v0VzMax);
-        triMass = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Trident: Vertex mass", 100, 0, 0.1 * ebeam);
-        triZVsMass = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Trident: Vertex Z vs. mass", 100, 0, 0.1 * ebeam, 100, -v0VzMax, v0VzMax);
+        triTrackMomentum2D = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Moller: Bottom vs. top momentum", 100, 0, v0PzMax * ebeam, 100, 0, v0PzMax * ebeam);
+        triDeltaP = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Moller: Bottom - top momentum", 100, -ebeam, ebeam);
+        triSumP = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Moller: Bottom + top momentum", 100, v0PzMin * ebeam, v0PzMax * ebeam);
+        triPyEleVsPyPos = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Moller: Py(t) vs Py(b)", 50, -2 * v0PyMax * ebeam, 2 * v0PyMax * ebeam, 50, -2 * v0PyMax * ebeam, 2 * v0PyMax * ebeam);
+        triPxEleVsPxPos = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Moller: Px(t) vs Px(b)", 50, -2 * v0PxMax * ebeam, 2 * v0PxMax * ebeam, 50, -2 * v0PxMax * ebeam, 2 * v0PxMax * ebeam);
+
+        triMassMomentum = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Moller: Vertex mass vs. vertex momentum", 100, v0PzMin * ebeam, v0PzMax * ebeam, 100, 0, 0.1 * ebeam);
+        triZVsMomentum = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Moller: Vertex Z vs. vertex momentum", 100, v0PzMin * ebeam, v0PzMax * ebeam, 100, -v0VzMax, v0VzMax);
+        triMass = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Moller: Vertex mass", 100, 0, 0.1 * ebeam);
+        triZVsMass = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Moller: Vertex Z vs. mass", 100, 0, 0.1 * ebeam, 100, -v0VzMax, v0VzMax);
 //        triX = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Trident: Vertex X", 100, -v0VxMax, v0VxMax);
 //        triY = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Trident: Vertex Y", 100, -v0VyMax, v0VyMax);
 //        triZ = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Trident: Vertex Z", 100, -v0VzMax, v0VzMax);
 //        triXY = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Trident: Vertex Y vs. X", 100, -v0VxMax, v0VxMax, 100, -v0VyMax, v0VyMax);
 //        triZY = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Trident: Vertex Z vs. Y", 100, -v0VyMax, v0VyMax, 100, -v0VzMax, v0VzMax);
-//        triPx = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Trident: Vertex Px", 100, -v0PxMax, v0PxMax);
-//        triPy = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Trident: Vertex Py", 100, -v0PyMax, v0PyMax);
-//        triPz = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Trident: Vertex Pz", 100, v0PzMin, v0PzMax);
-//        triPxPy = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Trident: Vertex Py vs. Px", 100, -v0PxMax, v0PxMax, 100, -v0PyMax, v0PyMax);
-//        triU = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Trident: Vertex Px over Ptot", 100, -0.1, 0.1);
-//        triV = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Trident: Vertex Py over Ptot", 100, -0.1, 0.1);
-
-        triRadTrackTimeDiff = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Radiative trident: Track time difference", 100, -10, 10);
-        triRadTrackTime2D = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Radiative trident: Track time vs. track time", 100, -10, 10, 100, -10, 10);
-
-        triRadTrackMomentum2D = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Radiative trident: Positron vs. electron momentum", 100, 0, v0PzMax * ebeam, 100, 0, v0PzMax * ebeam);
-        triRadDeltaP = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Radiative trident: Positron - electron momentum", 100, -ebeam, ebeam);
-        triRadSumP = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Radiative trident: Positron + electron momentum", 100, v0PzMin * ebeam, v0PzMax * ebeam);
-        triRadPyEleVsPyPos = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Radiative trident: Py(e) vs Py(p)", 50, -v0PyMax * ebeam, v0PyMax * ebeam, 50, -v0PyMax * ebeam, v0PyMax * ebeam);
-        triRadPxEleVsPxPos = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Radiative trident: Px(e) vs Px(p)", 50, -v0PxMax * ebeam, v0PxMax * ebeam, 50, -v0PxMax * ebeam, v0PxMax * ebeam);
-
-//        triRadMassMomentum = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Radiative trident: Vertex mass vs. vertex momentum", 100, v0PzMin, v0PzMax, 100, 0, 0.1);
-//        triRadZVsMomentum = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Radiative trident: Vertex Z vs. vertex momentum", 100, v0PzMin, v0PzMax, 100, -v0VzMax, v0VzMax);
-        triRadMass = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Radiative trident: Vertex mass", 100, 0, 0.1 * ebeam);
-        triRadZVsMass = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Radiative trident: Vertex Z vs. mass", 100, 0, 0.1 * ebeam, 100, -v0VzMax, v0VzMax);
-//        triRadX = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Radiative trident: Vertex X", 100, -v0VxMax, v0VxMax);
-//        triRadY = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Radiative trident: Vertex Y", 100, -v0VyMax, v0VyMax);
-//        triRadZ = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Radiative trident: Vertex Z", 100, -v0VzMax, v0VzMax);
-//        triRadXY = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Radiative trident: Vertex Y vs. X", 100, -v0VxMax, v0VxMax, 100, -v0VyMax, v0VyMax);
-//        triRadZY = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Radiative trident: Vertex Z vs. Y", 100, -v0VyMax, v0VyMax, 100, -v0VzMax, v0VzMax);
-        triRadPx = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Radiative trident: Vertex Px", 100, -v0PxMax * ebeam, v0PxMax * ebeam);
-        triRadPy = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Radiative trident: Vertex Py", 100, -v0PyMax * ebeam, v0PyMax * ebeam);
-        triRadPz = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Radiative trident: Vertex Pz", 100, v0PzMin * ebeam, v0PzMax * ebeam);
-        triRadPxPy = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Radiative trident: Vertex Py vs. Px", 100, -v0PxMax * ebeam, v0PxMax * ebeam, 100, -v0PyMax * ebeam, v0PyMax * ebeam);
-        triRadU = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Radiative trident: Vertex Px over Ptot", 100, -0.1, 0.1);
-        triRadV = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Radiative trident: Vertex Py over Ptot", 100, -0.1, 0.1);
+        triPx = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Trident: Vertex Px", 100, -v0PxMax, v0PxMax);
+        triPy = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Trident: Vertex Py", 100, -v0PyMax, v0PyMax);
+        triPz = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Trident: Vertex Pz", 100, v0PzMin, v0PzMax);
+        triPxPy = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Trident: Vertex Py vs. Px", 100, -v0PxMax, v0PxMax, 100, -v0PyMax, v0PyMax);
+        triU = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Trident: Vertex Px over Ptot", 100, -0.1, 0.1);
+        triV = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Trident: Vertex Py over Ptot", 100, -0.1, 0.1);
 
 //        vertTrackTimeDiff = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Vertex: Track time difference", 100, -10, 10);
 //        vertTrackTime2D = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Vertex: Track time vs. track time", 100, -10, 10, 100, -10, 10);
-        vertTrackMomentum2D = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Vertex: Positron vs. electron momentum", 100, 0, v0PzMax * ebeam, 100, 0, v0PzMax * ebeam);
-        vertDeltaP = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Vertex: Positron - electron momentum", 100, -ebeam, ebeam);
-        vertSumP = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Vertex: Positron + electron momentum", 100, v0PzMin * ebeam, v0PzMax * ebeam);
-        vertPyEleVsPyPos = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Vertex: Py(e) vs Py(p)", 50, -v0PyMax * ebeam, v0PyMax * ebeam, 50, -v0PyMax * ebeam, v0PyMax * ebeam);
-        vertPxEleVsPxPos = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Vertex: Px(e) vs Px(p)", 50, -v0PxMax * ebeam, v0PxMax * ebeam, 50, -v0PxMax * ebeam, v0PxMax * ebeam);
+        vertTrackMomentum2D = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Vertex: Bottom vs. top momentum", 100, 0, v0PzMax * ebeam, 100, 0, v0PzMax * ebeam);
+        vertDeltaP = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Vertex: Bottom - top momentum", 100, -ebeam, ebeam);
+        vertSumP = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Vertex: Bottom + top momentum", 100, v0PzMin * ebeam, v0PzMax * ebeam);
+        vertPyEleVsPyPos = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Vertex: Py(t) vs Py(b)", 50, -2 * v0PyMax * ebeam, 2 * v0PyMax * ebeam, 50, -2 * v0PyMax * ebeam, 2 * v0PyMax * ebeam);
+        vertPxEleVsPxPos = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Vertex: Px(t) vs Px(b)", 50, -2 * v0PxMax * ebeam, 2 * v0PxMax * ebeam, 50, -2 * v0PxMax * ebeam, 2 * v0PxMax * ebeam);
 
         vertMassMomentum = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Vertex: Vertex mass vs. vertex momentum", 100, v0PzMin * ebeam, v0PzMax * ebeam, 100, 0, 0.1 * ebeam);
         vertZVsMomentum = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Vertex: Vertex Z vs. vertex momentum", 100, v0PzMin * ebeam, v0PzMax * ebeam, 100, -v0VzMax, v0VzMax);
         vertMass = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Vertex: Vertex mass", 100, 0, 0.1 * ebeam);
         vertZVsMass = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Vertex: Vertex Z vs. mass", 100, 0, 0.1 * ebeam, 100, -v0VzMax, v0VzMax);
-//        vertX = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Vertex: Vertex X", 100, -v0VxMax, v0VxMax);
+        vertX = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Vertex: Vertex X", 100, -v0VxMax, v0VxMax);
         vertY = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Vertex: Vertex Y", 100, -v0VyMax, v0VyMax);
 //        vertZ = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Vertex: Vertex Z", 100, -v0VzMax, v0VzMax);
         vertXY = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Vertex: Vertex Y vs. X", 100, -v0VxMax, v0VxMax, 100, -v0VyMax, v0VyMax);
         vertZY = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Vertex: Vertex Z vs. Y", 100, -v0VyMax, v0VyMax, 100, -v0VzMax, v0VzMax);
-//        vertPx = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Vertex: Vertex Px", 100, -v0PxMax, v0PxMax);
-//        vertPy = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Vertex: Vertex Py", 100, -v0PyMax, v0PyMax);
-//        vertPz = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Vertex: Vertex Pz", 100, v0PzMin, v0PzMax);
-//        vertPxPy = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Vertex: Vertex Py vs. Px", 100, -v0PxMax, v0PxMax, 100, -v0PyMax, v0PyMax);
-//        vertU = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Vertex: Vertex Px over Ptot", 100, -0.1, 0.1);
-//        vertV = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Vertex: Vertex Py over Ptot", 100, -0.1, 0.1);
-
-        vertRadTrackTimeDiff = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Radiative vertex: Track time difference", 100, -10, 10);
-        vertRadTrackTime2D = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Radiative vertex: Track time vs. track time", 100, -10, 10, 100, -10, 10);
-
-        vertRadTrackMomentum2D = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Radiative vertex: Positron vs. electron momentum", 100, 0, v0PzMax * ebeam, 100, 0, v0PzMax * ebeam);
-        vertRadDeltaP = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Radiative vertex: Positron - electron momentum", 100, -ebeam, ebeam);
-        vertRadSumP = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Radiative vertex: Positron + electron momentum", 100, v0PzMin * ebeam, v0PzMax * ebeam);
-        vertRadPyEleVsPyPos = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Radiative vertex: Py(e) vs Py(p)", 50, -v0PyMax * ebeam, v0PyMax * ebeam, 50, -v0PyMax * ebeam, v0PyMax * ebeam);
-        vertRadPxEleVsPxPos = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Radiative vertex: Px(e) vs Px(p)", 50, -v0PxMax * ebeam, v0PxMax * ebeam, 50, -v0PxMax * ebeam, v0PxMax * ebeam);
-
-        vertRadMassMomentum = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Radiative vertex: Vertex mass vs. vertex momentum", 100, v0PzMin * ebeam, v0PzMax * ebeam, 100, 0, 0.1 * ebeam);
-        vertRadZVsMomentum = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Radiative vertex: Vertex Z vs. vertex momentum", 100, v0PzMin * ebeam, v0PzMax * ebeam, 100, -v0VzMax, v0VzMax);
-        vertRadMass = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Radiative vertex: Vertex mass", 100, 0, 0.1 * ebeam);
-        vertRadZVsMass = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Radiative vertex: Vertex Z vs. mass", 100, 0, 0.1 * ebeam, 100, -v0VzMax, v0VzMax);
-        vertRadX = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Radiative vertex: Vertex X", 100, -v0VxMax, v0VxMax);
-        vertRadY = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Radiative vertex: Vertex Y", 100, -v0VyMax, v0VyMax);
-        vertRadZ = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Radiative vertex: Vertex Z", 100, -v0VzMax, v0VzMax);
-        vertRadXY = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Radiative vertex: Vertex Y vs. X", 100, -v0VxMax, v0VxMax, 100, -v0VyMax, v0VyMax);
-        vertRadZY = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Radiative vertex: Vertex Z vs. Y", 100, -v0VyMax, v0VyMax, 100, -v0VzMax, v0VzMax);
-        vertRadPx = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Radiative vertex: Vertex Px", 100, -v0PxMax * ebeam, v0PxMax * ebeam);
-        vertRadPy = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Radiative vertex: Vertex Py", 100, -v0PyMax * ebeam, v0PyMax * ebeam);
-        vertRadPz = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Radiative vertex: Vertex Pz", 100, v0PzMin * ebeam, v0PzMax * ebeam);
-        vertRadPxPy = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Radiative vertex: Vertex Py vs. Px", 100, -v0PxMax * ebeam, v0PxMax * ebeam, 100, -v0PyMax * ebeam, v0PyMax * ebeam);
-        vertRadU = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Radiative vertex: Vertex Px over Ptot", 100, -0.1, 0.1);
-        vertRadV = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Radiative vertex: Vertex Py over Ptot", 100, -0.1, 0.1);
-
-        vertRadUnconBsconChi2 = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Radiative vertex: beamspot chi2 vs. uncon chi2", 100, 0, 25.0, 100, 0, 25.0);
+        vertPx = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Vertex: Vertex Px", 100, -v0PxMax, v0PxMax);
+        vertPy = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Vertex: Vertex Py", 100, -v0PyMax, v0PyMax);
+        vertPz = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Vertex: Vertex Pz", 100, v0PzMin, v0PzMax);
+        vertPxPy = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Vertex: Vertex Py vs. Px", 100, -v0PxMax, v0PxMax, 100, -v0PyMax, v0PyMax);
+        vertU = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Vertex: Vertex Px over Ptot", 100, -0.1, 0.1);
+        vertV = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Vertex: Vertex Py over Ptot", 100, -0.1, 0.1);
 
         nVtxCand = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Number of Vertexing Candidates", 5, 0, 4);
-
-        maxTrkChi2 = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Cut: Trk Chi2", 50, 0.0, 50.0);
-        zVsMaxTrkChi2 = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Cut: Vz vs Trk Chi2", 50, 0.0, 50.0, 50, -v0VzMax, v0VzMax);
-
-        v0Chi2 = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Cut: V0 Chi2", 50, 0.0, 25.0);
-        zVsV0Chi2 = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Cut: Vz vs V0 Chi2", 50, 0.0, 25.0, 50, -v0VzMax, v0VzMax);
-
-        trackTimeDiff = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Cut: Trk Time Diff", 50, 0.0, 10.0);
-        hitTimeStdDev = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Cut: Hit Time Std Dev", 50, 0.0, 10.0);
-        zVsTrackTimeDiff = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Cut: Vz vs Trk Time Diff", 50, 0.0, 10.0, 50, -v0VzMax, v0VzMax);
-        zVsHitTimeStdDev = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Cut: Vz vs Hit Time Std Dev", 50, 0.0, 10.0, 50, -v0VzMax, v0VzMax);
-
-        eventTrkCount = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Cut: Num Tracks", 10, 0.5, 10.5);
-        eventPosCount = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Cut: Num Positrons", 5, 0.5, 5.5);
-        zVsEventTrkCount = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Cut: Vz vs Num Tracks", 10, 0.5, 10.5, 50, -v0VzMax, v0VzMax);
-        zVsEventPosCount = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Cut: Vz vs Num Positrons", 5, 0.5, 5.5, 50, -v0VzMax, v0VzMax);
-
-        l1Iso = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Cut: L1 Isolation", 50, 0.0, 5.0);
-        zVsL1Iso = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Cut: Vz vs L1 Isolation", 50, 0.0, 5.0, 50, -v0VzMax, v0VzMax);
-
-        for (Cut cut : Cut.values()) {
-            for (int i = 0; i < 2; i++) {
-                cutVertexZ[cut.ordinal()][i] = aida.histogram1D(String.format("%s%s%s/failed cut %d: %s/%s: Vertex Z position (mm)", plotDir, trkType, triggerType, cut.ordinal(), cut.name, i == VERTEX ? "vertex" : "trident"),
-                        100, -v0VzMax, v0VzMax);
-                cutVertexMass[cut.ordinal()][i] = aida.histogram1D(String.format("%s%s%s/failed cut %d: %s/%s: Vertex mass (GeV)", plotDir, trkType, triggerType, cut.ordinal(), cut.name, i == VERTEX ? "vertex" : "trident"),
-                        100, 0, 0.1 * ebeam);
-                cutVertexZVsMass[cut.ordinal()][i] = aida.histogram2D(String.format("%s%s%s/failed cut %d: %s/%s: Vertex Z vs. mass", plotDir, trkType, triggerType, cut.ordinal(), cut.name, i == VERTEX ? "vertex" : "trident"),
-                        100, 0, 0.1 * ebeam, 100, -v0VzMax, v0VzMax);
-            }
-        }
     }
 
     @Override
@@ -498,16 +359,7 @@
             return;
         }
 
-        nEvents++;
-
-        int nV0 = 0;
         List<ReconstructedParticle> unConstrainedV0List = event.get(ReconstructedParticle.class, unconstrainedV0CandidatesColName);
-        for (ReconstructedParticle v0 : unConstrainedV0List) {
-            if (isGBL == TrackType.isGBL(v0.getType())) {
-                nV0++;
-            }
-        }
-        nRecoV0 += nV0;
 
         RelationalTable hitToStrips = TrackUtils.getHitToStripsTable(event);
         RelationalTable hitToRotated = TrackUtils.getHitToRotatedTable(event);
@@ -539,55 +391,168 @@
             Hep3Vector v0Vtx = VecOp.mult(beamAxisRotation, uncVert.getPosition());
 
             List<Track> tracks = new ArrayList<Track>();
-            ReconstructedParticle electron = uncV0.getParticles().get(ReconParticleDriver.ELECTRON);
-            ReconstructedParticle positron = uncV0.getParticles().get(ReconParticleDriver.POSITRON);
-            if (electron.getCharge() != -1 || positron.getCharge() != 1) {
+            ReconstructedParticle top = uncV0.getParticles().get(ReconParticleDriver.MOLLER_TOP);
+            ReconstructedParticle bot = uncV0.getParticles().get(ReconParticleDriver.MOLLER_BOT);
+            if (top.getCharge() != -1 || bot.getCharge() != -1) {
                 throw new RuntimeException("incorrect charge on v0 daughters");
             }
-            tracks.add(electron.getTracks().get(0));
-            tracks.add(positron.getTracks().get(0));
+            tracks.add(top.getTracks().get(0));
+            tracks.add(bot.getTracks().get(0));
             if (tracks.size() != 2) {
                 throw new RuntimeException("expected two tracks in vertex, got " + tracks.size());
             }
-            List<Double> trackTimes = new ArrayList<Double>();
-            List<Double> hitTimes = new ArrayList<Double>();
-            double mean = 0;
-            for (Track track : tracks) {
-                trackTimes.add(TrackUtils.getTrackTime(track, hitToStrips, hitToRotated));
-                for (TrackerHit hit : TrackUtils.getStripHits(track, hitToStrips, hitToRotated)) {
-                    mean += hit.getTime();
-                    hitTimes.add(hit.getTime());
-                }
-            }
-            mean /= hitTimes.size();
-            double stdDev = 0;
-            for (Double time : hitTimes) {
-                stdDev += Math.pow(time - mean, 2);
-            }
-            stdDev /= (hitTimes.size() - 1);
-            stdDev = Math.sqrt(stdDev);
-
-            Double[] eleIso = TrackUtils.getIsolations(electron.getTracks().get(0), hitToStrips, hitToRotated);
-            Double[] posIso = TrackUtils.getIsolations(positron.getTracks().get(0), hitToStrips, hitToRotated);
+
+            Double[] topIso = TrackUtils.getIsolations(top.getTracks().get(0), hitToStrips, hitToRotated);
+            Double[] botIso = TrackUtils.getIsolations(bot.getTracks().get(0), hitToStrips, hitToRotated);
             double minL1Iso = -9999;
-            if (eleIso[0] != null && posIso[0] != null) {
-                double eleL1Iso = Math.min(Math.abs(eleIso[0]), Math.abs(eleIso[1]));
-                double posL1Iso = Math.min(Math.abs(posIso[0]), Math.abs(posIso[1]));
-                minL1Iso = Math.min(eleL1Iso, posL1Iso);
-            }
+            if (topIso[0] != null && botIso[0] != null) {
+                double topL1Iso = Math.min(Math.abs(topIso[0]), Math.abs(topIso[1]));
+                double botL1Iso = Math.min(Math.abs(botIso[0]), Math.abs(botIso[1]));
+                minL1Iso = Math.min(topL1Iso, botL1Iso);
+            }
+
+            double tTop = TrackUtils.getTrackTime(top.getTracks().get(0), hitToStrips, hitToRotated);
+            double tBot = TrackUtils.getTrackTime(bot.getTracks().get(0), hitToStrips, hitToRotated);
+            Hep3Vector pTopRot = VecOp.mult(beamAxisRotation, top.getMomentum());
+            Hep3Vector pBotRot = VecOp.mult(beamAxisRotation, bot.getMomentum());
+
+            Hep3Vector topAtEcal = TrackUtils.getTrackPositionAtEcal(top.getTracks().get(0));
+            Hep3Vector botAtEcal = TrackUtils.getTrackPositionAtEcal(bot.getTracks().get(0));
 
             BilliorVertexer vtxFitter = new BilliorVertexer(TrackUtils.getBField(event.getDetector()).y());
             vtxFitter.setBeamSize(beamSize);
+            vtxFitter.setBeamPosition(beamPos);
             List<BilliorTrack> billiorTracks = new ArrayList<BilliorTrack>();
-            billiorTracks.add(new BilliorTrack(electron.getTracks().get(0)));
-            billiorTracks.add(new BilliorTrack(positron.getTracks().get(0)));
+            billiorTracks.add(new BilliorTrack(top.getTracks().get(0)));
+            billiorTracks.add(new BilliorTrack(bot.getTracks().get(0)));
+
             vtxFitter.doBeamSpotConstraint(true);
             BilliorVertex bsconVertex = vtxFitter.fitVertex(billiorTracks);
+            ReconstructedParticle bscV0 = HpsReconParticleDriver.makeReconstructedParticle(top, bot, bsconVertex);
+            Hep3Vector bscMomRot = VecOp.mult(beamAxisRotation, bscV0.getMomentum());
+            Hep3Vector bscVtx = VecOp.mult(beamAxisRotation, bscV0.getStartVertex().getPosition());
+
+            vtxFitter.doTargetConstraint(true);
+            BilliorVertex tarVertex = vtxFitter.fitVertex(billiorTracks);
+            ReconstructedParticle tarV0 = HpsReconParticleDriver.makeReconstructedParticle(top, bot, tarVertex);
+            Hep3Vector tarMomRot = VecOp.mult(beamAxisRotation, tarV0.getMomentum());
+            Hep3Vector tarVtx = VecOp.mult(beamAxisRotation, tarV0.getStartVertex().getPosition());
+
+            vtxFitter.setBeamSize(vzcBeamSize);
+            vtxFitter.doTargetConstraint(true);
+            BilliorVertex vzcVertex = vtxFitter.fitVertex(billiorTracks);
+            ReconstructedParticle vzcV0 = HpsReconParticleDriver.makeReconstructedParticle(top, bot, vzcVertex);
+            Hep3Vector vzcMomRot = VecOp.mult(beamAxisRotation, vzcV0.getMomentum());
+            Hep3Vector vzcVtx = VecOp.mult(beamAxisRotation, vzcV0.getStartVertex().getPosition());
+
+            if (tupleWriter != null) {
+                boolean trkCut = top.getMomentum().magnitude() < tupleTrkPCut * ebeam && bot.getMomentum().magnitude() < tupleTrkPCut * ebeam;
+                boolean sumCut = top.getMomentum().magnitude() + bot.getMomentum().magnitude() > tupleMinSumCut * ebeam && top.getMomentum().magnitude() + bot.getMomentum().magnitude() < tupleMaxSumCut * ebeam;
+
+                if (!cutTuple || (trkCut && sumCut)) {
+
+                    tupleMap.put("run/I", (double) event.getRunNumber());
+                    tupleMap.put("event/I", (double) event.getEventNumber());
+
+                    tupleMap.put("uncPX/D", v0MomRot.x());
+                    tupleMap.put("uncPY/D", v0MomRot.y());
+                    tupleMap.put("uncPZ/D", v0MomRot.z());
+                    tupleMap.put("uncP/D", v0MomRot.magnitude());
+                    tupleMap.put("uncVX/D", v0Vtx.x());
+                    tupleMap.put("uncVY/D", v0Vtx.y());
+                    tupleMap.put("uncVZ/D", v0Vtx.z());
+                    tupleMap.put("uncChisq/D", uncV0.getStartVertex().getChi2());
+                    tupleMap.put("uncM/D", uncV0.getMass());
+
+                    tupleMap.put("bscPX/D", bscMomRot.x());
+                    tupleMap.put("bscPY/D", bscMomRot.y());
+                    tupleMap.put("bscPZ/D", bscMomRot.z());
+                    tupleMap.put("bscP/D", bscMomRot.magnitude());
+                    tupleMap.put("bscVX/D", bscVtx.x());
+                    tupleMap.put("bscVY/D", bscVtx.y());
+                    tupleMap.put("bscVZ/D", bscVtx.z());
+                    tupleMap.put("bscChisq/D", bscV0.getStartVertex().getChi2());
+                    tupleMap.put("bscM/D", bscV0.getMass());
+
+                    tupleMap.put("tarPX/D", tarMomRot.x());
+                    tupleMap.put("tarPY/D", tarMomRot.y());
+                    tupleMap.put("tarPZ/D", tarMomRot.z());
+                    tupleMap.put("tarP/D", tarMomRot.magnitude());
+                    tupleMap.put("tarVX/D", tarVtx.x());
+                    tupleMap.put("tarVY/D", tarVtx.y());
+                    tupleMap.put("tarVZ/D", tarVtx.z());
+                    tupleMap.put("tarChisq/D", tarV0.getStartVertex().getChi2());
+                    tupleMap.put("tarM/D", tarV0.getMass());
+
+                    tupleMap.put("vzcPX/D", vzcMomRot.x());
+                    tupleMap.put("vzcPY/D", vzcMomRot.y());
+                    tupleMap.put("vzcPZ/D", vzcMomRot.z());
+                    tupleMap.put("vzcP/D", vzcMomRot.magnitude());
+                    tupleMap.put("vzcVX/D", vzcVtx.x());
+                    tupleMap.put("vzcVY/D", vzcVtx.y());
+                    tupleMap.put("vzcVZ/D", vzcVtx.z());
+                    tupleMap.put("vzcChisq/D", vzcV0.getStartVertex().getChi2());
+                    tupleMap.put("vzcM/D", vzcV0.getMass());
+
+                    tupleMap.put("topPX/D", pTopRot.x());
+                    tupleMap.put("topPY/D", pTopRot.y());
+                    tupleMap.put("topPZ/D", pTopRot.z());
+                    tupleMap.put("topP/D", pTopRot.magnitude());
+                    tupleMap.put("topTrkD0/D", top.getTracks().get(0).getTrackStates().get(0).getD0());
+                    tupleMap.put("topTrkZ0/D", top.getTracks().get(0).getTrackStates().get(0).getZ0());
+                    tupleMap.put("topTrkEcalX/D", topAtEcal.x());
+                    tupleMap.put("topTrkEcalY/D", topAtEcal.y());
+                    tupleMap.put("topTrkChisq/D", top.getTracks().get(0).getChi2());
+                    tupleMap.put("topTrkHits/I", (double) top.getTracks().get(0).getTrackerHits().size());
+                    tupleMap.put("topTrkType/I", (double) top.getType());
+                    tupleMap.put("topTrkT/D", tTop);
+                    tupleMap.put("topHasL1/B", topIso[0] != null ? 1.0 : 0.0);
+                    tupleMap.put("topHasL2/B", topIso[2] != null ? 1.0 : 0.0);
+                    tupleMap.put("topMatchChisq/D", top.getGoodnessOfPID());
+                    if (!top.getClusters().isEmpty()) {
+                        Cluster topC = top.getClusters().get(0);
+                        tupleMap.put("topClT/D", ClusterUtilities.getSeedHitTime(topC));
+                        tupleMap.put("topClE/D", topC.getEnergy());
+                        tupleMap.put("topClX/D", topC.getPosition()[0]);
+                        tupleMap.put("topClY/D", topC.getPosition()[1]);
+                        tupleMap.put("topClZ/D", topC.getPosition()[2]);
+                        tupleMap.put("topClHits/I", (double) topC.getCalorimeterHits().size());
+                    }
+
+                    tupleMap.put("botPX/D", pBotRot.x());
+                    tupleMap.put("botPY/D", pBotRot.y());
+                    tupleMap.put("botPZ/D", pBotRot.z());
+                    tupleMap.put("botP/D", pBotRot.magnitude());
+                    tupleMap.put("botTrkD0/D", bot.getTracks().get(0).getTrackStates().get(0).getD0());
+                    tupleMap.put("botTrkZ0/D", bot.getTracks().get(0).getTrackStates().get(0).getZ0());
+                    tupleMap.put("botTrkEcalX/D", botAtEcal.x());
+                    tupleMap.put("botTrkEcalY/D", botAtEcal.y());
+                    tupleMap.put("botTrkChisq/D", bot.getTracks().get(0).getChi2());
+                    tupleMap.put("botTrkHits/I", (double) bot.getTracks().get(0).getTrackerHits().size());
+                    tupleMap.put("botTrkType/I", (double) bot.getType());
+                    tupleMap.put("botTrkT/D", tBot);
+                    tupleMap.put("botHasL1/B", botIso[0] != null ? 1.0 : 0.0);
+                    tupleMap.put("botHasL2/B", botIso[2] != null ? 1.0 : 0.0);
+                    tupleMap.put("botMatchChisq/D", bot.getGoodnessOfPID());
+                    if (!bot.getClusters().isEmpty()) {
+                        Cluster botC = bot.getClusters().get(0);
+                        tupleMap.put("botClT/D", ClusterUtilities.getSeedHitTime(botC));
+                        tupleMap.put("botClE/D", botC.getEnergy());
+                        tupleMap.put("botClHits/I", (double) botC.getCalorimeterHits().size());
+                    }
+
+                    tupleMap.put("minL1Iso/D", minL1Iso);
+
+                    tupleMap.put("nTrk/I", (double) ntrk);
+                    tupleMap.put("nPos/I", (double) npos);
+                    writeTuple();
+                }
+            }
 
             //start applying cuts
             EnumSet<Cut> bits = EnumSet.noneOf(Cut.class);
 
-            boolean trackQualityCut = Math.max(tracks.get(0).getChi2(), tracks.get(1).getChi2()) < (isGBL ? maxChi2GBLTrack : maxChi2SeedTrack);
+            boolean trackQualityCut = Math.max(top.getTracks().get(0).getChi2(), bot.getTracks().get(0).getChi2()) < (isGBL ? maxChi2GBLTrack : maxChi2SeedTrack);
             if (trackQualityCut) {
                 bits.add(Cut.TRK_QUALITY);
             }
@@ -598,29 +563,24 @@
             }
 
             boolean vertexMomentumCut = v0MomRot.z() < v0PzMaxCut * ebeam && v0MomRot.z() > v0PzMinCut * ebeam && Math.abs(v0MomRot.x()) < v0PxCut * ebeam && Math.abs(v0MomRot.y()) < v0PyCut * ebeam;
-            boolean vertexPositionCut = Math.abs(v0Vtx.x()) < v0UnconVxCut && Math.abs(v0Vtx.y()) < v0UnconVyCut && Math.abs(v0Vtx.z()) < v0UnconVzCut && Math.abs(bsconVertex.getPosition().x()) < v0BsconVxCut && Math.abs(bsconVertex.getPosition().y()) < v0BsconVyCut;
+            boolean vertexPositionCut = Math.abs(v0Vtx.x()) < v0UnconVxCut && Math.abs(v0Vtx.y()) < v0UnconVyCut && Math.abs(v0Vtx.z()) < v0UnconVzCut && Math.abs(bscVtx.x()) < v0BsconVxCut && Math.abs(bscVtx.y()) < v0BsconVyCut;
             if (vertexMomentumCut && vertexPositionCut) {
                 bits.add(Cut.VERTEX_CUTS);
             }
 
-            boolean trackTimeDiffCut = Math.abs(trackTimes.get(0) - trackTimes.get(1)) < trkTimeDiff;
+            boolean trackTimeDiffCut = Math.abs(tTop - tBot) < trkTimeDiff;
             if (trackTimeDiffCut) {
                 bits.add(Cut.TIMING);
             }
 
-            boolean topBottomCut = electron.getMomentum().y() * positron.getMomentum().y() < 0;
-            boolean pMinCut = electron.getMomentum().magnitude() > minPCut * ebeam && positron.getMomentum().magnitude() > minPCut * ebeam;
-            boolean pMaxCut = electron.getMomentum().magnitude() < beamPCut * ebeam && positron.getMomentum().magnitude() < beamPCut * ebeam;
-            if (topBottomCut && pMaxCut && pMinCut) {
+//            boolean topBottomCut = top.getMomentum().y() * bot.getMomentum().y() < 0;
+//            boolean pMinCut = top.getMomentum().magnitude() > minTrkPCut * ebeam && bot.getMomentum().magnitude() > minTrkPCut * ebeam;
+            boolean pMaxCut = top.getMomentum().magnitude() < maxTrkPCut * ebeam && bot.getMomentum().magnitude() < maxTrkPCut * ebeam;
+//            boolean pSumCut = top.getMomentum().magnitude() + bot.getMomentum().magnitude() < maxPSumCut * ebeam && top.getMomentum().magnitude() + bot.getMomentum().magnitude() < minPSumCut * ebeam;
+//            boolean pMaxCut = top.getMomentum().magnitude() < maxTrkPCut * ebeam && bot.getMomentum().magnitude() < maxTrkPCut * ebeam;
+            if (pMaxCut) {
                 bits.add(Cut.TRACK_CUTS);
             }
-
-            boolean clusterMatchCut = !electron.getClusters().isEmpty() && !positron.getClusters().isEmpty();
-            boolean clusterTimeCut = clusterMatchCut && Math.abs(ClusterUtilities.getSeedHitTime(electron.getClusters().get(0)) - ClusterUtilities.getSeedHitTime(positron.getClusters().get(0))) < clusterTimeDiffCut;
-//disable cut for now
-//            if (clusterMatchCut && clusterTimeCut) {
-            bits.add(Cut.CLUSTER_CUTS);
-//            }
 
             boolean eventTrkCountCut = ntrk >= 2 && ntrk <= nTrkMax;
             boolean eventPosCountCut = npos >= 1 && npos <= nPosMax;
@@ -628,14 +588,9 @@
                 bits.add(Cut.EVENT_QUALITY);
             }
 
-            boolean frontHitsCut = eleIso[0] != null && posIso[0] != null && eleIso[2] != null && posIso[2] != null;
+            boolean frontHitsCut = topIso[0] != null && botIso[0] != null && topIso[2] != null && botIso[2] != null;
             if (frontHitsCut) {
                 bits.add(Cut.FRONT_HITS);
-            }
-
-            boolean isoCut = minL1Iso > l1IsoMin;
-            if (!frontHitsCut || isoCut) { //diagnostic plots look better if failing the front hits cut makes you pass this one
-                bits.add(Cut.ISOLATION);
             }
 
             for (Cut cut : Cut.values()) {
@@ -643,66 +598,11 @@
                     if (cut.ordinal() == Cut.firstVertexingCut) {//if we get here, we've passed all non-vertexing cuts
                         candidateList.add(uncV0);
                     }
-                    nPassCut[cut.ordinal()]++;
                 } else {
                     break;
                 }
             }
 
-            for (Cut cut : Cut.values()) {
-                EnumSet<Cut> allButThisCut = EnumSet.allOf(Cut.class);
-                allButThisCut.remove(cut);
-                if (bits.containsAll(allButThisCut)) {
-                    if (uncV0.getMass() > plotsMinMass * ebeam && uncV0.getMass() < plotsMaxMass * ebeam) {
-                        switch (cut) {
-                            case ISOLATION:
-                                l1Iso.fill(minL1Iso);
-                                zVsL1Iso.fill(minL1Iso, v0Vtx.z());
-                                break;
-                            case EVENT_QUALITY:
-                                eventTrkCount.fill(ntrk);
-                                eventPosCount.fill(npos);
-                                zVsEventTrkCount.fill(ntrk, v0Vtx.z());
-                                zVsEventPosCount.fill(npos, v0Vtx.z());
-                                break;
-                            case TIMING:
-                                trackTimeDiff.fill(Math.abs(trackTimes.get(0) - trackTimes.get(1)));
-                                hitTimeStdDev.fill(stdDev);
-                                zVsTrackTimeDiff.fill(Math.abs(trackTimes.get(0) - trackTimes.get(1)), v0Vtx.z());
-                                zVsHitTimeStdDev.fill(stdDev, v0Vtx.z());
-                                break;
-                            case VTX_QUALITY:
-                                v0Chi2.fill(uncVert.getChi2());
-                                zVsV0Chi2.fill(uncVert.getChi2(), v0Vtx.z());
-                                break;
-                            case TRK_QUALITY:
-                                maxTrkChi2.fill(Math.max(tracks.get(0).getChi2(), tracks.get(1).getChi2()));
-                                zVsMaxTrkChi2.fill(Math.max(tracks.get(0).getChi2(), tracks.get(1).getChi2()), v0Vtx.z());
-                                break;
-                        }
-                    }
-                    if (!bits.contains(cut)) {
-                        if (uncV0.getMass() > plotsMinMass * ebeam && uncV0.getMass() < plotsMaxMass * ebeam) {
-                            cutVertexZ[cut.ordinal()][VERTEX].fill(v0Vtx.z());
-                        }
-                        cutVertexMass[cut.ordinal()][VERTEX].fill(uncV0.getMass());
-                        cutVertexZVsMass[cut.ordinal()][VERTEX].fill(uncV0.getMass(), v0Vtx.z());
-                    }
-                }
-
-                EnumSet<Cut> allTriCutsButThisCut = EnumSet.range(Cut.values()[0], Cut.values()[Cut.firstVertexingCut - 1]);
-                allTriCutsButThisCut.remove(cut);
-                if (bits.containsAll(allTriCutsButThisCut)) {
-                    if (!bits.contains(cut)) {
-                        if (uncV0.getMass() > plotsMinMass * ebeam && uncV0.getMass() < plotsMaxMass * ebeam) {
-                            cutVertexZ[cut.ordinal()][TRIDENT].fill(v0Vtx.z());
-                        }
-                        cutVertexMass[cut.ordinal()][TRIDENT].fill(uncV0.getMass());
-                        cutVertexZVsMass[cut.ordinal()][TRIDENT].fill(uncV0.getMass(), v0Vtx.z());
-                    }
-                }
-            }
-
             if (bits.containsAll(EnumSet.range(Cut.values()[0], Cut.values()[Cut.firstVertexingCut - 1]))) {
                 candidateList.add(uncV0);
             }
@@ -719,67 +619,40 @@
             ReconstructedParticle bestCandidate = candidateList.get((int) (Math.random() * candidateList.size()));
 
             //fill some stuff: 
-            ReconstructedParticle electron = bestCandidate.getParticles().get(ReconParticleDriver.ELECTRON);
-            ReconstructedParticle positron = bestCandidate.getParticles().get(ReconParticleDriver.POSITRON);
-            if (electron.getCharge() != -1 || positron.getCharge() != 1) {
-                throw new RuntimeException("vertex needs e+ and e- but is missing one or both");
-            }
-
-            double tEle = TrackUtils.getTrackTime(electron.getTracks().get(0), hitToStrips, hitToRotated);
-            double tPos = TrackUtils.getTrackTime(positron.getTracks().get(0), hitToStrips, hitToRotated);
+            ReconstructedParticle top = bestCandidate.getParticles().get(ReconParticleDriver.MOLLER_TOP);
+            ReconstructedParticle bot = bestCandidate.getParticles().get(ReconParticleDriver.MOLLER_BOT);
+            if (top.getCharge() != -1 || bot.getCharge() != -1) {
+                throw new RuntimeException("vertex needs two e- but is missing one or both");
+            }
+
+            Hep3Vector pEleRot = VecOp.mult(beamAxisRotation, top.getMomentum());
+            Hep3Vector pPosRot = VecOp.mult(beamAxisRotation, bot.getMomentum());
+            Hep3Vector v0Vtx = VecOp.mult(beamAxisRotation, bestCandidate.getStartVertex().getPosition());
             Hep3Vector pBestV0Rot = VecOp.mult(beamAxisRotation, bestCandidate.getMomentum());
-            Hep3Vector pEleRot = VecOp.mult(beamAxisRotation, electron.getMomentum());
-            Hep3Vector pPosRot = VecOp.mult(beamAxisRotation, positron.getMomentum());
-            Hep3Vector v0Vtx = VecOp.mult(beamAxisRotation, bestCandidate.getStartVertex().getPosition());
 
 //            triTrackTime2D.fill(tEle, tPos);
 //            triTrackTimeDiff.fill(tEle - tPos);
             triZVsMomentum.fill(bestCandidate.getMomentum().magnitude(), v0Vtx.z());
             triMassMomentum.fill(bestCandidate.getMomentum().magnitude(), bestCandidate.getMass());
-            triTrackMomentum2D.fill(electron.getMomentum().magnitude(), positron.getMomentum().magnitude());
+            triTrackMomentum2D.fill(top.getMomentum().magnitude(), bot.getMomentum().magnitude());
             triPyEleVsPyPos.fill(pEleRot.y(), pPosRot.y());
             triPxEleVsPxPos.fill(pEleRot.x(), pPosRot.x());
             triSumP.fill(bestCandidate.getMomentum().magnitude());
-            triDeltaP.fill(positron.getMomentum().magnitude() - electron.getMomentum().magnitude());
-
-//            triPxPy.fill(pBestV0Rot.x(), pBestV0Rot.y());
+            triDeltaP.fill(bot.getMomentum().magnitude() - top.getMomentum().magnitude());
+
+            triPxPy.fill(pBestV0Rot.x(), pBestV0Rot.y());
             triMass.fill(bestCandidate.getMass());
             triZVsMass.fill(bestCandidate.getMass(), v0Vtx.z());
 //            triX.fill(v0Vtx.x());
 //            triY.fill(v0Vtx.y());
 //            triZ.fill(v0Vtx.z());
-//            triPx.fill(pBestV0Rot.x());
-//            triPy.fill(pBestV0Rot.y());
-//            triPz.fill(pBestV0Rot.z());
-//            triU.fill(pBestV0Rot.x() / pBestV0Rot.magnitude());
-//            triV.fill(pBestV0Rot.y() / pBestV0Rot.magnitude());
+            triPx.fill(pBestV0Rot.x());
+            triPy.fill(pBestV0Rot.y());
+            triPz.fill(pBestV0Rot.z());
+            triU.fill(pBestV0Rot.x() / pBestV0Rot.magnitude());
+            triV.fill(pBestV0Rot.y() / pBestV0Rot.magnitude());
 //            triXY.fill(v0Vtx.x(), v0Vtx.y());
 //            triZY.fill(v0Vtx.y(), v0Vtx.z());
-            if (bestCandidate.getMomentum().magnitude() > radCut * ebeam) {
-                triRadTrackTime2D.fill(tEle, tPos);
-                triRadTrackTimeDiff.fill(tEle - tPos);
-//                triRadZVsMomentum.fill(bestCandidate.getMomentum().magnitude(), v0Vtx.z());
-//                triRadMassMomentum.fill(bestCandidate.getMomentum().magnitude(), bestCandidate.getMass());
-                triRadTrackMomentum2D.fill(electron.getMomentum().magnitude(), positron.getMomentum().magnitude());
-                triRadPyEleVsPyPos.fill(pEleRot.y(), pPosRot.y());
-                triRadPxEleVsPxPos.fill(pEleRot.x(), pPosRot.x());
-                triRadSumP.fill(bestCandidate.getMomentum().magnitude());
-                triRadDeltaP.fill(positron.getMomentum().magnitude() - electron.getMomentum().magnitude());
-
-                triRadPxPy.fill(pBestV0Rot.x(), pBestV0Rot.y());
-                triRadMass.fill(bestCandidate.getMass());
-                triRadZVsMass.fill(bestCandidate.getMass(), v0Vtx.z());
-//                triRadX.fill(v0Vtx.x());
-//                triRadY.fill(v0Vtx.y());
-//                triRadZ.fill(v0Vtx.z());
-                triRadPx.fill(pBestV0Rot.x());
-                triRadPy.fill(pBestV0Rot.y());
-                triRadPz.fill(pBestV0Rot.z());
-                triRadU.fill(pBestV0Rot.x() / pBestV0Rot.magnitude());
-                triRadV.fill(pBestV0Rot.y() / pBestV0Rot.magnitude());
-//                triRadXY.fill(v0Vtx.x(), v0Vtx.y());
-//                triRadZY.fill(v0Vtx.y(), v0Vtx.z());
-            }
         }
 
         if (!vertCandidateList.isEmpty()) {
@@ -788,118 +661,41 @@
             Vertex unconVertex = bestCandidate.getStartVertex();
 
             //fill some stuff: 
-            ReconstructedParticle electron = bestCandidate.getParticles().get(ReconParticleDriver.ELECTRON);
-            ReconstructedParticle positron = bestCandidate.getParticles().get(ReconParticleDriver.POSITRON);
-            if (electron.getCharge() != -1 || positron.getCharge() != 1) {
-                throw new RuntimeException("vertex needs e+ and e- but is missing one or both");
-            }
-
-            double tEle = TrackUtils.getTrackTime(electron.getTracks().get(0), hitToStrips, hitToRotated);
-            double tPos = TrackUtils.getTrackTime(positron.getTracks().get(0), hitToStrips, hitToRotated);
+            ReconstructedParticle top = bestCandidate.getParticles().get(ReconParticleDriver.MOLLER_TOP);
+            ReconstructedParticle bot = bestCandidate.getParticles().get(ReconParticleDriver.MOLLER_BOT);
+            if (top.getCharge() != -1 || bot.getCharge() != -1) {
+                throw new RuntimeException("vertex needs two e- but is missing one or both");
+            }
+
+            Hep3Vector pEleRot = VecOp.mult(beamAxisRotation, top.getMomentum());
+            Hep3Vector pPosRot = VecOp.mult(beamAxisRotation, bot.getMomentum());
+            Hep3Vector v0Vtx = VecOp.mult(beamAxisRotation, unconVertex.getPosition());
             Hep3Vector pBestV0Rot = VecOp.mult(beamAxisRotation, bestCandidate.getMomentum());
-            Hep3Vector pEleRot = VecOp.mult(beamAxisRotation, electron.getMomentum());
-            Hep3Vector pPosRot = VecOp.mult(beamAxisRotation, positron.getMomentum());
-            Hep3Vector v0Vtx = VecOp.mult(beamAxisRotation, unconVertex.getPosition());
 
 //            vertTrackTime2D.fill(tEle, tPos);
 //            vertTrackTimeDiff.fill(tEle - tPos);
             vertZVsMomentum.fill(bestCandidate.getMomentum().magnitude(), v0Vtx.z());
             vertMassMomentum.fill(bestCandidate.getMomentum().magnitude(), bestCandidate.getMass());
-            vertTrackMomentum2D.fill(electron.getMomentum().magnitude(), positron.getMomentum().magnitude());
+            vertTrackMomentum2D.fill(top.getMomentum().magnitude(), bot.getMomentum().magnitude());
             vertPyEleVsPyPos.fill(pEleRot.y(), pPosRot.y());
             vertPxEleVsPxPos.fill(pEleRot.x(), pPosRot.x());
             vertSumP.fill(bestCandidate.getMomentum().magnitude());
-            vertDeltaP.fill(positron.getMomentum().magnitude() - electron.getMomentum().magnitude());
-
-//            vertPxPy.fill(pBestV0Rot.x(), pBestV0Rot.y());
+            vertDeltaP.fill(bot.getMomentum().magnitude() - top.getMomentum().magnitude());
+
+            vertPxPy.fill(pBestV0Rot.x(), pBestV0Rot.y());
             vertMass.fill(bestCandidate.getMass());
             vertZVsMass.fill(bestCandidate.getMass(), v0Vtx.z());
-//            vertX.fill(v0Vtx.x());
+            vertX.fill(v0Vtx.x());
             vertY.fill(v0Vtx.y());
 //            vertZ.fill(v0Vtx.z());
-//            vertPx.fill(pBestV0Rot.x());
-//            vertPy.fill(pBestV0Rot.y());
-//            vertPz.fill(pBestV0Rot.z());
-//            vertU.fill(pBestV0Rot.x() / pBestV0Rot.magnitude());
-//            vertV.fill(pBestV0Rot.y() / pBestV0Rot.magnitude());
+            vertPx.fill(pBestV0Rot.x());
+            vertPy.fill(pBestV0Rot.y());
+            vertPz.fill(pBestV0Rot.z());
+            vertU.fill(pBestV0Rot.x() / pBestV0Rot.magnitude());
+            vertV.fill(pBestV0Rot.y() / pBestV0Rot.magnitude());
             vertXY.fill(v0Vtx.x(), v0Vtx.y());
             vertZY.fill(v0Vtx.y(), v0Vtx.z());
-            if (bestCandidate.getMomentum().magnitude() > radCut * ebeam) {
-
-                BilliorVertexer vtxFitter = new BilliorVertexer(TrackUtils.getBField(event.getDetector()).y());
-                vtxFitter.setBeamSize(beamSize);
-                List<BilliorTrack> billiorTracks = new ArrayList<BilliorTrack>();
-                billiorTracks.add(new BilliorTrack(electron.getTracks().get(0)));
-                billiorTracks.add(new BilliorTrack(positron.getTracks().get(0)));
-                vtxFitter.doBeamSpotConstraint(true);
-                BilliorVertex bsconVertex = vtxFitter.fitVertex(billiorTracks);
-                vtxFitter.doTargetConstraint(true);
-                BilliorVertex tarconVertex = vtxFitter.fitVertex(billiorTracks);
-                vertRadUnconBsconChi2.fill(unconVertex.getChi2(), bsconVertex.getChi2());
-
-                vertRadTrackTime2D.fill(tEle, tPos);
-                vertRadTrackTimeDiff.fill(tEle - tPos);
-                vertRadZVsMomentum.fill(bestCandidate.getMomentum().magnitude(), v0Vtx.z());
-                vertRadMassMomentum.fill(bestCandidate.getMomentum().magnitude(), bestCandidate.getMass());
-                vertRadTrackMomentum2D.fill(electron.getMomentum().magnitude(), positron.getMomentum().magnitude());
-                vertRadPyEleVsPyPos.fill(pEleRot.y(), pPosRot.y());
-                vertRadPxEleVsPxPos.fill(pEleRot.x(), pPosRot.x());
-                vertRadSumP.fill(bestCandidate.getMomentum().magnitude());
-                vertRadDeltaP.fill(positron.getMomentum().magnitude() - electron.getMomentum().magnitude());
-
-                vertRadPxPy.fill(pBestV0Rot.x(), pBestV0Rot.y());
-                vertRadMass.fill(bestCandidate.getMass());
-                vertRadZVsMass.fill(bestCandidate.getMass(), v0Vtx.z());
-                vertRadX.fill(v0Vtx.x());
-                vertRadY.fill(v0Vtx.y());
-                vertRadZ.fill(v0Vtx.z());
-                vertRadPx.fill(pBestV0Rot.x());
-                vertRadPy.fill(pBestV0Rot.y());
-                vertRadPz.fill(pBestV0Rot.z());
-                vertRadU.fill(pBestV0Rot.x() / pBestV0Rot.magnitude());
-                vertRadV.fill(pBestV0Rot.y() / pBestV0Rot.magnitude());
-                vertRadXY.fill(v0Vtx.x(), v0Vtx.y());
-                vertRadZY.fill(v0Vtx.y(), v0Vtx.z());
-            }
-        }
-    }
-
-    @Override
-    // TODO: Change from System.out to use logger instead.
-    public void printDQMData() {
-        System.out.println("TridendMonitoring::printDQMData");
-        for (Entry<String, Double> entry : monitoredQuantityMap.entrySet()) {
-            System.out.println(entry.getKey() + " = " + entry.getValue());
-        }
-        System.out.println("*******************************");
-
-        System.out.println("TridendMonitoring::Tridend Selection Summary: " + (isGBL ? "GBLTrack" : "SeedTrack"));
-
-        System.out.println("\t\t\tTridend Selection Summary");
-        System.out.println("******************************************************************************************");
-        System.out.println(String.format("Number of      V0:\t%8.0f\t%8.6f\t%8.6f\t%8.6f\n", nRecoV0, nRecoV0 / nRecoV0, nRecoV0 / nRecoV0, nRecoV0 / nEvents));
-
-        for (Cut cut : Cut.values()) {
-            if (cut.ordinal() == Cut.firstVertexingCut) {
-                System.out.println("******************************************************************************************");
-                System.out.println("\t\t\tVertex Selection Summary");
-                System.out.println("******************************************************************************************");
-            }
-            System.out.format("%-12s Cuts:\t%8.0f\t%8.6f\t%8.6f\t%8.6f\n", cut.name, nPassCut[cut.ordinal()], nPassCut[cut.ordinal()] / (cut.ordinal() == 0 ? nRecoV0 : nPassCut[cut.ordinal() == 0 ? 0 : (cut.ordinal() - 1)]), nPassCut[cut.ordinal()] / nRecoV0, nPassCut[cut.ordinal()] / nEvents);
-        }
-        System.out.println("******************************************************************************************");
-    }
-
-    /**
-     * Calculate the averages here and fill the map
-     */
-    @Override
-    public void calculateEndOfRunQuantities() {
-
-        IAnalysisFactory analysisFactory = IAnalysisFactory.create();
-        IFitFactory fitFactory = analysisFactory.createFitFactory();
-        IFitter fitter = fitFactory.createFitter("chi2");
-
+        }
     }
 
     @Override
@@ -909,10 +705,4 @@
             LOGGER.info("ALTER TABLE dqm ADD " + fpQuantNames[i] + " double;");
         }
     }
-
-    IFitResult fitVertexPosition(IHistogram1D h1d, IFitter fitter, double[] init, String range
-    ) {
-        return fitter.fit(h1d, "g+p1", init, range);
-    }
-
 }

Modified: java/trunk/analysis/src/main/java/org/hps/analysis/dataquality/TrackingMonitoring.java
 =============================================================================
--- java/trunk/analysis/src/main/java/org/hps/analysis/dataquality/TrackingMonitoring.java	(original)
+++ java/trunk/analysis/src/main/java/org/hps/analysis/dataquality/TrackingMonitoring.java	Tue Apr 19 14:25:49 2016
@@ -373,9 +373,8 @@
         int cntPos = 0;
         int cntTop = 0;
         int cntBot = 0;
-        double ecalFace = 1393.0;//mm
         for (Track trk : tracks) {
-            Hep3Vector trackPosAtEcalFace = TrackUtils.extrapolateTrack(trk, ecalFace);
+            Hep3Vector trackPosAtEcalFace = TrackUtils.getTrackPositionAtEcal(trk);
             double xAtECal = trackPosAtEcalFace.x();
             double yAtECal = trackPosAtEcalFace.y();
             if (yAtECal > 0) {

Modified: java/trunk/analysis/src/main/java/org/hps/analysis/dataquality/TridentMonitoring.java
 =============================================================================
--- java/trunk/analysis/src/main/java/org/hps/analysis/dataquality/TridentMonitoring.java	(original)
+++ java/trunk/analysis/src/main/java/org/hps/analysis/dataquality/TridentMonitoring.java	Tue Apr 19 14:25:49 2016
@@ -14,15 +14,16 @@
 import java.util.List;
 import java.util.Map.Entry;
 import java.util.logging.Logger;
-
 import org.hps.conditions.beam.BeamEnergy.BeamEnergyCollection;
 import org.hps.recon.ecal.cluster.ClusterUtilities;
+import org.hps.recon.particle.HpsReconParticleDriver;
 import org.hps.recon.particle.ReconParticleDriver;
 import org.hps.recon.tracking.TrackType;
 import org.hps.recon.tracking.TrackUtils;
 import org.hps.recon.vertexing.BilliorTrack;
 import org.hps.recon.vertexing.BilliorVertex;
 import org.hps.recon.vertexing.BilliorVertexer;
+import org.lcsim.event.Cluster;
 import org.lcsim.event.EventHeader;
 import org.lcsim.event.ReconstructedParticle;
 import org.lcsim.event.RelationalTable;
@@ -201,7 +202,11 @@
     private IHistogram1D maxTrkChi2;
     private IHistogram2D zVsMaxTrkChi2;
     private IHistogram1D v0Chi2;
+    private IHistogram1D bsconV0Chi2;
     private IHistogram2D zVsV0Chi2;
+    private IHistogram2D zVsBsconV0Chi2;
+    private IHistogram1D v0Chi2Diff;
+    private IHistogram2D zVsV0Chi2Diff;
     private IHistogram1D trackTimeDiff;
     private IHistogram2D zVsTrackTimeDiff;
     private IHistogram1D hitTimeStdDev;
@@ -260,7 +265,12 @@
 
     private double l1IsoMin = 0.5;
 
-    private double[] beamSize = {0.001, 0.130, 0.050}; //rough estimate from harp scans during engineering run production running
+    private final double tupleTrkPCut = 0.9;
+    private final double tupleMaxSumCut = 1.3;
+
+    private final double[] beamSize = {0.001, 0.130, 0.050}; //rough estimate from harp scans during engineering run production running
+    private final double[] beamPos = {0.0, 0.0, 0.0};
+    private final double[] vzcBeamSize = {0.001, 100, 100};
 
 //cluster matching
 //    private boolean reqCluster = false;
@@ -272,6 +282,31 @@
     private float nRecoV0 = 0;
     private final float[] nPassCut = new float[Cut.nCuts];
 
+    public TridentMonitoring() {
+        this.tupleVariables = new String[]{"run/I", "event/I",
+            "nTrk/I", "nPos/I",
+            "uncPX/D", "uncPY/D", "uncPZ/D", "uncP/D",
+            "uncVX/D", "uncVY/D", "uncVZ/D", "uncChisq/D", "uncM/D",
+            "bscPX/D", "bscPY/D", "bscPZ/D", "bscP/D",
+            "bscVX/D", "bscVY/D", "bscVZ/D", "bscChisq/D", "bscM/D",
+            "tarPX/D", "tarPY/D", "tarPZ/D", "tarP/D",
+            "tarVX/D", "tarVY/D", "tarVZ/D", "tarChisq/D", "tarM/D",
+            "vzcPX/D", "vzcPY/D", "vzcPZ/D", "vzcP/D",
+            "vzcVX/D", "vzcVY/D", "vzcVZ/D", "vzcChisq/D", "vzcM/D",
+            "elePX/D", "elePY/D", "elePZ/D", "eleP/D",
+            "eleTrkChisq/D", "eleTrkHits/I", "eleTrkType/I", "eleTrkT/D",
+            "eleTrkD0/D", "eleTrkZ0/D", "eleTrkEcalX/D", "eleTrkEcalY/D",
+            "eleHasL1/B", "eleHasL2/B",
+            "eleMatchChisq/D", "eleClT/D", "eleClE/D", "eleClHits/I",
+            "posPX/D", "posPY/D", "posPZ/D", "posP/D",
+            "posTrkChisq/D", "posTrkHits/I", "posTrkType/I", "posTrkT/D",
+            "posTrkD0/D", "posTrkZ0/D", "posTrkEcalX/D", "posTrkEcalY/D",
+            "posHasL1/B", "posHasL2/B",
+            "posMatchChisq/D", "posClT/D", "posClE/D", "posClHits/I",
+            "minL1Iso/D"
+        };
+    }
+
     public void setMaxChi2GBLTrack(double maxChi2GBLTrack) {
         this.maxChi2GBLTrack = maxChi2GBLTrack;
     }
@@ -310,6 +345,14 @@
 
     public void setBeamSizeY(double beamSizeY) {
         this.beamSize[2] = beamSizeY;
+    }
+
+    public void setBeamPosX(double beamPosX) {
+        this.beamPos[1] = beamPosX;
+    }
+
+    public void setBeamPosY(double beamPosY) {
+        this.beamPos[2] = beamPosY;
     }
 
     double ebeam;
@@ -319,8 +362,8 @@
         LOGGER.info("TridendMonitoring::detectorChanged  Setting up the plotter");
         beamAxisRotation.setActiveEuler(Math.PI / 2, -0.0305, -Math.PI / 2);
 
-        BeamEnergyCollection beamEnergyCollection = 
-            this.getConditionsManager().getCachedConditions(BeamEnergyCollection.class, "beam_energies").getCachedData();        
+        BeamEnergyCollection beamEnergyCollection
+                = this.getConditionsManager().getCachedConditions(BeamEnergyCollection.class, "beam_energies").getCachedData();
         ebeam = beamEnergyCollection.get(0).getBeamEnergy();
         aida.tree().cd("/");
         String trkType = "SeedTrack/";
@@ -451,6 +494,10 @@
 
         v0Chi2 = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Cut: V0 Chi2", 50, 0.0, 25.0);
         zVsV0Chi2 = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Cut: Vz vs V0 Chi2", 50, 0.0, 25.0, 50, -v0VzMax, v0VzMax);
+        bsconV0Chi2 = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Cut: Bscon V0 Chi2", 50, 0.0, 25.0);
+        zVsBsconV0Chi2 = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Cut: Vz vs Bscon V0 Chi2", 50, 0.0, 25.0, 50, -v0VzMax, v0VzMax);
+        v0Chi2Diff = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Cut: Bscon-Uncon V0 Chi2 Diff", 50, 0.0, 25.0);
+        zVsV0Chi2Diff = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Cut: Vz vs Bscon-Uncon V0 Chi2 Diff", 50, 0.0, 25.0, 50, -v0VzMax, v0VzMax);
 
         trackTimeDiff = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Cut: Trk Time Diff", 50, 0.0, 10.0);
         hitTimeStdDev = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Cut: Hit Time Std Dev", 50, 0.0, 10.0);
@@ -462,8 +509,8 @@
         zVsEventTrkCount = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Cut: Vz vs Num Tracks", 10, 0.5, 10.5, 50, -v0VzMax, v0VzMax);
         zVsEventPosCount = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Cut: Vz vs Num Positrons", 5, 0.5, 5.5, 50, -v0VzMax, v0VzMax);
 
-        l1Iso = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Cut: L1 Isolation", 50, 0.0, 5.0);
-        zVsL1Iso = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Cut: Vz vs L1 Isolation", 50, 0.0, 5.0, 50, -v0VzMax, v0VzMax);
+        l1Iso = aida.histogram1D(plotDir + trkType + triggerType + "/" + "Cut: L1 Isolation", 100, 0.0, 5.0);
+        zVsL1Iso = aida.histogram2D(plotDir + trkType + triggerType + "/" + "Cut: Vz vs L1 Isolation", 100, 0.0, 5.0, 50, -v0VzMax, v0VzMax);
 
         for (Cut cut : Cut.values()) {
             for (int i = 0; i < 2; i++) {
@@ -549,11 +596,9 @@
             if (tracks.size() != 2) {
                 throw new RuntimeException("expected two tracks in vertex, got " + tracks.size());
             }
-            List<Double> trackTimes = new ArrayList<Double>();
             List<Double> hitTimes = new ArrayList<Double>();
             double mean = 0;
             for (Track track : tracks) {
-                trackTimes.add(TrackUtils.getTrackTime(track, hitToStrips, hitToRotated));
                 for (TrackerHit hit : TrackUtils.getStripHits(track, hitToStrips, hitToRotated)) {
                     mean += hit.getTime();
                     hitTimes.add(hit.getTime());
@@ -576,18 +621,144 @@
                 minL1Iso = Math.min(eleL1Iso, posL1Iso);
             }
 
+            double tEle = TrackUtils.getTrackTime(electron.getTracks().get(0), hitToStrips, hitToRotated);
+            double tPos = TrackUtils.getTrackTime(positron.getTracks().get(0), hitToStrips, hitToRotated);
+            Hep3Vector pEleRot = VecOp.mult(beamAxisRotation, electron.getMomentum());
+            Hep3Vector pPosRot = VecOp.mult(beamAxisRotation, positron.getMomentum());
+
+            Hep3Vector eleAtEcal = TrackUtils.getTrackPositionAtEcal(electron.getTracks().get(0));
+            Hep3Vector posAtEcal = TrackUtils.getTrackPositionAtEcal(positron.getTracks().get(0));
+
             BilliorVertexer vtxFitter = new BilliorVertexer(TrackUtils.getBField(event.getDetector()).y());
             vtxFitter.setBeamSize(beamSize);
+            vtxFitter.setBeamPosition(beamPos);
             List<BilliorTrack> billiorTracks = new ArrayList<BilliorTrack>();
             billiorTracks.add(new BilliorTrack(electron.getTracks().get(0)));
             billiorTracks.add(new BilliorTrack(positron.getTracks().get(0)));
+
             vtxFitter.doBeamSpotConstraint(true);
             BilliorVertex bsconVertex = vtxFitter.fitVertex(billiorTracks);
+            ReconstructedParticle bscV0 = HpsReconParticleDriver.makeReconstructedParticle(electron, positron, bsconVertex);
+            Hep3Vector bscMomRot = VecOp.mult(beamAxisRotation, bscV0.getMomentum());
+            Hep3Vector bscVtx = VecOp.mult(beamAxisRotation, bscV0.getStartVertex().getPosition());
+
+            vtxFitter.doTargetConstraint(true);
+            BilliorVertex tarVertex = vtxFitter.fitVertex(billiorTracks);
+            ReconstructedParticle tarV0 = HpsReconParticleDriver.makeReconstructedParticle(electron, positron, tarVertex);
+            Hep3Vector tarMomRot = VecOp.mult(beamAxisRotation, tarV0.getMomentum());
+            Hep3Vector tarVtx = VecOp.mult(beamAxisRotation, tarV0.getStartVertex().getPosition());
+
+            vtxFitter.setBeamSize(vzcBeamSize);
+            vtxFitter.doTargetConstraint(true);
+            BilliorVertex vzcVertex = vtxFitter.fitVertex(billiorTracks);
+            ReconstructedParticle vzcV0 = HpsReconParticleDriver.makeReconstructedParticle(electron, positron, vzcVertex);
+            Hep3Vector vzcMomRot = VecOp.mult(beamAxisRotation, vzcV0.getMomentum());
+            Hep3Vector vzcVtx = VecOp.mult(beamAxisRotation, vzcV0.getStartVertex().getPosition());
+
+            if (tupleWriter != null) {
+                boolean trkCut = electron.getMomentum().magnitude() < tupleTrkPCut * ebeam && positron.getMomentum().magnitude() < tupleTrkPCut * ebeam;
+                boolean sumCut = electron.getMomentum().magnitude() + positron.getMomentum().magnitude() < tupleMaxSumCut * ebeam;
+                if (!cutTuple || (trkCut && sumCut)) {
+
+                    tupleMap.put("run/I", (double) event.getRunNumber());
+                    tupleMap.put("event/I", (double) event.getEventNumber());
+
+                    tupleMap.put("uncPX/D", v0MomRot.x());
+                    tupleMap.put("uncPY/D", v0MomRot.y());
+                    tupleMap.put("uncPZ/D", v0MomRot.z());
+                    tupleMap.put("uncP/D", v0MomRot.magnitude());
+                    tupleMap.put("uncVX/D", v0Vtx.x());
+                    tupleMap.put("uncVY/D", v0Vtx.y());
+                    tupleMap.put("uncVZ/D", v0Vtx.z());
+                    tupleMap.put("uncChisq/D", uncV0.getStartVertex().getChi2());
+                    tupleMap.put("uncM/D", uncV0.getMass());
+
+                    tupleMap.put("bscPX/D", bscMomRot.x());
+                    tupleMap.put("bscPY/D", bscMomRot.y());
+                    tupleMap.put("bscPZ/D", bscMomRot.z());
+                    tupleMap.put("bscP/D", bscMomRot.magnitude());
+                    tupleMap.put("bscVX/D", bscVtx.x());
+                    tupleMap.put("bscVY/D", bscVtx.y());
+                    tupleMap.put("bscVZ/D", bscVtx.z());
+                    tupleMap.put("bscChisq/D", bscV0.getStartVertex().getChi2());
+                    tupleMap.put("bscM/D", bscV0.getMass());
+
+                    tupleMap.put("tarPX/D", tarMomRot.x());
+                    tupleMap.put("tarPY/D", tarMomRot.y());
+                    tupleMap.put("tarPZ/D", tarMomRot.z());
+                    tupleMap.put("tarP/D", tarMomRot.magnitude());
+                    tupleMap.put("tarVX/D", tarVtx.x());
+                    tupleMap.put("tarVY/D", tarVtx.y());
+                    tupleMap.put("tarVZ/D", tarVtx.z());
+                    tupleMap.put("tarChisq/D", tarV0.getStartVertex().getChi2());
+                    tupleMap.put("tarM/D", tarV0.getMass());
+
+                    tupleMap.put("vzcPX/D", vzcMomRot.x());
+                    tupleMap.put("vzcPY/D", vzcMomRot.y());
+                    tupleMap.put("vzcPZ/D", vzcMomRot.z());
+                    tupleMap.put("vzcP/D", vzcMomRot.magnitude());
+                    tupleMap.put("vzcVX/D", vzcVtx.x());
+                    tupleMap.put("vzcVY/D", vzcVtx.y());
+                    tupleMap.put("vzcVZ/D", vzcVtx.z());
+                    tupleMap.put("vzcChisq/D", vzcV0.getStartVertex().getChi2());
+                    tupleMap.put("vzcM/D", vzcV0.getMass());
+
+                    tupleMap.put("elePX/D", pEleRot.x());
+                    tupleMap.put("elePY/D", pEleRot.y());
+                    tupleMap.put("elePZ/D", pEleRot.z());
+                    tupleMap.put("eleP/D", pEleRot.magnitude());
+                    tupleMap.put("eleTrkD0/D", electron.getTracks().get(0).getTrackStates().get(0).getD0());
+                    tupleMap.put("eleTrkZ0/D", electron.getTracks().get(0).getTrackStates().get(0).getZ0());
+                    tupleMap.put("eleTrkEcalX/D", eleAtEcal.x());
+                    tupleMap.put("eleTrkEcalY/D", eleAtEcal.y());
+                    tupleMap.put("eleTrkChisq/D", electron.getTracks().get(0).getChi2());
+                    tupleMap.put("eleTrkHits/I", (double) electron.getTracks().get(0).getTrackerHits().size());
+                    tupleMap.put("eleTrkType/I", (double) electron.getType());
+                    tupleMap.put("eleTrkT/D", tEle);
+                    tupleMap.put("eleHasL1/B", eleIso[0] != null ? 1.0 : 0.0);
+                    tupleMap.put("eleHasL2/B", eleIso[2] != null ? 1.0 : 0.0);
+                    tupleMap.put("eleMatchChisq/D", electron.getGoodnessOfPID());
+                    if (!electron.getClusters().isEmpty()) {
+                        Cluster eleC = electron.getClusters().get(0);
+                        tupleMap.put("eleClT/D", ClusterUtilities.getSeedHitTime(eleC));
+                        tupleMap.put("eleClE/D", eleC.getEnergy());
+                        tupleMap.put("eleClHits/I", (double) eleC.getCalorimeterHits().size());
+                    }
+
+                    tupleMap.put("posPX/D", pPosRot.x());
+                    tupleMap.put("posPY/D", pPosRot.y());
+                    tupleMap.put("posPZ/D", pPosRot.z());
+                    tupleMap.put("posP/D", pPosRot.magnitude());
+                    tupleMap.put("posTrkD0/D", positron.getTracks().get(0).getTrackStates().get(0).getD0());
+                    tupleMap.put("posTrkZ0/D", positron.getTracks().get(0).getTrackStates().get(0).getZ0());
+                    tupleMap.put("posTrkEcalX/D", posAtEcal.x());
+                    tupleMap.put("posTrkEcalY/D", posAtEcal.y());
+                    tupleMap.put("posTrkChisq/D", positron.getTracks().get(0).getChi2());
+                    tupleMap.put("posTrkHits/I", (double) positron.getTracks().get(0).getTrackerHits().size());
+                    tupleMap.put("posTrkType/I", (double) positron.getType());
+                    tupleMap.put("posTrkT/D", tPos);
+                    tupleMap.put("posHasL1/B", posIso[0] != null ? 1.0 : 0.0);
+                    tupleMap.put("posHasL2/B", posIso[2] != null ? 1.0 : 0.0);
+                    tupleMap.put("posMatchChisq/D", positron.getGoodnessOfPID());
+                    if (!positron.getClusters().isEmpty()) {
+                        Cluster posC = positron.getClusters().get(0);
+                        tupleMap.put("posClT/D", ClusterUtilities.getSeedHitTime(posC));
+                        tupleMap.put("posClE/D", posC.getEnergy());
+                        tupleMap.put("posClHits/I", (double) posC.getCalorimeterHits().size());
+                    }
+
+                    tupleMap.put("minL1Iso/D", minL1Iso);
+
+                    tupleMap.put("nTrk/I", (double) ntrk);
+                    tupleMap.put("nPos/I", (double) npos);
+                    writeTuple();
+                }
+            }
 
             //start applying cuts
             EnumSet<Cut> bits = EnumSet.noneOf(Cut.class);
 
-            boolean trackQualityCut = Math.max(tracks.get(0).getChi2(), tracks.get(1).getChi2()) < (isGBL ? maxChi2GBLTrack : maxChi2SeedTrack);
+            boolean trackQualityCut = Math.max(electron.getTracks().get(0).getChi2(), positron.getTracks().get(0).getChi2()) < (isGBL ? maxChi2GBLTrack : maxChi2SeedTrack);
             if (trackQualityCut) {
                 bits.add(Cut.TRK_QUALITY);
             }
@@ -598,12 +769,12 @@
             }
 
             boolean vertexMomentumCut = v0MomRot.z() < v0PzMaxCut * ebeam && v0MomRot.z() > v0PzMinCut * ebeam && Math.abs(v0MomRot.x()) < v0PxCut * ebeam && Math.abs(v0MomRot.y()) < v0PyCut * ebeam;
-            boolean vertexPositionCut = Math.abs(v0Vtx.x()) < v0UnconVxCut && Math.abs(v0Vtx.y()) < v0UnconVyCut && Math.abs(v0Vtx.z()) < v0UnconVzCut && Math.abs(bsconVertex.getPosition().x()) < v0BsconVxCut && Math.abs(bsconVertex.getPosition().y()) < v0BsconVyCut;
+            boolean vertexPositionCut = Math.abs(v0Vtx.x()) < v0UnconVxCut && Math.abs(v0Vtx.y()) < v0UnconVyCut && Math.abs(v0Vtx.z()) < v0UnconVzCut && Math.abs(bscVtx.x()) < v0BsconVxCut && Math.abs(bscVtx.y()) < v0BsconVyCut;
             if (vertexMomentumCut && vertexPositionCut) {
                 bits.add(Cut.VERTEX_CUTS);
             }
 
-            boolean trackTimeDiffCut = Math.abs(trackTimes.get(0) - trackTimes.get(1)) < trkTimeDiff;
+            boolean trackTimeDiffCut = Math.abs(tEle - tPos) < trkTimeDiff;
             if (trackTimeDiffCut) {
                 bits.add(Cut.TIMING);
             }
@@ -653,7 +824,7 @@
                 EnumSet<Cut> allButThisCut = EnumSet.allOf(Cut.class);
                 allButThisCut.remove(cut);
                 if (bits.containsAll(allButThisCut)) {
-                    if (uncV0.getMass() > plotsMinMass * ebeam && uncV0.getMass() < plotsMaxMass * ebeam) {
+                    if (uncV0.getMass() > plotsMinMass * ebeam && uncV0.getMass() < plotsMaxMass * ebeam && uncV0.getMomentum().magnitude() > radCut * ebeam) {
                         switch (cut) {
                             case ISOLATION:
                                 l1Iso.fill(minL1Iso);
@@ -666,14 +837,18 @@
                                 zVsEventPosCount.fill(npos, v0Vtx.z());
                                 break;
                             case TIMING:
-                                trackTimeDiff.fill(Math.abs(trackTimes.get(0) - trackTimes.get(1)));
+                                trackTimeDiff.fill(Math.abs(tEle - tPos));
                                 hitTimeStdDev.fill(stdDev);
-                                zVsTrackTimeDiff.fill(Math.abs(trackTimes.get(0) - trackTimes.get(1)), v0Vtx.z());
+                                zVsTrackTimeDiff.fill(Math.abs(tEle - tPos), v0Vtx.z());
                                 zVsHitTimeStdDev.fill(stdDev, v0Vtx.z());
                                 break;
                             case VTX_QUALITY:
                                 v0Chi2.fill(uncVert.getChi2());
                                 zVsV0Chi2.fill(uncVert.getChi2(), v0Vtx.z());
+                                bsconV0Chi2.fill(bsconVertex.getChi2());
+                                zVsBsconV0Chi2.fill(bsconVertex.getChi2(), v0Vtx.z());
+                                v0Chi2Diff.fill(bsconVertex.getChi2() - uncVert.getChi2());
+                                zVsV0Chi2Diff.fill(bsconVertex.getChi2() - uncVert.getChi2(), v0Vtx.z());
                                 break;
                             case TRK_QUALITY:
                                 maxTrkChi2.fill(Math.max(tracks.get(0).getChi2(), tracks.get(1).getChi2()));
@@ -828,6 +1003,8 @@
 
                 BilliorVertexer vtxFitter = new BilliorVertexer(TrackUtils.getBField(event.getDetector()).y());
                 vtxFitter.setBeamSize(beamSize);
+                vtxFitter.setBeamPosition(beamPos);
+//                vtxFitter.setDebug(false);
                 List<BilliorTrack> billiorTracks = new ArrayList<BilliorTrack>();
                 billiorTracks.add(new BilliorTrack(electron.getTracks().get(0)));
                 billiorTracks.add(new BilliorTrack(positron.getTracks().get(0)));