Print

Print


Author: [log in to unmask]
Date: Tue Nov 25 20:26:14 2014
New Revision: 1596

Log:
Add optional output file for generated calibration data.  Make fit optional and if disabled use the histogram's mean and sigma instead.  Minor refactoring of code into separate methods.

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

Modified: java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/EcalCalibrationsDriver.java
 =============================================================================
--- java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/EcalCalibrationsDriver.java	(original)
+++ java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/EcalCalibrationsDriver.java	Tue Nov 25 20:26:14 2014
@@ -7,10 +7,12 @@
 import hep.aida.IFunctionFactory;
 import hep.aida.IHistogram1D;
 
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
 import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Date;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -34,6 +36,10 @@
  * This Driver will generate a {@link org.hps.conditions.EcalCalibration} collection
  * from the ADC value distributions of raw ECAL data.  It may optionally insert this
  * information into the conditions database using the file's run number.
+ * 
+ * Currently, it uses every ADC value for the distribution, but filtering should probably
+ * be added to exclude hits above a certain threshold.
+ * 
  * @author Jeremy McCormick <[log in to unmask]>
  */
 public class EcalCalibrationsDriver extends Driver {
@@ -41,21 +47,58 @@
     EcalConditions ecalConditions = null;
     DatabaseConditionsManager conditionsManager = null;
     AIDA aida = AIDA.defaultInstance();
+    IFunctionFactory functionFactory = aida.analysisFactory().createFunctionFactory(null);
+    IFitFactory fitFactory = aida.analysisFactory().createFitFactory();
     boolean loadCalibrations = false;
+    boolean performFit = true;
+    File outputFile = null;
     Set<Integer> runs = new HashSet<Integer>();
     
+    /**
+     * Set whether to automatically load the conditions into the database.
+     * @param loadCalibrations True to load conditions into the database.
+     */
     public void setLoadCalibrations(boolean loadCalibrations) {
         this.loadCalibrations = loadCalibrations;
     }
     
-    public void detectorChanged(Detector detector) {
+    /**
+     * Set whether to perform a function fit to get the mean and sigma values.
+     * @param performFit True to perform a function fit of the histogram.
+     */
+    public void setPerformFit(boolean performFit) {
+        this.performFit = performFit;
+    }
+    
+    /**
+     * Set an output file path for writing the calibration data.  
+     * @param outputFileName The path to the output file.
+     */
+    public void setOutputFileName(String outputFileName) {
+        if (outputFileName == null) {
+            throw new IllegalArgumentException("The outputFileName argument is null.");
+        }
+        outputFile = new File(outputFileName);
+    }
+        
+    /**
+     * Initialize this Driver when conditions change is triggered.
+     */
+    @Override
+    public void detectorChanged(Detector detector) {        
         conditionsManager = DatabaseConditionsManager.getInstance();
         ecalConditions = conditionsManager.getCachedConditions(EcalConditions.class, TableConstants.ECAL_CONDITIONS).getCachedData();
+        
+        // Create a histogram for every ECAL channel.
         for (EcalChannel channel : ecalConditions.getChannelCollection().getObjects()) {
             aida.histogram1D("ECAL Channel " + channel.getChannelId(), 300, 0, 300.);
         }
     }
     
+    /**
+     * Process the event data, filling the channel histograms from the ADC values.
+     */
+    @Override
     public void process(EventHeader event) {
         runs.add(event.getRunNumber());
         if (event.hasCollection(RawTrackerHit.class, "EcalReadoutHits")) {
@@ -72,6 +115,11 @@
         }
     }
     
+    /**
+     * End of data hook, which will get the mean and sigma for the ADC distributions.
+     * It may optionally write these to a file and push the values into the database.
+     */
+    @Override
     public void endOfData() {
         
         if (runs.size() == 0) {
@@ -79,29 +127,35 @@
         }
         List<Integer> runList = new ArrayList<Integer>(runs);
         Collections.sort(runList);
-        
-        IFunctionFactory functionFactory = aida.analysisFactory().createFunctionFactory(null);
-        IFitFactory fitFactory = aida.analysisFactory().createFitFactory();
-        
+                
         EcalCalibrationCollection calibrations = new EcalCalibrationCollection();
         TableMetaData tableMetaData = conditionsManager.findTableMetaData(TableConstants.ECAL_CALIBRATIONS);
         calibrations.setTableMetaData(tableMetaData);
         
+        // Loop over all ECAL channels.
         for (EcalChannel channel : ecalConditions.getChannelCollection().getObjects()) {
+            
+            // Get the histogram with ADC distribution for this channel. 
             IHistogram1D histogram = aida.histogram1D("ECAL Channel " + channel.getChannelId());
                                  
-            IFunction function = functionFactory.createFunctionByName("Gaussian", "G");        
-            IFitter fitter = fitFactory.createFitter("chi2", "jminuit");
-            double[] parameters = new double[3];
-            parameters[0] = histogram.maxBinHeight();
-            parameters[1] = histogram.mean();
-            parameters[2] = histogram.rms();
-            function.setParameters(parameters);
-            IFitResult fitResult = fitter.fit(histogram, function);
             int channelId = channel.getChannelId();
-                        
-            double mean = fitResult.fittedParameter("mean");
-            double sigma = fitResult.fittedParameter("sigma");
+            
+            double mean = 0;
+            double sigma = 0;
+            
+            if (performFit) {
+                // Perform a Gaussian fit and use its mean and sigma.
+                IFitResult fitResult = doGaussianFit(histogram);
+                mean = fitResult.fittedParameter("mean");
+                sigma = fitResult.fittedParameter("sigma");
+            } else {
+                // Use the histogram's statistics for mean and sigma. 
+                mean = histogram.mean();
+                sigma = histogram.rms();
+            }
+            
+            // Create a new calibration object and add it to the collection, using mean for pedestal
+            // and sigma for noise.
             EcalCalibration calibration = new EcalCalibration(channelId, mean, sigma);
             try {
                 calibrations.add(calibration);
@@ -109,27 +163,96 @@
                 throw new RuntimeException(e);
             }
         } 
-        System.out.println(calibrations.toString());
+        
+        // Get the list of field names for the header.
+        StringBuffer buffer = new StringBuffer();
+        for (String fieldName : tableMetaData.getFieldNames()) {
+            buffer.append(fieldName + " ");
+        }
+        buffer.setLength(buffer.length() - 1);
+        String fieldNames = buffer.toString();
+        
+        // Is there an output file for the calibration data?
+        if (outputFile != null) {
+            // Write the calibration data to an output text file.
+            writeToFile(calibrations, fieldNames);
+        } else {
+            // Just print out the information to the console.
+            System.out.println(fieldNames);
+            System.out.println(calibrations.toString());
+        }
+        
+        // Load the calibrations into the conditions database?
         if (loadCalibrations) {
-            int collectionId = conditionsManager.getNextCollectionID(TableConstants.ECAL_CALIBRATIONS);
-            try {
-                calibrations.setCollectionId(collectionId);
-                calibrations.insert();
-                int runStart = runList.get(0);
-                int runEnd = runList.get(runList.size() - 1);
-                ConditionsRecord conditionsRecord = new ConditionsRecord(
-                        calibrations.getCollectionId(), 
-                        runStart, 
-                        runEnd, 
-                        TableConstants.ECAL_CALIBRATIONS,
-                        TableConstants.ECAL_CALIBRATIONS, 
-                        "Auto generated by EcalCalibrationsDriver.", 
-                        "eng_run");
-                conditionsRecord.setTableMetaData(conditionsManager.findTableMetaData(TableConstants.CONDITIONS_RECORD));
-                conditionsRecord.insert();
-            } catch (ConditionsObjectException | SQLException e) {
-                throw new RuntimeException(e);
-            }
-        }
+            loadCalibrations(runList, calibrations);
+        }
+    }
+
+    /**
+     * Write the calibration data to an output file.
+     * @param calibrations The calibration data which is record delimited by new lines.
+     * @param fieldNames The list of field names as a single string.
+     */
+    private void writeToFile(EcalCalibrationCollection calibrations, String fieldNames) {
+        FileWriter writer = null;
+        try {
+            writer = new FileWriter(outputFile);
+            writer.write(fieldNames);
+            writer.write(calibrations.toString());
+        } catch (IOException e) {
+            throw new RuntimeException("There was a problem writing to the output file.", e);
+        } finally {
+            if (writer != null) {
+                try {
+                    writer.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+    /**
+     * Load the calibration data into the conditions database.
+     * @param runList The list of runs processed in the job.
+     * @param calibrations The collection of calibration objects.
+     */
+    private void loadCalibrations(List<Integer> runList, EcalCalibrationCollection calibrations) {
+        int collectionId = conditionsManager.getNextCollectionID(TableConstants.ECAL_CALIBRATIONS);
+        try {
+            calibrations.setCollectionId(collectionId);
+            calibrations.insert();
+            int runStart = runList.get(0);
+            int runEnd = runList.get(runList.size() - 1);
+            ConditionsRecord conditionsRecord = new ConditionsRecord(
+                    calibrations.getCollectionId(), 
+                    runStart, 
+                    runEnd, 
+                    TableConstants.ECAL_CALIBRATIONS,
+                    TableConstants.ECAL_CALIBRATIONS, 
+                    "Auto generated by EcalCalibrationsDriver.", 
+                    "eng_run");
+            conditionsRecord.setTableMetaData(conditionsManager.findTableMetaData(TableConstants.CONDITIONS_RECORD));
+            conditionsRecord.insert();
+        } catch (ConditionsObjectException | SQLException e) {
+            throw new RuntimeException(e);
+        }
+    }
+    
+    /**
+     * Do a Gaussian fit to calculate the mean and sigma of a histogram.
+     * @param histogram The histogram for the ECAL channel. 
+     * @return The fit result.
+     */
+    private IFitResult doGaussianFit(IHistogram1D histogram) {
+        IFunction function = functionFactory.createFunctionByName("Gaussian", "G");        
+        IFitter fitter = fitFactory.createFitter("chi2", "jminuit");
+        double[] parameters = new double[3];
+        parameters[0] = histogram.maxBinHeight();
+        parameters[1] = histogram.mean();
+        parameters[2] = histogram.rms();
+        function.setParameters(parameters);
+        IFitResult fitResult = fitter.fit(histogram, function);
+        return fitResult;
     }
 }