Print

Print


Author: [log in to unmask]
Date: Tue Sep 27 08:50:14 2016
New Revision: 4501

Log:
Adding working copy of a DAQConfigDriver that can read runtime settings from the database.

Added:
    java/trunk/users/src/main/java/org/hps/users/kmccarty/DatabaseDAQConfigDriver.java   (with props)
Modified:
    java/trunk/users/src/main/java/org/hps/users/kmccarty/HPSEcalDataPlotsDriver.java
    java/trunk/users/src/main/java/org/hps/users/kmccarty/TriggerProcessAnalysisDriver.java
    java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/FormattedPlot.java
    java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/FormattedPlot1D.java
    java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/FormattedPlot2D.java
    java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/PlotFormatModule.java
    java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/PlotsFormatter.java
    java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/formatter/InvariantMassPlotsFormatter.java
    java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/formatter/MTEPlotFormatter.java
    java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/formatter/MTETriggerPlotsFormatter.java
    java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/formatter/ParticleMCAnalysisPlotsFormatter.java
    java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/formatter/RafoTridentFormatter.java
    java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/formatter/SingleTriggerPlotsFormatter.java
    java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/formatter/TridentTrackFormatter.java
    java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/formatter/TriggerPlotsFormat.java

Added: java/trunk/users/src/main/java/org/hps/users/kmccarty/DatabaseDAQConfigDriver.java
 =============================================================================
--- java/trunk/users/src/main/java/org/hps/users/kmccarty/DatabaseDAQConfigDriver.java	(added)
+++ java/trunk/users/src/main/java/org/hps/users/kmccarty/DatabaseDAQConfigDriver.java	Tue Sep 27 08:50:14 2016
@@ -0,0 +1,79 @@
+package org.hps.users.kmccarty;
+
+import org.hps.record.daqconfig.ConfigurationManager;
+import org.hps.record.daqconfig.DAQConfigDriver;
+import org.hps.record.daqconfig.EvioDAQParser;
+import org.hps.record.triggerbank.TriggerConfigData;
+import org.hps.record.triggerbank.TriggerConfigData.Crate;
+import org.hps.rundb.DaoProvider;
+import org.hps.rundb.RunManager;
+import org.lcsim.event.EventHeader;
+import org.lcsim.geometry.Detector;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.StringReader;
+
+public class DatabaseDAQConfigDriver extends DAQConfigDriver {
+	// Define the crate enumerables by crate number. Crates are
+	// in the order 46, 37, 39.
+	private static final Crate[] CRATES = { Crate.CONFIG3, Crate.CONFIG1, Crate.CONFIG2 };
+	
+	@Override
+	public void detectorChanged(Detector detector) {
+		// Make sure that the run number is defined.
+		if(getRunNumber() == -1) { throw new IllegalArgumentException("Run number is undefined."); }
+		
+		// Get the trigger configuration data.
+		RunManager manager = new RunManager();
+		manager.setRun(getRunNumber());
+		DaoProvider factory = new DaoProvider(manager.getConnection());
+		TriggerConfigData triggerConfig = factory.getTriggerConfigDao().getTriggerConfig(RunManager.getRunManager().getRun());
+		
+		// Convert the trigger configuration text blocks into individual
+		// strings.
+		String[][] data = null;
+		try { data = getDataFileArrays(triggerConfig); }
+		catch(IOException e) {
+			throw new RuntimeException("An error occurred when processing the trigger data.");
+		}
+        
+        // Instantiate an EvIO DAQ parser and feed it the data.
+        EvioDAQParser daqConfig = new EvioDAQParser();
+        for(int i = 0; i < 3; i++) {
+            daqConfig.parse(CRATES[i].getCrateNumber(), getRunNumber(), data[i]);
+        }
+        
+        // Update the configuration manager.
+        ConfigurationManager.updateConfiguration(daqConfig);
+        
+        // Close the manager.
+        manager.closeConnection();
+	}
+	
+	@Override
+	public void process(EventHeader event) { }
+	
+	private static final String[][] getDataFileArrays(TriggerConfigData triggerConfig) throws IOException {
+        // Create file readers to process the data files.
+		StringReader[] fr = new StringReader[3];
+        BufferedReader[] reader = new BufferedReader[3];
+        for(int i = 0; i < 3; i++) {
+        	fr[i] = new StringReader(triggerConfig.getData().get(CRATES[i]));
+            reader[i] = new BufferedReader(fr[i]);
+        }
+		
+		// Convert the crate data into an array of strings. These must
+		// be in the order of 46, 37, 39.
+        String[][] data = getDataFileArrays(reader);
+		
+		// Close the readers.
+		for(int i = 0; i < 3; i++) {
+			reader[i].close();
+			fr[i].close();
+		}
+		
+		// Return the converted data.
+		return data;
+	}
+}

Modified: java/trunk/users/src/main/java/org/hps/users/kmccarty/HPSEcalDataPlotsDriver.java
 =============================================================================
--- java/trunk/users/src/main/java/org/hps/users/kmccarty/HPSEcalDataPlotsDriver.java	(original)
+++ java/trunk/users/src/main/java/org/hps/users/kmccarty/HPSEcalDataPlotsDriver.java	Tue Sep 27 08:50:14 2016
@@ -27,22 +27,23 @@
  * @author Kyle McCarty <[log in to unmask]>
  */
 public class HPSEcalDataPlotsDriver extends Driver {
-    private String plotsGroupName= "Data Plots";
-    private String bankCollectionName = "TriggerBank";
-    private String clusterCollectionName = "EcalClusters";
-    
-    private static final int PULSER   = 0;
-    private static final int SINGLES0 = 1;
-    private static final int SINGLES1 = 2;
-    private static final int PAIR0    = 3;
-    private static final int PAIR1    = 4;
-    
-    private static final int ALL       = 0;
-    private static final int EDGE      = 1;
-    private static final int FIDUCIAL = 2;
-    
-    private AIDA aida = AIDA.defaultInstance();
-    private IHistogram1D[][] clusterTotalEnergy = new IHistogram1D[5][3];
+	private boolean useGoodSVT = false;
+	private String plotsGroupName= "Data Plots";
+	private String bankCollectionName = "TriggerBank";
+	private String clusterCollectionName = "EcalClusters";
+	
+	private static final int PULSER   = 0;
+	private static final int SINGLES0 = 1;
+	private static final int SINGLES1 = 2;
+	private static final int PAIR0    = 3;
+	private static final int PAIR1    = 4;
+	
+	private static final int ALL       = 0;
+	private static final int EDGE      = 1;
+	private static final int FIDUCIAL  = 2;
+	
+	private AIDA aida = AIDA.defaultInstance();
+	private IHistogram1D[][] clusterTotalEnergy = new IHistogram1D[5][3];
     private IHistogram1D[][] clusterTime = new IHistogram1D[5][3];
     private IHistogram1D[][] clusterHitCount = new IHistogram1D[5][3];
     private IHistogram1D[][] clusterSeedEnergy = new IHistogram1D[5][3];
@@ -101,204 +102,228 @@
                 pairCoplanarityEnergySum[i][j] = aida.histogram2D(plotsGroupName + "/" + triggerNames[i] + "/"
                         + positionNames[j] + "/Pair Energy Sum vs. Coplanarity", 150, 0.000, 1.500, 180, 0, 180);
                 pairEnergySlope2D[i][j] = aida.histogram2D(plotsGroupName + "/" + triggerNames[i] + "/"
-                        + positionNames[j] + "/Pair Energy Slope 2D", 75, 0.000, 1.500, 100, 0.0, 400.0);
+                		+ positionNames[j] + "/Pair Energy Slope 2D", 75, 0.000, 1.500, 100, 0.0, 400.0);
+			}
+		}
+	}
+	
+	/**
+	 * Processes the event clusters and populates distribution charts
+	 * from them for each trigger. Also creates separate plots for the
+	 * edge and fiducial regions.
+	 * @param event - The event containing LCIO collections to be used
+	 * for plot population.
+	 */
+	@Override
+	public void process(EventHeader event) {
+		// Check whether the SVT was active in this event.
+		final String[] flagNames = { "svt_bias_good", "svt_burstmode_noise_good", "svt_position_good" };
+		boolean svtGood = true;
+        for(int i = 0; i < flagNames.length; i++) {
+            int[] flag = event.getIntegerParameters().get(flagNames[i]);
+            if(flag == null || flag[0] == 0) {
+                svtGood = false;
             }
         }
-    }
-    
-    /**
-     * Processes the event clusters and populates distribution charts
-     * from them for each trigger. Also creates separate plots for the
-     * edge and fiducial regions.
-     * @param event - The event containing LCIO collections to be used
-     * for plot population.
-     */
-    @Override
-    public void process(EventHeader event) {
-        // Get the TI and SSP banks.
-        TIData tiBank = null;
-        SSPData sspBank = null;
-        if(event.hasCollection(GenericObject.class, bankCollectionName)) {
-            // Get the bank list.
-            List<GenericObject> bankList = event.get(GenericObject.class, bankCollectionName);
-            
-            // Search through the banks and get the SSP and TI banks.
-            for(GenericObject obj : bankList) {
-                // If this is an SSP bank, parse it.
-                if(AbstractIntData.getTag(obj) == SSPData.BANK_TAG) {
-                    sspBank = new SSPData(obj);
-                }
-                
-                // Otherwise, if this is a TI bank, parse it.
-                else if(AbstractIntData.getTag(obj) == TIData.BANK_TAG) {
-                    tiBank = new TIData(obj);
-                }
-            }
-        }
+		
+        // If the SVT is not properly running, skip the event.
+        if(!svtGood && useGoodSVT) { return; }
         
-        // Get the list of clusters.
-        List<Cluster> clusters = null;
-        if(event.hasCollection(Cluster.class, clusterCollectionName)) {
-            clusters = event.get(Cluster.class, clusterCollectionName);
-        }
-        
-        // Require that all collections be initialized.
-        if(sspBank == null || tiBank == null || clusters == null) {
-            return;
-        }
-        
-        // Track which triggers are active.
-        boolean[] activeTrigger = new boolean[5];
-        activeTrigger[PULSER] = tiBank.isPulserTrigger();
-        activeTrigger[SINGLES0] = tiBank.isSingle0Trigger();
-        activeTrigger[SINGLES1] = tiBank.isSingle1Trigger();
-        activeTrigger[PAIR0] = tiBank.isPair0Trigger();
-        activeTrigger[PAIR1] = tiBank.isPair1Trigger();
-        
-        // Plot all cluster properties for each trigger.
-        for(Cluster cluster : clusters) {
-            // Check whether the cluster is a fiducial or edge cluster.
-            int positional = inFiducialRegion(cluster) ? FIDUCIAL : EDGE;
-            
-            // Fill the appropriate plots for each trigger with an
-            // active trigger bit for single clusters.
-            for(int i = 0; i < 5; i++) {
-                if(activeTrigger[i]) {
-                    // Populate the ALL plots.
-                    clusterSeedEnergy[i][ALL].fill(TriggerModule.getValueClusterSeedEnergy(cluster));
-                    clusterTotalEnergy[i][ALL].fill(cluster.getEnergy());
-                    clusterHitCount[i][ALL].fill(TriggerModule.getClusterHitCount(cluster));
-                    clusterTime[i][ALL].fill(TriggerModule.getClusterTime(cluster));
-                    clusterSeedPosition[i][ALL].fill(TriggerModule.getClusterXIndex(cluster),
-                            TriggerModule.getClusterYIndex(cluster));
-                    
-                    // Populate the positional plots.
-                    clusterSeedEnergy[i][positional].fill(TriggerModule.getValueClusterSeedEnergy(cluster));
-                    clusterTotalEnergy[i][positional].fill(cluster.getEnergy());
-                    clusterHitCount[i][positional].fill(TriggerModule.getClusterHitCount(cluster));
-                    clusterTime[i][positional].fill(TriggerModule.getClusterTime(cluster));
-                    clusterSeedPosition[i][positional].fill(TriggerModule.getClusterXIndex(cluster),
-                            TriggerModule.getClusterYIndex(cluster));
-                }
-            }
-        }
-        
-        // Plot all pair properties for each trigger.
-        List<Cluster[]> pairs = TriggerModule.getTopBottomPairs(clusters, Cluster.class);
-        for(Cluster[] pair : pairs) {
-            // Check whether the cluster is a fiducial or edge cluster.
-            boolean[] isFiducial = {
-                    inFiducialRegion(pair[0]),
-                    inFiducialRegion(pair[1])
-            };
-            int positional = (isFiducial[0] && isFiducial[1]) ? FIDUCIAL : EDGE;
-            
-            // Fill the appropriate plots for each trigger with an
-            // active trigger bit for single clusters.
-            for(int i = 0; i < 5; i++) {
-                if(activeTrigger[i]) {
-                    // Calculate the values.
-                    double energySum = TriggerModule.getValueEnergySum(pair);
-                    double energyDiff = TriggerModule.getValueEnergyDifference(pair);
-                    double energySlope = TriggerModule.getValueEnergySlope(pair, 0.00550);
-                    double coplanarity = TriggerModule.getValueCoplanarity(pair);
-                    double timeCoincidence = TriggerModule.getValueTimeCoincidence(pair);
-                    
-                    // Get the energy slope values.
-                    Cluster lowCluster = pair[0].getEnergy() < pair[1].getEnergy() ? pair[0] : pair[1];
-                    double clusterDistance = TriggerModule.getClusterDistance(lowCluster);
-                    
-                    // Populate the ALL plots.
-                    pairEnergySum[i][ALL].fill(energySum);
-                    pairEnergyDifference[i][ALL].fill(energyDiff);
-                    pairEnergySlope[i][ALL].fill(energySlope);
-                    pairCoplanarity[i][ALL].fill(coplanarity);
-                    pairTimeCoincidence[i][ALL].fill(timeCoincidence);
-                    pairEnergySum2D[i][ALL].fill(pair[0].getEnergy(), pair[1].getEnergy());
-                    pairCoplanarityEnergySum[i][ALL].fill(energySum, coplanarity);
-                    pairEnergySlope2D[i][ALL].fill(lowCluster.getEnergy(), clusterDistance);
-                    
-                    // Populate the positional plots.
-                    pairEnergySum[i][positional].fill(energySum);
-                    pairEnergyDifference[i][positional].fill(energyDiff);
-                    pairEnergySlope[i][positional].fill(energySlope);
-                    pairCoplanarity[i][positional].fill(coplanarity);
-                    pairTimeCoincidence[i][positional].fill(timeCoincidence);
-                    pairEnergySum2D[i][positional].fill(pair[0].getEnergy(), pair[1].getEnergy());
-                    pairCoplanarityEnergySum[i][positional].fill(energySum, coplanarity);
-                    pairEnergySlope2D[i][positional].fill(lowCluster.getEnergy(), clusterDistance);
-                }
-            }
-        }
-    }
-    
-    /**
-     * Indicates whether the argument cluster is located in the fiducial
-     * region or not.
-     * @param cluster - The cluster to check.
-     * @return Returns <code>true</code> if the cluster is located in
-     * the fiducial region and <code>false</code> otherwise.
-     */
-    private static final boolean inFiducialRegion(Cluster cluster) {
-        // Get the x and y indices for the cluster.
-        int ix   = TriggerModule.getClusterXIndex(cluster);
-        int absx = Math.abs(TriggerModule.getClusterXIndex(cluster));
-        int absy = Math.abs(TriggerModule.getClusterYIndex(cluster));
-        
-        // Check if the cluster is on the top or the bottom of the
-        // calorimeter, as defined by |y| == 5. This is an edge cluster
-        // and is not in the fiducial region.
-        if(absy == 5) {
-            return false;
-        }
-        
-        // Check if the cluster is on the extreme left or right side
-        // of the calorimeter, as defined by |x| == 23. This is also
-        // and edge cluster is not in the fiducial region.
-        if(absx == 23) {
-            return false;
-        }
-        
-        // Check if the cluster is along the beam gap, as defined by
-        // |y| == 1. This is an internal edge cluster and is not in the
-        // fiducial region.
-        if(absy == 1) {
-            return false;
-        }
-        
-        // Lastly, check if the cluster falls along the beam hole, as
-        // defined by clusters with -11 <= x <= -1 and |y| == 2. This
-        // is not the fiducial region.
-        if(absy == 2 && ix <= -1 && ix >= -11) {
-            return false;
-        }
-        
-        // If all checks fail, the cluster is in the fiducial region.
-        return true;
-    }
-    
-    /**
-     * Sets the name of the LCIO collection containing the clusters
-     * that are to be plotted.
-     * @param collection - The LCIO collection name.
-     */
-    public void setClusterCollectionName(String collection) {
-        clusterCollectionName = collection;
-    }
-    
-    /**
-     * Defines the name of the LCIO collection containing the TI bank.
-     * @param collection - The LCIO collection name.
-     */
-    public void setBankCollectionName(String collection) {
-        bankCollectionName = collection;
-    }
-    
-    /**
-     * Sets the name of the super-group folder containing all plots.
-     * @param name - The name of the plots folder.
-     */
-    public void setPlotsGroupName(String name) {
-        plotsGroupName = name;
-    }
+		// Get the TI and SSP banks.
+		TIData tiBank = null;
+		SSPData sspBank = null;
+		if(event.hasCollection(GenericObject.class, bankCollectionName)) {
+			// Get the bank list.
+			List<GenericObject> bankList = event.get(GenericObject.class, bankCollectionName);
+			
+			// Search through the banks and get the SSP and TI banks.
+			for(GenericObject obj : bankList) {
+				// If this is an SSP bank, parse it.
+				if(AbstractIntData.getTag(obj) == SSPData.BANK_TAG) {
+					sspBank = new SSPData(obj);
+				}
+				
+				// Otherwise, if this is a TI bank, parse it.
+				else if(AbstractIntData.getTag(obj) == TIData.BANK_TAG) {
+					tiBank = new TIData(obj);
+				}
+			}
+		}
+		
+		// Get the list of clusters.
+		List<Cluster> clusters = null;
+		if(event.hasCollection(Cluster.class, clusterCollectionName)) {
+			clusters = event.get(Cluster.class, clusterCollectionName);
+		}
+		
+		// Require that all collections be initialized.
+		if(sspBank == null || tiBank == null || clusters == null) {
+			return;
+		}
+		
+		// Track which triggers are active.
+		boolean[] activeTrigger = new boolean[5];
+		activeTrigger[PULSER] = tiBank.isPulserTrigger();
+		activeTrigger[SINGLES0] = tiBank.isSingle0Trigger();
+		activeTrigger[SINGLES1] = tiBank.isSingle1Trigger();
+		activeTrigger[PAIR0] = tiBank.isPair0Trigger();
+		activeTrigger[PAIR1] = tiBank.isPair1Trigger();
+		
+		// Plot all cluster properties for each trigger.
+		for(Cluster cluster : clusters) {
+			// Check whether the cluster is a fiducial or edge cluster.
+			int positional = inFiducialRegion(cluster) ? FIDUCIAL : EDGE;
+			
+			// Fill the appropriate plots for each trigger with an
+			// active trigger bit for single clusters.
+			for(int i = 0; i < 5; i++) {
+				if(activeTrigger[i]) {
+					// Populate the ALL plots.
+					clusterSeedEnergy[i][ALL].fill(TriggerModule.getValueClusterSeedEnergy(cluster));
+					clusterTotalEnergy[i][ALL].fill(cluster.getEnergy());
+					clusterHitCount[i][ALL].fill(TriggerModule.getClusterHitCount(cluster));
+					clusterTime[i][ALL].fill(TriggerModule.getClusterTime(cluster));
+					clusterSeedPosition[i][ALL].fill(TriggerModule.getClusterXIndex(cluster),
+							TriggerModule.getClusterYIndex(cluster));
+					
+					// Populate the positional plots.
+					clusterSeedEnergy[i][positional].fill(TriggerModule.getValueClusterSeedEnergy(cluster));
+					clusterTotalEnergy[i][positional].fill(cluster.getEnergy());
+					clusterHitCount[i][positional].fill(TriggerModule.getClusterHitCount(cluster));
+					clusterTime[i][positional].fill(TriggerModule.getClusterTime(cluster));
+					clusterSeedPosition[i][positional].fill(TriggerModule.getClusterXIndex(cluster),
+							TriggerModule.getClusterYIndex(cluster));
+				}
+			}
+		}
+		
+		// Plot all pair properties for each trigger.
+		List<Cluster[]> pairs = TriggerModule.getTopBottomPairs(clusters, Cluster.class);
+		for(Cluster[] pair : pairs) {
+			// Check whether the cluster is a fiducial or edge cluster.
+			boolean[] isFiducial = {
+					inFiducialRegion(pair[0]),
+					inFiducialRegion(pair[1])
+			};
+			int positional = (isFiducial[0] && isFiducial[1]) ? FIDUCIAL : EDGE;
+			
+			// Fill the appropriate plots for each trigger with an
+			// active trigger bit for single clusters.
+			for(int i = 0; i < 5; i++) {
+				if(activeTrigger[i]) {
+					// Calculate the values.
+					double energySum = TriggerModule.getValueEnergySum(pair);
+					double energyDiff = TriggerModule.getValueEnergyDifference(pair);
+					double energySlope = TriggerModule.getValueEnergySlope(pair, 0.00550);
+					double coplanarity = TriggerModule.getValueCoplanarity(pair);
+					double timeCoincidence = TriggerModule.getValueTimeCoincidence(pair);
+					
+					// Get the energy slope values.
+					Cluster lowCluster = pair[0].getEnergy() < pair[1].getEnergy() ? pair[0] : pair[1];
+					double clusterDistance = TriggerModule.getClusterDistance(lowCluster);
+					
+					// Populate the ALL plots.
+					pairEnergySum[i][ALL].fill(energySum);
+					pairEnergyDifference[i][ALL].fill(energyDiff);
+					pairEnergySlope[i][ALL].fill(energySlope);
+					pairCoplanarity[i][ALL].fill(coplanarity);
+					pairTimeCoincidence[i][ALL].fill(timeCoincidence);
+					pairEnergySum2D[i][ALL].fill(pair[0].getEnergy(), pair[1].getEnergy());
+					pairCoplanarityEnergySum[i][ALL].fill(energySum, coplanarity);
+					pairEnergySlope2D[i][ALL].fill(lowCluster.getEnergy(), clusterDistance);
+					
+					// Populate the positional plots.
+					pairEnergySum[i][positional].fill(energySum);
+					pairEnergyDifference[i][positional].fill(energyDiff);
+					pairEnergySlope[i][positional].fill(energySlope);
+					pairCoplanarity[i][positional].fill(coplanarity);
+					pairTimeCoincidence[i][positional].fill(timeCoincidence);
+					pairEnergySum2D[i][positional].fill(pair[0].getEnergy(), pair[1].getEnergy());
+					pairCoplanarityEnergySum[i][positional].fill(energySum, coplanarity);
+					pairEnergySlope2D[i][positional].fill(lowCluster.getEnergy(), clusterDistance);
+				}
+			}
+		}
+	}
+	
+	/**
+	 * Indicates whether the argument cluster is located in the fiducial
+	 * region or not.
+	 * @param cluster - The cluster to check.
+	 * @return Returns <code>true</code> if the cluster is located in
+	 * the fiducial region and <code>false</code> otherwise.
+	 */
+	private static final boolean inFiducialRegion(Cluster cluster) {
+		// Get the x and y indices for the cluster.
+		int ix   = TriggerModule.getClusterXIndex(cluster);
+		int absx = Math.abs(TriggerModule.getClusterXIndex(cluster));
+		int absy = Math.abs(TriggerModule.getClusterYIndex(cluster));
+		
+		// Check if the cluster is on the top or the bottom of the
+		// calorimeter, as defined by |y| == 5. This is an edge cluster
+		// and is not in the fiducial region.
+		if(absy == 5) {
+			return false;
+		}
+		
+		// Check if the cluster is on the extreme left or right side
+		// of the calorimeter, as defined by |x| == 23. This is also
+		// and edge cluster is not in the fiducial region.
+		if(absx == 23) {
+			return false;
+		}
+		
+		// Check if the cluster is along the beam gap, as defined by
+		// |y| == 1. This is an internal edge cluster and is not in the
+		// fiducial region.
+		if(absy == 1) {
+			return false;
+		}
+		
+		// Lastly, check if the cluster falls along the beam hole, as
+		// defined by clusters with -11 <= x <= -1 and |y| == 2. This
+		// is not the fiducial region.
+		if(absy == 2 && ix <= -1 && ix >= -11) {
+			return false;
+		}
+		
+		// If all checks fail, the cluster is in the fiducial region.
+		return true;
+	}
+	
+	/**
+	 * Sets the name of the LCIO collection containing the clusters
+	 * that are to be plotted.
+	 * @param collection - The LCIO collection name.
+	 */
+	public void setClusterCollectionName(String collection) {
+		clusterCollectionName = collection;
+	}
+	
+	/**
+	 * Defines the name of the LCIO collection containing the TI bank.
+	 * @param collection - The LCIO collection name.
+	 */
+	public void setBankCollectionName(String collection) {
+		bankCollectionName = collection;
+	}
+	
+	/**
+	 * Sets the name of the super-group folder containing all plots.
+	 * @param name - The name of the plots folder.
+	 */
+	public void setPlotsGroupName(String name) {
+		plotsGroupName = name;
+	}
+	
+	/**
+	 * Sets whether or not to skip events where the SVT was not in
+	 * position and active.
+	 * @param state - <code>true</code> indicates that only events
+	 * with an active, properly positioned SVT should be analyzed, and
+	 * <code>false</code> that all events will be included.
+	 */
+	public void setUseGoodSVT(boolean state) {
+		useGoodSVT = state;
+	}
 }

Modified: java/trunk/users/src/main/java/org/hps/users/kmccarty/TriggerProcessAnalysisDriver.java
 =============================================================================
--- java/trunk/users/src/main/java/org/hps/users/kmccarty/TriggerProcessAnalysisDriver.java	(original)
+++ java/trunk/users/src/main/java/org/hps/users/kmccarty/TriggerProcessAnalysisDriver.java	Tue Sep 27 08:50:14 2016
@@ -9,11 +9,18 @@
 import java.util.List;
 import java.util.Set;
 
+import org.hps.analysis.trigger.SimTriggerData;
+import org.hps.analysis.trigger.data.TriggerDiagStats;
+import org.hps.analysis.trigger.util.OutputLogger;
 import org.hps.recon.tracking.TrackType;
 import org.hps.recon.tracking.TrackUtils;
+import org.hps.record.triggerbank.AbstractIntData;
+import org.hps.record.triggerbank.SSPData;
+import org.hps.record.triggerbank.TIData;
 import org.hps.record.triggerbank.TriggerModule;
 import org.lcsim.event.Cluster;
 import org.lcsim.event.EventHeader;
+import org.lcsim.event.GenericObject;
 import org.lcsim.event.ReconstructedParticle;
 import org.lcsim.event.RelationalTable;
 import org.lcsim.event.Track;
@@ -21,78 +28,245 @@
 import org.lcsim.util.aida.AIDA;
 
 public class TriggerProcessAnalysisDriver extends Driver {
-    private int eventsProcessed = 0;
-    private int mollersProcessed = 0; 
-    private boolean checkSVT = false;
-    private int tridentsProcessed = 0;
-    private int gblMollersProcessed = 0;
-    private int gblTridentsProcessed = 0;
-    private double timeCoincidence = 2.5;
-    private double elasticThreshold = 0.800;
-    private double mollerLowerRange = 0.900;
-    private double mollerUpperRange = 1.200;
-    private AIDA aida = AIDA.defaultInstance();
-    private boolean checkTriggerTimeWindow = false;
-    private String clusterCollectionName = "EcalClustersCorr";
-    private String particleCollectionName = "FinalStateParticles";
-    
-    // Define trident cluster-track matched condition plots.
-    private IHistogram1D trctmInvariantMass = aida.histogram1D("Tridents CTMatched/Invariant Mass", 140, 0.0, 0.070);
-    private IHistogram1D trctmInstancesInEvent = aida.histogram1D("Tridents CTMatched/Instances in Event", 9, 0.5, 9.5);
-    private IHistogram1D trctmEnergySum1D = aida.histogram1D("Tridents CTMatched/Cluster Energy Sum", 150, 0.000, 1.500);
-    private IHistogram1D trctmMomentumSum1D = aida.histogram1D("Tridents CTMatched/Track Momentum Sum", 150, 0.000, 1.500);
-    private IHistogram1D trctmElectronEnergy = aida.histogram1D("Tridents CTMatched/Electron Cluster Energy", 150, 0.000, 1.500);
-    private IHistogram1D trctmElectronMomentum = aida.histogram1D("Tridents CTMatched/Electron Track Momentum", 150, 0.000, 1.500);
-    private IHistogram1D trctmPositronEnergy = aida.histogram1D("Tridents CTMatched/Positron Cluster Energy", 150, 0.000, 1.500);
-    private IHistogram1D trctmPositronMomentum = aida.histogram1D("Tridents CTMatched/Positron Track Momentum", 150, 0.000, 1.500);
-    private IHistogram1D trctmTimeCoincidence = aida.histogram1D("Tridents CTMatched/Time Coincidence", 100, -4, 4);
-    private IHistogram2D trctmClusterPosition = aida.histogram2D("Tridents CTMatched/Cluster Seed Position", 46, -23, 23, 11, -5.5, 5.5);
-    private IHistogram2D trctmEnergySum2D = aida.histogram2D("Tridents CTMatched/Cluster Energy Sum 2D", 300, 0.000, 1.500, 300, 0.000, 1.500);
-    private IHistogram2D trctmTrackPosition = aida.histogram2D("Tridents CTMatched/Extrapolated Track Position", 200, -400, 400, 55, -110, 110);
-    private IHistogram2D trctmMomentumSum2D = aida.histogram2D("Tridents CTMatched/Track Momentum Sum 2D", 300, 0.000, 1.500, 300, 0.000, 1.500);
-    private IHistogram2D trctmESumCoplanarity = aida.histogram2D("Tridents CTMatched/Cluster Energy Sum vs. Coplanarity", 300, 0.000, 1.500, 360, 0, 360);
-    private IHistogram2D trctmPSumCoplanarity = aida.histogram2D("Tridents CTMatched/Track Momentum Sum vs. Coplanarity", 300, 0.000, 1.500, 360, 0, 360);
-    
-    // Define the Moller cluster-track matched condition plots.
-    private IHistogram1D moctmInvariantMass = aida.histogram1D("Moller CTMatched/Invariant Mass", 140, 0.0, 0.070);
-    private IHistogram1D moctmInstancesInEvent = aida.histogram1D("Moller CTMatched/Instances in Event", 9, 0.5, 9.5);
-    private IHistogram1D moctmEnergySum1D = aida.histogram1D("Moller CTMatched/Cluster Energy Sum", 150, 0.000, 1.500);
-    private IHistogram1D moctmMomentumSum1D = aida.histogram1D("Moller CTMatched/Track Momentum Sum", 150, 0.000, 1.500);
-    private IHistogram1D moctmElectronEnergy = aida.histogram1D("Moller CTMatched/Electron Cluster Energy", 150, 0.000, 1.500);
-    private IHistogram1D moctmElectronMomentum = aida.histogram1D("Moller CTMatched/Electron Track Momentum", 150, 0.000, 1.500);
-    private IHistogram1D moctmTimeCoincidence = aida.histogram1D("Moller CTMatched/Time Coincidence", 100, -4, 4);
-    private IHistogram2D moctmClusterPosition = aida.histogram2D("Moller CTMatched/Cluster Seed Position", 46, -23, 23, 11, -5.5, 5.5);
-    private IHistogram2D moctmEnergySum2D = aida.histogram2D("Moller CTMatched/Cluster Energy Sum 2D", 300, 0.000, 1.500, 300, 0.000, 1.500);
-    private IHistogram2D moctmTrackPosition = aida.histogram2D("Moller CTMatched/Extrapolated Track Position", 200, -400, 400, 55, -110, 110);
-    private IHistogram2D moctmMomentumSum2D = aida.histogram2D("Moller CTMatched/Track Momentum Sum 2D", 300, 0.000, 1.500, 300, 0.000, 1.500);
-    private IHistogram2D moctmESumCoplanarity = aida.histogram2D("Moller CTMatched/Cluster Energy Sum vs. Coplanarity", 300, 0.000, 1.500, 360, 0, 360);
-    private IHistogram2D moctmPSumCoplanarity = aida.histogram2D("Moller CTMatched/Track Momentum Sum vs. Coplanarity", 300, 0.000, 1.500, 360, 0, 360);
-    
-    // Define the Moller track-only condition plots.
-    private IHistogram1D mogblTimeCoincidence = aida.histogram1D("Moller Track-Only/Time Coincidence", 100, -4, 4);
-    private IHistogram1D mogblInvariantMass = aida.histogram1D("Moller Track-Only/Invariant Mass", 140, 0.0, 0.070);
-    private IHistogram1D mogblInstancesInEvent = aida.histogram1D("Moller Track-Only/Instances in Event", 9, 0.5, 9.5);
-    private IHistogram1D mogblMomentumSum1D = aida.histogram1D("Moller Track-Only/Track Momentum Sum", 150, 0.000, 1.500);
-    private IHistogram1D mogblElectronMomentum = aida.histogram1D("Moller Track-Only/Electron Track Momentum", 150, 0.000, 1.500);
-    private IHistogram2D mogblTrackPosition = aida.histogram2D("Moller Track-Only/Extrapolated Track Position", 200, -400, 400, 55, -110, 110);
-    private IHistogram2D mogblMomentumSum2D = aida.histogram2D("Moller Track-Only/Track Momentum Sum 2D", 300, 0.000, 1.500, 300, 0.000, 1.500);
-    private IHistogram2D mogblPSumCoplanarity = aida.histogram2D("Moller Track-Only/Track Momentum Sum vs. Coplanarity", 300, 0.000, 1.500, 360, 0, 360);
-    
-    // Define the GBL trident condition plots.
-    private IHistogram1D trgblInvariantMass = aida.histogram1D("Tridents Track-Only/Invariant Mass", 140, 0.0, 0.070);
-    private IHistogram1D trgblInstancesInEvent = aida.histogram1D("Tridents Track-Only/Instances in Event", 9, 0.5, 9.5);
-    private IHistogram1D trgblMomentumSum1D = aida.histogram1D("Tridents Track-Only/Track Momentum Sum", 150, 0.000, 1.500);
-    private IHistogram1D trgblElectronMomentum = aida.histogram1D("Tridents Track-Only/Electron Track Momentum", 150, 0.000, 1.500);
-    private IHistogram1D trgblPositronMomentum = aida.histogram1D("Tridents Track-Only/Positron Track Momentum", 150, 0.000, 1.500);
-    private IHistogram1D trgblTimeCoincidence = aida.histogram1D("Tridents Track-Only/Time Coincidence", 100, -4, 4);
-    private IHistogram2D trgblTrackPosition = aida.histogram2D("Tridents Track-Only/Extrapolated Track Position", 200, -400, 400, 55, -110, 110);
-    private IHistogram2D trgblMomentumSum2D = aida.histogram2D("Tridents Track-Only/Track Momentum Sum 2D", 300, 0.000, 1.500, 300, 0.000, 1.500);
-    private IHistogram2D trgblPSumCoplanarity = aida.histogram2D("Tridents Track-Only/Track Momentum Sum vs. Coplanarity", 300, 0.000, 1.500, 360, 0, 360);
-    
-    @Override
-    public void endOfData() {
-        // Calculate the scaling factor for Hertz.
-        double scale = 19000.0 / eventsProcessed;
+	private int eventsProcessed = 0;
+	private int møllersProcessed = 0;
+	private boolean checkSVT = false;
+	private int tridentsProcessed = 0;
+	private int gblMøllersProcessed = 0;
+	private int gblTridentsProcessed = 0;
+	private int vertexedMøllersProcessed = 0;
+	private int vertexedTridentsProcessed = 0;
+	private double timeCoincidence = 2.5;
+	private double elasticThreshold = 0.900;
+	private double møllerLowerRange = 0.800;
+	private double møllerUpperRange = 1.300;
+	private AIDA aida = AIDA.defaultInstance();
+	private boolean checkTriggerTimeWindow = false;
+	private String bankCollectionName = "TriggerBank";
+	private String clusterCollectionName = "EcalClustersCorr";
+	private String particleCollectionName = "FinalStateParticles";
+	private String møllerCollectionName = "UnconstrainedMollerCandidates";
+	private String tridentCollectionName = "TargetConstrainedV0Candidates";
+	
+	// Track how many events pass each trigger configuration.
+	private int triggerActiveEvents = 0;
+	private int[][][][][] ctmTriggerMøllers = new int[2][2][2][2][2];
+	private int[][][][][] vtxTriggerMøllers = new int[2][2][2][2][2];
+	private int[][][][][] ctmTriggerTridents = new int[2][2][2][2][2];
+	private int[][][][][] vtxTriggerTridents = new int[2][2][2][2][2];
+	
+	// Define Møller cut constants.
+	/*
+	private static final int LOW = 0;
+	private static final int HIGH = 1;
+	private static final double[] MØLLER_ANGLE_THRESHOLD = {
+			(1 - 0.40) * 0.5109989 / (2 * 1056),
+			(1 + 0.40) * 0.5109989 / (2 * 1056)
+	};
+	private static final double[] MØLLER_ENERGY_THRESHOLD = {
+			(1 - 0.15) * 1.056,
+			(1 + 0.15) * 1.056
+	};
+	private static final double BEAM_ROTATION = -0.0305;
+	private static final double ELECTRON_MASS_2 = 0.0005109989 * 0.0005109989;
+	*/
+	
+	// Define trident cluster-track matched condition plots.
+	private IHistogram1D trctmInvariantMass = aida.histogram1D("Tridents CTMatched/Invariant Mass", 140, 0.0, 0.070);
+	private IHistogram1D trctmInstancesInEvent = aida.histogram1D("Tridents CTMatched/Instances in Event", 9, 0.5, 9.5);
+	private IHistogram1D trctmEnergySum1D = aida.histogram1D("Tridents CTMatched/Cluster Energy Sum", 150, 0.000, 1.500);
+	private IHistogram1D trctmMomentumSum1D = aida.histogram1D("Tridents CTMatched/Track Momentum Sum", 150, 0.000, 1.500);
+	private IHistogram1D trctmElectronEnergy = aida.histogram1D("Tridents CTMatched/Electron Cluster Energy", 150, 0.000, 1.500);
+	private IHistogram1D trctmElectronMomentum = aida.histogram1D("Tridents CTMatched/Electron Track Momentum", 150, 0.000, 1.500);
+	private IHistogram1D trctmPositronEnergy = aida.histogram1D("Tridents CTMatched/Positron Cluster Energy", 150, 0.000, 1.500);
+	private IHistogram1D trctmPositronMomentum = aida.histogram1D("Tridents CTMatched/Positron Track Momentum", 150, 0.000, 1.500);
+	private IHistogram1D trctmTimeCoincidence = aida.histogram1D("Tridents CTMatched/Time Coincidence", 100, -4, 4);
+	private IHistogram2D trctmClusterPosition = aida.histogram2D("Tridents CTMatched/Cluster Seed Position", 46, -23, 23, 11, -5.5, 5.5);
+	private IHistogram2D trctmEnergySum2D = aida.histogram2D("Tridents CTMatched/Cluster Energy Sum 2D", 300, 0.000, 1.500, 300, 0.000, 1.500);
+	private IHistogram2D trctmTrackPosition = aida.histogram2D("Tridents CTMatched/Extrapolated Track Position", 200, -400, 400, 55, -110, 110);
+	private IHistogram2D trctmMomentumSum2D = aida.histogram2D("Tridents CTMatched/Track Momentum Sum 2D", 300, 0.000, 1.500, 300, 0.000, 1.500);
+	private IHistogram2D trctmESumCoplanarity = aida.histogram2D("Tridents CTMatched/Cluster Energy Sum vs. Coplanarity", 300, 0.000, 1.500, 360, 0, 360);
+	private IHistogram2D trctmPSumCoplanarity = aida.histogram2D("Tridents CTMatched/Track Momentum Sum vs. Coplanarity", 300, 0.000, 1.500, 360, 0, 360);
+	
+	// Define trident vertexed condition plots.
+	private IHistogram1D trvtxInvariantMass = aida.histogram1D("Tridents Vertexed/Invariant Mass", 140, 0.0, 0.070);
+	private IHistogram1D trvtxInstancesInEvent = aida.histogram1D("Tridents Vertexed/Instances in Event", 9, 0.5, 9.5);
+	private IHistogram1D trvtxEnergySum1D = aida.histogram1D("Tridents Vertexed/Cluster Energy Sum", 150, 0.000, 1.500);
+	private IHistogram1D trvtxMomentumSum1D = aida.histogram1D("Tridents Vertexed/Track Momentum Sum", 150, 0.000, 1.500);
+	private IHistogram1D trvtxElectronEnergy = aida.histogram1D("Tridents Vertexed/Electron Cluster Energy", 150, 0.000, 1.500);
+	private IHistogram1D trvtxElectronMomentum = aida.histogram1D("Tridents Vertexed/Electron Track Momentum", 150, 0.000, 1.500);
+	private IHistogram1D trvtxPositronEnergy = aida.histogram1D("Tridents Vertexed/Positron Cluster Energy", 150, 0.000, 1.500);
+	private IHistogram1D trvtxPositronMomentum = aida.histogram1D("Tridents Vertexed/Positron Track Momentum", 150, 0.000, 1.500);
+	private IHistogram1D trvtxTimeCoincidence = aida.histogram1D("Tridents Vertexed/Time Coincidence", 100, -4, 4);
+	private IHistogram2D trvtxClusterPosition = aida.histogram2D("Tridents Vertexed/Cluster Seed Position", 46, -23, 23, 11, -5.5, 5.5);
+	private IHistogram2D trvtxEnergySum2D = aida.histogram2D("Tridents Vertexed/Cluster Energy Sum 2D", 300, 0.000, 1.500, 300, 0.000, 1.500);
+	private IHistogram2D trvtxTrackPosition = aida.histogram2D("Tridents Vertexed/Extrapolated Track Position", 200, -400, 400, 55, -110, 110);
+	private IHistogram2D trvtxMomentumSum2D = aida.histogram2D("Tridents Vertexed/Track Momentum Sum 2D", 300, 0.000, 1.500, 300, 0.000, 1.500);
+	private IHistogram2D trvtxESumCoplanarity = aida.histogram2D("Tridents Vertexed/Cluster Energy Sum vs. Coplanarity", 300, 0.000, 1.500, 360, 0, 360);
+	private IHistogram2D trvtxPSumCoplanarity = aida.histogram2D("Tridents Vertexed/Track Momentum Sum vs. Coplanarity", 300, 0.000, 1.500, 360, 0, 360);
+	private IHistogram1D trvtxChiSquared = aida.histogram1D("Tridents Vertexed/Chi Squared", 1000, 0.0, 1000.0);
+	
+	// Define the Møller cluster-track matched condition plots.
+	private IHistogram1D møctmInvariantMass = aida.histogram1D("Møller CTMatched/Invariant Mass", 140, 0.0, 0.070);
+	private IHistogram1D møctmInstancesInEvent = aida.histogram1D("Møller CTMatched/Instances in Event", 9, 0.5, 9.5);
+	private IHistogram1D møctmEnergySum1D = aida.histogram1D("Møller CTMatched/Cluster Energy Sum", 150, 0.000, 1.500);
+	private IHistogram1D møctmMomentumSum1D = aida.histogram1D("Møller CTMatched/Track Momentum Sum", 150, 0.000, 1.500);
+	private IHistogram1D møctmElectronEnergy = aida.histogram1D("Møller CTMatched/Electron Cluster Energy", 150, 0.000, 1.500);
+	private IHistogram1D møctmElectronMomentum = aida.histogram1D("Møller CTMatched/Electron Track Momentum", 150, 0.000, 1.500);
+	private IHistogram1D møctmTimeCoincidence = aida.histogram1D("Møller CTMatched/Time Coincidence", 100, -4, 4);
+	private IHistogram2D møctmClusterPosition = aida.histogram2D("Møller CTMatched/Cluster Seed Position", 46, -23, 23, 11, -5.5, 5.5);
+	private IHistogram2D møctmEnergySum2D = aida.histogram2D("Møller CTMatched/Cluster Energy Sum 2D", 300, 0.000, 1.500, 300, 0.000, 1.500);
+	private IHistogram2D møctmTrackPosition = aida.histogram2D("Møller CTMatched/Extrapolated Track Position", 200, -400, 400, 55, -110, 110);
+	private IHistogram2D møctmMomentumSum2D = aida.histogram2D("Møller CTMatched/Track Momentum Sum 2D", 300, 0.000, 1.500, 300, 0.000, 1.500);
+	private IHistogram2D møctmESumCoplanarity = aida.histogram2D("Møller CTMatched/Cluster Energy Sum vs. Coplanarity", 300, 0.000, 1.500, 360, 0, 360);
+	private IHistogram2D møctmPSumCoplanarity = aida.histogram2D("Møller CTMatched/Track Momentum Sum vs. Coplanarity", 300, 0.000, 1.500, 360, 0, 360);
+	
+	// Define the Møller track-only condition plots.
+	private IHistogram1D møgblTimeCoincidence = aida.histogram1D("Møller Track-Only/Time Coincidence", 100, -4, 4);
+	private IHistogram1D møgblInvariantMass = aida.histogram1D("Møller Track-Only/Invariant Mass", 140, 0.0, 0.070);
+	private IHistogram1D møgblInstancesInEvent = aida.histogram1D("Møller Track-Only/Instances in Event", 9, 0.5, 9.5);
+	private IHistogram1D møgblMomentumSum1D = aida.histogram1D("Møller Track-Only/Track Momentum Sum", 150, 0.000, 1.500);
+	private IHistogram1D møgblElectronMomentum = aida.histogram1D("Møller Track-Only/Electron Track Momentum", 150, 0.000, 1.500);
+	private IHistogram2D møgblTrackPosition = aida.histogram2D("Møller Track-Only/Extrapolated Track Position", 200, -400, 400, 55, -110, 110);
+	private IHistogram2D møgblMomentumSum2D = aida.histogram2D("Møller Track-Only/Track Momentum Sum 2D", 300, 0.000, 1.500, 300, 0.000, 1.500);
+	private IHistogram2D møgblPSumCoplanarity = aida.histogram2D("Møller Track-Only/Track Momentum Sum vs. Coplanarity", 300, 0.000, 1.500, 360, 0, 360);
+	
+	// Define the Møller vertexed condition plots.
+	private IHistogram1D møvtxTimeCoincidence = aida.histogram1D("Møller Vertexed/Time Coincidence", 100, -4, 4);
+	private IHistogram1D møvtxInvariantMass = aida.histogram1D("Møller Vertexed/Invariant Mass", 140, 0.0, 0.070);
+	private IHistogram1D møvtxInstancesInEvent = aida.histogram1D("Møller Vertexed/Instances in Event", 9, 0.5, 9.5);
+	private IHistogram1D møvtxMomentumSum1D = aida.histogram1D("Møller Vertexed/Track Momentum Sum", 150, 0.000, 1.500);
+	private IHistogram1D møvtxElectronMomentum = aida.histogram1D("Møller Vertexed/Electron Track Momentum", 150, 0.000, 1.500);
+	private IHistogram2D møvtxTrackPosition = aida.histogram2D("Møller Vertexed/Extrapolated Track Position", 200, -400, 400, 55, -110, 110);
+	private IHistogram2D møvtxMomentumSum2D = aida.histogram2D("Møller Vertexed/Track Momentum Sum 2D", 300, 0.000, 1.500, 300, 0.000, 1.500);
+	private IHistogram2D møvtxPSumCoplanarity = aida.histogram2D("Møller Vertexed/Track Momentum Sum vs. Coplanarity", 300, 0.000, 1.500, 360, 0, 360);
+	
+	// Define the GBL trident condition plots.
+	private IHistogram1D trgblInvariantMass = aida.histogram1D("Tridents Track-Only/Invariant Mass", 140, 0.0, 0.070);
+	private IHistogram1D trgblInstancesInEvent = aida.histogram1D("Tridents Track-Only/Instances in Event", 9, 0.5, 9.5);
+	private IHistogram1D trgblMomentumSum1D = aida.histogram1D("Tridents Track-Only/Track Momentum Sum", 150, 0.000, 1.500);
+	private IHistogram1D trgblElectronMomentum = aida.histogram1D("Tridents Track-Only/Electron Track Momentum", 150, 0.000, 1.500);
+	private IHistogram1D trgblPositronMomentum = aida.histogram1D("Tridents Track-Only/Positron Track Momentum", 150, 0.000, 1.500);
+	private IHistogram1D trgblTimeCoincidence = aida.histogram1D("Tridents Track-Only/Time Coincidence", 100, -4, 4);
+	private IHistogram2D trgblTrackPosition = aida.histogram2D("Tridents Track-Only/Extrapolated Track Position", 200, -400, 400, 55, -110, 110);
+	private IHistogram2D trgblMomentumSum2D = aida.histogram2D("Tridents Track-Only/Track Momentum Sum 2D", 300, 0.000, 1.500, 300, 0.000, 1.500);
+	private IHistogram2D trgblPSumCoplanarity = aida.histogram2D("Tridents Track-Only/Track Momentum Sum vs. Coplanarity", 300, 0.000, 1.500, 360, 0, 360);
+	
+	@Override
+	public void endOfData() {
+		// Calculate the scaling factor for Hertz.
+		double scale = 19000.0 / eventsProcessed;
+		
+		System.out.println("Processed " + eventsProcessed + " events.");
+		System.out.println("Processed " + møllersProcessed + " Møller events");
+		System.out.println("\tAcceptance :: " + (100.0 * møllersProcessed / eventsProcessed) + "%");
+		System.out.println("\tRate       :: " + (møllersProcessed * scale) + " Hz");
+		
+		System.out.println("Processed " + tridentsProcessed + " trident events");
+		System.out.println("\tAcceptance :: " + (100.0 * tridentsProcessed / eventsProcessed) + "%");
+		System.out.println("\tRate       :: " + (tridentsProcessed * scale) + " Hz");
+		
+		/*
+		System.out.println("Processed " + gblMøllersProcessed + " track-only Møller events");
+		System.out.println("\tAcceptance :: " + (100.0 * gblMøllersProcessed / eventsProcessed) + "%");
+		System.out.println("\tRate       :: " + (gblMøllersProcessed * scale) + " Hz");
+		
+		System.out.println("Processed " + gblTridentsProcessed + " track-only trident events");
+		System.out.println("\tAcceptance :: " + (100.0 * gblTridentsProcessed / eventsProcessed) + "%");
+		System.out.println("\tRate       :: " + (gblTridentsProcessed * scale) + " Hz");
+		*/
+		
+		System.out.println("Processed " + vertexedMøllersProcessed + " vertexed Møller events");
+		System.out.println("\tAcceptance :: " + (100.0 * vertexedMøllersProcessed / eventsProcessed) + "%");
+		System.out.println("\tRate       :: " + (vertexedMøllersProcessed * scale) + " Hz");
+		
+		System.out.println("Processed " + vertexedTridentsProcessed + " vertexed trident events");
+		System.out.println("\tAcceptance :: " + (100.0 * vertexedTridentsProcessed / eventsProcessed) + "%");
+		System.out.println("\tRate       :: " + (vertexedTridentsProcessed * scale) + " Hz");
+		
+		
+		System.out.println("CTM Møllers:");
+		for(int pulser = 0; pulser < 2; pulser++) {
+			for(int singles0 = 0; singles0 < 2; singles0++) {
+				for(int singles1 = 0; singles1 < 2; singles1++) {
+					for(int pair0 = 0; pair0 < 2; pair0++) {
+						for(int pair1 = 0; pair1 < 2; pair1++) {
+							System.out.printf("\t%5b  %5b  %5b  %5b  %5b  %d%n",
+									pulser == 1 ? true : false, singles0 == 1 ? true : false,
+									singles1 == 1 ? true : false, pair0 == 1 ? true : false,
+									pair1 == 1 ? true : false, ctmTriggerMøllers[pulser][singles0][singles1][pair0][pair1]);
+						}
+					}
+				}
+			}
+		}
+		
+		System.out.println("CTM Tridents:");
+		for(int pulser = 0; pulser < 2; pulser++) {
+			for(int singles0 = 0; singles0 < 2; singles0++) {
+				for(int singles1 = 0; singles1 < 2; singles1++) {
+					for(int pair0 = 0; pair0 < 2; pair0++) {
+						for(int pair1 = 0; pair1 < 2; pair1++) {
+							System.out.printf("\t%5b  %5b  %5b  %5b  %5b  %d%n",
+									pulser == 1 ? true : false, singles0 == 1 ? true : false,
+									singles1 == 1 ? true : false, pair0 == 1 ? true : false,
+									pair1 == 1 ? true : false, ctmTriggerTridents[pulser][singles0][singles1][pair0][pair1]);
+						}
+					}
+				}
+			}
+		}
+		
+		System.out.println("VTX Møllers:");
+		for(int pulser = 0; pulser < 2; pulser++) {
+			for(int singles0 = 0; singles0 < 2; singles0++) {
+				for(int singles1 = 0; singles1 < 2; singles1++) {
+					for(int pair0 = 0; pair0 < 2; pair0++) {
+						for(int pair1 = 0; pair1 < 2; pair1++) {
+							System.out.printf("\t%5b  %5b  %5b  %5b  %5b  %d%n",
+									pulser == 1 ? true : false, singles0 == 1 ? true : false,
+									singles1 == 1 ? true : false, pair0 == 1 ? true : false,
+									pair1 == 1 ? true : false, vtxTriggerMøllers[pulser][singles0][singles1][pair0][pair1]);
+						}
+					}
+				}
+			}
+		}
+		
+		System.out.println("VTX Tridents:");
+		for(int pulser = 0; pulser < 2; pulser++) {
+			for(int singles0 = 0; singles0 < 2; singles0++) {
+				for(int singles1 = 0; singles1 < 2; singles1++) {
+					for(int pair0 = 0; pair0 < 2; pair0++) {
+						for(int pair1 = 0; pair1 < 2; pair1++) {
+							System.out.printf("\t%5b  %5b  %5b  %5b  %5b  %d%n",
+									pulser == 1 ? true : false, singles0 == 1 ? true : false,
+									singles1 == 1 ? true : false, pair0 == 1 ? true : false,
+									pair1 == 1 ? true : false, vtxTriggerTridents[pulser][singles0][singles1][pair0][pair1]);
+						}
+					}
+				}
+			}
+		}
+	}
+	
+	/**
+	@Override
+	public void process(EventHeader event) {
+		// Check whether the SVT was active in this event and, if so,
+		// skip it. This can be disabled through the steering file for
+		// Monte Carlo data, where the "SVT" is always active.
+		if(checkSVT) {
+			final String[] flagNames = { "svt_bias_good", "svt_burstmode_noise_good", "svt_position_good" };
+			boolean svtGood = true;
+	        for(int i = 0; i < flagNames.length; i++) {
+	            int[] flag = event.getIntegerParameters().get(flagNames[i]);
+	            if(flag == null || flag[0] == 0) {
+	                svtGood = false;
+	            }
+	        }
+	        if(!svtGood) { return; }
+		}
         
         System.out.println("Processed " + eventsProcessed + " events.");
         System.out.println("Processed " + mollersProcessed + " Moller events");
@@ -110,7 +284,7 @@
         System.out.println("Processed " + gblTridentsProcessed + " Rafo trident events");
         System.out.println("\tAcceptance :: " + (100.0 * gblTridentsProcessed / eventsProcessed) + "%");
         System.out.println("\tRate       :: " + (gblTridentsProcessed * scale) + " Hz");
-    }
+    }**/
     
 /*
     @Override
@@ -171,583 +345,870 @@
         
         // Check if the event has a collection of tracks. If it exists,
         // extract it. Otherwise, skip the event.
-        if(!event.hasCollection(ReconstructedParticle.class, particleCollectionName)) {
-            return;
-        }
-        List<ReconstructedParticle> trackList = event.get(ReconstructedParticle.class, particleCollectionName);
-        
-        // Check if the event has a collection of clusters. If it
-        // exists, extract it. Otherwise, skip the event.
-        if(!event.hasCollection(Cluster.class, clusterCollectionName)) {
-            return;
-        }
-        List<Cluster> clusterList = event.get(Cluster.class, clusterCollectionName);
-        
-        // Get cluster-track matched top/bottom pairs.
-        List<ReconstructedParticle[]> gblMatchedPairs = getTopBottomTracksGBL(trackList);
-        List<ReconstructedParticle[]> ctMatchedPairs  = getTopBottomTracksCTMatched(trackList);
-        
-        System.out.println("CTM Pairs :: " + ctMatchedPairs.size());
-        System.out.println("GBL Pairs :: " + gblMatchedPairs.size());
-        
-        // Get the trident and Moller tracks for the matched track
-        // and cluster pair condition sets.
-        List<ReconstructedParticle[]> mollers     = getMollerTracksCTMatched(ctMatchedPairs);
-        List<ReconstructedParticle[]> mollersGBL  = getMollerTracksGBL(gblMatchedPairs, event);
-        List<ReconstructedParticle[]> tridents    = getTridentTracksCTMatched(ctMatchedPairs);
-        List<ReconstructedParticle[]> tridentsGBL = getTridentClustersGBL(gblMatchedPairs, TriggerModule.getTopBottomPairs(clusterList, Cluster.class), event);
-        
-        // Track how many events had tridents and Mollers.
-        if(!mollers.isEmpty()) { mollersProcessed++; }
-        if(!tridents.isEmpty()) { tridentsProcessed++; }
-        if(!mollersGBL.isEmpty()) { gblMollersProcessed++; }
-        if(!tridentsGBL.isEmpty()) { gblTridentsProcessed++; }
-        
-        // Produce Moller cluster-track matched plots.
-        moctmInstancesInEvent.fill(mollers.size());
-        for(ReconstructedParticle[] pair : mollers) {
-            // Get the track clusters.
-            Track[] tracks = { pair[0].getTracks().get(0), pair[1].getTracks().get(0) };
-            Cluster[] trackClusters = { pair[0].getClusters().get(0), pair[1].getClusters().get(0) };
-            
-            // Populate the cluster plots.
-            moctmElectronEnergy.fill(trackClusters[0].getEnergy());
-            moctmElectronEnergy.fill(trackClusters[1].getEnergy());
-            moctmEnergySum1D.fill(TriggerModule.getValueEnergySum(trackClusters));
-            moctmEnergySum2D.fill(trackClusters[0].getEnergy(), trackClusters[1].getEnergy());
-            moctmESumCoplanarity.fill(TriggerModule.getValueEnergySum(trackClusters), getCalculatedCoplanarity(trackClusters));
-            moctmTimeCoincidence.fill(TriggerModule.getClusterTime(trackClusters[0]) - TriggerModule.getClusterTime(trackClusters[1]));
-            moctmClusterPosition.fill(TriggerModule.getClusterXIndex(trackClusters[0]), TriggerModule.getClusterYIndex(trackClusters[0]));
-            moctmClusterPosition.fill(TriggerModule.getClusterXIndex(trackClusters[1]), TriggerModule.getClusterYIndex(trackClusters[1]));
-            
-            // Populate the momentum plots.
-            moctmInvariantMass.fill(getInvariantMass(pair));
-            moctmElectronMomentum.fill(pair[0].getMomentum().magnitude());
-            moctmElectronMomentum.fill(pair[1].getMomentum().magnitude());
-            moctmMomentumSum1D.fill(VecOp.add(pair[0].getMomentum(), pair[1].getMomentum()).magnitude());
-            moctmMomentumSum2D.fill(pair[0].getMomentum().magnitude(), pair[1].getMomentum().magnitude());
-            moctmTrackPosition.fill(TrackUtils.getTrackPositionAtEcal(tracks[0]).x(), TrackUtils.getTrackPositionAtEcal(tracks[0]).y());
-            moctmTrackPosition.fill(TrackUtils.getTrackPositionAtEcal(tracks[1]).x(), TrackUtils.getTrackPositionAtEcal(tracks[1]).y());
-            moctmPSumCoplanarity.fill(VecOp.add(pair[0].getMomentum(), pair[1].getMomentum()).magnitude(),
-                    getCalculatedCoplanarity(new Track[] { pair[0].getTracks().get(0), pair[1].getTracks().get(0) }));
-        }
-        
-        // Produce trident cluster-track matched plots.
-        trctmInstancesInEvent.fill(tridents.size());
-        for(ReconstructedParticle[] pair : tridents) {
-            // Get the electron and positron tracks.
-            ReconstructedParticle electronTrack = pair[pair[0].getCharge() < 0 ? 0 : 1];
-            ReconstructedParticle positronTrack = pair[pair[0].getCharge() > 0 ? 0 : 1];
-            
-            // Get the track clusters.
-            Cluster electronCluster = electronTrack.getClusters().get(0);
-            Cluster positronCluster = positronTrack.getClusters().get(0);
-            Track[] tracks = { pair[0].getTracks().get(0), pair[1].getTracks().get(0) };
-            Cluster[] trackClusters = { pair[0].getClusters().get(0), pair[1].getClusters().get(0) };
-            
-            // Populate the cluster plots.
-            trctmElectronEnergy.fill(electronCluster.getEnergy());
-            trctmPositronEnergy.fill(positronCluster.getEnergy());
-            trctmEnergySum2D.fill(pair[0].getEnergy(), pair[1].getEnergy());
-            trctmEnergySum1D.fill(TriggerModule.getValueEnergySum(trackClusters));
-            trctmESumCoplanarity.fill(TriggerModule.getValueEnergySum(trackClusters), getCalculatedCoplanarity(trackClusters));
-            trctmTimeCoincidence.fill(TriggerModule.getClusterTime(trackClusters[0]) - TriggerModule.getClusterTime(trackClusters[1]));
-            trctmClusterPosition.fill(TriggerModule.getClusterXIndex(trackClusters[0]), TriggerModule.getClusterYIndex(trackClusters[0]));
-            trctmClusterPosition.fill(TriggerModule.getClusterXIndex(trackClusters[1]), TriggerModule.getClusterYIndex(trackClusters[1]));
-            
-            // Populate the momentum plots.
-            trctmInvariantMass.fill(getInvariantMass(pair));
-            trctmElectronMomentum.fill(electronTrack.getMomentum().magnitude());
-            trctmPositronMomentum.fill(positronTrack.getMomentum().magnitude());
-            trctmMomentumSum1D.fill(VecOp.add(pair[0].getMomentum(), pair[1].getMomentum()).magnitude());
-            trctmMomentumSum2D.fill(pair[0].getMomentum().magnitude(), pair[1].getMomentum().magnitude());
-            trctmTrackPosition.fill(TrackUtils.getTrackPositionAtEcal(tracks[0]).x(), TrackUtils.getTrackPositionAtEcal(tracks[0]).y());
-            trctmTrackPosition.fill(TrackUtils.getTrackPositionAtEcal(tracks[1]).x(), TrackUtils.getTrackPositionAtEcal(tracks[1]).y());
-            trctmPSumCoplanarity.fill(VecOp.add(pair[0].getMomentum(), pair[1].getMomentum()).magnitude(),
-                    getCalculatedCoplanarity(new Track[] { pair[0].getTracks().get(0), pair[1].getTracks().get(0) }));
-        }
-        
-        // Produce the Moller track-only plots.
-        mogblInstancesInEvent.fill(mollersGBL.size());
-        RelationalTable<?, ?> hitToStrips = TrackUtils.getHitToStripsTable(event);
-        RelationalTable<?, ?> hitToRotated = TrackUtils.getHitToRotatedTable(event);
-        for(ReconstructedParticle pair[] : mollersGBL) {
-            // Get the tracks and track times.
-            Track[] tracks = { pair[0].getTracks().get(0), pair[1].getTracks().get(0) };
-            double times[] = {
-                    TrackUtils.getTrackTime(tracks[0], hitToStrips, hitToRotated),
-                    TrackUtils.getTrackTime(tracks[1], hitToStrips, hitToRotated)    
-            };
-            
-            // Fill the plots.
-            mogblTimeCoincidence.fill(times[0] - times[1]);
-            mogblInvariantMass.fill(getInvariantMass(pair));
-            mogblElectronMomentum.fill(pair[0].getMomentum().magnitude());
-            mogblElectronMomentum.fill(pair[1].getMomentum().magnitude());
-            mogblMomentumSum1D.fill(VecOp.add(pair[0].getMomentum(), pair[1].getMomentum()).magnitude());
-            mogblMomentumSum2D.fill(pair[0].getMomentum().magnitude(), pair[1].getMomentum().magnitude());
-            mogblTrackPosition.fill(TrackUtils.getTrackPositionAtEcal(tracks[0]).x(), TrackUtils.getTrackPositionAtEcal(tracks[0]).y());
-            mogblTrackPosition.fill(TrackUtils.getTrackPositionAtEcal(tracks[1]).x(), TrackUtils.getTrackPositionAtEcal(tracks[1]).y());
-            mogblPSumCoplanarity.fill(VecOp.add(pair[0].getMomentum(), pair[1].getMomentum()).magnitude(),
-                    getCalculatedCoplanarity(new Track[] { pair[0].getTracks().get(0), pair[1].getTracks().get(0) }));
-        }
-        
-        // Produce track-only trident plots.
-        trgblInstancesInEvent.fill(tridentsGBL.size());
-        for(ReconstructedParticle[] pair : tridentsGBL) {
-            // Get the tracks and track times.
-            Track[] tracks = { pair[0].getTracks().get(0), pair[1].getTracks().get(0) };
-            double times[] = {
-                    TrackUtils.getTrackTime(tracks[0], hitToStrips, hitToRotated),
-                    TrackUtils.getTrackTime(tracks[1], hitToStrips, hitToRotated)    
-            };
-            
-            // Get the positron and the electron.
-            ReconstructedParticle positron = pair[0].getCharge() > 0 ? pair[0] : pair[1];
-            ReconstructedParticle electron = pair[0].getCharge() < 0 ? pair[0] : pair[1];
-            
-            // Fill the plots.
-            trgblTimeCoincidence.fill(times[0] - times[1]);
-            trgblInvariantMass.fill(getInvariantMass(pair));
-            trgblElectronMomentum.fill(electron.getMomentum().magnitude());
-            trgblPositronMomentum.fill(positron.getMomentum().magnitude());
-            trgblMomentumSum1D.fill(VecOp.add(pair[0].getMomentum(), pair[1].getMomentum()).magnitude());
-            trgblMomentumSum2D.fill(pair[0].getMomentum().magnitude(), pair[1].getMomentum().magnitude());
-            trgblTrackPosition.fill(TrackUtils.getTrackPositionAtEcal(tracks[0]).x(), TrackUtils.getTrackPositionAtEcal(tracks[0]).y());
-            trgblTrackPosition.fill(TrackUtils.getTrackPositionAtEcal(tracks[1]).x(), TrackUtils.getTrackPositionAtEcal(tracks[1]).y());
-            trgblPSumCoplanarity.fill(VecOp.add(pair[0].getMomentum(), pair[1].getMomentum()).magnitude(),
-                    getCalculatedCoplanarity(new Track[] { pair[0].getTracks().get(0), pair[1].getTracks().get(0) }));
-        }
-    }
-    
-    public void setCheckSVT(boolean state) {
-        checkSVT = state;
-    }
-    
-    public void setCheckTriggerTimeWindow(boolean state) {
-        checkTriggerTimeWindow = state;
-    }
-    
-    /**
-     * Gets a list of all possible GBL top/bottom track pairs. These
-     * tracks are not guaranteed to have a matched cluster.
-     * @param trackList - A list of all possible tracks.
-     * @return Returns a list of track pairs.
-     */
-    private static final List<ReconstructedParticle[]> getTopBottomTracksGBL(List<ReconstructedParticle> trackList) {
-        // Separate the tracks into top and bottom tracks based on
-        // the value of tan(Λ). Use only GBL tracks to avoid track
-        // duplication.
-        List<ReconstructedParticle> topTracks = new ArrayList<ReconstructedParticle>();
-        List<ReconstructedParticle> botTracks = new ArrayList<ReconstructedParticle>();
-        trackLoop:
-        for(ReconstructedParticle track : trackList) {
-            // Require that the ReconstructedParticle contain an actual
-            // Track object.
-            if(track.getTracks().isEmpty()) {
-                continue trackLoop;
-            }
-            
-            // Ignore tracks that are not GBL tracks.
-            if(!TrackType.isGBL(track.getType())) {
-                continue trackLoop;
-            }
-            
-            // If the above tests pass, the ReconstructedParticle has
-            // a track and is also a GBL track. Separate it into either
-            // a top or a bottom track based on its tan(Λ) value.
-            if(track.getTracks().get(0).getTrackStates().get(0).getTanLambda() > 0) {
-                topTracks.add(track);
-            } else {
-                botTracks.add(track);
-            }
-        }
-        
-        // Form all top/bottom pairs with the unique tracks.
-        List<ReconstructedParticle[]> pairList = new ArrayList<ReconstructedParticle[]>();
-        for(ReconstructedParticle topTrack : topTracks) {
-            for(ReconstructedParticle botTrack : botTracks) {
-                pairList.add(new ReconstructedParticle[] { topTrack, botTrack });
-            }
-        }
-        
-        // Return the result.
-        return pairList;
-    }
-    
-    /**
-     * Produces pairs of tracks. The track pairs are required to be
-     * matched to a cluster and the associated clusters must form a
-     * top/bottom pair. If more than one track points to the same
-     * cluster, only the first track is retained.
-     * @param trackList - A list of all tracks.
-     * @return Returns a list of track pairs meeting the aforementioned
-     * conditions.
-     */
-    private static final List<ReconstructedParticle[]> getTopBottomTracksCTMatched(List<ReconstructedParticle> trackList) {
-        // Track clusters that have already been seen to prevent clusters
-        // that have duplicate tracks from reappearing.
-        Set<Cluster> clusterSet = new HashSet<Cluster>();
-        
-        // Separate the tracks into top and bottom tracks based on
-        // the track cluster. Filter out tracks with no clusters.
-        List<ReconstructedParticle> topTracks = new ArrayList<ReconstructedParticle>();
-        List<ReconstructedParticle> botTracks = new ArrayList<ReconstructedParticle>();
-        trackLoop:
-        for(ReconstructedParticle track : trackList) {
-            // Check if the track has a cluster. If not, skip it.
-            if(track.getClusters().isEmpty()) {
-                continue trackLoop;
-            }
-            
-            // If the track doesn't have actual tracks, skip it.
-            if(track.getTracks().isEmpty()) {
-                continue trackLoop;
-            }
-            
-            // Check if the track cluster has already seen.
-            Cluster trackCluster = track.getClusters().get(0);
-            if(clusterSet.contains(trackCluster)) {
-                continue trackLoop;
-            }
-            
-            // If the track has a unique cluster, add it to the proper
-            // list based on the cluster y-index.
-            clusterSet.add(trackCluster);
-            if(TriggerModule.getClusterYIndex(trackCluster) > 0) {
-                topTracks.add(track);
-            } else {
-                botTracks.add(track);
-            }
-        }
-        
-        // Form all top/bottom pairs with the unique tracks.
-        List<ReconstructedParticle[]> pairList = new ArrayList<ReconstructedParticle[]>();
-        for(ReconstructedParticle topTrack : topTracks) {
-            for(ReconstructedParticle botTrack : botTracks) {
-                pairList.add(new ReconstructedParticle[] { topTrack, botTrack });
-            }
-        }
-        
-        // Return the result.
-        return pairList;
-    }
-    
-    private final List<ReconstructedParticle[]> getTridentClustersGBL(List<ReconstructedParticle[]> pairList, List<Cluster[]> clusterList, EventHeader event) {
-        // Store the set of track pairs that meet the trident condition.
-        List<ReconstructedParticle[]> tridentTracks = new ArrayList<ReconstructedParticle[]>();
-        
-        // Extract track relational tables from the event object.
-        RelationalTable<?, ?> hitToStrips = TrackUtils.getHitToStripsTable(event);
-        RelationalTable<?, ?> hitToRotated = TrackUtils.getHitToRotatedTable(event);
-        
-        // Tracks will not be considered for trident analysis unless there
-        // is at least one top/bottom cluster pair within the time window.
-        boolean passesClusterCondition = false;
-        tridentClusterLoop:
-        for(Cluster[] pair : clusterList) {
-            // Ignore clusters that are too far apart temporally.
-            if(TriggerModule.getValueTimeCoincidence(pair) > timeCoincidence) {
-                continue tridentClusterLoop;
-            }
-            
-            // Require that the cluster pair be top/bottom.
-            boolean hasTop = TriggerModule.getClusterYIndex(pair[0]) > 0 || TriggerModule.getClusterYIndex(pair[1]) > 0;
-            boolean hasBot = TriggerModule.getClusterYIndex(pair[0]) < 0 || TriggerModule.getClusterYIndex(pair[1]) < 0;
-            if(!hasTop || !hasBot) {
-                continue tridentClusterLoop;
-            }
-            
-            // If the cluster passes, mark that it has done so and skip
-            // the rest. Only one pair need pass.
-            passesClusterCondition = true;
-            break tridentClusterLoop;
-        }
-        
-        // If no cluster pair passed the cluster condition, no tracks
-        // are allowed to pass either.
-        if(!passesClusterCondition) {
-            return tridentTracks;
-        }
-        
-        // Next, check the track pair list. A track pair must have a
-        // positive and a negative track and must also be within the
-        // time coincidence window.
-        tridentTrackLoop:
-        for(ReconstructedParticle[] pair : pairList) {
-            // Check that there is at least one positive and one negative
-            // track in the pair.
-            boolean hasPositive = pair[0].getCharge() > 0 || pair[1].getCharge() > 0;
-            boolean hasNegative = pair[0].getCharge() < 0 || pair[1].getCharge() < 0;
-            if(!hasPositive || !hasNegative) {
-                break tridentTrackLoop;
-            }
-            
-            // Check that the track pair passes the time cut.
-            double times[] = {
-                TrackUtils.getTrackTime(pair[0].getTracks().get(0), hitToStrips, hitToRotated),
-                TrackUtils.getTrackTime(pair[1].getTracks().get(0), hitToStrips, hitToRotated)    
-            };
-            
-            if(Math.abs(times[0] - times[1]) > timeCoincidence) {
-                continue tridentTrackLoop;
-            }
-            
-            // Require that the negative track have less than the
-            // elastic threshold momentum to exclude elastic electrons.
-            if(pair[0].getCharge() < 0 && pair[0].getMomentum().magnitude() > elasticThreshold
-                    || pair[1].getCharge() < 0 && pair[1].getMomentum().magnitude() > elasticThreshold) {
-                continue tridentTrackLoop;
-            }
-            
-            // If the track passes both, it is considered a trident pair.
-            tridentTracks.add(pair);
-        }
-        
-        // Return the resultant pairs.
-        return tridentTracks;
-    }
-    
-    /**
-     * Gets a list track pairs that meet the trident condition defined
-     * using tracks with matched calorimeter clusters. A pair meets the
-     * cluster/track matched trident condition is it meets the following:
-     * <ul><li>Both tracks have matched clusters.</li>
-     * <li>Has one positive track.</li>
-     * <li>Has one negative track.</li>
-     * <li>Clusters have a time coincidence of 2.5 ns or less.</li>
-     * <li>The electron momentum is below 900 MeV.</li></ul>
-     * @param pairList - A <code>List</code> collection of parameterized
-     * type <code>ReconstructedParticle[]</code> containing all valid
-     * top/bottom pairs of tracks with matched clusters. These will be
-     * tested to see if they meet the process criteria.
-     * @return Returns a list containing pairs of tracks that meet the
-     * trident condition.
-     */
-    private final List<ReconstructedParticle[]> getTridentTracksCTMatched(List<ReconstructedParticle[]> pairList) {
-        // Store the set of track pairs that meet the trident condition.
-        List<ReconstructedParticle[]> tridentTracks = new ArrayList<ReconstructedParticle[]>();
-        
-        // Loop over the filtered pair list and apply the trident
-        // condition test.
-        tridentLoop:
-        for(ReconstructedParticle[] pair : pairList) {
-            // There must be one positive and one negative track.
-            ReconstructedParticle electron = null;
-            ReconstructedParticle positron = null;
-            if(pair[0].getCharge() > 0) { positron = pair[0]; }
-            else if(pair[1].getCharge() > 0) { positron = pair[1]; }
-            if(pair[0].getCharge() < 0) { electron = pair[0]; }
-            else if(pair[1].getCharge() < 0) { electron = pair[1]; }
-            if(electron == null || positron == null) {
-                continue tridentLoop;
-            }
-            
-            // Make sure that the clusters are not the same. This should
-            // not actually ever be possible...
-            if(pair[0].getClusters().get(0) == pair[1].getClusters().get(0)) {
-                continue tridentLoop;
-            }
-            
-            // The clusters must within a limited time window.
-            /*
-            Cluster[] trackClusters = { pair[0].getClusters().get(0), pair[1].getClusters().get(0) };
-            if(TriggerModule.getValueTimeCoincidence(trackClusters) > timeCoincidence) {
-                continue tridentLoop;
-            }
-            */
-            
-            // The clusters must be coincidental within an energy
-            // dependent coincidence window.
-            Cluster[] trackClusters = { pair[0].getClusters().get(0), pair[1].getClusters().get(0) };
-            if(!isCoincidental(trackClusters)) {
-                continue tridentLoop;
-            }
-            
-            // Require that the electron in the pair have an energy
-            // below the elastic threshold to exclude elastic electrons.
-            if(electron.getMomentum().magnitude() >= elasticThreshold) {
-                continue tridentLoop;
-            }
-            
-            // Require that all clusters occur within the trigger time
-            // window to exclude accidentals.
-            if(checkTriggerTimeWindow) {
-                if(!inTriggerWindow(trackClusters[0]) || !inTriggerWindow(trackClusters[1])) {
-                    continue tridentLoop;
-                }
-            }
-            
-            // If all the above conditions are met, the pair is to be
-            // considered a trident pair. Add it to the list.
-            tridentTracks.add(pair);
-        }
-        
-        // Return the list of pairs that passed the condition.
-        return tridentTracks;
-    }
-    
-    private final List<ReconstructedParticle[]> getMollerTracksGBL(List<ReconstructedParticle[]> pairList, EventHeader event) {
-        // Store the set of track pairs that meet the Moller condition.
-        List<ReconstructedParticle[]> mollerTracks = new ArrayList<ReconstructedParticle[]>();
-        
-        // Extract track relational tables from the event object.
-        RelationalTable<?, ?> hitToStrips = TrackUtils.getHitToStripsTable(event);
-        RelationalTable<?, ?> hitToRotated = TrackUtils.getHitToRotatedTable(event);
-        
-        // Loop over the filtered pair list and apply the Moller
-        // condition test.
-        mollerLoop:
-        for(ReconstructedParticle[] pair : pairList) {
-            // Both tracks must be negatively charged.
-            if(pair[0].getCharge() > 0 || pair[1].getCharge() > 0) {
-                continue mollerLoop;
-            }
-            
-            // The clusters must within a limited time window.
-            double times[] = {
-                TrackUtils.getTrackTime(pair[0].getTracks().get(0), hitToStrips, hitToRotated),
-                TrackUtils.getTrackTime(pair[1].getTracks().get(0), hitToStrips, hitToRotated)    
-            };
-            
-            if(Math.abs(times[0] - times[1]) > timeCoincidence) {
-                continue mollerLoop;
-            }
-            
-            // Require that the electrons in the pair have energies
-            // below the elastic threshold to exclude said electrons.
-            if(pair[0].getMomentum().magnitude() > elasticThreshold || pair[1].getMomentum().magnitude() > elasticThreshold) {
-                continue mollerLoop;
-            }
-            
-            // Require that the energy of the pair be within a range
-            // that is sufficiently "Moller-like."
-            double momentumSum = VecOp.add(pair[0].getMomentum(), pair[1].getMomentum()).magnitude();
-            if(momentumSum < mollerLowerRange || momentumSum > mollerUpperRange) {
-                continue mollerLoop;
-            }
-            
-            // If all the above conditions are met, the pair is to be
-            // considered a trident pair. Add it to the list.
-            mollerTracks.add(pair);
-        }
-        
-        // Return the list of pairs that passed the condition.
-        return mollerTracks;
-    }
-    
-    /**
-     * Gets a list track pairs that meet the Moller condition defined
-     * using tracks with matched calorimeter clusters. A pair meets the
-     * cluster/track matched Moller condition is it meets the following:
-     * <ul><li>Both tracks have matched clusters.</li>
-     * <li>Both tracks are negative.</li>
-     * <li>Clusters have a time coincidence of 2.5 ns or less.</li>
-     * <li>The electron momenta are below 900 MeV.</li>
-     * <li>The momentum sum of the tracks is in the range <code>800 MeV
-     * ≤ p1 + p2 ≤ 1500 MeV</li></ul>
-     * @param pairList - A <code>List</code> collection of parameterized
-     * type <code>ReconstructedParticle[]</code> containing all valid
-     * top/bottom pairs of tracks with matched clusters. These will be
-     * tested to see if they meet the process criteria.
-     * @return Returns a list containing pairs of tracks that meet the
-     * Moller condition.
-     */
-    private final List<ReconstructedParticle[]> getMollerTracksCTMatched(List<ReconstructedParticle[]> pairList) {
-        // Store the set of track pairs that meet the Moller condition.
-        List<ReconstructedParticle[]> mollerTracks = new ArrayList<ReconstructedParticle[]>();
-        
-        // Loop over the filtered pair list and apply the Moller
-        // condition test.
-        mollerLoop:
-        for(ReconstructedParticle[] pair : pairList) {
-            // Both tracks must be negatively charged.
-            if(pair[0].getCharge() > 0 || pair[1].getCharge() > 0) {
-                continue mollerLoop;
-            }
-            
-            // The clusters must within a limited time window.
-            /*
-            Cluster[] trackClusters = { pair[0].getClusters().get(0), pair[1].getClusters().get(0) };
-            if(TriggerModule.getValueTimeCoincidence(trackClusters) > timeCoincidence) {
-                continue mollerLoop;
-            }
-            */
-            
-            // The clusters must be coincidental within an energy
-            // dependent coincidence window.
-            Cluster[] trackClusters = { pair[0].getClusters().get(0), pair[1].getClusters().get(0) };
-            if(!isCoincidental(trackClusters)) {
-                continue mollerLoop;
-            }
-            
-            // Require that the electrons in the pair have energies
-            // below the elastic threshold to exclude said electrons.
-            if(pair[0].getMomentum().magnitude() > elasticThreshold || pair[1].getMomentum().magnitude() > elasticThreshold) {
-                continue mollerLoop;
-            }
-            
-            // Require that the energy of the pair be within a range
-            // that is sufficiently "Moller-like."
-            double momentumSum = VecOp.add(pair[0].getMomentum(), pair[1].getMomentum()).magnitude();
-            if(momentumSum < mollerLowerRange || momentumSum > mollerUpperRange) {
-                continue mollerLoop;
-            }
-            
-            // Require that all clusters occur within the trigger time
-            // window to exclude accidentals.
-            if(checkTriggerTimeWindow) {
-                if(!inTriggerWindow(trackClusters[0]) || !inTriggerWindow(trackClusters[1])) {
-                    continue mollerLoop;
-                }
-            }
-            
-            // If all the above conditions are met, the pair is to be
-            // considered a trident pair. Add it to the list.
-            mollerTracks.add(pair);
-        }
-        
-        // Return the list of pairs that passed the condition.
-        return mollerTracks;
-    }
-    
-    /**
-     * Calculates the approximate invariant mass for a pair of tracks
-     * from their momentum. This assumes that the particles are either
-     * electrons or positrons, and thusly have a sufficiently small
-     * mass term that it can be safely excluded.
-     * @param pair - The track pair for which to calculate the invariant
-     * mass.
-     * @return Returns the approximate invariant mass in units of GeV.
-     */
-    private static final double getInvariantMass(ReconstructedParticle[] pair) {
-        // Get the momentum squared.
-        double p2 = Math.pow(pair[0].getMomentum().magnitude() + pair[1].getMomentum().magnitude(), 2);
-        
-        // Get the remaining terms.
-        double xPro = pair[0].getMomentum().x() + pair[1].getMomentum().x();
-        double yPro = pair[0].getMomentum().y() + pair[1].getMomentum().y();
-        double zPro = pair[0].getMomentum().z() + pair[1].getMomentum().z();
-        
-        // Calculate the invariant mass.
-        return Math.sqrt(p2 - Math.pow(xPro, 2) - Math.pow(yPro, 2) - Math.pow(zPro, 2));
-    }
-    
-    /**
-     * Calculates the coplanarity angle between two points, specified
-     * by a double array. The array must be of the format (x, y, z).
-     * @param position - The first position array.
-     * @param otherPosition - The second position array.
-     * @return Returns the coplanarity angle between the points in units
-     * of degrees.
-     */
-    private static final double getCalculatedCoplanarity(double[] position, double[] otherPosition) {
-        // Define the x- and y-coordinates of the clusters as well as
-        // calorimeter center.
-        final double ORIGIN_X = 42.52;
-        double x[] = { position[0], otherPosition[0] };
-        double y[] = { position[1], otherPosition[1] };
-        
+		if(!event.hasCollection(ReconstructedParticle.class, particleCollectionName)) {
+			return;
+		}
+		List<ReconstructedParticle> trackList = event.get(ReconstructedParticle.class, particleCollectionName);
+		
+		// Check if the event has a collection of clusters. If it
+		// exists, extract it. Otherwise, skip the event.
+		if(!event.hasCollection(Cluster.class, clusterCollectionName)) {
+			return;
+		}
+		List<Cluster> clusterList = event.get(Cluster.class, clusterCollectionName);
+		
+		// Check if a trident candidate collection exists, and obtain
+		// it if so. Continue with the event if it does not.
+		List<ReconstructedParticle> tridentCandidates = null;
+		if(event.hasCollection(ReconstructedParticle.class, tridentCollectionName)) {
+			tridentCandidates = event.get(ReconstructedParticle.class, tridentCollectionName);
+		} else {
+			tridentCandidates = new ArrayList<ReconstructedParticle>(0);
+		}
+		
+		// Check if a Møller candidate collection exists, and obtain
+		// it if so. Continue with the event if it does not.
+		List<ReconstructedParticle> møllerCandidates = null;
+		if(event.hasCollection(ReconstructedParticle.class, møllerCollectionName)) {
+			møllerCandidates = event.get(ReconstructedParticle.class, møllerCollectionName);
+		} else {
+			møllerCandidates = new ArrayList<ReconstructedParticle>(0);
+		}
+		
+		// Get cluster-track matched top/bottom pairs.
+		List<ReconstructedParticle[]> gblMatchedPairs = getTopBottomTracksGBL(trackList);
+		List<ReconstructedParticle[]> ctMatchedPairs  = getTopBottomTracksCTMatched(trackList);
+		
+		// Get the trident and Møller tracks for the matched track
+		// and cluster pair condition sets.
+		List<ReconstructedParticle[]> møllers     = getMøllerTracksCTMatched(ctMatchedPairs);
+		List<ReconstructedParticle[]> møllersGBL  = getMøllerTracksGBL(gblMatchedPairs, event);
+		List<ReconstructedParticle[]> tridents    = getTridentTracksCTMatched(ctMatchedPairs);
+		List<ReconstructedParticle[]> tridentsVTX = getTridentTracksVertexed(tridentCandidates);
+		List<ReconstructedParticle[]> møllersVTX  = getMøllerTracksVertexed(møllerCandidates);
+		List<ReconstructedParticle[]> tridentsGBL = getTridentClustersGBL(gblMatchedPairs, TriggerModule.getTopBottomPairs(clusterList, Cluster.class), event);
+		
+		// Track how many events had tridents and Møllers.
+		if(!møllers.isEmpty()) { møllersProcessed++; }
+		if(!tridents.isEmpty()) { tridentsProcessed++; }
+		if(!møllersGBL.isEmpty()) { gblMøllersProcessed++; }
+		if(!tridentsGBL.isEmpty()) { gblTridentsProcessed++; }
+		if(!møllersVTX.isEmpty()) { vertexedMøllersProcessed++; }
+		if(!tridentsVTX.isEmpty()) { vertexedTridentsProcessed++; }
+		
+		// Get the SSP clusters.
+		if(event.hasCollection(GenericObject.class, bankCollectionName)) {
+			// Get the bank list.
+			List<GenericObject> bankList = event.get(GenericObject.class, bankCollectionName);
+			
+			// Check for simulated triggers. If they exist, populate the
+			// trigger tracking variables.
+			for(GenericObject obj : bankList) {
+				if(AbstractIntData.getTag(obj) == TIData.BANK_TAG) {
+					TIData tiBank = new TIData(obj);
+					
+					// Establish which triggers were active.
+					boolean isPulser   = tiBank.isPulserTrigger();
+					boolean isPair0    = tiBank.isPair0Trigger();
+					boolean isPair1    = tiBank.isPair1Trigger();
+					boolean isSingles0 = tiBank.isSingle0Trigger();
+					boolean isSingles1 = tiBank.isSingle1Trigger();
+					
+					// Populate the appropriate trigger tracking variables.
+					triggerActiveEvents++;
+					if(!møllers.isEmpty()) {
+						ctmTriggerMøllers[isPulser ? 1 : 0][isSingles0 ? 1 : 0][isSingles1 ? 1 : 0][isPair0 ? 1 : 0][isPair1 ? 1 : 0]++;
+					} if(!tridents.isEmpty()) {
+						ctmTriggerTridents[isPulser ? 1 : 0][isSingles0 ? 1 : 0][isSingles1 ? 1 : 0][isPair0 ? 1 : 0][isPair1 ? 1 : 0]++;
+					} if(!møllersVTX.isEmpty()) {
+						vtxTriggerMøllers[isPulser ? 1 : 0][isSingles0 ? 1 : 0][isSingles1 ? 1 : 0][isPair0 ? 1 : 0][isPair1 ? 1 : 0]++;
+					} if(!tridentsVTX.isEmpty()) {
+						vtxTriggerTridents[isPulser ? 1 : 0][isSingles0 ? 1 : 0][isSingles1 ? 1 : 0][isPair0 ? 1 : 0][isPair1 ? 1 : 0]++;
+					}
+				}
+			}
+		}
+		
+		// Produce Møller cluster-track matched plots.
+		møctmInstancesInEvent.fill(møllers.size());
+		for(ReconstructedParticle[] pair : møllers) {
+			// Get the track clusters.
+			Track[] tracks = { pair[0].getTracks().get(0), pair[1].getTracks().get(0) };
+			Cluster[] trackClusters = { pair[0].getClusters().get(0), pair[1].getClusters().get(0) };
+			
+			// Populate the cluster plots.
+			møctmElectronEnergy.fill(trackClusters[0].getEnergy());
+			møctmElectronEnergy.fill(trackClusters[1].getEnergy());
+			møctmEnergySum1D.fill(TriggerModule.getValueEnergySum(trackClusters));
+			møctmEnergySum2D.fill(trackClusters[0].getEnergy(), trackClusters[1].getEnergy());
+			møctmESumCoplanarity.fill(TriggerModule.getValueEnergySum(trackClusters), getCalculatedCoplanarity(trackClusters));
+			møctmTimeCoincidence.fill(TriggerModule.getClusterTime(trackClusters[0]) - TriggerModule.getClusterTime(trackClusters[1]));
+			møctmClusterPosition.fill(TriggerModule.getClusterXIndex(trackClusters[0]), TriggerModule.getClusterYIndex(trackClusters[0]));
+			møctmClusterPosition.fill(TriggerModule.getClusterXIndex(trackClusters[1]), TriggerModule.getClusterYIndex(trackClusters[1]));
+			
+			// Populate the momentum plots.
+			møctmInvariantMass.fill(getInvariantMass(pair));
+			møctmElectronMomentum.fill(pair[0].getMomentum().magnitude());
+			møctmElectronMomentum.fill(pair[1].getMomentum().magnitude());
+			møctmMomentumSum1D.fill(VecOp.add(pair[0].getMomentum(), pair[1].getMomentum()).magnitude());
+			møctmMomentumSum2D.fill(pair[0].getMomentum().magnitude(), pair[1].getMomentum().magnitude());
+			møctmTrackPosition.fill(TrackUtils.getTrackPositionAtEcal(tracks[0]).x(), TrackUtils.getTrackPositionAtEcal(tracks[0]).y());
+			møctmTrackPosition.fill(TrackUtils.getTrackPositionAtEcal(tracks[1]).x(), TrackUtils.getTrackPositionAtEcal(tracks[1]).y());
+			møctmPSumCoplanarity.fill(VecOp.add(pair[0].getMomentum(), pair[1].getMomentum()).magnitude(),
+					getCalculatedCoplanarity(new Track[] { pair[0].getTracks().get(0), pair[1].getTracks().get(0) }));
+		}
+		
+		// Produce trident cluster-track matched plots.
+		trctmInstancesInEvent.fill(tridents.size());
+		for(ReconstructedParticle[] pair : tridents) {
+			// Get the electron and positron tracks.
+			ReconstructedParticle electronTrack = pair[pair[0].getCharge() < 0 ? 0 : 1];
+			ReconstructedParticle positronTrack = pair[pair[0].getCharge() > 0 ? 0 : 1];
+			
+			// Get the track clusters.
+			Cluster electronCluster = electronTrack.getClusters().get(0);
+			Cluster positronCluster = positronTrack.getClusters().get(0);
+			Track[] tracks = { pair[0].getTracks().get(0), pair[1].getTracks().get(0) };
+			Cluster[] trackClusters = { pair[0].getClusters().get(0), pair[1].getClusters().get(0) };
+			
+			// Populate the cluster plots.
+			trctmElectronEnergy.fill(electronCluster.getEnergy());
+			trctmPositronEnergy.fill(positronCluster.getEnergy());
+			trctmEnergySum2D.fill(pair[0].getEnergy(), pair[1].getEnergy());
+			trctmEnergySum1D.fill(TriggerModule.getValueEnergySum(trackClusters));
+			trctmESumCoplanarity.fill(TriggerModule.getValueEnergySum(trackClusters), getCalculatedCoplanarity(trackClusters));
+			trctmTimeCoincidence.fill(TriggerModule.getClusterTime(trackClusters[0]) - TriggerModule.getClusterTime(trackClusters[1]));
+			trctmClusterPosition.fill(TriggerModule.getClusterXIndex(trackClusters[0]), TriggerModule.getClusterYIndex(trackClusters[0]));
+			trctmClusterPosition.fill(TriggerModule.getClusterXIndex(trackClusters[1]), TriggerModule.getClusterYIndex(trackClusters[1]));
+			
+			// Populate the momentum plots.
+			trctmInvariantMass.fill(getInvariantMass(pair));
+			trctmElectronMomentum.fill(electronTrack.getMomentum().magnitude());
+			trctmPositronMomentum.fill(positronTrack.getMomentum().magnitude());
+			trctmMomentumSum1D.fill(VecOp.add(pair[0].getMomentum(), pair[1].getMomentum()).magnitude());
+			trctmMomentumSum2D.fill(pair[0].getMomentum().magnitude(), pair[1].getMomentum().magnitude());
+			trctmTrackPosition.fill(TrackUtils.getTrackPositionAtEcal(tracks[0]).x(), TrackUtils.getTrackPositionAtEcal(tracks[0]).y());
+			trctmTrackPosition.fill(TrackUtils.getTrackPositionAtEcal(tracks[1]).x(), TrackUtils.getTrackPositionAtEcal(tracks[1]).y());
+			trctmPSumCoplanarity.fill(VecOp.add(pair[0].getMomentum(), pair[1].getMomentum()).magnitude(),
+					getCalculatedCoplanarity(new Track[] { pair[0].getTracks().get(0), pair[1].getTracks().get(0) }));
+		}
+		
+		// Produce trident vertexed plots.
+		trvtxInstancesInEvent.fill(tridentsVTX.size());
+		for(ReconstructedParticle[] pair : tridentsVTX) {
+			// Get the electron and positron tracks.
+			ReconstructedParticle electronTrack = pair[pair[0].getCharge() < 0 ? 0 : 1];
+			ReconstructedParticle positronTrack = pair[pair[0].getCharge() > 0 ? 0 : 1];
+			
+			// Get the track clusters.
+			Cluster electronCluster = electronTrack.getClusters().get(0);
+			Cluster positronCluster = positronTrack.getClusters().get(0);
+			Track[] tracks = { pair[0].getTracks().get(0), pair[1].getTracks().get(0) };
+			Cluster[] trackClusters = { pair[0].getClusters().get(0), pair[1].getClusters().get(0) };
+			
+			// Populate the cluster plots.
+			trvtxElectronEnergy.fill(electronCluster.getEnergy());
+			trvtxPositronEnergy.fill(positronCluster.getEnergy());
+			trvtxEnergySum2D.fill(pair[0].getEnergy(), pair[1].getEnergy());
+			trvtxEnergySum1D.fill(TriggerModule.getValueEnergySum(trackClusters));
+			trvtxESumCoplanarity.fill(TriggerModule.getValueEnergySum(trackClusters), getCalculatedCoplanarity(trackClusters));
+			trvtxTimeCoincidence.fill(TriggerModule.getClusterTime(trackClusters[0]) - TriggerModule.getClusterTime(trackClusters[1]));
+			trvtxClusterPosition.fill(TriggerModule.getClusterXIndex(trackClusters[0]), TriggerModule.getClusterYIndex(trackClusters[0]));
+			trvtxClusterPosition.fill(TriggerModule.getClusterXIndex(trackClusters[1]), TriggerModule.getClusterYIndex(trackClusters[1]));
+			
+			// Populate the momentum plots.
+			trvtxInvariantMass.fill(getInvariantMass(pair));
+			trvtxElectronMomentum.fill(electronTrack.getMomentum().magnitude());
+			trvtxPositronMomentum.fill(positronTrack.getMomentum().magnitude());
+			trvtxMomentumSum1D.fill(VecOp.add(pair[0].getMomentum(), pair[1].getMomentum()).magnitude());
+			trvtxMomentumSum2D.fill(pair[0].getMomentum().magnitude(), pair[1].getMomentum().magnitude());
+			trvtxTrackPosition.fill(TrackUtils.getTrackPositionAtEcal(tracks[0]).x(), TrackUtils.getTrackPositionAtEcal(tracks[0]).y());
+			trvtxTrackPosition.fill(TrackUtils.getTrackPositionAtEcal(tracks[1]).x(), TrackUtils.getTrackPositionAtEcal(tracks[1]).y());
+			trvtxPSumCoplanarity.fill(VecOp.add(pair[0].getMomentum(), pair[1].getMomentum()).magnitude(),
+					getCalculatedCoplanarity(new Track[] { pair[0].getTracks().get(0), pair[1].getTracks().get(0) }));
+		}
+		
+		// Produce the Møller vertexed plots.
+		møvtxInstancesInEvent.fill(møllersVTX.size());
+		RelationalTable<?, ?> hitToStrips = TrackUtils.getHitToStripsTable(event);
+		RelationalTable<?, ?> hitToRotated = TrackUtils.getHitToRotatedTable(event);
+		for(ReconstructedParticle pair[] : møllersVTX) {
+			// Get the tracks and track times.
+			Track[] tracks = { pair[0].getTracks().get(0), pair[1].getTracks().get(0) };
+			double times[] = {
+					TrackUtils.getTrackTime(tracks[0], hitToStrips, hitToRotated),
+					TrackUtils.getTrackTime(tracks[1], hitToStrips, hitToRotated)	
+			};
+			
+			// Fill the plots.
+			møvtxTimeCoincidence.fill(times[0] - times[1]);
+			møvtxInvariantMass.fill(getInvariantMass(pair));
+			møvtxElectronMomentum.fill(pair[0].getMomentum().magnitude());
+			møvtxElectronMomentum.fill(pair[1].getMomentum().magnitude());
+			møvtxMomentumSum1D.fill(VecOp.add(pair[0].getMomentum(), pair[1].getMomentum()).magnitude());
+			møvtxMomentumSum2D.fill(pair[0].getMomentum().magnitude(), pair[1].getMomentum().magnitude());
+			møvtxTrackPosition.fill(TrackUtils.getTrackPositionAtEcal(tracks[0]).x(), TrackUtils.getTrackPositionAtEcal(tracks[0]).y());
+			møvtxTrackPosition.fill(TrackUtils.getTrackPositionAtEcal(tracks[1]).x(), TrackUtils.getTrackPositionAtEcal(tracks[1]).y());
+			møvtxPSumCoplanarity.fill(VecOp.add(pair[0].getMomentum(), pair[1].getMomentum()).magnitude(),
+					getCalculatedCoplanarity(new Track[] { pair[0].getTracks().get(0), pair[1].getTracks().get(0) }));
+		}
+		
+		// Produce the Møller track-only plots.
+		møgblInstancesInEvent.fill(møllersGBL.size());
+		for(ReconstructedParticle pair[] : møllersGBL) {
+			// Get the tracks and track times.
+			Track[] tracks = { pair[0].getTracks().get(0), pair[1].getTracks().get(0) };
+			double times[] = {
+					TrackUtils.getTrackTime(tracks[0], hitToStrips, hitToRotated),
+					TrackUtils.getTrackTime(tracks[1], hitToStrips, hitToRotated)	
+			};
+			
+			// Fill the plots.
+			møgblTimeCoincidence.fill(times[0] - times[1]);
+			møgblInvariantMass.fill(getInvariantMass(pair));
+			møgblElectronMomentum.fill(pair[0].getMomentum().magnitude());
+			møgblElectronMomentum.fill(pair[1].getMomentum().magnitude());
+			møgblMomentumSum1D.fill(VecOp.add(pair[0].getMomentum(), pair[1].getMomentum()).magnitude());
+			møgblMomentumSum2D.fill(pair[0].getMomentum().magnitude(), pair[1].getMomentum().magnitude());
+			møgblTrackPosition.fill(TrackUtils.getTrackPositionAtEcal(tracks[0]).x(), TrackUtils.getTrackPositionAtEcal(tracks[0]).y());
+			møgblTrackPosition.fill(TrackUtils.getTrackPositionAtEcal(tracks[1]).x(), TrackUtils.getTrackPositionAtEcal(tracks[1]).y());
+			møgblPSumCoplanarity.fill(VecOp.add(pair[0].getMomentum(), pair[1].getMomentum()).magnitude(),
+					getCalculatedCoplanarity(new Track[] { pair[0].getTracks().get(0), pair[1].getTracks().get(0) }));
+		}
+		
+		// Produce track-only trident plots.
+		trgblInstancesInEvent.fill(tridentsGBL.size());
+		for(ReconstructedParticle[] pair : tridentsGBL) {
+			// Get the tracks and track times.
+			Track[] tracks = { pair[0].getTracks().get(0), pair[1].getTracks().get(0) };
+			double times[] = {
+					TrackUtils.getTrackTime(tracks[0], hitToStrips, hitToRotated),
+					TrackUtils.getTrackTime(tracks[1], hitToStrips, hitToRotated)	
+			};
+			
+			// Get the positron and the electron.
+			ReconstructedParticle positron = pair[0].getCharge() > 0 ? pair[0] : pair[1];
+			ReconstructedParticle electron = pair[0].getCharge() < 0 ? pair[0] : pair[1];
+			
+			// Fill the plots.
+			trgblTimeCoincidence.fill(times[0] - times[1]);
+			trgblInvariantMass.fill(getInvariantMass(pair));
+			trgblElectronMomentum.fill(electron.getMomentum().magnitude());
+			trgblPositronMomentum.fill(positron.getMomentum().magnitude());
+			trgblMomentumSum1D.fill(VecOp.add(pair[0].getMomentum(), pair[1].getMomentum()).magnitude());
+			trgblMomentumSum2D.fill(pair[0].getMomentum().magnitude(), pair[1].getMomentum().magnitude());
+			trgblTrackPosition.fill(TrackUtils.getTrackPositionAtEcal(tracks[0]).x(), TrackUtils.getTrackPositionAtEcal(tracks[0]).y());
+			trgblTrackPosition.fill(TrackUtils.getTrackPositionAtEcal(tracks[1]).x(), TrackUtils.getTrackPositionAtEcal(tracks[1]).y());
+			trgblPSumCoplanarity.fill(VecOp.add(pair[0].getMomentum(), pair[1].getMomentum()).magnitude(),
+					getCalculatedCoplanarity(new Track[] { pair[0].getTracks().get(0), pair[1].getTracks().get(0) }));
+		}
+	}
+	
+	public void setCheckSVT(boolean state) {
+		checkSVT = state;
+	}
+	
+	public void setCheckTriggerTimeWindow(boolean state) {
+		checkTriggerTimeWindow = state;
+	}
+	
+	/**
+	 * Gets a list of all possible GBL top/bottom track pairs. These
+	 * tracks are not guaranteed to have a matched cluster.
+	 * @param trackList - A list of all possible tracks.
+	 * @return Returns a list of track pairs.
+	 */
+	private static final List<ReconstructedParticle[]> getTopBottomTracksGBL(List<ReconstructedParticle> trackList) {
+		// Separate the tracks into top and bottom tracks based on
+		// the value of tan(Λ). Use only GBL tracks to avoid track
+		// duplication.
+		List<ReconstructedParticle> topTracks = new ArrayList<ReconstructedParticle>();
+		List<ReconstructedParticle> botTracks = new ArrayList<ReconstructedParticle>();
+		trackLoop:
+		for(ReconstructedParticle track : trackList) {
+			// Require that the ReconstructedParticle contain an actual
+			// Track object.
+			if(track.getTracks().isEmpty()) {
+				continue trackLoop;
+			}
+			
+			// Ignore tracks that are not GBL tracks.
+			if(!TrackType.isGBL(track.getType())) {
+				continue trackLoop;
+			}
+			
+			// If the above tests pass, the ReconstructedParticle has
+			// a track and is also a GBL track. Separate it into either
+			// a top or a bottom track based on its tan(Λ) value.
+			if(track.getTracks().get(0).getTrackStates().get(0).getTanLambda() > 0) {
+				topTracks.add(track);
+			} else {
+				botTracks.add(track);
+			}
+		}
+		
+		// Form all top/bottom pairs with the unique tracks.
+		List<ReconstructedParticle[]> pairList = new ArrayList<ReconstructedParticle[]>();
+		for(ReconstructedParticle topTrack : topTracks) {
+			for(ReconstructedParticle botTrack : botTracks) {
+				pairList.add(new ReconstructedParticle[] { topTrack, botTrack });
+			}
+		}
+		
+		// Return the result.
+		return pairList;
+	}
+	
+	/**
+	 * Produces pairs of tracks. The track pairs are required to be
+	 * matched to a cluster and the associated clusters must form a
+	 * top/bottom pair. If more than one track points to the same
+	 * cluster, only the first track is retained.
+	 * @param trackList - A list of all tracks.
+	 * @return Returns a list of track pairs meeting the aforementioned
+	 * conditions.
+	 */
+	private static final List<ReconstructedParticle[]> getTopBottomTracksCTMatched(List<ReconstructedParticle> trackList) {
+		// Track clusters that have already been seen to prevent clusters
+		// that have duplicate tracks from reappearing.
+		Set<Cluster> clusterSet = new HashSet<Cluster>();
+		
+		// Separate the tracks into top and bottom tracks based on
+		// the track cluster. Filter out tracks with no clusters.
+		List<ReconstructedParticle> topTracks = new ArrayList<ReconstructedParticle>();
+		List<ReconstructedParticle> botTracks = new ArrayList<ReconstructedParticle>();
+		trackLoop:
+		for(ReconstructedParticle track : trackList) {
+			// Check if the track has a cluster. If not, skip it.
+			if(track.getClusters().isEmpty()) {
+				continue trackLoop;
+			}
+			
+			// If the track doesn't have actual tracks, skip it.
+			if(track.getTracks().isEmpty()) {
+				continue trackLoop;
+			}
+			
+			// Check if the track cluster has already seen.
+			Cluster trackCluster = track.getClusters().get(0);
+			if(clusterSet.contains(trackCluster)) {
+				continue trackLoop;
+			}
+			
+			// If the track has a unique cluster, add it to the proper
+			// list based on the cluster y-index.
+			clusterSet.add(trackCluster);
+			if(TriggerModule.getClusterYIndex(trackCluster) > 0) {
+				topTracks.add(track);
+			} else {
+				botTracks.add(track);
+			}
+		}
+		
+		// Form all top/bottom pairs with the unique tracks.
+		List<ReconstructedParticle[]> pairList = new ArrayList<ReconstructedParticle[]>();
+		for(ReconstructedParticle topTrack : topTracks) {
+			for(ReconstructedParticle botTrack : botTracks) {
+				pairList.add(new ReconstructedParticle[] { topTrack, botTrack });
+			}
+		}
+		
+		// Return the result.
+		return pairList;
+	}
+	
+	private final List<ReconstructedParticle[]> getTridentTracksVertexed(List<ReconstructedParticle> candidateList) {
+		// Store the set of track pairs that meet the trident condition.
+		List<ReconstructedParticle[]> tridentTracks = new ArrayList<ReconstructedParticle[]>();
+		
+		// Loop over the filtered pair list and apply the trident
+		// condition test.
+		tridentLoop:
+		for(ReconstructedParticle candidate : candidateList) {
+			// Require that the vertex fit have a X^2 value of less
+			// than 25.
+			trvtxChiSquared.fill(candidate.getStartVertex().getChi2());
+			if(candidate.getStartVertex().getChi2() > 10) {
+				continue tridentLoop;
+			}
+			
+			// Make sure that each particle is track/cluster matched.
+			ReconstructedParticle[] pair = {
+					candidate.getParticles().get(0),
+					candidate.getParticles().get(1)
+			};
+			if(pair[0].getTracks().isEmpty() || pair[0].getClusters().isEmpty()) {
+				continue tridentLoop;
+			}
+			if(pair[1].getTracks().isEmpty() || pair[1].getClusters().isEmpty()) {
+				continue tridentLoop;
+			}
+			
+			// Make sure there is a top/bottom cluster pair.
+			Cluster[] trackClusters = { pair[0].getClusters().get(0), pair[1].getClusters().get(0) };
+			boolean hasTop = TriggerModule.getClusterYIndex(trackClusters[0]) > 0 || TriggerModule.getClusterYIndex(trackClusters[1]) > 0;
+			boolean hasBot = TriggerModule.getClusterYIndex(trackClusters[0]) < 0 || TriggerModule.getClusterYIndex(trackClusters[1]) < 0;
+			if(!hasTop || !hasBot) {
+				continue tridentLoop;
+			}
+			
+			// There must be one positive and one negative track.
+			ReconstructedParticle electron = null;
+			ReconstructedParticle positron = null;
+			if(pair[0].getCharge() > 0) { positron = pair[0]; }
+			else if(pair[1].getCharge() > 0) { positron = pair[1]; }
+			if(pair[0].getCharge() < 0) { electron = pair[0]; }
+			else if(pair[1].getCharge() < 0) { electron = pair[1]; }
+			if(electron == null || positron == null) {
+				continue tridentLoop;
+			}
+			
+			// Make sure that the clusters are not the same. This should
+			// not actually ever be possible...
+			if(pair[0].getClusters().get(0) == pair[1].getClusters().get(0)) {
+				continue tridentLoop;
+			}
+			
+			// The clusters must within a limited time window.
+			if(TriggerModule.getValueTimeCoincidence(trackClusters) > timeCoincidence) {
+				continue tridentLoop;
+			}
+			
+			// Require that the electron in the pair have an energy
+			// below the elastic threshold to exclude elastic electrons.
+			if(electron.getMomentum().magnitude() >= elasticThreshold) {
+				continue tridentLoop;
+			}
+			
+			// Require that all clusters occur within the trigger time
+			// window to exclude accidentals.
+			if(checkTriggerTimeWindow) {
+				if(!inTriggerWindow(trackClusters[0]) || !inTriggerWindow(trackClusters[1])) {
+					continue tridentLoop;
+				}
+			}
+			
+			// If all the above conditions are met, the pair is to be
+			// considered a trident pair. Add it to the list.
+			tridentTracks.add(pair);
+		}
+		
+		// Return the list of pairs that passed the condition.
+		return tridentTracks;
+	}
+	
+	private final List<ReconstructedParticle[]> getTridentClustersGBL(List<ReconstructedParticle[]> pairList, List<Cluster[]> clusterList, EventHeader event) {
+		// Store the set of track pairs that meet the trident condition.
+		List<ReconstructedParticle[]> tridentTracks = new ArrayList<ReconstructedParticle[]>();
+		
+		// Extract track relational tables from the event object.
+		RelationalTable<?, ?> hitToStrips = TrackUtils.getHitToStripsTable(event);
+		RelationalTable<?, ?> hitToRotated = TrackUtils.getHitToRotatedTable(event);
+		
+		// Tracks will not be considered for trident analysis unless there
+		// is at least one top/bottom cluster pair within the time window.
+		boolean passesClusterCondition = false;
+		tridentClusterLoop:
+		for(Cluster[] pair : clusterList) {
+			// Ignore clusters that are too far apart temporally.
+			if(TriggerModule.getValueTimeCoincidence(pair) > timeCoincidence) {
+				continue tridentClusterLoop;
+			}
+			
+			// Require that the cluster pair be top/bottom.
+			boolean hasTop = TriggerModule.getClusterYIndex(pair[0]) > 0 || TriggerModule.getClusterYIndex(pair[1]) > 0;
+			boolean hasBot = TriggerModule.getClusterYIndex(pair[0]) < 0 || TriggerModule.getClusterYIndex(pair[1]) < 0;
+			if(!hasTop || !hasBot) {
+				continue tridentClusterLoop;
+			}
+			
+			// If the cluster passes, mark that it has done so and skip
+			// the rest. Only one pair need pass.
+			passesClusterCondition = true;
+			break tridentClusterLoop;
+		}
+		
+		// If no cluster pair passed the cluster condition, no tracks
+		// are allowed to pass either.
+		if(!passesClusterCondition) {
+			return tridentTracks;
+		}
+		
+		// Next, check the track pair list. A track pair must have a
+		// positive and a negative track and must also be within the
+		// time coincidence window.
+		tridentTrackLoop:
+		for(ReconstructedParticle[] pair : pairList) {
+			// Check that there is at least one positive and one negative
+			// track in the pair.
+			boolean hasPositive = pair[0].getCharge() > 0 || pair[1].getCharge() > 0;
+			boolean hasNegative = pair[0].getCharge() < 0 || pair[1].getCharge() < 0;
+			if(!hasPositive || !hasNegative) {
+				break tridentTrackLoop;
+			}
+			
+			// Check that the track pair passes the time cut.
+			double times[] = {
+				TrackUtils.getTrackTime(pair[0].getTracks().get(0), hitToStrips, hitToRotated),
+				TrackUtils.getTrackTime(pair[1].getTracks().get(0), hitToStrips, hitToRotated)	
+			};
+			
+			if(Math.abs(times[0] - times[1]) > timeCoincidence) {
+				continue tridentTrackLoop;
+			}
+			
+			// Require that the negative track have less than the
+			// elastic threshold momentum to exclude elastic electrons.
+			if(pair[0].getCharge() < 0 && pair[0].getMomentum().magnitude() > elasticThreshold
+					|| pair[1].getCharge() < 0 && pair[1].getMomentum().magnitude() > elasticThreshold) {
+				continue tridentTrackLoop;
+			}
+			
+			// If the track passes both, it is considered a trident pair.
+			tridentTracks.add(pair);
+		}
+		
+		// Return the resultant pairs.
+		return tridentTracks;
+	}
+	
+	/**
+	 * Gets a list track pairs that meet the trident condition defined
+	 * using tracks with matched calorimeter clusters. A pair meets the
+	 * cluster/track matched trident condition is it meets the following:
+	 * <ul><li>Both tracks have matched clusters.</li>
+	 * <li>Has one positive track.</li>
+	 * <li>Has one negative track.</li>
+	 * <li>Clusters have a time coincidence of 2.5 ns or less.</li>
+	 * <li>The electron momentum is below 900 MeV.</li></ul>
+	 * @param pairList - A <code>List</code> collection of parameterized
+	 * type <code>ReconstructedParticle[]</code> containing all valid
+	 * top/bottom pairs of tracks with matched clusters. These will be
+	 * tested to see if they meet the process criteria.
+	 * @return Returns a list containing pairs of tracks that meet the
+	 * trident condition.
+	 */
+	private final List<ReconstructedParticle[]> getTridentTracksCTMatched(List<ReconstructedParticle[]> pairList) {
+		// Store the set of track pairs that meet the trident condition.
+		List<ReconstructedParticle[]> tridentTracks = new ArrayList<ReconstructedParticle[]>();
+		
+		// Loop over the filtered pair list and apply the trident
+		// condition test.
+		tridentLoop:
+		for(ReconstructedParticle[] pair : pairList) {
+			// There must be one positive and one negative track.
+			ReconstructedParticle electron = null;
+			ReconstructedParticle positron = null;
+			if(pair[0].getCharge() > 0) { positron = pair[0]; }
+			else if(pair[1].getCharge() > 0) { positron = pair[1]; }
+			if(pair[0].getCharge() < 0) { electron = pair[0]; }
+			else if(pair[1].getCharge() < 0) { electron = pair[1]; }
+			if(electron == null || positron == null) {
+				continue tridentLoop;
+			}
+			
+			// Make sure that the clusters are not the same. This should
+			// not actually ever be possible...
+			if(pair[0].getClusters().get(0) == pair[1].getClusters().get(0)) {
+				continue tridentLoop;
+			}
+			
+			// The clusters must within a limited time window.
+			Cluster[] trackClusters = { pair[0].getClusters().get(0), pair[1].getClusters().get(0) };
+			if(TriggerModule.getValueTimeCoincidence(trackClusters) > timeCoincidence) {
+				continue tridentLoop;
+			}
+			
+			// Require that the electron in the pair have an energy
+			// below the elastic threshold to exclude elastic electrons.
+			if(electron.getMomentum().magnitude() >= elasticThreshold) {
+				continue tridentLoop;
+			}
+			
+			// Require that all clusters occur within the trigger time
+			// window to exclude accidentals.
+			if(checkTriggerTimeWindow) {
+				if(!inTriggerWindow(trackClusters[0]) || !inTriggerWindow(trackClusters[1])) {
+					continue tridentLoop;
+				}
+			}
+			
+			// If all the above conditions are met, the pair is to be
+			// considered a trident pair. Add it to the list.
+			tridentTracks.add(pair);
+		}
+		
+		// Return the list of pairs that passed the condition.
+		return tridentTracks;
+	}
+	
+	private final List<ReconstructedParticle[]> getMøllerTracksGBL(List<ReconstructedParticle[]> pairList, EventHeader event) {
+		// Store the set of track pairs that meet the Møller condition.
+		List<ReconstructedParticle[]> møllerTracks = new ArrayList<ReconstructedParticle[]>();
+		
+		// Extract track relational tables from the event object.
+		RelationalTable<?, ?> hitToStrips = TrackUtils.getHitToStripsTable(event);
+		RelationalTable<?, ?> hitToRotated = TrackUtils.getHitToRotatedTable(event);
+		
+		// Loop over the filtered pair list and apply the Møller
+		// condition test.
+		møllerLoop:
+		for(ReconstructedParticle[] pair : pairList) {
+			// Both tracks must be negatively charged.
+			if(pair[0].getCharge() > 0 || pair[1].getCharge() > 0) {
+				continue møllerLoop;
+			}
+			
+			// The clusters must within a limited time window.
+			double times[] = {
+				TrackUtils.getTrackTime(pair[0].getTracks().get(0), hitToStrips, hitToRotated),
+				TrackUtils.getTrackTime(pair[1].getTracks().get(0), hitToStrips, hitToRotated)	
+			};
+			
+			if(Math.abs(times[0] - times[1]) > timeCoincidence) {
+				continue møllerLoop;
+			}
+			
+			// Require that the electrons in the pair have energies
+			// below the elastic threshold to exclude said electrons.
+			if(pair[0].getMomentum().magnitude() > elasticThreshold || pair[1].getMomentum().magnitude() > elasticThreshold) {
+				continue møllerLoop;
+			}
+			
+			// Require that the energy of the pair be within a range
+			// that is sufficiently "Møller-like."
+			double momentumSum = VecOp.add(pair[0].getMomentum(), pair[1].getMomentum()).magnitude();
+			if(momentumSum < møllerLowerRange || momentumSum > møllerUpperRange) {
+				continue møllerLoop;
+			}
+			
+			// If all the above conditions are met, the pair is to be
+			// considered a trident pair. Add it to the list.
+			møllerTracks.add(pair);
+		}
+		
+		// Return the list of pairs that passed the condition.
+		return møllerTracks;
+	}
+	
+	private final List<ReconstructedParticle[]> getMøllerTracksVertexed(List<ReconstructedParticle> candidateList) {
+		// Store the set of track pairs that meet the Møller condition.
+		List<ReconstructedParticle[]> møllerTracks = new ArrayList<ReconstructedParticle[]>();
+		
+		// Loop over the candidate list and apply the Møller cuts.
+		møllerLoop:
+		for(ReconstructedParticle candidate : candidateList) {
+			// Require that the vertex fit have a X^2 value of less
+			// than 25.
+			if(candidate.getStartVertex().getChi2() > 10) {
+				continue møllerLoop;
+			}
+			
+			// Make sure that each particle is track/cluster matched.
+			ReconstructedParticle[] pair = {
+					candidate.getParticles().get(0),
+					candidate.getParticles().get(1)
+			};
+			if(pair[0].getTracks().isEmpty() || pair[0].getClusters().isEmpty()) {
+				continue møllerLoop;
+			}
+			if(pair[1].getTracks().isEmpty() || pair[1].getClusters().isEmpty()) {
+				continue møllerLoop;
+			}
+			
+			// Make sure there is a top/bottom cluster pair.
+			Cluster[] trackClusters = { pair[0].getClusters().get(0), pair[1].getClusters().get(0) };
+			boolean hasTop = TriggerModule.getClusterYIndex(trackClusters[0]) > 0 || TriggerModule.getClusterYIndex(trackClusters[1]) > 0;
+			boolean hasBot = TriggerModule.getClusterYIndex(trackClusters[0]) < 0 || TriggerModule.getClusterYIndex(trackClusters[1]) < 0;
+			if(!hasTop || !hasBot) {
+				continue møllerLoop;
+			}
+			
+			// Require that the clusters be within the time coincidence.
+			if(TriggerModule.getValueTimeCoincidence(trackClusters) > timeCoincidence) {
+				continue møllerLoop;
+			}
+			
+			// Require that both tracks have less than the elastic
+			// threshold in momentum.
+			if(pair[0].getMomentum().magnitude() > elasticThreshold || pair[1].getMomentum().magnitude() > elasticThreshold) {
+				continue møllerLoop;
+			}
+			
+			
+			
+			
+			// Variable definitions
+			double[] mom1 = pair[0].getMomentum().v();
+			double px1 = mom1[0];
+			double py1 = mom1[1];
+			double pz1 = mom1[2];
+			
+			double unrot_px1 = px1*Math.cos(-0.0305) + pz1*Math.sin(-0.0305);
+			double unrot_pz1 = pz1*Math.cos(-0.0305) - px1*Math.sin(-0.0305);
+			
+			double unrot_theta1 = Math.atan2(Math.sqrt(unrot_px1*unrot_px1 + py1*py1),unrot_pz1);
+			double TrackE1 = Math.sqrt(Math.sqrt(px1*px1 + py1*py1 + pz1*pz1)*Math.sqrt(px1*px1 + py1*py1 + pz1*pz1) + 0.0005109989*0.0005109989);
+			
+			
+			double[] mom2 = pair[1].getMomentum().v();
+			double px2 = mom2[0];
+			double py2 = mom2[1];
+			double pz2 = mom2[2];
+			
+			double unrot_px2 = px2*Math.cos(-0.0305) + pz2*Math.sin(-0.0305);
+			double unrot_pz2 = pz2*Math.cos(-0.0305) - px2*Math.sin(-0.0305);
+			
+			double unrot_theta2 = Math.atan2(Math.sqrt(unrot_px2*unrot_px2 + py2*py2),unrot_pz2);
+			double TrackE2 = Math.sqrt(Math.sqrt(px2*px2 + py2*py2 + pz2*pz2)*Math.sqrt(px2*px2 + py2*py2 + pz2*pz2) + 0.0005109989*0.0005109989);
+			
+			
+			// Ultimate Moller Cut
+			if((Math.sin(unrot_theta1/2)*Math.sin(unrot_theta2/2)<=(1+0.20)*0.5109989/(2*1056) && Math.sin(unrot_theta1/2)*Math.sin(unrot_theta2/2)>=(1-0.20)*0.5109989/(2*1056)) ) {
+				if( (TrackE1+TrackE2<=(1+0.10)*1.056 && TrackE1+TrackE2>=(1-0.10)*1.056) ) {
+					
+					
+					
+					
+					møllerTracks.add(pair);
+				}
+			}
+			
+			
+			
+			
+			/*
+			double[] trackE = new double[2];
+			double[] unrotTheta = new double[2];
+			double[][] unrotP = new double[2][3];
+			for(int i = 0; i < pair.length; i++) {
+				unrotP[i][0] = pair[i].getMomentum().x() * Math.cos(BEAM_ROTATION) + pair[i].getMomentum().z() * Math.sin(BEAM_ROTATION);
+				unrotP[i][2] = pair[i].getMomentum().z() * Math.cos(BEAM_ROTATION) - pair[i].getMomentum().x() * Math.sin(BEAM_ROTATION);
+				unrotTheta[i] = Math.atan2(Math.sqrt(unrotP[i][0] * unrotP[i][0] + pair[0].getMomentum().y() * pair[i].getMomentum().y()), unrotP[0][2]);
+				trackE[i] = Math.sqrt(pair[i].getMomentum().magnitudeSquared() + ELECTRON_MASS_2);
+			}
+			
+			// Perform the track angle threshold cuts.
+			double unrotatedTheta = Math.sin(unrotTheta[0] / 2) * Math.sin(unrotTheta[1] / 2);
+			if((unrotatedTheta <= MØLLER_ANGLE_THRESHOLD[HIGH] && unrotatedTheta >= MØLLER_ANGLE_THRESHOLD[LOW])) {
+				// Perform the track energy sum threshold cuts.
+				double trackESum = trackE[0] + trackE[1];
+				if((trackESum <= MØLLER_ENERGY_THRESHOLD[HIGH] && trackESum >= MØLLER_ENERGY_THRESHOLD[LOW])) {
+					// If a pair passes all the Møller cuts, then it
+					// is a Møller pair.
+					møllerTracks.add(pair);
+				}
+			}
+			*/
+		}
+		
+		// Return the Møller list.
+		return møllerTracks;
+	}
+	
+	/**
+	 * Gets a list track pairs that meet the Møller condition defined
+	 * using tracks with matched calorimeter clusters. A pair meets the
+	 * cluster/track matched Møller condition is it meets the following:
+	 * <ul><li>Both tracks have matched clusters.</li>
+	 * <li>Both tracks are negative.</li>
+	 * <li>Clusters have a time coincidence of 2.5 ns or less.</li>
+	 * <li>The electron momenta are below 900 MeV.</li>
+	 * <li>The momentum sum of the tracks is in the range <code>800 MeV
+	 * ≤ p1 + p2 ≤ 1500 MeV</li></ul>
+	 * @param pairList - A <code>List</code> collection of parameterized
+	 * type <code>ReconstructedParticle[]</code> containing all valid
+	 * top/bottom pairs of tracks with matched clusters. These will be
+	 * tested to see if they meet the process criteria.
+	 * @return Returns a list containing pairs of tracks that meet the
+	 * Møller condition.
+	 */
+	private final List<ReconstructedParticle[]> getMøllerTracksCTMatched(List<ReconstructedParticle[]> pairList) {
+		// Store the set of track pairs that meet the Møller condition.
+		List<ReconstructedParticle[]> møllerTracks = new ArrayList<ReconstructedParticle[]>();
+		
+		// Loop over the filtered pair list and apply the Møller
+		// condition test.
+		møllerLoop:
+		for(ReconstructedParticle[] pair : pairList) {
+			// Both tracks must be negatively charged.
+			if(pair[0].getCharge() > 0 || pair[1].getCharge() > 0) {
+				continue møllerLoop;
+			}
+			
+			// The clusters must within a limited time window.
+			Cluster[] trackClusters = { pair[0].getClusters().get(0), pair[1].getClusters().get(0) };
+			if(TriggerModule.getValueTimeCoincidence(trackClusters) > timeCoincidence) {
+				continue møllerLoop;
+			}
+			
+			// Require that the electrons in the pair have energies
+			// below the elastic threshold to exclude said electrons.
+			if(pair[0].getMomentum().magnitude() > elasticThreshold || pair[1].getMomentum().magnitude() > elasticThreshold) {
+				continue møllerLoop;
+			}
+			
+			// Require that the energy of the pair be within a range
+			// that is sufficiently "Møller-like."
+			double momentumSum = VecOp.add(pair[0].getMomentum(), pair[1].getMomentum()).magnitude();
+			if(momentumSum < møllerLowerRange || momentumSum > møllerUpperRange) {
+				continue møllerLoop;
+			}
+			
+			// Require that all clusters occur within the trigger time
+			// window to exclude accidentals.
+			if(checkTriggerTimeWindow) {
+				if(!inTriggerWindow(trackClusters[0]) || !inTriggerWindow(trackClusters[1])) {
+					continue møllerLoop;
+				}
+			}
+			
+			// If all the above conditions are met, the pair is to be
+			// considered a trident pair. Add it to the list.
+			møllerTracks.add(pair);
+		}
+		
+		// Return the list of pairs that passed the condition.
+		return møllerTracks;
+	}
+	
+	/**
+	 * Calculates the approximate invariant mass for a pair of tracks
+	 * from their momentum. This assumes that the particles are either
+	 * electrons or positrons, and thusly have a sufficiently small
+	 * mass term that it can be safely excluded.
+	 * @param pair - The track pair for which to calculate the invariant
+	 * mass.
+	 * @return Returns the approximate invariant mass in units of GeV.
+	 */
+	private static final double getInvariantMass(ReconstructedParticle[] pair) {
+		// Get the momentum squared.
+		double p2 = Math.pow(pair[0].getMomentum().magnitude() + pair[1].getMomentum().magnitude(), 2);
+		
+		// Get the remaining terms.
+		double xPro = pair[0].getMomentum().x() + pair[1].getMomentum().x();
+		double yPro = pair[0].getMomentum().y() + pair[1].getMomentum().y();
+		double zPro = pair[0].getMomentum().z() + pair[1].getMomentum().z();
+		
+		// Calculate the invariant mass.
+		return Math.sqrt(p2 - Math.pow(xPro, 2) - Math.pow(yPro, 2) - Math.pow(zPro, 2));
+	}
+	
+	/**
+	 * Calculates the coplanarity angle between two points, specified
+	 * by a double array. The array must be of the format (x, y, z).
+	 * @param position - The first position array.
+	 * @param otherPosition - The second position array.
+	 * @return Returns the coplanarity angle between the points in units
+	 * of degrees.
+	 */
+	private static final double getCalculatedCoplanarity(double[] position, double[] otherPosition) {
+		// Define the x- and y-coordinates of the clusters as well as
+		// calorimeter center.
+		final double ORIGIN_X = 42.52;
+		double x[] = { position[0], otherPosition[0] };
+		double y[] = { position[1], otherPosition[1] };
+		
         // Get the cluster angles.
         double[] clusterAngle = new double[2];
         for(int i = 0; i < 2; i++) {

Modified: java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/FormattedPlot.java
 =============================================================================
--- java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/FormattedPlot.java	(original)
+++ java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/FormattedPlot.java	Tue Sep 27 08:50:14 2016
@@ -1,25 +1,25 @@
 package org.hps.users.kmccarty.plots;
 
 public abstract class FormattedPlot {
-    private final String xAxis;
-    private final String yAxis;
-    private final String plotName;
-    
-    public FormattedPlot(String xAxis, String yAxis, String plotName) {
-        this.xAxis = xAxis;
-        this.yAxis = yAxis;
-        this.plotName = plotName;
-    }
-    
-    public String getPlotName() {
-        return plotName;
-    }
-    
-    public String getXAxisName() {
-        return xAxis;
-    }
-    
-    public String getYAxisName() {
-        return yAxis;
-    }
+	private final String xAxis;
+	private final String yAxis;
+	private final String plotName;
+	
+	public FormattedPlot(String xAxis, String yAxis, String plotName) {
+		this.xAxis = xAxis;
+		this.yAxis = yAxis;
+		this.plotName = plotName;
+	}
+	
+	public String getPlotName() {
+		return plotName;
+	}
+	
+	public String getXAxisName() {
+		return xAxis;
+	}
+	
+	public String getYAxisName() {
+		return yAxis;
+	}
 }

Modified: java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/FormattedPlot1D.java
 =============================================================================
--- java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/FormattedPlot1D.java	(original)
+++ java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/FormattedPlot1D.java	Tue Sep 27 08:50:14 2016
@@ -1,41 +1,136 @@
 package org.hps.users.kmccarty.plots;
 
+import java.util.HashSet;
+import java.util.Set;
+
 import org.hps.users.kmccarty.plots.PlotsFormatter.ColorStyle;
+import org.hps.users.kmccarty.plots.PlotsFormatter.DisplayStyle;
 
 import hep.aida.IHistogram1D;
 
 public class FormattedPlot1D extends FormattedPlot {
-    private final ColorStyle style;
-    private final IHistogram1D plot;
-    private final double axisRange;
-    
-    public FormattedPlot1D(IHistogram1D plot, ColorStyle style, String xAxis, String yAxis, String plotName) {
-        super(xAxis, yAxis, plotName);
-        this.plot = plot;
-        this.style = style;
-        this.axisRange = -1;
-    }
-    
-    public FormattedPlot1D(IHistogram1D plot, ColorStyle style, String xAxis, String yAxis, String plotName, double axisRange) {
-        super(xAxis, yAxis, plotName);
-        this.plot = plot;
-        this.style = style;
-        this.axisRange = axisRange;
-    }
-    
-    public IHistogram1D getPlot() {
-        return plot;
-    }
-    
-    public ColorStyle getColorStyle() {
-        return style;
-    }
-    
-    public boolean definesAxisRange() {
-        return axisRange != -1;
-    }
-    
-    public double getAxisRange() {
-        return axisRange;
-    }
+	private final double axisMin;
+	private final double axisMax;
+	private final ColorStyle[] styles;
+	private final IHistogram1D[] plots;
+	private final DisplayStyle dispStyle;
+	
+	public FormattedPlot1D(IHistogram1D plot, ColorStyle style, String xAxis, String yAxis, String plotName) {
+		this(new IHistogram1D[] { plot }, new ColorStyle[] { style }, new String[] { plotName }, xAxis, yAxis, DisplayStyle.BAR, plotName);
+	}
+	
+	public FormattedPlot1D(IHistogram1D plot, ColorStyle style, String xAxis, String yAxis, DisplayStyle dispStyle, String plotName) {
+		this(new IHistogram1D[] { plot }, new ColorStyle[] { style }, new String[] { plotName }, xAxis, yAxis, dispStyle, plotName);
+	}
+	
+	public FormattedPlot1D(IHistogram1D plots[], ColorStyle[] styles, String[] entryNames,
+			String xAxis, String yAxis, DisplayStyle dispStyle, String plotName) {
+		this(plots, styles, entryNames, xAxis, yAxis, dispStyle, plotName, -1, -1);
+	}
+	
+	public FormattedPlot1D(IHistogram1D plot, ColorStyle style, String xAxis, String yAxis, String plotName, double axisMin, double axisMax) {
+		this(new IHistogram1D[] { plot }, new ColorStyle[] { style }, new String[] { plotName },
+				xAxis, yAxis, DisplayStyle.BAR, plotName, axisMin, axisMax);
+	}
+	
+	public FormattedPlot1D(IHistogram1D plot, ColorStyle style, String xAxis, String yAxis,
+			DisplayStyle dispStyle, String plotName, double axisMin, double axisMax) {
+		this(new IHistogram1D[] { plot }, new ColorStyle[] { style }, new String[] { plotName },
+				xAxis, yAxis, dispStyle, plotName, axisMin, axisMax);
+	}
+	
+	public FormattedPlot1D(IHistogram1D plots[], ColorStyle[] styles, String[] entryNames, String xAxis,
+			String yAxis, DisplayStyle dispStyle, String plotName, double axisMin, double axisMax) {
+		// Initialize the object.
+		super(xAxis, yAxis, plotName);
+		this.plots = plots;
+		this.styles = styles;
+		this.axisMin = axisMin;
+		this.axisMax = axisMax;
+		if(dispStyle == null) { this.dispStyle = DisplayStyle.BAR; }
+		else { this.dispStyle = dispStyle; }
+		
+		// Verify that the plot array is valid for a compound plot.
+		if(!verifyPlots(plots)) {
+			throw new IllegalArgumentException("Plots array invalid; plots must have the same bins!");
+		}
+		
+		// Verify that all color styles are defined and are equal in
+		// number to the plots.
+		if(styles == null || styles.length != plots.length) {
+			throw new IllegalArgumentException("Color style array invalid; a number of color styles equal to plots must be defined.");
+		}
+		for(int i = 0; i < styles.length; i++) {
+			if(styles[i] == null) {
+				throw new IllegalArgumentException("Color style array invalid; all color styles must be defined.");
+			}
+		}
+		
+		// Set the names of each individual entry plot.
+		if(entryNames == null || entryNames.length != plots.length) {
+			throw new IllegalArgumentException("When defining multiple plots, a unique entry name must be defined for each.");
+		}
+		Set<String> entryNameSet = new HashSet<String>(entryNames.length);
+		for(int i = 0; i < plots.length; i++) {
+			if(entryNames[i] == null || entryNameSet.contains(entryNames[i])) {
+				throw new IllegalArgumentException("When defining multiple plots, a unique entry name must be defined for each.");
+			}
+			entryNameSet.add(entryNames[i]);
+			plots[i].setTitle(entryNames[i]);
+		}
+	}
+	
+	public IHistogram1D[] getPlots() {
+		return plots;
+	}
+	
+	public ColorStyle[] getColorStyle() {
+		return styles;
+	}
+	
+	public boolean definesAxisRange() {
+		return axisMax != -1;
+	}
+	
+	public double getAxisMin() {
+		return axisMin;
+	}
+	
+	public double getAxisMax() {
+		return axisMax;
+	}
+	
+	public DisplayStyle getDisplayStyle() {
+		return dispStyle;
+	}
+	
+	private static final boolean verifyPlots(IHistogram1D[] plots) {
+		// The plot file must be defined.
+		if(plots == null) { return false; }
+		
+		// If there is only one plot, it passes automatically.
+		if(plots.length == 1) { return true; }
+		
+		// All plots must have the same dimensions and bin values.
+		int baseBins = plots[0].axis().bins();
+		for(IHistogram1D plot : plots) {
+			// Check that the plot has the same number of bins.
+			if(plot.axis().bins() != baseBins) { return false; }
+		}
+		
+		// Check that each bin in the plots has the same value.
+		for(int bin = 0; bin < baseBins; bin++) {
+			// Get the value of the first bin in the base plot.
+			double baseBinValue = plots[0].axis().binLowerEdge(0);
+			
+			// Check that all other plots are the same.
+			for(IHistogram1D plot : plots) {
+				// Check that the plot has the same number of bins.
+				if(plot.axis().binLowerEdge(0) != baseBinValue) { return false; }
+			}
+		}
+		
+		// Otherwise, the plots are the same.
+		return true;
+	}
 }

Modified: java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/FormattedPlot2D.java
 =============================================================================
--- java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/FormattedPlot2D.java	(original)
+++ java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/FormattedPlot2D.java	Tue Sep 27 08:50:14 2016
@@ -3,48 +3,48 @@
 import hep.aida.IHistogram2D;
 
 public class FormattedPlot2D extends FormattedPlot {
-    private final IHistogram2D plot;
-    private final boolean logarithmic;
-    private final double xAxisRange;
-    private final double yAxisRange;
-    
-    public FormattedPlot2D(IHistogram2D plot, boolean logarithmic, String xAxis, String yAxis, String plotName) {
-        super(xAxis, yAxis, plotName);
-        this.plot = plot;
-        this.xAxisRange = -1;
-        this.yAxisRange = -1;
-        this.logarithmic = logarithmic;
-    }
-    
-    public FormattedPlot2D(IHistogram2D plot, boolean logarithmic, String xAxis, String yAxis, String plotName, double xAxisRange, double yAxisRange) {
-        super(xAxis, yAxis, plotName);
-        this.plot = plot;
-        this.xAxisRange = xAxisRange;
-        this.yAxisRange = yAxisRange;
-        this.logarithmic = logarithmic;
-    }
-    
-    public IHistogram2D getPlot() {
-        return plot;
-    }
-    
-    public boolean isLogarithmic() {
-        return logarithmic;
-    }
-    
-    public boolean definesXAxisRange() {
-        return xAxisRange != -1;
-    }
-    
-    public boolean definesYAxisRange() {
-        return yAxisRange != -1;
-    }
-    
-    public double getXAxisRange() {
-        return xAxisRange;
-    }
-    
-    public double getYAxisRange() {
-        return yAxisRange;
-    }
+	private final IHistogram2D plot;
+	private final boolean logarithmic;
+	private final double xAxisRange;
+	private final double yAxisRange;
+	
+	public FormattedPlot2D(IHistogram2D plot, boolean logarithmic, String xAxis, String yAxis, String plotName) {
+		super(xAxis, yAxis, plotName);
+		this.plot = plot;
+		this.xAxisRange = -1;
+		this.yAxisRange = -1;
+		this.logarithmic = logarithmic;
+	}
+	
+	public FormattedPlot2D(IHistogram2D plot, boolean logarithmic, String xAxis, String yAxis, String plotName, double xAxisRange, double yAxisRange) {
+		super(xAxis, yAxis, plotName);
+		this.plot = plot;
+		this.xAxisRange = xAxisRange;
+		this.yAxisRange = yAxisRange;
+		this.logarithmic = logarithmic;
+	}
+	
+	public IHistogram2D getPlot() {
+		return plot;
+	}
+	
+	public boolean isLogarithmic() {
+		return logarithmic;
+	}
+	
+	public boolean definesXAxisRange() {
+		return xAxisRange != -1;
+	}
+	
+	public boolean definesYAxisRange() {
+		return yAxisRange != -1;
+	}
+	
+	public double getXAxisRange() {
+		return xAxisRange;
+	}
+	
+	public double getYAxisRange() {
+		return yAxisRange;
+	}
 }

Modified: java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/PlotFormatModule.java
 =============================================================================
--- java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/PlotFormatModule.java	(original)
+++ java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/PlotFormatModule.java	Tue Sep 27 08:50:14 2016
@@ -7,8 +7,6 @@
 import hep.aida.IPlotterFactory;
 import hep.aida.ref.plotter.PlotterRegion;
 
-import org.hps.users.kmccarty.plots.PlotsFormatter.ColorStyle;
-
 import java.io.BufferedWriter;
 import java.io.File;
 import java.io.FileWriter;
@@ -17,189 +15,220 @@
 import java.util.List;
 
 public class PlotFormatModule {
-    private String width = "2000";
-    private String height = "1200";
-    private List<FormattedPlot1D> formattedPlots1D = new ArrayList<FormattedPlot1D>();
-    private List<FormattedPlot2D> formattedPlots2D = new ArrayList<FormattedPlot2D>();
-    
-    public void addPlot1D(FormattedPlot1D plot) {
-        formattedPlots1D.add(plot);
-    }
-    
-    public void addPlot2D(FormattedPlot2D plot) {
-        formattedPlots2D.add(plot);
-    }
-    
-    public void setDisplayHeight(int height) {
-        this.height = "" + height;
-    }
-    
-    public void setDisplayWidth(int width) {
-        this.width = "" + width;
-    }
-    
-    public void displayPlots() {
-        try { processPlots(null); }
-        catch (IOException e) { e.printStackTrace(); }
-    }
-    
-    public void savePlots(String filePath) throws IOException {
-        processPlots(filePath);
-    }
-    
-    private void processPlots(String filePath) throws IOException {
-        // Create a plotter factory.
-        IAnalysisFactory af = IAnalysisFactory.create();
-        IPlotterFactory plotterFactory = af.createPlotterFactory();
-        
-        // Format and display the 1D plots.
-        for(FormattedPlot1D formattedPlot : formattedPlots1D) {
-            // Get the plot.
-            IHistogram1D plot = formattedPlot.getPlot();
-            
-            // Create a plotter and plotting region for the plot.
-            IPlotter plotter = plotterFactory.create(plot.title());
-            plotter.createRegions(1);
-            plotter.region(0).plot(plot);
-            
-            // Set the axis range.
-            PlotterRegion region = (PlotterRegion) plotter.region(0);
-            if(formattedPlot.definesAxisRange()) {
-                region.getPlot().getXAxis().setMax(formattedPlot.getAxisRange());
-            }
-            
-            // Format the axis labels.
-            region.getPlot().setTitle(formattedPlot.getPlotName());
-            region.getPlot().getXAxis().setLabel(formattedPlot.getXAxisName());
-            region.getPlot().getYAxis().setLabel(formattedPlot.getYAxisName());
-            
-            // Format the fonts and general plot presentation.
-            PlotsFormatter.setDefault1DStyle(region, new ColorStyle[] { formattedPlot.getColorStyle() });
-            
-            // Set the plotter dimensions.
-            plotter.setParameter("plotterWidth", width);
-            plotter.setParameter("plotterHeight", height);
-            
-            // If the file path is null, display the plots. Otherwise,
-            // save them to the destination folder.
-            if(filePath == null) { plotter.show(); }
-            else {
-                File plotFile = new File(filePath + formattedPlot.getPlotName() + ".png");
-                if(plotFile.exists()) { plotFile.delete(); }
-                plotter.writeToFile(filePath + formattedPlot.getPlotName() + ".png");
-                System.out.printf("Saved plot \"%s\" to path: %s%n", formattedPlot.getPlotName(), filePath + formattedPlot.getPlotName() + ".png");
-            }
-        }
-        
-        // Format and display the 2D plots.
-        for(FormattedPlot2D formattedPlot : formattedPlots2D) {
-            // Get the plot.
-            IHistogram2D plot = formattedPlot.getPlot();
-            
-            // Create a plotter and plotting region for the plot.
-            IPlotter plotter = plotterFactory.create(formattedPlot.getPlotName());
-            plotter.createRegions(1);
-            plotter.region(0).plot(plot);
-            
-            // Set the axis range.
-            PlotterRegion region = (PlotterRegion) plotter.region(0);
-            if(formattedPlot.definesXAxisRange()) {
-                region.getPlot().getXAxis().setMax(formattedPlot.getXAxisRange());
-            } if(formattedPlot.definesYAxisRange()) {
-                region.getPlot().getYAxis().setMax(formattedPlot.getYAxisRange());
-            }
-            
-            // Format the axis labels.
-            region.getPlot().setTitle(formattedPlot.getPlotName());
-            region.getPlot().getXAxis().setLabel(formattedPlot.getXAxisName());
-            region.getPlot().getYAxis().setLabel(formattedPlot.getYAxisName());
-            
-            // Format the fonts and general plot presentation.
-            PlotsFormatter.setDefault2DStyle(region, formattedPlot.isLogarithmic());
-            
-            // Set the plotter dimensions.
-            plotter.setParameter("plotterWidth", width);
-            plotter.setParameter("plotterHeight", height);
-            
-            // If the file path is null, display the plots. Otherwise,
-            // save them to the destination folder.
-            if(filePath == null) { plotter.show(); }
-            else {
-                File plotFile = new File(filePath + formattedPlot.getPlotName() + ".png");
-                if(plotFile.exists()) { plotFile.delete(); }
-                plotter.writeToFile(filePath + formattedPlot.getPlotName() + ".png");
-                System.out.printf("Saved plot \"%s\" to path: %s%n", formattedPlot.getPlotName(), filePath + formattedPlot.getPlotName() + ".png");
-            }
-        }
-    }
-    
-    public void exportPlots(String filePath) throws IOException {
-        // Export the 1D plots in a text format.
-        for(FormattedPlot1D plot : formattedPlots1D) {
-            exportPlot(filePath, plot);
-        }
-        
-        // Export the 2D plots in a text format.
-        for(FormattedPlot2D plot : formattedPlots2D) {
-            exportPlot(filePath, plot);
-        }
-    }
-    
-    private static final void exportPlot(String filePath, FormattedPlot plot) throws IOException {
-        // Check if this is a one or two dimensional plot.
-        boolean is1D = plot instanceof FormattedPlot1D;
-        
-        // Create a file object for the plot.
-        String plotPath = filePath + plot.getPlotName() + (is1D ? ".aida1D" : ".aida2D");
-        File datFile = new File(plotPath);
-        
-        // If the plot file already exists, delete it.
-        if(datFile.exists()) { datFile.delete(); }
-        
-        // Create a new file for the plot to occupy.
-        datFile.createNewFile();
-        
-        // Get the textual form of the plot.
-        String plotText = null;
-        if(is1D) { plotText = toTextFormat(((FormattedPlot1D) plot).getPlot()); }
-        else { plotText = toTextFormat(((FormattedPlot2D) plot).getPlot()); }
-        
-        // Write the plot text to the file.
-        BufferedWriter writer = new BufferedWriter(new FileWriter(datFile));
-        writer.write(plotText);
-        writer.close();
-        
-        // Note that the file was written.
-        System.out.printf("Plot \"%s\" was exported to path: %s%n", plot.getPlotName(), plotPath);
-    }
-    
-    private static final String toTextFormat(IHistogram1D plot) {
-        // Create a buffer to hold the converted plot.
-        StringBuffer buffer = new StringBuffer();
-        
-        // Iterate over the bins and output the plot in the format of
-        // "[BIN_MEAN] [BIN_VALUE]" with a tab delimiter.
-        for(int bin = 0; bin < plot.axis().bins(); bin++) {
-            buffer.append(String.format("%f\t%f%n", plot.binMean(bin), plot.binHeight(bin)));
-        }
-        
-        // Return the converted file.
-        return buffer.toString();
-    }
-    
-    private static final String toTextFormat(IHistogram2D plot) {
-        // Create a buffer to hold the converted plot.
-        StringBuffer buffer = new StringBuffer();
-        
-        // Iterate over the bins and output the plot in the format of
-        // "[X_BIN_MEAN] [Y_BIN_MEAN] [BIN_VALUE]" with a tab delimiter.
-        for(int xBin = 0; xBin < plot.xAxis().bins(); xBin++) {
-            for(int yBin = 0; yBin < plot.yAxis().bins(); yBin++) {
-                buffer.append(String.format("%f\t%f\t%f%n", plot.binMeanX(xBin, yBin), plot.binMeanY(xBin, yBin), plot.binHeight(xBin, yBin)));
-            }
-        }
-        
-        // Return the converted file.
-        return buffer.toString();
-    }
+	private String width = "2000";
+	private String height = "1200";
+	private List<FormattedPlot1D> formattedPlots1D = new ArrayList<FormattedPlot1D>();
+	private List<FormattedPlot2D> formattedPlots2D = new ArrayList<FormattedPlot2D>();
+	
+	public void addPlot1D(FormattedPlot1D plot) {
+		formattedPlots1D.add(plot);
+	}
+	
+	public void addPlot2D(FormattedPlot2D plot) {
+		formattedPlots2D.add(plot);
+	}
+	
+	public void setDisplayHeight(int height) {
+		this.height = "" + height;
+	}
+	
+	public void setDisplayWidth(int width) {
+		this.width = "" + width;
+	}
+	
+	public void displayPlots() {
+		try { processPlots(null); }
+		catch (IOException e) { e.printStackTrace(); }
+	}
+	
+	public void savePlots(String filePath) throws IOException {
+		processPlots(filePath);
+	}
+	
+	private void processPlots(String filePath) throws IOException {
+		// Create a plotter factory.
+		IAnalysisFactory af = IAnalysisFactory.create();
+		IPlotterFactory plotterFactory = af.createPlotterFactory();
+		
+		// Format and display the 1D plots.
+		for(FormattedPlot1D formattedPlot : formattedPlots1D) {
+			// Get the plot(s).
+			IHistogram1D[] plots = formattedPlot.getPlots();
+			
+			// Create a plotter and plotting region for the plot.
+			IPlotter plotter = plotterFactory.create(formattedPlot.getPlotName());
+			plotter.createRegions(1);
+			for(IHistogram1D plot : plots) {
+				plotter.region(0).plot(plot);
+			}
+			
+			// Set the axis range.
+			PlotterRegion region = (PlotterRegion) plotter.region(0);
+			if(formattedPlot.definesAxisRange()) {
+				region.getPlot().getXAxis().setMin(formattedPlot.getAxisMin());
+				region.getPlot().getXAxis().setMax(formattedPlot.getAxisMax());
+			}
+			
+			// Format the axis labels.
+			region.getPlot().setTitle(formattedPlot.getPlotName());
+			region.getPlot().getXAxis().setLabel(formattedPlot.getXAxisName());
+			region.getPlot().getYAxis().setLabel(formattedPlot.getYAxisName());
+			
+			// Format the fonts and general plot presentation.
+			PlotsFormatter.setDefault1DStyle(region, formattedPlot.getColorStyle(), formattedPlot.getDisplayStyle());
+			
+			// Set the plotter dimensions.
+			plotter.setParameter("plotterWidth", width);
+			plotter.setParameter("plotterHeight", height);
+			
+			// If the file path is null, display the plots. Otherwise,
+			// save them to the destination folder.
+			if(filePath == null) { plotter.show(); }
+			else {
+				String name = sanitize(formattedPlot.getPlotName());
+				File plotFile = new File(filePath + name + ".png");
+				if(plotFile.exists()) { plotFile.delete(); }
+				plotter.writeToFile(filePath + name + ".png");
+				System.out.printf("Saved plot \"%s\" to path: %s%n", name, filePath + name + ".png");
+			}
+		}
+		
+		// Format and display the 2D plots.
+		for(FormattedPlot2D formattedPlot : formattedPlots2D) {
+			// Get the plot.
+			IHistogram2D plot = formattedPlot.getPlot();
+			
+			// Create a plotter and plotting region for the plot.
+			IPlotter plotter = plotterFactory.create(formattedPlot.getPlotName());
+			plotter.createRegions(1);
+			plotter.region(0).plot(plot);
+			
+			// Set the axis range.
+			PlotterRegion region = (PlotterRegion) plotter.region(0);
+			if(formattedPlot.definesXAxisRange()) {
+				region.getPlot().getXAxis().setMax(formattedPlot.getXAxisRange());
+			} if(formattedPlot.definesYAxisRange()) {
+				region.getPlot().getYAxis().setMax(formattedPlot.getYAxisRange());
+			}
+			
+			// Format the axis labels.
+			region.getPlot().setTitle(formattedPlot.getPlotName());
+			region.getPlot().getXAxis().setLabel(formattedPlot.getXAxisName());
+			region.getPlot().getYAxis().setLabel(formattedPlot.getYAxisName());
+			
+			// Format the fonts and general plot presentation.
+			PlotsFormatter.setDefault2DStyle(region, formattedPlot.isLogarithmic());
+			
+			// Set the plotter dimensions.
+			plotter.setParameter("plotterWidth", width);
+			plotter.setParameter("plotterHeight", height);
+			
+			// If the file path is null, display the plots. Otherwise,
+			// save them to the destination folder.
+			if(filePath == null) { plotter.show(); }
+			else {
+				File plotFile = new File(filePath + formattedPlot.getPlotName() + ".png");
+				if(plotFile.exists()) { plotFile.delete(); }
+				plotter.writeToFile(filePath + formattedPlot.getPlotName() + ".png");
+				System.out.printf("Saved plot \"%s\" to path: %s%n", formattedPlot.getPlotName(), filePath + formattedPlot.getPlotName() + ".png");
+			}
+		}
+	}
+	
+	public void exportPlots(String filePath) throws IOException {
+		// Export the 1D plots in a text format.
+		for(FormattedPlot1D plot : formattedPlots1D) {
+			exportPlot(filePath, plot);
+		}
+		
+		// Export the 2D plots in a text format.
+		for(FormattedPlot2D plot : formattedPlots2D) {
+			exportPlot(filePath, plot);
+		}
+	}
+	
+	private static final void exportPlot(String filePath, FormattedPlot plot) throws IOException {
+		// Check if this is a one or two dimensional plot.
+		boolean is1D = plot instanceof FormattedPlot1D;
+		
+		// Create a file object for the plot.
+		String plotPath = filePath + plot.getPlotName() + (is1D ? ".aida1D" : ".aida2D");
+		File datFile = new File(plotPath);
+		
+		// If the plot file already exists, delete it.
+		if(datFile.exists()) { datFile.delete(); }
+		
+		// Create a new file for the plot to occupy.
+		datFile.createNewFile();
+		
+		// Get the textual form of the plot.
+		String plotText = null;
+		if(is1D) { plotText = toTextFormat(((FormattedPlot1D) plot).getPlots()); }
+		else { plotText = toTextFormat(((FormattedPlot2D) plot).getPlot()); }
+		
+		// Write the plot text to the file.
+		BufferedWriter writer = new BufferedWriter(new FileWriter(datFile));
+		writer.write(plotText);
+		writer.close();
+		
+		// Note that the file was written.
+		System.out.printf("Plot \"%s\" was exported to path: %s%n", plot.getPlotName(), plotPath);
+	}
+	
+	private static final String toTextFormat(IHistogram1D[] plot) {
+		// Create a buffer to hold the converted plot.
+		StringBuffer buffer = new StringBuffer();
+		
+		// Iterate over the bins and output the plot in the format of
+		// "[BIN_MEAN] [BIN_VALUE]" with a tab delimiter.
+		for(int bin = 0; bin < plot[0].axis().bins(); bin++) {
+			// Add the bin value to the file once.
+			buffer.append(String.format("%f", plot[0].binMean(bin)));
+			
+			// Add all the plots' bin heights to the line.)
+			for(int i = 0; i < plot.length; i++) {
+				buffer.append(String.format("\t%f", plot[i].binHeight(bin)));
+			}
+		}
+		
+		// Return the converted file.
+		return buffer.toString();
+	}
+	
+	private static final String toTextFormat(IHistogram2D plot) {
+		// Create a buffer to hold the converted plot.
+		StringBuffer buffer = new StringBuffer();
+		
+		// Iterate over the bins and output the plot in the format of
+		// "[X_BIN_MEAN] [Y_BIN_MEAN] [BIN_VALUE]" with a tab delimiter.
+		for(int xBin = 0; xBin < plot.xAxis().bins(); xBin++) {
+			for(int yBin = 0; yBin < plot.yAxis().bins(); yBin++) {
+				buffer.append(String.format("%f\t%f\t%f%n", plot.binMeanX(xBin, yBin), plot.binMeanY(xBin, yBin), plot.binHeight(xBin, yBin)));
+			}
+		}
+		
+		// Return the converted file.
+		return buffer.toString();
+	}
+	
+	/**
+	 * Sanitizes a filename for saving.
+	 * @param filename - The original filename.
+	 * @return Returns the filename, but with all characters except
+	 * those which are alphanumeric or a dash ('-') excluded.
+	 */
+	private static final String sanitize(String filename) {
+		// Store the sanitized filename.
+		StringBuffer cleanName = new StringBuffer();
+		
+		// Only allow alphanumeric characters.
+		for(char c : filename.toCharArray()) {
+			if(Character.isLetterOrDigit(c) || c == '-') {
+				cleanName.append(c);
+			}
+		}
+		
+		// Return the cleaned name.
+		return cleanName.toString();
+	}
 }

Modified: java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/PlotsFormatter.java
 =============================================================================
--- java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/PlotsFormatter.java	(original)
+++ java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/PlotsFormatter.java	Tue Sep 27 08:50:14 2016
@@ -8,120 +8,146 @@
 import java.awt.Font;
 
 public class PlotsFormatter {
-    // Define plot fonts.
-    public static final Font BASIC_FONT = new Font("Calibri", Font.PLAIN, 30);
-    public static final Font AXIS_FONT  = new Font("Calibri", Font.BOLD,  35);
-    public static final Font TITLE_FONT = new Font("Calibri", Font.BOLD,  45);
-    
-    // Defines the color style options for plot data.
-    public static enum ColorStyle {
-         MS_BLUE(new Color( 79, 129, 189), new Color( 36,  64,  97)), MS_ORANGE(new Color(247, 150,  70), new Color(152,  72,   6)),
-          MS_RED(new Color(192,  80,  77), new Color( 99,  36,  35)),      GREY(new Color(166, 166, 166), new Color( 89,  89,  89)),
-        MS_GREEN(new Color(155, 187,  89), new Color( 79,  98,  40)),   CRIMSON(new Color(161,   0,   0), new Color(104,   0,   0)),
-            RUST(new Color(161,  80,   0), new Color(105,  80,   0)),    YELLOW(new Color(161, 161,   0), new Color(122, 109,   8)),
-          FOREST(new Color( 65, 102,   0), new Color( 37,  79,   0)),     GREEN(new Color(  7, 132,  70), new Color(  7,  82,  30)),
-            TEAL(new Color(  0, 130, 130), new Color(  0,  90, 100)),  CERULEAN(new Color(  0,  86, 130), new Color(  0,  28,  83)),
-            BLUE(new Color(  0,  33, 203), new Color(  0,   0, 137)),    INDIGO(new Color( 68,  10, 127), new Color(  0,   0,  61)),
-          PURPLE(new Color(106,   0, 106), new Color( 63,   0,  56)),   FUSCHIA(new Color(119,   0,  60), new Color( 60,   0,  60));
-        
-        private final Color fillColor;
-        private final Color lineColor;
-        
-        private ColorStyle(Color fillColor, Color lineColor) {
-            this.fillColor = fillColor;
-            this.lineColor = lineColor;
-        }
-        
-        public Color getFillColor() { return fillColor; }
-        
-        public Color getLineColor() { return lineColor; }
-    };
-    
-    /**
-     * Sets the plot display formatting for 1D plots.
-     * @param region - The plotter region to format.
-     * @param color - The data color settings to use.
-     */
-    public static final void setDefault1DStyle(PlotterRegion region, ColorStyle[] color) {
-        // Get the names of each plot on in the region.
-        String[] dataNames = region.getAllDataNames();
-        
-        // Check whether this is an overlay plot. Overlay plots contain
-        // more than one data name.
-        boolean overlay = (dataNames.length > 1 ? true : false);
-        
-        // Iterate over each plot in the region.
-        for(int i = 0; i < dataNames.length; i++) {
-            // Set the overlay style if needed.
-            if(overlay) {
-                // Get the fill style for the current data type.
-                JASHist1DHistogramStyle fillStyle = (JASHist1DHistogramStyle) region.getDataForName(dataNames[i]).getStyle();
-                
-                // Set the histogram style to display thick-lined bars
-                // with no fill. The color is set by the "color" argument.
-                fillStyle.setHistogramFill(false);
-                fillStyle.setHistogramBarLineWidth(3);
-                fillStyle.setHistogramBarLineColor(color[i].getFillColor());
-                
-                // Set the legend text style.
-                region.getPlot().getLegend().setFont(new Font("Calibri", Font.PLAIN, 20));
-            }
-            
-            // Otherwise, set the fill style for a single plot.
-            else {
-                // Get the fill style for the current data type.
-                JASHist1DHistogramStyle fillStyle = (JASHist1DHistogramStyle) region.getDataForName(dataNames[i]).getStyle();
-                
-                // Set the histogram style to display thick-lined bars
-                // with a fill color. The colors are defined by the
-                // "color" argument.
-                fillStyle.setHistogramBarLineWidth(3);
-                fillStyle.setHistogramBarColor(color[i].getFillColor());
-                fillStyle.setHistogramBarLineColor(color[i].getLineColor());
-            }
-            
-            // Set the statistics box style.
-            region.getPlot().getStats().setVisible(true);
-            region.getPlot().getStats().setFont(BASIC_FONT);
-            
-            // Set the title font.
-            region.getPlot().getTitleObject().setFont(TITLE_FONT);
-            
-            // Set the axis tick-mark fonts.
-            region.getPlot().getXAxis().setFont(BASIC_FONT);
-            region.getPlot().getYAxis().setFont(BASIC_FONT);
-            region.getPlot().getXAxis().getLabelObject().setFont(AXIS_FONT);
-            region.getPlot().getYAxis().getLabelObject().setFont(AXIS_FONT);
-        }
-    }
-    
-    /**
-     * Sets the plot display formatting for 1D plots.
-     * @param region - The plotter region to format.
-     */
-    public static final void setDefault2DStyle(PlotterRegion region, boolean logarithmic) {
-        // Get the fill style object. 2D plots should never be overlay
-        // plots, so there should only ever be one data name.
-        JASHist2DHistogramStyle fillStyle = (JASHist2DHistogramStyle) region.getDataForName(region.getAllDataNames()[0]).getStyle();
-        
-        // Set the fill style for a two-dimensional plot.
-        if(logarithmic) { fillStyle.setLogZ(true); }
-        fillStyle.setHistStyle(JASHist2DHistogramStyle.STYLE_COLORMAP);
-        fillStyle.setColorMapScheme(JASHist2DHistogramStyle.COLORMAP_RAINBOW);
-        
-        // Make the statistics box invisible.
-        region.getPlot().getStats().setVisible(false);
-        
-        // Set the general plot font (which is also the z-axis font).
-        region.getPlot().setFont(BASIC_FONT);
-        
-        // Set the title font.
-        region.getPlot().getTitleObject().setFont(TITLE_FONT);
-        
-        // Set the axis tick-mark fonts.
-        region.getPlot().getXAxis().setFont(BASIC_FONT);
-        region.getPlot().getYAxis().setFont(BASIC_FONT);
-        region.getPlot().getXAxis().getLabelObject().setFont(AXIS_FONT);
-        region.getPlot().getYAxis().getLabelObject().setFont(AXIS_FONT);
-    }
+	// Define plot fonts.
+	public static final Font BASIC_FONT = new Font("Calibri", Font.PLAIN, 30);
+	public static final Font AXIS_FONT  = new Font("Calibri", Font.BOLD,  35);
+	public static final Font TITLE_FONT = new Font("Calibri", Font.BOLD,  45);
+	
+	// Defines whether the histogram should be a line or bar histogram.
+	public enum DisplayStyle { BAR, LINE };
+	
+	// Defines the color style options for plot data.
+	public static enum ColorStyle {
+		 MS_BLUE(new Color( 79, 129, 189), new Color( 36,  64,  97)), MS_ORANGE(new Color(247, 150,  70), new Color(152,  72,   6)),
+		  MS_RED(new Color(192,  80,  77), new Color( 99,  36,  35)),      GREY(new Color(166, 166, 166), new Color( 89,  89,  89)),
+		MS_GREEN(new Color(155, 187,  89), new Color( 79,  98,  40)),   CRIMSON(new Color(161,   0,   0), new Color(104,   0,   0)),
+		    RUST(new Color(161,  80,   0), new Color(105,  80,   0)),    YELLOW(new Color(161, 161,   0), new Color(122, 109,   8)),
+		  FOREST(new Color( 65, 102,   0), new Color( 37,  79,   0)),     GREEN(new Color(  7, 132,  70), new Color(  7,  82,  30)),
+		    TEAL(new Color(  0, 130, 130), new Color(  0,  90, 100)),  CERULEAN(new Color(  0,  86, 130), new Color(  0,  28,  83)),
+		    BLUE(new Color(  0,  33, 203), new Color(  0,   0, 137)),    INDIGO(new Color( 68,  10, 127), new Color(  0,   0,  61)),
+		  PURPLE(new Color(106,   0, 106), new Color( 63,   0,  56)),   FUSCHIA(new Color(119,   0,  60), new Color( 60,   0,  60));
+		
+		private final Color fillColor;
+		private final Color lineColor;
+		
+		private ColorStyle(Color fillColor, Color lineColor) {
+			this.fillColor = fillColor;
+			this.lineColor = lineColor;
+		}
+		
+		public Color getFillColor() { return fillColor; }
+		
+		public Color getLineColor() { return lineColor; }
+	};
+	
+	/**
+	 * Sets the plot display formatting for 1D plots.
+	 * @param region - The plotter region to format.
+	 * @param color - The data color settings to use.
+	 */
+	public static final void setDefault1DStyle(PlotterRegion region, ColorStyle[] color, DisplayStyle style) {
+		// Get the names of each plot on in the region.
+		String[] dataNames = region.getAllDataNames();
+		
+		// Check whether this is an overlay plot. Overlay plots contain
+		// more than one data name.
+		boolean overlay = (dataNames.length > 1 ? true : false);
+		System.out.println("Is overlay: " + overlay);
+		
+		// Iterate over each plot in the region.
+		for(int i = 0; i < dataNames.length; i++) {
+			System.out.println("Processing data name [" + i + "]: " + dataNames[i]);
+			
+			// Set the overlay style if needed.
+			if(overlay) {
+				// Get the fill style for the current data type.
+				JASHist1DHistogramStyle fillStyle = (JASHist1DHistogramStyle) region.getDataForName(dataNames[i]).getStyle();
+				
+				// Set the histogram style to display thick-lined bars
+				// with no fill. The color is set by the "color" argument.
+				fillStyle.setHistogramFill(false);
+				fillStyle.setHistogramBarLineWidth(3);
+				fillStyle.setShowErrorBars(false);
+				if(style == DisplayStyle.LINE) {
+					fillStyle.setLinesBetweenPointsWidth(3);
+					fillStyle.setShowHistogramBars(false);
+					fillStyle.setShowLinesBetweenPoints(true);
+					fillStyle.setLineColor(color[i].getFillColor());
+				} else {
+					fillStyle.setShowHistogramBars(true);
+					fillStyle.setShowLinesBetweenPoints(false);
+					fillStyle.setHistogramBarLineColor(color[i].getFillColor());
+				}
+				
+				// Set the legend text style.
+				region.getPlot().getLegend().setFont(new Font("Calibri", Font.PLAIN, 20));
+			}
+			
+			// Otherwise, set the fill style for a single plot.
+			else {
+				// Get the fill style for the current data type.
+				JASHist1DHistogramStyle fillStyle = (JASHist1DHistogramStyle) region.getDataForName(dataNames[i]).getStyle();
+				
+				// Set the histogram style to display thick-lined bars
+				// with a fill color. The colors are defined by the
+				// "color" argument.
+				fillStyle.setHistogramBarLineWidth(3);
+				if(style == DisplayStyle.LINE) {
+					fillStyle.setHistogramFill(false);
+					fillStyle.setLinesBetweenPointsWidth(3);
+					fillStyle.setShowHistogramBars(false);
+					fillStyle.setShowLinesBetweenPoints(true);
+					fillStyle.setLineColor(color[i].getFillColor());
+				} else {
+					fillStyle.setShowHistogramBars(true);
+					fillStyle.setShowLinesBetweenPoints(false);
+					fillStyle.setHistogramBarColor(color[i].getFillColor());
+					fillStyle.setHistogramBarLineColor(color[i].getLineColor());
+				}
+			}
+			
+			// Set the statistics box style.
+			region.getPlot().getStats().setVisible(true);
+			region.getPlot().getStats().setFont(BASIC_FONT);
+			
+			// Set the title font.
+			region.getPlot().getTitleObject().setFont(TITLE_FONT);
+			
+			// Set the axis tick-mark fonts.
+			region.getPlot().getXAxis().setFont(BASIC_FONT);
+			region.getPlot().getYAxis().setFont(BASIC_FONT);
+			region.getPlot().getXAxis().getLabelObject().setFont(AXIS_FONT);
+			region.getPlot().getYAxis().getLabelObject().setFont(AXIS_FONT);
+		}
+	}
+	
+	/**
+	 * Sets the plot display formatting for 1D plots.
+	 * @param region - The plotter region to format.
+	 */
+	public static final void setDefault2DStyle(PlotterRegion region, boolean logarithmic) {
+		// Get the fill style object. 2D plots should never be overlay
+		// plots, so there should only ever be one data name.
+		JASHist2DHistogramStyle fillStyle = (JASHist2DHistogramStyle) region.getDataForName(region.getAllDataNames()[0]).getStyle();
+		
+		// Set the fill style for a two-dimensional plot.
+		if(logarithmic) { fillStyle.setLogZ(true); }
+		fillStyle.setHistStyle(JASHist2DHistogramStyle.STYLE_COLORMAP);
+		fillStyle.setColorMapScheme(JASHist2DHistogramStyle.COLORMAP_RAINBOW);
+		
+		// Make the statistics box invisible.
+		region.getPlot().getStats().setVisible(false);
+		
+		// Set the general plot font (which is also the z-axis font).
+		region.getPlot().setFont(BASIC_FONT);
+		
+		// Set the title font.
+		region.getPlot().getTitleObject().setFont(TITLE_FONT);
+		
+		// Set the axis tick-mark fonts.
+		region.getPlot().getXAxis().setFont(BASIC_FONT);
+		region.getPlot().getYAxis().setFont(BASIC_FONT);
+		region.getPlot().getXAxis().getLabelObject().setFont(AXIS_FONT);
+		region.getPlot().getYAxis().getLabelObject().setFont(AXIS_FONT);
+	}
 }

Modified: java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/formatter/InvariantMassPlotsFormatter.java
 =============================================================================
--- java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/formatter/InvariantMassPlotsFormatter.java	(original)
+++ java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/formatter/InvariantMassPlotsFormatter.java	Tue Sep 27 08:50:14 2016
@@ -19,317 +19,317 @@
 import hep.aida.ref.plotter.PlotterRegion;
 
 public class InvariantMassPlotsFormatter {
-    // Define plot fonts.
-    private static final Font BASIC_FONT = new Font("Calibri", Font.PLAIN, 20);
-    private static final Font AXIS_FONT  = new Font("Calibri", Font.BOLD,  25);
-    private static final Font TITLE_FONT = new Font("Calibri", Font.BOLD,  35);
-    
-    // Defines the color style options for plot data.
-    private enum ColorStyle {
-         MS_BLUE(new Color( 79, 129, 189), new Color( 36,  64,  97)), MS_ORANGE(new Color(247, 150,  70), new Color(152,  72,   6)),
-          MS_RED(new Color(192,  80,  77), new Color( 99,  36,  35)),      GREY(new Color(166, 166, 166), new Color( 89,  89,  89)),
-        MS_GREEN(new Color(155, 187,  89), new Color( 79,  98,  40)),   CRIMSON(new Color(161,   0,   0), new Color(104,   0,   0)),
-            RUST(new Color(161,  80,   0), new Color(105,  80,   0)),    YELLOW(new Color(161, 161,   0), new Color(122, 109,   8)),
-          FOREST(new Color( 65, 102,   0), new Color( 37,  79,   0)),     GREEN(new Color(  7, 132,  70), new Color(  7,  82,  30)),
-            TEAL(new Color(  0, 130, 130), new Color(  0,  90, 100)),  CERULEAN(new Color(  0,  86, 130), new Color(  0,  28,  83)),
-            BLUE(new Color(  0,  33, 203), new Color(  0,   0, 137)),    INDIGO(new Color( 68,  10, 127), new Color(  0,   0,  61)),
-          PURPLE(new Color(106,   0, 106), new Color( 63,   0,  56)),   FUSCHIA(new Color(119,   0,  60), new Color( 60,   0,  60));
-        
-        private final Color fillColor;
-        private final Color lineColor;
-        
-        private ColorStyle(Color fillColor, Color lineColor) {
-            this.fillColor = fillColor;
-            this.lineColor = lineColor;
-        }
-        
-        public Color getFillColor() { return fillColor; }
-        
-        public Color getLineColor() { return lineColor; }
-    };
-        
-    /**
-     * Loads all plots in a file and formats them according to the
-     * indicated style.
-     * @param args - Unused default executable parameter.
-     * @throws IOException Occurs if there is an issue opening the file.
-     */
-    public static void main(String[] args) throws IOException {
-        // Define the root directory for the plots.
-        String rootDir = "D:\\cygwin64\\home\\Kyle\\";
-        
-        // Define the new name of the file containing the trigger plots.
-        String[] plotFile = {
-                rootDir + "temp.aida"
-        };
-        
-        // Define the run numbers for each file.
-        String[] runNumber = { "1 Hits", "2 Hits" };
-        
-        // Define the scaling factors for each plot.
-        double scaleFactor = 13.254;
-        
-        // Get the plots file and open it.
-        IAnalysisFactory af = IAnalysisFactory.create();
-        ITree[] tree = new ITree[plotFile.length];
-        for(int i = 0; i < plotFile.length; i++) {
-            tree[i] = af.createTreeFactory().create(plotFile[i]);
-            if(tree[i] == null) { throw new IllegalArgumentException("Unable to load plot file."); }
-        }
-        
-        // Get the histograms.
-        IHistogram1D[] invariantMassPlots = new IHistogram1D[3];
-        invariantMassPlots[0] = (IHistogram1D) tree[0].find("Trident Analysis/Particle Invariant Mass (1 Hit)");
-        invariantMassPlots[1] = (IHistogram1D) tree[0].find("Trident Analysis/Particle Invariant Mass (2 Hit)");
-        IHistogram1D electronEnergyPlot = (IHistogram1D) tree[0].find("Trident Analysis/Electron Energy");
-        IHistogram1D positronEnergyPlot = (IHistogram1D) tree[0].find("Trident Analysis/Positron Energy");
-        IHistogram1D energySumPlot = (IHistogram1D) tree[0].find("Trident Analysis/Energy Sum Distribution");
-        IHistogram2D energySum2DPlot = (IHistogram2D) tree[0].find("Trident Analysis/2D Energy Distribution");
-        IHistogram1D tridentElectronEnergyPlot = (IHistogram1D) tree[0].find("Trident Analysis/Trident Electron Energy");
-        IHistogram1D tridentPositronEnergyPlot = (IHistogram1D) tree[0].find("Trident Analysis/Trident Positron Energy");
-        
-        // Define the plot titles and arrays.
-        IHistogram[] plots = { electronEnergyPlot, positronEnergyPlot, energySumPlot, tridentElectronEnergyPlot, tridentPositronEnergyPlot };
-        String[] titles = { "Electron Energy", "Positron Energy", "Energy Sum", "Trident Electron Energy", "Trident Positron Energy" };
-        String[] xTitles = { "Energy (GeV)", "Energy (GeV)", "Energy Sum (GeV)", "Energy (GeV)", "Energy (GeV)" };
-        
-        // Re-bin the histograms to have 5-times larger bins. First,
-        // get the bin count and upper and lower bounds of the plot.
-        int bins = invariantMassPlots[0].axis().bins();
-        double low = invariantMassPlots[0].axis().binLowerEdge(0);
-        double high = invariantMassPlots[0].axis().binUpperEdge(invariantMassPlots[0].axis().bins() - 1);
-        
-        // Create new plots with the larger bin sizes.
-        AIDA aida = AIDA.defaultInstance();
-        IHistogram1D[] newPlot = new IHistogram1D[2];
-        newPlot[0] = aida.histogram1D("Particle Invariant Mass (1 Hit)", bins / 5, low, high);
-        newPlot[1] = aida.histogram1D("Particle Invariant Mass (2 Hit)", bins / 5, low, high);
-        
-        // Populate the new plots with the data from the old ones.
-        for(int j = 0; j < 2; j++) {
-            for(int i = 0; i < bins; i++) {
-                int entries = invariantMassPlots[j].binEntries(i);
-                double center = invariantMassPlots[j].axis().binCenter(i);
-                for(int k = 0; k < entries; k++) {
-                    newPlot[j].fill(center);
-                }
-            }
-        }
-        
-        // Replace the old plots.
-        invariantMassPlots = newPlot;
-        
-        // Create a plotter factory.
-        IPlotterFactory plotterFactory = af.createPlotterFactory();
-        
-        // Format and display the basic histograms.
-        for(int i = 0; i < plots.length; i++) {
-            // Scale the histogram by the appropriate scaling factor.
-            plots[i].scale(1.0 / scaleFactor);
-            
-            // Create a plotter and plotting region for the plot.
-            IPlotter plotter = plotterFactory.create(titles[i]);
-            plotter.createRegions(1);
-            plotter.region(0).plot(plots[i]);
-            
-            // Format the axis labels.
-            PlotterRegion region = (PlotterRegion) plotter.region(0);
-            region.getPlot().setTitle(titles[i]);
-            region.getPlot().getXAxis().setLabel(xTitles[i]);
-            region.getPlot().getYAxis().setLabel("Rate (Hz)");
-            
-            // Format the fonts and general plot presentation.
-            setDefault1DStyle(region, new ColorStyle[] { ColorStyle.GREY });
-            
-            // Show the plot.
-            plotter.setParameter("plotterWidth", "2000");
-            plotter.setParameter("plotterHeight", "1200");
-            plotter.show();
-        }
-        
-        // Format and display the 2D histogram.
-        energySum2DPlot.scale(1.0 / scaleFactor);
-        IPlotter plotter2D = plotterFactory.create("2D Energy Sum");
-        plotter2D.createRegions(1);
-        plotter2D.region(0).plot(energySum2DPlot);
-        
-        // Format the axis labels.
-        PlotterRegion region2D = (PlotterRegion) plotter2D.region(0);
-        region2D.getPlot().setTitle("2D Energy Sum");
-        region2D.getPlot().getXAxis().setLabel("Electron Energy (GeV)");
-        region2D.getPlot().getYAxis().setLabel("Positron Energy (GeV)");
-        
-        // Format the fonts and general plot presentation.
-        setDefault2DStyle(region2D, false);
-        
-        // Show the plot.
-        plotter2D.setParameter("plotterWidth", "2000");
-        plotter2D.setParameter("plotterHeight", "1200");
-        plotter2D.show();
-        
-        // Format and display the histograms.
-        for(int i = 0; i < 2; i++) {
-            // Scale the histogram by the appropriate scaling factor.
-            invariantMassPlots[i].scale(1.0 / scaleFactor);
-            
-            // Create a plotter and plotting region for the plot.
-            IPlotter plotter = plotterFactory.create("Particle Invariant Mass (" + runNumber[i] + ")");
-            plotter.createRegions(1);
-            plotter.region(0).plot(invariantMassPlots[i]);
-            
-            // Format the axis labels.
-            PlotterRegion region = (PlotterRegion) plotter.region(0);
-            region.getPlot().setTitle("Particle Invariant Mass (" + runNumber[i] + ")");
-            region.getPlot().getXAxis().setLabel("Invariant Mass (GeV)");
-            region.getPlot().getYAxis().setLabel("Rate (Hz)");
-            
-            // Format the fonts and general plot presentation.
-            setDefault1DStyle(region, new ColorStyle[] { ColorStyle.GREY });
-            
-            // Show the plot.
-            plotter.setParameter("plotterWidth", "2000");
-            plotter.setParameter("plotterHeight", "1200");
-            plotter.show();
-        }
-        
-        // Note which plot is the numerator and which is the denominator.
-        int numerator   = 0;
-        int denominator = 1;
-        
-        // Create a new histogram to display the ratios of the rates.
-        IHistogram1D ratioPlot = AIDA.defaultInstance().histogram1D("Invariant Mass Ratio (" + runNumber[numerator] + " / "
-                + runNumber[denominator] + ")", invariantMassPlots[0].axis().bins(),
-                invariantMassPlots[0].axis().lowerEdge(), invariantMassPlots[0].axis().upperEdge());
-        
-        // Iterate over each bin.
-        for(int bin = 0; bin < invariantMassPlots[0].axis().bins(); bin++) {
-            // Calculate the ratio.
-            double ratio = invariantMassPlots[numerator].binHeight(bin) / invariantMassPlots[denominator].binHeight(bin);
-            
-            // If the ratio is either not a number of infinite, skip
-            // this bin.
-            if(Double.isNaN(ratio) || Double.isInfinite(ratio)) { continue; }
-            
-            // Populate the ratio plot bin.
-            ratioPlot.fill(invariantMassPlots[0].axis().binCenter(bin), ratio);
-        }
-        
-        // Create a plotter and plotting region for the plot.
-        IPlotter plotter = plotterFactory.create("Invariant Mass Ratio (5411 / 5554)");
-        plotter.createRegions(1);
-        plotter.region(0).plot(ratioPlot);
-        
-        // Format the axis labels.
-        PlotterRegion region = (PlotterRegion) plotter.region(0);
-        region.getPlot().setTitle("Invariant Mass Ratio (" + runNumber[numerator] + " / " + runNumber[denominator] + ")");
-        region.getPlot().getXAxis().setLabel("Invariant Mass (GeV)");
-        region.getPlot().getXAxis().setMin(0.010);
-        region.getPlot().getXAxis().setMax(0.060);
-        region.getPlot().getYAxis().setLabel("Ratio");
-        
-        // Format the fonts and general plot presentation.
-        setDefault1DStyle(region, new ColorStyle[] { ColorStyle.GREY });
-        
-        // Disable the error bars.
-        JASHist1DHistogramStyle fillStyle = (JASHist1DHistogramStyle) region.getDataForName(region.getAllDataNames()[0]).getStyle();
-        fillStyle.setShowErrorBars(false);
-        
-        // Show the plot.
-        plotter.setParameter("plotterWidth", "2000");
-        plotter.setParameter("plotterHeight", "1200");
-        plotter.show();
-        
-        // Close the trees.
-        for(int i = 0; i < plotFile.length; i++) {
-            tree[i].close();
-        }
-    }
-    
-    /**
-     * Sets the plot display formatting for 1D plots.
-     * @param region - The plotter region to format.
-     * @param color - The data color settings to use.
-     */
-    private static final void setDefault1DStyle(PlotterRegion region, ColorStyle[] color) {
-        // Get the names of each plot on in the region.
-        String[] dataNames = region.getAllDataNames();
-        
-        // Check whether this is an overlay plot. Overlay plots contain
-        // more than one data name.
-        boolean overlay = (dataNames.length > 1 ? true : false);
-        
-        // Iterate over each plot in the region.
-        for(int i = 0; i < dataNames.length; i++) {
-            // Set the overlay style if needed.
-            if(overlay) {
-                // Get the fill style for the current data type.
-                JASHist1DHistogramStyle fillStyle = (JASHist1DHistogramStyle) region.getDataForName(dataNames[i]).getStyle();
-                
-                // Set the histogram style to display thick-lined bars
-                // with no fill. The color is set by the "color" argument.
-                fillStyle.setHistogramFill(false);
-                fillStyle.setHistogramBarLineWidth(3);
-                fillStyle.setHistogramBarLineColor(color[i].getFillColor());
-                
-                // Set the legend text style.
-                region.getPlot().getLegend().setFont(new Font("Calibri", Font.PLAIN, 20));
-            }
-            
-            // Otherwise, set the fill style for a single plot.
-            else {
-                // Get the fill style for the current data type.
-                JASHist1DHistogramStyle fillStyle = (JASHist1DHistogramStyle) region.getDataForName(dataNames[i]).getStyle();
-                
-                // Set the histogram style to display thick-lined bars
-                // with a fill color. The colors are defined by the
-                // "color" argument.
-                fillStyle.setHistogramBarLineWidth(3);
-                fillStyle.setHistogramBarColor(color[i].getFillColor());
-                fillStyle.setHistogramBarLineColor(color[i].getLineColor());
-            }
-            
-            // Set the statistics box style.
-            region.getPlot().getStats().setVisible(true);
-            region.getPlot().getStats().setFont(BASIC_FONT);
-            
-            // Set the title font.
-            region.getPlot().getTitleObject().setFont(TITLE_FONT);
-            
-            // Set the axis tick-mark fonts.
-            region.getPlot().getXAxis().setFont(BASIC_FONT);
-            region.getPlot().getYAxis().setFont(BASIC_FONT);
-            region.getPlot().getXAxis().getLabelObject().setFont(AXIS_FONT);
-            region.getPlot().getYAxis().getLabelObject().setFont(AXIS_FONT);
-        }
-    }
-    
-    /**
-     * Sets the plot display formatting for 1D plots.
-     * @param region - The plotter region to format.
-     */
-    private static final void setDefault2DStyle(PlotterRegion region, boolean logarithmic) {
-        // Get the fill style object. 2D plots should never be overlay
-        // plots, so there should only ever be one data name.
-        JASHist2DHistogramStyle fillStyle = (JASHist2DHistogramStyle) region.getDataForName(region.getAllDataNames()[0]).getStyle();
-        
-        // Set the fill style for a two-dimensional plot.
-        if(logarithmic) { fillStyle.setLogZ(true); }
-        fillStyle.setHistStyle(JASHist2DHistogramStyle.STYLE_COLORMAP);
-        fillStyle.setColorMapScheme(JASHist2DHistogramStyle.COLORMAP_RAINBOW);
-        
-        // Make the statistics box invisible.
-        region.getPlot().getStats().setVisible(false);
-        
-        // Set the general plot font (which is also the z-axis font).
-        region.getPlot().setFont(BASIC_FONT);
-        
-        // Set the title font.
-        region.getPlot().getTitleObject().setFont(TITLE_FONT);
-        
-        // Set the axis tick-mark fonts.
-        region.getPlot().getXAxis().setFont(BASIC_FONT);
-        region.getPlot().getYAxis().setFont(BASIC_FONT);
-        region.getPlot().getXAxis().getLabelObject().setFont(AXIS_FONT);
-        region.getPlot().getYAxis().getLabelObject().setFont(AXIS_FONT);
-    }
+	// Define plot fonts.
+	private static final Font BASIC_FONT = new Font("Calibri", Font.PLAIN, 20);
+	private static final Font AXIS_FONT  = new Font("Calibri", Font.BOLD,  25);
+	private static final Font TITLE_FONT = new Font("Calibri", Font.BOLD,  35);
+	
+	// Defines the color style options for plot data.
+	private enum ColorStyle {
+		 MS_BLUE(new Color( 79, 129, 189), new Color( 36,  64,  97)), MS_ORANGE(new Color(247, 150,  70), new Color(152,  72,   6)),
+		  MS_RED(new Color(192,  80,  77), new Color( 99,  36,  35)),      GREY(new Color(166, 166, 166), new Color( 89,  89,  89)),
+		MS_GREEN(new Color(155, 187,  89), new Color( 79,  98,  40)),   CRIMSON(new Color(161,   0,   0), new Color(104,   0,   0)),
+		    RUST(new Color(161,  80,   0), new Color(105,  80,   0)),    YELLOW(new Color(161, 161,   0), new Color(122, 109,   8)),
+		  FOREST(new Color( 65, 102,   0), new Color( 37,  79,   0)),     GREEN(new Color(  7, 132,  70), new Color(  7,  82,  30)),
+		    TEAL(new Color(  0, 130, 130), new Color(  0,  90, 100)),  CERULEAN(new Color(  0,  86, 130), new Color(  0,  28,  83)),
+		    BLUE(new Color(  0,  33, 203), new Color(  0,   0, 137)),    INDIGO(new Color( 68,  10, 127), new Color(  0,   0,  61)),
+		  PURPLE(new Color(106,   0, 106), new Color( 63,   0,  56)),   FUSCHIA(new Color(119,   0,  60), new Color( 60,   0,  60));
+		
+		private final Color fillColor;
+		private final Color lineColor;
+		
+		private ColorStyle(Color fillColor, Color lineColor) {
+			this.fillColor = fillColor;
+			this.lineColor = lineColor;
+		}
+		
+		public Color getFillColor() { return fillColor; }
+		
+		public Color getLineColor() { return lineColor; }
+	};
+		
+	/**
+	 * Loads all plots in a file and formats them according to the
+	 * indicated style.
+	 * @param args - Unused default executable parameter.
+	 * @throws IOException Occurs if there is an issue opening the file.
+	 */
+	public static void main(String[] args) throws IOException {
+		// Define the root directory for the plots.
+		String rootDir = "D:\\cygwin64\\home\\Kyle\\";
+		
+		// Define the new name of the file containing the trigger plots.
+		String[] plotFile = {
+				rootDir + "temp.aida"
+		};
+		
+		// Define the run numbers for each file.
+		String[] runNumber = { "1 Hits", "2 Hits" };
+		
+		// Define the scaling factors for each plot.
+		double scaleFactor = 13.254;
+		
+		// Get the plots file and open it.
+		IAnalysisFactory af = IAnalysisFactory.create();
+		ITree[] tree = new ITree[plotFile.length];
+		for(int i = 0; i < plotFile.length; i++) {
+			tree[i] = af.createTreeFactory().create(plotFile[i]);
+			if(tree[i] == null) { throw new IllegalArgumentException("Unable to load plot file."); }
+		}
+		
+		// Get the histograms.
+		IHistogram1D[] invariantMassPlots = new IHistogram1D[3];
+		invariantMassPlots[0] = (IHistogram1D) tree[0].find("Trident Analysis/Particle Invariant Mass (1 Hit)");
+		invariantMassPlots[1] = (IHistogram1D) tree[0].find("Trident Analysis/Particle Invariant Mass (2 Hit)");
+		IHistogram1D electronEnergyPlot = (IHistogram1D) tree[0].find("Trident Analysis/Electron Energy");
+		IHistogram1D positronEnergyPlot = (IHistogram1D) tree[0].find("Trident Analysis/Positron Energy");
+		IHistogram1D energySumPlot = (IHistogram1D) tree[0].find("Trident Analysis/Energy Sum Distribution");
+		IHistogram2D energySum2DPlot = (IHistogram2D) tree[0].find("Trident Analysis/2D Energy Distribution");
+		IHistogram1D tridentElectronEnergyPlot = (IHistogram1D) tree[0].find("Trident Analysis/Trident Electron Energy");
+		IHistogram1D tridentPositronEnergyPlot = (IHistogram1D) tree[0].find("Trident Analysis/Trident Positron Energy");
+		
+		// Define the plot titles and arrays.
+		IHistogram[] plots = { electronEnergyPlot, positronEnergyPlot, energySumPlot, tridentElectronEnergyPlot, tridentPositronEnergyPlot };
+		String[] titles = { "Electron Energy", "Positron Energy", "Energy Sum", "Trident Electron Energy", "Trident Positron Energy" };
+		String[] xTitles = { "Energy (GeV)", "Energy (GeV)", "Energy Sum (GeV)", "Energy (GeV)", "Energy (GeV)" };
+		
+		// Re-bin the histograms to have 5-times larger bins. First,
+		// get the bin count and upper and lower bounds of the plot.
+		int bins = invariantMassPlots[0].axis().bins();
+		double low = invariantMassPlots[0].axis().binLowerEdge(0);
+		double high = invariantMassPlots[0].axis().binUpperEdge(invariantMassPlots[0].axis().bins() - 1);
+		
+		// Create new plots with the larger bin sizes.
+		AIDA aida = AIDA.defaultInstance();
+		IHistogram1D[] newPlot = new IHistogram1D[2];
+		newPlot[0] = aida.histogram1D("Particle Invariant Mass (1 Hit)", bins / 5, low, high);
+		newPlot[1] = aida.histogram1D("Particle Invariant Mass (2 Hit)", bins / 5, low, high);
+		
+		// Populate the new plots with the data from the old ones.
+		for(int j = 0; j < 2; j++) {
+			for(int i = 0; i < bins; i++) {
+				int entries = invariantMassPlots[j].binEntries(i);
+				double center = invariantMassPlots[j].axis().binCenter(i);
+				for(int k = 0; k < entries; k++) {
+					newPlot[j].fill(center);
+				}
+			}
+		}
+		
+		// Replace the old plots.
+		invariantMassPlots = newPlot;
+		
+		// Create a plotter factory.
+		IPlotterFactory plotterFactory = af.createPlotterFactory();
+		
+		// Format and display the basic histograms.
+		for(int i = 0; i < plots.length; i++) {
+			// Scale the histogram by the appropriate scaling factor.
+			plots[i].scale(1.0 / scaleFactor);
+			
+			// Create a plotter and plotting region for the plot.
+			IPlotter plotter = plotterFactory.create(titles[i]);
+			plotter.createRegions(1);
+			plotter.region(0).plot(plots[i]);
+			
+			// Format the axis labels.
+			PlotterRegion region = (PlotterRegion) plotter.region(0);
+			region.getPlot().setTitle(titles[i]);
+			region.getPlot().getXAxis().setLabel(xTitles[i]);
+			region.getPlot().getYAxis().setLabel("Rate (Hz)");
+			
+			// Format the fonts and general plot presentation.
+			setDefault1DStyle(region, new ColorStyle[] { ColorStyle.GREY });
+			
+			// Show the plot.
+			plotter.setParameter("plotterWidth", "2000");
+			plotter.setParameter("plotterHeight", "1200");
+			plotter.show();
+		}
+		
+		// Format and display the 2D histogram.
+		energySum2DPlot.scale(1.0 / scaleFactor);
+		IPlotter plotter2D = plotterFactory.create("2D Energy Sum");
+		plotter2D.createRegions(1);
+		plotter2D.region(0).plot(energySum2DPlot);
+		
+		// Format the axis labels.
+		PlotterRegion region2D = (PlotterRegion) plotter2D.region(0);
+		region2D.getPlot().setTitle("2D Energy Sum");
+		region2D.getPlot().getXAxis().setLabel("Electron Energy (GeV)");
+		region2D.getPlot().getYAxis().setLabel("Positron Energy (GeV)");
+		
+		// Format the fonts and general plot presentation.
+		setDefault2DStyle(region2D, false);
+		
+		// Show the plot.
+		plotter2D.setParameter("plotterWidth", "2000");
+		plotter2D.setParameter("plotterHeight", "1200");
+		plotter2D.show();
+		
+		// Format and display the histograms.
+		for(int i = 0; i < 2; i++) {
+			// Scale the histogram by the appropriate scaling factor.
+			invariantMassPlots[i].scale(1.0 / scaleFactor);
+			
+			// Create a plotter and plotting region for the plot.
+			IPlotter plotter = plotterFactory.create("Particle Invariant Mass (" + runNumber[i] + ")");
+			plotter.createRegions(1);
+			plotter.region(0).plot(invariantMassPlots[i]);
+			
+			// Format the axis labels.
+			PlotterRegion region = (PlotterRegion) plotter.region(0);
+			region.getPlot().setTitle("Particle Invariant Mass (" + runNumber[i] + ")");
+			region.getPlot().getXAxis().setLabel("Invariant Mass (GeV)");
+			region.getPlot().getYAxis().setLabel("Rate (Hz)");
+			
+			// Format the fonts and general plot presentation.
+			setDefault1DStyle(region, new ColorStyle[] { ColorStyle.GREY });
+			
+			// Show the plot.
+			plotter.setParameter("plotterWidth", "2000");
+			plotter.setParameter("plotterHeight", "1200");
+			plotter.show();
+		}
+		
+		// Note which plot is the numerator and which is the denominator.
+		int numerator   = 0;
+		int denominator = 1;
+		
+		// Create a new histogram to display the ratios of the rates.
+		IHistogram1D ratioPlot = AIDA.defaultInstance().histogram1D("Invariant Mass Ratio (" + runNumber[numerator] + " / "
+				+ runNumber[denominator] + ")", invariantMassPlots[0].axis().bins(),
+				invariantMassPlots[0].axis().lowerEdge(), invariantMassPlots[0].axis().upperEdge());
+		
+		// Iterate over each bin.
+		for(int bin = 0; bin < invariantMassPlots[0].axis().bins(); bin++) {
+			// Calculate the ratio.
+			double ratio = invariantMassPlots[numerator].binHeight(bin) / invariantMassPlots[denominator].binHeight(bin);
+			
+			// If the ratio is either not a number of infinite, skip
+			// this bin.
+			if(Double.isNaN(ratio) || Double.isInfinite(ratio)) { continue; }
+			
+			// Populate the ratio plot bin.
+			ratioPlot.fill(invariantMassPlots[0].axis().binCenter(bin), ratio);
+		}
+		
+		// Create a plotter and plotting region for the plot.
+		IPlotter plotter = plotterFactory.create("Invariant Mass Ratio (5411 / 5554)");
+		plotter.createRegions(1);
+		plotter.region(0).plot(ratioPlot);
+		
+		// Format the axis labels.
+		PlotterRegion region = (PlotterRegion) plotter.region(0);
+		region.getPlot().setTitle("Invariant Mass Ratio (" + runNumber[numerator] + " / " + runNumber[denominator] + ")");
+		region.getPlot().getXAxis().setLabel("Invariant Mass (GeV)");
+		region.getPlot().getXAxis().setMin(0.010);
+		region.getPlot().getXAxis().setMax(0.060);
+		region.getPlot().getYAxis().setLabel("Ratio");
+		
+		// Format the fonts and general plot presentation.
+		setDefault1DStyle(region, new ColorStyle[] { ColorStyle.GREY });
+		
+		// Disable the error bars.
+		JASHist1DHistogramStyle fillStyle = (JASHist1DHistogramStyle) region.getDataForName(region.getAllDataNames()[0]).getStyle();
+		fillStyle.setShowErrorBars(false);
+		
+		// Show the plot.
+		plotter.setParameter("plotterWidth", "2000");
+		plotter.setParameter("plotterHeight", "1200");
+		plotter.show();
+		
+		// Close the trees.
+		for(int i = 0; i < plotFile.length; i++) {
+			tree[i].close();
+		}
+	}
+	
+	/**
+	 * Sets the plot display formatting for 1D plots.
+	 * @param region - The plotter region to format.
+	 * @param color - The data color settings to use.
+	 */
+	private static final void setDefault1DStyle(PlotterRegion region, ColorStyle[] color) {
+		// Get the names of each plot on in the region.
+		String[] dataNames = region.getAllDataNames();
+		
+		// Check whether this is an overlay plot. Overlay plots contain
+		// more than one data name.
+		boolean overlay = (dataNames.length > 1 ? true : false);
+		
+		// Iterate over each plot in the region.
+		for(int i = 0; i < dataNames.length; i++) {
+			// Set the overlay style if needed.
+			if(overlay) {
+				// Get the fill style for the current data type.
+				JASHist1DHistogramStyle fillStyle = (JASHist1DHistogramStyle) region.getDataForName(dataNames[i]).getStyle();
+				
+				// Set the histogram style to display thick-lined bars
+				// with no fill. The color is set by the "color" argument.
+				fillStyle.setHistogramFill(false);
+				fillStyle.setHistogramBarLineWidth(3);
+				fillStyle.setHistogramBarLineColor(color[i].getFillColor());
+				
+				// Set the legend text style.
+				region.getPlot().getLegend().setFont(new Font("Calibri", Font.PLAIN, 20));
+			}
+			
+			// Otherwise, set the fill style for a single plot.
+			else {
+				// Get the fill style for the current data type.
+				JASHist1DHistogramStyle fillStyle = (JASHist1DHistogramStyle) region.getDataForName(dataNames[i]).getStyle();
+				
+				// Set the histogram style to display thick-lined bars
+				// with a fill color. The colors are defined by the
+				// "color" argument.
+				fillStyle.setHistogramBarLineWidth(3);
+				fillStyle.setHistogramBarColor(color[i].getFillColor());
+				fillStyle.setHistogramBarLineColor(color[i].getLineColor());
+			}
+			
+			// Set the statistics box style.
+			region.getPlot().getStats().setVisible(true);
+			region.getPlot().getStats().setFont(BASIC_FONT);
+			
+			// Set the title font.
+			region.getPlot().getTitleObject().setFont(TITLE_FONT);
+			
+			// Set the axis tick-mark fonts.
+			region.getPlot().getXAxis().setFont(BASIC_FONT);
+			region.getPlot().getYAxis().setFont(BASIC_FONT);
+			region.getPlot().getXAxis().getLabelObject().setFont(AXIS_FONT);
+			region.getPlot().getYAxis().getLabelObject().setFont(AXIS_FONT);
+		}
+	}
+	
+	/**
+	 * Sets the plot display formatting for 1D plots.
+	 * @param region - The plotter region to format.
+	 */
+	private static final void setDefault2DStyle(PlotterRegion region, boolean logarithmic) {
+		// Get the fill style object. 2D plots should never be overlay
+		// plots, so there should only ever be one data name.
+		JASHist2DHistogramStyle fillStyle = (JASHist2DHistogramStyle) region.getDataForName(region.getAllDataNames()[0]).getStyle();
+		
+		// Set the fill style for a two-dimensional plot.
+		if(logarithmic) { fillStyle.setLogZ(true); }
+		fillStyle.setHistStyle(JASHist2DHistogramStyle.STYLE_COLORMAP);
+		fillStyle.setColorMapScheme(JASHist2DHistogramStyle.COLORMAP_RAINBOW);
+		
+		// Make the statistics box invisible.
+		region.getPlot().getStats().setVisible(false);
+		
+		// Set the general plot font (which is also the z-axis font).
+		region.getPlot().setFont(BASIC_FONT);
+		
+		// Set the title font.
+		region.getPlot().getTitleObject().setFont(TITLE_FONT);
+		
+		// Set the axis tick-mark fonts.
+		region.getPlot().getXAxis().setFont(BASIC_FONT);
+		region.getPlot().getYAxis().setFont(BASIC_FONT);
+		region.getPlot().getXAxis().getLabelObject().setFont(AXIS_FONT);
+		region.getPlot().getYAxis().getLabelObject().setFont(AXIS_FONT);
+	}
 }

Modified: java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/formatter/MTEPlotFormatter.java
 =============================================================================
--- java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/formatter/MTEPlotFormatter.java	(original)
+++ java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/formatter/MTEPlotFormatter.java	Tue Sep 27 08:50:14 2016
@@ -19,308 +19,308 @@
 import hep.aida.ref.plotter.PlotterRegion;
 
 public class MTEPlotFormatter {
-    // Define plot fonts.
-    private static final Font BASIC_FONT = new Font("Calibri", Font.PLAIN, 20);
-    private static final Font AXIS_FONT  = new Font("Calibri", Font.BOLD,  25);
-    private static final Font TITLE_FONT = new Font("Calibri", Font.BOLD,  35);
-    
-    // Defines the color style options for plot data.
-    private enum ColorStyle {
-         MS_BLUE(new Color( 79, 129, 189), new Color( 36,  64,  97)), MS_ORANGE(new Color(247, 150,  70), new Color(152,  72,   6)),
-          MS_RED(new Color(192,  80,  77), new Color( 99,  36,  35)),      GREY(new Color(166, 166, 166), new Color( 89,  89,  89)),
-        MS_GREEN(new Color(155, 187,  89), new Color( 79,  98,  40)),   CRIMSON(new Color(161,   0,   0), new Color(104,   0,   0)),
-            RUST(new Color(161,  80,   0), new Color(105,  80,   0)),    YELLOW(new Color(161, 161,   0), new Color(122, 109,   8)),
-          FOREST(new Color( 65, 102,   0), new Color( 37,  79,   0)),     GREEN(new Color(  7, 132,  70), new Color(  7,  82,  30)),
-            TEAL(new Color(  0, 130, 130), new Color(  0,  90, 100)),  CERULEAN(new Color(  0,  86, 130), new Color(  0,  28,  83)),
-            BLUE(new Color(  0,  33, 203), new Color(  0,   0, 137)),    INDIGO(new Color( 68,  10, 127), new Color(  0,   0,  61)),
-          PURPLE(new Color(106,   0, 106), new Color( 63,   0,  56)),   FUSCHIA(new Color(119,   0,  60), new Color( 60,   0,  60));
-        
-        private final Color fillColor;
-        private final Color lineColor;
-        
-        private ColorStyle(Color fillColor, Color lineColor) {
-            this.fillColor = fillColor;
-            this.lineColor = lineColor;
-        }
-        
-        public Color getFillColor() { return fillColor; }
-        
-        public Color getLineColor() { return lineColor; }
-    };
-        
-    /**
-     * Loads all plots in a file and formats them according to the
-     * indicated style.
-     * @param args - Unused default executable parameter.
-     * @throws IOException Occurs if there is an issue opening the file.
-     */
-    public static void main(String[] args) throws IOException {
-        // Define the root directory for the plots.
-        String rootDir = "D:\\cygwin64\\home\\Kyle\\";
-        
-        // Define the new name of the file containing the trigger plots.
-        String plotFile = rootDir + "temp.aida";
-        
-        // Define the scaling factors for each plot.
-        double scaleFactor = 1;
-        
-        // Get the plots file and open it.
-        IAnalysisFactory af = IAnalysisFactory.create();
-        ITree tree = af.createTreeFactory().create(plotFile);
-        if(tree == null) { throw new IllegalArgumentException("Unable to load plot file."); }
-        
-        // Define index references for each event type.
-        int MOLLER  = 0;
-        int TRIDENT = 1;
-        int ELASTIC = 2;
-        
-        // Get the histograms.
-        IHistogram1D[] trackCountPlots = new IHistogram1D[3];
-        trackCountPlots[MOLLER]  = (IHistogram1D) tree.find("MTE Analysis/Møller Event Tracks");
-        trackCountPlots[TRIDENT] = (IHistogram1D) tree.find("MTE Analysis/Trident Event Tracks");
-        trackCountPlots[ELASTIC] = (IHistogram1D) tree.find("MTE Analysis/Elastic Event Tracks");
-        
-        IHistogram1D[] energyPlots = new IHistogram1D[3];
-        energyPlots[MOLLER]  = (IHistogram1D) tree.find("MTE Analysis/Møller Electron Energy Distribution");
-        energyPlots[TRIDENT] = (IHistogram1D) tree.find("MTE Analysis/Trident Electron Energy Distribution");
-        energyPlots[ELASTIC] = (IHistogram1D) tree.find("MTE Analysis/Elastic Energy Distribution");
-        
-        IHistogram1D[] energySumPlots = new IHistogram1D[2];
-        energySumPlots[MOLLER]  = (IHistogram1D) tree.find("MTE Analysis/Møller Energy Sum Distribution");
-        energySumPlots[TRIDENT] = (IHistogram1D) tree.find("MTE Analysis/Trident Energy Sum Distribution");
-        
-        IHistogram2D[] energy2DPlots = new IHistogram2D[2];
-        energy2DPlots[MOLLER]  = (IHistogram2D) tree.find("MTE Analysis/Møller 2D Energy Distribution");
-        energy2DPlots[TRIDENT] = (IHistogram2D) tree.find("MTE Analysis/Trident 2D Energy Distribution");
-        
-        // Create a plotter factory.
-        IPlotterFactory plotterFactory = af.createPlotterFactory();
-        
-        // Format the track count plots.
-        for(IHistogram1D trackCountPlot : trackCountPlots) {
-            // Create a plotter and plotting region for the plot.
-            IPlotter plotter = plotterFactory.create(trackCountPlot.title());
-            plotter.createRegions(1);
-            plotter.region(0).plot(trackCountPlot);
-            
-            // Format the axis labels.
-            PlotterRegion region = (PlotterRegion) plotter.region(0);
-            region.getPlot().setTitle(trackCountPlot.title());
-            region.getPlot().getXAxis().setLabel("Number of Tracks");
-            region.getPlot().getYAxis().setLabel("Count");
-            
-            // Format the fonts and general plot presentation.
-            setDefault1DStyle(region, new ColorStyle[] { ColorStyle.GREY });
-            
-            // Show the plot.
-            plotter.setParameter("plotterWidth", "2000");
-            plotter.setParameter("plotterHeight", "1200");
-            plotter.show();
-        }
-        
-        // Format the electron energy plots.
-        for(IHistogram1D energyPlot : energyPlots) {
-            // Create a plotter and plotting region for the plot.
-            IPlotter plotter = plotterFactory.create(energyPlot.title());
-            plotter.createRegions(1);
-            plotter.region(0).plot(energyPlot);
-            
-            // Format the axis labels.
-            PlotterRegion region = (PlotterRegion) plotter.region(0);
-            region.getPlot().setTitle(energyPlot.title());
-            region.getPlot().getXAxis().setLabel("Track Energy (GeV)");
-            region.getPlot().getYAxis().setLabel("Count");
-            
-            // Format the fonts and general plot presentation.
-            setDefault1DStyle(region, new ColorStyle[] { ColorStyle.GREY });
-            
-            // Show the plot.
-            plotter.setParameter("plotterWidth", "2000");
-            plotter.setParameter("plotterHeight", "1200");
-            plotter.show();
-        }
-        
-        // Format the energy sum plots.
-        for(IHistogram1D energySumPlot : energySumPlots) {
-            // Create a plotter and plotting region for the plot.
-            IPlotter plotter = plotterFactory.create(energySumPlot.title());
-            plotter.createRegions(1);
-            plotter.region(0).plot(energySumPlot);
-            
-            // Format the axis labels.
-            PlotterRegion region = (PlotterRegion) plotter.region(0);
-            region.getPlot().setTitle(energySumPlot.title());
-            region.getPlot().getXAxis().setLabel("Track Energy (GeV)");
-            region.getPlot().getYAxis().setLabel("Count");
-            
-            // Format the fonts and general plot presentation.
-            setDefault1DStyle(region, new ColorStyle[] { ColorStyle.GREY });
-            
-            // Show the plot.
-            plotter.setParameter("plotterWidth", "2000");
-            plotter.setParameter("plotterHeight", "1200");
-            plotter.show();
-        }
-        
-        // Format the 2D energy sum plots.
-        for(IHistogram2D energy2DPlot : energy2DPlots) {
-            // Create a plotter and plotting region for the plot.
-            IPlotter plotter = plotterFactory.create(energy2DPlot.title());
-            plotter.createRegions(1);
-            plotter.region(0).plot(energy2DPlot);
-            
-            // Format the axis labels.
-            PlotterRegion region = (PlotterRegion) plotter.region(0);
-            region.getPlot().setTitle(energy2DPlot.title());
-            region.getPlot().getXAxis().setLabel("First Track Energy (GeV)");
-            region.getPlot().getYAxis().setLabel("Second Track Energy (GeV)");
-            
-            
-            // Format the fonts and general plot presentation.
-            setDefault2DStyle(region, false);
-            
-            // Show the plot.
-            plotter.setParameter("plotterWidth", "2000");
-            plotter.setParameter("plotterHeight", "1200");
-            plotter.show();
-        }
-        
-        // Disable the error bars.
-        //JASHist1DHistogramStyle fillStyle = (JASHist1DHistogramStyle) region.getDataForName(region.getAllDataNames()[0]).getStyle();
-        //fillStyle.setShowErrorBars(false);
-        
-        // Close the tree.
-        tree.close();
-    }
-    
-    /**
-     * Sets the plot display formatting for 1D plots.
-     * @param region - The plotter region to format.
-     * @param color - The data color settings to use.
-     */
-    private static final void setDefault1DStyle(PlotterRegion region, ColorStyle[] color) {
-        // Get the names of each plot on in the region.
-        String[] dataNames = region.getAllDataNames();
-        
-        // Check whether this is an overlay plot. Overlay plots contain
-        // more than one data name.
-        boolean overlay = (dataNames.length > 1 ? true : false);
-        
-        // Iterate over each plot in the region.
-        for(int i = 0; i < dataNames.length; i++) {
-            // Set the overlay style if needed.
-            if(overlay) {
-                // Get the fill style for the current data type.
-                JASHist1DHistogramStyle fillStyle = (JASHist1DHistogramStyle) region.getDataForName(dataNames[i]).getStyle();
-                
-                // Set the histogram style to display thick-lined bars
-                // with no fill. The color is set by the "color" argument.
-                fillStyle.setHistogramFill(false);
-                fillStyle.setHistogramBarLineWidth(3);
-                fillStyle.setHistogramBarLineColor(color[i].getFillColor());
-                
-                // Set the legend text style.
-                region.getPlot().getLegend().setFont(new Font("Calibri", Font.PLAIN, 20));
-            }
-            
-            // Otherwise, set the fill style for a single plot.
-            else {
-                // Get the fill style for the current data type.
-                JASHist1DHistogramStyle fillStyle = (JASHist1DHistogramStyle) region.getDataForName(dataNames[i]).getStyle();
-                
-                // Set the histogram style to display thick-lined bars
-                // with a fill color. The colors are defined by the
-                // "color" argument.
-                fillStyle.setHistogramBarLineWidth(3);
-                fillStyle.setHistogramBarColor(color[i].getFillColor());
-                fillStyle.setHistogramBarLineColor(color[i].getLineColor());
-            }
-            
-            // Set the statistics box style.
-            region.getPlot().getStats().setVisible(true);
-            region.getPlot().getStats().setFont(BASIC_FONT);
-            
-            // Set the title font.
-            region.getPlot().getTitleObject().setFont(TITLE_FONT);
-            
-            // Set the axis tick-mark fonts.
-            region.getPlot().getXAxis().setFont(BASIC_FONT);
-            region.getPlot().getYAxis().setFont(BASIC_FONT);
-            region.getPlot().getXAxis().getLabelObject().setFont(AXIS_FONT);
-            region.getPlot().getYAxis().getLabelObject().setFont(AXIS_FONT);
-        }
-    }
-    
-    /**
-     * Sets the plot display formatting for 1D plots.
-     * @param region - The plotter region to format.
-     */
-    private static final void setDefault2DStyle(PlotterRegion region, boolean logarithmic) {
-        // Get the fill style object. 2D plots should never be overlay
-        // plots, so there should only ever be one data name.
-        JASHist2DHistogramStyle fillStyle = (JASHist2DHistogramStyle) region.getDataForName(region.getAllDataNames()[0]).getStyle();
-        
-        // Set the fill style for a two-dimensional plot.
-        if(logarithmic) { fillStyle.setLogZ(true); }
-        fillStyle.setHistStyle(JASHist2DHistogramStyle.STYLE_COLORMAP);
-        fillStyle.setColorMapScheme(JASHist2DHistogramStyle.COLORMAP_RAINBOW);
-        
-        // Make the statistics box invisible.
-        region.getPlot().getStats().setVisible(false);
-        
-        // Set the general plot font (which is also the z-axis font).
-        region.getPlot().setFont(BASIC_FONT);
-        
-        // Set the title font.
-        region.getPlot().getTitleObject().setFont(TITLE_FONT);
-        
-        // Set the axis tick-mark fonts.
-        region.getPlot().getXAxis().setFont(BASIC_FONT);
-        region.getPlot().getYAxis().setFont(BASIC_FONT);
-        region.getPlot().getXAxis().getLabelObject().setFont(AXIS_FONT);
-        region.getPlot().getYAxis().getLabelObject().setFont(AXIS_FONT);
-    }
-    
-    /**
-     * Recursive method that gets all object names from a tree that
-     * are not directories. Method should not be called directly, but
-     * rather called only through the <code>getHistograms(ITree)</code>
-     * method.
-     * @param tree - The tree from which to obtain the object names.
-     * @param directory - The directory in which to search for objects.
-     * @param list - The list in which to place the objects.
-     * @return Returns the <code>List</code> collection that was given
-     * as an argument.
-     */
-    private static final List<String> getHistograms(ITree tree, String directory, List<String> list) {
-        // Get the list of objects in the directory.
-        String[] treeObjects = tree.listObjectNames(directory);
-        
-        // Print the objects.
-        for(String objectName : treeObjects) {
-            // Check if the object is a directory.
-            boolean isDirectory = isDirectory(objectName);
-            
-            // If the object is a directory, get the histograms from it.
-            if(isDirectory) {
-                getHistograms(tree, objectName, list);
-            }
-            
-            // If the object is a plot, add it to the list.
-            else { list.add(objectName); }
-        }
-        
-        // Return the list.
-        return list;
-    }
-    
-    /**
-     * Checks whether a tree object is a directory.
-     * @param object - The object to check.
-     * @return Returns <code>true</code> if the object is a directory
-     * and <code>false</code> otherwise.
-     */
-    private static final boolean isDirectory(String object) {
-        return (object.toCharArray()[object.length() - 1] == '/');
-    }
+	// Define plot fonts.
+	private static final Font BASIC_FONT = new Font("Calibri", Font.PLAIN, 20);
+	private static final Font AXIS_FONT  = new Font("Calibri", Font.BOLD,  25);
+	private static final Font TITLE_FONT = new Font("Calibri", Font.BOLD,  35);
+	
+	// Defines the color style options for plot data.
+	private enum ColorStyle {
+		 MS_BLUE(new Color( 79, 129, 189), new Color( 36,  64,  97)), MS_ORANGE(new Color(247, 150,  70), new Color(152,  72,   6)),
+		  MS_RED(new Color(192,  80,  77), new Color( 99,  36,  35)),      GREY(new Color(166, 166, 166), new Color( 89,  89,  89)),
+		MS_GREEN(new Color(155, 187,  89), new Color( 79,  98,  40)),   CRIMSON(new Color(161,   0,   0), new Color(104,   0,   0)),
+		    RUST(new Color(161,  80,   0), new Color(105,  80,   0)),    YELLOW(new Color(161, 161,   0), new Color(122, 109,   8)),
+		  FOREST(new Color( 65, 102,   0), new Color( 37,  79,   0)),     GREEN(new Color(  7, 132,  70), new Color(  7,  82,  30)),
+		    TEAL(new Color(  0, 130, 130), new Color(  0,  90, 100)),  CERULEAN(new Color(  0,  86, 130), new Color(  0,  28,  83)),
+		    BLUE(new Color(  0,  33, 203), new Color(  0,   0, 137)),    INDIGO(new Color( 68,  10, 127), new Color(  0,   0,  61)),
+		  PURPLE(new Color(106,   0, 106), new Color( 63,   0,  56)),   FUSCHIA(new Color(119,   0,  60), new Color( 60,   0,  60));
+		
+		private final Color fillColor;
+		private final Color lineColor;
+		
+		private ColorStyle(Color fillColor, Color lineColor) {
+			this.fillColor = fillColor;
+			this.lineColor = lineColor;
+		}
+		
+		public Color getFillColor() { return fillColor; }
+		
+		public Color getLineColor() { return lineColor; }
+	};
+		
+	/**
+	 * Loads all plots in a file and formats them according to the
+	 * indicated style.
+	 * @param args - Unused default executable parameter.
+	 * @throws IOException Occurs if there is an issue opening the file.
+	 */
+	public static void main(String[] args) throws IOException {
+		// Define the root directory for the plots.
+		String rootDir = "D:\\cygwin64\\home\\Kyle\\";
+		
+		// Define the new name of the file containing the trigger plots.
+		String plotFile = rootDir + "temp.aida";
+		
+		// Define the scaling factors for each plot.
+		double scaleFactor = 1;
+		
+		// Get the plots file and open it.
+		IAnalysisFactory af = IAnalysisFactory.create();
+		ITree tree = af.createTreeFactory().create(plotFile);
+		if(tree == null) { throw new IllegalArgumentException("Unable to load plot file."); }
+		
+		// Define index references for each event type.
+		int MOLLER  = 0;
+		int TRIDENT = 1;
+		int ELASTIC = 2;
+		
+		// Get the histograms.
+		IHistogram1D[] trackCountPlots = new IHistogram1D[3];
+		trackCountPlots[MOLLER]  = (IHistogram1D) tree.find("MTE Analysis/Møller Event Tracks");
+		trackCountPlots[TRIDENT] = (IHistogram1D) tree.find("MTE Analysis/Trident Event Tracks");
+		trackCountPlots[ELASTIC] = (IHistogram1D) tree.find("MTE Analysis/Elastic Event Tracks");
+		
+		IHistogram1D[] energyPlots = new IHistogram1D[3];
+		energyPlots[MOLLER]  = (IHistogram1D) tree.find("MTE Analysis/Møller Electron Energy Distribution");
+		energyPlots[TRIDENT] = (IHistogram1D) tree.find("MTE Analysis/Trident Electron Energy Distribution");
+		energyPlots[ELASTIC] = (IHistogram1D) tree.find("MTE Analysis/Elastic Energy Distribution");
+		
+		IHistogram1D[] energySumPlots = new IHistogram1D[2];
+		energySumPlots[MOLLER]  = (IHistogram1D) tree.find("MTE Analysis/Møller Energy Sum Distribution");
+		energySumPlots[TRIDENT] = (IHistogram1D) tree.find("MTE Analysis/Trident Energy Sum Distribution");
+		
+		IHistogram2D[] energy2DPlots = new IHistogram2D[2];
+		energy2DPlots[MOLLER]  = (IHistogram2D) tree.find("MTE Analysis/Møller 2D Energy Distribution");
+		energy2DPlots[TRIDENT] = (IHistogram2D) tree.find("MTE Analysis/Trident 2D Energy Distribution");
+		
+		// Create a plotter factory.
+		IPlotterFactory plotterFactory = af.createPlotterFactory();
+		
+		// Format the track count plots.
+		for(IHistogram1D trackCountPlot : trackCountPlots) {
+			// Create a plotter and plotting region for the plot.
+			IPlotter plotter = plotterFactory.create(trackCountPlot.title());
+			plotter.createRegions(1);
+			plotter.region(0).plot(trackCountPlot);
+			
+			// Format the axis labels.
+			PlotterRegion region = (PlotterRegion) plotter.region(0);
+			region.getPlot().setTitle(trackCountPlot.title());
+			region.getPlot().getXAxis().setLabel("Number of Tracks");
+			region.getPlot().getYAxis().setLabel("Count");
+			
+			// Format the fonts and general plot presentation.
+			setDefault1DStyle(region, new ColorStyle[] { ColorStyle.GREY });
+			
+			// Show the plot.
+			plotter.setParameter("plotterWidth", "2000");
+			plotter.setParameter("plotterHeight", "1200");
+			plotter.show();
+		}
+		
+		// Format the electron energy plots.
+		for(IHistogram1D energyPlot : energyPlots) {
+			// Create a plotter and plotting region for the plot.
+			IPlotter plotter = plotterFactory.create(energyPlot.title());
+			plotter.createRegions(1);
+			plotter.region(0).plot(energyPlot);
+			
+			// Format the axis labels.
+			PlotterRegion region = (PlotterRegion) plotter.region(0);
+			region.getPlot().setTitle(energyPlot.title());
+			region.getPlot().getXAxis().setLabel("Track Energy (GeV)");
+			region.getPlot().getYAxis().setLabel("Count");
+			
+			// Format the fonts and general plot presentation.
+			setDefault1DStyle(region, new ColorStyle[] { ColorStyle.GREY });
+			
+			// Show the plot.
+			plotter.setParameter("plotterWidth", "2000");
+			plotter.setParameter("plotterHeight", "1200");
+			plotter.show();
+		}
+		
+		// Format the energy sum plots.
+		for(IHistogram1D energySumPlot : energySumPlots) {
+			// Create a plotter and plotting region for the plot.
+			IPlotter plotter = plotterFactory.create(energySumPlot.title());
+			plotter.createRegions(1);
+			plotter.region(0).plot(energySumPlot);
+			
+			// Format the axis labels.
+			PlotterRegion region = (PlotterRegion) plotter.region(0);
+			region.getPlot().setTitle(energySumPlot.title());
+			region.getPlot().getXAxis().setLabel("Track Energy (GeV)");
+			region.getPlot().getYAxis().setLabel("Count");
+			
+			// Format the fonts and general plot presentation.
+			setDefault1DStyle(region, new ColorStyle[] { ColorStyle.GREY });
+			
+			// Show the plot.
+			plotter.setParameter("plotterWidth", "2000");
+			plotter.setParameter("plotterHeight", "1200");
+			plotter.show();
+		}
+		
+		// Format the 2D energy sum plots.
+		for(IHistogram2D energy2DPlot : energy2DPlots) {
+			// Create a plotter and plotting region for the plot.
+			IPlotter plotter = plotterFactory.create(energy2DPlot.title());
+			plotter.createRegions(1);
+			plotter.region(0).plot(energy2DPlot);
+			
+			// Format the axis labels.
+			PlotterRegion region = (PlotterRegion) plotter.region(0);
+			region.getPlot().setTitle(energy2DPlot.title());
+			region.getPlot().getXAxis().setLabel("First Track Energy (GeV)");
+			region.getPlot().getYAxis().setLabel("Second Track Energy (GeV)");
+			
+			
+			// Format the fonts and general plot presentation.
+			setDefault2DStyle(region, false);
+			
+			// Show the plot.
+			plotter.setParameter("plotterWidth", "2000");
+			plotter.setParameter("plotterHeight", "1200");
+			plotter.show();
+		}
+		
+		// Disable the error bars.
+		//JASHist1DHistogramStyle fillStyle = (JASHist1DHistogramStyle) region.getDataForName(region.getAllDataNames()[0]).getStyle();
+		//fillStyle.setShowErrorBars(false);
+		
+		// Close the tree.
+		tree.close();
+	}
+	
+	/**
+	 * Sets the plot display formatting for 1D plots.
+	 * @param region - The plotter region to format.
+	 * @param color - The data color settings to use.
+	 */
+	private static final void setDefault1DStyle(PlotterRegion region, ColorStyle[] color) {
+		// Get the names of each plot on in the region.
+		String[] dataNames = region.getAllDataNames();
+		
+		// Check whether this is an overlay plot. Overlay plots contain
+		// more than one data name.
+		boolean overlay = (dataNames.length > 1 ? true : false);
+		
+		// Iterate over each plot in the region.
+		for(int i = 0; i < dataNames.length; i++) {
+			// Set the overlay style if needed.
+			if(overlay) {
+				// Get the fill style for the current data type.
+				JASHist1DHistogramStyle fillStyle = (JASHist1DHistogramStyle) region.getDataForName(dataNames[i]).getStyle();
+				
+				// Set the histogram style to display thick-lined bars
+				// with no fill. The color is set by the "color" argument.
+				fillStyle.setHistogramFill(false);
+				fillStyle.setHistogramBarLineWidth(3);
+				fillStyle.setHistogramBarLineColor(color[i].getFillColor());
+				
+				// Set the legend text style.
+				region.getPlot().getLegend().setFont(new Font("Calibri", Font.PLAIN, 20));
+			}
+			
+			// Otherwise, set the fill style for a single plot.
+			else {
+				// Get the fill style for the current data type.
+				JASHist1DHistogramStyle fillStyle = (JASHist1DHistogramStyle) region.getDataForName(dataNames[i]).getStyle();
+				
+				// Set the histogram style to display thick-lined bars
+				// with a fill color. The colors are defined by the
+				// "color" argument.
+				fillStyle.setHistogramBarLineWidth(3);
+				fillStyle.setHistogramBarColor(color[i].getFillColor());
+				fillStyle.setHistogramBarLineColor(color[i].getLineColor());
+			}
+			
+			// Set the statistics box style.
+			region.getPlot().getStats().setVisible(true);
+			region.getPlot().getStats().setFont(BASIC_FONT);
+			
+			// Set the title font.
+			region.getPlot().getTitleObject().setFont(TITLE_FONT);
+			
+			// Set the axis tick-mark fonts.
+			region.getPlot().getXAxis().setFont(BASIC_FONT);
+			region.getPlot().getYAxis().setFont(BASIC_FONT);
+			region.getPlot().getXAxis().getLabelObject().setFont(AXIS_FONT);
+			region.getPlot().getYAxis().getLabelObject().setFont(AXIS_FONT);
+		}
+	}
+	
+	/**
+	 * Sets the plot display formatting for 1D plots.
+	 * @param region - The plotter region to format.
+	 */
+	private static final void setDefault2DStyle(PlotterRegion region, boolean logarithmic) {
+		// Get the fill style object. 2D plots should never be overlay
+		// plots, so there should only ever be one data name.
+		JASHist2DHistogramStyle fillStyle = (JASHist2DHistogramStyle) region.getDataForName(region.getAllDataNames()[0]).getStyle();
+		
+		// Set the fill style for a two-dimensional plot.
+		if(logarithmic) { fillStyle.setLogZ(true); }
+		fillStyle.setHistStyle(JASHist2DHistogramStyle.STYLE_COLORMAP);
+		fillStyle.setColorMapScheme(JASHist2DHistogramStyle.COLORMAP_RAINBOW);
+		
+		// Make the statistics box invisible.
+		region.getPlot().getStats().setVisible(false);
+		
+		// Set the general plot font (which is also the z-axis font).
+		region.getPlot().setFont(BASIC_FONT);
+		
+		// Set the title font.
+		region.getPlot().getTitleObject().setFont(TITLE_FONT);
+		
+		// Set the axis tick-mark fonts.
+		region.getPlot().getXAxis().setFont(BASIC_FONT);
+		region.getPlot().getYAxis().setFont(BASIC_FONT);
+		region.getPlot().getXAxis().getLabelObject().setFont(AXIS_FONT);
+		region.getPlot().getYAxis().getLabelObject().setFont(AXIS_FONT);
+	}
+	
+	/**
+	 * Recursive method that gets all object names from a tree that
+	 * are not directories. Method should not be called directly, but
+	 * rather called only through the <code>getHistograms(ITree)</code>
+	 * method.
+	 * @param tree - The tree from which to obtain the object names.
+	 * @param directory - The directory in which to search for objects.
+	 * @param list - The list in which to place the objects.
+	 * @return Returns the <code>List</code> collection that was given
+	 * as an argument.
+	 */
+	private static final List<String> getHistograms(ITree tree, String directory, List<String> list) {
+		// Get the list of objects in the directory.
+		String[] treeObjects = tree.listObjectNames(directory);
+		
+		// Print the objects.
+		for(String objectName : treeObjects) {
+			// Check if the object is a directory.
+			boolean isDirectory = isDirectory(objectName);
+			
+			// If the object is a directory, get the histograms from it.
+			if(isDirectory) {
+				getHistograms(tree, objectName, list);
+			}
+			
+			// If the object is a plot, add it to the list.
+			else { list.add(objectName); }
+		}
+		
+		// Return the list.
+		return list;
+	}
+	
+	/**
+	 * Checks whether a tree object is a directory.
+	 * @param object - The object to check.
+	 * @return Returns <code>true</code> if the object is a directory
+	 * and <code>false</code> otherwise.
+	 */
+	private static final boolean isDirectory(String object) {
+		return (object.toCharArray()[object.length() - 1] == '/');
+	}
 }

Modified: java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/formatter/MTETriggerPlotsFormatter.java
 =============================================================================
--- java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/formatter/MTETriggerPlotsFormatter.java	(original)
+++ java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/formatter/MTETriggerPlotsFormatter.java	Tue Sep 27 08:50:14 2016
@@ -15,164 +15,164 @@
 
 
 public class MTETriggerPlotsFormatter {
-    public static void main(String[] args) throws IllegalArgumentException, IOException {
-        // Define the root directory for the plots.
-        String rootDir = "D:\\cygwin64\\home\\Kyle\\";
-        
-        // Define the new name of the file containing the trigger plots.
-        String plotFile = rootDir + "5772-ana.aida";
-        
-        // Get the plots file and open it.
-        IAnalysisFactory af = IAnalysisFactory.create();
-        ITree tree = af.createTreeFactory().create(plotFile);
-        if(tree == null) { throw new IllegalArgumentException("Unable to load plot file."); }
-        
-        // Define the 1D trigger plot names for Møllers and tridents.
-        String[] plotNames1D = { "Cluster Hit Count", "Cluster Seed Energy", "Cluster Total Energy",
-                "Pair Coplanarity", "Pair Energy Difference", "Pair Energy Slope", "Pair Energy Sum" };
-        String[] displayNames1D = { "Cluster Hit Count", "Cluster Seed Energy", "Cluster Total Energy",
-                "Pair Coplanarity", "Pair Energy Difference", "Pair Energy Slope", "Pair Energy Sum" };
-        String[] xAxisNames1D = { "Hit Count", "Seed Energy (GeV)", "Total Energy (GeV)",
-                "Coplanarity (Degrees)", "Energy Difference (GeV)", "Energy Slope (GeV)", "Energy Sum (GeV)" };
-        String yAxisName1D = "Count";
-        
-        // Define the 2D trigger plot names for Møllers and tridents.
-        String[] plotNames2D = { "Cluster Seed", "Pair Energy Sum 2D" };
-        String[] displayNames2D = { "Cluster Seed Distribution", "2D Energy Sum" };
-        String[] xAxisNames2D = { "x-Index", "Second Cluster Energy (GeV)" };
-        String[] yAxisNames2D = { "y-Index", "First Cluster Energy (GeV)" };
-        
-        // Define the 1D trigger plot names for elastics.
-        String[] plotNamesElastic1D = { "Cluster Hit Count", "Cluster Seed Energy", "Cluster Total Energy" };
-        String[] displayNamesElastic1D = { "Cluster Hit Count", "Cluster Seed Energy", "Cluster Total Energy" };
-        String[] xAxisNamesElastic1D = { "Hit Count", "Seed Energy (GeV)", "Total Energy (GeV)" };
-        String yAxisNameElastic1D = "Count";
-        
-        // Define the 2D trigger plot names for elastics.
-        String[] plotNamesElastic2D = { "Cluster Seed" };
-        String[] displayNamesElastic2D = { "Cluster Seed Distribution" };
-        String[] xAxisNamesElastic2D = { "x-Index" };
-        String[] yAxisNamesElastic2D = { "y-Index" };
-        
-        // Define the Møller, trident, and elastic prefixes.
-        String allPrefix = "All Trigger Plots/Pair Plots/";
-        String møllerPrefix = "Møller Trigger Plots/Pair Plots/";
-        String tridentPrefix = "Trident Trigger Plots/Pair Plots/";
-        String elasticPrefix = "Elastic Trigger Plots/Singles Plots/";
-        String allSinglesPrefix = "All Trigger Plots/Singles Plots/";
-        
-        // Define the plot type prefix.
-        String allTypeName = "All Pairs - ";
-        String møllerTypeName = "Møller - ";
-        String tridentTypeName = "Trident - ";
-        String elasticTypeName = "Elastic - ";
-        String allSinglesTypeName = "All Singles - ";
-        
-        // Define the plot type colors.
-        ColorStyle allColor = PlotsFormatter.ColorStyle.GREY;
-        ColorStyle møllerColor = PlotsFormatter.ColorStyle.MS_BLUE;
-        ColorStyle tridentColor = PlotsFormatter.ColorStyle.MS_ORANGE;
-        ColorStyle elasticColor = PlotsFormatter.ColorStyle.MS_GREEN;
-        
-        // Create a plot formatting module.
-        PlotFormatModule module = new PlotFormatModule();
-        
-        // Get the histograms and add them to the module. Start with the
-        // trident and Møller plots.
-        for(int i = 0; i < plotNames1D.length; i++) {
-            // Get the Møller and trident plots.
-            IHistogram1D allPlot = (IHistogram1D) tree.find(allPrefix + plotNames1D[i]);
-            IHistogram1D møllerPlot = (IHistogram1D) tree.find(møllerPrefix + plotNames1D[i]);
-            IHistogram1D tridentPlot = (IHistogram1D) tree.find(tridentPrefix + plotNames1D[i]);
-            
-            // Make a formatted plot for each.
-            FormattedPlot1D allFormattedPlot = new FormattedPlot1D(allPlot, allColor, xAxisNames1D[i], yAxisName1D, allTypeName + displayNames1D[i]);
-            FormattedPlot1D møllerFormattedPlot = new FormattedPlot1D(møllerPlot, møllerColor, xAxisNames1D[i], yAxisName1D, møllerTypeName + displayNames1D[i]);
-            FormattedPlot1D tridentFormattedPlot = new FormattedPlot1D(tridentPlot, tridentColor, xAxisNames1D[i], yAxisName1D, tridentTypeName + displayNames1D[i]);
-            
-            // Add them to the module.
-            module.addPlot1D(allFormattedPlot);
-            module.addPlot1D(møllerFormattedPlot);
-            module.addPlot1D(tridentFormattedPlot);
-        }
-        for(int i = 0; i < plotNames2D.length; i++) {
-            // Get the Møller and trident plots.
-            IHistogram2D allPlot = (IHistogram2D) tree.find(allPrefix + plotNames2D[i]);
-            IHistogram2D møllerPlot = (IHistogram2D) tree.find(møllerPrefix + plotNames2D[i]);
-            IHistogram2D tridentPlot = (IHistogram2D) tree.find(tridentPrefix + plotNames2D[i]);
-            
-            // Make a formatted plot for each.
-            FormattedPlot2D allFormattedPlot = new FormattedPlot2D(allPlot, i == 0 ? true : false, xAxisNames2D[i], yAxisNames2D[i], allTypeName + displayNames2D[i]);
-            FormattedPlot2D møllerFormattedPlot = new FormattedPlot2D(møllerPlot, i == 0 ? true : false, xAxisNames2D[i], yAxisNames2D[i], møllerTypeName + displayNames2D[i]);
-            FormattedPlot2D tridentFormattedPlot = new FormattedPlot2D(tridentPlot, i == 0 ? true : false, xAxisNames2D[i], yAxisNames2D[i], tridentTypeName + displayNames2D[i]);
-            
-            // Add them to the module.
-            module.addPlot2D(allFormattedPlot);
-            module.addPlot2D(møllerFormattedPlot);
-            module.addPlot2D(tridentFormattedPlot);
-        }
-        
-        // Get the histograms for the elastic plots and add them to the module.
-        for(int i = 0; i < plotNamesElastic1D.length; i++) {
-            // Get the Møller and trident plots.
-            IHistogram1D allPlot = (IHistogram1D) tree.find(allSinglesPrefix + plotNames1D[i]);
-            IHistogram1D elasticPlot = (IHistogram1D) tree.find(elasticPrefix + plotNames1D[i]);
-            
-            // Make a formatted plot for each.
-            FormattedPlot1D allFormattedPlot = new FormattedPlot1D(allPlot, allColor, xAxisNamesElastic1D[i], yAxisNameElastic1D,
-                    allSinglesTypeName + displayNamesElastic1D[i]);
-            FormattedPlot1D elasticFormattedPlot = new FormattedPlot1D(elasticPlot, elasticColor, xAxisNamesElastic1D[i], yAxisNameElastic1D,
-                    elasticTypeName + displayNamesElastic1D[i]);
-            
-            // Add them to the module.
-            module.addPlot1D(allFormattedPlot);
-            module.addPlot1D(elasticFormattedPlot);
-        }
-        for(int i = 0; i < plotNamesElastic2D.length; i++) {
-            // Get the Møller and trident plots.
-            IHistogram2D allPlot = (IHistogram2D) tree.find(allPrefix + plotNamesElastic2D[i]);
-            IHistogram2D elasticPlot = (IHistogram2D) tree.find(møllerPrefix + plotNamesElastic2D[i]);
-            
-            // Make a formatted plot for each.
-            FormattedPlot2D allFormattedPlot = new FormattedPlot2D(allPlot, i == 0 ? true : false, xAxisNamesElastic2D[i], yAxisNamesElastic2D[i],
-                    allSinglesTypeName + plotNames2D[i]);
-            FormattedPlot2D elasticFormattedPlot = new FormattedPlot2D(elasticPlot, i == 0 ? true : false, xAxisNamesElastic2D[i], yAxisNamesElastic2D[i],
-                    elasticTypeName + displayNamesElastic2D[i]);
-            
-            // Add them to the module.
-            module.addPlot2D(allFormattedPlot);
-            module.addPlot2D(elasticFormattedPlot);
-        }
-        
-        // Add the MTE plots to the module.
-        module.addPlot1D(new FormattedPlot1D((IHistogram1D) tree.find("MTE Analysis/Elastic Energy Distribution"), elasticColor,
-                "Momentum (GeV)", "Count", "Elastic - Momentum"));
-        module.addPlot1D(new FormattedPlot1D((IHistogram1D) tree.find("MTE Analysis/Elastic Event Tracks"), elasticColor,
-                "Tracks", "Count", "Elastic - Tracks in Event"));
-        
-        module.addPlot1D(new FormattedPlot1D((IHistogram1D) tree.find("MTE Analysis/Møller Energy Sum Distribution"), møllerColor,
-                "Momentum Sum (GeV)", "Count", "Møller - Momentum Sum"));
-        module.addPlot1D(new FormattedPlot1D((IHistogram1D) tree.find("MTE Analysis/Møller Electron Energy Distribution"), møllerColor,
-                "Momentum (GeV)", "Count", "Møller - Momentum (Electron)"));
-        module.addPlot1D(new FormattedPlot1D((IHistogram1D) tree.find("MTE Analysis/Møller Time Coincidence Distribution (All Møller Cuts)"), møllerColor,
-                "Time (ns)", "Count", "Møller - Time Coincidence"));
-        module.addPlot1D(new FormattedPlot1D((IHistogram1D) tree.find("MTE Analysis/Møller Event Tracks"), møllerColor,
-                "Tracks", "Count", "Møller - Tracks in Event"));
-        module.addPlot2D(new FormattedPlot2D((IHistogram2D) tree.find("MTE Analysis/Møller 2D Energy Distribution"), false,
-                "First Track Momentum (GeV)", "Second Track Momentum (GeV)", "Møller - 2D Momentum Sum"));
-        
-        module.addPlot1D(new FormattedPlot1D((IHistogram1D) tree.find("MTE Analysis/Trident Energy Sum Distribution"), tridentColor,
-                "Momentum Sum (GeV)", "Count", "Trident - Momentum Sum"));
-        module.addPlot1D(new FormattedPlot1D((IHistogram1D) tree.find("MTE Analysis/Trident Electron Energy Distribution"), tridentColor,
-                "Momentum (GeV)", "Count", "Trident - Momentum (Electron)"));
-        module.addPlot1D(new FormattedPlot1D((IHistogram1D) tree.find("MTE Analysis/Trident Positron Energy Distribution"), tridentColor,
-                "Momentum (GeV)", "Count", "Trident - Momentum (Positron)"));
-        module.addPlot1D(new FormattedPlot1D((IHistogram1D) tree.find("MTE Analysis/Trident Event Tracks"), tridentColor,
-                "Tracks", "Count", "Trident - Tracks in Event"));
-        module.addPlot2D(new FormattedPlot2D((IHistogram2D) tree.find("MTE Analysis/Trident 2D Energy Distribution"), false,
-                "First Track Momentum (GeV)", "Second Track Momentum (GeV)", "Trident - 2D Momentum Sum"));
-        
-        // Display the plots.
-        module.savePlots("C:\\Users\\Kyle\\Desktop\\EnergyShift\\TestPrint\\");
-    }
+	public static void main(String[] args) throws IllegalArgumentException, IOException {
+		// Define the root directory for the plots.
+		String rootDir = "D:\\cygwin64\\home\\Kyle\\";
+		
+		// Define the new name of the file containing the trigger plots.
+		String plotFile = rootDir + "5772-ana.aida";
+		
+		// Get the plots file and open it.
+		IAnalysisFactory af = IAnalysisFactory.create();
+		ITree tree = af.createTreeFactory().create(plotFile);
+		if(tree == null) { throw new IllegalArgumentException("Unable to load plot file."); }
+		
+		// Define the 1D trigger plot names for Møllers and tridents.
+		String[] plotNames1D = { "Cluster Hit Count", "Cluster Seed Energy", "Cluster Total Energy",
+				"Pair Coplanarity", "Pair Energy Difference", "Pair Energy Slope", "Pair Energy Sum" };
+		String[] displayNames1D = { "Cluster Hit Count", "Cluster Seed Energy", "Cluster Total Energy",
+				"Pair Coplanarity", "Pair Energy Difference", "Pair Energy Slope", "Pair Energy Sum" };
+		String[] xAxisNames1D = { "Hit Count", "Seed Energy (GeV)", "Total Energy (GeV)",
+				"Coplanarity (Degrees)", "Energy Difference (GeV)", "Energy Slope (GeV)", "Energy Sum (GeV)" };
+		String yAxisName1D = "Count";
+		
+		// Define the 2D trigger plot names for Møllers and tridents.
+		String[] plotNames2D = { "Cluster Seed", "Pair Energy Sum 2D" };
+		String[] displayNames2D = { "Cluster Seed Distribution", "2D Energy Sum" };
+		String[] xAxisNames2D = { "x-Index", "Second Cluster Energy (GeV)" };
+		String[] yAxisNames2D = { "y-Index", "First Cluster Energy (GeV)" };
+		
+		// Define the 1D trigger plot names for elastics.
+		String[] plotNamesElastic1D = { "Cluster Hit Count", "Cluster Seed Energy", "Cluster Total Energy" };
+		String[] displayNamesElastic1D = { "Cluster Hit Count", "Cluster Seed Energy", "Cluster Total Energy" };
+		String[] xAxisNamesElastic1D = { "Hit Count", "Seed Energy (GeV)", "Total Energy (GeV)" };
+		String yAxisNameElastic1D = "Count";
+		
+		// Define the 2D trigger plot names for elastics.
+		String[] plotNamesElastic2D = { "Cluster Seed" };
+		String[] displayNamesElastic2D = { "Cluster Seed Distribution" };
+		String[] xAxisNamesElastic2D = { "x-Index" };
+		String[] yAxisNamesElastic2D = { "y-Index" };
+		
+		// Define the Møller, trident, and elastic prefixes.
+		String allPrefix = "All Trigger Plots/Pair Plots/";
+		String møllerPrefix = "Møller Trigger Plots/Pair Plots/";
+		String tridentPrefix = "Trident Trigger Plots/Pair Plots/";
+		String elasticPrefix = "Elastic Trigger Plots/Singles Plots/";
+		String allSinglesPrefix = "All Trigger Plots/Singles Plots/";
+		
+		// Define the plot type prefix.
+		String allTypeName = "All Pairs - ";
+		String møllerTypeName = "Møller - ";
+		String tridentTypeName = "Trident - ";
+		String elasticTypeName = "Elastic - ";
+		String allSinglesTypeName = "All Singles - ";
+		
+		// Define the plot type colors.
+		ColorStyle allColor = PlotsFormatter.ColorStyle.GREY;
+		ColorStyle møllerColor = PlotsFormatter.ColorStyle.MS_BLUE;
+		ColorStyle tridentColor = PlotsFormatter.ColorStyle.MS_ORANGE;
+		ColorStyle elasticColor = PlotsFormatter.ColorStyle.MS_GREEN;
+		
+		// Create a plot formatting module.
+		PlotFormatModule module = new PlotFormatModule();
+		
+		// Get the histograms and add them to the module. Start with the
+		// trident and Møller plots.
+		for(int i = 0; i < plotNames1D.length; i++) {
+			// Get the Møller and trident plots.
+			IHistogram1D allPlot = (IHistogram1D) tree.find(allPrefix + plotNames1D[i]);
+			IHistogram1D møllerPlot = (IHistogram1D) tree.find(møllerPrefix + plotNames1D[i]);
+			IHistogram1D tridentPlot = (IHistogram1D) tree.find(tridentPrefix + plotNames1D[i]);
+			
+			// Make a formatted plot for each.
+			FormattedPlot1D allFormattedPlot = new FormattedPlot1D(allPlot, allColor, xAxisNames1D[i], yAxisName1D, allTypeName + displayNames1D[i]);
+			FormattedPlot1D møllerFormattedPlot = new FormattedPlot1D(møllerPlot, møllerColor, xAxisNames1D[i], yAxisName1D, møllerTypeName + displayNames1D[i]);
+			FormattedPlot1D tridentFormattedPlot = new FormattedPlot1D(tridentPlot, tridentColor, xAxisNames1D[i], yAxisName1D, tridentTypeName + displayNames1D[i]);
+			
+			// Add them to the module.
+			module.addPlot1D(allFormattedPlot);
+			module.addPlot1D(møllerFormattedPlot);
+			module.addPlot1D(tridentFormattedPlot);
+		}
+		for(int i = 0; i < plotNames2D.length; i++) {
+			// Get the Møller and trident plots.
+			IHistogram2D allPlot = (IHistogram2D) tree.find(allPrefix + plotNames2D[i]);
+			IHistogram2D møllerPlot = (IHistogram2D) tree.find(møllerPrefix + plotNames2D[i]);
+			IHistogram2D tridentPlot = (IHistogram2D) tree.find(tridentPrefix + plotNames2D[i]);
+			
+			// Make a formatted plot for each.
+			FormattedPlot2D allFormattedPlot = new FormattedPlot2D(allPlot, i == 0 ? true : false, xAxisNames2D[i], yAxisNames2D[i], allTypeName + displayNames2D[i]);
+			FormattedPlot2D møllerFormattedPlot = new FormattedPlot2D(møllerPlot, i == 0 ? true : false, xAxisNames2D[i], yAxisNames2D[i], møllerTypeName + displayNames2D[i]);
+			FormattedPlot2D tridentFormattedPlot = new FormattedPlot2D(tridentPlot, i == 0 ? true : false, xAxisNames2D[i], yAxisNames2D[i], tridentTypeName + displayNames2D[i]);
+			
+			// Add them to the module.
+			module.addPlot2D(allFormattedPlot);
+			module.addPlot2D(møllerFormattedPlot);
+			module.addPlot2D(tridentFormattedPlot);
+		}
+		
+		// Get the histograms for the elastic plots and add them to the module.
+		for(int i = 0; i < plotNamesElastic1D.length; i++) {
+			// Get the Møller and trident plots.
+			IHistogram1D allPlot = (IHistogram1D) tree.find(allSinglesPrefix + plotNames1D[i]);
+			IHistogram1D elasticPlot = (IHistogram1D) tree.find(elasticPrefix + plotNames1D[i]);
+			
+			// Make a formatted plot for each.
+			FormattedPlot1D allFormattedPlot = new FormattedPlot1D(allPlot, allColor, xAxisNamesElastic1D[i], yAxisNameElastic1D,
+					allSinglesTypeName + displayNamesElastic1D[i]);
+			FormattedPlot1D elasticFormattedPlot = new FormattedPlot1D(elasticPlot, elasticColor, xAxisNamesElastic1D[i], yAxisNameElastic1D,
+					elasticTypeName + displayNamesElastic1D[i]);
+			
+			// Add them to the module.
+			module.addPlot1D(allFormattedPlot);
+			module.addPlot1D(elasticFormattedPlot);
+		}
+		for(int i = 0; i < plotNamesElastic2D.length; i++) {
+			// Get the Møller and trident plots.
+			IHistogram2D allPlot = (IHistogram2D) tree.find(allPrefix + plotNamesElastic2D[i]);
+			IHistogram2D elasticPlot = (IHistogram2D) tree.find(møllerPrefix + plotNamesElastic2D[i]);
+			
+			// Make a formatted plot for each.
+			FormattedPlot2D allFormattedPlot = new FormattedPlot2D(allPlot, i == 0 ? true : false, xAxisNamesElastic2D[i], yAxisNamesElastic2D[i],
+					allSinglesTypeName + plotNames2D[i]);
+			FormattedPlot2D elasticFormattedPlot = new FormattedPlot2D(elasticPlot, i == 0 ? true : false, xAxisNamesElastic2D[i], yAxisNamesElastic2D[i],
+					elasticTypeName + displayNamesElastic2D[i]);
+			
+			// Add them to the module.
+			module.addPlot2D(allFormattedPlot);
+			module.addPlot2D(elasticFormattedPlot);
+		}
+		
+		// Add the MTE plots to the module.
+		module.addPlot1D(new FormattedPlot1D((IHistogram1D) tree.find("MTE Analysis/Elastic Energy Distribution"), elasticColor,
+				"Momentum (GeV)", "Count", "Elastic - Momentum"));
+		module.addPlot1D(new FormattedPlot1D((IHistogram1D) tree.find("MTE Analysis/Elastic Event Tracks"), elasticColor,
+				"Tracks", "Count", "Elastic - Tracks in Event"));
+		
+		module.addPlot1D(new FormattedPlot1D((IHistogram1D) tree.find("MTE Analysis/Møller Energy Sum Distribution"), møllerColor,
+				"Momentum Sum (GeV)", "Count", "Møller - Momentum Sum"));
+		module.addPlot1D(new FormattedPlot1D((IHistogram1D) tree.find("MTE Analysis/Møller Electron Energy Distribution"), møllerColor,
+				"Momentum (GeV)", "Count", "Møller - Momentum (Electron)"));
+		module.addPlot1D(new FormattedPlot1D((IHistogram1D) tree.find("MTE Analysis/Møller Time Coincidence Distribution (All Møller Cuts)"), møllerColor,
+				"Time (ns)", "Count", "Møller - Time Coincidence"));
+		module.addPlot1D(new FormattedPlot1D((IHistogram1D) tree.find("MTE Analysis/Møller Event Tracks"), møllerColor,
+				"Tracks", "Count", "Møller - Tracks in Event"));
+		module.addPlot2D(new FormattedPlot2D((IHistogram2D) tree.find("MTE Analysis/Møller 2D Energy Distribution"), false,
+				"First Track Momentum (GeV)", "Second Track Momentum (GeV)", "Møller - 2D Momentum Sum"));
+		
+		module.addPlot1D(new FormattedPlot1D((IHistogram1D) tree.find("MTE Analysis/Trident Energy Sum Distribution"), tridentColor,
+				"Momentum Sum (GeV)", "Count", "Trident - Momentum Sum"));
+		module.addPlot1D(new FormattedPlot1D((IHistogram1D) tree.find("MTE Analysis/Trident Electron Energy Distribution"), tridentColor,
+				"Momentum (GeV)", "Count", "Trident - Momentum (Electron)"));
+		module.addPlot1D(new FormattedPlot1D((IHistogram1D) tree.find("MTE Analysis/Trident Positron Energy Distribution"), tridentColor,
+				"Momentum (GeV)", "Count", "Trident - Momentum (Positron)"));
+		module.addPlot1D(new FormattedPlot1D((IHistogram1D) tree.find("MTE Analysis/Trident Event Tracks"), tridentColor,
+				"Tracks", "Count", "Trident - Tracks in Event"));
+		module.addPlot2D(new FormattedPlot2D((IHistogram2D) tree.find("MTE Analysis/Trident 2D Energy Distribution"), false,
+				"First Track Momentum (GeV)", "Second Track Momentum (GeV)", "Trident - 2D Momentum Sum"));
+		
+		// Display the plots.
+		module.savePlots("C:\\Users\\Kyle\\Desktop\\EnergyShift\\TestPrint\\");
+	}
 }

Modified: java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/formatter/ParticleMCAnalysisPlotsFormatter.java
 =============================================================================
--- java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/formatter/ParticleMCAnalysisPlotsFormatter.java	(original)
+++ java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/formatter/ParticleMCAnalysisPlotsFormatter.java	Tue Sep 27 08:50:14 2016
@@ -13,43 +13,43 @@
 import org.hps.users.kmccarty.plots.PlotsFormatter.ColorStyle;
 
 public class ParticleMCAnalysisPlotsFormatter {
-    public static void main(String[] args) throws IllegalArgumentException, IOException {
-        // Define the root directory for the plots.
-        String rootDir = "D:\\cygwin64\\home\\Kyle\\";
-        
-        // Define the new name of the file containing the trigger plots.
-        String plotFile = rootDir + "moller-mc-out_triggerPlots.aida";
-        
-        // Get the plots file and open it.
-        IAnalysisFactory af = IAnalysisFactory.create();
-        ITree tree = af.createTreeFactory().create(plotFile);
-        if(tree == null) { throw new IllegalArgumentException("Unable to load plot file."); }
-        
-        // Create a plot formatting module.
-        PlotFormatModule module = new PlotFormatModule();
-        
-        // Define the plot color.
-        ColorStyle plotColor = ColorStyle.MS_BLUE;
-        
-        // Define the plots to be read.
-        module.addPlot1D(new FormattedPlot1D((IHistogram1D) tree.find("MC Analysis/Electron Energy Distribution"),
-                plotColor, "Electron Energy (GeV)", "Count", "Electron Energy Distribution"));
-        module.addPlot1D(new FormattedPlot1D((IHistogram1D) tree.find("MC Analysis/Electron\\Electron Momentum Sum Distribution"),
-                plotColor, "Momentum Sum (GeV)", "Count", "Momentum Sum Distribution"));
-        module.addPlot1D(new FormattedPlot1D((IHistogram1D) tree.find("MC Analysis/Electron\\Electron Pair Angle Distribution"),
-                plotColor, "Momentum Sum (GeV)", "Count", "Pair Angle Distribution"));
-        module.addPlot1D(new FormattedPlot1D((IHistogram1D) tree.find("MC Analysis/Particle x-Momentum Distribution"),
-                plotColor, "Momentum (GeV)", "Count", "Particle x-Momentum Distribution"));
-        module.addPlot1D(new FormattedPlot1D((IHistogram1D) tree.find("MC Analysis/Particle y-Momentum Distribution"),
-                plotColor, "Momentum (GeV)", "Count", "Particle y-Momentum Distribution"));
-        module.addPlot1D(new FormattedPlot1D((IHistogram1D) tree.find("MC Analysis/Particle z-Momentum Distribution"),
-                plotColor, "Momentum (GeV)", "Count", "Particle z-Momentum Distribution"));
-        module.addPlot2D(new FormattedPlot2D((IHistogram2D) tree.find("MC Analysis/Electron\\Electron 2D Momentum Distribution"),
-                true, "Particle 1 Momentum (GeV)", "Particle 2 Momentum (GeV)", "2D Momentum Sum Distribution"));
-        module.addPlot2D(new FormattedPlot2D((IHistogram2D) tree.find("MC Analysis/Particle Momentum Distribution"),
-                true, "px (GeV)", "py (GeV)", "Particle x/y Momentum Distribution"));
-        
-        // Display the plots.
-        module.displayPlots();
-    }
+	public static void main(String[] args) throws IllegalArgumentException, IOException {
+		// Define the root directory for the plots.
+		String rootDir = "D:\\cygwin64\\home\\Kyle\\";
+		
+		// Define the new name of the file containing the trigger plots.
+		String plotFile = rootDir + "moller-mc-out_triggerPlots.aida";
+		
+		// Get the plots file and open it.
+		IAnalysisFactory af = IAnalysisFactory.create();
+		ITree tree = af.createTreeFactory().create(plotFile);
+		if(tree == null) { throw new IllegalArgumentException("Unable to load plot file."); }
+		
+		// Create a plot formatting module.
+		PlotFormatModule module = new PlotFormatModule();
+		
+		// Define the plot color.
+		ColorStyle plotColor = ColorStyle.MS_BLUE;
+		
+		// Define the plots to be read.
+		module.addPlot1D(new FormattedPlot1D((IHistogram1D) tree.find("MC Analysis/Electron Energy Distribution"),
+				plotColor, "Electron Energy (GeV)", "Count", "Electron Energy Distribution"));
+		module.addPlot1D(new FormattedPlot1D((IHistogram1D) tree.find("MC Analysis/Electron\\Electron Momentum Sum Distribution"),
+				plotColor, "Momentum Sum (GeV)", "Count", "Momentum Sum Distribution"));
+		module.addPlot1D(new FormattedPlot1D((IHistogram1D) tree.find("MC Analysis/Electron\\Electron Pair Angle Distribution"),
+				plotColor, "Momentum Sum (GeV)", "Count", "Pair Angle Distribution"));
+		module.addPlot1D(new FormattedPlot1D((IHistogram1D) tree.find("MC Analysis/Particle x-Momentum Distribution"),
+				plotColor, "Momentum (GeV)", "Count", "Particle x-Momentum Distribution"));
+		module.addPlot1D(new FormattedPlot1D((IHistogram1D) tree.find("MC Analysis/Particle y-Momentum Distribution"),
+				plotColor, "Momentum (GeV)", "Count", "Particle y-Momentum Distribution"));
+		module.addPlot1D(new FormattedPlot1D((IHistogram1D) tree.find("MC Analysis/Particle z-Momentum Distribution"),
+				plotColor, "Momentum (GeV)", "Count", "Particle z-Momentum Distribution"));
+		module.addPlot2D(new FormattedPlot2D((IHistogram2D) tree.find("MC Analysis/Electron\\Electron 2D Momentum Distribution"),
+				true, "Particle 1 Momentum (GeV)", "Particle 2 Momentum (GeV)", "2D Momentum Sum Distribution"));
+		module.addPlot2D(new FormattedPlot2D((IHistogram2D) tree.find("MC Analysis/Particle Momentum Distribution"),
+				true, "px (GeV)", "py (GeV)", "Particle x/y Momentum Distribution"));
+		
+		// Display the plots.
+		module.displayPlots();
+	}
 }

Modified: java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/formatter/RafoTridentFormatter.java
 =============================================================================
--- java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/formatter/RafoTridentFormatter.java	(original)
+++ java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/formatter/RafoTridentFormatter.java	Tue Sep 27 08:50:14 2016
@@ -13,101 +13,101 @@
 import hep.aida.ITree;
 
 public class RafoTridentFormatter {
-    /**
-     * Loads all plots in a file and formats them according to the
-     * indicated style.
-     * @param args - Unused default executable parameter.
-     * @throws IOException Occurs if there is an issue opening the file.
-     */
-    public static void main(String[] args) throws IOException {
-        // Define the root directory for the plots.
-        String rootDir = "D:\\cygwin64\\home\\Kyle\\";
-        
-        // Define the new name of the file containing the trigger plots.
-        String plotFile = rootDir + "mte-out.aida";
-        
-        // Get the plots file and open it.
-        IAnalysisFactory af = IAnalysisFactory.create();
-        ITree tree = af.createTreeFactory().create(plotFile);
-        if(tree == null) { throw new IllegalArgumentException("Unable to load plot file."); }
-        
-        // Declare the histogram names.
-        String energySumName = "Energy Sum";
-        String timeCoincidenceName = "Time Coincidence";
-        String timeEnergy2DName = "Cluster Time vs. Cluster Energy";
-        String hCoplanaritySum2DName = "Hardware Coplanarity vs. Energy Sum";
-        String coplanaritySum2DName = "Calculated Coplanarity vs. Energy Sum";
-        String energySum2DName = "Top Cluster Energy vs. Bottom Cluster Energy";
-        String fiducial = " (Fiducial Region)";
-        
-        // Get the histograms.
-        IHistogram1D[] energySum = {
-                (IHistogram1D) tree.find("Trident/" + energySumName),
-                (IHistogram1D) tree.find("Trident/" + energySumName + fiducial)
-        };
-        IHistogram1D[] timeCoincidence = {
-                (IHistogram1D) tree.find("Trident/" + timeCoincidenceName),
-                (IHistogram1D) tree.find("Trident/" + timeCoincidenceName + fiducial)
-        };
-        IHistogram2D[] coplanaritySum = {
-                (IHistogram2D) tree.find("Trident/" + coplanaritySum2DName),
-                (IHistogram2D) tree.find("Trident/" + coplanaritySum2DName + fiducial)
-        };
-        IHistogram2D[] hcoplanaritySum = {
-                (IHistogram2D) tree.find("Trident/" + hCoplanaritySum2DName),
-                (IHistogram2D) tree.find("Trident/" + hCoplanaritySum2DName + fiducial)
-        };
-        IHistogram2D[] energySum2D = {
-                (IHistogram2D) tree.find("Trident/" + energySum2DName),
-                (IHistogram2D) tree.find("Trident/" + energySum2DName + fiducial)
-        };
-        IHistogram2D[] timeEnergy = {
-                (IHistogram2D) tree.find("Trident/" + timeEnergy2DName),
-                (IHistogram2D) tree.find("Trident/" + timeEnergy2DName + fiducial)
-        };
-        
-        // Define the scaling factors for each plot.
-        double scaleFactor = 19000.0 / 9736969.0;
-        
-        // Define the plot titles and arrays for 1D plots.
-        IHistogram1D[][] plots = { energySum, timeCoincidence  };
-        String titles[] = { energySumName, timeCoincidenceName, coplanaritySum2DName, hCoplanaritySum2DName, energySum2DName, timeEnergy2DName };
-        String[] xTitles = { "Energy (GeV)", "Time Difference (ns)" };
-        String yTitle = "Rate (Hz)";
-        
-        // Define the plot titles and arrays for 2D plots.
-        IHistogram2D[][] plots2D = { coplanaritySum, hcoplanaritySum, energySum2D, timeEnergy };
-        String[] titles2D = { coplanaritySum2DName, hCoplanaritySum2DName, energySum2DName, timeEnergy2DName };
-        String[] xTitles2D = { "Coplanarity (Degrees)", "Coplanarity (Degrees)", "Top Cluster Energy (GeV)", "Time Coincidence (ns)" };
-        String[] yTitles2D = { "Energy Sum (GeV)", "Energy Sum (GeV)", "Bottom Cluster Energy (GeV)", "Energy Sum (GeV)" };
-        String zTitle2D = "Rate (Hz)";
-        
-        // Create a plot formatting module.
-        PlotFormatModule module = new PlotFormatModule();
-        
-        // Define the plot color.
-        ColorStyle plotColor = ColorStyle.MS_BLUE;
-        
-        // Define the plots to be read.
-        for(int i = 0; i < plots.length; i++) {
-            plots[i][0].scale(scaleFactor);
-            plots[i][1].scale(scaleFactor);
-            module.addPlot1D(new FormattedPlot1D(plots[i][0], plotColor, xTitles[i], yTitle, titles[i]));
-            module.addPlot1D(new FormattedPlot1D(plots[i][1], plotColor, xTitles[i],  yTitle, titles[i] + fiducial));
-        }
-        for(int i = 0; i < plots2D.length; i++) {
-            plots2D[i][0].scale(scaleFactor);
-            plots2D[i][1].scale(scaleFactor);
-            module.addPlot2D(new FormattedPlot2D(plots2D[i][0], false, xTitles2D[i], yTitles2D[i], titles2D[i]));
-            module.addPlot2D(new FormattedPlot2D(plots2D[i][1], false, xTitles2D[i], yTitles2D[i], titles2D[i] + fiducial));
-        }
-        
-        // Display the plots.
-        //module.displayPlots();
-        module.savePlots("C:\\Users\\Kyle\\Desktop\\EnergyShift\\run-5772\\RafoPlots\\");
-        module.exportPlots("C:\\Users\\Kyle\\Desktop\\EnergyShift\\run-5772\\RafoPlots\\");
-        
-        // Close the tree.
-        tree.close();
-    }
+	/**
+	 * Loads all plots in a file and formats them according to the
+	 * indicated style.
+	 * @param args - Unused default executable parameter.
+	 * @throws IOException Occurs if there is an issue opening the file.
+	 */
+	public static void main(String[] args) throws IOException {
+		// Define the root directory for the plots.
+		String rootDir = "D:\\cygwin64\\home\\Kyle\\";
+		
+		// Define the new name of the file containing the trigger plots.
+		String plotFile = rootDir + "mte-out.aida";
+		
+		// Get the plots file and open it.
+		IAnalysisFactory af = IAnalysisFactory.create();
+		ITree tree = af.createTreeFactory().create(plotFile);
+		if(tree == null) { throw new IllegalArgumentException("Unable to load plot file."); }
+		
+		// Declare the histogram names.
+		String energySumName = "Energy Sum";
+		String timeCoincidenceName = "Time Coincidence";
+		String timeEnergy2DName = "Cluster Time vs. Cluster Energy";
+		String hCoplanaritySum2DName = "Hardware Coplanarity vs. Energy Sum";
+		String coplanaritySum2DName = "Calculated Coplanarity vs. Energy Sum";
+		String energySum2DName = "Top Cluster Energy vs. Bottom Cluster Energy";
+		String fiducial = " (Fiducial Region)";
+		
+		// Get the histograms.
+		IHistogram1D[] energySum = {
+				(IHistogram1D) tree.find("Trident/" + energySumName),
+				(IHistogram1D) tree.find("Trident/" + energySumName + fiducial)
+		};
+		IHistogram1D[] timeCoincidence = {
+				(IHistogram1D) tree.find("Trident/" + timeCoincidenceName),
+				(IHistogram1D) tree.find("Trident/" + timeCoincidenceName + fiducial)
+		};
+		IHistogram2D[] coplanaritySum = {
+				(IHistogram2D) tree.find("Trident/" + coplanaritySum2DName),
+				(IHistogram2D) tree.find("Trident/" + coplanaritySum2DName + fiducial)
+		};
+		IHistogram2D[] hcoplanaritySum = {
+				(IHistogram2D) tree.find("Trident/" + hCoplanaritySum2DName),
+				(IHistogram2D) tree.find("Trident/" + hCoplanaritySum2DName + fiducial)
+		};
+		IHistogram2D[] energySum2D = {
+				(IHistogram2D) tree.find("Trident/" + energySum2DName),
+				(IHistogram2D) tree.find("Trident/" + energySum2DName + fiducial)
+		};
+		IHistogram2D[] timeEnergy = {
+				(IHistogram2D) tree.find("Trident/" + timeEnergy2DName),
+				(IHistogram2D) tree.find("Trident/" + timeEnergy2DName + fiducial)
+		};
+		
+		// Define the scaling factors for each plot.
+		double scaleFactor = 19000.0 / 9736969.0;
+		
+		// Define the plot titles and arrays for 1D plots.
+		IHistogram1D[][] plots = { energySum, timeCoincidence  };
+		String titles[] = { energySumName, timeCoincidenceName, coplanaritySum2DName, hCoplanaritySum2DName, energySum2DName, timeEnergy2DName };
+		String[] xTitles = { "Energy (GeV)", "Time Difference (ns)" };
+		String yTitle = "Rate (Hz)";
+		
+		// Define the plot titles and arrays for 2D plots.
+		IHistogram2D[][] plots2D = { coplanaritySum, hcoplanaritySum, energySum2D, timeEnergy };
+		String[] titles2D = { coplanaritySum2DName, hCoplanaritySum2DName, energySum2DName, timeEnergy2DName };
+		String[] xTitles2D = { "Coplanarity (Degrees)", "Coplanarity (Degrees)", "Top Cluster Energy (GeV)", "Time Coincidence (ns)" };
+		String[] yTitles2D = { "Energy Sum (GeV)", "Energy Sum (GeV)", "Bottom Cluster Energy (GeV)", "Energy Sum (GeV)" };
+		String zTitle2D = "Rate (Hz)";
+		
+		// Create a plot formatting module.
+		PlotFormatModule module = new PlotFormatModule();
+		
+		// Define the plot color.
+		ColorStyle plotColor = ColorStyle.MS_BLUE;
+		
+		// Define the plots to be read.
+		for(int i = 0; i < plots.length; i++) {
+			plots[i][0].scale(scaleFactor);
+			plots[i][1].scale(scaleFactor);
+			module.addPlot1D(new FormattedPlot1D(plots[i][0], plotColor, xTitles[i], yTitle, titles[i]));
+			module.addPlot1D(new FormattedPlot1D(plots[i][1], plotColor, xTitles[i],  yTitle, titles[i] + fiducial));
+		}
+		for(int i = 0; i < plots2D.length; i++) {
+			plots2D[i][0].scale(scaleFactor);
+			plots2D[i][1].scale(scaleFactor);
+			module.addPlot2D(new FormattedPlot2D(plots2D[i][0], false, xTitles2D[i], yTitles2D[i], titles2D[i]));
+			module.addPlot2D(new FormattedPlot2D(plots2D[i][1], false, xTitles2D[i], yTitles2D[i], titles2D[i] + fiducial));
+		}
+		
+		// Display the plots.
+		//module.displayPlots();
+		module.savePlots("C:\\Users\\Kyle\\Desktop\\EnergyShift\\run-5772\\RafoPlots\\");
+		module.exportPlots("C:\\Users\\Kyle\\Desktop\\EnergyShift\\run-5772\\RafoPlots\\");
+		
+		// Close the tree.
+		tree.close();
+	}
 }

Modified: java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/formatter/SingleTriggerPlotsFormatter.java
 =============================================================================
--- java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/formatter/SingleTriggerPlotsFormatter.java	(original)
+++ java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/formatter/SingleTriggerPlotsFormatter.java	Tue Sep 27 08:50:14 2016
@@ -13,151 +13,151 @@
 import hep.aida.ITree;
 
 public class SingleTriggerPlotsFormatter {
-    
-    public static void main(String[] args) throws IllegalArgumentException, IOException {
-        // Define the root directory for the plots.
-        String rootDir = "D:\\cygwin64\\home\\Kyle\\";
-        
-        // Define the new name of the file containing the trigger plots.
-        String plotFile = rootDir + "trident-readout-full.aida";
-        
-        // Get the plots file and open it.
-        IAnalysisFactory af = IAnalysisFactory.create();
-        ITree tree = af.createTreeFactory().create(plotFile);
-        if(tree == null) { throw new IllegalArgumentException("Unable to load plot file."); }
-        
-        // Define plots variables.
-        int UNCUT     = 0;
-        int TRIGGERED = 1;
-        String[] plotsDir = { "NoCuts/", "PassedAll/" };
-        int PLOT_HIT_COUNT      = 0;
-        int PLOT_SEED_ENERGY    = 1;
-        int PLOT_CLUSTER_ENERGY = 2;
-        int PLOT_COPLANARITY    = 3;
-        int PLOT_ENERGY_SUM     = 4;
-        int PLOT_ENERGY_DIFF    = 5;
-        int PLOT_ENERGY_SLOPE   = 6;
-        int PLOT_SEED_DIST      = 0;
-        int PLOT_ENERGY_SUM_2D  = 1;
-        
-        // Define the internal plot names.
-        String[] plotNameInternal1D = new String[7];
-        String[] plotNameInternal2D = new String[2];
-        plotNameInternal1D[PLOT_HIT_COUNT]      = "Cluster Hit Count";
-        plotNameInternal1D[PLOT_SEED_ENERGY]    = "Cluster Seed Energy";
-        plotNameInternal1D[PLOT_CLUSTER_ENERGY] = "Cluster Total Energy";
-        plotNameInternal1D[PLOT_COPLANARITY]    = "Pair Coplanarity";
-        plotNameInternal1D[PLOT_ENERGY_SUM]     = "Pair Energy Sum";
-        plotNameInternal1D[PLOT_ENERGY_DIFF]    = "Pair Energy Difference";
-        plotNameInternal1D[PLOT_ENERGY_SLOPE]   = "Pair Energy Slope";
-        plotNameInternal2D[PLOT_SEED_DIST]      = "Cluster Seed";
-        plotNameInternal2D[PLOT_ENERGY_SUM_2D]  = "Pair Energy Sum 2D";
-        
-        // Define the plot display names.
-        String[] plotName1D = new String[7];
-        String[] plotName2D = new String[2];
-        for(int j = 0; j < plotNameInternal1D.length; j++) {
-            plotName1D[j] = plotNameInternal1D[j];
-        }
-        for(int j = 0; j < plotNameInternal2D.length; j++) {
-            plotName2D[j] = plotNameInternal2D[j];
-        }
-        plotName1D[PLOT_ENERGY_SUM]    = "1D Pair Energy Sum";
-        plotName2D[PLOT_SEED_DIST]     = "Cluster Seed Distribution";
-        plotName2D[PLOT_ENERGY_SUM_2D] = "2D Pair Energy Sum";
-        
-        String[] xTitles1D = new String[plotName1D.length];
-        String[] xTitles2D = new String[plotName2D.length];
-        xTitles1D[PLOT_HIT_COUNT]      = "Hit Count";
-        xTitles1D[PLOT_SEED_ENERGY]    = "Seed Energy (GeV)";
-        xTitles1D[PLOT_CLUSTER_ENERGY] = "Cluster Energy (GeV)";
-        xTitles1D[PLOT_COPLANARITY]    = "Coplanarity Angle (Degrees)";
-        xTitles1D[PLOT_ENERGY_SUM]     = "Energy Sum (GeV)";
-        xTitles1D[PLOT_ENERGY_DIFF]    = "Energy Difference (GeV)";
-        xTitles1D[PLOT_ENERGY_SLOPE]   = "Energy Slope (GeV)";
-        xTitles2D[PLOT_SEED_DIST]      = "x-Index";
-        xTitles2D[PLOT_ENERGY_SUM_2D]  = "First Cluster Energy (GeV)";
-        String yTitle1D = "Count";
-        String[] yTitles2D = new String[plotName2D.length];
-        yTitles2D[PLOT_SEED_DIST]      = "y-Index";
-        yTitles2D[PLOT_ENERGY_SUM_2D]  = "Second Cluster Energy (GeV)";
-        
-        // Define axis ranges.
-        double[] axisRanges1D = new double[plotName1D.length];
-        axisRanges1D[PLOT_HIT_COUNT]      = -1;
-        axisRanges1D[PLOT_SEED_ENERGY]    = 1.1;
-        axisRanges1D[PLOT_CLUSTER_ENERGY] = 1.1;
-        axisRanges1D[PLOT_COPLANARITY]    = 180;
-        axisRanges1D[PLOT_ENERGY_SUM]     = 2.2;
-        axisRanges1D[PLOT_ENERGY_DIFF]    = 1.1;
-        axisRanges1D[PLOT_ENERGY_SLOPE]   = 2.4;
-        double[] xAxisRanges2D = new double[plotName2D.length];
-        double[] yAxisRanges2D = new double[plotName2D.length];
-        xAxisRanges2D[PLOT_SEED_DIST]      = -1;
-        xAxisRanges2D[PLOT_ENERGY_SUM_2D]  = 1.1;
-        yAxisRanges2D[PLOT_SEED_DIST]      = -1;
-        yAxisRanges2D[PLOT_ENERGY_SUM_2D]  = 1.1;
-        
-        // Define the plot names.
-        String[][] plotLocations1D = new String[plotsDir.length][plotNameInternal1D.length];
-        String[][] plotLocations2D = new String[plotsDir.length][plotNameInternal2D.length];
-        for(int i = 0; i < plotsDir.length; i++) {
-            for(int j = 0; j < plotNameInternal1D.length; j++) {
-                plotLocations1D[i][j] = plotsDir[i] + plotNameInternal1D[j];
-            }
-        }
-        for(int i = 0; i < plotsDir.length; i++) {
-            for(int j = 0; j < plotNameInternal2D.length; j++) {
-                plotLocations2D[i][j] = plotsDir[i] + plotNameInternal2D[j];
-            }
-        }
-        
-        // Create a plot formatting module.
-        PlotFormatModule module = new PlotFormatModule();
-        
-        // Load the plot objects.
-        for(int i = 0; i < plotName1D.length; i++) {
-            // Get the uncut and triggered plots.
-            IHistogram1D uncutPlot = (IHistogram1D) tree.find(plotLocations1D[UNCUT][i]);
-            IHistogram1D triggeredPlot = (IHistogram1D) tree.find(plotLocations1D[TRIGGERED][i] + " (Passed All Cuts)");
-            
-            // Make a formatted plot for each.
-            FormattedPlot1D uncutFormattedPlot;
-            FormattedPlot1D triggeredFormattedPlot;
-            if(axisRanges1D[i] != -1) {
-                uncutFormattedPlot = new FormattedPlot1D(uncutPlot, PlotsFormatter.ColorStyle.GREY, xTitles1D[i], yTitle1D, plotName1D[i] + " (No Cuts)", axisRanges1D[i]);
-                triggeredFormattedPlot = new FormattedPlot1D(triggeredPlot, PlotsFormatter.ColorStyle.MS_GREEN, xTitles1D[i], yTitle1D, plotName1D[i] + " (Triggered)", axisRanges1D[i]);
-            } else {
-                uncutFormattedPlot = new FormattedPlot1D(uncutPlot, PlotsFormatter.ColorStyle.GREY, xTitles1D[i], yTitle1D, plotName1D[i] + " (No Cuts)");
-                triggeredFormattedPlot = new FormattedPlot1D(triggeredPlot, PlotsFormatter.ColorStyle.MS_GREEN, xTitles1D[i], yTitle1D, plotName1D[i] + " (Triggered)");
-            }
-            
-            // Add the plots to the module.
-            module.addPlot1D(uncutFormattedPlot);
-            module.addPlot1D(triggeredFormattedPlot);
-        }
-        for(int i = 0; i < plotName2D.length; i++) {
-            // Get the uncut and triggered plots.
-            IHistogram2D uncutPlot = (IHistogram2D) tree.find(plotLocations2D[UNCUT][i]);
-            IHistogram2D triggeredPlot = (IHistogram2D) tree.find(plotLocations2D[TRIGGERED][i] + " (Passed All Cuts)");
-            
-            // Make a formatted plot for each.
-            FormattedPlot2D uncutFormattedPlot;
-            FormattedPlot2D triggeredFormattedPlot;
-            if(xAxisRanges2D[i] != -1) {
-                uncutFormattedPlot = new FormattedPlot2D(uncutPlot, true, xTitles2D[i], yTitles2D[i], plotName2D[i] + " (No Cuts)", xAxisRanges2D[i], yAxisRanges2D[i]);
-                triggeredFormattedPlot = new FormattedPlot2D(triggeredPlot, true, xTitles2D[i], yTitles2D[i], plotName2D[i] + " (Triggered)", xAxisRanges2D[i], yAxisRanges2D[i]);
-            } else {
-                uncutFormattedPlot = new FormattedPlot2D(uncutPlot, true, xTitles2D[i], yTitles2D[i], plotName2D[i] + " (No Cuts)");
-                triggeredFormattedPlot = new FormattedPlot2D(triggeredPlot, true, xTitles2D[i], yTitles2D[i], plotName2D[i] + " (Triggered)");
-            }
-            
-            // Add the plots to the module.
-            module.addPlot2D(uncutFormattedPlot);
-            module.addPlot2D(triggeredFormattedPlot);
-        }
-        
-        // Save the plots.
-        module.savePlots("C:\\Users\\Kyle\\Desktop\\EnergyShift\\MonteCarlo\\Trident\\Trigger\\");
-    }
+	
+	public static void main(String[] args) throws IllegalArgumentException, IOException {
+		// Define the root directory for the plots.
+		String rootDir = "D:\\cygwin64\\home\\Kyle\\";
+		
+		// Define the new name of the file containing the trigger plots.
+		String plotFile = rootDir + "trident-readout-full.aida";
+		
+		// Get the plots file and open it.
+		IAnalysisFactory af = IAnalysisFactory.create();
+		ITree tree = af.createTreeFactory().create(plotFile);
+		if(tree == null) { throw new IllegalArgumentException("Unable to load plot file."); }
+		
+		// Define plots variables.
+		int UNCUT     = 0;
+		int TRIGGERED = 1;
+		String[] plotsDir = { "NoCuts/", "PassedAll/" };
+		int PLOT_HIT_COUNT      = 0;
+		int PLOT_SEED_ENERGY    = 1;
+		int PLOT_CLUSTER_ENERGY = 2;
+		int PLOT_COPLANARITY    = 3;
+		int PLOT_ENERGY_SUM     = 4;
+		int PLOT_ENERGY_DIFF    = 5;
+		int PLOT_ENERGY_SLOPE   = 6;
+		int PLOT_SEED_DIST      = 0;
+		int PLOT_ENERGY_SUM_2D  = 1;
+		
+		// Define the internal plot names.
+		String[] plotNameInternal1D = new String[7];
+		String[] plotNameInternal2D = new String[2];
+		plotNameInternal1D[PLOT_HIT_COUNT]      = "Cluster Hit Count";
+		plotNameInternal1D[PLOT_SEED_ENERGY]    = "Cluster Seed Energy";
+		plotNameInternal1D[PLOT_CLUSTER_ENERGY] = "Cluster Total Energy";
+		plotNameInternal1D[PLOT_COPLANARITY]    = "Pair Coplanarity";
+		plotNameInternal1D[PLOT_ENERGY_SUM]     = "Pair Energy Sum";
+		plotNameInternal1D[PLOT_ENERGY_DIFF]    = "Pair Energy Difference";
+		plotNameInternal1D[PLOT_ENERGY_SLOPE]   = "Pair Energy Slope";
+		plotNameInternal2D[PLOT_SEED_DIST]      = "Cluster Seed";
+		plotNameInternal2D[PLOT_ENERGY_SUM_2D]  = "Pair Energy Sum 2D";
+		
+		// Define the plot display names.
+		String[] plotName1D = new String[7];
+		String[] plotName2D = new String[2];
+		for(int j = 0; j < plotNameInternal1D.length; j++) {
+			plotName1D[j] = plotNameInternal1D[j];
+		}
+		for(int j = 0; j < plotNameInternal2D.length; j++) {
+			plotName2D[j] = plotNameInternal2D[j];
+		}
+		plotName1D[PLOT_ENERGY_SUM]    = "1D Pair Energy Sum";
+		plotName2D[PLOT_SEED_DIST]     = "Cluster Seed Distribution";
+		plotName2D[PLOT_ENERGY_SUM_2D] = "2D Pair Energy Sum";
+		
+		String[] xTitles1D = new String[plotName1D.length];
+		String[] xTitles2D = new String[plotName2D.length];
+		xTitles1D[PLOT_HIT_COUNT]      = "Hit Count";
+		xTitles1D[PLOT_SEED_ENERGY]    = "Seed Energy (GeV)";
+		xTitles1D[PLOT_CLUSTER_ENERGY] = "Cluster Energy (GeV)";
+		xTitles1D[PLOT_COPLANARITY]    = "Coplanarity Angle (Degrees)";
+		xTitles1D[PLOT_ENERGY_SUM]     = "Energy Sum (GeV)";
+		xTitles1D[PLOT_ENERGY_DIFF]    = "Energy Difference (GeV)";
+		xTitles1D[PLOT_ENERGY_SLOPE]   = "Energy Slope (GeV)";
+		xTitles2D[PLOT_SEED_DIST]      = "x-Index";
+		xTitles2D[PLOT_ENERGY_SUM_2D]  = "First Cluster Energy (GeV)";
+		String yTitle1D = "Count";
+		String[] yTitles2D = new String[plotName2D.length];
+		yTitles2D[PLOT_SEED_DIST]      = "y-Index";
+		yTitles2D[PLOT_ENERGY_SUM_2D]  = "Second Cluster Energy (GeV)";
+		
+		// Define axis ranges.
+		double[] axisRanges1D = new double[plotName1D.length];
+		axisRanges1D[PLOT_HIT_COUNT]      = -1;
+		axisRanges1D[PLOT_SEED_ENERGY]    = 1.1;
+		axisRanges1D[PLOT_CLUSTER_ENERGY] = 1.1;
+		axisRanges1D[PLOT_COPLANARITY]    = 180;
+		axisRanges1D[PLOT_ENERGY_SUM]     = 2.2;
+		axisRanges1D[PLOT_ENERGY_DIFF]    = 1.1;
+		axisRanges1D[PLOT_ENERGY_SLOPE]   = 2.4;
+		double[] xAxisRanges2D = new double[plotName2D.length];
+		double[] yAxisRanges2D = new double[plotName2D.length];
+		xAxisRanges2D[PLOT_SEED_DIST]      = -1;
+		xAxisRanges2D[PLOT_ENERGY_SUM_2D]  = 1.1;
+		yAxisRanges2D[PLOT_SEED_DIST]      = -1;
+		yAxisRanges2D[PLOT_ENERGY_SUM_2D]  = 1.1;
+		
+		// Define the plot names.
+		String[][] plotLocations1D = new String[plotsDir.length][plotNameInternal1D.length];
+		String[][] plotLocations2D = new String[plotsDir.length][plotNameInternal2D.length];
+		for(int i = 0; i < plotsDir.length; i++) {
+			for(int j = 0; j < plotNameInternal1D.length; j++) {
+				plotLocations1D[i][j] = plotsDir[i] + plotNameInternal1D[j];
+			}
+		}
+		for(int i = 0; i < plotsDir.length; i++) {
+			for(int j = 0; j < plotNameInternal2D.length; j++) {
+				plotLocations2D[i][j] = plotsDir[i] + plotNameInternal2D[j];
+			}
+		}
+		
+		// Create a plot formatting module.
+		PlotFormatModule module = new PlotFormatModule();
+		
+		// Load the plot objects.
+		for(int i = 0; i < plotName1D.length; i++) {
+			// Get the uncut and triggered plots.
+			IHistogram1D uncutPlot = (IHistogram1D) tree.find(plotLocations1D[UNCUT][i]);
+			IHistogram1D triggeredPlot = (IHistogram1D) tree.find(plotLocations1D[TRIGGERED][i] + " (Passed All Cuts)");
+			
+			// Make a formatted plot for each.
+			FormattedPlot1D uncutFormattedPlot;
+			FormattedPlot1D triggeredFormattedPlot;
+			if(axisRanges1D[i] != -1) {
+				uncutFormattedPlot = new FormattedPlot1D(uncutPlot, PlotsFormatter.ColorStyle.GREY, xTitles1D[i], yTitle1D, plotName1D[i] + " (No Cuts)", 0, axisRanges1D[i]);
+				triggeredFormattedPlot = new FormattedPlot1D(triggeredPlot, PlotsFormatter.ColorStyle.MS_GREEN, xTitles1D[i], yTitle1D, plotName1D[i] + " (Triggered)", 0, axisRanges1D[i]);
+			} else {
+				uncutFormattedPlot = new FormattedPlot1D(uncutPlot, PlotsFormatter.ColorStyle.GREY, xTitles1D[i], yTitle1D, plotName1D[i] + " (No Cuts)");
+				triggeredFormattedPlot = new FormattedPlot1D(triggeredPlot, PlotsFormatter.ColorStyle.MS_GREEN, xTitles1D[i], yTitle1D, plotName1D[i] + " (Triggered)");
+			}
+			
+			// Add the plots to the module.
+			module.addPlot1D(uncutFormattedPlot);
+			module.addPlot1D(triggeredFormattedPlot);
+		}
+		for(int i = 0; i < plotName2D.length; i++) {
+			// Get the uncut and triggered plots.
+			IHistogram2D uncutPlot = (IHistogram2D) tree.find(plotLocations2D[UNCUT][i]);
+			IHistogram2D triggeredPlot = (IHistogram2D) tree.find(plotLocations2D[TRIGGERED][i] + " (Passed All Cuts)");
+			
+			// Make a formatted plot for each.
+			FormattedPlot2D uncutFormattedPlot;
+			FormattedPlot2D triggeredFormattedPlot;
+			if(xAxisRanges2D[i] != -1) {
+				uncutFormattedPlot = new FormattedPlot2D(uncutPlot, true, xTitles2D[i], yTitles2D[i], plotName2D[i] + " (No Cuts)", xAxisRanges2D[i], yAxisRanges2D[i]);
+				triggeredFormattedPlot = new FormattedPlot2D(triggeredPlot, true, xTitles2D[i], yTitles2D[i], plotName2D[i] + " (Triggered)", xAxisRanges2D[i], yAxisRanges2D[i]);
+			} else {
+				uncutFormattedPlot = new FormattedPlot2D(uncutPlot, true, xTitles2D[i], yTitles2D[i], plotName2D[i] + " (No Cuts)");
+				triggeredFormattedPlot = new FormattedPlot2D(triggeredPlot, true, xTitles2D[i], yTitles2D[i], plotName2D[i] + " (Triggered)");
+			}
+			
+			// Add the plots to the module.
+			module.addPlot2D(uncutFormattedPlot);
+			module.addPlot2D(triggeredFormattedPlot);
+		}
+		
+		// Save the plots.
+		module.savePlots("C:\\Users\\Kyle\\Desktop\\EnergyShift\\MonteCarlo\\Trident\\Trigger\\");
+	}
 }

Modified: java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/formatter/TridentTrackFormatter.java
 =============================================================================
--- java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/formatter/TridentTrackFormatter.java	(original)
+++ java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/formatter/TridentTrackFormatter.java	Tue Sep 27 08:50:14 2016
@@ -16,187 +16,187 @@
 import hep.aida.ref.plotter.PlotterRegion;
 
 public class TridentTrackFormatter {
-    /**
-     * Loads all plots in a file and formats them according to the
-     * indicated style.
-     * @param args - Unused default executable parameter.
-     * @throws IOException Occurs if there is an issue opening the file.
-     */
-    public static void main(String[] args) throws IOException {
-        // Define the root directory for the plots.
-        String rootDir = "D:\\cygwin64\\home\\Kyle\\tmp\\";
-        
-        // Define the new name of the file containing the trigger plots.
-        String plotFile = rootDir + "trident-out.aida";
-        
-        // Get the plots file and open it.
-        IAnalysisFactory af = IAnalysisFactory.create();
-        ITree tree = af.createTreeFactory().create(plotFile);
-        if(tree == null) { throw new IllegalArgumentException("Unable to load plot file."); }
-        
-        // Declare the histogram names.
-        String trackName = "Tracks in Event (All)";
-        String posTrackName = "Tracks in Event (Positive)";
-        String negTrackName = "Tracks in Event (Negative)";
-        String posMomentumName = "Momentum (Positive)";
-        String negMomentumName = "Momentum (Negative)";
-        String energySumName = "Energy Sum";
-        String momentumSumName = "Momentum Sum";
-        String energyMomentumDiffName = "Energy-Momentum Difference";
-        String invariantMassName = "Invariant Mass";
-        String energySum2DName = "2D Energy Sum";
-        String momentumSum2DName = "2D Momentum Sum";
-        String positionName = "Track Cluster Position";
-        
-        // Get the histograms.
-        IHistogram1D[] tracks = {
-                (IHistogram1D) tree.find("Trident Analysis/All/" + trackName),
-                (IHistogram1D) tree.find("Trident Analysis/Cluster/" + trackName)
-        };
-        IHistogram1D[] posTracks = {
-                (IHistogram1D) tree.find("Trident Analysis/All/" + posTrackName),
-                (IHistogram1D) tree.find("Trident Analysis/Cluster/" + posTrackName)
-        };
-        IHistogram1D[] negTracks = {
-                (IHistogram1D) tree.find("Trident Analysis/All/" + negTrackName),
-                (IHistogram1D) tree.find("Trident Analysis/Cluster/" + negTrackName)
-        };
-        IHistogram1D[] posMomentum = {
-                (IHistogram1D) tree.find("Trident Analysis/All/" + posMomentumName),
-                (IHistogram1D) tree.find("Trident Analysis/Cluster/" + posMomentumName)
-        };
-        IHistogram1D[] negMomentum = {
-                (IHistogram1D) tree.find("Trident Analysis/All/" + negMomentumName),
-                (IHistogram1D) tree.find("Trident Analysis/Cluster/" + negMomentumName)
-        };
-        IHistogram1D[] energySum = {
-                (IHistogram1D) tree.find("Trident Analysis/All/" + energySumName),
-                (IHistogram1D) tree.find("Trident Analysis/Cluster/" + energySumName)
-        };
-        IHistogram1D[] momentumSum = {
-                (IHistogram1D) tree.find("Trident Analysis/All/" + momentumSumName),
-                (IHistogram1D) tree.find("Trident Analysis/Cluster/" + momentumSumName)
-        };
-        IHistogram1D[] energyMomentumDiff = {
-                (IHistogram1D) tree.find("Trident Analysis/All/" + energyMomentumDiffName),
-                (IHistogram1D) tree.find("Trident Analysis/Cluster/" + energyMomentumDiffName)
-        };
-        IHistogram1D[] invariantMass = {
-                (IHistogram1D) tree.find("Trident Analysis/All/" + invariantMassName),
-                (IHistogram1D) tree.find("Trident Analysis/Cluster/" + invariantMassName)
-        };
-        IHistogram2D[] energySum2D = {
-                (IHistogram2D) tree.find("Trident Analysis/All/" + energySum2DName),
-                (IHistogram2D) tree.find("Trident Analysis/Cluster/" + energySum2DName)
-        };
-        IHistogram2D[] momentumSum2D = {
-                (IHistogram2D) tree.find("Trident Analysis/All/" + momentumSum2DName),
-                (IHistogram2D) tree.find("Trident Analysis/Cluster/" + momentumSum2DName)
-        };
-        IHistogram2D[] position = {
-                (IHistogram2D) tree.find("Trident Analysis/All/" + positionName),
-                (IHistogram2D) tree.find("Trident Analysis/Cluster/" + positionName)
-        };
-        
-        // Re-bin the histograms to have 5-times larger bins. First,
-        // get the bin count and upper and lower bounds of the plot.
-        int bins = invariantMass[0].axis().bins();
-        double low = invariantMass[0].axis().binLowerEdge(0);
-        double high = invariantMass[0].axis().binUpperEdge(invariantMass[0].axis().bins() - 1);
-        
-        // Create new plots with the larger bin sizes.
-        AIDA aida = AIDA.defaultInstance();
-        IHistogram1D[] newPlot = new IHistogram1D[2];
-        newPlot[0] = aida.histogram1D(invariantMassName, bins / 5, low, high);
-        newPlot[1] = aida.histogram1D("Cluster " + invariantMassName, bins / 5, low, high);
-        
-        // Populate the new plots with the data from the old ones.
-        for(int j = 0; j < 2; j++) {
-            for(int i = 0; i < bins; i++) {
-                int entries = invariantMass[j].binEntries(i);
-                double center = invariantMass[j].axis().binCenter(i);
-                for(int k = 0; k < entries; k++) {
-                    newPlot[j].fill(center);
-                }
-            }
-        }
-        
-        // Replace the old plots.
-        invariantMass = newPlot;
-        
-        // Define the scaling factors for each plot.
-        double scaleFactor = 1;
-        
-        // Define the plot titles and arrays for 1D plots.
-        IHistogram[][] plots = { tracks, posTracks, negTracks, posMomentum, negMomentum, energySum, momentumSum, energyMomentumDiff, invariantMass };
-        String[] titles = { trackName, posTrackName, negTrackName, posMomentumName, negMomentumName, energySumName, momentumSumName,
-                energyMomentumDiffName, invariantMassName };
-        String[] xTitles = { "Tracks", "Tracks", "Tracks", "Momentum (GeV)", "Momentum (GeV)", "Energy Sum (GeV)", "Momentum Sum (GeV)",
-                "|E_Cluster - P_Track| (GeV)", "Invariant Mass (GeV)" };
-        String yTitle = "Count";
-        
-        // Define the plot titles and arrays for 2D plots.
-        IHistogram2D[][] plots2D = { energySum2D, momentumSum2D, position };
-        String[] titles2D = { energySum2DName, momentumSum2DName, positionName };
-        String[] xTitles2D = { "Positive Cluster Energy", "Positive Track Momentum", "x-Index" };
-        String[] yTitles2D = { "Negative Cluster Energy", "Negative Track Momentum", "y-Index" };
-        String zTitle2D = "Count";
-        
-        // Create a plotter factory.
-        IPlotterFactory plotterFactory = af.createPlotterFactory();
-        
-        // Format and display the basic histograms.
-        for(int i = 0; i < plots.length; i++) {
-            for(int j = 0; j < 2; j++) {
-                // Scale the histogram by the appropriate scaling factor.
-                plots[i][j].scale(1.0 / scaleFactor);
-                
-                // Create a plotter and plotting region for the plot.
-                IPlotter plotter = plotterFactory.create((j == 1 ? "Cluster " : "") + titles[i]);
-                plotter.createRegions(1);
-                plotter.region(0).plot(plots[i][j]);
-                
-                // Format the axis labels.
-                PlotterRegion region = (PlotterRegion) plotter.region(0);
-                region.getPlot().setTitle((j == 1 ? "Cluster " : "") + titles[i]);
-                region.getPlot().getXAxis().setLabel(xTitles[i]);
-                region.getPlot().getYAxis().setLabel(yTitle);
-                
-                // Format the fonts and general plot presentation.
-                PlotsFormatter.setDefault1DStyle(region, new ColorStyle[] { ColorStyle.GREY });
-                
-                // Show the plot.
-                plotter.setParameter("plotterWidth", "2000");
-                plotter.setParameter("plotterHeight", "1200");
-                plotter.show();
-            }
-        }
-        
-        // Format and display the 2D histogram.
-        for(int i = 0; i < plots2D.length; i++) {
-            for(int j = 0; j < 2; j++) {
-                plots2D[i][j].scale(1.0 / scaleFactor);
-                IPlotter plotter2D = plotterFactory.create((j == 1 ? "Cluster " : "") + titles2D[i]);
-                plotter2D.createRegions(1);
-                plotter2D.region(0).plot(plots2D[i][j]);
-                
-                // Format the axis labels.
-                PlotterRegion region2D = (PlotterRegion) plotter2D.region(0);
-                region2D.getPlot().setTitle((j == 1 ? "Cluster " : "") + titles2D[i]);
-                region2D.getPlot().getXAxis().setLabel(xTitles2D[i]);
-                region2D.getPlot().getYAxis().setLabel(yTitles2D[i]);
-                
-                // Format the fonts and general plot presentation.
-                PlotsFormatter.setDefault2DStyle(region2D, true);
-                
-                // Show the plot.
-                plotter2D.setParameter("plotterWidth", "2000");
-                plotter2D.setParameter("plotterHeight", "1200");
-                plotter2D.show();
-            }
-        }
-        
-        // Close the tree.
-        tree.close();
-    }
+	/**
+	 * Loads all plots in a file and formats them according to the
+	 * indicated style.
+	 * @param args - Unused default executable parameter.
+	 * @throws IOException Occurs if there is an issue opening the file.
+	 */
+	public static void main(String[] args) throws IOException {
+		// Define the root directory for the plots.
+		String rootDir = "D:\\cygwin64\\home\\Kyle\\tmp\\";
+		
+		// Define the new name of the file containing the trigger plots.
+		String plotFile = rootDir + "trident-out.aida";
+		
+		// Get the plots file and open it.
+		IAnalysisFactory af = IAnalysisFactory.create();
+		ITree tree = af.createTreeFactory().create(plotFile);
+		if(tree == null) { throw new IllegalArgumentException("Unable to load plot file."); }
+		
+		// Declare the histogram names.
+		String trackName = "Tracks in Event (All)";
+		String posTrackName = "Tracks in Event (Positive)";
+		String negTrackName = "Tracks in Event (Negative)";
+		String posMomentumName = "Momentum (Positive)";
+		String negMomentumName = "Momentum (Negative)";
+		String energySumName = "Energy Sum";
+		String momentumSumName = "Momentum Sum";
+		String energyMomentumDiffName = "Energy-Momentum Difference";
+		String invariantMassName = "Invariant Mass";
+		String energySum2DName = "2D Energy Sum";
+		String momentumSum2DName = "2D Momentum Sum";
+		String positionName = "Track Cluster Position";
+		
+		// Get the histograms.
+		IHistogram1D[] tracks = {
+				(IHistogram1D) tree.find("Trident Analysis/All/" + trackName),
+				(IHistogram1D) tree.find("Trident Analysis/Cluster/" + trackName)
+		};
+		IHistogram1D[] posTracks = {
+				(IHistogram1D) tree.find("Trident Analysis/All/" + posTrackName),
+				(IHistogram1D) tree.find("Trident Analysis/Cluster/" + posTrackName)
+		};
+		IHistogram1D[] negTracks = {
+				(IHistogram1D) tree.find("Trident Analysis/All/" + negTrackName),
+				(IHistogram1D) tree.find("Trident Analysis/Cluster/" + negTrackName)
+		};
+		IHistogram1D[] posMomentum = {
+				(IHistogram1D) tree.find("Trident Analysis/All/" + posMomentumName),
+				(IHistogram1D) tree.find("Trident Analysis/Cluster/" + posMomentumName)
+		};
+		IHistogram1D[] negMomentum = {
+				(IHistogram1D) tree.find("Trident Analysis/All/" + negMomentumName),
+				(IHistogram1D) tree.find("Trident Analysis/Cluster/" + negMomentumName)
+		};
+		IHistogram1D[] energySum = {
+				(IHistogram1D) tree.find("Trident Analysis/All/" + energySumName),
+				(IHistogram1D) tree.find("Trident Analysis/Cluster/" + energySumName)
+		};
+		IHistogram1D[] momentumSum = {
+				(IHistogram1D) tree.find("Trident Analysis/All/" + momentumSumName),
+				(IHistogram1D) tree.find("Trident Analysis/Cluster/" + momentumSumName)
+		};
+		IHistogram1D[] energyMomentumDiff = {
+				(IHistogram1D) tree.find("Trident Analysis/All/" + energyMomentumDiffName),
+				(IHistogram1D) tree.find("Trident Analysis/Cluster/" + energyMomentumDiffName)
+		};
+		IHistogram1D[] invariantMass = {
+				(IHistogram1D) tree.find("Trident Analysis/All/" + invariantMassName),
+				(IHistogram1D) tree.find("Trident Analysis/Cluster/" + invariantMassName)
+		};
+		IHistogram2D[] energySum2D = {
+				(IHistogram2D) tree.find("Trident Analysis/All/" + energySum2DName),
+				(IHistogram2D) tree.find("Trident Analysis/Cluster/" + energySum2DName)
+		};
+		IHistogram2D[] momentumSum2D = {
+				(IHistogram2D) tree.find("Trident Analysis/All/" + momentumSum2DName),
+				(IHistogram2D) tree.find("Trident Analysis/Cluster/" + momentumSum2DName)
+		};
+		IHistogram2D[] position = {
+				(IHistogram2D) tree.find("Trident Analysis/All/" + positionName),
+				(IHistogram2D) tree.find("Trident Analysis/Cluster/" + positionName)
+		};
+		
+		// Re-bin the histograms to have 5-times larger bins. First,
+		// get the bin count and upper and lower bounds of the plot.
+		int bins = invariantMass[0].axis().bins();
+		double low = invariantMass[0].axis().binLowerEdge(0);
+		double high = invariantMass[0].axis().binUpperEdge(invariantMass[0].axis().bins() - 1);
+		
+		// Create new plots with the larger bin sizes.
+		AIDA aida = AIDA.defaultInstance();
+		IHistogram1D[] newPlot = new IHistogram1D[2];
+		newPlot[0] = aida.histogram1D(invariantMassName, bins / 5, low, high);
+		newPlot[1] = aida.histogram1D("Cluster " + invariantMassName, bins / 5, low, high);
+		
+		// Populate the new plots with the data from the old ones.
+		for(int j = 0; j < 2; j++) {
+			for(int i = 0; i < bins; i++) {
+				int entries = invariantMass[j].binEntries(i);
+				double center = invariantMass[j].axis().binCenter(i);
+				for(int k = 0; k < entries; k++) {
+					newPlot[j].fill(center);
+				}
+			}
+		}
+		
+		// Replace the old plots.
+		invariantMass = newPlot;
+		
+		// Define the scaling factors for each plot.
+		double scaleFactor = 1;
+		
+		// Define the plot titles and arrays for 1D plots.
+		IHistogram[][] plots = { tracks, posTracks, negTracks, posMomentum, negMomentum, energySum, momentumSum, energyMomentumDiff, invariantMass };
+		String[] titles = { trackName, posTrackName, negTrackName, posMomentumName, negMomentumName, energySumName, momentumSumName,
+				energyMomentumDiffName, invariantMassName };
+		String[] xTitles = { "Tracks", "Tracks", "Tracks", "Momentum (GeV)", "Momentum (GeV)", "Energy Sum (GeV)", "Momentum Sum (GeV)",
+				"|E_Cluster - P_Track| (GeV)", "Invariant Mass (GeV)" };
+		String yTitle = "Count";
+		
+		// Define the plot titles and arrays for 2D plots.
+		IHistogram2D[][] plots2D = { energySum2D, momentumSum2D, position };
+		String[] titles2D = { energySum2DName, momentumSum2DName, positionName };
+		String[] xTitles2D = { "Positive Cluster Energy", "Positive Track Momentum", "x-Index" };
+		String[] yTitles2D = { "Negative Cluster Energy", "Negative Track Momentum", "y-Index" };
+		String zTitle2D = "Count";
+		
+		// Create a plotter factory.
+		IPlotterFactory plotterFactory = af.createPlotterFactory();
+		
+		// Format and display the basic histograms.
+		for(int i = 0; i < plots.length; i++) {
+			for(int j = 0; j < 2; j++) {
+				// Scale the histogram by the appropriate scaling factor.
+				plots[i][j].scale(1.0 / scaleFactor);
+				
+				// Create a plotter and plotting region for the plot.
+				IPlotter plotter = plotterFactory.create((j == 1 ? "Cluster " : "") + titles[i]);
+				plotter.createRegions(1);
+				plotter.region(0).plot(plots[i][j]);
+				
+				// Format the axis labels.
+				PlotterRegion region = (PlotterRegion) plotter.region(0);
+				region.getPlot().setTitle((j == 1 ? "Cluster " : "") + titles[i]);
+				region.getPlot().getXAxis().setLabel(xTitles[i]);
+				region.getPlot().getYAxis().setLabel(yTitle);
+				
+				// Format the fonts and general plot presentation.
+				PlotsFormatter.setDefault1DStyle(region, new ColorStyle[] { ColorStyle.GREY }, PlotsFormatter.DisplayStyle.BAR);
+				
+				// Show the plot.
+				plotter.setParameter("plotterWidth", "2000");
+				plotter.setParameter("plotterHeight", "1200");
+				plotter.show();
+			}
+		}
+		
+		// Format and display the 2D histogram.
+		for(int i = 0; i < plots2D.length; i++) {
+			for(int j = 0; j < 2; j++) {
+				plots2D[i][j].scale(1.0 / scaleFactor);
+				IPlotter plotter2D = plotterFactory.create((j == 1 ? "Cluster " : "") + titles2D[i]);
+				plotter2D.createRegions(1);
+				plotter2D.region(0).plot(plots2D[i][j]);
+				
+				// Format the axis labels.
+				PlotterRegion region2D = (PlotterRegion) plotter2D.region(0);
+				region2D.getPlot().setTitle((j == 1 ? "Cluster " : "") + titles2D[i]);
+				region2D.getPlot().getXAxis().setLabel(xTitles2D[i]);
+				region2D.getPlot().getYAxis().setLabel(yTitles2D[i]);
+				
+				// Format the fonts and general plot presentation.
+				PlotsFormatter.setDefault2DStyle(region2D, true);
+				
+				// Show the plot.
+				plotter2D.setParameter("plotterWidth", "2000");
+				plotter2D.setParameter("plotterHeight", "1200");
+				plotter2D.show();
+			}
+		}
+		
+		// Close the tree.
+		tree.close();
+	}
 }

Modified: java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/formatter/TriggerPlotsFormat.java
 =============================================================================
--- java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/formatter/TriggerPlotsFormat.java	(original)
+++ java/trunk/users/src/main/java/org/hps/users/kmccarty/plots/formatter/TriggerPlotsFormat.java	Tue Sep 27 08:50:14 2016
@@ -20,331 +20,331 @@
 import hep.aida.ref.plotter.PlotterRegion;
 
 public class TriggerPlotsFormat {
-    // Define plot fonts.
-    private static final Font BASIC_FONT = new Font("Calibri", Font.PLAIN, 20);
-    private static final Font AXIS_FONT  = new Font("Calibri", Font.BOLD,  25);
-    private static final Font TITLE_FONT = new Font("Calibri", Font.BOLD,  35);
-    
-    // Defines the color style options for plot data.
-    private enum ColorStyle {
-         MS_BLUE(new Color( 79, 129, 189), new Color( 36,  64,  97)), MS_ORANGE(new Color(247, 150,  70), new Color(152,  72,   6)),
-          MS_RED(new Color(192,  80,  77), new Color( 99,  36,  35)),      GREY(new Color(166, 166, 166), new Color( 89,  89,  89)),
-        MS_GREEN(new Color(155, 187,  89), new Color( 79,  98,  40)),   CRIMSON(new Color(161,   0,   0), new Color(104,   0,   0)),
-            RUST(new Color(161,  80,   0), new Color(105,  80,   0)),    YELLOW(new Color(161, 161,   0), new Color(122, 109,   8)),
-          FOREST(new Color( 65, 102,   0), new Color( 37,  79,   0)),     GREEN(new Color(  7, 132,  70), new Color(  7,  82,  30)),
-            TEAL(new Color(  0, 130, 130), new Color(  0,  90, 100)),  CERULEAN(new Color(  0,  86, 130), new Color(  0,  28,  83)),
-            BLUE(new Color(  0,  33, 203), new Color(  0,   0, 137)),    INDIGO(new Color( 68,  10, 127), new Color(  0,   0,  61)),
-          PURPLE(new Color(106,   0, 106), new Color( 63,   0,  56)),   FUSCHIA(new Color(119,   0,  60), new Color( 60,   0,  60));
-        
-        private final Color fillColor;
-        private final Color lineColor;
-        
-        private ColorStyle(Color fillColor, Color lineColor) {
-            this.fillColor = fillColor;
-            this.lineColor = lineColor;
-        }
-        
-        public Color getFillColor() { return fillColor; }
-        
-        public Color getLineColor() { return lineColor; }
-    };
-        
-    /**
-     * Loads all plots in a file and formats them according to the
-     * indicated style.
-     * @param args - Unused default executable parameter.
-     * @throws IOException Occurs if there is an issue opening the file.
-     */
-    public static void main(String[] args) throws IOException {
-        // Define the root directory for the plots.
-        String rootDir = "D:\\cygwin64\\home\\Kyle\\beam-plots\\base\\";
-        //String rootDir = "D:\\cygwin64\\home\\Kyle\\aprime-plots\\base\\readout-plots\\";
-        
-        // Define the new name of the file containing the trigger plots.
-        String[] plotFile = {
-                rootDir + "compiled-plots.aida"
-                //rootDir + "15-MeV\\compiled-plots.aida",
-                //rootDir + "20-MeV\\compiled-plots.aida",
-                //rootDir + "30-MeV\\compiled-plots.aida",
-                //rootDir + "40-MeV\\compiled-plots.aida",
-                //rootDir + "50-MeV\\compiled-plots.aida"
-        };
-        
-        // Define the names of each plot. This will be used for the
-        // legend in the case of multiple plots.
-        String[] treeName = {
-            "Background",
-            "15 MeV A'",
-            "20 MeV A'",
-            "30 MeV A'",
-            "40 MeV A'",
-            "50 MeV A'"
-        };
-        
-        // Define the color style for the plots.
-        ColorStyle[] dataColorStyle = {
-                ColorStyle.GREY,
-                ColorStyle.MS_GREEN,
-                ColorStyle.MS_BLUE,
-                ColorStyle.MS_ORANGE,
-                ColorStyle.MS_RED,
-                ColorStyle.TEAL,
-                ColorStyle.CRIMSON,
-                ColorStyle.FOREST
-        };
-        
-        // Get the plots file and open it.
-        IAnalysisFactory af = IAnalysisFactory.create();
-        ITree[] tree = new ITree[plotFile.length];
-        for(int i = 0; i < plotFile.length; i++) {
-            tree[i] = af.createTreeFactory().create(plotFile[i]);
-            if(tree[i] == null) { throw new IllegalArgumentException("Unable to load plot file."); }
-        }
-        
-        // Get a list of all the histograms in the file.
-        List<List<String>> treeHistograms = new ArrayList<List<String>>(plotFile.length);
-        for(int i = 0; i < plotFile.length; i++) {
-            treeHistograms.add(getHistograms(tree[i], "/NoCuts/"));//, "/PassedAll/"));
-        }
-        
-        // Create a plotter factory.
-        IPlotterFactory plotterFactory = af.createPlotterFactory();
-        
-        // Plot each histogram and format it.
-        for(String histogram : treeHistograms.get(0)) {
-            // Get the plot from the tree and verify that it is a 1D
-            // or 2D histogram. Other types are not supported.
-            IManagedObject histObject = tree[0].find(histogram);
-            if(!(histObject instanceof IHistogram1D) && !(histObject instanceof IHistogram2D)) {
-                continue;
-            }
-            
-            // Obtain the histogram object.
-            IBaseHistogram hist;
-            if(histObject instanceof IHistogram1D) { hist = (IHistogram1D) histObject; }
-            else { hist = (IHistogram2D) histObject; }
-            
-            // Define whether this is an overlay plot and whether
-            // this is a one or two dimensional plot.
-            boolean overlay = plotFile.length > 1;
-            boolean twoDimensional = hist instanceof IHistogram2D;
-            
-            // Generate the plotter and set its title. The plotter will
-            // use the title of the first tree's plot.
-            String plotTitle = hist.title();
-            IPlotter plotter = plotterFactory.create(plotTitle);
-            
-            // For single plots and one-dimensional overlay plots,
-            // there should only be a single plotter region.
-            if(!twoDimensional || !overlay) { plotter.createRegions(1); }
-            
-            // For two-dimensional overlay plots, create a region for
-            // each plot individually.
-            else { plotter.createRegions(2, (int) Math.ceil(plotFile.length / 2.0)); }
-            
-            // Find the histogram in each of the trees and plot them
-            // all on the same region.
-            for(int i = 0; i < plotFile.length; i++) {
-                // Get the histogram from the tree.
-                IManagedObject treeObject = tree[i].find(histogram);
-                IBaseHistogram treeHist;
-                if(treeObject instanceof IHistogram1D) { treeHist = (IHistogram1D) treeObject; }
-                else { treeHist = (IHistogram2D) treeObject; }
-                
-                // Display the plot.
-                if(treeHist != null) {
-                    // Set the title of plot to the name associated with
-                    // its tree. This ensures that the correct name will
-                    // appear on the legend.
-                    if(plotFile.length > 1) {
-                        treeHist.setTitle(treeName[i]);
-                    }
-                    
-                    // Plot the tree's data in the plotter region.
-                    if(!twoDimensional || !overlay) { plotter.region(0).plot(treeHist); }
-                    else {
-                        plotter.region(i).plot(treeHist);
-                        setDefault2DStyle(((PlotterRegion) plotter.region(i)), dataColorStyle);
-                    }
-                }
-            }
-            
-            // Format the plot region.
-            if(!twoDimensional) { setDefault1DStyle(((PlotterRegion) plotter.region(0)), dataColorStyle); }
-            else { setDefault2DStyle(((PlotterRegion) plotter.region(0)), dataColorStyle); }
-            
-            // Show the plotter.
-            plotter.region(0).setTitle(plotTitle);
-            plotter.setParameter("plotterWidth", "750");
-            plotter.setParameter("plotterHeight", "600");
-            //plotter.setParameter("plotterWidth", "2000");
-            //plotter.setParameter("plotterHeight", "1200");
-            plotter.show();
-        }
-        
-        // Close the trees.
-        for(int i = 0; i < plotFile.length; i++) {
-            tree[i].close();
-        }
-    }
-    
-    /**
-     * Sets the plot display formatting for 1D plots.
-     * @param region - The plotter region to format.
-     * @param color - The data color settings to use.
-     */
-    private static final void setDefault1DStyle(PlotterRegion region, ColorStyle[] color) {
-        // Get the names of each plot on in the region.
-        String[] dataNames = region.getAllDataNames();
-        
-        // Check whether this is an overlay plot. Overlay plots contain
-        // more than one data name.
-        boolean overlay = (dataNames.length > 1 ? true : false);
-        
-        // Iterate over each plot in the region.
-        for(int i = 0; i < dataNames.length; i++) {
-            // Set the overlay style if needed.
-            if(overlay) {
-                // Get the fill style for the current data type.
-                JASHist1DHistogramStyle fillStyle = (JASHist1DHistogramStyle) region.getDataForName(dataNames[i]).getStyle();
-                
-                // Set the histogram style to display thick-lined bars
-                // with no fill. The color is set by the "color" argument.
-                fillStyle.setHistogramFill(false);
-                fillStyle.setHistogramBarLineWidth(3);
-                fillStyle.setHistogramBarLineColor(color[i].getFillColor());
-                
-                // Set the legend text style.
-                region.getPlot().getLegend().setFont(new Font("Calibri", Font.PLAIN, 20));
-            }
-            
-            // Otherwise, set the fill style for a single plot.
-            else {
-                // Get the fill style for the current data type.
-                JASHist1DHistogramStyle fillStyle = (JASHist1DHistogramStyle) region.getDataForName(dataNames[i]).getStyle();
-                
-                // Set the histogram style to display thick-lined bars
-                // with a fill color. The colors are defined by the
-                // "color" argument.
-                fillStyle.setHistogramBarLineWidth(3);
-                fillStyle.setHistogramBarColor(color[i].getFillColor());
-                fillStyle.setHistogramBarLineColor(color[i].getLineColor());
-            }
-            
-            // Set the statistics box style.
-            region.getPlot().getStats().setVisible(true);
-            region.getPlot().getStats().setFont(BASIC_FONT);
-            
-            // Set the title font.
-            region.getPlot().getTitleObject().setFont(TITLE_FONT);
-            
-            // Set generic axis titles.
-            region.getPlot().getXAxis().setLabel("Data Label (Unit)");
-            region.getPlot().getYAxis().setLabel("Count");
-            
-            // Set the axis tick-mark fonts.
-            region.getPlot().getXAxis().setFont(BASIC_FONT);
-            region.getPlot().getYAxis().setFont(BASIC_FONT);
-            region.getPlot().getXAxis().getLabelObject().setFont(AXIS_FONT);
-            region.getPlot().getYAxis().getLabelObject().setFont(AXIS_FONT);
-        }
-    }
-    
-    /**
-     * Sets the plot display formatting for 1D plots.
-     * @param region - The plotter region to format.
-     * @param color - The data color settings to use.
-     */
-    private static final void setDefault2DStyle(PlotterRegion region, ColorStyle[] color) {
-        // Get the fill style object. 2D plots should never be overlay
-        // plots, so there should only ever be one data name.
-        JASHist2DHistogramStyle fillStyle = (JASHist2DHistogramStyle) region.getDataForName(region.getAllDataNames()[0]).getStyle();
-        
-        // Set the fill style for a two-dimensional plot.
-        fillStyle.setLogZ(true);
-        fillStyle.setHistStyle(JASHist2DHistogramStyle.STYLE_COLORMAP);
-        fillStyle.setColorMapScheme(JASHist2DHistogramStyle.COLORMAP_RAINBOW);
-        
-        // Make the statistics box invisible.
-        region.getPlot().getStats().setVisible(false);
-        
-        // Set the general plot font (which is also the z-axis font).
-        region.getPlot().setFont(BASIC_FONT);
-        
-        // Set the title font.
-        region.getPlot().getTitleObject().setFont(TITLE_FONT);
-        
-        // Set generic axis titles.
-        region.getPlot().getXAxis().setLabel("Data Label (Unit)");
-        region.getPlot().getYAxis().setLabel("Data Label (Unit)");
-        
-        // Set the axis tick-mark fonts.
-        region.getPlot().getXAxis().setFont(BASIC_FONT);
-        region.getPlot().getYAxis().setFont(BASIC_FONT);
-        region.getPlot().getXAxis().getLabelObject().setFont(AXIS_FONT);
-        region.getPlot().getYAxis().getLabelObject().setFont(AXIS_FONT);
-    }
-    
-    /**
-     * Gets a list of all objects that are not directories in a tree.
-     * @param tree - The tree from which to extract the object names.
-     * @return Returns the object names as <code>String</code> objects
-     * in a <code>List</code> collection.
-     */
-    private static final List<String> getHistograms(ITree tree) {
-        return getHistograms(tree, "/");
-    }
-    
-    /**
-     * Gets a list of all objects that are not directories in a tree.
-     * @param tree - The tree from which to extract the object names.
-     * @return Returns the object names as <code>String</code> objects
-     * in a <code>List</code> collection.
-     */
-    private static final List<String> getHistograms(ITree tree, String rootDir) {
-        return getHistograms(tree, rootDir, new ArrayList<String>());
-    }
-    
-    /**
-     * Recursive method that gets all object names from a tree that
-     * are not directories. Method should not be called directly, but
-     * rather called only through the <code>getHistograms(ITree)</code>
-     * method.
-     * @param tree - The tree from which to obtain the object names.
-     * @param directory - The directory in which to search for objects.
-     * @param list - The list in which to place the objects.
-     * @return Returns the <code>List</code> collection that was given
-     * as an argument.
-     */
-    private static final List<String> getHistograms(ITree tree, String directory, List<String> list) {
-        // Get the list of objects in the directory.
-        String[] treeObjects = tree.listObjectNames(directory);
-        
-        // Print the objects.
-        for(String objectName : treeObjects) {
-            // Check if the object is a directory.
-            boolean isDirectory = isDirectory(objectName);
-            
-            // If the object is a directory, get the histograms from it.
-            if(isDirectory) {
-                getHistograms(tree, objectName, list);
-            }
-            
-            // If the object is a plot, add it to the list.
-            else { list.add(objectName); }
-        }
-        
-        // Return the list.
-        return list;
-    }
-    
-    /**
-     * Checks whether a tree object is a directory.
-     * @param object - The object to check.
-     * @return Returns <code>true</code> if the object is a directory
-     * and <code>false</code> otherwise.
-     */
-    private static final boolean isDirectory(String object) {
-        return (object.toCharArray()[object.length() - 1] == '/');
-    }
+	// Define plot fonts.
+	private static final Font BASIC_FONT = new Font("Calibri", Font.PLAIN, 20);
+	private static final Font AXIS_FONT  = new Font("Calibri", Font.BOLD,  25);
+	private static final Font TITLE_FONT = new Font("Calibri", Font.BOLD,  35);
+	
+	// Defines the color style options for plot data.
+	private enum ColorStyle {
+		 MS_BLUE(new Color( 79, 129, 189), new Color( 36,  64,  97)), MS_ORANGE(new Color(247, 150,  70), new Color(152,  72,   6)),
+		  MS_RED(new Color(192,  80,  77), new Color( 99,  36,  35)),      GREY(new Color(166, 166, 166), new Color( 89,  89,  89)),
+		MS_GREEN(new Color(155, 187,  89), new Color( 79,  98,  40)),   CRIMSON(new Color(161,   0,   0), new Color(104,   0,   0)),
+		    RUST(new Color(161,  80,   0), new Color(105,  80,   0)),    YELLOW(new Color(161, 161,   0), new Color(122, 109,   8)),
+		  FOREST(new Color( 65, 102,   0), new Color( 37,  79,   0)),     GREEN(new Color(  7, 132,  70), new Color(  7,  82,  30)),
+		    TEAL(new Color(  0, 130, 130), new Color(  0,  90, 100)),  CERULEAN(new Color(  0,  86, 130), new Color(  0,  28,  83)),
+		    BLUE(new Color(  0,  33, 203), new Color(  0,   0, 137)),    INDIGO(new Color( 68,  10, 127), new Color(  0,   0,  61)),
+		  PURPLE(new Color(106,   0, 106), new Color( 63,   0,  56)),   FUSCHIA(new Color(119,   0,  60), new Color( 60,   0,  60));
+		
+		private final Color fillColor;
+		private final Color lineColor;
+		
+		private ColorStyle(Color fillColor, Color lineColor) {
+			this.fillColor = fillColor;
+			this.lineColor = lineColor;
+		}
+		
+		public Color getFillColor() { return fillColor; }
+		
+		public Color getLineColor() { return lineColor; }
+	};
+		
+	/**
+	 * Loads all plots in a file and formats them according to the
+	 * indicated style.
+	 * @param args - Unused default executable parameter.
+	 * @throws IOException Occurs if there is an issue opening the file.
+	 */
+	public static void main(String[] args) throws IOException {
+		// Define the root directory for the plots.
+		String rootDir = "D:\\cygwin64\\home\\Kyle\\beam-plots\\base\\";
+		//String rootDir = "D:\\cygwin64\\home\\Kyle\\aprime-plots\\base\\readout-plots\\";
+		
+		// Define the new name of the file containing the trigger plots.
+		String[] plotFile = {
+				rootDir + "compiled-plots.aida"
+				//rootDir + "15-MeV\\compiled-plots.aida",
+				//rootDir + "20-MeV\\compiled-plots.aida",
+				//rootDir + "30-MeV\\compiled-plots.aida",
+				//rootDir + "40-MeV\\compiled-plots.aida",
+				//rootDir + "50-MeV\\compiled-plots.aida"
+		};
+		
+		// Define the names of each plot. This will be used for the
+		// legend in the case of multiple plots.
+		String[] treeName = {
+			"Background",
+			"15 MeV A'",
+			"20 MeV A'",
+			"30 MeV A'",
+			"40 MeV A'",
+			"50 MeV A'"
+		};
+		
+		// Define the color style for the plots.
+		ColorStyle[] dataColorStyle = {
+				ColorStyle.GREY,
+				ColorStyle.MS_GREEN,
+				ColorStyle.MS_BLUE,
+				ColorStyle.MS_ORANGE,
+				ColorStyle.MS_RED,
+				ColorStyle.TEAL,
+				ColorStyle.CRIMSON,
+				ColorStyle.FOREST
+		};
+		
+		// Get the plots file and open it.
+		IAnalysisFactory af = IAnalysisFactory.create();
+		ITree[] tree = new ITree[plotFile.length];
+		for(int i = 0; i < plotFile.length; i++) {
+			tree[i] = af.createTreeFactory().create(plotFile[i]);
+			if(tree[i] == null) { throw new IllegalArgumentException("Unable to load plot file."); }
+		}
+		
+		// Get a list of all the histograms in the file.
+		List<List<String>> treeHistograms = new ArrayList<List<String>>(plotFile.length);
+		for(int i = 0; i < plotFile.length; i++) {
+			treeHistograms.add(getHistograms(tree[i], "/NoCuts/"));//, "/PassedAll/"));
+		}
+		
+		// Create a plotter factory.
+		IPlotterFactory plotterFactory = af.createPlotterFactory();
+		
+		// Plot each histogram and format it.
+		for(String histogram : treeHistograms.get(0)) {
+			// Get the plot from the tree and verify that it is a 1D
+			// or 2D histogram. Other types are not supported.
+			IManagedObject histObject = tree[0].find(histogram);
+			if(!(histObject instanceof IHistogram1D) && !(histObject instanceof IHistogram2D)) {
+				continue;
+			}
+			
+			// Obtain the histogram object.
+			IBaseHistogram hist;
+			if(histObject instanceof IHistogram1D) { hist = (IHistogram1D) histObject; }
+			else { hist = (IHistogram2D) histObject; }
+			
+			// Define whether this is an overlay plot and whether
+			// this is a one or two dimensional plot.
+			boolean overlay = plotFile.length > 1;
+			boolean twoDimensional = hist instanceof IHistogram2D;
+			
+			// Generate the plotter and set its title. The plotter will
+			// use the title of the first tree's plot.
+			String plotTitle = hist.title();
+			IPlotter plotter = plotterFactory.create(plotTitle);
+			
+			// For single plots and one-dimensional overlay plots,
+			// there should only be a single plotter region.
+			if(!twoDimensional || !overlay) { plotter.createRegions(1); }
+			
+			// For two-dimensional overlay plots, create a region for
+			// each plot individually.
+			else { plotter.createRegions(2, (int) Math.ceil(plotFile.length / 2.0)); }
+			
+			// Find the histogram in each of the trees and plot them
+			// all on the same region.
+			for(int i = 0; i < plotFile.length; i++) {
+				// Get the histogram from the tree.
+				IManagedObject treeObject = tree[i].find(histogram);
+				IBaseHistogram treeHist;
+				if(treeObject instanceof IHistogram1D) { treeHist = (IHistogram1D) treeObject; }
+				else { treeHist = (IHistogram2D) treeObject; }
+				
+				// Display the plot.
+				if(treeHist != null) {
+					// Set the title of plot to the name associated with
+					// its tree. This ensures that the correct name will
+					// appear on the legend.
+					if(plotFile.length > 1) {
+						treeHist.setTitle(treeName[i]);
+					}
+					
+					// Plot the tree's data in the plotter region.
+					if(!twoDimensional || !overlay) { plotter.region(0).plot(treeHist); }
+					else {
+						plotter.region(i).plot(treeHist);
+						setDefault2DStyle(((PlotterRegion) plotter.region(i)), dataColorStyle);
+					}
+				}
+			}
+			
+			// Format the plot region.
+			if(!twoDimensional) { setDefault1DStyle(((PlotterRegion) plotter.region(0)), dataColorStyle); }
+			else { setDefault2DStyle(((PlotterRegion) plotter.region(0)), dataColorStyle); }
+			
+			// Show the plotter.
+			plotter.region(0).setTitle(plotTitle);
+			plotter.setParameter("plotterWidth", "750");
+			plotter.setParameter("plotterHeight", "600");
+			//plotter.setParameter("plotterWidth", "2000");
+			//plotter.setParameter("plotterHeight", "1200");
+			plotter.show();
+		}
+		
+		// Close the trees.
+		for(int i = 0; i < plotFile.length; i++) {
+			tree[i].close();
+		}
+	}
+	
+	/**
+	 * Sets the plot display formatting for 1D plots.
+	 * @param region - The plotter region to format.
+	 * @param color - The data color settings to use.
+	 */
+	private static final void setDefault1DStyle(PlotterRegion region, ColorStyle[] color) {
+		// Get the names of each plot on in the region.
+		String[] dataNames = region.getAllDataNames();
+		
+		// Check whether this is an overlay plot. Overlay plots contain
+		// more than one data name.
+		boolean overlay = (dataNames.length > 1 ? true : false);
+		
+		// Iterate over each plot in the region.
+		for(int i = 0; i < dataNames.length; i++) {
+			// Set the overlay style if needed.
+			if(overlay) {
+				// Get the fill style for the current data type.
+				JASHist1DHistogramStyle fillStyle = (JASHist1DHistogramStyle) region.getDataForName(dataNames[i]).getStyle();
+				
+				// Set the histogram style to display thick-lined bars
+				// with no fill. The color is set by the "color" argument.
+				fillStyle.setHistogramFill(false);
+				fillStyle.setHistogramBarLineWidth(3);
+				fillStyle.setHistogramBarLineColor(color[i].getFillColor());
+				
+				// Set the legend text style.
+				region.getPlot().getLegend().setFont(new Font("Calibri", Font.PLAIN, 20));
+			}
+			
+			// Otherwise, set the fill style for a single plot.
+			else {
+				// Get the fill style for the current data type.
+				JASHist1DHistogramStyle fillStyle = (JASHist1DHistogramStyle) region.getDataForName(dataNames[i]).getStyle();
+				
+				// Set the histogram style to display thick-lined bars
+				// with a fill color. The colors are defined by the
+				// "color" argument.
+				fillStyle.setHistogramBarLineWidth(3);
+				fillStyle.setHistogramBarColor(color[i].getFillColor());
+				fillStyle.setHistogramBarLineColor(color[i].getLineColor());
+			}
+			
+			// Set the statistics box style.
+			region.getPlot().getStats().setVisible(true);
+			region.getPlot().getStats().setFont(BASIC_FONT);
+			
+			// Set the title font.
+			region.getPlot().getTitleObject().setFont(TITLE_FONT);
+			
+			// Set generic axis titles.
+			region.getPlot().getXAxis().setLabel("Data Label (Unit)");
+			region.getPlot().getYAxis().setLabel("Count");
+			
+			// Set the axis tick-mark fonts.
+			region.getPlot().getXAxis().setFont(BASIC_FONT);
+			region.getPlot().getYAxis().setFont(BASIC_FONT);
+			region.getPlot().getXAxis().getLabelObject().setFont(AXIS_FONT);
+			region.getPlot().getYAxis().getLabelObject().setFont(AXIS_FONT);
+		}
+	}
+	
+	/**
+	 * Sets the plot display formatting for 1D plots.
+	 * @param region - The plotter region to format.
+	 * @param color - The data color settings to use.
+	 */
+	private static final void setDefault2DStyle(PlotterRegion region, ColorStyle[] color) {
+		// Get the fill style object. 2D plots should never be overlay
+		// plots, so there should only ever be one data name.
+		JASHist2DHistogramStyle fillStyle = (JASHist2DHistogramStyle) region.getDataForName(region.getAllDataNames()[0]).getStyle();
+		
+		// Set the fill style for a two-dimensional plot.
+		fillStyle.setLogZ(true);
+		fillStyle.setHistStyle(JASHist2DHistogramStyle.STYLE_COLORMAP);
+		fillStyle.setColorMapScheme(JASHist2DHistogramStyle.COLORMAP_RAINBOW);
+		
+		// Make the statistics box invisible.
+		region.getPlot().getStats().setVisible(false);
+		
+		// Set the general plot font (which is also the z-axis font).
+		region.getPlot().setFont(BASIC_FONT);
+		
+		// Set the title font.
+		region.getPlot().getTitleObject().setFont(TITLE_FONT);
+		
+		// Set generic axis titles.
+		region.getPlot().getXAxis().setLabel("Data Label (Unit)");
+		region.getPlot().getYAxis().setLabel("Data Label (Unit)");
+		
+		// Set the axis tick-mark fonts.
+		region.getPlot().getXAxis().setFont(BASIC_FONT);
+		region.getPlot().getYAxis().setFont(BASIC_FONT);
+		region.getPlot().getXAxis().getLabelObject().setFont(AXIS_FONT);
+		region.getPlot().getYAxis().getLabelObject().setFont(AXIS_FONT);
+	}
+	
+	/**
+	 * Gets a list of all objects that are not directories in a tree.
+	 * @param tree - The tree from which to extract the object names.
+	 * @return Returns the object names as <code>String</code> objects
+	 * in a <code>List</code> collection.
+	 */
+	private static final List<String> getHistograms(ITree tree) {
+		return getHistograms(tree, "/");
+	}
+	
+	/**
+	 * Gets a list of all objects that are not directories in a tree.
+	 * @param tree - The tree from which to extract the object names.
+	 * @return Returns the object names as <code>String</code> objects
+	 * in a <code>List</code> collection.
+	 */
+	private static final List<String> getHistograms(ITree tree, String rootDir) {
+		return getHistograms(tree, rootDir, new ArrayList<String>());
+	}
+	
+	/**
+	 * Recursive method that gets all object names from a tree that
+	 * are not directories. Method should not be called directly, but
+	 * rather called only through the <code>getHistograms(ITree)</code>
+	 * method.
+	 * @param tree - The tree from which to obtain the object names.
+	 * @param directory - The directory in which to search for objects.
+	 * @param list - The list in which to place the objects.
+	 * @return Returns the <code>List</code> collection that was given
+	 * as an argument.
+	 */
+	private static final List<String> getHistograms(ITree tree, String directory, List<String> list) {
+		// Get the list of objects in the directory.
+		String[] treeObjects = tree.listObjectNames(directory);
+		
+		// Print the objects.
+		for(String objectName : treeObjects) {
+			// Check if the object is a directory.
+			boolean isDirectory = isDirectory(objectName);
+			
+			// If the object is a directory, get the histograms from it.
+			if(isDirectory) {
+				getHistograms(tree, objectName, list);
+			}
+			
+			// If the object is a plot, add it to the list.
+			else { list.add(objectName); }
+		}
+		
+		// Return the list.
+		return list;
+	}
+	
+	/**
+	 * Checks whether a tree object is a directory.
+	 * @param object - The object to check.
+	 * @return Returns <code>true</code> if the object is a directory
+	 * and <code>false</code> otherwise.
+	 */
+	private static final boolean isDirectory(String object) {
+		return (object.toCharArray()[object.length() - 1] == '/');
+	}
 }