Print

Print


Author: [log in to unmask]
Date: Fri Sep 30 11:50:32 2016
New Revision: 4505

Log:
Updated the EcalOnlineRawConverter to function with pre-readout Monte Carlo.

Modified:
    java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/EcalOnlineRawConverter.java
    java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/EcalOnlineRawConverterDriver.java

Modified: java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/EcalOnlineRawConverter.java
 =============================================================================
--- java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/EcalOnlineRawConverter.java	(original)
+++ java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/EcalOnlineRawConverter.java	Fri Sep 30 11:50:32 2016
@@ -1,31 +1,52 @@
 package org.hps.recon.ecal;
-
 
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.util.ArrayList;
+import java.util.List;
 
 import org.hps.record.daqconfig.ConfigurationManager;
 import org.hps.record.daqconfig.FADCConfig;
 import org.lcsim.event.CalorimeterHit;
-import org.lcsim.event.EventHeader;
 import org.lcsim.event.GenericObject;
 import org.lcsim.event.RawCalorimeterHit;
 import org.lcsim.event.RawTrackerHit;
 
 /**
+ * <code>EcalOnlineRawConverter</code> handles the conversion of raw
+ * hits of all modes to energy hit <code>CalorimeterHit</code> objects.
+ * This converter will employ the runtime values for all parameters and
+ * is intended to emulate the firmware specifically.<br/>
+ * <br/>
+ * The converter requires the presence of the DAQ configuration manager,
+ * which is activated by either <code>DatabaseDAQConfigDriver</code>
+ * or <code>DAQConfigDriver</code> depending on from where it is to
+ * obtain the configuration.<br/>
+ * <br/>
+ * This converter is primarily employed in the trigger and hardware
+ * diagnostic processes as well as the readout simulation in Monte
+ * Carlo.
  * 
- * This is a EcalRawConverter used only for pure firmware emulation for
- * studying trigger efficiency from real data.  It requires the DAQ
- * configuration to be read from EVIO in order to set the parameters.
- * 
+ * @author Nathan Baltzell <[log in to unmask]>
+ * @author Kyle McCarty <[log in to unmask]>
  */
 public class EcalOnlineRawConverter {
-
+    // Defines the maximum number of peaks that may be extracted from
+    // a single waveform.
+    private int nPeak = 3;
+    // The DAQ configuration manager for FADC parameters.
     private FADCConfig config = null;
+    // Whether or not a constant integration window should be assumed
+    // for the purpose of pedestal calculations/
+    private boolean constantWindow = false;
+    // The number of nanoseconds in a clock-cycle (sample).
     private static final int nsPerSample = 4;
-    private int nPeak = 3;
-    
+    
+    /**
+     * Instantiates the <code>EcalOnlineRawConverter</code> and connects
+     * it to the <code>ConfigurationManager</code> to receive settings
+     * from the DAQ configuration.
+     */
     public EcalOnlineRawConverter() {
         // Track changes in the DAQ configuration.
         ConfigurationManager.addActionListener(new ActionListener() {
@@ -33,174 +54,275 @@
             public void actionPerformed(ActionEvent e) {
                 // Get the FADC configuration.
                 config = ConfigurationManager.getInstance().getFADCConfig();
+                
                 // Get the number of peaks.
-                if(config.getMode() == 1) nPeak = Integer.MAX_VALUE;
-                else                      nPeak = config.getMaxPulses();
-                // Print the FADC configuration.
-                System.out.println();
-                System.out.println();
-                System.out.printf("NSA            :: %d ns%n", config.getNSA());
-                System.out.printf("NSB            :: %d ns%n", config.getNSB());
-                System.out.printf("Window Samples :: %d clock-cycles%n", config.getWindowWidth());
-                System.out.printf("Max Peaks      :: %d peaks%n", nPeak);
-                System.out.println("======================================================================");
-                System.out.println("=== FADC Pulse-Processing Settings ===================================");
-                System.out.println("======================================================================");
-                config.printConfig(System.out);
+                if(config.getMode() == 1) { nPeak = Integer.MAX_VALUE; }
+                else { nPeak = config.getMaxPulses(); }
             }
         });
     }
-
-    /**
-     * Get pedestal for entire pulse integral.  Account for clipping if
-     * windowSamples is greater than zero.
-     */
-    public double getPulsePedestal(EventHeader event,long cellID,int windowSamples,int thresholdCrossing) {
-        int firstSample,lastSample;
-        if ( windowSamples>0 && (config.getNSA()+config.getNSB())/nsPerSample >= windowSamples ) {
-            // special case where firmware always integrates entire window
+    
+    /**
+     * Gets the pedestal for a given crystal and threshold crossing.
+     * @param cellID - The cell ID of the crystal.
+     * @param windowSamples - The size of the readout window. A value
+     * of <code>-1</code> indicates an infinite readout window.
+     * @param thresholdCrossing - The time of the threshold crossing in
+     * 4-nanosecond clock-cycles (samples).
+     * @return Returns the pedestal for the crystal and threshold
+     * crossing.
+     */
+    public double getPulsePedestal(long cellID, int windowSamples, int thresholdCrossing) {
+        // Track the starting and ending samples over which integration
+        // will occur. Only the intermediary samples need be considered
+        // for pedestal calculation.
+        int firstSample, lastSample;
+        
+        // For finite readout windows, calculate the pedestal based on
+        // the size of the full readout window in the event that the
+        // integration window is larger than the readout window.
+        if(windowSamples > 0 && (config.getNSA() + config.getNSB()) / nsPerSample >= windowSamples) {
             firstSample = 0;
-            lastSample = windowSamples-1;
-        } else {
-            firstSample = thresholdCrossing - config.getNSB()/nsPerSample;
-            lastSample  = thresholdCrossing + config.getNSA()/nsPerSample-1;
-            if (windowSamples > 0) {
-                // properly pedestal subtract pulses clipped by edge(s) of readout window:
-                if (firstSample < 0) firstSample=0;
-                if (lastSample >= windowSamples) lastSample=windowSamples-1;
+            lastSample = windowSamples - 1;
+        }
+        
+        // Otherwise, the pedestal should be calculated based on the
+        // integration window size.
+        else {
+            // Define the sample width as equivalent to the integration
+            // window size.
+            firstSample = thresholdCrossing - config.getNSB() / nsPerSample;
+            lastSample  = thresholdCrossing + config.getNSA() / nsPerSample - 1;
+            
+            // In the event of a finite readout window, ignore any
+            // samples that fall outside the readout window. Since these
+            // are clipped and will not be integrated, these pedestals
+            // do not contribute.
+            if(windowSamples > 0) {
+                if(firstSample < 0) { firstSample = 0; }
+                if(lastSample >= windowSamples) { lastSample = windowSamples - 1; }
             }
         }
-        return (lastSample-firstSample+1)*config.getPedestal(cellID);
-    }
-   
+        
+        // Calculate and return the pedestal.
+        return(lastSample - firstSample + 1) * config.getPedestal(cellID);
+    }
+    
+    /**
+     * Converts a mode-1 digitized waveform into standard energy hit.
+     * @param hit - The "hit" object representing the digitized waveform
+     * for a given crystal.
+     * @return Returns a list of <code>CalorimeterHit</code> objects
+     * parsed from the waveform.
+     */
+    public List<CalorimeterHit> HitDtoA(RawTrackerHit hit) {
+        // Get the cell ID for the crystal as well as the digitized
+        // waveform samples.
+        final long cellID = hit.getCellID();
+        final short[] waveform = hit.getADCValues();
+        
+        // If there are no samples, then there is nothing to integrate.
+        if(waveform.length == 0) { return null; }
+        
+        // The pulse integration threshold is defined as the combination
+        // of the pedestal and the threshold configuration parameter.
+        final int absoluteThreshold = (int) (config.getPedestal(cellID) + config.getThreshold(cellID));
+        
+        // Store each instance of a threshold crossing in that can be
+        // found within the digitized waveform.
+        List<Integer> thresholdCrossings = new ArrayList<Integer>();
+        
+        // Check for the special case of the first sample exceeding
+        // the integration threshold.
+        if(waveform[0] > absoluteThreshold) {
+            thresholdCrossings.add(0);
+        } 
+        
+        // Search the remaining samples for threshold crossings.
+        thresholdLoop:
+        for(int sample = 1; sample < waveform.length; ++sample) {
+            if(waveform[sample] > absoluteThreshold && waveform[sample - 1] <= absoluteThreshold) {
+                // Add the sample index to the list of threshold crossing.
+                thresholdCrossings.add(sample);
+                
+                // No new threshold crossings can be registered within
+                // this pulse. In the case of mode-1 data, the end of
+                // the pulse is considered to be 8 samples past the
+                // crossing, as the per the SSP. Otherwise, it is defined
+                // by the integration window.
+                if(config.getMode() == 1) { sample += 8; }
+                else { sample += config.getNSA() / nsPerSample - 1; }
+                
+                // If there is a limit defined on the maximum number
+                // of peaks that may be processed, terminate the search
+                // after this number of peaks have been found.
+                if(thresholdCrossings.size() >= nPeak) { break thresholdLoop; }
+            }
+        }
+        
+        // Use the previously located threshold crossing to generate
+        // calorimeter hits.
+        List<CalorimeterHit> newHits = new ArrayList<CalorimeterHit>();
+        for(int thresholdCrossing : thresholdCrossings) {
+            // Perform the pulse integral.
+            final double[] data = convertWaveformToPulse(waveform, thresholdCrossing);
+            double time = data[0];
+            double sum = data[1];
+            
+            // Perform pedestal subtraction.
+            sum -= getPulsePedestal(cellID, waveform.length, thresholdCrossing);
+          
+            // Perform gain scaling.
+            double energy = adcToEnergy(sum, cellID);
+            
+            // Create a new hit and add it to the list.
+            newHits.add(CalorimeterHitUtilities.create(energy, time, cellID));
+        }
+        
+        // Return the list of hits.
+        return newHits;
+    }
+    
+    /**
+     * Converts a raw mode-3 hit to a proper calorimeter hit in units
+     * of energy.
+     * @param hit - The raw hit that is to be converted.
+     * @param timeOffset - The time offset for the hit.
+     * @return Returns a <code>CalorimeterHit</code> hit object that
+     * represents the raw mode-3 hit with units of energy and a correct
+     * time-stamp.
+     */
+    public CalorimeterHit HitDtoA(RawCalorimeterHit hit, double timeOffset) {
+        // Verify the validity of the time-stamp.
+        if(hit.getTimeStamp() % 64 != 0) {
+            System.out.println("Unexpected time-stamp: " + hit.getTimeStamp());
+        }
+        
+        // Get the pedestal. In the case of a constant integration window
+        // (i.e. infinite readout window size, so no risk of clipping),
+        // the window width should be given as -1. Otherwise, the real
+        // readout window size should be used.
+        long id = hit.getCellID();
+        double time = hit.getTimeStamp() / 16.0;
+        double pedestal = getPulsePedestal(id, constantWindow ? -1 : config.getWindowWidth(), (int) time / nsPerSample);
+        
+        // Calculate the total ADC value for the pulse and convert it
+        // to energy.
+        double adcSum = hit.getAmplitude() - pedestal;
+        double rawEnergy = adcToEnergy(adcSum, id);
+        
+        // Create a calorimeter hit from the result and return it.
+        return CalorimeterHitUtilities.create(rawEnergy, time + timeOffset, id);
+    }
+    
+    /**
+     * Converts a raw mode-7 hit to a proper calorimeter hit in units
+     * of energy.
+     * @param hit - The raw hit that is to be converted.
+     * @param mode7Data - Additional mode-7 data object.
+     * @param timeOffset - The time offset for the hit.
+     * @return Returns a <code>CalorimeterHit</code> hit object that
+     * represents the raw mode-7 hit with units of energy and a correct
+     * time-stamp.
+     */
+    public CalorimeterHit HitDtoA(RawCalorimeterHit hit, GenericObject mode7Data, double timeOffset) {
+        // Get the time and crystal cell ID for the hit. Note that the
+        // time-stamps use the full 62.5 ps resolution.
+        double time = hit.getTimeStamp() / 16.0;
+        long id = hit.getCellID();
+        
+        // Get the pedestal. In the case of a constant integration window
+        // (i.e. infinite readout window size, so no risk of clipping),
+        // the window width should be given as -1. Otherwise, the real
+        // readout window size should be used.
+        double pedestal = getPulsePedestal(id, constantWindow ? -1 : config.getWindowWidth(), (int) time / nsPerSample);
+        
+        // Calculate the total ADC value for the pulse and convert it
+        // to energy.
+        double adcSum = hit.getAmplitude() - pedestal;
+        double rawEnergy = adcToEnergy(adcSum, id);
+        
+        // Create a calorimeter hit from the result and return it.
+        return CalorimeterHitUtilities.create(rawEnergy, time + timeOffset, id);
+    }
+    
+    /**
+     * Converts a value in ADC in a crystal to energy in units of GeV.
+     * @param adcSum - The ADC value to convert.
+     * @param cellID - The cell ID of the crystal containing the value.
+     * @return Returns the ADC value as an energy in units of GeV.
+     */
+    private double adcToEnergy(double adcSum, long cellID) {
+        return config.getGain(cellID) * adcSum * EcalUtils.MeV;
+    }
     
     /**
      * Emulate the FADC250 firmware in conversion of Mode-1 waveform to a Mode-3/7 pulse,
      * given a time for threshold crossing.
      */
-    public double[] convertWaveformToPulse(RawTrackerHit hit,int thresholdCrossing,boolean mode7) {
-       
-        short samples[] = hit.getADCValues();
-        // choose integration range:
-        int firstSample,lastSample;
-        if ((config.getNSA()+config.getNSB())/nsPerSample >= samples.length) {
-            // firmware treats this case specially:
+    
+    /**
+     * Converts a mode-1 digitized waveform to a mode-3/7 pulse for a
+     * a given threshold crossing.
+     * @param waveform - The digitized waveform. Each array value should
+     * correspond to a sample of the waveform in units of ADC.
+     * @param thresholdCrossing - The time of the threshold crossing
+     * in samples.
+     * @return Returns a <code>double</code> primitive of size 2. The
+     * first value represents the time in nanoseconds of the pulser and
+     * the second value the total integrated value of the pulse in ADC.
+     */
+    private double[] convertWaveformToPulse(short[] waveform, int thresholdCrossing) {
+        // Store the integration range.
+        int firstSample, lastSample;
+        
+        // If the integration range is larger than the number of samples,
+        // then all the samples are used for pulse integration.
+        if((config.getNSA() + config.getNSB()) / nsPerSample >= waveform.length) {
             firstSample = 0;
-            lastSample = samples.length-1;
-        } else {
-            firstSample = thresholdCrossing - config.getNSB()/nsPerSample;
-            lastSample  = thresholdCrossing + config.getNSA()/nsPerSample - 1;
-        }
-        
-        // pulse integral:
+            lastSample = waveform.length - 1;
+        }
+        
+        // Otherwise, the integration range covers a number of samples
+        // before and after the threshold crossing as defined by the
+        // run parameters.
+        else {
+            firstSample = thresholdCrossing - config.getNSB() / nsPerSample;
+            lastSample  = thresholdCrossing + config.getNSA() / nsPerSample - 1;
+        }
+        
+        // Perform the pulse integral.
         double sumADC = 0;
-        for (int jj=firstSample; jj<=lastSample; jj++) {
-            if (jj<0) continue;
-            if (jj>=samples.length) break;
-            sumADC += samples[jj];
-        }
-
-        // pulse time with 4ns resolution:
-        double pulseTime=thresholdCrossing*nsPerSample;
-        return new double []{pulseTime,sumADC};
-    }
-   
-    
-    /**
-     *
-     */
-    public ArrayList <CalorimeterHit> HitDtoA(EventHeader event, RawTrackerHit hit) {
-        final long cellID = hit.getCellID();
-        final short samples[] = hit.getADCValues();
-        if(samples.length == 0) return null;
-        
-        // threshold is pedestal plus threshold configuration parameter:
-        final int absoluteThreshold;
-        int leadingEdgeThreshold = config.getThreshold(cellID);
-        absoluteThreshold = (int) (config.getPedestal(cellID) + leadingEdgeThreshold);
-        
-        ArrayList <Integer> thresholdCrossings = new ArrayList<Integer>();
-        
-        // special case, first sample is above threshold:
-        if (samples[0] > absoluteThreshold) {
-            thresholdCrossings.add(0);
-        } 
-        
-        // search for threshold crossings:
-        for(int ii = 1; ii < samples.length; ++ii) {
-            if ( samples[ii]   >  absoluteThreshold && 
-                 samples[ii-1] <= absoluteThreshold) {
-                
-                // found one:
-                thresholdCrossings.add(ii);
-
-                // search for next threshold crossing begins at end of this pulse:
-                if (ConfigurationManager.getInstance().getFADCConfig().getMode() == 1) {
-                    // special case, emulating SSP:
-                    ii += 8;
-                } else {
-                    // "normal" case, emulating FADC250:
-                    ii += config.getNSA()/nsPerSample - 1;
-                }
-
-                // firmware limit on # of peaks:
-                if (thresholdCrossings.size() >= nPeak) break;
-            }
-        }
-        
-        // make hits
-        ArrayList <CalorimeterHit> newHits = new ArrayList<CalorimeterHit>();
-        for(int thresholdCrossing : thresholdCrossings) {
-            // do pulse integral:
-            final double[] data = convertWaveformToPulse(hit, thresholdCrossing, false);
-            double time = data[0];
-            double sum = data[1];
-            
-            // do pedestal subtraction:
-            sum -= getPulsePedestal(event, cellID, samples.length, thresholdCrossing);
-          
-            // do gain scaling:
-            double energy = adcToEnergy(sum, cellID);
-            
-            newHits.add(CalorimeterHitUtilities.create(energy,time,cellID));
-        }
-        
-        return newHits;
-    }
-
-    /**
-     * This HitDtoA is for Mode-3 data.
-     */
-    public CalorimeterHit HitDtoA(EventHeader event,RawCalorimeterHit hit, double timeOffset) {
-        if (hit.getTimeStamp() % 64 != 0) {
-            System.out.println("unexpected timestamp " + hit.getTimeStamp());
-        }
-        double time = hit.getTimeStamp() / 16.0;
-        long id = hit.getCellID();
-        double pedestal = getPulsePedestal(event,id,config.getWindowWidth(),(int)time/nsPerSample);
-        double adcSum = hit.getAmplitude() - pedestal;
-        double rawEnergy = adcToEnergy(adcSum, id);
-        return CalorimeterHitUtilities.create(rawEnergy, time + timeOffset, id);
-    }
-
-    /**
-     * This HitDtoA is exclusively for Mode-7 data, hence the GenericObject parameter.
-     */
-    public CalorimeterHit HitDtoA(EventHeader event,RawCalorimeterHit hit, GenericObject mode7Data, double timeOffset) {
-        double time = hit.getTimeStamp() / 16.0; //timestamps use the full 62.5 ps resolution
-        long id = hit.getCellID();
-        double pedestal = getPulsePedestal(event,id,config.getWindowWidth(),(int)time/nsPerSample);
-        double adcSum = hit.getAmplitude() - pedestal;
-        double rawEnergy = adcToEnergy(adcSum, id);       
-        return CalorimeterHitUtilities.create(rawEnergy, time + timeOffset, id);
-    }
-
-
-    /**
-     * return energy (units of GeV) corresponding to the ADC sum and crystal ID
-     */
-    private double adcToEnergy(double adcSum, long cellID) {
-        return config.getGain(cellID) * adcSum * EcalUtils.MeV;
-    }
-
-}
+        integrationLoop:
+        for (int sample = firstSample; sample <= lastSample; sample++) {
+            // If the current sample occurs before the readout window,
+            // then it does not exist and can not be integrated. Skip it.
+            if(sample < 0) { continue integrationLoop; }
+            
+            // Likewise, samples that occur after the readout window are
+            // not retained and must be skipped.
+            if(sample >= waveform.length) { break integrationLoop; }
+            
+            // Otherwise, add the sample to the pulse total.
+            sumADC += waveform[sample];
+        }
+        
+        // Calculate the pulse time with a 4 nanosecond resolution.
+        double pulseTime = thresholdCrossing * nsPerSample;
+        
+        // Return both the pulse time and the total integrated pulse ADC.
+        return new double [] { pulseTime, sumADC };
+    }
+    
+    /**
+     * Sets whether to use a constant integration window for the the
+     * purpose of determining the correct pedestal. This should be used
+     * in conjunction with Monte Carlo data during the readout cycle.
+     * @param state - <code>true</code> ignores the size of the readout
+     * window when calculating pedestals, and <code>false</code> accounts
+     * for it in the case of pulse-clipping.
+     */
+    void setUseConstantWindow(boolean state) {
+        constantWindow = state;
+    }
+}

Modified: java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/EcalOnlineRawConverterDriver.java
 =============================================================================
--- java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/EcalOnlineRawConverterDriver.java	(original)
+++ java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/EcalOnlineRawConverterDriver.java	Fri Sep 30 11:50:32 2016
@@ -23,119 +23,138 @@
  *
 */
 public class EcalOnlineRawConverterDriver extends Driver {
-
     private EcalOnlineRawConverter converter = null;
     /**
-     * Input collection name
-     * Can be a {@link org.lcsim.event.RawTrackerHit} or {@link org.lcsim.event.RawCalorimeterHit}
-     * These have ADC and sample time information.
+     * The input LCIO collection name. This can be either a
+     * {@link org.lcsim.event.RawTrackerHit} or
+     * {@link org.lcsim.event.RawCalorimeterHit}. These have ADC and
+     * sample time information.
      */
     private String rawCollectionName = "EcalReadoutHits";
     
     /**
-     * Output collection name
-     * Always a {@link org.lcsim.event.CalorimeterHit}
-     * This has energy (GeV) and ns time information.
+     * The output LCIO collection name. This will always a
+     * {@link org.lcsim.event.CalorimeterHit} with energy (GeV) and
+     * ns time information.
      */
     private String ecalCollectionName = "EcalCalHits";
-
+    
     /**
      * ecalCollectionName "type" (must match detector-data) 
      */
     private final String ecalReadoutName = "EcalHits";
-
-    /*
-     * Output relation between ecalCollectionName and Mode-7 pedestals
+    
+    /**
+     * Output relation between ecalCollectionName and Mode-7 pedestals.
      */
     private static final String extraDataRelationsName = "EcalReadoutExtraDataRelations";
-
-    public EcalOnlineRawConverterDriver() {
-        converter = new EcalOnlineRawConverter();
-    }
-
+    
     /**
-     * Set the output {@link org.lcsim.event.CalorimeterHit} collection name,
-     * 
-     * @param ecalCollectionName The <code>CalorimeterHit</code> collection name.
+     * Instantiates the <code>EcalOnlineRawConverter</code> for this
+     * driver.
      */
-    public void setEcalCollectionName(String ecalCollectionName) {
-        this.ecalCollectionName = ecalCollectionName;
-    }
-
+    public EcalOnlineRawConverterDriver() { converter = new EcalOnlineRawConverter(); }
+    
     /**
-     * Set the input raw collection name
-     * <p>
-     * Depending on the Driver configuration, this could be a collection
-     * of {@link org.lcsim.event.RawTrackerHit} objects for Mode-1
-     * or {@link org.lcsim.event.RawCalorimeterHit} objects for Mode-3
-     * or Mode-7.
-     * 
-     * @param rawCollectionName The raw collection name.
+     * Checks that the required LCIO collection names are defined.
      */
-    public void setRawCollectionName(String rawCollectionName) {
-        this.rawCollectionName = rawCollectionName;
-    }
-
     @Override
     public void startOfData() {
-        if (ecalCollectionName == null) {
+        if(ecalCollectionName == null) {
             throw new RuntimeException("The parameter ecalCollectionName was not set!");
         }
     }
-
+    
     @Override
     public void process(EventHeader event) {
-        // Do not process the event if the DAQ configuration should be
-        // used for value, but is not initialized.
+        // Do not process the event if the DAQ configuration is not
+        // initialized. All online raw converter parameters are obtained
+        // from this class, and this nothing can be done before they
+        // are available.
         if(!ConfigurationManager.isInitialized()) {
             return;
         }
         
         double timeOffset = 0.0;
+        
+        // Define the LCIO data flags.
         int flags = 0;
-        flags += 1 << LCIOConstants.RCHBIT_TIME; //store hit time
-        flags += 1 << LCIOConstants.RCHBIT_LONG; //store hit position; this flag has no effect for RawCalorimeterHits
-
+        flags += 1 << LCIOConstants.RCHBIT_TIME; // Store hit time.
+        flags += 1 << LCIOConstants.RCHBIT_LONG; // Store hit position; this flag has no effect for RawCalorimeterHits.
+        
+        // Create a list to store hits.
         ArrayList<CalorimeterHit> newHits = new ArrayList<CalorimeterHit>();
-
-        /*
-         * This is for FADC Mode-1 data:    
-         */
-        if (event.hasCollection(RawTrackerHit.class, rawCollectionName)) {
+        
+        // Events that contain RawTrackerHit objects use mode-1 data.
+        if(event.hasCollection(RawTrackerHit.class, rawCollectionName)) {
+            // Get the list of mode-1 waveforms.
             List<RawTrackerHit> hits = event.get(RawTrackerHit.class, rawCollectionName);
-
-            for (RawTrackerHit hit : hits) {
-                newHits.addAll(converter.HitDtoA(event,hit));
+            
+            // Extract hits from each waveform and store them.
+            for(RawTrackerHit hit : hits) {
+                newHits.addAll(converter.HitDtoA(hit));
             }
+            
+            // Add the hits to the data stream.
             event.put(ecalCollectionName, newHits, CalorimeterHit.class, flags, ecalReadoutName);
         }
-
-        /*
-         * This is for FADC pulse mode data (Mode-3 or Mode-7):
-         */
-        if (event.hasCollection(RawCalorimeterHit.class, rawCollectionName)) { 
-
-            /*
-             * This is for FADC Mode-7 data:
-             */
-            if (event.hasCollection(LCRelation.class, extraDataRelationsName)) { // extra information available from mode 7 readout
+        
+        // Events that contain RawCalorimeterHit objects are either
+        // mode-3 or mode-7.
+        if(event.hasCollection(RawCalorimeterHit.class, rawCollectionName)) {
+            // Check for extra relations data. This indicates that the
+            // hits should be interpreted as mode-7.
+            if(event.hasCollection(LCRelation.class, extraDataRelationsName)) { // extra information available from mode 7 readout
                 List<LCRelation> extraDataRelations = event.get(LCRelation.class, extraDataRelationsName);
-                for (LCRelation rel : extraDataRelations) {
+                for(LCRelation rel : extraDataRelations) {
                     RawCalorimeterHit hit = (RawCalorimeterHit) rel.getFrom();
                     GenericObject extraData = (GenericObject) rel.getTo();
-                    newHits.add(converter.HitDtoA(event,hit, extraData, timeOffset));
+                    newHits.add(converter.HitDtoA(hit, extraData, timeOffset));
                 }
-            } else {
-                /*
-                 * This is for FADC Mode-3 data:
-                 */
+            }
+            
+            // Otherwise, the hits should be treated as mode-3.
+            else {
                 List<RawCalorimeterHit> hits = event.get(RawCalorimeterHit.class, rawCollectionName);
-                for (RawCalorimeterHit hit : hits) {
-                    newHits.add(converter.HitDtoA(event, hit, timeOffset));
+                for(RawCalorimeterHit hit : hits) {
+                    newHits.add(converter.HitDtoA(hit, timeOffset));
                 }
             }
             event.put(ecalCollectionName, newHits, CalorimeterHit.class, flags, ecalReadoutName);
         }
     }
-
-}
+    
+    /**
+     * Sets the output {@link org.lcsim.event.CalorimeterHit} LCIO
+     * collection name.
+     * @param ecalCollectionName - The LCIO collection name for output
+     * data.
+     */
+    public void setEcalCollectionName(String ecalCollectionName) {
+        this.ecalCollectionName = ecalCollectionName;
+    }
+    
+    /**
+     * Sets whether to use a constant integration window for the the
+     * purpose of determining the correct pedestal. This should be used
+     * in conjunction with Monte Carlo data during the readout cycle.
+     * @param state - <code>true</code> ignores the size of the readout
+     * window when calculating pedestals, and <code>false</code> accounts
+     * for it in the case of pulse-clipping.
+     */
+    public void setIsReadoutSimulation(boolean state) {
+        converter.setUseConstantWindow(state);
+    }
+    
+    /**
+     * Sets the input raw hit data LCIO collection name. Depending on
+     * the driver configuration, this could be either a collection of
+     * {@link org.lcsim.event.RawTrackerHit} objects for mode-1 data or
+     * {@link org.lcsim.event.RawCalorimeterHit} objects for mode-3
+     * and mode-7 data.
+     * @param rawCollectionName - The LCIO collection name for raw data.
+     */
+    public void setRawCollectionName(String rawCollectionName) {
+        this.rawCollectionName = rawCollectionName;
+    }
+}