Print

Print


Author: [log in to unmask]
Date: Mon Mar 23 16:23:56 2015
New Revision: 2509

Log:
Add first pass at EPICS data parsing from EVIO.  (This will be moved to another module at some point.)

Added:
    java/trunk/evio/src/main/java/org/hps/evio/epics/
    java/trunk/evio/src/main/java/org/hps/evio/epics/EpicsEvioProcessor.java
    java/trunk/evio/src/main/java/org/hps/evio/epics/EpicsGenericObject.java
    java/trunk/evio/src/main/java/org/hps/evio/epics/EpicsScalarData.java
    java/trunk/evio/src/test/java/org/hps/evio/epics/
    java/trunk/evio/src/test/java/org/hps/evio/epics/EpicsScalarDataTest.java
Modified:
    java/trunk/evio/pom.xml

Modified: java/trunk/evio/pom.xml
 =============================================================================
--- java/trunk/evio/pom.xml	(original)
+++ java/trunk/evio/pom.xml	Mon Mar 23 16:23:56 2015
@@ -19,6 +19,10 @@
         <dependency>
             <groupId>org.hps</groupId>
             <artifactId>hps-tracking</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.hps</groupId>
+            <artifactId>hps-record-util</artifactId>
         </dependency>
     </dependencies>
     <build>

Added: java/trunk/evio/src/main/java/org/hps/evio/epics/EpicsEvioProcessor.java
 =============================================================================
--- java/trunk/evio/src/main/java/org/hps/evio/epics/EpicsEvioProcessor.java	(added)
+++ java/trunk/evio/src/main/java/org/hps/evio/epics/EpicsEvioProcessor.java	Mon Mar 23 16:23:56 2015
@@ -0,0 +1,55 @@
+package org.hps.evio.epics;
+
+import org.hps.record.evio.EvioEventConstants;
+import org.hps.record.evio.EvioEventProcessor;
+import org.jlab.coda.jevio.BaseStructure;
+import org.jlab.coda.jevio.EvioEvent;
+
+/**
+ * This is an EVIO event processor that will read EPICS events (event tag 31) 
+ * and turn them into {@link EpicsScalarData} objects.
+ *   
+ * @author Jeremy McCormick <[log in to unmask]>
+ */
+public final class EpicsEvioProcessor extends EvioEventProcessor {
+
+    public void process(EvioEvent evio) {
+        
+        if (evio.getHeader().getTag() != EvioEventConstants.EPICS_EVENT_TAG) {
+            // Just silently skip these events because otherwise too many error messages might print.
+            return;
+        }
+
+        System.out.println("Epics EVIO event " + evio.getEventNumber());
+        System.out.println("Dumping EPICS event ...");
+        System.out.println(evio.toXML());
+
+        // Find the bank with the EPICS information.
+        BaseStructure epicsBank = null;
+        BaseStructure topBank = evio.getChildrenList().get(0);
+        System.out.println("got top bank: " + topBank.getHeader().getTag());
+        for (BaseStructure childBank : topBank.getChildrenList()) {
+            System.out.println("found child bank tag: " + childBank.getHeader().getTag());
+            if (childBank.getHeader().getTag() == EvioEventConstants.EPICS_BANK_TAG) {
+                System.out.println("found EPICS bank tag: " + childBank.getHeader().getTag());
+                epicsBank = childBank;
+                break;
+            }
+        }
+
+        if (epicsBank != null) {
+            System.out.println("found EPICS bank with tag " + epicsBank.getHeader().getTag());
+            String epicsData = epicsBank.getStringData()[0];
+            System.out.println("dumping EPICS string data ...");
+            System.out.println(epicsData);
+
+            EpicsScalarData data = new EpicsScalarData();
+            data.fromString(epicsData);
+
+            System.out.println("parsed EPICS data ...");
+            System.out.println(data.toString());
+        } else {
+            System.out.println("did not find EPICS data bank in event");
+        }
+    }
+}

Added: java/trunk/evio/src/main/java/org/hps/evio/epics/EpicsGenericObject.java
 =============================================================================
