Print

Print


Author: [log in to unmask]
Date: Tue Sep 22 12:10:36 2015
New Revision: 3665

Log:
Added LCSim driver to cross-check Rafo's analysis.

Added:
    java/trunk/users/src/main/java/org/hps/users/kmccarty/RafoAnalysis.java
Modified:
    java/trunk/users/src/main/java/org/hps/users/kmccarty/MTEAnalysis.java
    java/trunk/users/src/main/java/org/hps/users/kmccarty/MTETriggerPlotsFormatter.java
    java/trunk/users/src/main/java/org/hps/users/kmccarty/ParticleMCAnalysisDriver.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

Modified: java/trunk/users/src/main/java/org/hps/users/kmccarty/MTEAnalysis.java
 =============================================================================
--- java/trunk/users/src/main/java/org/hps/users/kmccarty/MTEAnalysis.java	(original)
+++ java/trunk/users/src/main/java/org/hps/users/kmccarty/MTEAnalysis.java	Tue Sep 22 12:10:36 2015
@@ -52,6 +52,9 @@
 	private IHistogram1D timePlot = aida.histogram1D("MTE Analysis/Track Cluster Time Distribution", 4000, 0, 400);
 	private IHistogram1D timeCoincidencePlot = aida.histogram1D("MTE Analysis/Møller Time Coincidence Distribution", 1000, 0, 100);
 	private IHistogram1D timeCoincidenceAllCutsPlot = aida.histogram1D("MTE Analysis/Møller Time Coincidence Distribution (All Møller Cuts)", 1000, 0, 100);
+	private IHistogram1D negTrackCount = aida.histogram1D("MTE Analysis/All Negative Tracks", 10, -0.5, 9.5);
+	private IHistogram1D posTrackCount = aida.histogram1D("MTE Analysis/All Positive Event Tracks", 10, -0.5, 9.5);
+	private IHistogram1D chargedTrackCount = aida.histogram1D("MTE Analysis/All Event Event Tracks", 10, -0.5, 9.5);
 	private TriggerPlotsModule allPlots = new TriggerPlotsModule("All");
 	private TriggerPlotsModule møllerPlots = new TriggerPlotsModule("Møller");
 	private TriggerPlotsModule tridentPlots = new TriggerPlotsModule("Trident");
@@ -68,6 +71,12 @@
 	private int møllerEvents = 0;
 	private int tridentEvents = 0;
 	private int elasticEvents = 0;
