Print

Print


Author: [log in to unmask]
Date: Thu Jun  4 09:23:09 2015
New Revision: 3088

Log:
Add tools for getting opening angle information from MYA (still work in progress).

Added:
    java/trunk/conditions/src/main/java/org/hps/conditions/svt/MotorPositionLoader.java
    java/trunk/conditions/src/main/java/org/hps/conditions/svt/OpeningAngleLoader.java
Modified:
    java/trunk/conditions/src/main/java/org/hps/conditions/run/RunSpreadsheet.java

Modified: java/trunk/conditions/src/main/java/org/hps/conditions/run/RunSpreadsheet.java
 =============================================================================
--- java/trunk/conditions/src/main/java/org/hps/conditions/run/RunSpreadsheet.java	(original)
+++ java/trunk/conditions/src/main/java/org/hps/conditions/run/RunSpreadsheet.java	Thu Jun  4 09:23:09 2015
@@ -4,6 +4,10 @@
 import java.io.FileNotFoundException;
 import java.io.FileReader;
 import java.io.IOException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.LinkedHashMap;
 import java.util.List;
 
 import org.apache.commons.csv.CSVFormat;
@@ -36,10 +40,17 @@
      *
      * @param args the command line arguments
      */
-    public static void main(final String args[]) {
+    public static void main(final String args[]) throws Exception {
         final RunSpreadsheet runSpreadsheet = new RunSpreadsheet(new File(args[0]));
         for (final CSVRecord record : runSpreadsheet.getRecords()) {
-            System.out.println(record);
+            try {
+                System.out.print("start date: " + parseStartDate(record) + ", ");
+                System.out.print("end date: " + parseEndDate(record) + ", ");
+                System.out.print(record);
+                System.out.println();
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
         }
     }
 
@@ -118,4 +129,79 @@
     public List<CSVRecord> getRecords() {
         return records;
     }
+    
+    private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("MM/dd/yyyy H:mm"); 
+    
+    private static Date parseStartDate(CSVRecord record) throws ParseException {
+        return DATE_FORMAT.parse(record.get("date") + " " + record.get("start_time"));
+    }
+    
+    private static Date parseEndDate(CSVRecord record) throws ParseException {
+        return DATE_FORMAT.parse(record.get("date") + " " + record.get("end_time"));
+    }
+    
+    private static int parseRunNumber(CSVRecord record) throws NumberFormatException {
+        return Integer.parseInt(record.get("run"));
+    }
+    
+    public static class RunData {
+        
+        private int run;
+        private Date startDate;
+        private Date endDate;
+        private CSVRecord record;
+        
+        RunData(CSVRecord record) throws NumberFormatException {
+            this.record = record;
+            run = parseRunNumber(this.record);
+            try {
+                startDate = RunSpreadsheet.parseStartDate(this.record);
+            } catch (ParseException e) {                
+            }
+            try {
+                endDate = RunSpreadsheet.parseEndDate(this.record);
+            } catch (ParseException e) {                
+            }
+        }
+        
+        public int getRun() {
+            return run;
+        }
+        
+        public Date getStartDate() {
+            return startDate;
+        }
+        
+        public Date getEndDate() {
+            return endDate;
+        }      
+        
+        public String toString() {
+            return "RunData { run: " + run + ", startDate: " + startDate + ", endDate: " + endDate + " }";
+        }
+        
+        public CSVRecord getRecord() {
+            return record;
+        }
+    }
+    
+    @SuppressWarnings("serial")
+    public static class RunMap extends LinkedHashMap<Integer, RunData> {
+        
+        private void addRunData(RunData runData) {
+            this.put(runData.getRun(), runData);
+        }
+    }
+    
+    public RunMap getRunMap() {
+        RunMap runMap = new RunMap();
+        for (final CSVRecord record : getRecords()) {
+            try {
+                runMap.addRunData(new RunData(record));
+            } catch (NumberFormatException e) {
+                e.printStackTrace();
+            }
+        }
+        return runMap;
+    }    
 }

Added: java/trunk/conditions/src/main/java/org/hps/conditions/svt/MotorPositionLoader.java
 =============================================================================
--- java/trunk/conditions/src/main/java/org/hps/conditions/svt/MotorPositionLoader.java	(added)
+++ java/trunk/conditions/src/main/java/org/hps/conditions/svt/MotorPositionLoader.java	Thu Jun  4 09:23:09 2015
@@ -0,0 +1,278 @@
+package org.hps.conditions.svt;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.PosixParser;
+
+/**
+ * Load SVT motor positions from a MYA dump, figure out time ranges (same position for > 10 seconds), and then 
+ * convert the motor stage to an opening angle.
+ * <p>
+ * The calculated angle ranges are written out to a comma delimited text file with double-quoted field values.
+ *
+ * @author Jeremy McCormick
+ */
+public class MotorPositionLoader {
+
+    class MotorPositionInterval {
+
+        private final Date endDate;
+        private final Date startDate;
+        private final double angle;
+        private final double yStage;
+
+        MotorPositionInterval(final Date startDate, final Date endDate, final double angle, final double yStage) {
+            this.startDate = startDate;
+            this.endDate = endDate;
+            this.angle = angle;
+            this.yStage = yStage;
+        }
+
+        Date getEndDate() {
+            return endDate;
+        }
+
+        Date getStartDate() {
+            return startDate;
+        }
+
+        double getAngle() {
+            return angle;
+        }
+        
+        double getYStage() {
+            return yStage;
+        }
+        
+        public String toString() {
+            return "MotorPositionInterval { start: " + startDate + ", end: " + endDate + ", angle: " + angle + ", yStage: " + yStage + " }";
+        }
+    }
+
+    private class MotorPositionMyaRecord {
+
+        private final Date date;
+        private final double position;
+
+        MotorPositionMyaRecord(final Date date, final double position) {
+            this.date = date;
+            this.position = position;
+        }
+
+        Date getDate() {
+            return date;
+        }
+
+        double getPosition() {
+            return position;
+        }
+    }
+
+    enum Side {
+        BOT, TOP
+    }
+
+    private static final double ANGLE_CONVERSION = 832.714;
+
+    private static final double BOTTOM_ANGLE_CONSTANT = 17.397;
+    //private static final double BOTTOM_LAYER_CONSTANT1 = 0.363;
+    //private static final double BOTTOM_LAYER_CONSTANT2 = -6.815;
+
+    private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
+    private static final long MIN_TIME_INTERVAL = 10000L;
+
+    private static final Options OPTIONS = new Options();
+
+    private static final double TOP_ANGLE_CONSTANT = 17.821;
+    //private static final double TOP_LAYER_CONSTANT1 = -0.391;
+    //private static final double TOP_LAYER_CONSTANT2 = 7.472;
+
+    static {
+        OPTIONS.addOption("h", "help", false, "print help");
+        OPTIONS.addOption("s", "side", true, "'top' or 'bot' (required)");
+        OPTIONS.getOption("s").setRequired(true);
+        OPTIONS.addOption("i", "input-file", true, "input text file dumped from MYA (required)");
+        OPTIONS.getOption("i").setRequired(true);
+        OPTIONS.addOption("o", "output-file", true, "output text file with computed angle intervals");
+        //OPTIONS.addOption("l", "layer", false, "write out layer 1 position instead of computed angle");
+    }
+    
+    public void setSide(Side side) {
+        this.side = side;
+        if (Side.TOP.equals(side)) {
+            this.motorConstant = TOP_ANGLE_CONSTANT;
+            //this.layerConstant1 = TOP_LAYER_CONSTANT1;
+            //this.layerConstant2 = TOP_LAYER_CONSTANT2;
+        } else if (Side.BOT.equals(side)) {
+            this.motorConstant = BOTTOM_ANGLE_CONSTANT;
+            //this.layerConstant1 = BOTTOM_LAYER_CONSTANT1;
+            //this.layerConstant2 = BOTTOM_LAYER_CONSTANT2;
+        }
+    }
+        
+    /**
+     * Run from command line arguments.
+     * 
+     * @param args
+     */
+    void run(final String args[]) {
+        
+        final PosixParser parser = new PosixParser();
+        
+        CommandLine cl = null;        
+        try {
+            cl = parser.parse(OPTIONS, args);
+        } catch (final Exception e) {
+            printUsage(1);
+            throw new RuntimeException();
+        }
+
+        if (cl.hasOption("h")) {
+            printUsage(0);
+        }
+
+        if (cl.hasOption("s")) {
+            setSide(Side.valueOf(cl.getOptionValue("s").toUpperCase()));
+        } else {
+            printUsage(0);
+        }
+        
+        this.setSide(side);
+                
+        String path = null;
+        if (cl.hasOption("i")) {
+            path = cl.getOptionValue("i");
+        } else {
+            printUsage(1);
+        }
+
+        //if (cl.hasOption("l")) {
+        //    setWriteLayerPosition(true);
+        //}
+
+        try {
+            load(path);
+        } catch (final Exception e) {
+            throw new RuntimeException(e);
+        }
+
+        // Find the time intervals with a certain motor position setting.
+        findIntervals();
+
+        if (cl.hasOption("o")) {
+            final String outputPath = cl.getOptionValue("o");
+            try {
+                toCsv(outputPath);
+            } catch (final IOException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    public static void main(final String args[]) {        
+        new MotorPositionLoader().run(args);
+    }
+
+    /**
+     * Print the usage statement for this tool to the console.
+     */
+    private static final void printUsage(final int status) {
+        final HelpFormatter help = new HelpFormatter();
+        help.printHelp("MotorPositionLoader", "", OPTIONS, "");
+        System.exit(status);
+    }
+
+    private List<MotorPositionInterval> intervals;
+
+    //private double layerConstant1;
+    //private double layerConstant2;
+
+    private double motorConstant;
+
+    private List<MotorPositionMyaRecord> records;
+
+    //private boolean writeLayerPosition = false;
+    
+    Side side = null;
+
+    MotorPositionLoader() {
+    }
+
+    private double computeAngle(final double yStage) {
+        double angle = (motorConstant - yStage) / ANGLE_CONVERSION;
+        if (Side.BOT.equals(side)) {
+            angle = -angle;
+        }
+        return angle;
+    }
+
+    //private double computeLayer1Position(final double yStage) {
+    //    return layerConstant1 * yStage + layerConstant2;
+    //}
+
+    List<MotorPositionInterval> findIntervals() {
+        intervals = new ArrayList<MotorPositionInterval>();
+        for (int i = 0; i < records.size() - 1; i++) {
+            final Date currentDate = records.get(i).getDate();
+            final Date nextDate = records.get(i + 1).getDate();
+            final long timeDiff = nextDate.getTime() - currentDate.getTime();
+            if (timeDiff >= MIN_TIME_INTERVAL) {
+                final double yStage = records.get(i).getPosition();
+                double angle = this.computeAngle(yStage);
+                intervals.add(new MotorPositionInterval(currentDate, nextDate, angle, yStage));
+            }
+        }
+        return intervals;
+    }
+
+    void load(final String path) throws IOException, ParseException, FileNotFoundException {
+        records = new ArrayList<MotorPositionMyaRecord>();
+        try (BufferedReader br = new BufferedReader(new FileReader(path))) {
+            String line;
+            while ((line = br.readLine()) != null) {
+                final String dateString = line.substring(0, 19);
+                final String positionString = line.substring(20);
+                try {
+                    final Date date = DATE_FORMAT.parse(dateString);
+                    final double position = Double.parseDouble(positionString);
+                    records.add(new MotorPositionMyaRecord(date, position));
+                } catch (final NumberFormatException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+    //private void setWriteLayerPosition(final boolean writeLayer) {
+    //    this.writeLayerPosition = writeLayer;
+    //}
+
+    private void toCsv(final String path) throws IOException {
+        System.out.println("writing " + intervals.size() + " intervals to file to " + path + " ...");
+        final FileWriter fw = new FileWriter(new File(path));
+        final BufferedWriter bw = new BufferedWriter(fw);
+        for (final MotorPositionInterval interval : intervals) {
+            bw.write("\"" + DATE_FORMAT.format(interval.getStartDate()) + "\",");
+            bw.write("\"" + DATE_FORMAT.format(interval.getEndDate()) + "\",");
+            bw.write("\"" + interval.getAngle() + "\"");
+            bw.write('\n');
+        }
+        bw.close();
+        System.out.println("done writing intervals");
+    }
+}

Added: java/trunk/conditions/src/main/java/org/hps/conditions/svt/OpeningAngleLoader.java
 =============================================================================
--- java/trunk/conditions/src/main/java/org/hps/conditions/svt/OpeningAngleLoader.java	(added)
+++ java/trunk/conditions/src/main/java/org/hps/conditions/svt/OpeningAngleLoader.java	Thu Jun  4 09:23:09 2015
@@ -0,0 +1,133 @@
+package org.hps.conditions.svt;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+
+import org.hps.conditions.run.RunSpreadsheet;
+import org.hps.conditions.run.RunSpreadsheet.RunData;
+import org.hps.conditions.run.RunSpreadsheet.RunMap;
+import org.hps.conditions.svt.MotorPositionLoader.MotorPositionInterval;
+import org.hps.conditions.svt.MotorPositionLoader.Side;
+
+public class OpeningAngleLoader {
+
+    private static final String TOP_FILE = "mya_svt_top.txt";
+    private static final String BOT_FILE = "mya_svt_bot.txt";
+    private static final String RUN_FILE = "runs.csv";
+    private static final String OUT_FILE = "svt_opening_angles.txt";
+    
+    private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("MMMM dd YYYY HH:mm z");
+    
+    public static void main(String[] args) throws Exception {
+        
+        // Load top and bottom intervals from MYA dump.
+        List<MotorPositionInterval> topIntervals = getMotorPositionIntervals(TOP_FILE, Side.TOP);
+        List<MotorPositionInterval> botIntervals = getMotorPositionIntervals(BOT_FILE, Side.BOT);
+        
+        // Load run map from spreadsheet.
+        RunMap runMap = loadRunMap(RUN_FILE);
+        
+        // Write out run data combined with SVT opening angle intervals.
+        PrintStream ps = new PrintStream(new FileOutputStream(OUT_FILE));
+        for (final RunData data : runMap.values()) {
+            if (acceptRun(data)) {
+                final MotorPositionInterval topInterval = findInterval(topIntervals, data.getStartDate());
+                final MotorPositionInterval botInterval = findInterval(botIntervals, data.getStartDate());
+                printLine(ps, data, topInterval, botInterval);
+            }
+        }        
+        ps.close();
+    }
+    
+    private static void printLine(PrintStream ps, RunData data, MotorPositionInterval topInterval, MotorPositionInterval botInterval) {
+        ps.print("run: " + data.getRun() + " @ [" + data.getRecord().get("svt_y_position") + "], ");
+        if (topInterval != null) {
+            ps.print("start(top): " + DATE_FORMAT.format(topInterval.getStartDate()) + ", ");
+            ps.print("end(top): " + DATE_FORMAT.format(topInterval.getEndDate()) + ", ");
+        } else if (botInterval != null) {
+            ps.print("start(bot): " + DATE_FORMAT.format(botInterval.getStartDate()) + ", ");
+            ps.print("end(bot): " + DATE_FORMAT.format(botInterval.getEndDate()) + ", ");
+        } else {
+            ps.print("start: NONE, end: NONE, ");
+        }
+        ps.print("topAngle: ");
+        if (topInterval != null) {
+            ps.print(topInterval.getAngle());
+        } else {
+            ps.print("NONE");
+        }
+        ps.print(", botAngle: ");
+        if (botInterval != null) {
+            ps.print(botInterval.getAngle());
+        } else {
+            ps.print("NONE");
+        }
+        ps.print(", topYStage: ");
+        if (topInterval != null) {
+            ps.print(topInterval.getYStage());
+        } else {
+            ps.print("NONE");
+        }
+        ps.print(", botYStage: ");
+        if (botInterval != null) {
+            ps.print(botInterval.getYStage());
+        } else {
+            ps.print("NONE");
+        }
+        ps.println();
+        ps.flush();
+    }
+    
+    private static List<MotorPositionInterval> getMotorPositionIntervals(String path, Side side) throws Exception {
+        MotorPositionLoader loader = new MotorPositionLoader();
+        loader.setSide(side);
+        loader.load(path);
+        return loader.findIntervals();
+    }
+
+    /**
+     * Check if the run record looks good.
+     * 
+     * @param data
+     * @return
+     */
+    private static boolean acceptRun(RunData data) {
+        return !data.getRecord().get("to_tape").equals("JUNK") && data.getRecord().get("trigger_config").trim().length() > 0
+                && !data.getRecord().get("trigger_config").contains("cosmic") && data.getStartDate() != null;
+    }
+    
+    private static RunMap loadRunMap(String path) {
+        final File runFile = new File(path);
+        final RunSpreadsheet runSpreadsheet = new RunSpreadsheet(runFile);
+        return runSpreadsheet.getRunMap();
+    }
+
+    private static MotorPositionInterval findInterval(List<MotorPositionInterval> intervals, Date date) {
+        MotorPositionInterval interval = null;
+        Iterator<MotorPositionInterval> it = intervals.listIterator();
+        while ((interval = it.next()) != null) {
+                
+            // Start and end dates in the interval.
+            Date startDate = interval.getStartDate();
+            Date endDate = interval.getEndDate();
+
+            // Check if given date is within the interval.
+            if ((startDate.compareTo(date) == -1 || startDate.compareTo(date) == 0) && endDate.compareTo(date) == 1
+                    || endDate.compareTo(date) == 0) {
+                break;
+            }
+                
+            // Didn't find it.
+            if (!it.hasNext()) {
+                interval = null;
+                break;
+            }            
+        }
+        return interval;
+    }   
+}