--- java/trunk/evio/src/main/java/org/hps/evio/epics/EpicsGenericObject.java	(added)
+++ java/trunk/evio/src/main/java/org/hps/evio/epics/EpicsGenericObject.java	Mon Mar 23 16:23:56 2015
@@ -0,0 +1,56 @@
+package org.hps.evio.epics;
+
+import org.lcsim.event.GenericObject;
+
+/**
+ * This is an implementation of GenericObject for reading and writing EPICS data.
+ * There is no functionality here.  Users that need this data in their <code>Driver</code>
+ * classes should instead use {@link EpicsScalarData#read(org.lcsim.event.EventHeader)}
+ * to create the class with the actual API.
+ * 
+ * @author Jeremy McCormick <[log in to unmask]>
+ */
+final class EpicsGenericObject implements GenericObject {
+
+    String[] keys;
+    double[] values;
+
+    @Override
+    public int getNInt() {
+        return 0;
+    }
+
+    @Override
+    public int getNFloat() {
+        return 0;
+    }
+
+    @Override
+    public int getNDouble() {
+        return values.length;
+    }
+
+    @Override
+    public int getIntVal(int index) {
+        return 0;
+    }
+
+    @Override
+    public float getFloatVal(int index) {
+        return 0;
+    }
+
+    @Override
+    public double getDoubleVal(int index) {
+        return values[index];
+    }
+
+    @Override
+    public boolean isFixedSize() {
+        return false;
+    }
+
+    public String getKey(int index) {
+        return keys[index];
+    }
+}

Added: java/trunk/evio/src/main/java/org/hps/evio/epics/EpicsScalarData.java
 =============================================================================
