Skip to content

Commit

Permalink
Merge branch 'master' into counts-v2
Browse files Browse the repository at this point in the history
  • Loading branch information
rakow authored Oct 25, 2023
2 parents 8348791 + 46160f1 commit 52ad070
Show file tree
Hide file tree
Showing 100 changed files with 2,738 additions and 744 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ public Integer call() throws Exception {

Table persons = Table.read().csv(CsvReadOptions.builder(IOUtils.getBufferedReader(input.getPath("persons.csv")))
.columnTypesPartial(Map.of("person", ColumnType.TEXT))
.sample(false)
.separator(';').build());

int total = persons.rowCount();
Expand Down Expand Up @@ -132,6 +133,7 @@ public Integer call() throws Exception {

Table trips = Table.read().csv(CsvReadOptions.builder(IOUtils.getBufferedReader(input.getPath("trips.csv")))
.columnTypesPartial(columnTypes)
.sample(false)
.separator(';').build());


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ public void install() {
System.out.println((int) listener.counts.get("car"));
System.out.println(listener.counts.get("walk"));

assertEquals(44195, (int) listener.counts.get("pt"));
assertEquals(132316, (int) listener.counts.get("car"));
assertEquals(82139, (int) listener.counts.get("walk"));
assertEquals(44195, listener.counts.get("pt"), 2);
assertEquals(132316, listener.counts.get("car"), 2);
assertEquals(82139, listener.counts.get("walk"), 2);

}

Expand Down
7 changes: 7 additions & 0 deletions contribs/drt-extensions/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@
<version>16.0-SNAPSHOT</version>
</dependency>

<dependency>
<groupId>org.matsim.contrib</groupId>
<artifactId>informed-mode-choice</artifactId>
<version>16.0-SNAPSHOT</version>
</dependency>

<dependency>
<groupId>org.matsim.contrib</groupId>
<artifactId>simwrapper</artifactId>
Expand All @@ -33,6 +39,7 @@
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<!-- Scenario parameters only used in testing -->
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
import org.matsim.contrib.dvrp.schedule.ScheduleTimingUpdater;
import org.matsim.contrib.dvrp.vrpagent.VrpAgentLogic;
import org.matsim.contrib.ev.infrastructure.ChargingInfrastructure;
import org.matsim.contrib.ev.infrastructure.ChargingInfrastructures;
import org.matsim.contrib.ev.infrastructure.ChargingInfrastructureUtils;
import org.matsim.core.api.experimental.events.EventsManager;
import org.matsim.core.mobsim.framework.MobsimTimer;
import org.matsim.core.modal.ModalProviders;
Expand Down Expand Up @@ -95,8 +95,8 @@ protected void configureQSim() {
getter.getModal(DrtRequestInsertionRetryQueue.class)))).asEagerSingleton();

bindModal(ChargingInfrastructure.class).toProvider(modalProvider(
getter -> ChargingInfrastructures.createModalNetworkChargers(getter.get(ChargingInfrastructure.class),
getter.getModal(Network.class), getMode()))).asEagerSingleton();
getter -> ChargingInfrastructureUtils.createModalNetworkChargers(getter.get(ChargingInfrastructure.class ),
getter.getModal(Network.class), getMode() ))).asEagerSingleton();

// XXX if overridden to something else, make sure that the depots are equipped with chargers
// otherwise vehicles will not re-charge
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
package org.matsim.contrib.drt.extension.estimator;

import org.apache.commons.math3.stat.descriptive.SummaryStatistics;
import org.apache.commons.math3.stat.regression.RegressionResults;
import org.apache.commons.math3.stat.regression.SimpleRegression;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.matsim.api.core.v01.events.PersonMoneyEvent;
import org.matsim.contrib.drt.analysis.DrtEventSequenceCollector;
import org.matsim.contrib.drt.extension.estimator.run.DrtEstimatorConfigGroup;
import org.matsim.contrib.drt.fare.DrtFareParams;
import org.matsim.contrib.drt.routing.DrtRoute;
import org.matsim.contrib.drt.run.DrtConfigGroup;
import org.matsim.contrib.drt.speedup.DrtSpeedUp;
import org.matsim.core.controler.events.IterationEndsEvent;
import org.matsim.core.controler.listener.IterationEndsListener;
import org.matsim.core.utils.misc.OptionalTime;

import java.util.SplittableRandom;

