Author: [log in to unmask]
Date: Tue Aug 4 15:10:48 2015
New Revision: 3332
Log:
Add persistency of EPICS header to LCIO. HPSJAVA-567
Added:
java/trunk/record-util/src/main/java/org/hps/record/epics/EpicsHeader.java
Modified:
java/trunk/record-util/src/main/java/org/hps/record/epics/EpicsData.java
java/trunk/record-util/src/main/java/org/hps/record/epics/EpicsEvioProcessor.java
java/trunk/record-util/src/main/java/org/hps/record/epics/EpicsGenericObject.java
Modified: java/trunk/record-util/src/main/java/org/hps/record/epics/EpicsData.java
=============================================================================
--- java/trunk/record-util/src/main/java/org/hps/record/epics/EpicsData.java (original)
+++ java/trunk/record-util/src/main/java/org/hps/record/epics/EpicsData.java Tue Aug 4 15:10:48 2015
@@ -14,7 +14,8 @@
/**
* This is an API for reading and writing EPICS data to LCIO events, as well as parsing the data from a CDATA section
* within an EVIO string data bank. The {@link #read(EventHeader)} method should be used to create one of these objects
- * from an LCIO event.
+ * from an LCIO event. The keys are stored in the string parameters of the collection, because
+ * <code>GenericObject</code> cannot persist string data.
*
* @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
*/
@@ -26,80 +27,79 @@
private static final String DEFAULT_COLLECTION_NAME = "EpicsData";
/**
- * This map contains the list of EPICS key descriptions from the<br/>
+ * Dummy float parameters to make LCIO persistency work.
+ */
+ private static final Map<String, float[]> DUMMY_FLOAT_MAP = new HashMap<String, float[]>();
+
+ /**
+ * Dummy int parameters to make LCIO persistency work.
+ */
+ private static final Map<String, int[]> DUMMY_INT_MAP = new HashMap<String, int[]>();
+
+ /**
+ * Collection parameter that has the EPICS variable names.
+ */
+ private static final String EPICS_VARIABLE_NAMES = "EPICS_VARIABLE_NAMES";
+
+ /**
+ * This map contains the list of EPICS keys and their descriptions from the<br/>
* <a href="https://confluence.slac.stanford.edu/display/hpsg/EVIO+Data+Format">EVIO Data Format Confluence Page</a>
*/
- private final static Map<String, String> DESCRIPTIONS = new HashMap<String, String>();
-
- /**
- * Dummy float parameters to make LCIO persistency work.
- */
- private static final Map<String, float[]> DUMMY_FLOAT_MAP = new HashMap<String, float[]>();
-
- /**
- * Dummy int parameters to make LCIO persistency work.
- */
- private static final Map<String, int[]> DUMMY_INT_MAP = new HashMap<String, int[]>();
-
- /**
- * Collection parameter that has the EPICS variable names.
- */
- private static final String EPICS_VARIABLE_NAMES = "EPICS_VARIABLE_NAMES";
-
- /**
- * List of descriptions.
- */
- // FIXME: Maybe this should not be listed here.
+ private final static Map<String, String> VARIABLES = new HashMap<String, String>();
+
+ /**
+ * List of possible EPICS keys.
+ */
static {
- DESCRIPTIONS.put("MBSY2C_energy", "Beam energy according to Hall B BSY dipole string");
- DESCRIPTIONS.put("PSPECIRBCK", "Pair Spectrometer Current Readback");
- DESCRIPTIONS.put("HPS:LS450_2:FIELD", "Frascati probe field");
- DESCRIPTIONS.put("HPS:LS450_1:FIELD", "Pair Spectrometer probe field");
- DESCRIPTIONS.put("MTIRBCK", "Frascati Current Readback");
- DESCRIPTIONS.put("VCG2C21 2C21", "Vacuum gauge pressure");
- DESCRIPTIONS.put("VCG2C21A", "2C21A Vacuum gauge pressure");
- DESCRIPTIONS.put("VCG2C24A", "2C24A Vacuum gauge pressure");
- DESCRIPTIONS.put("VCG2H00A", "2H00 Vacuum gauge pressure");
- DESCRIPTIONS.put("VCG2H01A", "2H01 Vacuum gauge pressure");
- DESCRIPTIONS.put("VCG2H02A", "2H02 Vacuum gauge pressure");
- DESCRIPTIONS.put("scaler_calc1", "Faraday cup current");
- DESCRIPTIONS.put("scalerS12b", "HPS-Left beam halo count");
- DESCRIPTIONS.put("scalerS13b", "HPS-Right beam halo count");
- DESCRIPTIONS.put("scalerS14b", "HPS-Top beam halo count");
- DESCRIPTIONS.put("scalerS15b", "HPS-SC beam halo count");
- DESCRIPTIONS.put("hallb_IPM2C21A_XPOS", "Beam position X at 2C21");
- DESCRIPTIONS.put("hallb_IPM2C21A_YPOS", "Beam position Y at 2C21");
- DESCRIPTIONS.put("hallb_IPM2C21A_CUR", "Current at 2C21");
- DESCRIPTIONS.put("hallb_IPM2C24A_XPOS", "Beam position X at 2C24");
- DESCRIPTIONS.put("hallb_IPM2C24A_YPOS", "Beam position Y at 2C24");
- DESCRIPTIONS.put("hallb_IPM2C24A_CUR", "Current at 2C24");
- DESCRIPTIONS.put("hallb_IPM2H00_XPOS", "Beam position X at 2H00");
- DESCRIPTIONS.put("hallb_IPM2H00_YPOS", "Beam position Y at 2H00");
- DESCRIPTIONS.put("hallb_IPM2H00_CUR", "Current at 2H00");
- DESCRIPTIONS.put("hallb_IPM2H02_YPOS", "Beam position X at 2H02");
- DESCRIPTIONS.put("hallb_IPM2H02_XPOS", "Beam position Y at 2H02");
+ VARIABLES.put("MBSY2C_energy", "Beam energy according to Hall B BSY dipole string");
+ VARIABLES.put("PSPECIRBCK", "Pair Spectrometer Current Readback");
+ VARIABLES.put("HPS:LS450_2:FIELD", "Frascati probe field");
+ VARIABLES.put("HPS:LS450_1:FIELD", "Pair Spectrometer probe field");
+ VARIABLES.put("MTIRBCK", "Frascati Current Readback");
+ VARIABLES.put("VCG2C21 2C21", "Vacuum gauge pressure");
+ VARIABLES.put("VCG2C21A", "2C21A Vacuum gauge pressure");
+ VARIABLES.put("VCG2C24A", "2C24A Vacuum gauge pressure");
+ VARIABLES.put("VCG2H00A", "2H00 Vacuum gauge pressure");
+ VARIABLES.put("VCG2H01A", "2H01 Vacuum gauge pressure");
+ VARIABLES.put("VCG2H02A", "2H02 Vacuum gauge pressure");
+ VARIABLES.put("scaler_calc1", "Faraday cup current");
+ VARIABLES.put("scalerS12b", "HPS-Left beam halo count");
+ VARIABLES.put("scalerS13b", "HPS-Right beam halo count");
+ VARIABLES.put("scalerS14b", "HPS-Top beam halo count");
+ VARIABLES.put("scalerS15b", "HPS-SC beam halo count");
+ VARIABLES.put("hallb_IPM2C21A_XPOS", "Beam position X at 2C21");
+ VARIABLES.put("hallb_IPM2C21A_YPOS", "Beam position Y at 2C21");
+ VARIABLES.put("hallb_IPM2C21A_CUR", "Current at 2C21");
+ VARIABLES.put("hallb_IPM2C24A_XPOS", "Beam position X at 2C24");
+ VARIABLES.put("hallb_IPM2C24A_YPOS", "Beam position Y at 2C24");
+ VARIABLES.put("hallb_IPM2C24A_CUR", "Current at 2C24");
+ VARIABLES.put("hallb_IPM2H00_XPOS", "Beam position X at 2H00");
+ VARIABLES.put("hallb_IPM2H00_YPOS", "Beam position Y at 2H00");
+ VARIABLES.put("hallb_IPM2H00_CUR", "Current at 2H00");
+ VARIABLES.put("hallb_IPM2H02_YPOS", "Beam position X at 2H02");
+ VARIABLES.put("hallb_IPM2H02_XPOS", "Beam position Y at 2H02");
+ }
+
+ /**
+ * Get the description of a named EPICS variable.
+ *
+ * @param name the name of the variable
+ */
+ public static String getVariableDescription(final String name) {
+ return VARIABLES.get(name);
}
/**
* Get the static list of all available EPICs variable names.
* <p>
* This could be different than the variable names which were actually written into the collection header. For this,
- * instead use the method {@link #getKeys()}.
+ * instead use the method {@link #getKeys()} method.
*
* @return the set of default EPICS variable names
*/
- public static Set<String> getDefaultKeys() {
- return DESCRIPTIONS.keySet();
+ public static Set<String> getVariableNames() {
+ return VARIABLES.keySet();
};
-
- /**
- * Get the description of a named EPICS variable.
- *
- * @param name the name of the variable
- */
- public static String getDescription(final String name) {
- return DESCRIPTIONS.get(name);
- }
/**
* <p>
@@ -142,6 +142,26 @@
private final Map<String, Double> dataMap = new LinkedHashMap<String, Double>();
/**
+ * The EPICS header information.
+ */
+ private EpicsHeader epicsHeader;
+
+ /**
+ * Class constructor.
+ */
+ public EpicsData() {
+ }
+
+ /**
+ * Class constructor that parses string data.
+ *
+ * @param data the string data
+ */
+ EpicsData(final String data) {
+ this.fromString(data);
+ }
+
+ /**
* Given a list of names, read the double values from the {@link org.lcsim.event.GenericObject} into the data map of
* this object.
*
@@ -149,8 +169,16 @@
* @param names The list of names.
*/
private void fromGenericObject(final GenericObject object, final String[] names) {
+
+ // Read data from double array.
for (int index = 0; index < names.length; index++) {
this.dataMap.put(names[index], object.getDoubleVal(index));
+ }
+
+ // Read header data if set.
+ if (object.getNInt() > 0) {
+ final int[] headerData = new int[] {object.getIntVal(0), object.getIntVal(1), object.getIntVal(2)};
+ this.epicsHeader = new EpicsHeader(headerData);
}
}
@@ -174,10 +202,17 @@
}
/**
+ * Get the EPICS header information or <code>null</code> if not set.
+ */
+ public EpicsHeader getEpicsHeader() {
+ return this.epicsHeader;
+ }
+
+ /**
* Get the list of EPICS variables used by this object.
* <p>
- * This could potentially be different than the list of default names from {@link #getDefaultKeys()} but it will
- * usually be the same.
+ * This could potentially be different than the list of default names from {@link #getVariableNames()} as not all
+ * variables are included in every EPICS event.
*
* @return the list of used EPICS variable names
*/
@@ -186,7 +221,7 @@
}
/**
- * Get a double value from the key which should be a valid EPICS variable name.
+ * Get a double value from the key, which should be a valid EPICS variable name.
*
* @return the value from the key
*/
@@ -204,6 +239,15 @@
}
/**
+ * Set the EPICS header information.
+ *
+ * @param epicsHeader the {@link EpicsHeader} object
+ */
+ void setEpicsHeader(final EpicsHeader epicsHeader) {
+ this.epicsHeader = epicsHeader;
+ }
+
+ /**
* Set a double value by name.
*
* @return the value from the key
@@ -218,15 +262,28 @@
* @return the <code>GenericObject</code> representing this data
*/
private EpicsGenericObject toGenericObject() {
+
+ // Create new GenericObject.
final EpicsGenericObject newObject = new EpicsGenericObject();
+
newObject.setKeys(new String[this.dataMap.size()]);
newObject.setValues(new double[this.dataMap.size()]);
+
int index = 0;
for (final String key : this.dataMap.keySet()) {
newObject.setKey(index, key);
newObject.setValue(index, this.dataMap.get(key));
index++;
}
+
+ // Write header information into the object's int array.
+ if (epicsHeader != null) {
+ final int[] headerData = new int[] {
+ epicsHeader.getRun(),
+ epicsHeader.getSequence(),
+ epicsHeader.getTimeStamp()};
+ newObject.setHeaderData(headerData);
+ }
return newObject;
}
@@ -261,9 +318,13 @@
* @param collectionName the name of the collection in the output event
*/
private void write(final EventHeader event, final String collectionName) {
+
+ // Create the new collection and add the GenericObject to it.
final List<GenericObject> collection = new ArrayList<GenericObject>();
final EpicsGenericObject object = this.toGenericObject();
collection.add(object);
+
+ // Write out the collection to the event, including the string parameters with the key names.
final Map<String, String[]> stringMap = new HashMap<String, String[]>();
stringMap.put(EPICS_VARIABLE_NAMES, object.getKeys());
event.put(collectionName, collection, GenericObject.class, 0, DUMMY_INT_MAP, DUMMY_FLOAT_MAP, stringMap);
Modified: java/trunk/record-util/src/main/java/org/hps/record/epics/EpicsEvioProcessor.java
=============================================================================
--- java/trunk/record-util/src/main/java/org/hps/record/epics/EpicsEvioProcessor.java (original)
+++ java/trunk/record-util/src/main/java/org/hps/record/epics/EpicsEvioProcessor.java Tue Aug 4 15:10:48 2015
@@ -17,7 +17,7 @@
*
* @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
*/
-public final class EpicsEvioProcessor extends EvioEventProcessor {
+public class EpicsEvioProcessor extends EvioEventProcessor {
/**
* Setup class logger.
@@ -55,12 +55,22 @@
// Find the bank with the EPICS data string.
final BaseStructure epicsBank = EvioBankTag.EPICS_STRING.findBank(evio);
- // Was EPICS data found?
+ // Was EPICS data found in the event?
if (epicsBank != null) {
+
// Create EpicsData object from bank's string data.
- final String epicsData = epicsBank.getStringData()[0];
- this.data = new EpicsData();
- this.data.fromString(epicsData);
+ this.data = new EpicsData(epicsBank.getStringData()[0]);
+
+ // Find the header information in the event.
+ final BaseStructure headerBank = EvioBankTag.EPICS_HEADER.findBank(evio);
+
+ if (headerBank != null) {
+ // Set the header object.
+ this.data.setEpicsHeader(EpicsHeader.fromEvio(headerBank.getIntData()));
+ } else {
+ LOGGER.warning("No EPICS header bank found in event.");
+ }
+
} else {
// This is an error because the string data bank should always be present in EPICS events.
final RuntimeException x = new RuntimeException("No EPICS data bank found in EPICS event.");
@@ -69,7 +79,7 @@
}
}
}
-
+
/**
* Reset the current <code>EpicsData</code> object to <code>null</code>.
*/
Modified: java/trunk/record-util/src/main/java/org/hps/record/epics/EpicsGenericObject.java
=============================================================================
--- java/trunk/record-util/src/main/java/org/hps/record/epics/EpicsGenericObject.java (original)
+++ java/trunk/record-util/src/main/java/org/hps/record/epics/EpicsGenericObject.java Tue Aug 4 15:10:48 2015
@@ -3,12 +3,18 @@
import org.lcsim.event.GenericObject;
/**
- * This is an implementation of GenericObject for reading and writing EPICS data. There is no functionality here intended for ends users. Instead, the
- * EPICS data should be accessed using {@link EpicsData#read(org.lcsim.event.EventHeader)} to create the data object from input event data.
+ * This is an implementation of GenericObject for reading and writing EPICS data. There is no functionality here
+ * intended for ends users. Instead, the EPICS data should be accessed using
+ * {@link EpicsData#read(org.lcsim.event.EventHeader)} to create the data object from input event data.
*
* @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
*/
final class EpicsGenericObject implements GenericObject {
+
+ /**
+ * The header information.
+ */
+ private int[] headerData;
/**
* The names of the EPICS variables.
@@ -37,7 +43,7 @@
@Override
public int getIntVal(final int index) {
- return 0;
+ return headerData[index];
}
/**
@@ -76,7 +82,7 @@
@Override
public int getNInt() {
- return 0;
+ return this.headerData.length;
}
/**
@@ -85,6 +91,15 @@
@Override
public boolean isFixedSize() {
return false;
+ }
+
+ /**
+ * Set the header data.
+ *
+ * @param data the header data array
+ */
+ void setHeaderData(final int[] headerData) {
+ this.headerData = headerData;
}
/**
Added: java/trunk/record-util/src/main/java/org/hps/record/epics/EpicsHeader.java
=============================================================================
--- java/trunk/record-util/src/main/java/org/hps/record/epics/EpicsHeader.java (added)
+++ java/trunk/record-util/src/main/java/org/hps/record/epics/EpicsHeader.java Tue Aug 4 15:10:48 2015
@@ -0,0 +1,80 @@
+package org.hps.record.epics;
+
+/**
+ * Representation of EPICs header data (run, sequence, time stamp).
+ *
+ * @author Jeremy McCormick, SLAC
+ */
+public final class EpicsHeader {
+
+ /**
+ * Create an {@link EpicsHeader} from an int array in the EVIO bank.
+ * <p>
+ * This reads in indices 1 to 3 as 0 and 5 are unused.
+ *
+ * @param headerBank the header bank data
+ * @return the {@link EpicsHeader} object
+ */
+ static EpicsHeader fromEvio(final int[] headerBank) {
+ final int[] headerData = new int[] {headerBank[1], headerBank[2], headerBank[3]};
+ return new EpicsHeader(headerData);
+ }
+
+ /**
+ * The run number.
+ */
+ private final int run;
+
+ /**
+ * The sequence number.
+ */
+ private final int sequence;
+
+ /**
+ * The time stamp in seconds (Unix).
+ */
+ private final int timestamp;
+
+ /**
+ * Class constructor.
+ * <p>
+ * The data array should be length 3 and usually will come from the int data of a <code>GenericObject</code>.
+ *
+ * @param data the header data with length 3
+ */
+ public EpicsHeader(final int[] data) {
+ if (data.length != 3) {
+ throw new IllegalArgumentException("Bad array length: " + data.length);
+ }
+ run = data[0];
+ sequence = data[1];
+ timestamp = data[2];
+ }
+
+ /**
+ * Get the run number.
+ *
+ * @return the run number
+ */
+ public int getRun() {
+ return run;
+ }
+
+ /**
+ * Get the sequence number.
+ *
+ * @return the sequence number
+ */
+ public int getSequence() {
+ return sequence;
+ }
+
+ /**
+ * Get the time stamp.
+ *
+ * @return the time stamp
+ */
+ public int getTimeStamp() {
+ return timestamp;
+ }
+}
|