Skip to content

Commit

Permalink
Merge branch 'master' into simwrapper-avro
Browse files Browse the repository at this point in the history
  • Loading branch information
rakow authored Jun 17, 2024
2 parents 8a4f11a + ad18ae0 commit 8177bfd
Show file tree
Hide file tree
Showing 33 changed files with 435 additions and 188 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,8 @@ public Integer call() throws Exception {
private Config prepareConfig() {
Config config = ConfigUtils.loadConfig(ApplicationUtils.matchInput("config.xml", input.getRunDirectory()).toAbsolutePath().toString(), new NoiseConfigGroup());

config.vehicles().setVehiclesFile(ApplicationUtils.matchInput("vehicles", input.getRunDirectory()).toAbsolutePath().toString());
//it is important to match "output_vehicles" because otherwise dvrpVehicle files might be matched and the code crashes later
config.vehicles().setVehiclesFile(ApplicationUtils.matchInput("output_vehicles", input.getRunDirectory()).toAbsolutePath().toString());
config.network().setInputFile(ApplicationUtils.matchInput("network", input.getRunDirectory()).toAbsolutePath().toString());
config.transit().setTransitScheduleFile(null);
config.transit().setVehiclesFile(null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
package org.matsim.contrib.drt.extension.operations.shifts.analysis.efficiency;

import com.google.inject.Inject;
import jakarta.inject.Provider;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtils;
import org.jfree.chart.JFreeChart;
Expand All @@ -27,7 +28,7 @@
import org.matsim.core.controler.listener.IterationEndsListener;
import org.matsim.core.utils.io.IOUtils;

import jakarta.inject.Provider;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.*;
Expand All @@ -43,6 +44,12 @@ public final class ShiftEfficiencyAnalysisControlerListener implements Iteration
private final DrtConfigGroup drtConfigGroup;
private final ShiftEfficiencyTracker shiftEfficiencyTracker;

private final String delimiter;
private final String runId;
private boolean headerWritten = false;
private static final String notAvailableString = "NA";


@Inject
public ShiftEfficiencyAnalysisControlerListener(DrtConfigGroup drtConfigGroup,
ShiftEfficiencyTracker shiftEfficiencyTracker,
Expand All @@ -52,21 +59,66 @@ public ShiftEfficiencyAnalysisControlerListener(DrtConfigGroup drtConfigGroup,
this.shiftEfficiencyTracker = shiftEfficiencyTracker;
this.drtShiftsSpecification = drtShiftsSpecification;
this.matsimServices = matsimServices;
this.delimiter = matsimServices.getConfig().global().getDefaultDelimiter();
this.runId = Optional.ofNullable(matsimServices.getConfig().controller().getRunId()).orElse(notAvailableString);
}

@Override
public void notifyIterationEnds(IterationEndsEvent event) {
int createGraphsInterval = event.getServices().getConfig().controller().getCreateGraphsInterval();
boolean createGraphs = createGraphsInterval >0 && event.getIteration() % createGraphsInterval == 0;

writeAndPlotShiftEfficiency(
shiftEfficiencyTracker.getCurrentRecord().getRevenueByShift(),
shiftEfficiencyTracker.getCurrentRecord().getRequestsByShift(),
shiftEfficiencyTracker.getCurrentRecord().getFinishedShifts(),
ShiftEfficiencyTracker.Record record = shiftEfficiencyTracker.getCurrentRecord();
writeAndPlotShiftEfficiency(
record.getRevenueByShift(),
record.getRequestsByShift(),
record.getFinishedShifts(),
filename(event, "shiftRevenue", ".png"),
filename(event, "shiftRidesPerVrh", ".png"),
filename(event, "shiftEfficiency", ".csv"),
createGraphs);

List<DrtShiftSpecification> finishedShifts = record.finishedShifts()
.keySet()
.stream()
.map(id -> drtShiftsSpecification.get().getShiftSpecifications().get(id))
.toList();

double earliestShiftStart = finishedShifts.stream().map(DrtShiftSpecification::getStartTime).mapToDouble(d -> d).min().orElse(Double.NaN);
double latestShiftEnd = finishedShifts.stream().map(DrtShiftSpecification::getEndTime).mapToDouble(d -> d).min().orElse(Double.NaN);

double numberOfShifts = finishedShifts.size();
double numberOfShiftHours = finishedShifts.
stream()
.map(s -> (s.getEndTime() - s.getStartTime()) - (s.getBreak().isPresent() ? s.getBreak().get().getDuration() : 0.))
.mapToDouble(d -> d)
.sum() / 3600.;

long uniqueVehicles = record.getFinishedShifts().values().stream().distinct().count();

double totalRevenue = record.revenueByShift().values().stream().mapToDouble(d -> d).sum();
double meanRevenuePerShift = record.revenueByShift().values().stream().mapToDouble(d -> d).average().orElse(Double.NaN);
double meanRevenuePerShiftHour = totalRevenue / numberOfShiftHours;

double totalRides = record.getRequestsByShift().values().stream().mapToDouble(List::size).sum();
double meanRidesPerShift = record.getRequestsByShift().values().stream().mapToDouble(List::size).average().orElse(Double.NaN);
double meanRidesPerShiftHour = totalRides / numberOfShiftHours;

StringJoiner stringJoiner = new StringJoiner(delimiter);
stringJoiner
.add(earliestShiftStart + "")
.add(latestShiftEnd + "")
.add(numberOfShifts + "")
.add(numberOfShiftHours + "")
.add(uniqueVehicles + "")
.add(meanRevenuePerShift + "")
.add(meanRevenuePerShiftHour + "")
.add(totalRevenue + "")
.add(meanRidesPerShift + "")
.add(meanRidesPerShiftHour + "")
.add(totalRides + "");
writeIterationShiftEfficiencyStats(stringJoiner.toString(), event.getIteration());

}

private void writeAndPlotShiftEfficiency(Map<Id<DrtShift>, Double> revenuePerShift,
Expand Down Expand Up @@ -126,12 +178,42 @@ private void writeAndPlotShiftEfficiency(Map<Id<DrtShift>, Double> revenuePerShi
}
}

private void writeIterationShiftEfficiencyStats(String summarizeShiftEfficiency, int it) {
try (var bw = getAppendingBufferedWriter("drt_shift_efficiency_metrics", ".csv")) {
if (!headerWritten) {
headerWritten = true;
StringJoiner stringJoiner = new StringJoiner(delimiter);
stringJoiner
.add("earliestShiftStart")
.add("latestShiftEnd")
.add("numberOfShifts")
.add("numberOfShiftHours")
.add("uniqueVehicles")
.add("meanRevenuePerShift")
.add("meanRevenuePerShiftHour")
.add("totalRevenue")
.add("meanRidesPerShift")
.add("meanRidesPerShiftHour")
.add("totalRides");
bw.write(line("runId", "iteration", stringJoiner.toString()));
}
bw.write(runId + delimiter + it + delimiter + summarizeShiftEfficiency);
bw.newLine();
} catch (IOException e) {
throw new RuntimeException(e);
}
}

private String filename(IterationEndsEvent event, String prefix, String extension) {
return matsimServices.getControlerIO()
.getIterationFilename(event.getIteration(), prefix + "_" + drtConfigGroup.getMode() + extension);
}

private static String line(Object... cells) {
return Arrays.stream(cells).map(Object::toString).collect(Collectors.joining(";", "", "\n"));
private String line(Object... cells) {
return Arrays.stream(cells).map(Object::toString).collect(Collectors.joining(delimiter, "", "\n"));
}

private BufferedWriter getAppendingBufferedWriter(String prefix, String extension) {
return IOUtils.getAppendingBufferedWriter(matsimServices.getControlerIO().getOutputFilename(prefix + "_" + drtConfigGroup.getMode() + extension));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public final class ShiftEfficiencyTracker implements PersonMoneyEventHandler,

private Record currentRecord;

public static record Record(Map<Id<DrtShift>, Double> revenueByShift,
public record Record(Map<Id<DrtShift>, Double> revenueByShift,
Map<Id<Request>, Id<DrtShift>> shiftByRequest,
Map<Id<DrtShift>, Id<DvrpVehicle>> finishedShifts){
public Map<Id<DrtShift>, Double> getRevenueByShift() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,12 @@ public void install() {
public void install() {
bindModal(DrtZonalWaitTimesAnalyzer.class).toProvider(modalProvider(
getter -> new DrtZonalWaitTimesAnalyzer(drtConfig, getter.getModal(DrtEventSequenceCollector.class),
getter.getModal(ZoneSystem.class)))).asEagerSingleton();
getter.getModal(ZoneSystem.class), config.global().getDefaultDelimiter()))).asEagerSingleton();
addControlerListenerBinding().to(modalKey(DrtZonalWaitTimesAnalyzer.class));
}
});
}
});

}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.matsim.contrib.drt.extension.operations.DrtWithOperationsConfigGroup;
import org.matsim.contrib.drt.extension.operations.operationFacilities.OperationFacilitiesParams;
import org.matsim.contrib.drt.extension.operations.shifts.config.ShiftsParams;
import org.matsim.contrib.drt.fare.DrtFareParams;
import org.matsim.contrib.drt.optimizer.DrtOptimizationConstraintsSet;
import org.matsim.contrib.drt.optimizer.insertion.extensive.ExtensiveInsertionSearchParams;
import org.matsim.contrib.drt.optimizer.rebalancing.RebalancingParams;
Expand Down Expand Up @@ -142,6 +143,11 @@ void test() {
shiftsParams.allowInFieldChangeover = true;
drtWithShiftsConfigGroup.addParameterSet(operationsParams);

DrtFareParams drtFareParams = new DrtFareParams();
drtFareParams.baseFare = 1.;
drtFareParams.distanceFare_m = 1. / 1000;
drtWithShiftsConfigGroup.addParameterSet(drtFareParams);

final Controler run = DrtOperationsControlerCreator.createControler(config, false);
run.run();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ private void writeIterationVehicleStats(String summarizeVehicles, String vehOcc,
try (var bw = getAppendingBufferedWriter("drt_detailed_distanceStats", ".csv")) {
if (!vheaderWritten) {
vheaderWritten = true;
bw.write("runId;iteration");
bw.write("runId" + delimiter + "iteration");
for (int i = 0; i <= maxcap; i++) {
bw.write(delimiter + i + " pax distance_m");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public void install() {

bindModal(DrtZonalWaitTimesAnalyzer.class).toProvider(modalProvider(
getter -> new DrtZonalWaitTimesAnalyzer(drtCfg, getter.getModal(DrtEventSequenceCollector.class),
getter.getModal(ZoneSystem.class)))).asEagerSingleton();
getter.getModal(ZoneSystem.class), getConfig().global().getDefaultDelimiter()))).asEagerSingleton();
addControlerListenerBinding().to(modalKey(DrtZonalWaitTimesAnalyzer.class));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,16 @@ public final class DrtZonalWaitTimesAnalyzer implements IterationEndsListener, S
private final ZoneSystem zones;
private static final Id<Zone> zoneIdForOutsideOfZonalSystem = Id.create("outsideOfDrtZonalSystem", Zone.class);
private static final String notAvailableString = "NaN";

private final String delimiter;
private static final Logger log = LogManager.getLogger(DrtZonalWaitTimesAnalyzer.class);

public DrtZonalWaitTimesAnalyzer(DrtConfigGroup configGroup, DrtEventSequenceCollector requestAnalyzer,
ZoneSystem zones) {
ZoneSystem zones, String delimiter) {
this.drtCfg = configGroup;
this.requestAnalyzer = requestAnalyzer;
this.zones = zones;
this.delimiter = delimiter;
}

@Override
Expand All @@ -76,7 +79,6 @@ public void notifyIterationEnds(IterationEndsEvent event) {
}

public void write(String fileName) {
String delimiter = ";";
Map<Id<Zone>, DescriptiveStatistics> zoneStats = createZonalStats();
BufferedWriter bw = IOUtils.getBufferedWriter(fileName);
try {
Expand All @@ -85,7 +87,11 @@ public void write(String fileName) {
format.setMinimumIntegerDigits(1);
format.setMaximumFractionDigits(2);
format.setGroupingUsed(false);
bw.append("zone;centerX;centerY;nRequests;sumWaitTime;meanWaitTime;min;max;p95;p90;p80;p75;p50");
String header = new StringJoiner(delimiter)
.add("zone").add("centerX").add("centerY").add("nRequests")
.add("sumWaitTime").add("meanWaitTime").add("min").add("max")
.add("p95").add("p90").add("p80").add("p75").add("p50").toString();
bw.append(header);
// sorted output
SortedSet<Id<Zone>> zoneIdsAndOutside = new TreeSet<>(zones.getZones().keySet());
zoneIdsAndOutside.add(zoneIdForOutsideOfZonalSystem);
Expand All @@ -96,31 +102,22 @@ public void write(String fileName) {
String centerY = drtZone != null ? String.valueOf(drtZone.getCentroid().getY()) : notAvailableString;
DescriptiveStatistics stats = zoneStats.get(zoneId);
bw.newLine();
bw.append(zoneId.toString())
.append(delimiter)
.append(centerX)
.append(delimiter)
.append(centerY)
.append(delimiter)
.append(format.format(stats.getN()))
.append(delimiter)
.append(format.format(stats.getSum()))
.append(delimiter)
.append(String.valueOf(stats.getMean()))
.append(delimiter)
.append(String.valueOf(stats.getMin()))
.append(delimiter)
.append(String.valueOf(stats.getMax()))
.append(delimiter)
.append(String.valueOf(stats.getPercentile(95)))
.append(delimiter)
.append(String.valueOf(stats.getPercentile(90)))
.append(delimiter)
.append(String.valueOf(stats.getPercentile(80)))
.append(delimiter)
.append(String.valueOf(stats.getPercentile(75)))
.append(delimiter)
.append(String.valueOf(stats.getPercentile(50)));
bw.append(
new StringJoiner(delimiter)
.add(zoneId.toString())
.add(centerX)
.add(centerY)
.add(format.format(stats.getN()))
.add(format.format(stats.getSum()))
.add(String.valueOf(stats.getMean()))
.add(String.valueOf(stats.getMin()))
.add(String.valueOf(stats.getMax()))
.add(String.valueOf(stats.getPercentile(95)))
.add(String.valueOf(stats.getPercentile(90)))
.add(String.valueOf(stats.getPercentile(80)))
.add(String.valueOf(stats.getPercentile(75)))
.add(String.valueOf(stats.getPercentile(50))).toString()
);
}
bw.flush();
bw.close();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Set;
import java.util.function.Supplier;

Expand Down Expand Up @@ -38,7 +40,7 @@ public class PrebookingStopActivity extends FirstLastSimStepDynActivity implemen
private final Map<Id<Request>, ? extends AcceptedDrtRequest> dropoffRequests;

private final IdMap<Request, Double> enterTimes = new IdMap<>(Request.class);
private final IdMap<Request, Double> leaveTimes = new IdMap<>(Request.class);
private final Queue<QueuedRequest> leaveTimes = new PriorityQueue<>();
private final Set<Id<Request>> enteredRequests = new HashSet<>();

private final PrebookingManager prebookingManager;
Expand Down Expand Up @@ -84,27 +86,30 @@ protected void beforeFirstStep(double now) {
private void initDropoffRequests(double now) {
for (var request : dropoffRequests.values()) {
double leaveTime = now + stopDurationProvider.calcDropoffDuration(vehicle, request.getRequest());
leaveTimes.put(request.getId(), leaveTime);
leaveTimes.add(new QueuedRequest(request.getId(), leaveTime));
}

updateDropoffRequests(now);
}

private boolean updateDropoffRequests(double now) {
var iterator = leaveTimes.entrySet().iterator();

while (iterator.hasNext()) {
var entry = iterator.next();

if (entry.getValue() <= now) { // Request should leave now
passengerHandler.dropOffPassengers(driver, entry.getKey(), now);
prebookingManager.notifyDropoff(entry.getKey());
onboard -= dropoffRequests.get(entry.getKey()).getPassengerCount();
iterator.remove();
}
while (!leaveTimes.isEmpty() && leaveTimes.peek().time <= now) {
Id<Request> requestId = leaveTimes.poll().id;
passengerHandler.dropOffPassengers(driver, requestId, now);
prebookingManager.notifyDropoff(requestId);
onboard -= dropoffRequests.get(requestId).getPassengerCount();
}

return leaveTimes.size() == 0;
return leaveTimes.isEmpty();
}

private record QueuedRequest(Id<Request> id, double time) implements Comparable<QueuedRequest> {

@Override
public int compareTo(QueuedRequest o) {
return Double.compare(this.time, o.time);
}
}

private boolean updatePickupRequests(double now) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ public void install() {
addTravelTimeBinding(DvrpTravelTimeModule.DVRP_ESTIMATED).toProvider(() -> {
URL url = ConfigGroup.getInputFileURL(getConfig().getContext(), dvrpCfg.initialTravelTimesFile);
var timeDiscretizer = new TimeDiscretizer(getConfig().travelTimeCalculator());
var linkTravelTimes = DvrpOfflineTravelTimes.loadLinkTravelTimes(timeDiscretizer, url);
var linkTravelTimes = DvrpOfflineTravelTimes.loadLinkTravelTimes(timeDiscretizer, url,
getConfig().global().getDefaultDelimiter());
return DvrpOfflineTravelTimes.asTravelTime(timeDiscretizer, linkTravelTimes);
}).asEagerSingleton();
} else {
Expand Down
Loading

0 comments on commit 8177bfd

Please sign in to comment.