Skip to content

Commit

Permalink
Merge pull request #2781 from matsim-org/rejectionAnalysis
Browse files Browse the repository at this point in the history
analyse number of rejection by time bin
  • Loading branch information
tschlenther authored Sep 28, 2023
2 parents 5120823 + 77bec68 commit e41035b
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -140,11 +140,6 @@ public void configure(Header header, Layout layout) {
viz.center = data.context().getCenter();
viz.zoom = data.context().mapZoomLevel;
})
//TODO group rejections per time bin. better put it into the plot with wait stats over daty time.
// .el(Line.class, (viz, data) -> {
// viz.dataset = data.output("ITERS/it." + lastIteration + "/*rejections_" + drtConfigGroup.mode + ".csv");
// viz.x = "time";
// })
;

// This plot is not absolutely necesarry given the hex plots
Expand All @@ -163,12 +158,13 @@ public void configure(Header header, Layout layout) {
viz.title = "Final Demand and Wait Stats over day time";
viz.description = "Number of rides (customers) is displayed in bars, wait statistics in lines";

Plotly.DataSet dataset = viz.addDataset(data.output("*_waitStats_" + drtConfigGroup.mode + ".csv"));
Plotly.DataSet waitStats = viz.addDataset(data.output("*_waitStats_" + drtConfigGroup.mode + ".csv"));
Plotly.DataSet rejections = viz.addDataset(data.output("*drt_rejections_perTimeBin_" + drtConfigGroup.mode + ".csv"));

viz.layout = tech.tablesaw.plotly.components.Layout.builder()
.xAxis(Axis.builder().title("Time Bin").build())
.yAxis(Axis.builder().title("Wait Time [s]").build())
.yAxis2(Axis.builder().title("Nr of Rides")
.yAxis2(Axis.builder().title("Nr of Rides/Rejections")
.side(Axis.Side.right)
.overlaying(ScatterTrace.YAxis.Y)
.build())
Expand All @@ -179,7 +175,7 @@ public void configure(Header header, Layout layout) {
.mode(ScatterTrace.Mode.LINE)
.name("Average")
.build(),
dataset.mapping()
waitStats.mapping()
.x("timebin")
.y("average_wait")
);
Expand All @@ -188,7 +184,7 @@ public void configure(Header header, Layout layout) {
.mode(ScatterTrace.Mode.LINE)
.name("P5")
.build(),
dataset.mapping()
waitStats.mapping()
.x("timebin")
.y("p_5")
);
Expand All @@ -197,7 +193,7 @@ public void configure(Header header, Layout layout) {
.mode(ScatterTrace.Mode.LINE)
.name("P95")
.build(),
dataset.mapping()
waitStats.mapping()
.x("timebin")
.y("p_95")
);
Expand All @@ -207,11 +203,21 @@ public void configure(Header header, Layout layout) {
.yAxis(ScatterTrace.YAxis.Y2.toString())
.name("Rides")
.build(),
dataset.mapping()
waitStats.mapping()
.x("timebin")
.y("legs")
);

viz.addTrace(BarTrace.builder(Plotly.OBJ_INPUT, Plotly.INPUT)
.opacity(0.3)
.yAxis(ScatterTrace.YAxis.Y2.toString())
.name("Rejections")
.build(),
rejections.mapping()
.x("timebin")
.y("rejections")
);

})
.el(Area.class, (viz, data) -> {
viz.title = "Vehicle occupancy"; //actually, without title the area plot won't work
Expand Down Expand Up @@ -248,7 +254,7 @@ public void configure(Header header, Layout layout) {
dataset.mapping()
.x("iteration")
.y("rejections")
.color(Plotly.ColorScheme.RdBu)
// .color(Plotly.ColorScheme.RdBu)
);

viz.addTrace(BarTrace.builder(Plotly.OBJ_INPUT, Plotly.INPUT)
Expand All @@ -257,7 +263,7 @@ public void configure(Header header, Layout layout) {
dataset.mapping()
.x("iteration")
.y("rides")
.color(Plotly.ColorScheme.RdBu)
// .color(Plotly.ColorScheme.RdBu)
);

})
Expand Down Expand Up @@ -294,7 +300,7 @@ public void configure(Header header, Layout layout) {
dataset.mapping()
.x("iteration")
.y("inVehicleTravelTime_mean")
.color(Plotly.ColorScheme.RdBu)
// .color(Plotly.ColorScheme.RdBu)
);

viz.addTrace(BarTrace.builder(Plotly.OBJ_INPUT, Plotly.INPUT)
Expand All @@ -304,7 +310,7 @@ public void configure(Header header, Layout layout) {
dataset.mapping()
.x("iteration")
.y("wait_average")
.color(Plotly.ColorScheme.RdBu)
// .color(Plotly.ColorScheme.RdBu)
);
})
.el(Line.class, (viz, data) -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,31 +19,7 @@

package org.matsim.contrib.drt.analysis;

import static java.util.stream.Collectors.toList;

import java.awt.BasicStroke;
import java.awt.Color;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.TreeMap;
import java.util.function.Function;
import java.util.stream.Collectors;

import com.google.common.base.Preconditions;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;
import org.apache.logging.log4j.LogManager;
Expand All @@ -70,12 +46,13 @@
import org.matsim.contrib.drt.passenger.events.DrtRequestSubmittedEvent;
import org.matsim.contrib.drt.run.DrtConfigGroup;
import org.matsim.contrib.drt.schedule.DrtStayTask;
import org.matsim.contrib.dvrp.analysis.VehicleOccupancyProfileCalculator;
import org.matsim.contrib.dvrp.fleet.DvrpVehicle;
import org.matsim.contrib.dvrp.fleet.DvrpVehicleSpecification;
import org.matsim.contrib.dvrp.fleet.FleetSpecification;
import org.matsim.contrib.dvrp.optimizer.Request;
import org.matsim.contrib.dvrp.passenger.PassengerPickedUpEvent;
import org.matsim.contrib.dvrp.analysis.VehicleOccupancyProfileCalculator;
import org.matsim.contrib.dvrp.passenger.PassengerRequestRejectedEvent;
import org.matsim.core.config.Config;
import org.matsim.core.config.groups.QSimConfigGroup;
import org.matsim.core.controler.MatsimServices;
Expand All @@ -87,7 +64,20 @@
import org.matsim.core.utils.misc.Time;
import org.matsim.vehicles.Vehicle;

import com.google.common.base.Preconditions;
import java.awt.*;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toList;

/**
* @author jbischoff
Expand Down Expand Up @@ -176,6 +166,13 @@ public void notifyIterationEnds(IterationEndsEvent event) {
.sorted(Comparator.comparing(leg -> leg.departureTime))
.collect(toList());

List<PassengerRequestRejectedEvent> rejectionEvents = drtEventSequenceCollector.getRejectedRequestSequences()
.values()
.stream()
.map(eventSequence -> eventSequence.getRejected().get())
.sorted(Comparator.comparing(rejectionEvent -> rejectionEvent.getTime()))
.collect(toList());

collection2Text(drtEventSequenceCollector.getRejectedRequestSequences().values(), filename(event, "drt_rejections", ".csv"),
String.join(delimiter, "time", "personId", "fromLinkId", "toLinkId", "fromX", "fromY", "toX", "toY"), seq -> {
DrtRequestSubmittedEvent submission = seq.getSubmitted();
Expand Down Expand Up @@ -252,6 +249,7 @@ public void notifyIterationEnds(IterationEndsEvent event) {
writeVehicleDistances(drtVehicleStats.getVehicleStates(), filename(event, "vehicleDistanceStats", ".csv"), delimiter);
analyseDetours(network, legs, drtVehicleStats.getTravelDistances(), drtCfg, filename(event, "drt_detours"), createGraphs, delimiter);
analyseWaitTimes(filename(event, "waitStats"), legs, 1800, createGraphs, delimiter);
analyseRejections(filename(event,"drt_rejections_perTimeBin"), rejectionEvents,1800, createGraphs, delimiter);
analyseConstraints(filename(event, "constraints"), legs, createGraphs);

double endTime = qSimCfg.getEndTime()
Expand Down Expand Up @@ -399,6 +397,7 @@ public void notifyShutdown(ShutdownEvent event) {
dumpOutput(event.getIteration(), "waitTimeComparison", ".png");
dumpOutput(event.getIteration(), "waitTimeComparison", ".csv");
dumpOutput(event.getIteration(), "drt_rejections", ".csv");
dumpOutput(event.getIteration(), "drt_rejections_perTimeBin", ".csv");
dumpOutput(event.getIteration(), "drt_legs", ".csv");
dumpOutput(event.getIteration(), "vehicleDistanceStats", ".csv");
dumpOutput(event.getIteration(), "drt_detours", ".csv");
Expand Down Expand Up @@ -453,6 +452,33 @@ private static Map<Double, List<DrtLeg>> splitLegsIntoBins(Collection<DrtLeg> le
return splitLegs;
}

private static Map<Double, List<PassengerRequestRejectedEvent>> splitEventsIntoBins(List<PassengerRequestRejectedEvent> rejectionEvents, int binSize_s) {
Map<Double, List<PassengerRequestRejectedEvent>> rejections = new TreeMap<>();

int startTime = ((int)(rejectionEvents.get(0).getTime() / binSize_s)) * binSize_s;
int endTime = ((int)(rejectionEvents.get(rejectionEvents.size() - 1).getTime() / binSize_s) + 1) * binSize_s;

for (int time = startTime; time < endTime; time = time + binSize_s) {

// rejection list in this timebin
List<PassengerRequestRejectedEvent> rejectionList = new ArrayList<>();

//Iterate through each rejection
for (PassengerRequestRejectedEvent rejectedEvent : rejectionEvents){
double rejectionTime = rejectedEvent.getTime();
if (rejectionTime > endTime || rejectionTime < startTime) {
LogManager.getLogger(DrtAnalysisControlerListener.class).error("wrong end / start Times for analysis");
}

if (rejectionTime > time && rejectionTime < time + binSize_s) {
rejectionList.add(rejectedEvent);
}
}
rejections.put((double)time, rejectionList);
}
return rejections;
}

private static void analyzeBoardingsAndDeboardings(List<DrtLeg> legs, String delimiter, double startTime, double endTime, double timeBinSize,
String boardingsFile, String deboardingsFile, Network network) {
if (endTime < startTime) {
Expand Down Expand Up @@ -708,6 +734,55 @@ private static void analyseWaitTimes(String fileName, List<DrtLeg> legs, int bin

}

private static void analyseRejections(String fileName, List<PassengerRequestRejectedEvent> rejectionEvents, int binsize_s, boolean createGraphs, String delimiter) {
if (rejectionEvents.size() == 0)
return;

Map<Double, List<PassengerRequestRejectedEvent>> splitEvents = splitEventsIntoBins(rejectionEvents, binsize_s);

DecimalFormat format = new DecimalFormat();
format.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.US));
format.setMinimumIntegerDigits(1);
format.setMaximumFractionDigits(2);
format.setGroupingUsed(false);

SimpleDateFormat sdf2 = new SimpleDateFormat("HH:mm:ss");

BufferedWriter bw = IOUtils.getBufferedWriter(fileName + ".csv");
TimeSeriesCollection dataset = new TimeSeriesCollection();
TimeSeries rejections = new TimeSeries("number of rejections");

try {
bw.write(String.join(delimiter, "timebin", "rejections"));

for(Map.Entry<Double, List<PassengerRequestRejectedEvent>> e : splitEvents.entrySet()){
int drt_numOfRejection = 0;
if (!e.getValue().isEmpty()) {
drt_numOfRejection = e.getValue().size();
}

Minute h = new Minute(sdf2.parse(Time.writeTime(e.getKey())));

rejections.addOrUpdate(h, Double.valueOf(drt_numOfRejection));
bw.newLine();
bw.write(String.join(delimiter, Time.writeTime(e.getKey()) + "",//
format.format(drt_numOfRejection) +""));
}

bw.flush();
bw.close();
if (createGraphs) {
dataset.addSeries(rejections);
JFreeChart chart = chartProfile(splitEvents.size(), dataset, "Number of rejections", "Number");
ChartSaveUtils.saveAsPNG(chart, fileName, 1500, 1000);
}

} catch (IOException | ParseException e) {

e.printStackTrace();
}
}

private static JFreeChart chartProfile(int length, TimeSeriesCollection dataset, String descriptor, String yax) {
JFreeChart chart = ChartFactory.createTimeSeriesChart(descriptor, "Time", yax, dataset);

Expand Down

0 comments on commit e41035b

Please sign in to comment.