Print

Print


Author: [log in to unmask]
Date: Tue Nov 10 15:21:05 2015
New Revision: 3947

Log:
Updates and improvements to EVIO metadata reader; changes and cleanup to record-util module.

Added:
    java/branches/jeremy-dev/record-util/src/main/java/org/hps/record/evio/EventTagMask.java
    java/branches/jeremy-dev/record-util/src/main/java/org/hps/record/triggerbank/TriggerType.java
      - copied, changed from r3945, java/branches/jeremy-dev/record-util/src/main/java/org/hps/record/evio/EventTagBitMask.java
Removed:
    java/branches/jeremy-dev/crawler/src/main/java/org/hps/crawler/RunSummaryMap.java
    java/branches/jeremy-dev/record-util/src/main/java/org/hps/record/evio/EventCountProcessor.java
    java/branches/jeremy-dev/record-util/src/main/java/org/hps/record/evio/EventTagBitMask.java
Modified:
    java/branches/jeremy-dev/crawler/src/main/java/org/hps/crawler/AidaMetadataReader.java
    java/branches/jeremy-dev/crawler/src/main/java/org/hps/crawler/CrawlerFileUtilities.java
    java/branches/jeremy-dev/crawler/src/main/java/org/hps/crawler/DatacatCrawler.java
    java/branches/jeremy-dev/crawler/src/main/java/org/hps/crawler/DatacatUtilities.java
    java/branches/jeremy-dev/crawler/src/main/java/org/hps/crawler/EvioMetadataReader.java
    java/branches/jeremy-dev/crawler/src/main/java/org/hps/crawler/FileMetadataReader.java
    java/branches/jeremy-dev/crawler/src/main/java/org/hps/crawler/FileSet.java
    java/branches/jeremy-dev/crawler/src/main/java/org/hps/crawler/LcioMetadataReader.java
    java/branches/jeremy-dev/record-util/src/main/java/org/hps/record/epics/EpicsData.java
    java/branches/jeremy-dev/record-util/src/main/java/org/hps/record/epics/EpicsEvioProcessor.java
    java/branches/jeremy-dev/record-util/src/main/java/org/hps/record/evio/EventTagConstant.java
    java/branches/jeremy-dev/record-util/src/main/java/org/hps/record/evio/EvioBankTag.java

Modified: java/branches/jeremy-dev/crawler/src/main/java/org/hps/crawler/AidaMetadataReader.java
 =============================================================================
--- java/branches/jeremy-dev/crawler/src/main/java/org/hps/crawler/AidaMetadataReader.java	(original)
+++ java/branches/jeremy-dev/crawler/src/main/java/org/hps/crawler/AidaMetadataReader.java	Tue Nov 10 15:21:05 2015
@@ -12,7 +12,7 @@
  *
  * @author Jeremy McCormick, SLAC
  */
