Print

Print


Author: [log in to unmask]
Date: Sat Mar  7 14:18:26 2015
New Revision: 2346

Log:
I create this driver as a copy of the EcalEventDisplay, including - as it was - the raw waveform, if available. I hope this will not be modified again

Added:
    java/trunk/monitoring-drivers/src/main/java/org/hps/monitoring/ecal/plots/EcalEventDisplayWithRawWaveform.java

Added: java/trunk/monitoring-drivers/src/main/java/org/hps/monitoring/ecal/plots/EcalEventDisplayWithRawWaveform.java
 =============================================================================
--- java/trunk/monitoring-drivers/src/main/java/org/hps/monitoring/ecal/plots/EcalEventDisplayWithRawWaveform.java	(added)
+++ java/trunk/monitoring-drivers/src/main/java/org/hps/monitoring/ecal/plots/EcalEventDisplayWithRawWaveform.java	Sat Mar  7 14:18:26 2015
@@ -0,0 +1,514 @@
+package org.hps.monitoring.ecal.plots;
+
+import hep.aida.IHistogram1D;
+import hep.aida.IHistogram2D;
+import hep.aida.IPlotter;
+import hep.aida.IPlotterFactory;
+import hep.aida.IPlotterStyle;
+
+import java.awt.Point;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.hps.monitoring.ecal.eventdisplay.ui.PDataEventViewer;
+import org.hps.monitoring.ecal.eventdisplay.ui.PEventViewer;
+import org.hps.monitoring.ecal.eventdisplay.ui.Viewer;
+import org.hps.monitoring.ecal.eventdisplay.util.CrystalEvent;
+import org.hps.monitoring.ecal.eventdisplay.util.CrystalListener;
+import org.hps.recon.ecal.ECalUtils;
+import org.lcsim.event.CalorimeterHit;
+import org.lcsim.event.Cluster;
+import org.lcsim.event.EventHeader;
+import org.lcsim.geometry.Detector;
+import org.lcsim.util.Driver;
+import org.lcsim.util.aida.AIDA;
+
+/**
+ * Driver <code>EcalEventDisplay</code> generates the histograms shown
+ * to the user in the fifth tab of the monitoring application. An
+ * instance of the single event display is employed to allow for the
+ * selection of specific crystal channels.<br/>
+ * <br/>
+ * The implementation is as follows:
+ * <ul><li>The event display is opened in a separate window</li>
+ * <li>It is updated regularly, according to the event refresh rate</li>
+ * <li>If the user clicks on a crystal, the corresponding energy and time
+ * distributions (both of type <code>IHistogram1D</code>) are shown in
+ * the last panel of the monitoring application, as well as a 2D histogram
+ * (hit time vs. hit energy). Finally, if available, the raw waveshape (in
+ * mV) is displayed.</li>
+ * 
+ * @author Andrea Celentano
+ */
+public class EcalEventDisplayWithRawWaveform extends Driver implements CrystalListener, ActionListener {
+	// Class variables.
+	private static final int NUM_CHANNELS = 11 * 47;
+	
+	// Plotter objects and variables.
+	private IPlotter plotter;
+	private IPlotterFactory plotterFactory;
+	private AIDA aida = AIDA.defaultInstance();	
+	
+	// LCIO Collection names.
+	private String inputCollection = "EcalCalHits";
+	private String clusterCollection = "EcalClusters";
+	private String inputCollectionRaw = "EcalReadoutHits";
+	
+	// Channel plot lists.
+	private ArrayList<IHistogram1D> channelEnergyPlot;
+	private ArrayList<IHistogram1D> clusterEnergyPlot;
+	private ArrayList<IHistogram1D> channelTimePlot;
+	//private ArrayList<IHistogram1D> channelRawWaveform;
+	private ArrayList<IHistogram2D> channelTimeVsEnergyPlot;
+	
+	// Internal variables.
+	private PEventViewer viewer;								 // Single event display.
+	private int pedSamples = 10;								 // 
+	private IPlotterStyle pstyle;								 // The plotter style for all plots.
+	private long lastEventTime = 0;								 // Tracks the time at which the last event occurred.
+	private int eventRefreshRate = 1;							 // The number of seconds before an update occurs.
+	private boolean resetOnUpdate = true;						 // Clears the event display on each update.
+	private double minEch = 10 * ECalUtils.MeV;					 // The energy scale minimum.
+	private double maxEch = 3500 * ECalUtils.MeV;				 // The energy scale maximum.
+	private int[] windowRaw = new int[NUM_CHANNELS];			 // The number of samples in a waveform for each channel.
+	private boolean[] isFirstRaw = new boolean[NUM_CHANNELS];	 // Whether a waveform plot was initiated for each channel.
+	
+	// Plot style and title variables.
+	private static final String NO_TITLE = "";
+	private static final String SIGNAL_TIME_TITLE = "Time (ns)";
+	private static final String HIT_TIME_TITLE = "Hit Time (ns)";
+	private static final String SIGNAL_DATA_STYLE_COLOR = "orange";
+	private static final String RAW_WAVEFORM_TITLE = "Raw Waveform";
+	private static final String HIT_ENERGY_TITLE = "Hit Energy (GeV)";
+	private static final String CLUSTER_ENERGY_TITLE = "Cluster Energy (GeV)";
+	private static final String SIGNAL_AMPLITUDE_TITLE = "Signal Amplitude (mV)";
+	
+	/**
+	 * Sets the upper bound of the energy scales used by the driver.
+	 * Energy units are in GeV.
+	 * @param maxEch - The energy scale upper bound.
+	 */
+	public void setMaxEch(double maxEch) {
+		this.maxEch = maxEch;
+	}
+	
+	/**
+	 * Sets the lower bound of the energy scales used by the driver.
+	 * Energy units are in GeV.
+	 * @param minEch - The lower energy scale bound.
+	 */
+	public void setMinEch(double minEch) {
+		this.minEch = minEch;
+	}
+	
+	public void setPedSamples(int pedSamples) {
+		this.pedSamples = pedSamples;
+	}
+	/**
+	 * Sets the LCIO collection name for the processed calorimeter hits.
+	 * @param inputCollection - The LCIO collection name.
+	 */
+	public void setInputCollection(String inputCollection) {
+		this.inputCollection = inputCollection;
+	}
+	
+	/**
+	 * Sets the LCIO collection name for the raw waveform hits.
+	 * @param inputCollectionRaw - The LCIO collection name.
+	 */
+	public void setInputCollectionRaw(String inputCollectionRaw) {
+		this.inputCollectionRaw = inputCollectionRaw;
+	}
+	
+	/**
+	 * Sets the LCIO collection name for calorimeter clusters.
+	 * @param inputClusterCollection - The LCIO collection name.
+	 */
+	public void setInputClusterCollection(String inputClusterCollection) {
+		this.clusterCollection = inputClusterCollection;
+	}
+	
+	/**
+	 * Sets the rate at which the GUI updates its elements,
+	 * @param eventRefreshRate - The rate at which the GUI should be
+	 * updated, in seconds.
+	 */
+	public void setEventRefreshRate(int eventRefreshRate) {
+		this.eventRefreshRate = eventRefreshRate;
+	}
+	
+	/**
+	 * Sets whether the event display should be cleared after event
+	 * or whether it should retain the previously displayed results.
+	 * @param resetOnUpdate - <code>true</code> means that the event
+	 * display should be cleared on each update and <code>false</code>
+	 * that it should not.
+	 */
+	public void setResetOnUpdate(boolean resetOnUpdate) {
+		this.resetOnUpdate = resetOnUpdate;
+	}
+	
+	/**
+	 * Initializes the single channel monitoring plots for all crystal
+	 * channels and defines the plotter region that contains them.
+	 */
+	@Override
+	public void detectorChanged(Detector detector) {
+		// Reset the AIDA tree directory.
+		aida.tree().cd("/");
+		
+		// Store histograms for the crystals.
+		channelEnergyPlot = new ArrayList<IHistogram1D>(NUM_CHANNELS);
+		channelTimePlot = new ArrayList<IHistogram1D>(NUM_CHANNELS);
+		channelRawWaveform = new ArrayList<IHistogram1D>(NUM_CHANNELS);
+		clusterEnergyPlot = new ArrayList<IHistogram1D>(NUM_CHANNELS);
+		channelTimeVsEnergyPlot = new ArrayList<IHistogram2D>(NUM_CHANNELS);
+		
+		// Create the histograms for single channel energy and time
+		// distribution.
+		for(int ii = 0; ii < NUM_CHANNELS; ii++) {
+			// The above instruction is a terrible hack, just to fill
+			// the arrayList with all the elements. They'll be initialized
+			// properly during the event readout, Since we want to account
+			// for possibly different raw waveform dimensions!
+			
+			//Get the x and y indices for the current channel.
+			int row = EcalMonitoringUtilities.getRowFromHistoID(ii);
+			int column = EcalMonitoringUtilities.getColumnFromHistoID(ii);
+			
+			// Initialize the histograms for the current crystal channel.
+			channelEnergyPlot.add(aida.histogram1D(detector.getDetectorName() + " : "
+						+ inputCollection + " : Hit Energy : " + column + " " + row
+						+ ": " + ii, 100, -0.2, maxEch));
+			channelTimePlot.add(aida.histogram1D(detector.getDetectorName() + " : "
+						+ inputCollection + " : Hit Time : " + column + " " + row + ": "
+						+ ii, 100, 0, 400));     
+			channelTimeVsEnergyPlot.add(aida.histogram2D(detector.getDetectorName()
+					+ " : " + inputCollection + " : Hit Time Vs Energy : " + column
+					+ " " + row + ": " + ii, 100, 0, 400, 100, -0.2, maxEch));              
+			channelRawWaveform.add(aida.histogram1D(detector.getDetectorName() + " : "
+					+ inputCollection + " : Hit Energy : " + column + " " + row + ": " + ii));
+			clusterEnergyPlot.add(aida.histogram1D(detector.getDetectorName() + " : "
+					+ inputCollection + " : Cluster Energy : " + column + " " + row
+					+ ": " + ii, 100, -0.2, maxEch));
+			
+			// Note that no raw waveform has yet been read for this
+			// crystal/channel.
+			windowRaw[ii] = 1;
+			isFirstRaw[ii] = true;
+		}
+		
+		// Define the plot region that will display the single channel
+		// plots in the monitoring application.
+		plotterFactory = aida.analysisFactory().createPlotterFactory("Single Channel");
+		plotter = plotterFactory.create("Single Channel");
+		pstyle = this.createDefaultStyle();
+		plotter.setTitle("");
+		plotter.createRegions(2,2);
+		
+		// Define the first plot region.
+		pstyle.xAxisStyle().setLabel(HIT_ENERGY_TITLE);
+		pstyle.yAxisStyle().setLabel(NO_TITLE);
+		plotter.region(0).plot(channelEnergyPlot.get(0), pstyle);
+		
+		// Define the second plot region.
+		pstyle.xAxisStyle().setLabel(HIT_TIME_TITLE);
+		pstyle.yAxisStyle().setLabel(NO_TITLE);
+		plotter.region(1).plot(channelTimePlot.get(0), pstyle);
+		
+		// Define the third plot region; this encompasses the time vs.
+		// energy plots.
+		pstyle.xAxisStyle().setLabel(HIT_TIME_TITLE);
+		pstyle.yAxisStyle().setLabel(HIT_ENERGY_TITLE);
+		plotter.region(2).plot(channelTimeVsEnergyPlot.get(0), pstyle);
+		
+		
+		
+		
+		// Define the fourth plot region; this encompasses the raw
+		// wave form plots.
+		pstyle.xAxisStyle().setLabel(RAW_WAVEFORM_TITLE);
+		pstyle.yAxisStyle().setLabel(NO_TITLE);
+		pstyle.dataStyle().fillStyle().setColor(SIGNAL_DATA_STYLE_COLOR);
+		pstyle.dataStyle().markerStyle().setColor(SIGNAL_DATA_STYLE_COLOR);
+		pstyle.dataStyle().errorBarStyle().setVisible(false);
+		plotter.region(3).plot(channelRawWaveform.get(0), pstyle);
+		
+		
+		// Display the plot region.
+		plotter.show();
+		
+		// Set the time tracker variables.
+		lastEventTime = 0;
+	}
+	
+	/**
+	 * Initializes the <code>Viewer</code> for the single event display.
+	 * If a configuration file is available, then it is used by the
+	 * <code>Viewer</code> to display hardware configuration mappings.
+	 * Otherwise, this is excluded.
+	 */
+	@Override
+	public void startOfData() {
+		// Check if the configuration mapping file exists.
+		File config = new File("ecal-mapping-config.csv");
+		
+		// If the file exists, load the viewer that will display it.
+		if(config.exists() && config.canRead()) {
+			// Account for IO read errors. Only load this version if
+			// the data file can be read successfully.
+			try { viewer = new PDataEventViewer(config.getAbsolutePath()); }
+			
+			// Otherwise, open the regular version.
+			catch (IOException e) { viewer = new PEventViewer(); }
+		}
+		
+		// If the file is not present, then just load the normal version.
+		else { viewer = new PEventViewer(); }
+		
+		// Set the viewer properties.
+		viewer.setScaleMinimum(minEch);
+		viewer.setScaleMaximum(maxEch);
+		viewer.addCrystalListener(this);
+		
+		// Make the Viewer object visible.
+		viewer.setVisible(true);
+	}
+	
+	/**
+	 * Hides the single event display and disposes it from memory.
+	 */
+	@Override
+	public void endOfData() {
+		viewer.setVisible(false);
+		viewer.dispose();
+	}
+	
+	@Override
+	public void process(EventHeader event){
+		// Check whether enough time has passed to perform an update
+		// on the event display.
+		boolean update = false;
+		long currentTime = System.currentTimeMillis() / 1000;
+		if((currentTime - lastEventTime) > eventRefreshRate){
+			lastEventTime = currentTime;
+			update = true;
+		}
+		
+		// If an update should be made, perform the update.
+		if(update && resetOnUpdate) { viewer.resetDisplay(); }
+		
+		// If the event has calorimeter hit objects...
+		if(event.hasCollection(CalorimeterHit.class, inputCollection)) {
+			// Get the list of calorimeter hits.
+			List<CalorimeterHit> hits = event.get(CalorimeterHit.class, inputCollection);
+			
+			// For each of the calorimeter hits...
+			for (CalorimeterHit hit : hits) {
+				// Get the x and y indices for the current hit.
+				int ix = hit.getIdentifierFieldValue("ix");
+				int iy = hit.getIdentifierFieldValue("iy");
+				
+				if (iy != 0 && ix != 0) {
+					// Get the histogram index for the hit.
+					int id = EcalMonitoringUtilities.getHistoIDFromRowColumn(iy, ix);
+					
+					// If the hit has energy, populate the plots.
+					if(hit.getCorrectedEnergy() > 0) {
+						channelEnergyPlot.get(id).fill(hit.getCorrectedEnergy());
+						channelTimePlot.get(id).fill(hit.getTime());
+						channelTimeVsEnergyPlot.get(id).fill(hit.getTime(), hit.getCorrectedEnergy());
+					}
+					
+					// If an update to the event display should be
+					// performed, give it the hits.
+					if(update) { viewer.addHit(hit); }
+				}
+			}
+		}
+		
+		// If there are clusters in the event...
+		if (event.hasCollection(Cluster.class, clusterCollection)) {
+			// Get the list of clusters.
+			List<Cluster> clusters = event.get(Cluster.class, clusterCollection);
+			
+			// Iterate over the clusters and add them to the event
+			// display if appropriate.
+			for (Cluster cluster : clusters) {
+				// Get the ix and iy indices for the seed.
+				int ix = cluster.getCalorimeterHits().get(0).getIdentifierFieldValue("ix");
+				int iy = cluster.getCalorimeterHits().get(0).getIdentifierFieldValue("iy");
+				
+				// Get the histogram index for the hit.
+				int id = EcalMonitoringUtilities.getHistoIDFromRowColumn(iy, ix);
+				
+				// Add the cluster energy to the plot.
+				if(cluster.getEnergy() > 0.0) {
+					clusterEnergyPlot.get(id).fill(cluster.getEnergy());
+				}
+				
+				// If an update is needed, add the cluster to the viewer.
+				if(update) { viewer.addCluster(cluster); }
+			}
+		}
+		
+	
+		// Plot the raw waveform only if raw tracker hit exist in the
+		// event.
+		if (event.hasCollection(RawTrackerHit.class, inputCollectionRaw)){
+		    // Get the list of raw tracker hits.
+		    List<RawTrackerHit> hits = event.get(RawTrackerHit.class, inputCollectionRaw);
+		    
+		    // Process each raw tracker hit.
+			for (RawTrackerHit hit : hits) {
+				// Get the x and y indices for the hit.
+				int ix = hit.getIdentifierFieldValue("ix");
+				int iy = hit.getIdentifierFieldValue("iy");
+				
+				if(iy != 0 && ix != 0) {
+					if(!ECalUtils.isInHole(iy, ix)) {
+						// Get the crystal ID for the current hit.
+						int id = ECalUtils.getHistoIDFromRowColumn(iy, ix);
+						
+						// The window is length is not known by default.
+						// If this is the first hit, read the window
+						// length and initialize the plot.
+						if(isFirstRaw[id]) {
+							// Note that this plot is initialized.
+							isFirstRaw[id] = false;
+							
+							// Set the waveform array.
+							windowRaw[id] = hit.getADCValues().length;
+							
+							// Initialize the waveform plot.
+							channelRawWaveform.set(id, aida.histogram1D(detector.getDetectorName()
+									+ " : " + inputCollectionRaw + " : Raw Waveform : " + ix + " "
+									+ iy + ": " + id, windowRaw[id], -0.5 * ECalUtils.ecalReadoutPeriod,
+									(-0.5 + windowRaw[id]) * ECalUtils.ecalReadoutPeriod));
+						}
+						
+						// If the plot should be updated, do so.
+						if(update) {
+							channelRawWaveform.get(id).reset();
+							for (int jj = 0; jj < windowRaw[id]; jj++) {
+								channelRawWaveform.get(id).fill(jj * ECalUtils.ecalReadoutPeriod,
+										hit.getADCValues()[jj] * ECalUtils.adcResolution * 1000);
+							}
+							double[] result = ECalUtils.computeAmplitude(hit.getADCValues(), windowRaw[id], pedSamples);
+							channelRawWaveform.get(id).setTitle("Ampl: " + String.format("%.2f", result[0])
+									+ " mV , ped : " + String.format("%.2f", result[1]) + " "
+									+ String.format("%.2f", result[2]) + " ADC counts");
+							plotter.region(3).refresh();
+						}
+					}
+				}
+			}
+		}
+		
+		
+		// Update the single event display.
+		if(update) { viewer.updateDisplay(); }
+	}
+	
+	@Override
+	public void actionPerformed(ActionEvent ae) { }
+	
+	@Override
+	public void crystalActivated(CrystalEvent e) { }
+	
+	@Override
+	public void crystalDeactivated(CrystalEvent e) { }
+	
+	/**
+	 * Updates the monitoring plots for the crystal that was clicked.
+	 */
+	@Override
+	public void crystalClicked(CrystalEvent e) {
+		// Get the crystal that was clicked in the LCSim coordinate system.
+		Point ecalPoint = Viewer.toEcalPoint(e.getCrystalID());
+		
+		// Make sure that the clicked crystal is valid. Necessary??
+		if((ecalPoint.x != 0) && (ecalPoint.y != 0))
+			if (!EcalMonitoringUtilities.isInHole(ecalPoint.y, ecalPoint.x)) {
+				// Get the crystal ID.
+				int id = EcalMonitoringUtilities.getHistoIDFromRowColumn(ecalPoint.y, ecalPoint.x);
+				
+				// Clear and replot region 0 for the new crystal.
+				plotter.region(0).clear();
+				pstyle.xAxisStyle().setLabel(HIT_ENERGY_TITLE);
+				pstyle.yAxisStyle().setLabel(NO_TITLE);
+				plotter.region(0).plot(channelEnergyPlot.get(id), pstyle);
+				
+				// Clear and replot region 1 for the new crystal.
+				plotter.region(1).clear();
+				pstyle.xAxisStyle().setLabel(HIT_TIME_TITLE);
+				pstyle.yAxisStyle().setLabel(NO_TITLE);
+				plotter.region(1).plot(channelTimePlot.get(id), pstyle);
+				
+				// Clear and replot region 2 for the new crystal.
+				plotter.region(2).clear();
+				pstyle.xAxisStyle().setLabel(HIT_TIME_TITLE);
+				pstyle.yAxisStyle().setLabel(HIT_ENERGY_TITLE);
+				plotter.region(2).plot(channelTimeVsEnergyPlot.get(id), pstyle);
+				
+		
+				// Process and plot the region 3 plot.
+				if(!isFirstRaw[id]) {
+					pstyle.yAxisStyle().setLabel(SIGNAL_AMPLITUDE_TITLE);
+					pstyle.xAxisStyle().setLabel(SIGNAL_TIME_TITLE);
+					pstyle.dataStyle().fillStyle().setColor(SIGNAL_DATA_STYLE_COLOR);
+					pstyle.dataStyle().markerStyle().setColor(SIGNAL_DATA_STYLE_COLOR);
+					pstyle.dataStyle().errorBarStyle().setVisible(false);
+				}
+				else {
+					pstyle.xAxisStyle().setLabel(HIT_ENERGY_TITLE);
+					pstyle.yAxisStyle().setLabel("");
+				}
+				plotter.region(3).plot(channelRawWaveform.get(id), pstyle);
+		}
+	}
+	
+	/**
+	 * Initializes the default style for plots.
+	 * @return Returns an <code>IPlotterStyle</code> object that
+	 * represents the default style for plots.
+	 */
+	public IPlotterStyle createDefaultStyle() {
+		IPlotterStyle pstyle = plotterFactory.createPlotterStyle();
+		// Set the appearance of the axes.
+		pstyle.xAxisStyle().labelStyle().setBold(true);
+		pstyle.yAxisStyle().labelStyle().setBold(true);
+		pstyle.xAxisStyle().tickLabelStyle().setBold(true);
+		pstyle.yAxisStyle().tickLabelStyle().setBold(true);
+		pstyle.xAxisStyle().lineStyle().setColor("black");
+		pstyle.yAxisStyle().lineStyle().setColor("black");
+		pstyle.xAxisStyle().lineStyle().setThickness(2);
+		pstyle.yAxisStyle().lineStyle().setThickness(2);
+		
+		// Set color settings.
+		pstyle.dataStyle().fillStyle().setParameter("colorMapScheme", "rainbow");
+		pstyle.dataStyle().fillStyle().setParameter("showZeroHeightBins", Boolean.FALSE.toString());
+		pstyle.dataStyle().errorBarStyle().setVisible(false);
+		pstyle.setParameter("hist2DStyle", "colorMap");
+		
+		// Force auto range to zero.
+		pstyle.yAxisStyle().setParameter("allowZeroSuppression", "false");
+		pstyle.xAxisStyle().setParameter("allowZeroSuppression", "false");
+		
+		// Set the title style.
+		pstyle.titleStyle().textStyle().setFontSize(20);
+		
+		// Draw caps on error bars.
+		pstyle.dataStyle().errorBarStyle().setParameter("errorBarDecoration", (new Float(1.0f)).toString());
+		
+		// Turn off grid lines until explicitly enabled.
+		pstyle.gridStyle().setVisible(false);
+		
+		// Return the style.
+		return pstyle;
+	}
+}