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;
+ }
+}
|