package cz.agents.agentpolis.darptestbed.siminfrastructure.logger.analyser; import com.google.common.collect.HashMultiset; import com.google.common.collect.Multiset; import com.google.common.eventbus.Subscribe; import cz.agents.agentpolis.darptestbed.siminfrastructure.logger.analyser.init.TestbedProcessor; import cz.agents.agentpolis.darptestbed.siminfrastructure.logger.analyser.structure.AvgMaxProcessor; import cz.agents.agentpolis.darptestbed.siminfrastructure.logger.item.*; import cz.agents.agentpolis.siminfrastructure.logger.agent.activity.logitem.EndDrivingLogItem; import cz.agents.agentpolis.siminfrastructure.logger.agent.activity.logitem.MovementArrivalLogItem; import cz.agents.agentpolis.siminfrastructure.logger.agent.activity.logitem.StartDrivingLogItem; import cz.agents.agentpolis.util.InitAndGetterUtil; import eu.superhub.wp4.simulator.analyser.processor.util.AvgCounter; import eu.superhub.wp4.simulator.analyser.structure.VehiclePath; import org.apache.log4j.Logger; import org.joda.time.DateTime; import org.joda.time.Duration; import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.*; public class TestbedLogAnalyser { private static final Logger LOGGER = Logger.getLogger(TestbedLogAnalyser.class); private final File resultOutputFile; private final long simulationStartTime; // String == vehicle id private final Map<String, VehiclePath> vehiclePaths = new HashMap<String, VehiclePath>(); private final List<TestbedProcessor> testbedProcessors = new ArrayList<TestbedProcessor>(); private final AvgMaxProcessor passengerOnBoardTime = new AvgMaxProcessor(); private final AvgMaxProcessor passengerWaitTime = new AvgMaxProcessor(); private final AvgMaxProcessor passengerTravelTime = new AvgMaxProcessor(); private final Multiset<VehicleHourKey> productivity = HashMultiset.create(); private final Map<String, PassengerRequestLogItem> passengerRequestLogItems = new HashMap<>(); private long algRealTime = 0; private int successfulRequests = 0; private int failedRequests = 0; private int impossibleRequests = 0; public TestbedLogAnalyser(File result) { this(result, System.currentTimeMillis()); } public TestbedLogAnalyser(File result, long simulationStartTime) { super(); this.resultOutputFile = result; this.simulationStartTime = simulationStartTime; } @Subscribe public void processPassengerRequest(PassengerRequestLogItem passengerRequest) { passengerWaitTime.addStartLogItem(passengerRequest.passengerId, passengerRequest.timeWindow.getEarliestDeparture()); passengerTravelTime.addStartLogItem(passengerRequest.passengerId, passengerRequest.timeWindow.getEarliestDeparture()); passengerRequestLogItems.put(passengerRequest.passengerId, passengerRequest); long interval = passengerRequest.timeWindow.getLatestArrival() - passengerRequest.timeWindow.getEarliestDeparture(); long drivingTime = passengerRequest.utils.computeDrivingTime(passengerRequest.fromNodeId, passengerRequest.toNodeId, 30); long slack = interval - drivingTime; if (slack < 0) { ++impossibleRequests; LOGGER.debug("#" + impossibleRequests + " - " + slack + " - " + drivingTime + " trip length - " + passengerRequest.utils.computeDistance( passengerRequest.fromNodeId, passengerRequest.toNodeId) + " - impossible " + "request - " + passengerRequest); } } @Subscribe public void processPassengerGetInVehicle(PassengerGetInVehicleLogItem passengerGetInVehicle) { productivity.add(VehicleHourKey.newinstance(passengerGetInVehicle.vehicleId, passengerGetInVehicle.simulationTime)); passengerWaitTime.addEndLogItem(passengerGetInVehicle.passengerId, passengerGetInVehicle.simulationTime); passengerOnBoardTime.addStartLogItem(passengerGetInVehicle.passengerId, passengerGetInVehicle.simulationTime); } @Subscribe public void processPassengerGetOffVehicle(PassengerGetOffVehicleLogItem passengerGetOffVehicle) { passengerOnBoardTime.addEndLogItem(passengerGetOffVehicle.passengerId, passengerGetOffVehicle.simulationTime); passengerTravelTime.addEndLogItem(passengerGetOffVehicle.passengerId, passengerGetOffVehicle.simulationTime); PassengerRequestLogItem passengerRequestLogItem = passengerRequestLogItems .get(passengerGetOffVehicle.passengerId); if (passengerRequestLogItem.timeWindow.getLatestArrival() <= passengerGetOffVehicle.simulationTime) { failedRequests++; } else { successfulRequests++; } } @Subscribe public void handleStartDrivingLogItem(StartDrivingLogItem startDrivingLogItem) { assert vehiclePaths.containsKey(startDrivingLogItem.driverId) == false : "Driver is driving "; VehiclePath vehiclePath = new VehiclePath(startDrivingLogItem.vehicleId, startDrivingLogItem.simulationTime); vehiclePaths.put(startDrivingLogItem.driverId, vehiclePath); } @Subscribe public void processRequestRejected(RequestRejectedLogItem requestRejected) { failedRequests++; } @Subscribe public void handleEndDrivingLogItem(EndDrivingLogItem endDrivingLogItem) { assert vehiclePaths.containsKey(endDrivingLogItem.driverId) : "Driver is not driving"; VehiclePath vehiclePath = vehiclePaths.remove(endDrivingLogItem.driverId); if (vehiclePath.path.size() > 0) { for (TestbedProcessor vehiclePathProcessor : testbedProcessors) { vehiclePathProcessor.process(endDrivingLogItem.driverId, vehiclePath); } } } @Subscribe public void handleAlgRealTimeLogItem(AlgRealTimeLogItem algRealTimeLogItem) { this.algRealTime += algRealTimeLogItem.realTime; } public void addVehiclePathProcessor(TestbedProcessor testbedProcessor) { testbedProcessors.add(testbedProcessor); } @Subscribe public void handleMovementArrivalLogItem(MovementArrivalLogItem movementArrivalLogItem) { VehiclePath vehiclePath = vehiclePaths.get(movementArrivalLogItem.agentId); if (vehiclePath != null) { vehiclePath.addPath(movementArrivalLogItem); vehiclePaths.put(movementArrivalLogItem.agentId, vehiclePath); } else { } } public void processResult() { StringBuilder resultOutput = new StringBuilder(); resultOutput.append(System.lineSeparator()); appendWithNewLine(resultOutput, "------ Simulation result -----------"); appendWithNewLine(resultOutput, "Successful requests: %s", successfulRequests); appendWithNewLine(resultOutput, "Failed requests: %s", failedRequests); appendWithNewLine(resultOutput, "Found impossible requests: %s", impossibleRequests); appendWithNewLine(resultOutput, "Average passenger travel time (on-board) is : %s", parseTime(passengerTravelTime.getAvg())); appendWithNewLine(resultOutput, "Max passenger travel time (on-board) is: %s", parseTime(passengerTravelTime.getMax())); appendWithNewLine(resultOutput, "Median passenger travel time (on-board) is: %s", parseTime(passengerTravelTime.getMedian())); appendWithNewLine(resultOutput, "Average passenger ride time (on-board) is: %s", parseTime(passengerOnBoardTime.getAvg())); appendWithNewLine(resultOutput, "Max passenger ride time (on-board) is: %s", parseTime(passengerOnBoardTime.getMax())); appendWithNewLine(resultOutput, "Median passenger ride time (on-board) is: %s", parseTime(passengerOnBoardTime.getMedian())); appendWithNewLine(resultOutput, "Average passenger wait time is: %s", parseTime(passengerWaitTime.getAvg())); appendWithNewLine(resultOutput, "Max passenger wait time is: %s", parseTime(passengerWaitTime.getMax())); appendWithNewLine(resultOutput, "Median passenger wait time is: %s", parseTime(passengerWaitTime.getMedian())); for (TestbedProcessor testbedProcessor : testbedProcessors) { resultOutput.append(testbedProcessor.provideResult()); resultOutput.append(System.lineSeparator()); } appendWithNewLine(resultOutput, "Alg. real time: %s", parseTime(this.algRealTime)); appendWithNewLine(resultOutput, "Simulation real time: %s", parseTime(System.currentTimeMillis() - simulationStartTime)); resultOutput.append(printProductivity()); LOGGER.info(resultOutput.toString()); writeResultToFile(resultOutput.toString()); } private void appendWithNewLine(StringBuilder resultOutput, String text, Object... args) { resultOutput.append(String.format(text, args)); resultOutput.append(System.lineSeparator()); } private void writeResultToFile(String resultOutput) { try (FileWriter fileWriter = new FileWriter(resultOutputFile)) { fileWriter.write(resultOutput); } catch (IOException e) { e.printStackTrace(); } } private static final DateTimeFormatter fmt = DateTimeFormat.forPattern("HH:mm:ss"); private String parseTime(double time) { return parseTime((long) time); } private String parseTime(long time) { if (time <= 0) { return "NaN"; } return fmt.print(new DateTime(1999, 1, 2, 0, 0, 0).plus(time)); } private String printProductivity() { SortedMap<Long, AvgCounter> avgCounters = computeAvgProductivity(); if (avgCounters.isEmpty()) { return ""; } StringBuilder output = new StringBuilder(); String pattern = "Hour - %s : avg. passenger per vehicle hour - %s"; for (long key = 0; key <= avgCounters.lastKey(); key++) { AvgCounter avgPassengerPerVehicleHour = avgCounters.get(key); if (avgPassengerPerVehicleHour == null) { output.append(String.format(pattern, key, 0)); } else { output.append(String.format(pattern, key, avgPassengerPerVehicleHour.getCurrentAvgValue())); } output.append(System.lineSeparator()); } return output.toString(); } private SortedMap<Long, AvgCounter> computeAvgProductivity() { SortedMap<Long, AvgCounter> avgCounters = new TreeMap<>(); for (VehicleHourKey vehicleHourKey : productivity) { AvgCounter avgCounter = InitAndGetterUtil.getDataOrInitFromMap(avgCounters, vehicleHourKey.hour, new AvgCounter()); avgCounter.addValue(productivity.count(vehicleHourKey)); avgCounters.put(vehicleHourKey.hour, avgCounter); } return avgCounters; } private static class VehicleHourKey { private final static long HOUR = Duration.standardHours(1).getMillis(); public final String vehicleId; public final long hour; private VehicleHourKey(String vehicleId, long hour) { super(); this.vehicleId = vehicleId; this.hour = hour; } public static VehicleHourKey newinstance(String vehicleId, long simulationTime) { return new VehicleHourKey(vehicleId, (long) simulationTime / HOUR); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (int) (hour ^ (hour >>> 32)); result = prime * result + ((vehicleId == null) ? 0 : vehicleId.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; VehicleHourKey other = (VehicleHourKey) obj; if (hour != other.hour) return false; if (vehicleId == null) { if (other.vehicleId != null) return false; } else if (!vehicleId.equals(other.vehicleId)) return false; return true; } } }