+	private int totalEvents = 0;
+	private int pair1Events = 0;
+	private int pair0Events = 0;
+	private int singles1Events = 0;
+	private int singles0Events = 0;
+	private int pulserEvents = 0;
 	
 	@Override
 	public void startOfData() {
@@ -99,9 +108,15 @@
 	
 	@Override
 	public void endOfData() {
-		System.out.println("Møller  Events :: " + møllerEvents);
-		System.out.println("Trident Events :: " + tridentEvents);
-		System.out.println("Elastic Events :: " + elasticEvents);
+		System.out.println("Møller  Events   :: " + møllerEvents);
+		System.out.println("Trident Events   :: " + tridentEvents);
+		System.out.println("Elastic Events   :: " + elasticEvents);
+		System.out.println("Total Events     :: " + totalEvents);
+		System.out.println("Pair 1 Events    :: " + pair1Events);
+		System.out.println("Pair 0 Events    :: " + pair0Events);
+		System.out.println("Singles 1 Events :: " + singles1Events);
+		System.out.println("Singles 0 Events :: " + singles0Events);
+		System.out.println("Pulser Events    :: " + pulserEvents);
 		
 		System.out.println("Plsr\tS0\tS1\tP0\tP1\tMøller");
 		for(Entry<String, Integer> entry : møllerBitMap.entrySet()) {
@@ -236,7 +251,7 @@
 					continue møllerTrackLoop;
 				}
 				
-				timeCoincidenceAllCutsPlot.fill(Math.abs(seeds[0].getTime() - seeds[1].getTime()));
+				//timeCoincidenceAllCutsPlot.fill(Math.abs(seeds[0].getTime() - seeds[1].getTime()));
 				
 				// Note that this is a Møller event.
 				isMøller = true;
@@ -283,6 +298,7 @@
 				// Check the trident condition.
 				if((pair[0].getCharge() < 0 && pair[1].getCharge() > 0) || pair[0].getCharge() > 0 && pair[1].getCharge() < 0) {
 					// Both tracks must have clusters associated with them.
+					/*
 					Cluster[] trackClusters = new Cluster[2];
 					for(int i = 0; i < 2; i++) {
 						// Disallow tracks with no associated clusters.
@@ -303,13 +319,14 @@
 					if(Math.abs(trackClusters[0].getCalorimeterHits().get(0).getTime() - trackClusters[1].getCalorimeterHits().get(0).getTime()) > timeCoincidenceCut) {
 						continue tridentTrackLoop;
 					}
+					*/
 					
 					// Require that the energy of the electron is below
 					// 900 MeV.
-					if((pair[0].getCharge() < 0 && pair[0].getMomentum().magnitude() < 0.900)
-							|| (pair[1].getCharge() < 0 && pair[1].getMomentum().magnitude() < 0.900)) {
+					//if((pair[0].getCharge() < 0 && pair[0].getMomentum().magnitude() < 0.900)
+					//		|| (pair[1].getCharge() < 0 && pair[1].getMomentum().magnitude() < 0.900)) {
 						isTrident = true;
-						tridentPlots.addClusterPair(trackClusters);
+						//tridentPlots.addClusterPair(trackClusters);
 						if(pair[0].getCharge() > 0) {
 							positronPlot.fill(pair[1].getMomentum().magnitude());
 							electronPlot[TRIDENT].fill(pair[0].getMomentum().magnitude());
@@ -319,7 +336,7 @@
 						}
 						energyPlot[TRIDENT].fill(VecOp.add(pair[0].getMomentum(), pair[1].getMomentum()).magnitude());
 						energy2DPlot[TRIDENT].fill(pair[0].getMomentum().magnitude(), pair[1].getMomentum().magnitude());
-					}
+					//}
 				}
 			}
 			
@@ -330,29 +347,55 @@
 				System.out.println();
 			}
 			
-			// Get the number of charged tracks in the event.
-			int tracks = 0;
-			for(ReconstructedParticle track : trackList) {
-				if(track.getCharge() != 0) {
-					if(excludeNoTrackEvents && !track.getTracks().isEmpty()) {
-						tracks++;
-					} else { tracks++; }
-				}
-			}
-			
 			// Get the TI bits.
 			String bitString = null;
+			TIData tiBank = null;
 			List<GenericObject> bankList = event.get(GenericObject.class, bankCollectionName);
 			for(GenericObject obj : bankList) {
 				if(AbstractIntData.getTag(obj) == TIData.BANK_TAG) {
-					TIData tiBank = new TIData(obj);
+					tiBank = new TIData(obj);
 					bitString = getBitString(tiBank.isPulserTrigger(), tiBank.isSingle0Trigger(),
 							tiBank.isSingle1Trigger(), tiBank.isPair0Trigger(), tiBank.isPair1Trigger());
+					
+					if(tiBank.isPair1Trigger()) {
+						pair1Events++;
+					} else if(tiBank.isPair0Trigger()) {
+						pair0Events++;
+					} else if(tiBank.isSingle1Trigger()) {
+						singles1Events++;
+					} else if(tiBank.isSingle0Trigger()) {
+						singles0Events++;
+					} else if(tiBank.isPulserTrigger()) {
+						pulserEvents++;
+					}
 				}
 			}
 			if(bitString == null) {
 				System.out.println("No TI data found!!");
 			}