--- java/trunk/evio/src/main/java/org/hps/evio/epics/EpicsScalarData.java	(added)
+++ java/trunk/evio/src/main/java/org/hps/evio/epics/EpicsScalarData.java	Mon Mar 23 16:23:56 2015
@@ -0,0 +1,175 @@
+package org.hps.evio.epics;
+
+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 org.lcsim.event.EventHeader;
+import org.lcsim.event.GenericObject;
+
+/**
+ * <p>
+ * This is an API for reading and writing EPICS scalar data to LCIO events,
+ * as well as parsing the scalar data from a CDATA section of an EVIO string
+ * data bank.
+ * <p>Sample data:<br/>
+ * <pre>
+ * 2010.350952  MBSY2C_energy
+ * 0.000000  PSPECIRBCK
+ * 2.190000  HPS:LS450_2:FIELD
+ * -8974.000000  HPS:LS450_1:FIELD
+ * 2400.000000  MTIRBCK
+ * 3.882200  VCG2C21
+ * 4.579233  VCG2C21A
+ * 6.799115  VCG2C24A
+ * 6.552529  VCG2H00A
+ * 5.429465  VCG2H01A
+ * 5.741360  VCG2H02A
+ * -0.069630  scaler_calc1
+ * 0.000000  scalerS12b
+ * 0.000000  scalerS13b
+ * 0.000000  scalerS14b
+ * 0.000000  scalerS15b
+ * 0.000000  hallb_IPM2C21A_XPOS
+ * 0.000000  hallb_IPM2C21A_YPOS
+ * 0.000000  hallb_IPM2C21A_CUR
+ * 0.000000  hallb_IPM2C24A_XPOS
+ * 0.000000  hallb_IPM2C24A_YPOS
+ * 0.000000  hallb_IPM2C24A_CUR
+ * 0.000000  hallb_IPM2H00_XPOS
+ * 0.000000  hallb_IPM2H00_YPOS
+ * 0.000000  hallb_IPM2H00_XPOS
+ * 0.000000  hallb_IPM2H00_XPOS
+ * 0.000000  hallb_IPM2H00_CUR
+ * 0.000000  hallb_IPM2H02_YPOS
+ * 0.000000  hallb_IPM2H02_XPOS
+ * </pre>   
+ * 
+ * @author Jeremy McCormick <[log in to unmask]>
+*/
+// TODO: This API needs to be accessible to recon and analysis modules.
+public final class EpicsScalarData extends LinkedHashMap<String, Double> {
+    
+    // Used in collection parameter map as name of the key list.
+    static final String EPICS_SCALAR_NAMES = "EPICS_SCALAR_NAMES";
+    
+    // Default collection name in the LCIO event.
+    static final String DEFAULT_COLLECTION_NAME = "EpicsScalarData";
+    
+    // Dummy collection parameter maps to try and make LCIO happy.
+    static final Map<String, int[]> DUMMY_INT_MAP = new HashMap<String, int[]>();    
+    static final Map<String, float[]> DUMMY_FLOAT_MAP = new HashMap<String, float[]>();
+   
+    /**
+     * Convert this object to a string.
+     */
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+        for (Entry<String, Double> entry : this.entrySet()) {
+            sb.append(entry.getKey() + " " + entry.getValue() + '\n');
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Parse a raw data string from the EVIO data bank and
+     * turn it into a list of keys and values within this object. 
+     * @param rawData The raw data in the form of a string.
+     */
+    void fromString(String rawData) {
+        String lines[] = rawData.split("\\r?\\n");
+        for (String line : lines) {
+            String trimmed = line.trim();
+            if (trimmed.length() == 0) {
+                continue;
+            }
+            String[] data = trimmed.split("  ");
+            Double value = Double.parseDouble(data[0]);
+            String key = data[1];
+            System.out.println("adding key, value: " + data[1] + " " + data[0]);
+            put(key, value);
+        }
+    }
+
+    /**
+     * Convert this object into a {@link org.lcsim.event.GenericObject} 
+     * that can be written into an LCIO collection.
+     * @return The GenericObject representing this data.
+     */
+    EpicsGenericObject toGenericObject() {
+        EpicsGenericObject newObject = new EpicsGenericObject();
+        newObject.keys = new String[this.size()];
+        newObject.values = new double[this.size()];
+        int index = 0;
+        for (String key : this.keySet()) {
+            newObject.keys[index] = key;
+            newObject.values[index] = this.get(key);
+            index++;
+        }
+        return newObject;
+    }
+
+    /**
+     * Given a list of keys, read the double values from the 
+     * {@link org.lcsim.event.GenericObject} into the map.
+     * @param object
+     * @param keys
+     */
+    void fromGenericObject(GenericObject object, String[] keys) {
+        for (int index = 0; index < keys.length; index++) {
+            this.put(keys[index], object.getDoubleVal(index));
+        }
+    }
+
+    /**
+     * Write this object into an LCIO event under the given collection name.
+     * @param event The LCIO event.
+     * @param collectionName The name of the collection in the event.
+     */
+    void write(EventHeader event, String collectionName) {
+        List<GenericObject> collection = new ArrayList<GenericObject>();
+        EpicsGenericObject object = this.toGenericObject();
+        collection.add(object);
+        Map<String, String[]> stringMap = new HashMap<String, String[]>();
+        stringMap.put(EPICS_SCALAR_NAMES, object.keys);
+        event.put(collectionName, collection, GenericObject.class, 0, DUMMY_INT_MAP, DUMMY_FLOAT_MAP, stringMap);
+    }
+    
+    /**
+     * Write this object into an LCIO event using the default collection name.
+     * @param event The LCIO event.
+     */
+    void write(EventHeader event) {
+        write(event, DEFAULT_COLLECTION_NAME);
+    }
+
+    /**
+     * Read data into this object from an LCIO event from the given collection name.
+     * @param event The LCIO event.
+     * @param collectionName The collection name.
+     * @return The EPICS data from the LCIO event.
+     */
+    EpicsScalarData read(EventHeader event, String collectionName) {
+        List<GenericObject> collection = event.get(GenericObject.class, collectionName);
+        @SuppressWarnings("rawtypes")
+        Map stringMap = event.getMetaData(collection).getStringParameters();
+        String[] keys = (String[]) stringMap.get(EPICS_SCALAR_NAMES);
+        EpicsScalarData data = new EpicsScalarData();
+        data.fromGenericObject(collection.get(0), keys);
+        return data;
+    }
+    
+    /**
+     * Read data into this object from an LCIO event using the default collection name.
+     * This is the primary method for users to read the EPICS data into their Drivers
+     * in the <code>process</code> method.         
+     * @param event The LCIO event. 
+     * @return The EPICS data from the event.
+     */
+    public EpicsScalarData read(EventHeader event) {
+        return read(event, DEFAULT_COLLECTION_NAME);
+    }
+}

Added: java/trunk/evio/src/test/java/org/hps/evio/epics/EpicsScalarDataTest.java
 =============================================================================
--- java/trunk/evio/src/test/java/org/hps/evio/epics/EpicsScalarDataTest.java	(added)
+++ java/trunk/evio/src/test/java/org/hps/evio/epics/EpicsScalarDataTest.java	Mon Mar 23 16:23:56 2015
@@ -0,0 +1,28 @@
+package org.hps.evio.epics;
+
+import junit.framework.TestCase;
+
+import org.hps.record.composite.CompositeLoop;
+import org.hps.record.composite.CompositeLoopConfiguration;
+import org.hps.record.enums.DataSourceType;
+import org.hps.record.enums.ProcessingStage;
+
+public class EpicsScalarDataTest extends TestCase {
+    
+    public void test() {
+        
+        CompositeLoopConfiguration configuration = new CompositeLoopConfiguration();
+        configuration.add(new EpicsEvioProcessor());
+        configuration.setDataSourceType(DataSourceType.EVIO_FILE);
+        configuration.setFilePath("/u1/data/hps/eng_run/hps_004385.evio.0");
+        configuration.setProcessingStage(ProcessingStage.EVIO);
+        configuration.setStopOnEndRun(false);
+        configuration.setStopOnErrors(false);
+        
+        CompositeLoop loop = new CompositeLoop();
+        loop.setConfiguration(configuration);
+        
+        loop.loop(-1);        
+    }
+
+}