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