+			
+			// Get the number of charged tracks in the event.
+			int tracks = 0;
+			int posTracks = 0;
+			int negTracks = 0;
+			for(ReconstructedParticle track : trackList) {
+				if(track.getCharge() != 0 && tiBank.isPulserTrigger()) {
+					if(excludeNoTrackEvents && !track.getTracks().isEmpty()) {
+						tracks++;
+						if(track.getCharge() > 0) { posTracks++; }
+						else { negTracks++; }
+					} else {
+						tracks++;
+						if(track.getCharge() > 0) { posTracks++; }
+						else { negTracks++; }
+					}
+				}
+			}
+			
+			// Populate the "all tracks" plots.
+			posTrackCount.fill(posTracks);
+			negTrackCount.fill(negTracks);
+			chargedTrackCount.fill(tracks);
 			
 			// Add the result to the appropriate plots and increment
 			// the appropriate trigger bit combination.
@@ -381,6 +424,7 @@
 				if(val == null) { elasticBitMap.put(bitString, 1); }
 				else { elasticBitMap.put(bitString, val + 1); }
 			}
+			totalEvents++;
 		}
 	}
 	

Modified: java/trunk/users/src/main/java/org/hps/users/kmccarty/MTETriggerPlotsFormatter.java
 =============================================================================
--- java/trunk/users/src/main/java/org/hps/users/kmccarty/MTETriggerPlotsFormatter.java	(original)
+++ java/trunk/users/src/main/java/org/hps/users/kmccarty/MTETriggerPlotsFormatter.java	Tue Sep 22 12:10:36 2015
@@ -5,7 +5,8 @@
 import org.hps.users.kmccarty.plots.FormattedPlot1D;
 import org.hps.users.kmccarty.plots.FormattedPlot2D;
 import org.hps.users.kmccarty.plots.PlotFormatModule;
-import org.hps.users.kmccarty.PlotsFormatter.ColorStyle;
+import org.hps.users.kmccarty.plots.PlotsFormatter;
+import org.hps.users.kmccarty.plots.PlotsFormatter.ColorStyle;
 
 import hep.aida.IAnalysisFactory;
 import hep.aida.IHistogram1D;

Modified: java/trunk/users/src/main/java/org/hps/users/kmccarty/ParticleMCAnalysisDriver.java
 =============================================================================
--- java/trunk/users/src/main/java/org/hps/users/kmccarty/ParticleMCAnalysisDriver.java	(original)
+++ java/trunk/users/src/main/java/org/hps/users/kmccarty/ParticleMCAnalysisDriver.java	Tue Sep 22 12:10:36 2015
@@ -19,9 +19,9 @@
 	// Declare plots.
 	private AIDA aida = AIDA.defaultInstance();
 	private IHistogram1D chargedTracksPlot = aida.histogram1D("MC Analysis/Event Tracks", 10, -0.5, 9.5);
-	private IHistogram1D allPlot = aida.histogram1D("MC Analysis/Electron Energy Distribution", 110, 0, 2.2);
-	private IHistogram1D electronPlot = aida.histogram1D("MC Analysis/Electron Energy Distribution", 110, 0, 2.2);
-	private IHistogram1D positronPlot = aida.histogram1D("MC Analysis/Positron Energy Distribution", 110, 0, 2.2);
+	private IHistogram1D allPlot = aida.histogram1D("MC Analysis/Electron Energy Distribution", 110, 0, 1.1);
+	private IHistogram1D electronPlot = aida.histogram1D("MC Analysis/Electron Energy Distribution", 110, 0, 1.1);
+	private IHistogram1D positronPlot = aida.histogram1D("MC Analysis/Positron Energy Distribution", 110, 0, 1.1);
 	private IHistogram1D momentumXPlot = aida.histogram1D("MC Analysis/Particle x-Momentum Distribution", 110, 0.0, 1.1);
 	private IHistogram1D momentumYPlot = aida.histogram1D("MC Analysis/Particle y-Momentum Distribution", 110, 0.0, 1.1);
 	private IHistogram1D momentumZPlot = aida.histogram1D("MC Analysis/Particle z-Momentum Distribution", 110, 0.0, 1.1);

