001/* *********************************************************************** * 002 * project: org.matsim.* 003 * * 004 * *********************************************************************** * 005 * * 006 * copyright : (C) 2017 by the members listed in the COPYING, * 007 * LICENSE and WARRANTY file. * 008 * email : info at matsim dot org * 009 * * 010 * *********************************************************************** * 011 * * 012 * This program is free software; you can redistribute it and/or modify * 013 * it under the terms of the GNU General Public License as published by * 014 * the Free Software Foundation; either version 2 of the License, or * 015 * (at your option) any later version. * 016 * See also COPYING, LICENSE and WARRANTY file * 017 * * 018 * *********************************************************************** */ 019 020/** 021 * 022 */ 023package org.matsim.contrib.drt.analysis; 024 025import java.io.BufferedWriter; 026import java.io.FileOutputStream; 027import java.io.IOException; 028import java.util.ArrayList; 029import java.util.HashMap; 030import java.util.List; 031import java.util.Map; 032import java.util.Map.Entry; 033 034import org.apache.commons.lang3.tuple.Pair; 035import org.jfree.chart.ChartUtils; 036import org.jfree.chart.JFreeChart; 037import org.jfree.data.xy.XYSeries; 038import org.matsim.api.core.v01.Coord; 039import org.matsim.api.core.v01.Id; 040import org.matsim.api.core.v01.events.PersonEntersVehicleEvent; 041import org.matsim.api.core.v01.events.handler.PersonEntersVehicleEventHandler; 042import org.matsim.api.core.v01.network.Network; 043import org.matsim.api.core.v01.population.Person; 044import org.matsim.contrib.drt.passenger.events.DrtRequestSubmittedEvent; 045import org.matsim.contrib.drt.passenger.events.DrtRequestSubmittedEventHandler; 046import org.matsim.contrib.drt.run.DrtConfigGroup; 047import org.matsim.contrib.dvrp.optimizer.Request; 048import org.matsim.contrib.dvrp.passenger.PassengerRequestRejectedEvent; 049import org.matsim.contrib.dvrp.passenger.PassengerRequestRejectedEventHandler; 050import org.matsim.contrib.dvrp.passenger.PassengerRequestScheduledEvent; 051import org.matsim.contrib.dvrp.passenger.PassengerRequestScheduledEventHandler; 052import org.matsim.core.api.experimental.events.EventsManager; 053import org.matsim.core.utils.collections.Tuple; 054import org.matsim.core.utils.io.IOUtils; 055 056/** 057 * @author jbischoff 058 */ 059public class DrtRequestAnalyzer implements PassengerRequestRejectedEventHandler, PassengerRequestScheduledEventHandler, 060 DrtRequestSubmittedEventHandler, PersonEntersVehicleEventHandler { 061 062 private final Map<Id<Request>, DrtRequestSubmittedEvent> submittedRequests = new HashMap<>(); 063 private final Map<Id<Request>, Tuple<Double, Double>> waitTimeCompare = new HashMap<>(); 064 private final Map<Id<Person>, PassengerRequestScheduledEvent> scheduledRequests = new HashMap<>(); 065 private final List<String> rejections = new ArrayList<>(); 066 private final Network network; 067 private final DrtConfigGroup drtCfg; 068 069 public DrtRequestAnalyzer(EventsManager events, Network network, DrtConfigGroup drtCfg) { 070 events.addHandler(this); 071 this.network = network; 072 this.drtCfg = drtCfg; 073 } 074 075 @Override 076 public void reset(int iteration) { 077 submittedRequests.clear(); 078 scheduledRequests.clear(); 079 waitTimeCompare.clear(); 080 rejections.clear(); 081 } 082 083 @Override 084 public void handleEvent(PersonEntersVehicleEvent event) { 085 if (this.scheduledRequests.containsKey(event.getPersonId())) { 086 PassengerRequestScheduledEvent scheduled = scheduledRequests.remove(event.getPersonId()); 087 DrtRequestSubmittedEvent submission = this.submittedRequests.remove(scheduled.getRequestId()); 088 double actualWaitTime = event.getTime() - submission.getTime(); 089 double estimatedWaitTime = scheduled.getPickupTime() - submission.getTime(); 090 waitTimeCompare.put(submission.getRequestId(), Tuple.of(actualWaitTime, estimatedWaitTime)); 091 092 } 093 } 094 095 @Override 096 public void handleEvent(PassengerRequestScheduledEvent event) { 097 if (!event.getMode().equals(drtCfg.getMode())) { 098 return; 099 } 100 DrtRequestSubmittedEvent submission = this.submittedRequests.get(event.getRequestId()); 101 if (submission != null) { 102 this.scheduledRequests.put(submission.getPersonId(), event); 103 } else 104 throw new RuntimeException("Vehicle allocation without submission?"); 105 } 106 107 @Override 108 public void handleEvent(DrtRequestSubmittedEvent event) { 109 if (!event.getMode().equals(drtCfg.getMode())) { 110 return; 111 } 112 this.submittedRequests.put(event.getRequestId(), event); 113 } 114 115 @Override 116 public void handleEvent(PassengerRequestRejectedEvent event) { 117 if (!event.getMode().equals(drtCfg.getMode())) { 118 return; 119 } 120 DrtRequestSubmittedEvent submission = this.submittedRequests.remove(event.getRequestId()); 121 Coord fromCoord = network.getLinks().get(submission.getFromLinkId()).getCoord(); 122 Coord toCoord = network.getLinks().get(submission.getToLinkId()).getCoord(); 123 this.rejections.add(submission.getTime() 124 + ";" 125 + submission.getPersonId() 126 + ";" 127 + submission.getFromLinkId() 128 + ";" 129 + submission.getToLinkId() 130 + ";" 131 + fromCoord.getX() 132 + ";" 133 + fromCoord.getY() 134 + ";" 135 + toCoord.getX() 136 + ";" 137 + toCoord.getY()); 138 } 139 140 /** 141 * @return the waitTimeCompare 142 */ 143 public Map<Id<Request>, Tuple<Double, Double>> getWaitTimeCompare() { 144 return waitTimeCompare; 145 } 146 147 /** 148 * @return the rejections 149 */ 150 public List<String> getRejections() { 151 return rejections; 152 } 153 154 public void writeAndPlotWaitTimeEstimateComparison(String plotFileName, String textFileName, boolean createChart) { 155 BufferedWriter bw = IOUtils.getBufferedWriter(textFileName); 156 157 XYSeries times = new XYSeries("waittimes", true, true); 158 159 try { 160 bw.append("RequestId;actualWaitTime;estimatedWaitTime;deviate"); 161 for (Entry<Id<Request>, Tuple<Double, Double>> e : this.waitTimeCompare.entrySet()) { 162 bw.newLine(); 163 double first = e.getValue().getFirst(); 164 double second = e.getValue().getSecond(); 165 bw.append(e.getKey().toString() + ";" + first + ";" + second + ";" + (first - second)); 166 times.add(first, second); 167 } 168 bw.flush(); 169 bw.close(); 170 171 if (createChart) { 172 final JFreeChart chart2 = DensityScatterPlots.createPlot("Wait times", "Actual wait time [s]", 173 "Initially planned wait time [s]", times, Pair.of(0., drtCfg.getMaxWaitTime())); 174 // xAxis.setLowerBound(0); 175 // yAxis.setLowerBound(0); 176 ChartUtils.writeChartAsPNG(new FileOutputStream(plotFileName), chart2, 1500, 1500); 177 } 178 } catch (IOException e) { 179 throw new RuntimeException(e); 180 } 181 } 182}