-public class AidaMetadataReader implements FileMetadataReader {
+final class AidaMetadataReader implements FileMetadataReader {
 
     /**
      * Get the metadata for a ROOT DQM file.

Modified: java/branches/jeremy-dev/crawler/src/main/java/org/hps/crawler/CrawlerFileUtilities.java
 =============================================================================
--- java/branches/jeremy-dev/crawler/src/main/java/org/hps/crawler/CrawlerFileUtilities.java	(original)
+++ java/branches/jeremy-dev/crawler/src/main/java/org/hps/crawler/CrawlerFileUtilities.java	Tue Nov 10 15:21:05 2015
@@ -7,7 +7,7 @@
  *
  * @author Jeremy McCormick, SLAC
  */
-public class CrawlerFileUtilities {
+final class CrawlerFileUtilities {
 
     /**
      * Get run number from file name assuming it looks like "hps_001234".

Modified: java/branches/jeremy-dev/crawler/src/main/java/org/hps/crawler/DatacatCrawler.java
 =============================================================================
--- java/branches/jeremy-dev/crawler/src/main/java/org/hps/crawler/DatacatCrawler.java	(original)
+++ java/branches/jeremy-dev/crawler/src/main/java/org/hps/crawler/DatacatCrawler.java	Tue Nov 10 15:21:05 2015
@@ -35,7 +35,7 @@
  *
  * @author Jeremy McCormick, SLAC
  */
-public class DatacatCrawler {
+public final class DatacatCrawler {
 
     /**
      * Visitor which creates a {@link FileSet} from walking a directory tree.
@@ -175,7 +175,7 @@
      * @param folder the folder in the datacat
      * @throws RuntimeException if the given path does not exist or it is not a folder
      */
-    void checkFolder(final String folder) {
+    private void checkFolder(final String folder) {
         final DatacatClient datacatClient = new DatacatClientFactory().createClient();
         if (!datacatClient.exists(folder)) {
             throw new RuntimeException("The folder " + folder + " does not exist in the data catalog.");
@@ -191,7 +191,7 @@
      * @param args the command line arguments
      * @return this object (for method chaining)
      */
-    public DatacatCrawler parse(final String[] args) {
+    private DatacatCrawler parse(final String[] args) {
         config = new CrawlerConfig();
 
         LOGGER.config("parsing command line options");
@@ -323,6 +323,11 @@
             }
             LOGGER.config("dataset site " + site);
             config.setDatasetSite(site);
+            
+            // Dry run.
+            if (cl.hasOption("D")) {
+                config.setDryRun(true);
+            }
 
         } catch (final ParseException e) {
             throw new RuntimeException("Error parsing options.", e);
@@ -353,7 +358,7 @@
     /**
      * Run the crawler job.
      */
-    void run() {
+    private void run() {
 
         // Create the file visitor for crawling the root directory with the given date filter.
         final DatacatFileVisitor visitor = new DatacatFileVisitor();
@@ -411,7 +416,7 @@
                         throw new RuntimeException("HTTP error code " + response + " received from server.");
                     }
                 } else {
-                    LOGGER.info("update on " + file.getPath() + " skipped from dry run");
+                    LOGGER.info("skipped updated on " + file.getPath() + " from dry run");
                 }
             }
             LOGGER.info("successfully added " + formatFiles.size() + " " + fileFormat + " files");

Modified: java/branches/jeremy-dev/crawler/src/main/java/org/hps/crawler/DatacatUtilities.java
 =============================================================================
--- java/branches/jeremy-dev/crawler/src/main/java/org/hps/crawler/DatacatUtilities.java	(original)
+++ java/branches/jeremy-dev/crawler/src/main/java/org/hps/crawler/DatacatUtilities.java	Tue Nov 10 15:21:05 2015
@@ -21,7 +21,7 @@
     /**
      * Static map of strings to dataset file formats.
      */
-    static Map<String, DatasetFileFormat> formatMap = new HashMap<String, DatasetFileFormat>();
+    private static Map<String, DatasetFileFormat> formatMap = new HashMap<String, DatasetFileFormat>();
     static {
         for (final DatasetFileFormat format : DatasetFileFormat.values()) {
             formatMap.put(format.extension(), format);

Modified: java/branches/jeremy-dev/crawler/src/main/java/org/hps/crawler/EvioMetadataReader.java
 =============================================================================
--- java/branches/jeremy-dev/crawler/src/main/java/org/hps/crawler/EvioMetadataReader.java	(original)
+++ java/branches/jeremy-dev/crawler/src/main/java/org/hps/crawler/EvioMetadataReader.java	Tue Nov 10 15:21:05 2015
@@ -2,38 +2,49 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.math.RoundingMode;
+import java.text.DecimalFormat;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import org.hps.record.evio.EventTagBitMask;
+import org.hps.record.epics.EpicsData;
+import org.hps.record.epics.EpicsEvioProcessor;
 import org.hps.record.evio.EventTagConstant;
+import org.hps.record.evio.EventTagMask;
 import org.hps.record.evio.EvioEventUtilities;
 import org.hps.record.evio.EvioFileUtilities;
+import org.hps.record.scalers.ScalerData;
 import org.hps.record.scalers.ScalersEvioProcessor;
+import org.hps.record.triggerbank.TriggerType;
 import org.jlab.coda.jevio.EvioEvent;
 import org.jlab.coda.jevio.EvioException;
 import org.jlab.coda.jevio.EvioReader;
 
 /**
- * Reads metadata from EVIO files.
- *
+ * Reads metadata from EVIO files, including the event count, run min and run max expected by the datacat,
+ * as well as many custom field values applicable to HPS EVIO raw data.
+ * <p>
+ * The size of the data file is set externally to this reader using the datacat client.
+ * 
  * @author Jeremy McCormick, SLAC
  */
-public class EvioMetadataReader implements FileMetadataReader {
+final class EvioMetadataReader implements FileMetadataReader {
 
     /**
      * Initialize the logger.
      */
     private static Logger LOGGER = Logger.getLogger(EvioMetadataReader.class.getPackage().getName());
-
+    
     /**
      * Get the EVIO file metadata.
-     *
+     *      
      * @param file the EVIO file
      * @return the metadata map of key and value pairs
      */
@@ -42,26 +53,37 @@
 
         Integer firstTimestamp = null;
         Integer lastTimestamp = null;
+        Integer firstPhysicsTimestamp = null;
+        Integer lastPhysicsTimestamp = null;
+        int totalEvents = 0;
         int badEvents = 0;
-        int eventCount = 0;
         int epicsEvents = 0;
-        int scalerBanks = 0;
-        boolean prestart = false;
-        boolean end = false;
-        boolean go = false;
+        int scalerEvents = 0;
+        int physicsEvents = 0;
+        int syncEvents = 0;
+        int pauseEvents = 0;
+        int prestartEvents = 0;
+        int endEvents = 0;
+        int goEvents = 0;        
         boolean blinded = true;
         Integer run = null;
         Integer lastPhysicsEvent = null;
         Integer firstPhysicsEvent = null;
+        double triggerRate = 0;
+        List<ScalerData> scalerData = new ArrayList<ScalerData>();
+        List<EpicsData> epicsData = new ArrayList<EpicsData>();
+                               
+        // Create map for counting event masks.        
+        Map<TriggerType, Integer> eventCounts = new HashMap<TriggerType, Integer>();
+        for (TriggerType mask : TriggerType.values()) {
+            eventCounts.put(mask, 0);
+        }
                 
-        // Create map for counting event masks.        
-        Map<EventTagBitMask, Integer> triggerCounts = new HashMap<EventTagBitMask, Integer>();
-        for (EventTagBitMask mask : EventTagBitMask.values()) {
-            triggerCounts.put(mask, 0);
-        }
-        
         // Scaler processor to check for scaler bank.
         ScalersEvioProcessor scalersProcessor = new ScalersEvioProcessor();
+        
+        // EPICS data processor.
+        EpicsEvioProcessor epicsProcessor = new EpicsEvioProcessor(); 
 
         // Get the file number from the name.
         final int fileNumber = EvioFileUtilities.getSequenceFromName(file);
@@ -72,10 +94,9 @@
         }
         
         EvioReader evioReader = null;
-        try {
-                                   
-            evioReader = EvioFileUtilities.open(file, true);
-            
+        try {                        
+            // Open file in sequential mode.
+            evioReader = EvioFileUtilities.open(file, true);            
             EvioEvent evioEvent = null;
 
             // Event read loop.
@@ -84,122 +105,173 @@
                 // Read in an EVIO event, trapping exceptions in case a parse error occurs.
                 boolean badEvent = false;
                 try {
-                    evioEvent = evioReader.parseNextEvent();
+                    // Parse next event.
+                    evioEvent = evioReader.parseNextEvent();                    
                 } catch (IOException | EvioException e) {
+                    // Trap event parsing errors from bad EVIO data.
                     badEvent = true;
+                    badEvents++;
                     LOGGER.warning("bad EVIO event " + evioEvent.getEventNumber() + " could not be parsed");
+                } finally {
+                    // End of file.
+                    if (!badEvent && evioEvent == null) {
+                        LOGGER.info("EOF after " + totalEvents + " events");
+                        break;
+                    }
+                    
+                    // Increment event count.
+                    totalEvents++;
                 }
                                 
-                // Increment bad event count and continue.
+                // Continue to next event if a parse error occurred.
                 if (badEvent) {
-                    badEvents++;
                     continue;
-                }
-                
-                // End of file.
-                if (evioEvent == null) {
-                    LOGGER.info("end of file reached after " + eventCount + " events");
-                    break;
-                }
-                
+                }                
+                                
+                // Debug print event number and tag.
+                LOGGER.finest("parsed event " + evioEvent.getEventNumber() + " with tag 0x" + String.format("%08x", evioEvent.getHeader().getTag()));
+                                
                 // Process different event types.
-                if (EventTagConstant.PRESTART.equals(evioEvent)) {
+                if (EventTagConstant.PRESTART.matches(evioEvent)) {
                                                             
                     // File has PRESTART event.
-                    LOGGER.info("found PRESTART event " + evioEvent.getEventNumber());
-                    prestart = true;
+                    LOGGER.fine("found PRESTART event " + evioEvent.getEventNumber());
+                    ++prestartEvents;
                     
                     // Set the run number from the PRESTART event.
                     final int[] controlEventData = EvioEventUtilities.getControlEventData(evioEvent);
                     if (run == null) {
                         run = controlEventData[1];
-                        LOGGER.info("set run to " + run + " from PRESTART");
-                    }
-                    
-                } else if (EventTagConstant.GO.equals(evioEvent)) {
+                        LOGGER.fine("set run to " + run + " from PRESTART");
+                    }
+                    
+                    // Set the first timestamp from the PRESTART event.
+                    if (firstTimestamp == null) {
+                        firstTimestamp = controlEventData[0];
+                        LOGGER.fine("set first timestamp to " + firstTimestamp + " from PRESTART event " + evioEvent.getEventNumber());
+                    }
+                    
+                } else if (EventTagConstant.GO.matches(evioEvent)) {
                     
                     // File has GO event.
-                    go = true;
-                    
-                    // Set the first timestamp from the GO event.
-                    final int[] controlEventData = EvioEventUtilities.getControlEventData(evioEvent);
-                    firstTimestamp = controlEventData[0];
-                    LOGGER.info("set first timestamp to " + firstTimestamp + " from GO event " + evioEvent.getEventNumber());
-                    
-                } else if (EventTagConstant.END.equals(evioEvent)) {
+                    goEvents++;
+                    
+                    // Set first timestamp from the GO event (will not override PRESTART time).
+                    if (firstTimestamp == null) {
+                        final int[] controlEventData = EvioEventUtilities.getControlEventData(evioEvent);
+                        firstTimestamp = controlEventData[0];
+                        LOGGER.fine("set first timestamp to " + firstTimestamp + " from GO event " + evioEvent.getEventNumber());
+                    }
+                                                           
+                } else if (EventTagConstant.END.matches(evioEvent)) {
                     
                     // File has END event.
-                    LOGGER.info("got END event");
-                    end = true;
+                    LOGGER.fine("got END event");
+                    endEvents++;
                     
                     // Set the last timestamp from the END event.
                     final int[] controlEventData = EvioEventUtilities.getControlEventData(evioEvent);
                     lastTimestamp = controlEventData[0];
-                    LOGGER.info("set last timestamp " + lastTimestamp + " from END event " + evioEvent.getEventNumber());
+                    LOGGER.fine("set last timestamp " + lastTimestamp + " from END event " + evioEvent.getEventNumber());
                     if (run == null) {
                         run = controlEventData[1];
-                        LOGGER.info("set run to " + run);
-                    }
+                        LOGGER.fine("set run to " + run);
+                    }
+                    
+                } else if (EventTagConstant.PAUSE.matches(evioEvent)) {
+                    
+                    // Count pause events.
+                    pauseEvents++;
                     
                 } else if (EvioEventUtilities.isPhysicsEvent(evioEvent)) {
                     
-                    // Event count on the file only includes physics events.
-                    eventCount++;
+                    // Count physics events.
+                    physicsEvents++;
                     
                     // Get head bank.
                     final int[] headBankData = EvioEventUtilities.getHeadBankData(evioEvent);
                     
-                    // Set first timestamp from head bank.
-                    if (firstTimestamp == null) {
+                    // Is head bank present?
+                    if (headBankData != null) {
+                        
+                        // Is timestamp set?
                         if (headBankData[3] != 0) {
-                            firstTimestamp = headBankData[3];
-                            LOGGER.info("set first timestamp to " + firstTimestamp + " from physics event " + evioEvent.getEventNumber());
+                            
+                            // Set first timestamp.
+                            if (firstTimestamp == null) {
+                                firstTimestamp = headBankData[3];
+                                LOGGER.fine("set first timestamp to " + firstTimestamp + " from physics event " + evioEvent.getEventNumber());                                
+                            }
+                            
+                            // Set first physics timestamp.
+                            if (firstPhysicsTimestamp == null) {                     
+                                firstPhysicsTimestamp = headBankData[3];
+                                LOGGER.fine("set first physics timestamp to " + firstTimestamp + " from event " + evioEvent.getEventNumber());                                
+                            }
+                            
+                            // Set last physics timestamp.
+                            lastPhysicsTimestamp = headBankData[3];
+                            LOGGER.finest("set last physics timestamp to " + firstTimestamp + " from event " + evioEvent.getEventNumber());
+                            
+                            // Set last timestamp.
+                            lastTimestamp = headBankData[3];
                         }
-                    }
-                    
-                    // Set run number from head bank if not set already.
-                    if (run == null) {
-                        run = headBankData[1];
-                        LOGGER.info("set run to " + run + " from physics event " + evioEvent.getEventNumber());
-                    }
-                    
+                        
+                        // Set run number.
+                        if (run == null) {
+                            run = headBankData[1];
+                            LOGGER.info("set run to " + run + " from physics event " + evioEvent.getEventNumber());
+                        }
+                    }                                                                
+                                                                                
                     // Get the event ID data.
                     final int[] eventIdData = EvioEventUtilities.getEventIdData(evioEvent);
-                    if (eventIdData == null) {
-                        throw new RuntimeException("The event ID data bank for event " + evioEvent.getEventNumber() + " is null.");
-                    }                    
-                    
-                    // Set the first physics event from event ID data.
-                    if (firstPhysicsEvent == null) {
-                        firstPhysicsEvent = eventIdData[0];
-                        LOGGER.info("set start event " + firstPhysicsEvent + " from physics event " + evioEvent.getEventNumber());
-                    }
-                    
-                    // Set the last physics event from the event ID data.
-                    lastPhysicsEvent = eventIdData[0];
-                   
-                    // Set the last timestamp from head bank.
-                    if (headBankData[3] != 0) {
-                        lastTimestamp = headBankData[3];
-                    }
-                    
-                    // Increment scaler bank count if exists in event.
+                    if (eventIdData != null) {
+                        
+                        // Set the last physics event.
+                        lastPhysicsEvent = eventIdData[0];
+
+                        // Set the first physics event.
+                        if (firstPhysicsEvent == null) {
+                            firstPhysicsEvent = eventIdData[0];
+                            LOGGER.fine("set start event " + firstPhysicsEvent + " from physics event " + evioEvent.getEventNumber());
+                        }                        
+                    }
+                                                                         
+                    // Count scaler events.
                     scalersProcessor.process(evioEvent);
                     if (scalersProcessor.getCurrentScalerData() != null) {
-                        scalerBanks++;
-                    }
-                    
-                    // Increment event mask counts for each type.
-                    Set<EventTagBitMask> masks = EventTagBitMask.getEventTagBitMasks(evioEvent);
-                    for (EventTagBitMask mask : masks) {
-                        int count = triggerCounts.get(mask) + 1;
-                        triggerCounts.put(mask, count);
-                    }                                    
-                    
-                } else if (EventTagConstant.EPICS.equals(evioEvent)) {
+                        scalerData.add(scalersProcessor.getCurrentScalerData());
+                        scalerEvents++;
+                    }
+                    
+                    // Count trigger types for this event.
+                    Set<TriggerType> triggerTypes = TriggerType.getTriggerTypes(evioEvent);
+                    for (TriggerType mask : triggerTypes) {
+                        int count = eventCounts.get(mask) + 1;
+                        eventCounts.put(mask, count);
+                        LOGGER.finer("incremented " + mask.name() + " to " + count);
+                    }
+                    
+                    // Count sync events.
+                    if (EventTagMask.SYNC.matches(evioEvent.getHeader().getTag())) {
+                        // Count sync events.
+                        ++syncEvents;
+                        LOGGER.finer("got sync event from tag " + String.format("%08x", evioEvent.getHeader().getTag()));
+                    }
+                                          
+                } else if (EventTagConstant.EPICS.matches(evioEvent)) {
+                                        
                     // Count EPICS events.
                     ++epicsEvents;
-                }
+                    
+                    // Get EPICS data for charge calculation.
+                    epicsProcessor.process(evioEvent);
+                    EpicsData epicsEvent = epicsProcessor.getEpicsData();
+                    if (epicsEvent.hasKey("scaler_calc1")) {
+                        epicsData.add(epicsEvent);    
+                    }                    
+                } 
             }
             
         } catch (final EvioException e) {
@@ -215,34 +287,89 @@
                 }
             }
         }
-     
+        
+        LOGGER.info("done reading "  + totalEvents + " events");
+        
+        // Rough trigger rate calculation.
+        triggerRate = calculateTriggerRate(firstPhysicsTimestamp, lastPhysicsTimestamp, physicsEvents);
+
+        // Calculate ungated charge.
+        //double ungatedCharge = calculateCharge(epicsData, firstPhysicsTimestamp, lastPhysicsTimestamp);
+        
+        // Calculated gated charge.
+        //double gatedCharge = calculateGatedCharge(ungatedCharge, scalerData, ScalerDataIndex.FCUP_TRG_GATED, ScalerDataIndex.FCUP_TRG_UNGATED);
+        
         // Create and fill the metadata map.
-        final Map<String, Object> metaDataMap = new LinkedHashMap<String, Object>();
-        metaDataMap.put("runMin", run);
-        metaDataMap.put("runMax", run);
-        metaDataMap.put("eventCount", eventCount);
-        metaDataMap.put("FILE", fileNumber);
-        metaDataMap.put("FIRST_TIMESTAMP", firstTimestamp);
-        metaDataMap.put("LAST_TIMESTAMP", lastTimestamp);
-        metaDataMap.put("FIRST_PHYSICS_EVENT", firstPhysicsEvent);
-        metaDataMap.put("LAST_PHYSICS_EVENT", lastPhysicsEvent);        
-        metaDataMap.put("BAD_EVENTS", badEvents);
-        metaDataMap.put("EPICS_EVENTS", epicsEvents);        
-        metaDataMap.put("SCALER_BANKS", scalerBanks);
-        metaDataMap.put("END", end);
-        metaDataMap.put("PRESTART", prestart);
-        metaDataMap.put("GO", go);        
-        metaDataMap.put("BLINDED", blinded);
-                      
-        // Add the event mask counts.
-        for (Entry<EventTagBitMask, Integer> entry : triggerCounts.entrySet()) {
-            // These two keys aren't working right so don't include them.
-            if (EventTagBitMask.PHYSICS != entry.getKey() && EventTagBitMask.SYNC != entry.getKey()) {
-                metaDataMap.put(entry.getKey().name(), entry.getValue());
-            }
-        }
-
+        final Map<String, Object> metadataMap = new LinkedHashMap<String, Object>();
+        
+        // Built-in fields of datacat.
+        metadataMap.put("runMin", run);
+        metadataMap.put("runMax", run);
+        metadataMap.put("eventCount", totalEvents);
+        
+        // Run number.
+        metadataMap.put("RUN", run);
+        
+        // File sequence number.
+        metadataMap.put("FILE_NUMBER", fileNumber);
+        
+        // Blinded flag.
+        metadataMap.put("BLINDED", blinded);
+        
+        // First and last timestamps which may come from control or physics events.
+        metadataMap.put("FIRST_TIMESTAMP", firstTimestamp);
+        metadataMap.put("LAST_TIMESTAMP", lastTimestamp);
+        
+        // First and last physics events.
+        metadataMap.put("FIRST_PHYSICS_EVENT", firstPhysicsEvent);
+        metadataMap.put("LAST_PHYSICS_EVENT", lastPhysicsEvent);
+        
+        // First and last physics event timestamps.
+        metadataMap.put("FIRST_PHYSICS_TIMESTAMP", firstPhysicsTimestamp);
+        metadataMap.put("LAST_PHYSICS_TIMESTAMP", lastPhysicsTimestamp);
+        
+        // Event counts.
+        metadataMap.put("PHYSICS_EVENTS", physicsEvents);
+        metadataMap.put("BAD_EVENTS", badEvents);
+        metadataMap.put("EPICS_EVENTS", epicsEvents);        
+        metadataMap.put("SCALER_EVENTS", scalerEvents);
+        metadataMap.put("END_EVENTS", endEvents);
+        metadataMap.put("PRESTART_EVENTS", prestartEvents);
+        metadataMap.put("GO_EVENTS", goEvents);
+        metadataMap.put("PAUSE_EVENTS", pauseEvents);
+        metadataMap.put("SYNC_EVENTS", syncEvents);
+        
+        // Trigger rate.
+        DecimalFormat df = new DecimalFormat("#.####");
+        df.setRoundingMode(RoundingMode.CEILING);
+        metadataMap.put("TRIGGER_RATE_KHZ", Double.parseDouble(df.format(triggerRate)));
+                                            
+        // Add the trigger counts.
+        for (Entry<TriggerType, Integer> entry : eventCounts.entrySet()) {
+            metadataMap.put(entry.getKey().name(), entry.getValue());
+        }
+        
+        // Print the file metadata to log.
+        StringBuffer sb = new StringBuffer();
+        sb.append('\n');
+        for (Entry<String, Object> entry : metadataMap.entrySet()) {
+            sb.append("  " + entry.getKey() + " = " + entry.getValue() + '\n');
+        }
+        LOGGER.info("file metadata ..." + '\n' + sb.toString());
+        
         // Return the completed metadata map.
-        return metaDataMap;
+        return metadataMap;
     }
+
+    /**
+     * Calculate the trigger rate in KHz.
+     * 
+     * @param firstTimestamp the first physics timestamp
+     * @param lastTimestamp the last physics timestamp
+     * @param physicsEvents the number of physics events
+     * @return the trigger rate calculation in KHz
+     */
+    private double calculateTriggerRate(Integer firstTimestamp, Integer lastTimestamp, int physicsEvents) {
+        return ((double) physicsEvents / ((double) lastTimestamp - (double) firstTimestamp)) / 1000.;
+    }    
 }

Modified: java/branches/jeremy-dev/crawler/src/main/java/org/hps/crawler/FileMetadataReader.java
 =============================================================================
--- java/branches/jeremy-dev/crawler/src/main/java/org/hps/crawler/FileMetadataReader.java	(original)
+++ java/branches/jeremy-dev/crawler/src/main/java/org/hps/crawler/FileMetadataReader.java	Tue Nov 10 15:21:05 2015
@@ -18,5 +18,5 @@
      * @return the metadata map
      * @throws IOException if there is an error reading the file
      */
-    public Map<String, Object> getMetadata(File file) throws IOException;
+    Map<String, Object> getMetadata(File file) throws IOException;
 }

Modified: java/branches/jeremy-dev/crawler/src/main/java/org/hps/crawler/FileSet.java
 =============================================================================
--- java/branches/jeremy-dev/crawler/src/main/java/org/hps/crawler/FileSet.java	(original)
+++ java/branches/jeremy-dev/crawler/src/main/java/org/hps/crawler/FileSet.java	Tue Nov 10 15:21:05 2015
@@ -14,14 +14,14 @@
  */
 public class FileSet extends HashMap<DatasetFileFormat, List<File>> {
     
-    public List<File> get(DatasetFileFormat format) {
+    List<File> get(DatasetFileFormat format) {
         if (super.get(format) == null) {
             this.put(format, new ArrayList<File>());
         }
         return super.get(format);
     }
     
-    public void addFile(DatasetFileFormat format, File file) {
+    void addFile(DatasetFileFormat format, File file) {
         this.get(format).add(file);
     }
 }

Modified: java/branches/jeremy-dev/crawler/src/main/java/org/hps/crawler/LcioMetadataReader.java
 =============================================================================
--- java/branches/jeremy-dev/crawler/src/main/java/org/hps/crawler/LcioMetadataReader.java	(original)
+++ java/branches/jeremy-dev/crawler/src/main/java/org/hps/crawler/LcioMetadataReader.java	Tue Nov 10 15:21:05 2015
@@ -21,7 +21,7 @@
  */
 public class LcioMetadataReader implements FileMetadataReader {
 
-    /*
+    /**
      * Setup the conditions system in dummy mode.
      */
     static {

Modified: java/branches/jeremy-dev/record-util/src/main/java/org/hps/record/epics/EpicsData.java
 =============================================================================
--- java/branches/jeremy-dev/record-util/src/main/java/org/hps/record/epics/EpicsData.java	(original)
+++ java/branches/jeremy-dev/record-util/src/main/java/org/hps/record/epics/EpicsData.java	Tue Nov 10 15:21:05 2015
@@ -281,7 +281,7 @@
         EpicsData epicsData = null;
         
         // Is this an EPICS event?
-        if (EventTagConstant.EPICS.equals(evioEvent)) {
+        if (EventTagConstant.EPICS.matches(evioEvent)) {
 
             // Find the bank with the EPICS data string.
             final BaseStructure epicsBank = EvioBankTag.EPICS_STRING.findBank(evioEvent);

Modified: java/branches/jeremy-dev/record-util/src/main/java/org/hps/record/epics/EpicsEvioProcessor.java
 =============================================================================
--- java/branches/jeremy-dev/record-util/src/main/java/org/hps/record/epics/EpicsEvioProcessor.java	(original)
+++ java/branches/jeremy-dev/record-util/src/main/java/org/hps/record/epics/EpicsEvioProcessor.java	Tue Nov 10 15:21:05 2015
@@ -45,7 +45,7 @@
     public void process(final EvioEvent evioEvent) {
 
         // Is this an EPICS event?
-        if (EventTagConstant.EPICS.equals(evioEvent)) {
+        if (EventTagConstant.EPICS.matches(evioEvent)) {
 
             LOGGER.fine("processing EPICS event " + evioEvent.getEventNumber());
 

Modified: java/branches/jeremy-dev/record-util/src/main/java/org/hps/record/evio/EventTagConstant.java
 =============================================================================
--- java/branches/jeremy-dev/record-util/src/main/java/org/hps/record/evio/EventTagConstant.java	(original)
+++ java/branches/jeremy-dev/record-util/src/main/java/org/hps/record/evio/EventTagConstant.java	Tue Nov 10 15:21:05 2015
@@ -63,7 +63,7 @@
         return tag == this.tag;
     }
     
-    public boolean equals(final EvioEvent evioEvent) {
+    public boolean matches(final EvioEvent evioEvent) {
         return evioEvent.getHeader().getTag() == this.tag;
     }
     

Added: java/branches/jeremy-dev/record-util/src/main/java/org/hps/record/evio/EventTagMask.java
 =============================================================================
--- java/branches/jeremy-dev/record-util/src/main/java/org/hps/record/evio/EventTagMask.java	(added)
+++ java/branches/jeremy-dev/record-util/src/main/java/org/hps/record/evio/EventTagMask.java	Tue Nov 10 15:21:05 2015
@@ -0,0 +1,40 @@
+package org.hps.record.evio;
+
+/**
+ * Event tag mask for physics and sync events.
+ * @author Jeremy McCormick, SLAC
+ */
+public enum EventTagMask {
+    
+    /** Sync event with scalers and/or trigger config. */
+    SYNC(0x40),
+    /** Physics events. */
+    PHYSICS(0x80);
+
+    /**
+     * Define an event tag with a mask.
+     * @param mask the bit mask value
+     */
+    EventTagMask(int mask) {
+        this.mask = mask;
+    }
+    
+    private int mask;
+    
+    /**
+     * Get the tag's mask value.
+     * @return the tag's mask value
+     */
+    public int getMask() {
+        return mask;
+    }
+    
+    /**
+     * Return <code>true</code> if the <code>eventTag</code> matches this mask.
+     * @param eventTag the event tag value from the EVIO header
+     * @return <code>true</code> if <code>eventTag</code> matches this mask
+     */
+    public boolean matches(int eventTag) {
+        return (eventTag & mask) > 0;
+    }   
+}

Modified: java/branches/jeremy-dev/record-util/src/main/java/org/hps/record/evio/EvioBankTag.java
 =============================================================================
--- java/branches/jeremy-dev/record-util/src/main/java/org/hps/record/evio/EvioBankTag.java	(original)
+++ java/branches/jeremy-dev/record-util/src/main/java/org/hps/record/evio/EvioBankTag.java	Tue Nov 10 15:21:05 2015
@@ -25,8 +25,10 @@
     /** Scaler data bank. */
     SCALERS(57621),
     /** Trigger configuration bank. */
-    TRIGGER_CONFIG(0xE10E);
-
+    TRIGGER_CONFIG(0xE10E),
+    /** TI trigger bank. */
+    TI_TRIGGER(0xe10a);
+    
     /**
      * The bank's tag value.
      */
@@ -46,7 +48,7 @@
      *
      * @param startBank the starting bank
      * @return the first bank matching the tag or <code>null<code> if not found
-     */
+     */    
     public BaseStructure findBank(final BaseStructure startBank) {
         BaseStructure foundBank = null;
         if (this.equals(startBank)) {
@@ -60,8 +62,8 @@
             }
         }
         return foundBank;
-    }
-
+    }    
+    
     /**
      * Get the bank tag value.
      *

Copied: java/branches/jeremy-dev/record-util/src/main/java/org/hps/record/triggerbank/TriggerType.java (from r3945, java/branches/jeremy-dev/record-util/src/main/java/org/hps/record/evio/EventTagBitMask.java)
 =============================================================================
--- java/branches/jeremy-dev/record-util/src/main/java/org/hps/record/evio/EventTagBitMask.java	(original)
+++ java/branches/jeremy-dev/record-util/src/main/java/org/hps/record/triggerbank/TriggerType.java	Tue Nov 10 15:21:05 2015
@@ -1,112 +1,86 @@
-package org.hps.record.evio;
+package org.hps.record.triggerbank;
 
 import java.util.HashSet;
 import java.util.Set;
 
+import org.hps.record.triggerbank.AbstractIntData.IntBankDefinition;
+import org.jlab.coda.jevio.BaseStructure;
 import org.jlab.coda.jevio.EvioEvent;
 
 /**
- * Encapsulates bit mask values for different types of physics events as described at 
+ * Provides bit mask checks for the trigger types defined in
  * <a href="https://confluence.slac.stanford.edu/display/hpsg/EVIO+Data+Format#EVIODataFormat-EVIOEventtypes-2015DataSet">EVIO Event types</a>.
  *
- * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
+ * @author Jeremy McCormick, SLAC
  */
-public enum EventTagBitMask {
-
-    /** LED or Cosmic trigger. */
-    LED_COSMIC(4),
+public enum TriggerType {
+    
+    /** LED or Cosmic trigger (sometimes called calibration also). */
+    LED_COSMIC(28),
     /** Pair 0 trigger. */
-    PAIRS0(2),
+    PAIRS0(26),
     /** Pair 1 trigger. */
-    PAIRS1(3),
-    /** Physics event. */
-    PHYSICS(7), // FIXME: Doesn't work!
+    PAIRS1(27),
     /** Pulser triggered event. */
-    PULSER(5),
+    PULSER(29),
     /** Single 0 trigger. */
-    SINGLE0(0),
+    SINGLES0(24),
     /** Single 1 trigger. */
-    SINGLE1(1),
-    /** Physics sync event. */
-    SYNC(6);
-
+    SINGLES1(25);
+    
     /**
      * The bit number.
      */
     private int bit;
 
     /**
-     * The bit mask.
+     * Constructor with bit number which is used to shift the input TI bits.    
+     * @param bit the bit number for shifting the TI bits
      */
-    private int bitMask;
-
-    /**
-     * Constructor with bit number.
-     *
-     * @param bit the bit number
-     */
-    private EventTagBitMask(final int bit) {
+    private TriggerType(final int bit) {
         this.bit = bit;
-        this.bitMask = 1 >> this.bit;
     }
 
     /**
-     * Get the bit number.
-     *
+     * Get the bit number.    
      * @return the bit number
      */
     public int getBit() {
         return this.bit;
     }
-
+    
     /**
-     * Get the bit mask.
-     *
-     * @return the bit mask
+     * Return <code>true</code> if the bits match this mask.    
+     * @param triggerBits the trigger bits from the TI bank
+     * @return <code>true</code> if the bits match this mask
      */
-    public int getBitMask() {
-        return this.bitMask;
-    }
-
-    /**
-     * Return <code>true</code> if the event's tag matches this mask.
-     *
-     * @param event an <code>EvioEvent</code> with tag to check against this mask
-     * @return <code>true</code> if the event's tag matches this mask
-     */
-    public boolean equals(final EvioEvent event) {
-        return equals(event.getHeader().getTag());
-    }
-
-    /**
-     * Return <code>true</code> if the tag matches this mask.
-     *
-     * @param eventTag the event's tag from the header bank
-     * @return <code>true</code> if the tag matches this mask
-     */
-    public boolean equals(final int eventTag) {
-        return (eventTag & this.bitMask) == 1;
+    public boolean matches(final int triggerBits) {
+        return ((triggerBits >> this.bit) & 1) == 1;
     }
     
-    public static Set<EventTagBitMask> getEventTagBitMasks(EvioEvent evioEvent) {
-        Set<EventTagBitMask> bitMasks = new HashSet<EventTagBitMask>();
-        if (LED_COSMIC.equals(evioEvent)) {
-            bitMasks.add(LED_COSMIC);
-        } if (PAIRS0.equals(evioEvent)) {
-            bitMasks.add(PAIRS0);
-        } if (PAIRS1.equals(evioEvent)) {
-            bitMasks.add(PAIRS1);
-        } if (PHYSICS.equals(evioEvent)) {
-            bitMasks.add(PHYSICS);
-        } if (PULSER.equals(evioEvent)) {
-            bitMasks.add(PULSER);
-        } if (SINGLE0.equals(evioEvent)) {
-            bitMasks.add(SINGLE0);
-        } if (SINGLE1.equals(evioEvent)) {
-            bitMasks.add(SINGLE1);
-        } if (SYNC.equals(evioEvent)) {
-            bitMasks.add(SYNC);
+    /**
+     * Definition of the TI bank in the EVIO event.
+     */
+    private static IntBankDefinition TI_BANK = new IntBankDefinition(TIData.class, new int[] {0x2e, 0xe10a});
+    
+    /**
+     * Get the applicable trigger types from the TI data in an EVIO event.
+     * @param evioEvent the input EVIO event with the TI data
+     * @return the set of matching trigger types for the event
+     */
+    public static Set<TriggerType> getTriggerTypes(EvioEvent evioEvent) {
+        Set<TriggerType> matches = new HashSet<TriggerType>();
+        BaseStructure tiBank = TI_BANK.findBank(evioEvent);
+        if (tiBank != null) {
+            int[] triggerData = tiBank.getIntData();
+            if (triggerData != null) {
+                for (TriggerType triggerType : TriggerType.values()) {
+                    if (triggerType.matches(triggerData[0])) {
+                        matches.add(triggerType);
+                    }
+                }
+            }
         }
-        return bitMasks;
-    }
+        return matches;
+    }      
 }