Added: java/trunk/users/src/main/java/org/hps/users/kmccarty/RafoAnalysis.java
 =============================================================================
--- java/trunk/users/src/main/java/org/hps/users/kmccarty/RafoAnalysis.java	(added)
+++ java/trunk/users/src/main/java/org/hps/users/kmccarty/RafoAnalysis.java	Tue Sep 22 12:10:36 2015
@@ -0,0 +1,303 @@
+package org.hps.users.kmccarty;
+
+import hep.aida.IHistogram1D;
+import hep.aida.IHistogram2D;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.hps.record.triggerbank.TriggerModule;
+import org.lcsim.event.Cluster;
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.ReconstructedParticle;
+import org.lcsim.util.Driver;
+import org.lcsim.util.aida.AIDA;
+
+public class RafoAnalysis extends Driver {
+	private String clusterCollectionName = "EcalClusters";
+	private String particleCollectionName = "FinalStateParticles";
+	
+	private AIDA aida = AIDA.defaultInstance();
+	private IHistogram1D t1TimeCoincidenceAll          = aida.histogram1D("Tier 1/Time Coincidence",                    45, 0.0, 15.0);
+	private IHistogram1D t1TimeCoincidenceFiducial     = aida.histogram1D("Tier 1/Time Coincidence (Fiducial Region)",  45, 0.0, 15.0);
+	private IHistogram1D t1EnergySumAll                = aida.histogram1D("Tier 1/Energy Sum",                         110, 0.0,  1.1);
+	private IHistogram1D t1EnergySumFiducial           = aida.histogram1D("Tier 1/Energy Sum (Fiducial Region)",       110, 0.0,  1.1);
+	private IHistogram2D t1EnergySum2DAll              = aida.histogram2D("Tier 1/Top Cluster Energy vs. Bottom Cluster Energy",                   55, 0, 1.1, 55, 0, 1.1);
+	private IHistogram2D t1EnergySum2DFiducial         = aida.histogram2D("Tier 1/Top Cluster Energy vs. Bottom Cluster Energy (Fiducial Region)", 55, 0, 1.1, 55, 0, 1.1);
+	private IHistogram2D t1SumCoplanarityAll           = aida.histogram2D("Tier 1/Hardware Coplanarity vs. Energy Sum",                            55, 0, 1.1, 165, 0, 230);
+	private IHistogram2D t1SumCoplanarityFiducial      = aida.histogram2D("Tier 1/Hardware Coplanarity vs. Energy Sum (Fiducial Region)",          55, 0, 1.1, 165, 0, 230);
+	private IHistogram2D t1SumCoplanarityCalcAll       = aida.histogram2D("Tier 1/Calculated Coplanarity vs. Energy Sum",                          55, 0, 1.1, 165, 0, 230);
+	private IHistogram2D t1SumCoplanarityCalcFiducial  = aida.histogram2D("Tier 1/Calculated Coplanarity vs. Energy Sum (Fiducial Region)",        55, 0, 1.1, 165, 0, 230);
+	private IHistogram2D t1TimeEnergyAll               = aida.histogram2D("Tier 1/Cluster Time vs. Cluster Energy",                                55, 0, 1.1,  25, 0, 100);
+	private IHistogram2D t1TimeEnergyFiducial          = aida.histogram2D("Tier 1/Cluster Time vs. Cluster Energy (Fiducial Region)",              55, 0, 1.1,  25, 0, 100);
+
+	private IHistogram1D t2TimeCoincidenceAll          = aida.histogram1D("Tier 1/Time Coincidence",                    45, 0.0, 15.0);
+	private IHistogram1D t2TimeCoincidenceFiducial     = aida.histogram1D("Tier 1/Time Coincidence (Fiducial Region)",  45, 0.0, 15.0);
+	private IHistogram1D t2EnergySumAll                = aida.histogram1D("Tier 1/Energy Sum",                         110, 0.0,  1.1);
+	private IHistogram1D t2EnergySumFiducial           = aida.histogram1D("Tier 1/Energy Sum (Fiducial Region)",       110, 0.0,  1.1);
+	private IHistogram2D t2EnergySum2DAll              = aida.histogram2D("Tier 1/Top Cluster Energy vs. Bottom Cluster Energy",                   55, 0, 1.1, 55, 0, 1.1);
+	private IHistogram2D t2EnergySum2DFiducial         = aida.histogram2D("Tier 1/Top Cluster Energy vs. Bottom Cluster Energy (Fiducial Region)", 55, 0, 1.1, 55, 0, 1.1);
+	private IHistogram2D t2SumCoplanarityAll           = aida.histogram2D("Tier 1/Hardware Coplanarity vs. Energy Sum",                            55, 0, 1.1, 165, 0, 230);
+	private IHistogram2D t2SumCoplanarityFiducial      = aida.histogram2D("Tier 1/Hardware Coplanarity vs. Energy Sum (Fiducial Region)",          55, 0, 1.1, 165, 0, 230);
+	private IHistogram2D t2SumCoplanarityCalcAll       = aida.histogram2D("Tier 1/Calculated Coplanarity vs. Energy Sum",                          55, 0, 1.1, 165, 0, 230);
+	private IHistogram2D t2SumCoplanarityCalcFiducial  = aida.histogram2D("Tier 1/Calculated Coplanarity vs. Energy Sum (Fiducial Region)",        55, 0, 1.1, 165, 0, 230);
+	private IHistogram2D t2TimeEnergyAll               = aida.histogram2D("Tier 1/Cluster Time vs. Cluster Energy",                                55, 0, 1.1,  25, 0, 100);
+	private IHistogram2D t2TimeEnergyFiducial          = aida.histogram2D("Tier 1/Cluster Time vs. Cluster Energy (Fiducial Region)",              55, 0, 1.1,  25, 0, 100);
+	
+	@Override
+	public void process(EventHeader event) {
+		// Get the list of particles, if it exists.
+		List<ReconstructedParticle> trackList = null;
+		if(event.hasCollection(ReconstructedParticle.class, particleCollectionName)) {
+			trackList = event.get(ReconstructedParticle.class, particleCollectionName);
+		}
+		
+		// Get the list of clusters, if it exists.
+		List<Cluster> clusterList = null;
+		if(event.hasCollection(Cluster.class, clusterCollectionName)) {
+			clusterList = event.get(Cluster.class, clusterCollectionName);
+		}
+		
+		// Make sure that the cluster and track lists both exist.
+		if(clusterList == null || trackList == null) {
+			return;
+		}
+		
+		// Perform tier 1 analysis. This requires that there be at
+		// least one top/bottom cluster pair with a time difference
+		// of less then 4 ns.
+		double t1TimeThreshold = 4;
+		
+		// Get a list of cluster pairs.
+		List<Cluster[]> pairList = getClusterPairs(clusterList);
+		
+		// Iterate over the cluster pairs.
+		boolean t1Passed = false;
+		t1ClusterLoop:
+		for(Cluster[] pair : pairList) {
+			// Check that the time difference for the cluster pair
+			// meets the time cut.
+			if(TriggerModule.getValueTimeCoincidence(pair) <= t1TimeThreshold) {
+				// Note that the tier 1 analysis condition passed.
+				t1Passed = true;
+				
+				// Break from the loop.
+				break t1ClusterLoop;
+			}
+		}
+		
+		// Perform the additional checks for tier 2 analysis. This
+		// requires that there be at least one top/bottom track pair
+		// and that one track be positive and the other be negative.
+		
+		// Get a list of top and bottom track pairs.
+		List<ReconstructedParticle[]> trackPairList = getTrackPairs(trackList);
+		
+		// Check that at least one top/bottom track has one negative and
+		// one positive track.
+		boolean t2Passed = false;
+		t2TrackLoop:
+		for(ReconstructedParticle[] pair : trackPairList) {
+			if((pair[0].getCharge() > 0 && pair[1].getCharge() < 0)
+					|| (pair[0].getCharge() < 0 && pair[1].getCharge() > 0)) {
+				t2Passed = true;
+				break t2TrackLoop;
+			}
+		}
+		
+		// Populate the tier 1 analysis plots, if the conditions were met.
+		if(t1Passed) {
+			// Track which clusters have already been added to the
+			// singles plot so that there are no repeats.
+			Set<Cluster> plotSet = new HashSet<Cluster>(clusterList.size());
+			Set<Cluster> plotFiducial = new HashSet<Cluster>(clusterList.size());
+			
+			for(Cluster[] pair : pairList) {
+				// Fill the all pairs plots.
+				double pairEnergy = pair[0].getEnergy() + pair[1].getEnergy();
+				t1EnergySumAll.fill(pairEnergy);
+				t1EnergySum2DAll.fill(pair[1].getEnergy(), pair[0].getEnergy());
+				t1TimeCoincidenceAll.fill(TriggerModule.getValueTimeCoincidence(pair));
+				t1SumCoplanarityCalcAll.fill(pairEnergy, getCalculatedCoplanarity(pair));
+				t1SumCoplanarityAll.fill(pairEnergy, TriggerModule.getValueCoplanarity(pair));
+				
+				// Fill the singles plots.
+				if(!plotSet.contains(pair[0])) {
+					plotSet.add(pair[0]);
+					t1TimeEnergyAll.fill(pair[0].getEnergy(), TriggerModule.getClusterTime(pair[0]));
+				} if(!plotSet.contains(pair[1])) {
+					plotSet.add(pair[1]);
+					t1TimeEnergyAll.fill(pair[1].getEnergy(), TriggerModule.getClusterTime(pair[1]));
+				}
+				
+				// Fill the fiducial plots if appropriate.
+				if(inFiducialRegion(pair[0]) && inFiducialRegion(pair[1])) {
+					t1EnergySumFiducial.fill(pairEnergy);
+					t1EnergySum2DFiducial.fill(pair[1].getEnergy(), pair[0].getEnergy());
+					t1TimeCoincidenceFiducial.fill(TriggerModule.getValueTimeCoincidence(pair));
+					t1SumCoplanarityCalcFiducial.fill(pairEnergy, getCalculatedCoplanarity(pair));
+					t1SumCoplanarityFiducial.fill(pairEnergy, TriggerModule.getValueCoplanarity(pair));
+				}
+				
+				// Fill the singles fiducial plots if appropriate.
+				if(!plotFiducial.contains(pair[0]) && inFiducialRegion(pair[0])) {
+					plotFiducial.add(pair[0]);
+					t1TimeEnergyFiducial.fill(pair[0].getEnergy(), TriggerModule.getClusterTime(pair[0]));
+				} if(!plotFiducial.contains(pair[1]) && inFiducialRegion(pair[1])) {
+					plotFiducial.add(pair[1]);
+					t1TimeEnergyFiducial.fill(pair[1].getEnergy(), TriggerModule.getClusterTime(pair[1]));
+				}
+			}
+		}
+		
+		// Populate the tier 2 analysis plots, if the conditions were met.
+		if(t2Passed) {
+			// Track which clusters have already been added to the
+			// singles plot so that there are no repeats.
+			Set<Cluster> plotSet = new HashSet<Cluster>(clusterList.size());
+			Set<Cluster> plotFiducial = new HashSet<Cluster>(clusterList.size());
+			
+			for(Cluster[] pair : pairList) {
+				// Fill the all pairs plots.
+				double pairEnergy = pair[0].getEnergy() + pair[1].getEnergy();
+				t2EnergySumAll.fill(pairEnergy);
+				t2EnergySum2DAll.fill(pair[1].getEnergy(), pair[0].getEnergy());
+				t2TimeCoincidenceAll.fill(TriggerModule.getValueTimeCoincidence(pair));
+				t2SumCoplanarityCalcAll.fill(pairEnergy, getCalculatedCoplanarity(pair));
+				t2SumCoplanarityAll.fill(pairEnergy, TriggerModule.getValueCoplanarity(pair));
+				
+				// Fill the singles plots.
+				if(!plotSet.contains(pair[0])) {
+					plotSet.add(pair[0]);
+					t2TimeEnergyAll.fill(pair[0].getEnergy(), TriggerModule.getClusterTime(pair[0]));
+				} if(!plotSet.contains(pair[1])) {
+					plotSet.add(pair[1]);
+					t2TimeEnergyAll.fill(pair[1].getEnergy(), TriggerModule.getClusterTime(pair[1]));
+				}
+				
+				// Fill the fiducial plots if appropriate.
+				if(inFiducialRegion(pair[0]) && inFiducialRegion(pair[1])) {
+					t2EnergySumFiducial.fill(pairEnergy);
+					t2EnergySum2DFiducial.fill(pair[1].getEnergy(), pair[0].getEnergy());
+					t2TimeCoincidenceFiducial.fill(TriggerModule.getValueTimeCoincidence(pair));
+					t2SumCoplanarityCalcFiducial.fill(pairEnergy, getCalculatedCoplanarity(pair));
+					t2SumCoplanarityFiducial.fill(pairEnergy, TriggerModule.getValueCoplanarity(pair));
+				}
+				
+				// Fill the singles fiducial plots if appropriate.
+				if(!plotFiducial.contains(pair[0]) && inFiducialRegion(pair[0])) {
+					plotFiducial.add(pair[0]);
+					t2TimeEnergyFiducial.fill(pair[0].getEnergy(), TriggerModule.getClusterTime(pair[0]));
+				} if(!plotFiducial.contains(pair[1]) && inFiducialRegion(pair[1])) {
+					plotFiducial.add(pair[1]);
+					t2TimeEnergyFiducial.fill(pair[1].getEnergy(), TriggerModule.getClusterTime(pair[1]));
+				}
+			}
+		}
+	}
+	
+	private static final double getCalculatedCoplanarity(Cluster[] pair) {
+		// Define the x- and y-coordinates of the clusters as well as
+		// calorimeter center.
+		final double ORIGIN_X = 42.52;
+		double x[] = { TriggerModule.getClusterSeedHit(pair[0]).getPosition()[0], TriggerModule.getClusterSeedHit(pair[1]).getPosition()[0] };
+		double y[] = { TriggerModule.getClusterSeedHit(pair[0]).getPosition()[0], TriggerModule.getClusterSeedHit(pair[1]).getPosition()[0] };
+		
+        // Get the cluster angles.
+        double[] clusterAngle = new double[2];
+        for(int i = 0; i < 2; i++) {
+            clusterAngle[i] = (Math.toDegrees(Math.atan2(y[i], x[i] - ORIGIN_X)) + 180.0) % 180.0;
+        }
+        
+        // Calculate the coplanarity cut value.
+        return Math.abs(clusterAngle[1] - clusterAngle[0]);
+	}
+	
+	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;
+	}
+	
+	private static final List<ReconstructedParticle[]> getTrackPairs(List<ReconstructedParticle> tracks) {
+		// Separate the tracks into top and bottom tracks.
+		List<ReconstructedParticle> topList = new ArrayList<ReconstructedParticle>();
+		List<ReconstructedParticle> botList = new ArrayList<ReconstructedParticle>();
+		for(ReconstructedParticle track : tracks) {
+			if(track.getMomentum().y() > 0.0) {
+				topList.add(track);
+			} else {
+				botList.add(track);
+			}
+		}
+		
+		// Form all permutations of top and bottom tracks.
+		List<ReconstructedParticle[]> pairList = new ArrayList<ReconstructedParticle[]>();
+		for(ReconstructedParticle topTrack : topList) {
+			for(ReconstructedParticle botTrack : botList) {
+				pairList.add(new ReconstructedParticle[] { topTrack, botTrack });
+			}
+		}
+		
+		// Return the resulting cluster pairs.
+		return pairList;
+	}
+	
+	private static final List<Cluster[]> getClusterPairs(List<Cluster> clusters) {
+		// Separate the clusters into top and bottom clusters.
+		List<Cluster> topList = new ArrayList<Cluster>();
+		List<Cluster> botList = new ArrayList<Cluster>();
+		for(Cluster cluster : clusters) {
+			if(TriggerModule.getClusterYIndex(cluster) > 0) {
+				topList.add(cluster);
+			} else {
+				botList.add(cluster);
+			}
+		}
+		
+		// Form all permutations of top and bottom clusters.
+		List<Cluster[]> pairList = new ArrayList<Cluster[]>();
+		for(Cluster topCluster : topList) {
+			for(Cluster botCluster : botList) {
+				pairList.add(new Cluster[] { topCluster, botCluster });
+			}
+		}
+		
+		// Return the resulting cluster pairs.
+		return pairList;
+	}
+}

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 22 12:10:36 2015
@@ -1,17 +1,26 @@
 package org.hps.users.kmccarty.plots;
 
