| 1 | package de.uka.ipd.sdq.sensorframework.visualisation.rvisualisation.utils; |
| 2 | |
| 3 | import java.io.File; |
| 4 | import java.io.FileWriter; |
| 5 | import java.io.IOException; |
| 6 | import java.util.Vector; |
| 7 | |
| 8 | import org.eclipse.core.runtime.IStatus; |
| 9 | import org.rosuda.JRI.REXP; |
| 10 | |
| 11 | import de.uka.ipd.sdq.sensorframework.entities.Measurement; |
| 12 | import de.uka.ipd.sdq.sensorframework.entities.SensorAndMeasurements; |
| 13 | import de.uka.ipd.sdq.sensorframework.entities.TimeSpanMeasurement; |
| 14 | import de.uka.ipd.sdq.sensorframework.visualisation.rvisualisation.RVisualisationPlugin; |
| 15 | import de.uka.ipd.sdq.sensorframework.visualisation.rvisualisation.reports.RReport.TimeseriesData; |
| 16 | |
| 17 | /** |
| 18 | * Provides helper method for working with the R engine and the SensorFramework. |
| 19 | * The class offers methods for feeding sensor data into R and may later also |
| 20 | * provide methods for more complex commands and calculation. |
| 21 | * |
| 22 | * @author Anne |
| 23 | * |
| 24 | */ |
| 25 | public class REngineHelper { |
| 26 | |
| 27 | /**Transfer data to R by the specified type. |
| 28 | * @author groenda |
| 29 | */ |
| 30 | public enum TransferType { |
| 31 | /** Transfer by temporary files. */ |
| 32 | FILE, |
| 33 | /** Transfer by memory. */ |
| 34 | MEMORY |
| 35 | } |
| 36 | |
| 37 | /** The default setting for data transfer to R. */ |
| 38 | public static final TransferType TRANSFER_TYPE = TransferType.FILE; |
| 39 | |
| 40 | /** |
| 41 | * Convenience method, calls |
| 42 | * {@link #storeMeasurementsInRVector(SensorAndMeasurements, int, TimeseriesData, TransferType, RConnection)} |
| 43 | * with the standard {@link TransferType} which is |
| 44 | * <code>TransferType.MEMORY</code>. |
| 45 | * |
| 46 | * @param measurements Measurements for a sensor. |
| 47 | * @param sensorNumber number of the sensor vector in R. |
| 48 | * @param dataSelection the data element to save. |
| 49 | * @param rConnection Connection to the R engine. |
| 50 | * @return R variable name which contains the data. |
| 51 | */ |
| 52 | public static String storeMeasurementsInRVector( |
| 53 | final SensorAndMeasurements measurements, final int sensorNumber, |
| 54 | final TimeseriesData dataSelection, |
| 55 | final RConnection rConnection) { |
| 56 | return storeMeasurementsInRVector(measurements, sensorNumber, dataSelection, TRANSFER_TYPE, rConnection); |
| 57 | } |
| 58 | |
| 59 | /**Export the measurements of a sensor to R. |
| 60 | * There are two alternatives. The measurements can be transferred |
| 61 | * via an array, which implies certain size restrictions. An alternative is |
| 62 | * to use a temporary file. The behavior can only be switched in source |
| 63 | * code by the constant <code>TRANSFER_TYPE</code>. |
| 64 | * Variable names in R are as follows:<br /> |
| 65 | * For timespan data: "sensor" + #<br /> |
| 66 | * For eventtime data: "sensor" + # + "_ET")<br /> |
| 67 | * |
| 68 | * @param measurements Measurements for a sensor. |
| 69 | * @param sensorNumber number of the sensor vector in R. |
| 70 | * @param dataSelection the data element to save. |
| 71 | * @param rConnection Connection to the R engine. |
| 72 | * @return R variable name which contains the data. |
| 73 | */ |
| 74 | public static String storeMeasurementsInRVector( |
| 75 | final SensorAndMeasurements measurements, final int sensorNumber, |
| 76 | final TimeseriesData dataSelection, final TransferType transferType, |
| 77 | final RConnection rConnection) { |
| 78 | String sensorName = null; |
| 79 | |
| 80 | if (dataSelection == TimeseriesData.TIMESPAN) { |
| 81 | sensorName = "sensor" + sensorNumber; |
| 82 | } else |
| 83 | if (dataSelection == TimeseriesData.EVENTTIME) { |
| 84 | sensorName = "sensor" + sensorNumber + "_ET"; |
| 85 | } else { |
| 86 | throw new RuntimeException("Unknown data element of time series."); |
| 87 | } |
| 88 | |
| 89 | if (transferType == TransferType.MEMORY) { |
| 90 | // Activate to transfer data via memory |
| 91 | double[] measurementsArray = |
| 92 | prepareExportToRByMemory(measurements, dataSelection); |
| 93 | rConnection.assign(sensorName, measurementsArray); |
| 94 | } |
| 95 | if (transferType == TransferType.FILE) { |
| 96 | // Activate to transfer data via temporary file |
| 97 | String rCommand = sensorName + " <- " |
| 98 | + prepareExportToRByFile(measurements, dataSelection); |
| 99 | Vector<REXP> result = rConnection.execute(rCommand); |
| 100 | // Error handling |
| 101 | if (!rConnection.getLastConsoleMessage().equalsIgnoreCase("Read " |
| 102 | + measurements.getMeasurements().size() + " items\n")) { |
| 103 | String rResults = "Executing command: '" + rCommand + "' with "; |
| 104 | for (REXP currentResult : result) { |
| 105 | rResults += "String: " + currentResult.asString() |
| 106 | + ", SymbolName: " + currentResult.asSymbolName() |
| 107 | + ", Type: " + currentResult.getType() + "\n"; |
| 108 | } |
| 109 | RVisualisationPlugin.log(IStatus.INFO, |
| 110 | "Storing Measurements in R via file is most likely wrong. Last message " |
| 111 | + "on the console was: " + rConnection.getLastConsoleMessage() |
| 112 | + "R returned:\n" + rResults); |
| 113 | } |
| 114 | |
| 115 | } |
| 116 | return sensorName; |
| 117 | } |
| 118 | |
| 119 | /**Prepares the export the measurements of a sensor to R. Therefore an |
| 120 | * array is filled with the measurements. |
| 121 | * |
| 122 | * @param measurements Measurements for a sensor. |
| 123 | * @param dataSelection the data element to save. |
| 124 | * @return R command to read measurements. |
| 125 | * Can be used to store data in a r vector. |
| 126 | */ |
| 127 | private static double[] prepareExportToRByMemory( |
| 128 | final SensorAndMeasurements measurements, |
| 129 | final TimeseriesData dataSelection) { |
| 130 | double[] measurementsArray = |
| 131 | new double[measurements.getMeasurements().size()]; |
| 132 | if (measurements.getMeasurements().size() == Integer.MAX_VALUE) { |
| 133 | RVisualisationPlugin.log(IStatus.ERROR, |
| 134 | "Too many measurements. Results might be inaccurate."); |
| 135 | } |
| 136 | int position = 0; |
| 137 | for (Measurement time : measurements.getMeasurements()) { |
| 138 | TimeSpanMeasurement tsm = (TimeSpanMeasurement) time; |
| 139 | measurementsArray[position++] = |
| 140 | (dataSelection == TimeseriesData.EVENTTIME) |
| 141 | ? tsm.getEventTime() |
| 142 | : tsm.getTimeSpan(); |
| 143 | } |
| 144 | return measurementsArray; |
| 145 | } |
| 146 | |
| 147 | /**Prepares to export the measurements of a time series sensor to R. |
| 148 | * Therefore a temporary file is created and the R command line to |
| 149 | * import this data is returned. |
| 150 | * |
| 151 | * @param measurements Measurements for a sensor. |
| 152 | * @param dataSelection the data element to save. |
| 153 | * @return R command to read measurements. |
| 154 | * Can be used to store data in a r vector. |
| 155 | */ |
| 156 | private static String prepareExportToRByFile( |
| 157 | final SensorAndMeasurements measurements, |
| 158 | final TimeseriesData dataSelection) { |
| 159 | File temporaryFile; |
| 160 | try { |
| 161 | temporaryFile = File.createTempFile("data", |
| 162 | (dataSelection == TimeseriesData.EVENTTIME) |
| 163 | ? "_et.txt" |
| 164 | : "_ts.txt" |
| 165 | ); |
| 166 | temporaryFile.deleteOnExit(); |
| 167 | FileWriter temporaryFileWriter = new FileWriter(temporaryFile); |
| 168 | StringBuffer result = new StringBuffer(); |
| 169 | for (Measurement time : measurements.getMeasurements()) { |
| 170 | TimeSpanMeasurement tsm = (TimeSpanMeasurement) time; |
| 171 | result.append( |
| 172 | (dataSelection == TimeseriesData.EVENTTIME) |
| 173 | ? tsm.getEventTime() |
| 174 | : tsm.getTimeSpan() |
| 175 | ); |
| 176 | result.append(" "); |
| 177 | } |
| 178 | temporaryFileWriter.write(result.toString()); |
| 179 | temporaryFileWriter.close(); |
| 180 | return "scan(file=\"" |
| 181 | + temporaryFile.getAbsolutePath().replace("\\", |
| 182 | "\\\\") |
| 183 | + "\")"; |
| 184 | } catch (IOException e) { |
| 185 | RVisualisationPlugin.log(IStatus.ERROR, |
| 186 | "Error accessing temporary file to transfer sensordata " |
| 187 | + "to R. \n\n Details: " + e.getMessage()); |
| 188 | } |
| 189 | return ""; |
| 190 | } |
| 191 | |
| 192 | } |