1 package org.opentrafficsim.imb.kpi; 2 3 import java.io.Serializable; 4 import java.util.ArrayList; 5 import java.util.List; 6 7 import org.djunits.unit.SpeedUnit; 8 import org.djunits.unit.TimeUnit; 9 import org.djunits.value.vdouble.scalar.Dimensionless; 10 import org.djunits.value.vdouble.scalar.Duration; 11 import org.djunits.value.vdouble.scalar.Length; 12 import org.djunits.value.vdouble.scalar.Speed; 13 import org.djunits.value.vdouble.scalar.Time; 14 import org.opentrafficsim.imb.IMBException; 15 import org.opentrafficsim.imb.connector.Connector; 16 import org.opentrafficsim.imb.connector.Connector.IMBEventType; 17 import org.opentrafficsim.kpi.sampling.Query; 18 import org.opentrafficsim.kpi.sampling.indicator.MeanSpeed; 19 import org.opentrafficsim.kpi.sampling.indicator.MeanTravelTime; 20 import org.opentrafficsim.kpi.sampling.indicator.MeanTripLength; 21 import org.opentrafficsim.kpi.sampling.indicator.TotalDelay; 22 import org.opentrafficsim.kpi.sampling.indicator.TotalNumberOfStops; 23 import org.opentrafficsim.kpi.sampling.indicator.TotalTravelDistance; 24 import org.opentrafficsim.kpi.sampling.indicator.TotalTravelTime; 25 26 /** 27 * OTS can publish messages about statistics or Key Performance Indicators (KPIs) of the relation between GTUs and a part of the 28 * network. Examples are average speeds, travel times, trip durations, and number of stops. The statistics can be transmitted 29 * via IMB at certain intervals. The statistics are based on the classes in the ots.road.sampling package. Most statistics 30 * consider a time interval (can be unbound) and a region in space (a collection of lanes; can be the entire network), filtered 31 * on metadata such as GTU type, origin, destination, or route.<br> 32 * When a statistic is published for the first time, a NEW message is sent to IMB to identify the type of statistic, the time 33 * interval and the lane(s) for which the statistic is calculated, and the metadata used to filter the GTUs. The CHANGE message 34 * is posted whenever an updated statistic is available, or when the sample frequency time is reached. When a statistic is no 35 * longer published, a DELETE event is posted. The Graph NEW messages are posted after the Network NEW, Node NEW, Link NEW, and 36 * Lane NEW messages are posted, as it has to be able to identify Lanes. 37 * <p> 38 * <style>table,th,td {border:1px solid grey; border-style:solid; text-align:left; border-collapse: collapse;}</style> 39 * <h2>NEW</h2> 40 * <table summary="" style="width:800px;"> 41 * <thead> 42 * <tr> 43 * <th style="width:25%;">Variable</th> 44 * <th style="width:15%;">Type</th> 45 * <th style="width:60%;">Comments</th> 46 * </tr> 47 * </thead><tbody> 48 * <tr> 49 * <td>timestamp</td> 50 * <td>double</td> 51 * <td>time of the event, in simulation time seconds</td> 52 * </tr> 53 * <tr> 54 * <td>statisticId</td> 55 * <td>String</td> 56 * <td>a unique id for the statistic, e.g. a UUID string</td> 57 * </tr> 58 * <tr> 59 * <td>description</td> 60 * <td>String</td> 61 * <td>textual description of the statistic</td> 62 * </tr> 63 * <tr> 64 * <td>networkId</td> 65 * <td>String</td> 66 * <td>id of the Network for which the statistic is made</td> 67 * </tr> 68 * <tr> 69 * <td>numberMetadataEntries</td> 70 * <td>int</td> 71 * <td>number of metadata entries</td> 72 * </tr> 73 * <tr> 74 * <td>metadataId_1</td> 75 * <td>String</td> 76 * <td>id of the first metadata entry</td> 77 * </tr> 78 * <tr> 79 * <td>metadataType_1</td> 80 * <td>String</td> 81 * <td>type of metadata, one of GTUTYPE, ORIGIN, DESTINATION, ROUTE</td> 82 * </tr> 83 * <tr> 84 * <td>metadataValue_1</td> 85 * <td>String</td> 86 * <td>value of the first metadata entry</td> 87 * </tr> 88 * <tr> 89 * <td>...</td> 90 * <td> </td> 91 * <td> </td> 92 * </tr> 93 * <tr> 94 * <td>metadataId_n</td> 95 * <td>String</td> <tdid of the last metadata entry</td> 96 * </tr> 97 * <tr> 98 * <td>metadataType_n</td> 99 * <td>String</td> 100 * <td>type of metadata, one of GTUTYPE, ORIGIN, DESTINATION, ROUTE</td> 101 * </tr> 102 * <tr> 103 * <td>metadataValue_n</td> 104 * <td>String</td> 105 * <td>value of the last metadata entry</td> 106 * </tr> 107 * <td>numberSpaceTimeRegions</td> 108 * <td>int</td> 109 * <td>number of space-time regions for this statistic</td> </tr> 110 * <tr> 111 * <td>startTime_1</td> 112 * <td>double</td> 113 * <td>start time for the first space time region, in seconds</td> 114 * </tr> 115 * <tr> 116 * <td>endTime_1</td> 117 * <td>double</td> 118 * <td>end time for the first space time region, in seconds</td> 119 * </tr> 120 * <tr> 121 * <td>linkId_1</td> 122 * <td>String</td> 123 * <td>id of the first Link for the space-time region</td> 124 * </tr> 125 * <tr> 126 * <td>laneId_1</td> 127 * <td>String</td> 128 * <td>id of the first Lane in the link for the space-time region</td> 129 * </tr> 130 * <tr> 131 * <td>...</td> 132 * <td> </td> 133 * <td> </td> 134 * </tr> 135 * <tr> 136 * <td>startTime_n</td> 137 * <td>double</td> 138 * <td>start time for the last space time region, in seconds</td> 139 * </tr> 140 * <tr> 141 * <td>endTime_n</td> 142 * <td>double</td> 143 * <td>end time for the last space time region, in seconds</td> 144 * </tr> 145 * <tr> 146 * <td>linkId_n</td> 147 * <td>String</td> 148 * <td>id of the last Link for the space-time region</td> 149 * </tr> 150 * <tr> 151 * <td>laneId_n</td> 152 * <td>String</td> 153 * <td>id of the last Lane in the link for the space-time region</td> 154 * </tr> 155 * <tr> 156 * <td>connected</td> 157 * <td>boolean</td> 158 * <td>whether the lanes in the space-time regions are longitudinally connected or not</td> 159 * </tr> 160 * <tr> 161 * <td>totalTrajectory</td> 162 * <td>boolean</td> 163 * <td>whether the sampling takes place of GTUs that have traveled the entire space region or not</td> 164 * </tr> 165 * <tr> 166 * <td>transmissionInterval</td> 167 * <td>double</td> 168 * <td>transmission interval of the statistic in seconds</td> 169 * </tr> 170 * </tbody> 171 * </table> 172 * </p> 173 * <p> 174 * <h2>CHANGE</h2> 175 * <table summary="" style="width:800px;"> 176 * <thead> 177 * <tr> 178 * <th style="width:25%;">Variable</th> 179 * <th style="width:15%;">Type</th> 180 * <th style="width:60%;">Comments</th> 181 * </tr> 182 * </thead><tbody> 183 * <tr> 184 * <td>timestamp</td> 185 * <td>double</td> 186 * <td>time of the event, in simulation time seconds</td> 187 * </tr> 188 * <tr> 189 * <td>statisticId</td> 190 * <td>String</td> 191 * <td>the unique id for the statistic, e.g. a UUID string</td> 192 * </tr> 193 * <tr> 194 * <td>totalGtuDistance/td> 195 * <td>double</td> 196 * <td>total distance traveled by filtered GTUs in the given time and space, in meters</td> 197 * </tr> 198 * <tr> 199 * <td>totalGtuTravelTime/td> 200 * <td>double</td> 201 * <td>total travel time by filtered GTUs in the given time and space, in seconds</td> 202 * </tr> 203 * <tr> 204 * <td>averageGtuSpeed/td> 205 * <td>double</td> 206 * <td>average filtered GTU speed in the given time and space, in meter/second</td> 207 * </tr> 208 * <tr> 209 * <td>averageGtuTravelTime/td> 210 * <td>double</td> 211 * <td>average filtered GTU travel time in the given time and space, in seconds</td> 212 * </tr> 213 * <tr> 214 * <td>totalGtuTimeDelay/td> 215 * <td>double</td> 216 * <td>total time delay incurred by the filtered GTUs in the given time and space, in seconds</td> 217 * </tr> 218 * <tr> 219 * <td>averageTripLength/td> 220 * <td>double</td> 221 * <td>average length of the trip of the filtered GTUs in the given time and space, in seconds</td> 222 * </tr> 223 * <tr> 224 * <td>totalNumberStops/td> 225 * <td>double</td> 226 * <td>total number of stops that GTUs made in the given time and space, dimensionless</td> 227 * </tr> 228 * </tbody> 229 * </table> 230 * </p> 231 * <p> 232 * <h2>DELETE</h2> 233 * <table summary="" style="width:800px;"> 234 * <thead> 235 * <tr> 236 * <th style="width:25%;">Variable</th> 237 * <th style="width:15%;">Type</th> 238 * <th style="width:60%;">Comments</th> 239 * </tr> 240 * </thead><tbody> 241 * <tr> 242 * <td>timestamp</td> 243 * <td>double</td> 244 * <td>time of the event, in simulation time seconds</td> 245 * </tr> 246 * <tr> 247 * <td>statisticId</td> 248 * <td>String</td> 249 * <td>the unique id for the statistic that is removed</td> 250 * </tr> 251 * </tbody> 252 * </table> 253 * </p> 254 * <p> 255 * Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br> 256 * BSD-style license. See <a href="http://opentrafficsim.org/docs/current/license.html">OpenTrafficSim License</a>. 257 * <p> 258 * @version $Revision$, $LastChangedDate$, by $Author$, initial version Sep 16, 2016 <br> 259 * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a> 260 * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a> 261 */ 262 public class ImbKpiTransceiver implements Serializable 263 { 264 265 /** */ 266 private static final long serialVersionUID = 20160923L; 267 268 /** IMB connector. */ 269 private final Connector connector; 270 271 /** The query for the statistic. */ 272 private final Query query; 273 274 /** The Network id for which the graph is made. */ 275 private final String networkId; 276 277 /** The interval between generation of graphs. */ 278 private final Duration transmissionInterval; 279 280 private TotalTravelDistance totalTravelDistance = new TotalTravelDistance(); 281 282 private TotalTravelTime totalTravelTime = new TotalTravelTime(); 283 284 private MeanSpeed meanSpeed = new MeanSpeed(this.totalTravelDistance, this.totalTravelTime); 285 286 private MeanTravelTime meanTravelTime = new MeanTravelTime(this.meanSpeed); 287 288 private MeanTripLength meanTripLength = new MeanTripLength(); 289 290 private TotalDelay totalDelay = new TotalDelay(new Speed(130.0, SpeedUnit.KM_PER_HOUR)); 291 292 private TotalNumberOfStops totalNumberOfStops = new TotalNumberOfStops(); 293 294 private Time updateTime = Time.ZERO; 295 296 // TODO implement DELETE message 297 298 /** 299 * Construct a new StatisticsGTULaneTransceiver. 300 * @param connector Connector; the IMB connector 301 * @param time Time; time of creation 302 * @param networkId String; the network id 303 * @param query Query; the statistics query 304 * @param transmissionInterval Duration; the interval between generation of graphs 305 * @throws IMBException when the post of the IMB message fails 306 */ 307 public ImbKpiTransceiver(final Connector connector, Time time, String networkId, 308 final Query query, final Duration transmissionInterval) throws IMBException 309 { 310 this.connector = connector; 311 this.query = query; 312 this.networkId = networkId; 313 this.transmissionInterval = transmissionInterval; 314 315 List<Object> newMessage = new ArrayList<>(); 316 newMessage.add(time.si); 317 newMessage.add(query.getId()); 318 newMessage.add(query.toString()); 319 newMessage.add(this.networkId); 320 newMessage.add((int) 0); // TODO numberMetadataEntries 321 newMessage.add((int) 0); // TODO numberSpaceTimeRegions 322 newMessage.add(false); // TODO "connected" not part of query anymore 323 newMessage.add(true); // TODO totalTrajectory 324 newMessage.add(transmissionInterval.si); 325 326 this.connector.postIMBMessage("StatisticsGTULane", IMBEventType.NEW, newMessage.toArray()); 327 sendStatisticsUpdate(); 328 } 329 330 /** 331 * Notifies about time, such that statistics over some period (very recently ended) can be gathered and published. 332 * @param time 333 */ 334 public void notifyTime(Time time) 335 { 336 if (time.gt(this.updateTime)) 337 { 338 try 339 { 340 sendStatisticsUpdate(); 341 } 342 catch (IMBException exception) 343 { 344 throw new RuntimeException("Cannot send statistics update.", exception); 345 } 346 } 347 } 348 349 /** 350 * @throws IMBException when the transmission of the IMB message fails 351 */ 352 public void sendStatisticsUpdate() throws IMBException 353 { 354 double time = this.updateTime.si; 355 Length tdist = this.totalTravelDistance.getValue(this.query, new Time(time, TimeUnit.SI)); 356 Duration ttt = this.totalTravelTime.getValue(this.query, new Time(time, TimeUnit.SI)); 357 Speed ms = this.meanSpeed.getValue(this.query, new Time(time, TimeUnit.SI)); 358 Duration mtt = this.meanTravelTime.getValue(this.query, new Time(time, TimeUnit.SI)); 359 Length mtl = this.meanTripLength.getValue(this.query, new Time(time, TimeUnit.SI)); 360 Duration tdel = this.totalDelay.getValue(this.query, new Time(time, TimeUnit.SI)); 361 Dimensionless nos = this.totalNumberOfStops.getValue(this.query, new Time(time, TimeUnit.SI)); 362 System.out.println("===== @time " + time + " s ====="); 363 System.out.println("Total distance " + tdist); 364 System.out.println("Total travel time " + ttt); 365 System.out.println("Mean speed " + ms); 366 System.out.println("Mean travel time " + mtt); 367 System.out.println("Mean trip length " + mtl); 368 System.out.println("Total delay " + tdel); 369 System.out.println("Number of stops " + nos); 370 this.connector.postIMBMessage( 371 "StatisticsGTULane", 372 IMBEventType.CHANGE, 373 new Object[] { time, this.query.getId(), tdist.si, ttt.si, ms.si, 374 mtt.si, tdel.si, mtl.si, nos.si }); 375 this.updateTime = this.updateTime.plus(this.transmissionInterval); 376 } 377 378 }