Author: [log in to unmask]
Date: Thu Apr 16 15:53:48 2015
New Revision: 2724
Log:
Some fix up to EcalEventDisplay Driver so it behaves better in monitoring app.
Modified:
java/trunk/monitoring-drivers/src/main/java/org/hps/monitoring/ecal/plots/EcalEventDisplay.java
Modified: java/trunk/monitoring-drivers/src/main/java/org/hps/monitoring/ecal/plots/EcalEventDisplay.java
=============================================================================
--- java/trunk/monitoring-drivers/src/main/java/org/hps/monitoring/ecal/plots/EcalEventDisplay.java (original)
+++ java/trunk/monitoring-drivers/src/main/java/org/hps/monitoring/ecal/plots/EcalEventDisplay.java Thu Apr 16 15:53:48 2015
@@ -13,6 +13,8 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
+
+import javax.swing.SwingUtilities;
import org.hps.monitoring.ecal.eventdisplay.ui.PDataEventViewer;
import org.hps.monitoring.ecal.eventdisplay.ui.PEventViewer;
@@ -28,507 +30,93 @@
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).The fourth panel reports energy for the crystal.</li>
- *
+ * This <code>Driver</code> creates an instance of the ECAL event display viewer and will generate plots in the
+ * monitoring app for individual channels that are selected. The event display is updated regularly, according to the
+ * event refresh rate. 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). The fourth panel reports energy for the crystal.
+ *
* @author Andrea Celentano
*/
public class EcalEventDisplay extends Driver implements CrystalListener, ActionListener {
+ private static final String CLUSTER_ENERGY_TITLE = "Cluster Energy (GeV)";
+
+ // 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 SIGNAL_TIME_TITLE = "Time (ns)";
+ private static final String HIT_TIME_TITLE = "Hit Time (ns)";
+ // Plot style and title variables.
+ private static final String NO_TITLE = "";
+
// Class variables.
private static final int NUM_CHANNELS = 11 * 47;
-
+ private final AIDA aida = AIDA.defaultInstance();
+ // Channel plot lists.
+ private ArrayList<IHistogram1D> channelEnergyPlot;
+
+ private ArrayList<IHistogram1D> channelTimePlot;
+ // private ArrayList<IHistogram1D> channelRawWaveform;
+ private ArrayList<IHistogram2D> channelTimeVsEnergyPlot;
+ private String clusterCollection = "EcalClusters";
+ private ArrayList<IHistogram1D> clusterEnergyPlot;
+
+ private String detectorName;
+ // private static final String SIGNAL_AMPLITUDE_TITLE = "Signal Amplitude (mV)";
+ private int eventRefreshRate = 1; // The number of seconds before an update occurs.
+ // LCIO Collection names.
+ private String inputCollection = "EcalCalHits";
+ private String inputCollectionRaw = "EcalReadoutHits";
+ private final boolean[] isFirstRaw = new boolean[NUM_CHANNELS]; // Whether a waveform plot was initiated for each
+ // channel.
+ private long lastEventTime = 0; // Tracks the time at which the last event occurred.
+ private double maxEch = 3500 * EcalUtils.MeV; // The energy scale maximum.
+ private double minEch = 10 * EcalUtils.MeV; // The energy scale minimum.
+ private int pedSamples = 10; //
// 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;
-
+ private IPlotterStyle pstyle; // The plotter style for all plots.
+ private boolean resetOnUpdate = true; // Clears the event display on each update.
// 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 String detectorName;
- //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("/");
- detectorName=detector.getName();
- // 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(detectorName + " : "
- + inputCollection + " : Hit Energy : " + column + " " + row
- + ": " + ii, 100, -0.2, maxEch));
- channelTimePlot.add(aida.histogram1D(detectorName + " : "
- + inputCollection + " : Hit Time : " + column + " " + row + ": "
- + ii, 100, 0, 400));
- channelTimeVsEnergyPlot.add(aida.histogram2D(detectorName
- + " : " + 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(detectorName + " : "
- + 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 cluster
- // energy for each channel.
- pstyle.xAxisStyle().setLabel(CLUSTER_ENERGY_TITLE);
- pstyle.yAxisStyle().setLabel(NO_TITLE);
- plotter.region(3).plot(clusterEnergyPlot.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() {
+ private final PEventViewer viewer; // Single event display.
+ private final int[] windowRaw = new int[NUM_CHANNELS]; // The number of samples in a waveform for each channel.
+
+ public EcalEventDisplay() {
// Check if the configuration mapping file exists.
- File config = new File("ecal-mapping-config.csv");
+ final File config = new File("ecal-mapping-config.csv");
// If the file exists, load the viewer that will display it.
- if(config.exists() && config.canRead()) {
+ 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()); }
-
+ try {
+ this.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.
- * Also removes histograms from aida tree. We do not want them in the output aida file, if any..
- */
- @Override
- public void endOfData() {
- viewer.setVisible(false);
- viewer.dispose();
-
- int row,column;
- String hName;
- //System.out.println("EcalEventDisplay endOfData clear histograms");
- 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.
- row = EcalMonitoringUtilities.getRowFromHistoID(ii);
- column = EcalMonitoringUtilities.getColumnFromHistoID(ii);
- hName=detectorName + " : "
- + inputCollection + " : Hit Energy : " + column + " " + row
- + ": " + ii;
- aida.tree().rm(hName);
-
- hName=detectorName + " : "
- + inputCollection + " : Hit Time : " + column + " " + row + ": "
- + ii;
- aida.tree().rm(hName);
-
- hName=detectorName+ " : " + inputCollection + " : Hit Time Vs Energy : " + column
- + " " + row + ": " + ii;
- aida.tree().rm(hName);
-
-
- if (isFirstRaw[ii]==false){
- hName=detectorName+
- " : " + inputCollectionRaw + " : Raw Waveform : " + column + " "
- + row + ": " + ii;
- aida.tree().rm(hName);
-
- }
-
- }
- //System.out.println("EcalEventDisplay endOfData clear histograms done");
- }
-
- @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.
- plotter.region(3).clear();
- pstyle.xAxisStyle().setLabel(CLUSTER_ENERGY_TITLE);
- pstyle.yAxisStyle().setLabel(NO_TITLE);
- plotter.region(3).plot(clusterEnergyPlot.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);
- **/
- }
+ catch (final IOException e) {
+ // Throw an error if this happens as configuration file should be accessible (checked for it already).
+ throw new RuntimeException(e);
+ // this.viewer = new PEventViewer();
+ }
+ } else {
+ // If the file is not present, then just load the normal version.
+ this.viewer = new PEventViewer();
+ }
+ }
+
+ @Override
+ public void actionPerformed(final ActionEvent ae) {
}
/**
* Initializes the default style for plots.
- * @return Returns an <code>IPlotterStyle</code> object that
- * represents 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();
+ final IPlotterStyle pstyle = this.plotterFactory.createPlotterStyle();
// Set the appearance of the axes.
pstyle.xAxisStyle().labelStyle().setBold(true);
pstyle.yAxisStyle().labelStyle().setBold(true);
@@ -553,7 +141,7 @@
pstyle.titleStyle().textStyle().setFontSize(20);
// Draw caps on error bars.
- pstyle.dataStyle().errorBarStyle().setParameter("errorBarDecoration", (new Float(1.0f)).toString());
+ pstyle.dataStyle().errorBarStyle().setParameter("errorBarDecoration", new Float(1.0f).toString());
// Turn off grid lines until explicitly enabled.
pstyle.gridStyle().setVisible(false);
@@ -561,4 +149,390 @@
// Return the style.
return pstyle;
}
+
+ @Override
+ public void crystalActivated(final CrystalEvent e) {
+ }
+
+ /**
+ * Updates the monitoring plots for the crystal that was clicked.
+ */
+ @Override
+ public void crystalClicked(final CrystalEvent e) {
+ // Get the crystal that was clicked in the LCSim coordinate system.
+ final 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.
+ final int id = EcalMonitoringUtilities.getHistoIDFromRowColumn(ecalPoint.y, ecalPoint.x);
+
+ // Clear and replot region 0 for the new crystal.
+ this.plotter.region(0).clear();
+ this.pstyle.xAxisStyle().setLabel(HIT_ENERGY_TITLE);
+ this.pstyle.yAxisStyle().setLabel(NO_TITLE);
+ this.plotter.region(0).plot(this.channelEnergyPlot.get(id), this.pstyle);
+
+ // Clear and replot region 1 for the new crystal.
+ this.plotter.region(1).clear();
+ this.pstyle.xAxisStyle().setLabel(HIT_TIME_TITLE);
+ this.pstyle.yAxisStyle().setLabel(NO_TITLE);
+ this.plotter.region(1).plot(this.channelTimePlot.get(id), this.pstyle);
+
+ // Clear and replot region 2 for the new crystal.
+ this.plotter.region(2).clear();
+ this.pstyle.xAxisStyle().setLabel(HIT_TIME_TITLE);
+ this.pstyle.yAxisStyle().setLabel(HIT_ENERGY_TITLE);
+ this.plotter.region(2).plot(this.channelTimeVsEnergyPlot.get(id), this.pstyle);
+
+ // Process and plot the region 3 plot.
+ this.plotter.region(3).clear();
+ this.pstyle.xAxisStyle().setLabel(CLUSTER_ENERGY_TITLE);
+ this.pstyle.yAxisStyle().setLabel(NO_TITLE);
+ this.plotter.region(3).plot(this.clusterEnergyPlot.get(id), this.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);
+ **/
+ }
+ }
+ }
+
+ @Override
+ public void crystalDeactivated(final CrystalEvent e) {
+ }
+
+ /**
+ * Initializes the single channel monitoring plots for all crystal channels and defines the plotter region that
+ * contains them.
+ */
+ @Override
+ public void detectorChanged(final Detector detector) {
+ // Reset the AIDA tree directory.
+ this.aida.tree().cd("/");
+ this.detectorName = detector.getName();
+ // Store histograms for the crystals.
+ this.channelEnergyPlot = new ArrayList<IHistogram1D>(NUM_CHANNELS);
+ this.channelTimePlot = new ArrayList<IHistogram1D>(NUM_CHANNELS);
+ // channelRawWaveform = new ArrayList<IHistogram1D>(NUM_CHANNELS);
+ this.clusterEnergyPlot = new ArrayList<IHistogram1D>(NUM_CHANNELS);
+ this.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.
+ final int row = EcalMonitoringUtilities.getRowFromHistoID(ii);
+ final int column = EcalMonitoringUtilities.getColumnFromHistoID(ii);
+
+ // Initialize the histograms for the current crystal channel.
+ this.channelEnergyPlot.add(this.aida.histogram1D(this.detectorName + " : " + this.inputCollection
+ + " : Hit Energy : " + column + " " + row + ": " + ii, 100, -0.2, this.maxEch));
+ this.channelTimePlot.add(this.aida.histogram1D(this.detectorName + " : " + this.inputCollection
+ + " : Hit Time : " + column + " " + row + ": " + ii, 100, 0, 400));
+ this.channelTimeVsEnergyPlot
+ .add(this.aida.histogram2D(this.detectorName + " : " + this.inputCollection
+ + " : Hit Time Vs Energy : " + column + " " + row + ": " + ii, 100, 0, 400, 100, -0.2,
+ this.maxEch));
+ // channelRawWaveform.add(aida.histogram1D(detector.getDetectorName() + " : "
+ // + inputCollection + " : Hit Energy : " + column + " " + row + ": " + ii));
+ this.clusterEnergyPlot.add(this.aida.histogram1D(this.detectorName + " : " + this.inputCollection
+ + " : Cluster Energy : " + column + " " + row + ": " + ii, 100, -0.2, this.maxEch));
+
+ // Note that no raw waveform has yet been read for this
+ // crystal/channel.
+ this.windowRaw[ii] = 1;
+ this.isFirstRaw[ii] = true;
+ }
+
+ // Define the plot region that will display the single channel
+ // plots in the monitoring application.
+ this.plotterFactory = this.aida.analysisFactory().createPlotterFactory("Single Channel");
+ this.plotter = this.plotterFactory.create("Single Channel");
+ this.pstyle = this.createDefaultStyle();
+ this.plotter.setTitle("");
+ this.plotter.createRegions(2, 2);
+
+ // Define the first plot region.
+ this.pstyle.xAxisStyle().setLabel(HIT_ENERGY_TITLE);
+ this.pstyle.yAxisStyle().setLabel(NO_TITLE);
+ this.plotter.region(0).plot(this.channelEnergyPlot.get(0), this.pstyle);
+
+ // Define the second plot region.
+ this.pstyle.xAxisStyle().setLabel(HIT_TIME_TITLE);
+ this.pstyle.yAxisStyle().setLabel(NO_TITLE);
+ this.plotter.region(1).plot(this.channelTimePlot.get(0), this.pstyle);
+
+ // Define the third plot region; this encompasses the time vs.
+ // energy plots.
+ this.pstyle.xAxisStyle().setLabel(HIT_TIME_TITLE);
+ this.pstyle.yAxisStyle().setLabel(HIT_ENERGY_TITLE);
+ this.plotter.region(2).plot(this.channelTimeVsEnergyPlot.get(0), this.pstyle);
+
+ // Define the fourth plot region; this encompasses the cluster
+ // energy for each channel.
+ this.pstyle.xAxisStyle().setLabel(CLUSTER_ENERGY_TITLE);
+ this.pstyle.yAxisStyle().setLabel(NO_TITLE);
+ this.plotter.region(3).plot(this.clusterEnergyPlot.get(0), this.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.
+ this.plotter.show();
+
+ // Set the time tracker variables.
+ this.lastEventTime = 0;
+ }
+
+ /**
+ * Hides the single event display and disposes it from memory. Also removes histograms from aida tree. We do not
+ * want them in the output aida file, if any..
+ */
+ @Override
+ public void endOfData() {
+ // Disposing of event display window needs to happen on the Swing EDT.
+ SwingUtilities.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ System.out.println("turning ECAL event display off");
+ EcalEventDisplay.this.viewer.setVisible(false);
+ System.out.println("disposing ECAL event display ...");
+ EcalEventDisplay.this.viewer.dispose();
+ System.out.println("done disposing ECAL event display");
+ }
+ });
+ // Comment this out for now. It is causing problems. --JM
+ /*
+ * int row,column; String hName; //System.out.println("EcalEventDisplay endOfData clear histograms"); 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. row =
+ * EcalMonitoringUtilities.getRowFromHistoID(ii); column = EcalMonitoringUtilities.getColumnFromHistoID(ii);
+ * hName=detectorName + " : " + inputCollection + " : Hit Energy : " + column + " " + row + ": " + ii;
+ * aida.tree().rm(hName); hName=detectorName + " : " + inputCollection + " : Hit Time : " + column + " " + row +
+ * ": " + ii; aida.tree().rm(hName); hName=detectorName+ " : " + inputCollection + " : Hit Time Vs Energy : " +
+ * column + " " + row + ": " + ii; aida.tree().rm(hName); if (isFirstRaw[ii]==false){ hName=detectorName+ " : "
+ * + inputCollectionRaw + " : Raw Waveform : " + column + " " + row + ": " + ii; aida.tree().rm(hName); } }
+ */
+ // System.out.println("EcalEventDisplay endOfData clear histograms done");
+ }
+
+ @Override
+ public void process(final EventHeader event) {
+ // Check whether enough time has passed to perform an update
+ // on the event display.
+ boolean update = false;
+ final long currentTime = System.currentTimeMillis() / 1000;
+ if (currentTime - this.lastEventTime > this.eventRefreshRate) {
+ this.lastEventTime = currentTime;
+ update = true;
+ }
+
+ // If an update should be made, perform the update.
+ if (update && this.resetOnUpdate) {
+ this.viewer.resetDisplay();
+ }
+
+ // If the event has calorimeter hit objects...
+ if (event.hasCollection(CalorimeterHit.class, this.inputCollection)) {
+ // Get the list of calorimeter hits.
+ final List<CalorimeterHit> hits = event.get(CalorimeterHit.class, this.inputCollection);
+
+ // For each of the calorimeter hits...
+ for (final CalorimeterHit hit : hits) {
+ // Get the x and y indices for the current hit.
+ final int ix = hit.getIdentifierFieldValue("ix");
+ final int iy = hit.getIdentifierFieldValue("iy");
+
+ if (iy != 0 && ix != 0) {
+ // Get the histogram index for the hit.
+ final int id = EcalMonitoringUtilities.getHistoIDFromRowColumn(iy, ix);
+
+ // If the hit has energy, populate the plots.
+ if (hit.getCorrectedEnergy() > 0) {
+ this.channelEnergyPlot.get(id).fill(hit.getCorrectedEnergy());
+ this.channelTimePlot.get(id).fill(hit.getTime());
+ this.channelTimeVsEnergyPlot.get(id).fill(hit.getTime(), hit.getCorrectedEnergy());
+ }
+
+ // If an update to the event display should be
+ // performed, give it the hits.
+ if (update) {
+ this.viewer.addHit(hit);
+ }
+ }
+ }
+ }
+
+ // If there are clusters in the event...
+ if (event.hasCollection(Cluster.class, this.clusterCollection)) {
+ // Get the list of clusters.
+ final List<Cluster> clusters = event.get(Cluster.class, this.clusterCollection);
+
+ // Iterate over the clusters and add them to the event
+ // display if appropriate.
+ for (final Cluster cluster : clusters) {
+ // Get the ix and iy indices for the seed.
+ final int ix = cluster.getCalorimeterHits().get(0).getIdentifierFieldValue("ix");
+ final int iy = cluster.getCalorimeterHits().get(0).getIdentifierFieldValue("iy");
+
+ // Get the histogram index for the hit.
+ final int id = EcalMonitoringUtilities.getHistoIDFromRowColumn(iy, ix);
+
+ // Add the cluster energy to the plot.
+ if (cluster.getEnergy() > 0.0) {
+ this.clusterEnergyPlot.get(id).fill(cluster.getEnergy());
+ }
+
+ // If an update is needed, add the cluster to the viewer.
+ if (update) {
+ this.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) {
+ this.viewer.updateDisplay();
+ }
+ }
+
+ /**
+ * 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(final int eventRefreshRate) {
+ this.eventRefreshRate = eventRefreshRate;
+ }
+
+ /**
+ * Sets the LCIO collection name for calorimeter clusters.
+ *
+ * @param inputClusterCollection - The LCIO collection name.
+ */
+ public void setInputClusterCollection(final String inputClusterCollection) {
+ this.clusterCollection = inputClusterCollection;
+ }
+
+ /**
+ * Sets the LCIO collection name for the processed calorimeter hits.
+ *
+ * @param inputCollection - The LCIO collection name.
+ */
+ public void setInputCollection(final String inputCollection) {
+ this.inputCollection = inputCollection;
+ }
+
+ /**
+ * Sets the LCIO collection name for the raw waveform hits.
+ *
+ * @param inputCollectionRaw - The LCIO collection name.
+ */
+ public void setInputCollectionRaw(final String inputCollectionRaw) {
+ this.inputCollectionRaw = inputCollectionRaw;
+ }
+
+ /**
+ * 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(final 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(final double minEch) {
+ this.minEch = minEch;
+ }
+
+ public void setPedSamples(final int pedSamples) {
+ this.pedSamples = pedSamples;
+ }
+
+ /**
+ * 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(final boolean resetOnUpdate) {
+ this.resetOnUpdate = resetOnUpdate;
+ }
+
+ /**
+ * 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() {
+
+ // Set the viewer properties from the Driver configuration parameters.
+ this.viewer.setScaleMinimum(this.minEch);
+ this.viewer.setScaleMaximum(this.maxEch);
+ this.viewer.addCrystalListener(this);
+
+ // Make the Viewer object visible. Run on the Swing EDT.
+ SwingUtilities.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ EcalEventDisplay.this.viewer.setVisible(true);
+ }
+ });
+ }
}
|