/**
* Estimates drt trips based only daily averages. No spatial or temporal differentiation is taken into account for the estimate.
* This estimator is suited for small scenarios with few vehicles and trips and consequently few data points.
*/
public class BasicDrtEstimator implements DrtEstimator, IterationEndsListener {

private static final Logger log = LogManager.getLogger(BasicDrtEstimator.class);

private final DrtEventSequenceCollector collector;
private final DrtEstimatorConfigGroup config;
private final DrtConfigGroup drtConfig;

private final SplittableRandom rnd = new SplittableRandom();
/**
* Currently valid estimates.
*/
private GlobalEstimate currentEst;
private RegressionResults fare;

public BasicDrtEstimator(DrtEventSequenceCollector collector, DrtEstimatorConfigGroup config,
DrtConfigGroup drtConfig) {
//zones = injector.getModal(DrtZonalSystem.class);
this.collector = collector;
this.config = config;
this.drtConfig = drtConfig;
}

@Override
public void notifyIterationEnds(IterationEndsEvent event) {

// Speed-up iteration need to be ignored for the estimates
if (drtConfig.getDrtSpeedUpParams().isPresent() &&
DrtSpeedUp.isTeleportDrtUsers(drtConfig.getDrtSpeedUpParams().get(),
event.getServices().getConfig().controller(), event.getIteration())) {
return;
}

GlobalEstimate est = new GlobalEstimate();

int n = 0;

int nRejections = collector.getRejectedRequestSequences().size();
int nSubmitted = collector.getRequestSubmissions().size();

for (DrtEventSequenceCollector.EventSequence seq : collector.getPerformedRequestSequences().values()) {

if (seq.getPickedUp().isPresent() && seq.getDroppedOff().isPresent()) {

double waitTime = seq.getPickedUp().get().getTime() - seq.getSubmitted().getTime();
est.waitTime.addValue(waitTime);

double unsharedTime = seq.getSubmitted().getUnsharedRideTime();
double travelTime = seq.getDroppedOff().get().getTime() - seq.getPickedUp().get().getTime();

est.detour.addValue(travelTime / unsharedTime);

double fare = seq.getDrtFares().stream().mapToDouble(PersonMoneyEvent::getAmount).sum();
est.fare.addData(seq.getSubmitted().getUnsharedRideDistance(), fare);
n++;
}
}

// At least some data points are required
if (n <= 3)
return;

fare = est.fare.regress();

double rejectionRate = (double) nRejections / nSubmitted;

if (currentEst == null) {
est.meanWait = est.waitTime.getMean();
est.stdWait = est.waitTime.getStandardDeviation();
est.meanDetour = est.detour.getMean();
est.stdDetour = est.detour.getStandardDeviation();
est.rejectionRate = rejectionRate;
} else {
est.meanWait = config.decayFactor * est.waitTime.getMean() + (1 - config.decayFactor) * currentEst.waitTime.getMean();
est.stdWait = config.decayFactor * est.waitTime.getStandardDeviation() + (1 - config.decayFactor) * currentEst.waitTime.getStandardDeviation();
est.meanDetour = config.decayFactor * est.detour.getMean() + (1 - config.decayFactor) * currentEst.detour.getMean();
est.stdDetour = config.decayFactor * est.detour.getStandardDeviation() + (1 - config.decayFactor) * currentEst.detour.getStandardDeviation();
est.rejectionRate = config.decayFactor * rejectionRate + (1 - config.decayFactor) * currentEst.rejectionRate;
}

log.info("Calculated {}", est);
currentEst = est;
}

@Override
public Estimate estimate(DrtRoute route, OptionalTime departureTime) {

if (currentEst == null) {
// If not estimates are present, use travel time alpha as detour
// beta is not used, because estimates are supposed to be minimums and not worst cases
double travelTime = Math.min(route.getDirectRideTime() + drtConfig.maxAbsoluteDetour,
route.getDirectRideTime() * drtConfig.maxTravelTimeAlpha);

double fare = 0;
if (drtConfig.getDrtFareParams().isPresent()) {
DrtFareParams fareParams = drtConfig.getDrtFareParams().get();
fare = fareParams.distanceFare_m * route.getDistance()
+ fareParams.timeFare_h * route.getDirectRideTime() / 3600.0
+ fareParams.baseFare;

fare = Math.max(fare, fareParams.minFarePerTrip);
}

// for distance, also use the max travel time alpha
return new Estimate(route.getDistance() * drtConfig.maxTravelTimeAlpha, travelTime, drtConfig.maxWaitTime, fare, 0);
}

double fare = 0;
if (this.fare != null)
fare = this.fare.getParameterEstimate(0) + this.fare.getParameterEstimate(1) * route.getDistance();

if (drtConfig.getDrtFareParams().isPresent()) {
fare = Math.max(fare, drtConfig.getDrtFareParams().get().minFarePerTrip);
}

double detour = Math.max(1, rnd.nextGaussian(currentEst.meanDetour, config.randomization * currentEst.stdDetour));
double waitTime = Math.max(0, rnd.nextGaussian(currentEst.meanWait, config.randomization * currentEst.stdWait));

return new Estimate(route.getDistance() * detour, route.getDirectRideTime() * detour, waitTime, fare, currentEst.rejectionRate);
}

/**
* Helper class to hold statistics.
*/
private static final class GlobalEstimate {

private final SummaryStatistics waitTime = new SummaryStatistics();
private final SummaryStatistics detour = new SummaryStatistics();
private final SimpleRegression fare = new SimpleRegression(true);

private double meanWait;
private double stdWait;
private double meanDetour;
private double stdDetour;
private double rejectionRate;

@Override
public String toString() {
return "GlobalEstimate{" +
"meanWait=" + meanWait +
", stdWait=" + stdWait +
", meanDetour=" + meanDetour +
", stdDetour=" + stdDetour +
", rejectionRate=" + rejectionRate +
'}';
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package org.matsim.contrib.drt.extension.estimator;

import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;
import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.matsim.api.core.v01.events.PersonMoneyEvent;
import org.matsim.contrib.drt.analysis.DrtEventSequenceCollector;
import org.matsim.contrib.drt.extension.estimator.run.DrtEstimatorConfigGroup;
import org.matsim.contrib.drt.routing.DrtRoute;
import org.matsim.core.controler.events.AfterMobsimEvent;
import org.matsim.core.controler.events.ShutdownEvent;
import org.matsim.core.controler.events.StartupEvent;
import org.matsim.core.controler.listener.AfterMobsimListener;
import org.matsim.core.controler.listener.ShutdownListener;
import org.matsim.core.controler.listener.StartupListener;
import org.matsim.core.utils.misc.OptionalTime;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

/**
* Analyzes and outputs drt estimates errors metrics based on daily requests.
*/
public final class DrtEstimateAnalyzer implements StartupListener, ShutdownListener, AfterMobsimListener {

private static final Logger log = LogManager.getLogger(DrtEstimateAnalyzer.class);

// Might be useful but not needed currently
//private final DefaultMainLegRouter.RouteCreator creator;
private final DrtEstimator estimator;
private final DrtEventSequenceCollector collector;
private final DrtEstimatorConfigGroup config;

private CSVPrinter csv;

public DrtEstimateAnalyzer(DrtEstimator estimator, DrtEventSequenceCollector collector, DrtEstimatorConfigGroup config) {
this.estimator = estimator;
this.collector = collector;
this.config = config;
}

@Override
public void notifyStartup(StartupEvent event) {

String filename = event.getServices().getControlerIO().getOutputFilename("drt_estimates_" + config.getMode() + ".csv");

try {
csv = new CSVPrinter(Files.newBufferedWriter(Path.of(filename), StandardCharsets.UTF_8), CSVFormat.DEFAULT);
csv.printRecord("iteration",
"wait_time_mae", "wait_time_err_q5", "wait_time_err_q50", "wait_time_err_q95",
"travel_time_mae", "travel_time_err_q5", "travel_time_err_q50", "travel_time_err_q95",
"fare_mae", "fare_err_q5", "fare_err_q50", "fare_err_q95"
);

} catch (IOException e) {
throw new UncheckedIOException("Could not open output file for estimates.", e);
}
}

@Override
public void notifyShutdown(ShutdownEvent event) {
try {
csv.close();
} catch (IOException e) {
log.warn("Could not close drt estimate file", e);
}
}

/**
* Needs to run before any estimators updates.
*/
@Override
public void notifyAfterMobsim(AfterMobsimEvent event) {

try {
csv.printRecord(calcMetrics(event.getIteration()));
csv.flush();
} catch (IOException e) {
throw new RuntimeException(e);
}
}

/**
* Return row of metrics for the csv file.
*/
private Iterable<Number> calcMetrics(int iteration) {

DescriptiveStatistics waitTime = new DescriptiveStatistics();
DescriptiveStatistics travelTime = new DescriptiveStatistics();
DescriptiveStatistics fare = new DescriptiveStatistics();

for (DrtEventSequenceCollector.EventSequence seq : collector.getPerformedRequestSequences().values()) {
if (seq.getPickedUp().isPresent() && seq.getDroppedOff().isPresent()) {

// many attributes are not filled, when using the constructor
DrtRoute route = new DrtRoute(seq.getSubmitted().getFromLinkId(), seq.getSubmitted().getToLinkId());
route.setDirectRideTime(seq.getSubmitted().getUnsharedRideTime());
route.setDistance(seq.getSubmitted().getUnsharedRideDistance());

double valWaitTime = seq.getPickedUp().get().getTime() - seq.getSubmitted().getTime();
double valTravelTime = seq.getDroppedOff().get().getTime() - seq.getPickedUp().get().getTime();
double valFare = seq.getDrtFares().stream().mapToDouble(PersonMoneyEvent::getAmount).sum();

DrtEstimator.Estimate estimate = estimator.estimate(route, OptionalTime.defined(seq.getSubmitted().getTime()));

waitTime.addValue(Math.abs(estimate.waitingTime() - valWaitTime));
travelTime.addValue(Math.abs(estimate.travelTime() - valTravelTime));
fare.addValue(Math.abs(estimate.fare() - valFare));
}
}

return List.of(
iteration,
waitTime.getMean(), waitTime.getPercentile(5), waitTime.getPercentile(50), waitTime.getPercentile(95),
travelTime.getMean(), travelTime.getPercentile(5), travelTime.getPercentile(50), travelTime.getPercentile(95),
fare.getMean(), fare.getPercentile(5), fare.getPercentile(50), fare.getPercentile(95)
);
}

}
Loading

0 comments on commit 52ad070

Please sign in to comment.