-import org.hps.users.kmccarty.PlotsFormatter.ColorStyle;
+import org.hps.users.kmccarty.plots.PlotsFormatter.ColorStyle;
 
 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() {
@@ -21,4 +30,12 @@
 	public ColorStyle getColorStyle() {
 		return style;
 	}
+	
+	public boolean definesAxisRange() {
+		return axisRange != -1;
+	}
+	
+	public double getAxisRange() {
+		return axisRange;
+	}
 }

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 22 12:10:36 2015
@@ -5,10 +5,22 @@
 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;
 	}
 	
@@ -19,4 +31,20 @@
 	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 22 12:10:36 2015
@@ -7,9 +7,9 @@
 import hep.aida.IPlotterFactory;
 import hep.aida.ref.plotter.PlotterRegion;
 
-import org.hps.users.kmccarty.PlotsFormatter;
-import org.hps.users.kmccarty.PlotsFormatter.ColorStyle;
+import org.hps.users.kmccarty.plots.PlotsFormatter.ColorStyle;
 
+import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
@@ -60,8 +60,13 @@
 			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.
-			PlotterRegion region = (PlotterRegion) plotter.region(0);
 			region.getPlot().setTitle(formattedPlot.getPlotName());
 			region.getPlot().getXAxis().setLabel(formattedPlot.getXAxisName());
 			region.getPlot().getYAxis().setLabel(formattedPlot.getYAxisName());
@@ -89,12 +94,18 @@
 			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.
-			PlotterRegion region = (PlotterRegion) plotter.region(0);
 			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());
@@ -106,7 +117,11 @@
 			// If the file path is null, display the plots. Otherwise,
 			// save them to the destination folder.
 			if(filePath == null) { plotter.show(); }
-			else { plotter.writeToFile(filePath + formattedPlot.getPlotName() + ".png"); }
+			else {
+				File plotFile = new File(filePath + formattedPlot.getPlotName() + ".png");
+				if(plotFile.exists()) { plotFile.delete(); }
+				plotter.writeToFile(filePath + formattedPlot.getPlotName() + ".png");
+			}
 		}
 	}
 }