From 1d981161d7d2568b6b4d7bc1c473e720470558bc Mon Sep 17 00:00:00 2001 From: Kai Nagel Date: Mon, 5 Feb 2024 14:48:59 +0100 Subject: [PATCH 01/19] changes --- .../contrib/drt/teleportation/Test.java | 2 + examples/scenarios/mielec/empty_config.xml | 71 +++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/Test.java create mode 100644 examples/scenarios/mielec/empty_config.xml diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/Test.java b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/Test.java new file mode 100644 index 00000000000..4880fcadbbf --- /dev/null +++ b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/Test.java @@ -0,0 +1,2 @@ +package org.matsim.contrib.drt.teleportation;class Test { +} diff --git a/examples/scenarios/mielec/empty_config.xml b/examples/scenarios/mielec/empty_config.xml new file mode 100644 index 00000000000..db2a8763ade --- /dev/null +++ b/examples/scenarios/mielec/empty_config.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 0ba8e3c28fd789e6dfa6317fae1d8cb2c72adb0f Mon Sep 17 00:00:00 2001 From: Kai Nagel Date: Mon, 5 Feb 2024 15:56:04 +0100 Subject: [PATCH 02/19] changes --- .../contrib/drt/teleportation/Test2.java | 322 ++++++++++++++++++ examples/scenarios/dvrp-grid/empty_config.xml | 20 ++ examples/scenarios/mielec/empty_config.xml | 67 ---- 3 files changed, 342 insertions(+), 67 deletions(-) create mode 100644 contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/Test2.java create mode 100644 examples/scenarios/dvrp-grid/empty_config.xml diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/Test2.java b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/Test2.java new file mode 100644 index 00000000000..386bcf9a062 --- /dev/null +++ b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/Test2.java @@ -0,0 +1,322 @@ +package org.matsim.contrib.drt.teleportation; + +import com.google.common.collect.ImmutableMap; +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.google.inject.TypeLiteral; +import com.google.inject.name.Named; +import org.apache.commons.lang3.tuple.Pair; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.locationtech.jts.geom.prep.PreparedGeometry; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Network; +import org.matsim.api.core.v01.population.Activity; +import org.matsim.api.core.v01.population.Person; +import org.matsim.api.core.v01.population.PlanElement; +import org.matsim.contrib.drt.routing.DrtRouteCreator; +import org.matsim.contrib.drt.routing.DrtStopFacility; +import org.matsim.contrib.drt.routing.DrtStopFacilityImpl; +import org.matsim.contrib.drt.routing.DrtStopNetwork; +import org.matsim.contrib.drt.run.DrtConfigGroup; +import org.matsim.contrib.drt.run.DrtControlerCreator; +import org.matsim.contrib.drt.run.DrtModeRoutingModule; +import org.matsim.contrib.dvrp.router.*; +import org.matsim.contrib.dvrp.run.AbstractDvrpModeModule; +import org.matsim.contrib.dvrp.run.DvrpMode; +import org.matsim.contrib.dvrp.run.DvrpModes; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigGroup; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.modal.ModalProviders; +import org.matsim.core.population.PopulationUtils; +import org.matsim.core.router.DefaultRoutingRequest; +import org.matsim.core.router.RoutingModule; +import org.matsim.core.router.RoutingRequest; +import org.matsim.core.router.TripRouter; +import org.matsim.core.router.costcalculators.TravelDisutilityFactory; +import org.matsim.core.router.speedy.SpeedyALTFactory; +import org.matsim.core.router.util.LeastCostPathCalculatorFactory; +import org.matsim.core.router.util.TravelTime; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.collections.QuadTrees; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.core.utils.timing.TimeInterpretation; +import org.matsim.examples.ExamplesUtils; +import org.matsim.facilities.Facility; +import org.matsim.pt.transitSchedule.api.TransitScheduleReader; +import org.matsim.testcases.MatsimTestUtils; +import org.matsim.utils.gis.shp2matsim.ShpGeometryUtils; +import org.matsim.utils.objectattributes.attributable.Attributes; + +import java.net.URL; +import java.util.*; + +class Test{ + + @RegisterExtension public MatsimTestUtils utils = new MatsimTestUtils(); + + @org.junit.jupiter.api.Test void test1() { + + URL url = IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "mielec" ), "empty_config.xml" ); + Config config = ConfigUtils.loadConfig( url ); + + config.network().setInputFile( "network.xml" ); + config.plans().setInputFile( "plans_only_drt_1.0.xml.gz" ); + + config.controller().setOutputDirectory( utils.getOutputDirectory() ); + config.controller().setLastIteration( 0 ); + + Scenario scenario = DrtControlerCreator.createScenarioWithDrtRouteFactory( config ); + ScenarioUtils.loadScenario( scenario ); + + Controler controler = new Controler( scenario ); + controler.addOverridingModule( new AbstractDvrpModeModule("drt"){ + @Override public void install(){ + DrtConfigGroup drtCfg = ConfigUtils.addOrGetModule( this.getConfig(), DrtConfigGroup.class ); + + this.addRoutingModuleBinding( "drt" ).toProvider( new DrtEstimatingRoutingModuleProvider( "drt" ) ); + + modalMapBinder(DvrpRoutingModuleProvider.Stage.class, RoutingModule.class).addBinding( + DvrpRoutingModuleProvider.Stage.MAIN) + .toProvider(new DvrpModeRoutingModule.DefaultMainLegRouterProvider(getMode()) );// not singleton + // this seems to bind an enum. maybe more heavyweight than necessary? + + bindModal( DefaultMainLegRouter.RouteCreator.class ).toProvider( + new DrtRouteCreatorProvider(drtCfg) );// not singleton + // this is used in DvrpModeRoutingModule (recruited by the DvrpRoutingModuleProvider above) + + bindModal( DrtStopNetwork.class ).toProvider(new DrtStopNetworkProvider(getConfig(), drtCfg) ).asEagerSingleton(); + // yyyy possibly not used for door2door; try to move inside the corresponding switch statement below. kai, feb'24 + + switch( drtCfg.operationalScheme ){ + case door2door -> bindModal( DvrpRoutingModule.AccessEgressFacilityFinder.class ).toProvider( + modalProvider( getter -> new DecideOnLinkAccessEgressFacilityFinder( getter.getModal( Network.class ) ) ) ) + .asEagerSingleton(); + case stopbased, serviceAreaBased -> { + bindModal( DvrpRoutingModule.AccessEgressFacilityFinder.class ).toProvider( modalProvider( + getter -> new ClosestAccessEgressFacilityFinder( drtCfg.maxWalkDistance, + getter.get( Network.class ), + QuadTrees.createQuadTree( getter.getModal( DrtStopNetwork.class ).getDrtStops().values() ) ) ) ) + .asEagerSingleton(); + } + default -> throw new IllegalStateException( "Unexpected value: " + drtCfg.operationalScheme ); + } + + } + } ); + + controler.run(); + + } + + private static class DrtEstimatingRoutingModule implements RoutingModule { + private static final Logger logger = LogManager.getLogger( DrtEstimatingRoutingModule.class ); + + public interface AccessEgressFacilityFinder { + Optional> findFacilities( Facility fromFacility, Facility toFacility, + Attributes tripAttributes ); + } + + private final AccessEgressFacilityFinder stopFinder; + private final String mode; + private final RoutingModule mainRouter; + private final RoutingModule accessRouter; + private final RoutingModule egressRouter; + private final TimeInterpretation timeInterpretation; + + public DrtEstimatingRoutingModule( RoutingModule mainRouter, RoutingModule accessRouter, RoutingModule egressRouter, + AccessEgressFacilityFinder stopFinder, String mode, TimeInterpretation timeInterpretation ) { + this.mainRouter = mainRouter; + this.stopFinder = stopFinder; + this.mode = mode; + this.accessRouter = accessRouter; + this.egressRouter = egressRouter; + this.timeInterpretation = timeInterpretation; + } + + @Override + public List calcRoute(RoutingRequest request) { + final Facility fromFacility = request.getFromFacility(); + final Facility toFacility = request.getToFacility(); + final double departureTime = request.getDepartureTime(); + final Person person = request.getPerson(); + + Optional> stops = stopFinder.findFacilities( + Objects.requireNonNull(fromFacility, "fromFacility is null" ), + Objects.requireNonNull(toFacility, "toFacility is null"), request.getAttributes()); + if (stops.isEmpty()) { + logger.debug("No access/egress stops found, agent will use fallback mode as leg mode (usually " + + TransportMode.walk + + ") and routing mode " + + mode + + ". Agent Id:\t" + + person.getId()); + return null; + } + + Facility accessFacility = stops.get().getLeft(); + Facility egressFacility = stops.get().getRight(); + if (accessFacility.getLinkId().equals(egressFacility.getLinkId())) { + logger.debug("Start and end stop are the same, agent will use fallback mode as leg mode (usually " + + TransportMode.walk + + ") and routing mode " + + mode + + ". Agent Id:\t" + + person.getId()); + return null; + } + + List trip = new ArrayList<>(); + + double now = departureTime; + + // access (sub-)trip: + List accessTrip = accessRouter.calcRoute( + DefaultRoutingRequest.of(fromFacility, accessFacility, now, person, request.getAttributes() ) ); + if (!accessTrip.isEmpty()) { + trip.addAll(accessTrip); + now = timeInterpretation.decideOnElementsEndTime(accessTrip, now).seconds(); + + // interaction activity: + trip.add(createDrtStageActivity(accessFacility, now)); + } + + // dvrp proper leg: + List drtLeg = mainRouter.calcRoute( + DefaultRoutingRequest.of(accessFacility, egressFacility, now, person, request.getAttributes())); + trip.addAll(drtLeg); + now = timeInterpretation.decideOnElementsEndTime(drtLeg, now).seconds(); + + // egress (sub-)trip: + List egressTrip = egressRouter.calcRoute( + DefaultRoutingRequest.of(egressFacility, toFacility, now, person, request.getAttributes())); + if (!egressTrip.isEmpty()) { + // interaction activity: + trip.add(createDrtStageActivity(egressFacility, now)); + + trip.addAll(egressTrip); + } + + return trip; + } + + private Activity createDrtStageActivity( Facility stopFacility, double now ) { + return PopulationUtils.createStageActivityFromCoordLinkIdAndModePrefix(stopFacility.getCoord(), + stopFacility.getLinkId(), mode ); + } + } + + private static class DrtEstimatingRoutingModuleProvider extends ModalProviders.AbstractProvider { + public enum Stage {ACCESS, MAIN, EGRESS} + + @Inject + @Named(TransportMode.walk) + private RoutingModule walkRouter; + + @Inject private TimeInterpretation timeInterpretation; + + @Inject private TripRouter tripRouter; + + public DrtEstimatingRoutingModuleProvider(String mode) { + super(mode, DvrpModes::mode ); + } + + @Override + public DrtEstimatingRoutingModule get() { + + RoutingModule drtRoutingModule = tripRouter.getRoutingModule( "drt" ); + drtRoutingModule.c + + Map stageRouters = getModalInstance( new TypeLiteral>() { + } ); + RoutingModule mainRouter = Objects.requireNonNull(stageRouters.get( DvrpRoutingModuleProvider.Stage.MAIN ), + "Main mode router must be explicitly bound"); + RoutingModule accessRouter = stageRouters.getOrDefault( DvrpRoutingModuleProvider.Stage.ACCESS, walkRouter ); + RoutingModule egressRouter = stageRouters.getOrDefault( DvrpRoutingModuleProvider.Stage.EGRESS, walkRouter ); + + return new DrtEstimatingRoutingModule(mainRouter, accessRouter, egressRouter, + getModalInstance( DrtEstimatingRoutingModule.AccessEgressFacilityFinder.class ), getMode(), timeInterpretation); + } + + } + + private static class DrtRouteCreatorProvider extends ModalProviders.AbstractProvider { + private final LeastCostPathCalculatorFactory leastCostPathCalculatorFactory; + + private final DrtConfigGroup drtCfg; + + private DrtRouteCreatorProvider(DrtConfigGroup drtCfg) { + super(drtCfg.getMode(), DvrpModes::mode); + this.drtCfg = drtCfg; + leastCostPathCalculatorFactory = new SpeedyALTFactory(); + } + + @Override + public DrtRouteCreator get() { + var travelTime = getModalInstance( TravelTime.class ); + return new DrtRouteCreator(drtCfg, getModalInstance(Network.class), leastCostPathCalculatorFactory, + travelTime, getModalInstance( TravelDisutilityFactory.class )); + } + } + + private static class DrtStopNetworkProvider extends ModalProviders.AbstractProvider { + + private final DrtConfigGroup drtCfg; + private final Config config; + + private DrtStopNetworkProvider(Config config, DrtConfigGroup drtCfg) { + super(drtCfg.getMode(), DvrpModes::mode); + this.drtCfg = drtCfg; + this.config = config; + } + + @Override + public DrtStopNetwork get() { + switch (drtCfg.operationalScheme) { + case door2door: + return ImmutableMap::of; + case stopbased: + return createDrtStopNetworkFromTransitSchedule(config, drtCfg); + case serviceAreaBased: + return createDrtStopNetworkFromServiceArea(config, drtCfg, getModalInstance(Network.class)); + default: + throw new RuntimeException("Unsupported operational scheme: " + drtCfg.operationalScheme); + } + } + } + + private static DrtStopNetwork createDrtStopNetworkFromServiceArea(Config config, DrtConfigGroup drtCfg, + Network drtNetwork) { + final List preparedGeometries = ShpGeometryUtils.loadPreparedGeometries( + ConfigGroup.getInputFileURL(config.getContext(), drtCfg.drtServiceAreaShapeFile ) ); + ImmutableMap, DrtStopFacility> drtStops = drtNetwork.getLinks() + .values() + .stream() + .filter(link -> ShpGeometryUtils.isCoordInPreparedGeometries(link.getToNode().getCoord(), + preparedGeometries)) + .map( DrtStopFacilityImpl::createFromLink ) + .collect(ImmutableMap.toImmutableMap(DrtStopFacility::getId, f -> f)); + return () -> drtStops; + } + + private static DrtStopNetwork createDrtStopNetworkFromTransitSchedule(Config config, DrtConfigGroup drtCfg) { + URL url = ConfigGroup.getInputFileURL(config.getContext(), drtCfg.transitStopFile); + Scenario scenario = ScenarioUtils.createScenario(ConfigUtils.createConfig()); + new TransitScheduleReader(scenario).readURL(url ); + ImmutableMap, DrtStopFacility> drtStops = scenario.getTransitSchedule() + .getFacilities() + .values() + .stream() + .map(DrtStopFacilityImpl::createFromFacility) + .collect(ImmutableMap.toImmutableMap(DrtStopFacility::getId, f -> f)); + return () -> drtStops; + } + + +} diff --git a/examples/scenarios/dvrp-grid/empty_config.xml b/examples/scenarios/dvrp-grid/empty_config.xml new file mode 100644 index 00000000000..104d6d369e6 --- /dev/null +++ b/examples/scenarios/dvrp-grid/empty_config.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/examples/scenarios/mielec/empty_config.xml b/examples/scenarios/mielec/empty_config.xml index db2a8763ade..a7240fffd87 100644 --- a/examples/scenarios/mielec/empty_config.xml +++ b/examples/scenarios/mielec/empty_config.xml @@ -1,71 +1,4 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 609b4ad43bc5c62cd933ee341d6ae182748baeba Mon Sep 17 00:00:00 2001 From: Kai Nagel Date: Mon, 5 Feb 2024 16:10:24 +0100 Subject: [PATCH 03/19] small changes towards end --- .../contrib/drt/teleportation/Test.java | 322 +++++++++++++++++- .../contrib/drt/teleportation/Test2.java | 251 ++------------ .../contrib/drt/routing/DrtRouteUpdater.java | 2 + .../contrib/drt/run/DrtModeRoutingModule.java | 35 +- 4 files changed, 372 insertions(+), 238 deletions(-) diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/Test.java b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/Test.java index 4880fcadbbf..57539c3796b 100644 --- a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/Test.java +++ b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/Test.java @@ -1,2 +1,322 @@ -package org.matsim.contrib.drt.teleportation;class Test { +package org.matsim.contrib.drt.teleportation; + +import com.google.common.collect.ImmutableMap; +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.google.inject.TypeLiteral; +import com.google.inject.name.Named; +import org.apache.commons.lang3.tuple.Pair; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.locationtech.jts.geom.prep.PreparedGeometry; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Network; +import org.matsim.api.core.v01.population.Activity; +import org.matsim.api.core.v01.population.Person; +import org.matsim.api.core.v01.population.PlanElement; +import org.matsim.contrib.drt.routing.DrtRouteCreator; +import org.matsim.contrib.drt.routing.DrtStopFacility; +import org.matsim.contrib.drt.routing.DrtStopFacilityImpl; +import org.matsim.contrib.drt.routing.DrtStopNetwork; +import org.matsim.contrib.drt.run.DrtConfigGroup; +import org.matsim.contrib.drt.run.DrtControlerCreator; +import org.matsim.contrib.drt.run.DrtModeRoutingModule; +import org.matsim.contrib.dvrp.router.*; +import org.matsim.contrib.dvrp.run.AbstractDvrpModeModule; +import org.matsim.contrib.dvrp.run.DvrpMode; +import org.matsim.contrib.dvrp.run.DvrpModes; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigGroup; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.modal.ModalProviders; +import org.matsim.core.population.PopulationUtils; +import org.matsim.core.router.DefaultRoutingRequest; +import org.matsim.core.router.RoutingModule; +import org.matsim.core.router.RoutingRequest; +import org.matsim.core.router.TripRouter; +import org.matsim.core.router.costcalculators.TravelDisutilityFactory; +import org.matsim.core.router.speedy.SpeedyALTFactory; +import org.matsim.core.router.util.LeastCostPathCalculatorFactory; +import org.matsim.core.router.util.TravelTime; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.collections.QuadTrees; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.core.utils.timing.TimeInterpretation; +import org.matsim.examples.ExamplesUtils; +import org.matsim.facilities.Facility; +import org.matsim.pt.transitSchedule.api.TransitScheduleReader; +import org.matsim.testcases.MatsimTestUtils; +import org.matsim.utils.gis.shp2matsim.ShpGeometryUtils; +import org.matsim.utils.objectattributes.attributable.Attributes; + +import java.net.URL; +import java.util.*; + +class Test{ + + @RegisterExtension public MatsimTestUtils utils = new MatsimTestUtils(); + + @org.junit.jupiter.api.Test void test1() { + + URL url = IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "mielec" ), "empty_config.xml" ); + Config config = ConfigUtils.loadConfig( url ); + + config.network().setInputFile( "network.xml" ); + config.plans().setInputFile( "plans_only_drt_1.0.xml.gz" ); + + config.controller().setOutputDirectory( utils.getOutputDirectory() ); + config.controller().setLastIteration( 0 ); + + Scenario scenario = DrtControlerCreator.createScenarioWithDrtRouteFactory( config ); + ScenarioUtils.loadScenario( scenario ); + + Controler controler = new Controler( scenario ); + controler.addOverridingModule( new AbstractDvrpModeModule("drt"){ + @Override public void install(){ + DrtConfigGroup drtCfg = ConfigUtils.addOrGetModule( this.getConfig(), DrtConfigGroup.class ); + + this.addRoutingModuleBinding( "drt" ).toProvider( new DrtEstimatingRoutingModuleProvider( "drt" ) ); + + modalMapBinder(DvrpRoutingModuleProvider.Stage.class, RoutingModule.class).addBinding( + DvrpRoutingModuleProvider.Stage.MAIN) + .toProvider(new DvrpModeRoutingModule.DefaultMainLegRouterProvider(getMode()) );// not singleton + // this seems to bind an enum. maybe more heavyweight than necessary? + + bindModal( DefaultMainLegRouter.RouteCreator.class ).toProvider( + new DrtRouteCreatorProvider(drtCfg) );// not singleton + // this is used in DvrpModeRoutingModule (recruited by the DvrpRoutingModuleProvider above) + + bindModal( DrtStopNetwork.class ).toProvider(new DrtStopNetworkProvider(getConfig(), drtCfg) ).asEagerSingleton(); + // yyyy possibly not used for door2door; try to move inside the corresponding switch statement below. kai, feb'24 + + switch( drtCfg.operationalScheme ){ + case door2door -> bindModal( DvrpRoutingModule.AccessEgressFacilityFinder.class ).toProvider( + modalProvider( getter -> new DecideOnLinkAccessEgressFacilityFinder( getter.getModal( Network.class ) ) ) ) + .asEagerSingleton(); + case stopbased, serviceAreaBased -> { + bindModal( DvrpRoutingModule.AccessEgressFacilityFinder.class ).toProvider( modalProvider( + getter -> new ClosestAccessEgressFacilityFinder( drtCfg.maxWalkDistance, + getter.get( Network.class ), + QuadTrees.createQuadTree( getter.getModal( DrtStopNetwork.class ).getDrtStops().values() ) ) ) ) + .asEagerSingleton(); + } + default -> throw new IllegalStateException( "Unexpected value: " + drtCfg.operationalScheme ); + } + + } + } ); + + controler.run(); + + } + + private static class DrtEstimatingRoutingModule implements RoutingModule { + private static final Logger logger = LogManager.getLogger( DrtEstimatingRoutingModule.class ); + + public interface AccessEgressFacilityFinder { + Optional> findFacilities( Facility fromFacility, Facility toFacility, + Attributes tripAttributes ); + } + + private final AccessEgressFacilityFinder stopFinder; + private final String mode; + private final RoutingModule mainRouter; + private final RoutingModule accessRouter; + private final RoutingModule egressRouter; + private final TimeInterpretation timeInterpretation; + + public DrtEstimatingRoutingModule( RoutingModule mainRouter, RoutingModule accessRouter, RoutingModule egressRouter, + AccessEgressFacilityFinder stopFinder, String mode, TimeInterpretation timeInterpretation ) { + this.mainRouter = mainRouter; + this.stopFinder = stopFinder; + this.mode = mode; + this.accessRouter = accessRouter; + this.egressRouter = egressRouter; + this.timeInterpretation = timeInterpretation; + } + + @Override + public List calcRoute(RoutingRequest request) { + final Facility fromFacility = request.getFromFacility(); + final Facility toFacility = request.getToFacility(); + final double departureTime = request.getDepartureTime(); + final Person person = request.getPerson(); + + Optional> stops = stopFinder.findFacilities( + Objects.requireNonNull(fromFacility, "fromFacility is null" ), + Objects.requireNonNull(toFacility, "toFacility is null"), request.getAttributes()); + if (stops.isEmpty()) { + logger.debug("No access/egress stops found, agent will use fallback mode as leg mode (usually " + + TransportMode.walk + + ") and routing mode " + + mode + + ". Agent Id:\t" + + person.getId()); + return null; + } + + Facility accessFacility = stops.get().getLeft(); + Facility egressFacility = stops.get().getRight(); + if (accessFacility.getLinkId().equals(egressFacility.getLinkId())) { + logger.debug("Start and end stop are the same, agent will use fallback mode as leg mode (usually " + + TransportMode.walk + + ") and routing mode " + + mode + + ". Agent Id:\t" + + person.getId()); + return null; + } + + List trip = new ArrayList<>(); + + double now = departureTime; + + // access (sub-)trip: + List accessTrip = accessRouter.calcRoute( + DefaultRoutingRequest.of(fromFacility, accessFacility, now, person, request.getAttributes() ) ); + if (!accessTrip.isEmpty()) { + trip.addAll(accessTrip); + now = timeInterpretation.decideOnElementsEndTime(accessTrip, now).seconds(); + + // interaction activity: + trip.add(createDrtStageActivity(accessFacility, now)); + } + + // dvrp proper leg: + List drtLeg = mainRouter.calcRoute( + DefaultRoutingRequest.of(accessFacility, egressFacility, now, person, request.getAttributes())); + trip.addAll(drtLeg); + now = timeInterpretation.decideOnElementsEndTime(drtLeg, now).seconds(); + + // egress (sub-)trip: + List egressTrip = egressRouter.calcRoute( + DefaultRoutingRequest.of(egressFacility, toFacility, now, person, request.getAttributes())); + if (!egressTrip.isEmpty()) { + // interaction activity: + trip.add(createDrtStageActivity(egressFacility, now)); + + trip.addAll(egressTrip); + } + + return trip; + } + + private Activity createDrtStageActivity( Facility stopFacility, double now ) { + return PopulationUtils.createStageActivityFromCoordLinkIdAndModePrefix(stopFacility.getCoord(), + stopFacility.getLinkId(), mode ); + } + } + + private static class DrtEstimatingRoutingModuleProvider extends ModalProviders.AbstractProvider { + public enum Stage {ACCESS, MAIN, EGRESS} + + @Inject + @Named(TransportMode.walk) + private RoutingModule walkRouter; + + @Inject private TimeInterpretation timeInterpretation; + + @Inject private TripRouter tripRouter; + + public DrtEstimatingRoutingModuleProvider(String mode) { + super(mode, DvrpModes::mode ); + } + + @Override + public DrtEstimatingRoutingModule get() { + + RoutingModule drtRoutingModule = tripRouter.getRoutingModule( "drt" ); +// drtRoutingModule.c + + Map stageRouters = getModalInstance( new TypeLiteral>() { + } ); + RoutingModule mainRouter = Objects.requireNonNull(stageRouters.get( DvrpRoutingModuleProvider.Stage.MAIN ), + "Main mode router must be explicitly bound"); + RoutingModule accessRouter = stageRouters.getOrDefault( DvrpRoutingModuleProvider.Stage.ACCESS, walkRouter ); + RoutingModule egressRouter = stageRouters.getOrDefault( DvrpRoutingModuleProvider.Stage.EGRESS, walkRouter ); + + return new DrtEstimatingRoutingModule(mainRouter, accessRouter, egressRouter, + getModalInstance( DrtEstimatingRoutingModule.AccessEgressFacilityFinder.class ), getMode(), timeInterpretation); + } + + } + + private static class DrtRouteCreatorProvider extends ModalProviders.AbstractProvider { + private final LeastCostPathCalculatorFactory leastCostPathCalculatorFactory; + + private final DrtConfigGroup drtCfg; + + private DrtRouteCreatorProvider(DrtConfigGroup drtCfg) { + super(drtCfg.getMode(), DvrpModes::mode); + this.drtCfg = drtCfg; + leastCostPathCalculatorFactory = new SpeedyALTFactory(); + } + + @Override + public DrtRouteCreator get() { + var travelTime = getModalInstance( TravelTime.class ); + return new DrtRouteCreator(drtCfg, getModalInstance(Network.class), leastCostPathCalculatorFactory, + travelTime, getModalInstance( TravelDisutilityFactory.class )); + } + } + + private static class DrtStopNetworkProvider extends ModalProviders.AbstractProvider { + + private final DrtConfigGroup drtCfg; + private final Config config; + + private DrtStopNetworkProvider(Config config, DrtConfigGroup drtCfg) { + super(drtCfg.getMode(), DvrpModes::mode); + this.drtCfg = drtCfg; + this.config = config; + } + + @Override + public DrtStopNetwork get() { + switch (drtCfg.operationalScheme) { + case door2door: + return ImmutableMap::of; + case stopbased: + return createDrtStopNetworkFromTransitSchedule(config, drtCfg); + case serviceAreaBased: + return createDrtStopNetworkFromServiceArea(config, drtCfg, getModalInstance(Network.class)); + default: + throw new RuntimeException("Unsupported operational scheme: " + drtCfg.operationalScheme); + } + } + } + + private static DrtStopNetwork createDrtStopNetworkFromServiceArea(Config config, DrtConfigGroup drtCfg, + Network drtNetwork) { + final List preparedGeometries = ShpGeometryUtils.loadPreparedGeometries( + ConfigGroup.getInputFileURL(config.getContext(), drtCfg.drtServiceAreaShapeFile ) ); + ImmutableMap, DrtStopFacility> drtStops = drtNetwork.getLinks() + .values() + .stream() + .filter(link -> ShpGeometryUtils.isCoordInPreparedGeometries(link.getToNode().getCoord(), + preparedGeometries)) + .map( DrtStopFacilityImpl::createFromLink ) + .collect(ImmutableMap.toImmutableMap(DrtStopFacility::getId, f -> f)); + return () -> drtStops; + } + + private static DrtStopNetwork createDrtStopNetworkFromTransitSchedule(Config config, DrtConfigGroup drtCfg) { + URL url = ConfigGroup.getInputFileURL(config.getContext(), drtCfg.transitStopFile); + Scenario scenario = ScenarioUtils.createScenario(ConfigUtils.createConfig()); + new TransitScheduleReader(scenario).readURL(url ); + ImmutableMap, DrtStopFacility> drtStops = scenario.getTransitSchedule() + .getFacilities() + .values() + .stream() + .map(DrtStopFacilityImpl::createFromFacility) + .collect(ImmutableMap.toImmutableMap(DrtStopFacility::getId, f -> f)); + return () -> drtStops; + } + + } diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/Test2.java b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/Test2.java index 386bcf9a062..1ad3d66c3e9 100644 --- a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/Test2.java +++ b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/Test2.java @@ -2,7 +2,6 @@ import com.google.common.collect.ImmutableMap; import com.google.inject.Inject; -import com.google.inject.Provider; import com.google.inject.TypeLiteral; import com.google.inject.name.Named; import org.apache.commons.lang3.tuple.Pair; @@ -17,13 +16,12 @@ import org.matsim.api.core.v01.population.Activity; import org.matsim.api.core.v01.population.Person; import org.matsim.api.core.v01.population.PlanElement; -import org.matsim.contrib.drt.routing.DrtRouteCreator; -import org.matsim.contrib.drt.routing.DrtStopFacility; -import org.matsim.contrib.drt.routing.DrtStopFacilityImpl; -import org.matsim.contrib.drt.routing.DrtStopNetwork; +import org.matsim.api.core.v01.population.Route; +import org.matsim.contrib.drt.extension.estimator.DrtEstimator; +import org.matsim.contrib.drt.extension.estimator.DrtInitialEstimator; +import org.matsim.contrib.drt.routing.*; import org.matsim.contrib.drt.run.DrtConfigGroup; import org.matsim.contrib.drt.run.DrtControlerCreator; -import org.matsim.contrib.drt.run.DrtModeRoutingModule; import org.matsim.contrib.dvrp.router.*; import org.matsim.contrib.dvrp.run.AbstractDvrpModeModule; import org.matsim.contrib.dvrp.run.DvrpMode; @@ -35,10 +33,7 @@ import org.matsim.core.controler.Controler; import org.matsim.core.modal.ModalProviders; import org.matsim.core.population.PopulationUtils; -import org.matsim.core.router.DefaultRoutingRequest; -import org.matsim.core.router.RoutingModule; -import org.matsim.core.router.RoutingRequest; -import org.matsim.core.router.TripRouter; +import org.matsim.core.router.*; import org.matsim.core.router.costcalculators.TravelDisutilityFactory; import org.matsim.core.router.speedy.SpeedyALTFactory; import org.matsim.core.router.util.LeastCostPathCalculatorFactory; @@ -57,7 +52,7 @@ import java.net.URL; import java.util.*; -class Test{ +class Test2{ @RegisterExtension public MatsimTestUtils utils = new MatsimTestUtils(); @@ -76,38 +71,12 @@ class Test{ ScenarioUtils.loadScenario( scenario ); Controler controler = new Controler( scenario ); - controler.addOverridingModule( new AbstractDvrpModeModule("drt"){ - @Override public void install(){ - DrtConfigGroup drtCfg = ConfigUtils.addOrGetModule( this.getConfig(), DrtConfigGroup.class ); - - this.addRoutingModuleBinding( "drt" ).toProvider( new DrtEstimatingRoutingModuleProvider( "drt" ) ); - - modalMapBinder(DvrpRoutingModuleProvider.Stage.class, RoutingModule.class).addBinding( - DvrpRoutingModuleProvider.Stage.MAIN) - .toProvider(new DvrpModeRoutingModule.DefaultMainLegRouterProvider(getMode()) );// not singleton - // this seems to bind an enum. maybe more heavyweight than necessary? - - bindModal( DefaultMainLegRouter.RouteCreator.class ).toProvider( - new DrtRouteCreatorProvider(drtCfg) );// not singleton - // this is used in DvrpModeRoutingModule (recruited by the DvrpRoutingModuleProvider above) - bindModal( DrtStopNetwork.class ).toProvider(new DrtStopNetworkProvider(getConfig(), drtCfg) ).asEagerSingleton(); - // yyyy possibly not used for door2door; try to move inside the corresponding switch statement below. kai, feb'24 - - switch( drtCfg.operationalScheme ){ - case door2door -> bindModal( DvrpRoutingModule.AccessEgressFacilityFinder.class ).toProvider( - modalProvider( getter -> new DecideOnLinkAccessEgressFacilityFinder( getter.getModal( Network.class ) ) ) ) - .asEagerSingleton(); - case stopbased, serviceAreaBased -> { - bindModal( DvrpRoutingModule.AccessEgressFacilityFinder.class ).toProvider( modalProvider( - getter -> new ClosestAccessEgressFacilityFinder( drtCfg.maxWalkDistance, - getter.get( Network.class ), - QuadTrees.createQuadTree( getter.getModal( DrtStopNetwork.class ).getDrtStops().values() ) ) ) ) - .asEagerSingleton(); - } - default -> throw new IllegalStateException( "Unexpected value: " + drtCfg.operationalScheme ); - } + // install the drt routing stuff, but not the mobsim stuff! + controler.addOverridingModule( new AbstractModule(){ + @Override public void install(){ + this.addRoutingModuleBinding( "drt" ).to( DrtEstimatingRoutingModule.class ); } } ); @@ -116,207 +85,37 @@ class Test{ } private static class DrtEstimatingRoutingModule implements RoutingModule { - private static final Logger logger = LogManager.getLogger( DrtEstimatingRoutingModule.class ); - public interface AccessEgressFacilityFinder { - Optional> findFacilities( Facility fromFacility, Facility toFacility, - Attributes tripAttributes ); + private final RoutingModule drtRoutingModule; + private DrtEstimatingRoutingModule( TripRouter tripRouter ) { + this.drtRoutingModule = tripRouter.getRoutingModule( "drt" ); } - private final AccessEgressFacilityFinder stopFinder; - private final String mode; - private final RoutingModule mainRouter; - private final RoutingModule accessRouter; - private final RoutingModule egressRouter; - private final TimeInterpretation timeInterpretation; - public DrtEstimatingRoutingModule( RoutingModule mainRouter, RoutingModule accessRouter, RoutingModule egressRouter, - AccessEgressFacilityFinder stopFinder, String mode, TimeInterpretation timeInterpretation ) { - this.mainRouter = mainRouter; - this.stopFinder = stopFinder; - this.mode = mode; - this.accessRouter = accessRouter; - this.egressRouter = egressRouter; - this.timeInterpretation = timeInterpretation; - } @Override public List calcRoute(RoutingRequest request) { - final Facility fromFacility = request.getFromFacility(); - final Facility toFacility = request.getToFacility(); - final double departureTime = request.getDepartureTime(); - final Person person = request.getPerson(); + List route = drtRoutingModule.calcRoute( request ); - Optional> stops = stopFinder.findFacilities( - Objects.requireNonNull(fromFacility, "fromFacility is null" ), - Objects.requireNonNull(toFacility, "toFacility is null"), request.getAttributes()); - if (stops.isEmpty()) { - logger.debug("No access/egress stops found, agent will use fallback mode as leg mode (usually " - + TransportMode.walk - + ") and routing mode " - + mode - + ". Agent Id:\t" - + person.getId()); - return null; - } - - Facility accessFacility = stops.get().getLeft(); - Facility egressFacility = stops.get().getRight(); - if (accessFacility.getLinkId().equals(egressFacility.getLinkId())) { - logger.debug("Start and end stop are the same, agent will use fallback mode as leg mode (usually " - + TransportMode.walk - + ") and routing mode " - + mode - + ". Agent Id:\t" - + person.getId()); - return null; - } + DrtRouteCreator creator = null; + creator.createRoute( departureTime, accessActLink, egressActLink, person, tripAttributes, routeFactories ); - List trip = new ArrayList<>(); + DrtRouteFactory factory = null; + Route drtRoute = factory.createRoute( startLinkId, endLinkId ); - double now = departureTime; - - // access (sub-)trip: - List accessTrip = accessRouter.calcRoute( - DefaultRoutingRequest.of(fromFacility, accessFacility, now, person, request.getAttributes() ) ); - if (!accessTrip.isEmpty()) { - trip.addAll(accessTrip); - now = timeInterpretation.decideOnElementsEndTime(accessTrip, now).seconds(); - - // interaction activity: - trip.add(createDrtStageActivity(accessFacility, now)); - } + // correct the attributes of the route as we need them - // dvrp proper leg: - List drtLeg = mainRouter.calcRoute( - DefaultRoutingRequest.of(accessFacility, egressFacility, now, person, request.getAttributes())); - trip.addAll(drtLeg); - now = timeInterpretation.decideOnElementsEndTime(drtLeg, now).seconds(); + DrtInitialEstimator estimator = new DrtInitialEstimator(){ + }; - // egress (sub-)trip: - List egressTrip = egressRouter.calcRoute( - DefaultRoutingRequest.of(egressFacility, toFacility, now, person, request.getAttributes())); - if (!egressTrip.isEmpty()) { - // interaction activity: - trip.add(createDrtStageActivity(egressFacility, now)); + DrtEstimator.Estimate estimate = estimator.estimate( route, 12. * 3600 ); - trip.addAll(egressTrip); - } + estimate.travelTime(); + estimate.distance(); - return trip; + return route; } - private Activity createDrtStageActivity( Facility stopFacility, double now ) { - return PopulationUtils.createStageActivityFromCoordLinkIdAndModePrefix(stopFacility.getCoord(), - stopFacility.getLinkId(), mode ); - } } - private static class DrtEstimatingRoutingModuleProvider extends ModalProviders.AbstractProvider { - public enum Stage {ACCESS, MAIN, EGRESS} - - @Inject - @Named(TransportMode.walk) - private RoutingModule walkRouter; - - @Inject private TimeInterpretation timeInterpretation; - - @Inject private TripRouter tripRouter; - - public DrtEstimatingRoutingModuleProvider(String mode) { - super(mode, DvrpModes::mode ); - } - - @Override - public DrtEstimatingRoutingModule get() { - - RoutingModule drtRoutingModule = tripRouter.getRoutingModule( "drt" ); - drtRoutingModule.c - - Map stageRouters = getModalInstance( new TypeLiteral>() { - } ); - RoutingModule mainRouter = Objects.requireNonNull(stageRouters.get( DvrpRoutingModuleProvider.Stage.MAIN ), - "Main mode router must be explicitly bound"); - RoutingModule accessRouter = stageRouters.getOrDefault( DvrpRoutingModuleProvider.Stage.ACCESS, walkRouter ); - RoutingModule egressRouter = stageRouters.getOrDefault( DvrpRoutingModuleProvider.Stage.EGRESS, walkRouter ); - - return new DrtEstimatingRoutingModule(mainRouter, accessRouter, egressRouter, - getModalInstance( DrtEstimatingRoutingModule.AccessEgressFacilityFinder.class ), getMode(), timeInterpretation); - } - - } - - private static class DrtRouteCreatorProvider extends ModalProviders.AbstractProvider { - private final LeastCostPathCalculatorFactory leastCostPathCalculatorFactory; - - private final DrtConfigGroup drtCfg; - - private DrtRouteCreatorProvider(DrtConfigGroup drtCfg) { - super(drtCfg.getMode(), DvrpModes::mode); - this.drtCfg = drtCfg; - leastCostPathCalculatorFactory = new SpeedyALTFactory(); - } - - @Override - public DrtRouteCreator get() { - var travelTime = getModalInstance( TravelTime.class ); - return new DrtRouteCreator(drtCfg, getModalInstance(Network.class), leastCostPathCalculatorFactory, - travelTime, getModalInstance( TravelDisutilityFactory.class )); - } - } - - private static class DrtStopNetworkProvider extends ModalProviders.AbstractProvider { - - private final DrtConfigGroup drtCfg; - private final Config config; - - private DrtStopNetworkProvider(Config config, DrtConfigGroup drtCfg) { - super(drtCfg.getMode(), DvrpModes::mode); - this.drtCfg = drtCfg; - this.config = config; - } - - @Override - public DrtStopNetwork get() { - switch (drtCfg.operationalScheme) { - case door2door: - return ImmutableMap::of; - case stopbased: - return createDrtStopNetworkFromTransitSchedule(config, drtCfg); - case serviceAreaBased: - return createDrtStopNetworkFromServiceArea(config, drtCfg, getModalInstance(Network.class)); - default: - throw new RuntimeException("Unsupported operational scheme: " + drtCfg.operationalScheme); - } - } - } - - private static DrtStopNetwork createDrtStopNetworkFromServiceArea(Config config, DrtConfigGroup drtCfg, - Network drtNetwork) { - final List preparedGeometries = ShpGeometryUtils.loadPreparedGeometries( - ConfigGroup.getInputFileURL(config.getContext(), drtCfg.drtServiceAreaShapeFile ) ); - ImmutableMap, DrtStopFacility> drtStops = drtNetwork.getLinks() - .values() - .stream() - .filter(link -> ShpGeometryUtils.isCoordInPreparedGeometries(link.getToNode().getCoord(), - preparedGeometries)) - .map( DrtStopFacilityImpl::createFromLink ) - .collect(ImmutableMap.toImmutableMap(DrtStopFacility::getId, f -> f)); - return () -> drtStops; - } - - private static DrtStopNetwork createDrtStopNetworkFromTransitSchedule(Config config, DrtConfigGroup drtCfg) { - URL url = ConfigGroup.getInputFileURL(config.getContext(), drtCfg.transitStopFile); - Scenario scenario = ScenarioUtils.createScenario(ConfigUtils.createConfig()); - new TransitScheduleReader(scenario).readURL(url ); - ImmutableMap, DrtStopFacility> drtStops = scenario.getTransitSchedule() - .getFacilities() - .values() - .stream() - .map(DrtStopFacilityImpl::createFromFacility) - .collect(ImmutableMap.toImmutableMap(DrtStopFacility::getId, f -> f)); - return () -> drtStops; - } - - } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/routing/DrtRouteUpdater.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/routing/DrtRouteUpdater.java index c3df5366f64..528a02f0c69 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/routing/DrtRouteUpdater.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/routing/DrtRouteUpdater.java @@ -24,6 +24,8 @@ import org.matsim.core.controler.listener.ReplanningListener; /** + * We think that this updates travel times after reach iteration (i.e. during "replanning" which seems a bit the wrong place where to do this). kai, feb'24 + * * @author Michal Maciejewski (michalm) */ public interface DrtRouteUpdater extends ReplanningListener { diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeRoutingModule.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeRoutingModule.java index c83a66d072d..af56b5e3e38 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeRoutingModule.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeRoutingModule.java @@ -66,6 +66,7 @@ * @author Michal Maciejewski (michalm) */ public class DrtModeRoutingModule extends AbstractDvrpModeModule { + // AbstractDvrpModeModule AbstractModalModule, which provides bindModal et al. AbstractDvrpModeModule gets rid of the generics of AbstractModalModule. private final DrtConfigGroup drtCfg; @@ -76,27 +77,38 @@ public DrtModeRoutingModule(DrtConfigGroup drtCfg) { @Override public void install() { + addRoutingModuleBinding(getMode()).toProvider(new DvrpRoutingModuleProvider(getMode()));// not singleton + // (this is the normal routing module binding) + modalMapBinder(DvrpRoutingModuleProvider.Stage.class, RoutingModule.class).addBinding( DvrpRoutingModuleProvider.Stage.MAIN) .toProvider(new DefaultMainLegRouterProvider(getMode()));// not singleton + // this seems to bind an enum. maybe more heavyweight than necessary? + bindModal(DefaultMainLegRouter.RouteCreator.class).toProvider( new DrtRouteCreatorProvider(drtCfg));// not singleton + // this is used in DvrpModeRoutingModule (recruited by the DvrpRoutingModuleProvider above) bindModal(DrtStopNetwork.class).toProvider(new DrtStopNetworkProvider(getConfig(), drtCfg)).asEagerSingleton(); - - if (drtCfg.operationalScheme == DrtConfigGroup.OperationalScheme.door2door) { - bindModal(AccessEgressFacilityFinder.class).toProvider( - modalProvider(getter -> new DecideOnLinkAccessEgressFacilityFinder(getter.getModal(Network.class)))) - .asEagerSingleton(); - } else { - bindModal(AccessEgressFacilityFinder.class).toProvider(modalProvider( - getter -> new ClosestAccessEgressFacilityFinder(drtCfg.maxWalkDistance, - getter.get(Network.class), - QuadTrees.createQuadTree(getter.getModal(DrtStopNetwork.class).getDrtStops().values())))) - .asEagerSingleton(); + // yyyy possibly not used for door2door; try to move inside the corresponding switch statement below. kai, feb'24 + + switch( drtCfg.operationalScheme ){ + case door2door -> bindModal( AccessEgressFacilityFinder.class ).toProvider( + modalProvider( getter -> new DecideOnLinkAccessEgressFacilityFinder( getter.getModal( Network.class ) ) ) ) + .asEagerSingleton(); + case stopbased, serviceAreaBased -> { + bindModal( AccessEgressFacilityFinder.class ).toProvider( modalProvider( + getter -> new ClosestAccessEgressFacilityFinder( drtCfg.maxWalkDistance, + getter.get( Network.class ), + QuadTrees.createQuadTree( getter.getModal( DrtStopNetwork.class ).getDrtStops().values() ) ) ) ) + .asEagerSingleton(); + } + default -> throw new IllegalStateException( "Unexpected value: " + drtCfg.operationalScheme ); } + // this is, we think, updating the max travel time based on congested travel time and the alpha-beta thing: + // (yyyy have same problem in Ride mode but do not address it there) bindModal(DrtRouteUpdater.class).toProvider(new ModalProviders.AbstractProvider<>(getMode(), DvrpModes::mode) { @Inject private Population population; @@ -112,6 +124,7 @@ public DefaultDrtRouteUpdater get() { } }).asEagerSingleton(); + // this binds the above as a controler listener: addControlerListenerBinding().to(modalKey(DrtRouteUpdater.class)); } From f3523adbda8cf15ed0a62508fde687e96f012f74 Mon Sep 17 00:00:00 2001 From: Chengqi Lu <43133404+luchengqi7@users.noreply.github.com> Date: Tue, 6 Feb 2024 18:27:58 +0100 Subject: [PATCH 04/19] wip some comments --- .../contrib/drt/teleportation/Test2.java | 51 ++++++++++++++----- .../contrib/drt/speedup/DrtSpeedUp.java | 9 +--- .../passenger/TeleportingPassengerEngine.java | 1 + 3 files changed, 40 insertions(+), 21 deletions(-) diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/Test2.java b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/Test2.java index 1ad3d66c3e9..841ee24bb6c 100644 --- a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/Test2.java +++ b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/Test2.java @@ -22,8 +22,11 @@ import org.matsim.contrib.drt.routing.*; import org.matsim.contrib.drt.run.DrtConfigGroup; import org.matsim.contrib.drt.run.DrtControlerCreator; +import org.matsim.contrib.drt.run.MultiModeDrtConfigGroup; +import org.matsim.contrib.drt.speedup.DrtSpeedUpParams; import org.matsim.contrib.dvrp.router.*; import org.matsim.contrib.dvrp.run.AbstractDvrpModeModule; +import org.matsim.contrib.dvrp.run.DvrpConfigGroup; import org.matsim.contrib.dvrp.run.DvrpMode; import org.matsim.contrib.dvrp.run.DvrpModes; import org.matsim.core.config.Config; @@ -48,6 +51,7 @@ import org.matsim.testcases.MatsimTestUtils; import org.matsim.utils.gis.shp2matsim.ShpGeometryUtils; import org.matsim.utils.objectattributes.attributable.Attributes; +import org.matsim.vis.otfvis.OTFVisConfigGroup; import java.net.URL; import java.util.*; @@ -58,8 +62,8 @@ class Test2{ @org.junit.jupiter.api.Test void test1() { - URL url = IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "mielec" ), "empty_config.xml" ); - Config config = ConfigUtils.loadConfig( url ); + URL url = IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "mielec" ), "mielec_drt_config.xml" ); + Config config = ConfigUtils.loadConfig( url, new MultiModeDrtConfigGroup(), new DvrpConfigGroup(), new OTFVisConfigGroup()); config.network().setInputFile( "network.xml" ); config.plans().setInputFile( "plans_only_drt_1.0.xml.gz" ); @@ -67,18 +71,39 @@ class Test2{ config.controller().setOutputDirectory( utils.getOutputDirectory() ); config.controller().setLastIteration( 0 ); - Scenario scenario = DrtControlerCreator.createScenarioWithDrtRouteFactory( config ); - ScenarioUtils.loadScenario( scenario ); - - Controler controler = new Controler( scenario ); // install the drt routing stuff, but not the mobsim stuff! + Controler controler = DrtControlerCreator.createControler(config, false); + + + DrtConfigGroup drtConfigGroup = DrtConfigGroup.getSingleModeDrtConfig(config); + + DrtSpeedUpParams params = new DrtSpeedUpParams(); + params.fractionOfIterationsSwitchOn = 0; + drtConfigGroup.addParameterSet(params); + + System.out.println(config); + + // TODO + // We want to use DRT infrastructure (routing) so we need to integrate into drt teleportation + // Write our own TeleportingPassengerEngine + // this engine can either calc estimates beforehand or during departure (using information of drt router) + + + // alternative: implement our own router + // do nothing drt specific -> calculate travel time information during routing + // can use standard teleportation engines given route information + // we need to update routes ourself, we have no drt access egress, no waiting times, no drt output or requests + // this would be more general, could be useful for other use cases? + // but we only need it for DRT for now? + /* controler.addOverridingModule( new AbstractModule(){ @Override public void install(){ this.addRoutingModuleBinding( "drt" ).to( DrtEstimatingRoutingModule.class ); } } ); + */ controler.run(); @@ -98,20 +123,20 @@ public List calcRoute(RoutingRequest request) { List route = drtRoutingModule.calcRoute( request ); DrtRouteCreator creator = null; - creator.createRoute( departureTime, accessActLink, egressActLink, person, tripAttributes, routeFactories ); + // creator.createRoute( departureTime, accessActLink, egressActLink, person, tripAttributes, routeFactories ); DrtRouteFactory factory = null; - Route drtRoute = factory.createRoute( startLinkId, endLinkId ); + // Route drtRoute = factory.createRoute( startLinkId, endLinkId ); // correct the attributes of the route as we need them - DrtInitialEstimator estimator = new DrtInitialEstimator(){ - }; + // DrtInitialEstimator estimator = new DrtInitialEstimator(){ + // }; - DrtEstimator.Estimate estimate = estimator.estimate( route, 12. * 3600 ); + // DrtEstimator.Estimate estimate = estimator.estimate( route, 12. * 3600 ); - estimate.travelTime(); - estimate.distance(); + // estimate.travelTime(); + // estimate.distance(); return route; } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/speedup/DrtSpeedUp.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/speedup/DrtSpeedUp.java index 5ad8dd776af..fd5ed666740 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/speedup/DrtSpeedUp.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/speedup/DrtSpeedUp.java @@ -53,14 +53,7 @@ public final class DrtSpeedUp implements IterationStartsListener, IterationEndsL public static boolean isTeleportDrtUsers(DrtSpeedUpParams drtSpeedUpParams, ControllerConfigGroup controlerConfig, int iteration) { - int lastIteration = controlerConfig.getLastIteration(); - if (iteration < drtSpeedUpParams.fractionOfIterationsSwitchOn * lastIteration - || iteration >= drtSpeedUpParams.fractionOfIterationsSwitchOff * lastIteration) { - return false; // full drt simulation - } - - //full drt simulation only with a defined interval - return iteration % drtSpeedUpParams.intervalDetailedIteration != 0; + return true; } private final String mode; diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/TeleportingPassengerEngine.java b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/TeleportingPassengerEngine.java index 1f773a77043..c7a4e524704 100644 --- a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/TeleportingPassengerEngine.java +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/TeleportingPassengerEngine.java @@ -165,6 +165,7 @@ public boolean handleDeparture(double now, MobsimAgent agent, Id fromLinkI private Route adaptLegRouteForTeleportation(List passengers, PassengerRequest request, double now) { Route teleportedRoute = teleportedRouteCalculator.calculateRoute(request); + for (MobsimPassengerAgent passenger : passengers) { Leg leg = (Leg)WithinDayAgentUtils.getCurrentPlanElement(passenger);//side effect: makes the plan modifiable Route originalRoute = leg.getRoute(); From af8bfaa3cf6291b64c3a8f7a7ee264c8be0340af Mon Sep 17 00:00:00 2001 From: Chengqi Lu <43133404+luchengqi7@users.noreply.github.com> Date: Mon, 12 Feb 2024 12:50:45 +0100 Subject: [PATCH 05/19] Add a concrete structure How this estimator may be used. --- .../contrib/drt/teleportation/Test2.java | 153 +++++++++++------- 1 file changed, 98 insertions(+), 55 deletions(-) diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/Test2.java b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/Test2.java index 841ee24bb6c..b0f00405305 100644 --- a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/Test2.java +++ b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/Test2.java @@ -1,75 +1,45 @@ package org.matsim.contrib.drt.teleportation; -import com.google.common.collect.ImmutableMap; -import com.google.inject.Inject; -import com.google.inject.TypeLiteral; -import com.google.inject.name.Named; -import org.apache.commons.lang3.tuple.Pair; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; import org.junit.jupiter.api.extension.RegisterExtension; -import org.locationtech.jts.geom.prep.PreparedGeometry; -import org.matsim.api.core.v01.Id; -import org.matsim.api.core.v01.Scenario; -import org.matsim.api.core.v01.TransportMode; -import org.matsim.api.core.v01.network.Network; -import org.matsim.api.core.v01.population.Activity; -import org.matsim.api.core.v01.population.Person; +import org.matsim.api.core.v01.network.Link; import org.matsim.api.core.v01.population.PlanElement; -import org.matsim.api.core.v01.population.Route; -import org.matsim.contrib.drt.extension.estimator.DrtEstimator; -import org.matsim.contrib.drt.extension.estimator.DrtInitialEstimator; import org.matsim.contrib.drt.routing.*; import org.matsim.contrib.drt.run.DrtConfigGroup; import org.matsim.contrib.drt.run.DrtControlerCreator; import org.matsim.contrib.drt.run.MultiModeDrtConfigGroup; import org.matsim.contrib.drt.speedup.DrtSpeedUpParams; -import org.matsim.contrib.dvrp.router.*; -import org.matsim.contrib.dvrp.run.AbstractDvrpModeModule; +import org.matsim.contrib.dvrp.path.VrpPaths; import org.matsim.contrib.dvrp.run.DvrpConfigGroup; -import org.matsim.contrib.dvrp.run.DvrpMode; -import org.matsim.contrib.dvrp.run.DvrpModes; import org.matsim.core.config.Config; -import org.matsim.core.config.ConfigGroup; import org.matsim.core.config.ConfigUtils; -import org.matsim.core.controler.AbstractModule; import org.matsim.core.controler.Controler; -import org.matsim.core.modal.ModalProviders; -import org.matsim.core.population.PopulationUtils; import org.matsim.core.router.*; -import org.matsim.core.router.costcalculators.TravelDisutilityFactory; -import org.matsim.core.router.speedy.SpeedyALTFactory; -import org.matsim.core.router.util.LeastCostPathCalculatorFactory; +import org.matsim.core.router.util.LeastCostPathCalculator; import org.matsim.core.router.util.TravelTime; -import org.matsim.core.scenario.ScenarioUtils; -import org.matsim.core.utils.collections.QuadTrees; import org.matsim.core.utils.io.IOUtils; -import org.matsim.core.utils.timing.TimeInterpretation; import org.matsim.examples.ExamplesUtils; -import org.matsim.facilities.Facility; -import org.matsim.pt.transitSchedule.api.TransitScheduleReader; import org.matsim.testcases.MatsimTestUtils; -import org.matsim.utils.gis.shp2matsim.ShpGeometryUtils; -import org.matsim.utils.objectattributes.attributable.Attributes; import org.matsim.vis.otfvis.OTFVisConfigGroup; import java.net.URL; import java.util.*; -class Test2{ +class Test2 { - @RegisterExtension public MatsimTestUtils utils = new MatsimTestUtils(); + @RegisterExtension + public MatsimTestUtils utils = new MatsimTestUtils(); - @org.junit.jupiter.api.Test void test1() { + @org.junit.jupiter.api.Test + void test1() { - URL url = IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "mielec" ), "mielec_drt_config.xml" ); - Config config = ConfigUtils.loadConfig( url, new MultiModeDrtConfigGroup(), new DvrpConfigGroup(), new OTFVisConfigGroup()); + URL url = IOUtils.extendUrl(ExamplesUtils.getTestScenarioURL("mielec"), "mielec_drt_config.xml"); + Config config = ConfigUtils.loadConfig(url, new MultiModeDrtConfigGroup(), new DvrpConfigGroup(), new OTFVisConfigGroup()); - config.network().setInputFile( "network.xml" ); - config.plans().setInputFile( "plans_only_drt_1.0.xml.gz" ); + config.network().setInputFile("network.xml"); + config.plans().setInputFile("plans_only_drt_1.0.xml.gz"); - config.controller().setOutputDirectory( utils.getOutputDirectory() ); - config.controller().setLastIteration( 0 ); + config.controller().setOutputDirectory(utils.getOutputDirectory()); + config.controller().setLastIteration(0); // install the drt routing stuff, but not the mobsim stuff! @@ -112,35 +82,108 @@ class Test2{ private static class DrtEstimatingRoutingModule implements RoutingModule { private final RoutingModule drtRoutingModule; - private DrtEstimatingRoutingModule( TripRouter tripRouter ) { - this.drtRoutingModule = tripRouter.getRoutingModule( "drt" ); - } + private DrtEstimatingRoutingModule(TripRouter tripRouter) { + this.drtRoutingModule = tripRouter.getRoutingModule("drt"); + } @Override public List calcRoute(RoutingRequest request) { - List route = drtRoutingModule.calcRoute( request ); + List route = drtRoutingModule.calcRoute(request); DrtRouteCreator creator = null; - // creator.createRoute( departureTime, accessActLink, egressActLink, person, tripAttributes, routeFactories ); + // creator.createRoute( departureTime, accessActLink, egressActLink, person, tripAttributes, routeFactories ); DrtRouteFactory factory = null; - // Route drtRoute = factory.createRoute( startLinkId, endLinkId ); + // Route drtRoute = factory.createRoute( startLinkId, endLinkId ); // correct the attributes of the route as we need them - // DrtInitialEstimator estimator = new DrtInitialEstimator(){ - // }; + // DrtInitialEstimator estimator = new DrtInitialEstimator(){ + // }; - // DrtEstimator.Estimate estimate = estimator.estimate( route, 12. * 3600 ); + // DrtEstimator.Estimate estimate = estimator.estimate( route, 12. * 3600 ); - // estimate.travelTime(); - // estimate.distance(); + // estimate.travelTime(); + // estimate.distance(); return route; } } + public record EstimatedDrtTeleportationInfo(double estTotalTravelTime, double estWaitTime, double estRideTime, double estRideDistance) { + // The teleportation info refers to the main DRT leg (accessLink -> egressLink, departing at departureTime) + // The info teleportation engine can make use of this data to generate a teleport leg + // wait time and ride time are specified, such that we can score them differently (if required) + } + + public record DrtRouteInfoEstimator(LeastCostPathCalculator router, TravelTime travelTime, DistributionGenerator distributionGenerator) { + // This record/class is to be created before (each?) MobSim/QSim. + public EstimatedDrtTeleportationInfo estimateDrtRoute(Link accessLink, Link egressLink, double departureTime) { + double waitTime = distributionGenerator.generateWaitTime(); + double directRideTime = VrpPaths.calcAndCreatePath(accessLink, egressLink, departureTime + waitTime, router, travelTime).getTravelTime(); + double rideTime = distributionGenerator.generateRideTime(directRideTime); + + // since VrpPath does not contain Path information. We need to calculate this manually. + // VRP path logic: toNode of fromLink -> fromNode of toLink -> toNode of toLink + LeastCostPathCalculator.Path path = router.calcLeastCostPath(accessLink.getToNode(), egressLink.getFromNode(), + departureTime + waitTime, null, null); + path.links.add(egressLink); + + double directRideDistance = path.links.stream().mapToDouble(Link::getLength).sum(); + double rideDistance = distributionGenerator.generateRideDistance(rideTime, directRideTime, directRideDistance); + + return new EstimatedDrtTeleportationInfo(waitTime + rideTime, waitTime, rideTime, rideDistance); + } + } + + public static class DistributionGenerator { + private final Random random = new Random(4711); + private final double estRideTimeAlpha; + private final double estRideTimeBeta; + private final double rideTimeStd; + private final double estMeanWaitTime; + private final double waitTimeStd; + private final double probabilityRejection; + + public DistributionGenerator(double estRideTimeAlpha, double estRideTimeBeta, double rideTimeStd, double estMeanWaitTime, + double waitTimeStd, double probabilityRejection) { + this.estRideTimeAlpha = estRideTimeAlpha; + this.estRideTimeBeta = estRideTimeBeta; + this.rideTimeStd = rideTimeStd; + this.estMeanWaitTime = estMeanWaitTime; + this.waitTimeStd = waitTimeStd; + this.probabilityRejection = probabilityRejection; + } + + public DistributionGenerator generateExampleDistributionGenerator() { + return new DistributionGenerator(1.5, 300, 0.2, 300, 0.4, 0.0); + } + + public double generateRideTime(double directRideTime) { + // TODO improve this distribution + double estMeanRideTime = estRideTimeAlpha * directRideTime + estRideTimeBeta; + return Math.max(directRideTime, estMeanRideTime * (1 + random.nextGaussian() * rideTimeStd)); + } + + public double generateRideDistance(double estRideTime, double directRideTime, double directRideDistance) { + // TODO Currently, same ratio is used as in the ride time estimation; improve this distribution + double ratio = estRideTime / directRideTime; + return ratio * directRideDistance; + } + + public double generateWaitTime() { + // TODO improve this distribution + return Math.max(estMeanWaitTime * (1 + random.nextGaussian() * waitTimeStd), 0); + } + + public boolean generateIsTripAccepted() { + // TODO maybe incorporate this into the estimated wait time, ride time and ride distance + return random.nextDouble() >= probabilityRejection; + } + } + + } From baf3fa40fd7bab52c6daabd54073b85a8d8f16c0 Mon Sep 17 00:00:00 2001 From: Chengqi Lu <43133404+luchengqi7@users.noreply.github.com> Date: Tue, 13 Feb 2024 17:32:35 +0100 Subject: [PATCH 06/19] WIP Some intermediate steps. --- .../estimator/run/DrtEstimatorModule.java | 119 ---------- .../run/MultiModeDrtEstimatorConfigGroup.java | 103 --------- .../MultiModalDrtLegEstimator.java | 3 +- .../MultiModaFixedDrtLegEstimatorTest.java | 23 +- .../MultiModalDrtLegEstimatorTest.java | 17 +- .../contrib/drt/teleportation/Test2.java | 40 +--- .../drt}/estimator/DrtEstimateAnalyzer.java | 11 +- .../contrib/drt}/estimator/DrtEstimator.java | 2 +- .../drt/estimator/DrtEstimatorModule.java | 68 ++++++ .../drt/estimator/DrtEstimatorParams.java} | 36 +-- .../drt}/estimator/DrtInitialEstimator.java | 2 +- .../estimator/EstimationRoutingModule.java | 27 +++ .../EstimationRoutingModuleProvider.java | 68 ++++++ .../estimator/impl/BasicDrtEstimator.java | 12 +- .../estimator/impl/ConstantDrtEstimator.java | 4 +- .../impl/PessimisticDrtEstimator.java | 4 +- .../contrib/drt/run/DrtConfigGroup.java | 14 ++ .../matsim/contrib/drt/run/DrtModeModule.java | 13 ++ .../contrib/drt/run/DrtModeQSimModule.java | 15 +- .../contrib/drt/run/DrtModeRoutingModule.java | 3 +- .../passenger/PassengerEngineQSimModule.java | 19 +- .../TeleportingEstimationPassengerEngine.java | 213 ++++++++++++++++++ .../TeleportingPassengerEngineTest.java | 2 +- 23 files changed, 477 insertions(+), 341 deletions(-) delete mode 100644 contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/run/DrtEstimatorModule.java delete mode 100644 contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/run/MultiModeDrtEstimatorConfigGroup.java rename contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/{estimator => modechoice}/MultiModalDrtLegEstimator.java (95%) rename contribs/{drt-extensions/src/main/java/org/matsim/contrib/drt/extension => drt/src/main/java/org/matsim/contrib/drt}/estimator/DrtEstimateAnalyzer.java (93%) rename contribs/{drt-extensions/src/main/java/org/matsim/contrib/drt/extension => drt/src/main/java/org/matsim/contrib/drt}/estimator/DrtEstimator.java (95%) create mode 100644 contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimatorModule.java rename contribs/{drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/run/DrtEstimatorConfigGroup.java => drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimatorParams.java} (55%) rename contribs/{drt-extensions/src/main/java/org/matsim/contrib/drt/extension => drt/src/main/java/org/matsim/contrib/drt}/estimator/DrtInitialEstimator.java (86%) create mode 100644 contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/EstimationRoutingModule.java create mode 100644 contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/EstimationRoutingModuleProvider.java rename contribs/{drt-extensions/src/main/java/org/matsim/contrib/drt/extension => drt/src/main/java/org/matsim/contrib/drt}/estimator/impl/BasicDrtEstimator.java (94%) rename contribs/{drt-extensions/src/main/java/org/matsim/contrib/drt/extension => drt/src/main/java/org/matsim/contrib/drt}/estimator/impl/ConstantDrtEstimator.java (91%) rename contribs/{drt-extensions/src/main/java/org/matsim/contrib/drt/extension => drt/src/main/java/org/matsim/contrib/drt}/estimator/impl/PessimisticDrtEstimator.java (91%) create mode 100644 contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/TeleportingEstimationPassengerEngine.java diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/run/DrtEstimatorModule.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/run/DrtEstimatorModule.java deleted file mode 100644 index c5a8ed00e7c..00000000000 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/run/DrtEstimatorModule.java +++ /dev/null @@ -1,119 +0,0 @@ -package org.matsim.contrib.drt.extension.estimator.run; - -import com.google.inject.Singleton; -import com.google.inject.multibindings.MapBinder; -import org.matsim.contrib.drt.analysis.DrtEventSequenceCollector; -import org.matsim.contrib.drt.extension.estimator.DrtEstimateAnalyzer; -import org.matsim.contrib.drt.extension.estimator.DrtEstimator; -import org.matsim.contrib.drt.extension.estimator.DrtInitialEstimator; -import org.matsim.contrib.drt.extension.estimator.impl.BasicDrtEstimator; -import org.matsim.contrib.drt.extension.estimator.impl.PessimisticDrtEstimator; -import org.matsim.contrib.drt.run.DrtConfigGroup; -import org.matsim.contrib.drt.run.MultiModeDrtConfigGroup; -import org.matsim.contrib.dvrp.run.AbstractDvrpModeModule; -import org.matsim.contrib.dvrp.run.DvrpMode; -import org.matsim.contrib.dvrp.run.DvrpModes; -import org.matsim.core.config.ConfigUtils; -import org.matsim.core.controler.AbstractModule; - -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.function.Function; - -/** - * Main module that needs to be installed if any estimator is to be used. - */ -public class DrtEstimatorModule extends AbstractModule { - - - /** - * Map of initial providers. - */ - private final Map> initial = new HashMap<>(); - - @Override - public void install() { - - MultiModeDrtConfigGroup drtConfigs = MultiModeDrtConfigGroup.get(getConfig()); - MultiModeDrtEstimatorConfigGroup configs = ConfigUtils.addOrGetModule(getConfig(), MultiModeDrtEstimatorConfigGroup.class); - - for (DrtConfigGroup cfg : drtConfigs.getModalElements()) { - - Optional estCfg = configs.getModalElement(cfg.mode); - - estCfg.ifPresent(drtEstimatorConfigGroup -> install(new ModeModule(cfg, drtEstimatorConfigGroup))); - } - } - - /** - * Configure initial estimators for the given modes. - * - * @param getter modal getter, which can be used to use other modal components via guice - */ - public DrtEstimatorModule withInitialEstimator(Function getter, String... modes) { - - if (modes.length == 0) - throw new IllegalArgumentException("At least one mode needs to be provided."); - - for (String mode : modes) { - initial.put(mode, getter); - } - - return this; - } - - final class ModeModule extends AbstractDvrpModeModule { - - private final DrtConfigGroup cfg; - private final DrtEstimatorConfigGroup group; - - public ModeModule(DrtConfigGroup cfg, DrtEstimatorConfigGroup group) { - super(group.mode); - this.cfg = cfg; - this.group = group; - } - - @Override - public void install() { - - // try with default injections and overwrite - if (group.estimator == DrtEstimatorConfigGroup.EstimatorType.BASIC) { - bindModal(DrtEstimator.class).toProvider(modalProvider( - getter -> new BasicDrtEstimator( - getter.getModal(DrtEventSequenceCollector.class), - getter.getModal(DrtInitialEstimator.class), - group, cfg - ) - )).in(Singleton.class); - } else if (group.estimator == DrtEstimatorConfigGroup.EstimatorType.INITIAL) { - bindModal(DrtEstimator.class).to(modalKey(DrtInitialEstimator.class)); - } - - if (initial.containsKey(group.mode)) { - bindModal(DrtInitialEstimator.class).toProvider(() -> initial.get(group.mode).apply(cfg)).in(Singleton.class); - } else - bindModal(DrtInitialEstimator.class).toInstance(new PessimisticDrtEstimator(cfg)); - - // DRT Estimators will be available as Map - MapBinder.newMapBinder(this.binder(), DvrpMode.class, DrtEstimator.class) - .addBinding(DvrpModes.mode(getMode())) - .to(modalKey(DrtEstimator.class)); - - addControlerListenerBinding().to(modalKey(DrtEstimator.class)); - - bindModal(DrtEstimatorConfigGroup.class).toInstance(group); - - // Needs to run before estimators - bindModal(DrtEstimateAnalyzer.class) - .toProvider( - modalProvider(getter -> new DrtEstimateAnalyzer(getter.getModal(DrtEstimator.class), getter.getModal(DrtEventSequenceCollector.class), group)) - ) - .in(Singleton.class); - - addControlerListenerBinding().to(modalKey(DrtEstimateAnalyzer.class)); - - } - - } -} diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/run/MultiModeDrtEstimatorConfigGroup.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/run/MultiModeDrtEstimatorConfigGroup.java deleted file mode 100644 index b998bf78648..00000000000 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/run/MultiModeDrtEstimatorConfigGroup.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * *********************************************************************** * - * project: org.matsim.* - * *********************************************************************** * - * * - * copyright : (C) 2018 by the members listed in the COPYING, * - * LICENSE and WARRANTY file. * - * email : info at matsim dot org * - * * - * *********************************************************************** * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * See also COPYING, LICENSE and WARRANTY file * - * * - * *********************************************************************** * - */ - -package org.matsim.contrib.drt.extension.estimator.run; - -import java.util.Collection; -import java.util.Optional; -import java.util.function.Supplier; - -import org.matsim.contrib.dvrp.run.MultiModal; -import org.matsim.contrib.dvrp.run.MultiModals; -import org.matsim.core.config.Config; -import org.matsim.core.config.ConfigGroup; -import org.matsim.core.config.ReflectiveConfigGroup; - -import com.google.common.base.Verify; - -/** - * @author Michal Maciejewski (michalm) - */ -public final class MultiModeDrtEstimatorConfigGroup extends ReflectiveConfigGroup implements MultiModal { - public static final String GROUP_NAME = "drtEstimators"; - - /** - * @param config - * @return MultiModeDrtConfigGroup if exists. Otherwise fails - */ - public static MultiModeDrtEstimatorConfigGroup get(Config config) { - return (MultiModeDrtEstimatorConfigGroup)config.getModule(GROUP_NAME); - } - - private final Supplier drtConfigSupplier; - - public MultiModeDrtEstimatorConfigGroup() { - this(DrtEstimatorConfigGroup::new); - } - - public MultiModeDrtEstimatorConfigGroup(Supplier drtConfigSupplier) { - super(GROUP_NAME); - this.drtConfigSupplier = drtConfigSupplier; - } - - @Override - protected void checkConsistency(Config config) { - super.checkConsistency(config); - Verify.verify(config.getModule(DrtEstimatorConfigGroup.GROUP_NAME) == null, - "In the multi-mode DRT setup, DrtEstimatorConfigGroup must not be defined at the config top level"); - MultiModals.requireAllModesUnique(this); - } - - @Override - public ConfigGroup createParameterSet(String type) { - if (type.equals(DrtEstimatorConfigGroup.GROUP_NAME)) { - return drtConfigSupplier.get(); - } else { - throw new IllegalArgumentException("Unsupported parameter set type: " + type); - } - } - - @Override - public void addParameterSet(ConfigGroup set) { - if (set instanceof DrtEstimatorConfigGroup) { - super.addParameterSet(set); - } else { - throw new IllegalArgumentException("Unsupported parameter set class: " + set); - } - } - - public void addParameterSet(DrtEstimatorConfigGroup set) { - addParameterSet((ConfigGroup) set); - } - - @Override - @SuppressWarnings("unchecked") - public Collection getModalElements() { - return (Collection)getParameterSets(DrtEstimatorConfigGroup.GROUP_NAME); - } - - /** - * Find estimator config for specific mode. - */ - public Optional getModalElement(String mode) { - return getModalElements().stream().filter(m -> m.getMode().equals(mode)).findFirst(); - } - -} diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/MultiModalDrtLegEstimator.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/modechoice/MultiModalDrtLegEstimator.java similarity index 95% rename from contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/MultiModalDrtLegEstimator.java rename to contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/modechoice/MultiModalDrtLegEstimator.java index 3481b7ec7a2..02708c65115 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/MultiModalDrtLegEstimator.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/modechoice/MultiModalDrtLegEstimator.java @@ -1,9 +1,10 @@ -package org.matsim.contrib.drt.extension.estimator; +package org.matsim.contrib.drt.extension.modechoice; import com.google.inject.Inject; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.matsim.api.core.v01.population.Leg; +import org.matsim.contrib.drt.estimator.DrtEstimator; import org.matsim.contrib.drt.routing.DrtRoute; import org.matsim.contrib.dvrp.run.DvrpMode; import org.matsim.core.scoring.functions.ModeUtilityParameters; diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/estimator/MultiModaFixedDrtLegEstimatorTest.java b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/estimator/MultiModaFixedDrtLegEstimatorTest.java index 5d4a8a1d5b6..2b0cb230683 100644 --- a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/estimator/MultiModaFixedDrtLegEstimatorTest.java +++ b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/estimator/MultiModaFixedDrtLegEstimatorTest.java @@ -4,11 +4,11 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import org.matsim.application.MATSimApplication; +import org.matsim.contrib.drt.extension.modechoice.MultiModalDrtLegEstimator; import org.matsim.contrib.drt.extension.DrtTestScenario; -import org.matsim.contrib.drt.extension.estimator.impl.ConstantDrtEstimator; -import org.matsim.contrib.drt.extension.estimator.run.DrtEstimatorConfigGroup; -import org.matsim.contrib.drt.extension.estimator.run.DrtEstimatorModule; -import org.matsim.contrib.drt.extension.estimator.run.MultiModeDrtEstimatorConfigGroup; +import org.matsim.contrib.drt.estimator.impl.ConstantDrtEstimator; +import org.matsim.contrib.drt.estimator.DrtEstimatorParams; +import org.matsim.contrib.drt.estimator.DrtEstimatorModule; import org.matsim.core.config.Config; import org.matsim.core.config.ConfigUtils; import org.matsim.core.config.groups.ReplanningConfigGroup; @@ -40,17 +40,18 @@ private static void prepare(Controler controler) { .withLegEstimator(MultiModalDrtLegEstimator.class, ModeOptions.AlwaysAvailable.class, "drt", "av"); controler.addOverridingModule(builder.build()); - controler.addOverridingModule(new DrtEstimatorModule() - .withInitialEstimator(cfg -> new ConstantDrtEstimator(cfg, 1.05, 300), "drt", "av")); + //TODO fix later +// controler.addOverridingModule(new DrtEstimatorModule() +// .withInitialEstimator(cfg -> new ConstantDrtEstimator(cfg, 1.05, 300), "drt", "av")); } private static void prepare(Config config) { - MultiModeDrtEstimatorConfigGroup estimators = ConfigUtils.addOrGetModule(config, MultiModeDrtEstimatorConfigGroup.class); - - estimators.addParameterSet(new DrtEstimatorConfigGroup("drt") - .withEstimator(DrtEstimatorConfigGroup.EstimatorType.INITIAL)); - estimators.addParameterSet(new DrtEstimatorConfigGroup("av")); +// MultiModeDrtEstimatorConfigGroup estimators = ConfigUtils.addOrGetModule(config, MultiModeDrtEstimatorConfigGroup.class); +// +// estimators.addParameterSet(new DrtEstimatorParams("drt") +// .withEstimator(DrtEstimatorParams.EstimatorType.INITIAL)); +// estimators.addParameterSet(new DrtEstimatorParams("av")); // Set subtour mode selection as strategy List strategies = config.replanning().getStrategySettings().stream() diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/estimator/MultiModalDrtLegEstimatorTest.java b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/estimator/MultiModalDrtLegEstimatorTest.java index 90601b72b29..bdc314bb112 100644 --- a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/estimator/MultiModalDrtLegEstimatorTest.java +++ b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/estimator/MultiModalDrtLegEstimatorTest.java @@ -4,12 +4,10 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import org.matsim.application.MATSimApplication; +import org.matsim.contrib.drt.estimator.DrtEstimatorModule; import org.matsim.contrib.drt.extension.DrtTestScenario; -import org.matsim.contrib.drt.extension.estimator.run.DrtEstimatorConfigGroup; -import org.matsim.contrib.drt.extension.estimator.run.DrtEstimatorModule; -import org.matsim.contrib.drt.extension.estimator.run.MultiModeDrtEstimatorConfigGroup; +import org.matsim.contrib.drt.extension.modechoice.MultiModalDrtLegEstimator; import org.matsim.core.config.Config; -import org.matsim.core.config.ConfigUtils; import org.matsim.core.config.groups.ReplanningConfigGroup; import org.matsim.core.controler.Controler; import org.matsim.modechoice.InformedModeChoiceModule; @@ -49,15 +47,16 @@ private static void prepare(Controler controler) { .withLegEstimator(MultiModalDrtLegEstimator.class, ModeOptions.AlwaysAvailable.class, "drt", "av"); controler.addOverridingModule(builder.build()); - controler.addOverridingModule(new DrtEstimatorModule()); +// controler.addOverridingModule(new DrtEstimatorModule()); } private static void prepare(Config config) { - MultiModeDrtEstimatorConfigGroup estimators = ConfigUtils.addOrGetModule(config, MultiModeDrtEstimatorConfigGroup.class); - - estimators.addParameterSet(new DrtEstimatorConfigGroup("drt")); - estimators.addParameterSet(new DrtEstimatorConfigGroup("av")); +// MultiModeDrtEstimatorConfigGroup estimators = ConfigUtils.addOrGetModule(config, MultiModeDrtEstimatorConfigGroup.class); +// +// estimators.addParameterSet(new DrtEstimatorParams("drt")); +// estimators.addParameterSet(new DrtEstimatorParams("av")); + // TODO fix later // Set subtour mode selection as strategy List strategies = config.replanning().getStrategySettings().stream() diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/Test2.java b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/Test2.java index b0f00405305..89acd867dd2 100644 --- a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/Test2.java +++ b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/Test2.java @@ -2,7 +2,9 @@ import org.junit.jupiter.api.extension.RegisterExtension; import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.population.Leg; import org.matsim.api.core.v01.population.PlanElement; +import org.matsim.contrib.drt.estimator.DrtEstimatorParams; import org.matsim.contrib.drt.routing.*; import org.matsim.contrib.drt.run.DrtConfigGroup; import org.matsim.contrib.drt.run.DrtControlerCreator; @@ -41,15 +43,14 @@ void test1() { config.controller().setOutputDirectory(utils.getOutputDirectory()); config.controller().setLastIteration(0); - // install the drt routing stuff, but not the mobsim stuff! Controler controler = DrtControlerCreator.createControler(config, false); DrtConfigGroup drtConfigGroup = DrtConfigGroup.getSingleModeDrtConfig(config); - DrtSpeedUpParams params = new DrtSpeedUpParams(); - params.fractionOfIterationsSwitchOn = 0; + DrtEstimatorParams params = new DrtEstimatorParams(); + params.teleport=true; drtConfigGroup.addParameterSet(params); System.out.println(config); @@ -79,39 +80,6 @@ void test1() { } - private static class DrtEstimatingRoutingModule implements RoutingModule { - - private final RoutingModule drtRoutingModule; - - private DrtEstimatingRoutingModule(TripRouter tripRouter) { - this.drtRoutingModule = tripRouter.getRoutingModule("drt"); - } - - - @Override - public List calcRoute(RoutingRequest request) { - List route = drtRoutingModule.calcRoute(request); - - DrtRouteCreator creator = null; - // creator.createRoute( departureTime, accessActLink, egressActLink, person, tripAttributes, routeFactories ); - - DrtRouteFactory factory = null; - // Route drtRoute = factory.createRoute( startLinkId, endLinkId ); - - // correct the attributes of the route as we need them - - // DrtInitialEstimator estimator = new DrtInitialEstimator(){ - // }; - - // DrtEstimator.Estimate estimate = estimator.estimate( route, 12. * 3600 ); - - // estimate.travelTime(); - // estimate.distance(); - - return route; - } - - } public record EstimatedDrtTeleportationInfo(double estTotalTravelTime, double estWaitTime, double estRideTime, double estRideDistance) { // The teleportation info refers to the main DRT leg (accessLink -> egressLink, departing at departureTime) diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/DrtEstimateAnalyzer.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimateAnalyzer.java similarity index 93% rename from contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/DrtEstimateAnalyzer.java rename to contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimateAnalyzer.java index d095a0037bd..0a249b9eace 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/DrtEstimateAnalyzer.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimateAnalyzer.java @@ -1,4 +1,4 @@ -package org.matsim.contrib.drt.extension.estimator; +package org.matsim.contrib.drt.estimator; import org.apache.commons.csv.CSVFormat; import org.apache.commons.csv.CSVPrinter; @@ -9,7 +9,6 @@ import org.matsim.api.core.v01.events.PersonMoneyEvent; import org.matsim.api.core.v01.population.Person; 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; @@ -38,20 +37,20 @@ public final class DrtEstimateAnalyzer implements StartupListener, ShutdownListe //private final DefaultMainLegRouter.RouteCreator creator; private final DrtEstimator estimator; private final DrtEventSequenceCollector collector; - private final DrtEstimatorConfigGroup config; + private final String mode; private CSVPrinter csv; - public DrtEstimateAnalyzer(DrtEstimator estimator, DrtEventSequenceCollector collector, DrtEstimatorConfigGroup config) { + public DrtEstimateAnalyzer(DrtEstimator estimator, DrtEventSequenceCollector collector, String mode) { this.estimator = estimator; this.collector = collector; - this.config = config; + this.mode = mode; } @Override public void notifyStartup(StartupEvent event) { - String filename = event.getServices().getControlerIO().getOutputFilename("drt_estimates_" + config.getMode() + ".csv"); + String filename = event.getServices().getControlerIO().getOutputFilename("drt_estimates_" + mode + ".csv"); try { csv = new CSVPrinter(Files.newBufferedWriter(Path.of(filename), StandardCharsets.UTF_8), CSVFormat.DEFAULT); diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/DrtEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimator.java similarity index 95% rename from contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/DrtEstimator.java rename to contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimator.java index fef209ed211..c7b2e9e3d76 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/DrtEstimator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimator.java @@ -1,4 +1,4 @@ -package org.matsim.contrib.drt.extension.estimator; +package org.matsim.contrib.drt.estimator; import org.matsim.contrib.drt.routing.DrtRoute; import org.matsim.core.controler.listener.ControlerListener; diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimatorModule.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimatorModule.java new file mode 100644 index 00000000000..734e6895136 --- /dev/null +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimatorModule.java @@ -0,0 +1,68 @@ +package org.matsim.contrib.drt.estimator; + +import com.google.inject.Singleton; +import com.google.inject.multibindings.MapBinder; +import org.matsim.contrib.drt.analysis.DrtEventSequenceCollector; +import org.matsim.contrib.drt.estimator.impl.BasicDrtEstimator; +import org.matsim.contrib.drt.estimator.impl.PessimisticDrtEstimator; +import org.matsim.contrib.drt.run.DrtConfigGroup; +import org.matsim.contrib.dvrp.run.AbstractDvrpModeModule; +import org.matsim.contrib.dvrp.run.DvrpMode; +import org.matsim.contrib.dvrp.run.DvrpModes; + +/** + * Main module that needs to be installed if any estimator is to be used. + */ +public class DrtEstimatorModule extends AbstractDvrpModeModule { + + private final DrtConfigGroup drtCfg; + private final DrtEstimatorParams params; + + public DrtEstimatorModule(String mode, DrtConfigGroup drtCfg, DrtEstimatorParams params) { + super(mode); + this.drtCfg = drtCfg; + this.params = params; + } + + @Override + public void install() { + + // try with default injections and overwrite + if (params.estimator == DrtEstimatorParams.EstimatorType.BASIC) { + bindModal(DrtEstimator.class).toProvider(modalProvider( + getter -> new BasicDrtEstimator( + getter.getModal(DrtEventSequenceCollector.class), + getter.getModal(DrtInitialEstimator.class), + params, drtCfg + ) + )).in(Singleton.class); + } else if (params.estimator == DrtEstimatorParams.EstimatorType.INITIAL) { + bindModal(DrtEstimator.class).to(modalKey(DrtInitialEstimator.class)); + } + + // TODO decide how initial estimators are defined + bindModal(DrtInitialEstimator.class).toInstance(new PessimisticDrtEstimator(drtCfg)); + + // DRT Estimators will be available as Map + MapBinder.newMapBinder(this.binder(), DvrpMode.class, DrtEstimator.class) + .addBinding(DvrpModes.mode(getMode())) + .to(modalKey(DrtEstimator.class)); + + addControlerListenerBinding().to(modalKey(DrtEstimator.class)); + + bindModal(DrtEstimatorParams.class).toInstance(params); + + // Needs to run before estimators + bindModal(DrtEstimateAnalyzer.class) + .toProvider( + modalProvider(getter -> new DrtEstimateAnalyzer(getter.getModal(DrtEstimator.class), + getter.getModal(DrtEventSequenceCollector.class), getMode())) + ) + .in(Singleton.class); + + addControlerListenerBinding().to(modalKey(DrtEstimateAnalyzer.class)); + + } + + +} diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/run/DrtEstimatorConfigGroup.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimatorParams.java similarity index 55% rename from contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/run/DrtEstimatorConfigGroup.java rename to contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimatorParams.java index 985435bcfc3..b0331389345 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/run/DrtEstimatorConfigGroup.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimatorParams.java @@ -1,14 +1,11 @@ -package org.matsim.contrib.drt.extension.estimator.run; +package org.matsim.contrib.drt.estimator; -import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Positive; import jakarta.validation.constraints.PositiveOrZero; -import org.matsim.api.core.v01.TransportMode; -import org.matsim.contrib.dvrp.run.Modal; -import org.matsim.contrib.util.ReflectiveConfigGroupWithConfigurableParameterSets; +import org.matsim.core.config.ReflectiveConfigGroup; -public class DrtEstimatorConfigGroup extends ReflectiveConfigGroupWithConfigurableParameterSets implements Modal { +public class DrtEstimatorParams extends ReflectiveConfigGroup { /** * Type of estimator, which will be installed in {@link DrtEstimatorModule}. @@ -27,22 +24,12 @@ public enum EstimatorType { CUSTOM } - public static final String GROUP_NAME = "drtEstimator"; + public static final String SET_NAME = "estimator"; - public DrtEstimatorConfigGroup() { - super(GROUP_NAME); + public DrtEstimatorParams() { + super(SET_NAME); } - public DrtEstimatorConfigGroup(String mode) { - super(GROUP_NAME); - this.mode = mode; - } - - @Parameter - @Comment("Mode of the drt service to estimate.") - @NotBlank - public String mode = TransportMode.drt; - @Parameter @Comment("Estimator typed to be used. In case of 'CUSTOM', guice bindings needs to be provided.") @NotNull @@ -58,15 +45,16 @@ public DrtEstimatorConfigGroup(String mode) { @PositiveOrZero public double randomization = 0.1; - @Override - public String getMode() { - return mode; - } + // TODO think about enum, or different place / name for this option + @Parameter + @Comment("Whether drt passengers should be teleported based on estimation") + @Deprecated + public boolean teleport = false; /** * Set estimator type and return same instance. */ - public DrtEstimatorConfigGroup withEstimator(EstimatorType estimator) { + public DrtEstimatorParams withEstimator(EstimatorType estimator) { this.estimator = estimator; return this; } diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/DrtInitialEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtInitialEstimator.java similarity index 86% rename from contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/DrtInitialEstimator.java rename to contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtInitialEstimator.java index a826a936e46..395ef79ff75 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/DrtInitialEstimator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtInitialEstimator.java @@ -1,4 +1,4 @@ -package org.matsim.contrib.drt.extension.estimator; +package org.matsim.contrib.drt.estimator; /** * This interface is used to provide an initial estimate for the drt service. diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/EstimationRoutingModule.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/EstimationRoutingModule.java new file mode 100644 index 00000000000..133fb6db5cf --- /dev/null +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/EstimationRoutingModule.java @@ -0,0 +1,27 @@ +package org.matsim.contrib.drt.estimator; + +import org.matsim.api.core.v01.population.PlanElement; +import org.matsim.contrib.dvrp.router.DvrpRoutingModule; +import org.matsim.core.router.RoutingModule; +import org.matsim.core.router.RoutingRequest; + +import java.util.List; + +/** + * Delegates routing to the original dvrp router and adds estimations to the leg. + * */ +public class EstimationRoutingModule implements RoutingModule { + private final DvrpRoutingModule delegate; + + public EstimationRoutingModule(DvrpRoutingModule delegate) { + this.delegate = delegate; + } + + @Override + public List calcRoute(RoutingRequest request) { + + List route = delegate.calcRoute(request); + + return route; + } +} diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/EstimationRoutingModuleProvider.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/EstimationRoutingModuleProvider.java new file mode 100644 index 00000000000..b9e68e64e2e --- /dev/null +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/EstimationRoutingModuleProvider.java @@ -0,0 +1,68 @@ +/* + * *********************************************************************** * + * project: org.matsim.* + * *********************************************************************** * + * * + * copyright : (C) 2019 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** * + */ + +package org.matsim.contrib.drt.estimator; + +import com.google.inject.Inject; +import com.google.inject.TypeLiteral; +import com.google.inject.name.Named; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.contrib.dvrp.router.DvrpRoutingModule; +import org.matsim.contrib.dvrp.router.DvrpRoutingModuleProvider; +import org.matsim.contrib.dvrp.router.DvrpRoutingModuleProvider.Stage; +import org.matsim.contrib.dvrp.run.DvrpMode; +import org.matsim.contrib.dvrp.run.DvrpModes; +import org.matsim.core.modal.ModalProviders; +import org.matsim.core.router.RoutingModule; +import org.matsim.core.utils.timing.TimeInterpretation; + +import java.util.Map; +import java.util.Objects; + +/** + * @author Michal Maciejewski (michalm) + */ +public class EstimationRoutingModuleProvider extends ModalProviders.AbstractProvider { + + @Inject + @Named(TransportMode.walk) + private RoutingModule walkRouter; + + @Inject + private TimeInterpretation timeInterpretation; + + public EstimationRoutingModuleProvider(String mode) { + super(mode, DvrpModes::mode); + } + + @Override + public EstimationRoutingModule get() { + Map stageRouters = getModalInstance(new TypeLiteral>() { + }); + RoutingModule mainRouter = Objects.requireNonNull(stageRouters.get(Stage.MAIN), + "Main mode router must be explicitly bound"); + RoutingModule accessRouter = stageRouters.getOrDefault(Stage.ACCESS, walkRouter); + RoutingModule egressRouter = stageRouters.getOrDefault(Stage.EGRESS, walkRouter); + + DvrpRoutingModule routingModule = new DvrpRoutingModule(mainRouter, accessRouter, egressRouter, + getModalInstance(DvrpRoutingModule.AccessEgressFacilityFinder.class), getMode(), timeInterpretation); + return new EstimationRoutingModule(routingModule); + } +} diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/impl/BasicDrtEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/BasicDrtEstimator.java similarity index 94% rename from contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/impl/BasicDrtEstimator.java rename to contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/BasicDrtEstimator.java index f1fd6f04c8f..cf8cb5416cd 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/impl/BasicDrtEstimator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/BasicDrtEstimator.java @@ -1,4 +1,4 @@ -package org.matsim.contrib.drt.extension.estimator.impl; +package org.matsim.contrib.drt.estimator.impl; import org.apache.commons.math3.stat.descriptive.SummaryStatistics; import org.apache.commons.math3.stat.regression.RegressionResults; @@ -9,9 +9,9 @@ import org.matsim.api.core.v01.events.PersonMoneyEvent; import org.matsim.api.core.v01.population.Person; import org.matsim.contrib.drt.analysis.DrtEventSequenceCollector; -import org.matsim.contrib.drt.extension.estimator.DrtEstimator; -import org.matsim.contrib.drt.extension.estimator.DrtInitialEstimator; -import org.matsim.contrib.drt.extension.estimator.run.DrtEstimatorConfigGroup; +import org.matsim.contrib.drt.estimator.DrtEstimator; +import org.matsim.contrib.drt.estimator.DrtInitialEstimator; +import org.matsim.contrib.drt.estimator.DrtEstimatorParams; import org.matsim.contrib.drt.routing.DrtRoute; import org.matsim.contrib.drt.run.DrtConfigGroup; import org.matsim.contrib.drt.speedup.DrtSpeedUp; @@ -31,7 +31,7 @@ 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 DrtEstimatorParams config; private final DrtConfigGroup drtConfig; private final DrtInitialEstimator initial; @@ -43,7 +43,7 @@ public class BasicDrtEstimator implements DrtEstimator, IterationEndsListener { private RegressionResults fare; public BasicDrtEstimator(DrtEventSequenceCollector collector, DrtInitialEstimator initial, - DrtEstimatorConfigGroup config, DrtConfigGroup drtConfig) { + DrtEstimatorParams config, DrtConfigGroup drtConfig) { //zones = injector.getModal(DrtZonalSystem.class); this.collector = collector; this.initial = initial; diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/impl/ConstantDrtEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/ConstantDrtEstimator.java similarity index 91% rename from contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/impl/ConstantDrtEstimator.java rename to contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/ConstantDrtEstimator.java index d9a4d4be46f..02363c67ea1 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/impl/ConstantDrtEstimator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/ConstantDrtEstimator.java @@ -1,6 +1,6 @@ -package org.matsim.contrib.drt.extension.estimator.impl; +package org.matsim.contrib.drt.estimator.impl; -import org.matsim.contrib.drt.extension.estimator.DrtInitialEstimator; +import org.matsim.contrib.drt.estimator.DrtInitialEstimator; import org.matsim.contrib.drt.fare.DrtFareParams; import org.matsim.contrib.drt.routing.DrtRoute; import org.matsim.contrib.drt.run.DrtConfigGroup; diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/impl/PessimisticDrtEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/PessimisticDrtEstimator.java similarity index 91% rename from contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/impl/PessimisticDrtEstimator.java rename to contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/PessimisticDrtEstimator.java index d26a318c635..c9cee293ceb 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/impl/PessimisticDrtEstimator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/PessimisticDrtEstimator.java @@ -1,6 +1,6 @@ -package org.matsim.contrib.drt.extension.estimator.impl; +package org.matsim.contrib.drt.estimator.impl; -import org.matsim.contrib.drt.extension.estimator.DrtInitialEstimator; +import org.matsim.contrib.drt.estimator.DrtInitialEstimator; import org.matsim.contrib.drt.fare.DrtFareParams; import org.matsim.contrib.drt.routing.DrtRoute; import org.matsim.contrib.drt.run.DrtConfigGroup; diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtConfigGroup.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtConfigGroup.java index 7fb685bd92e..78b23e54bd1 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtConfigGroup.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtConfigGroup.java @@ -30,6 +30,7 @@ import org.apache.logging.log4j.Logger; import org.matsim.api.core.v01.TransportMode; import org.matsim.contrib.drt.analysis.zonal.DrtZonalSystemParams; +import org.matsim.contrib.drt.estimator.DrtEstimatorParams; import org.matsim.contrib.drt.fare.DrtFareParams; import org.matsim.contrib.drt.optimizer.DrtRequestInsertionRetryParams; import org.matsim.contrib.drt.optimizer.insertion.DrtInsertionSearchParams; @@ -234,6 +235,9 @@ public enum OperationalScheme { @Nullable private PrebookingParams prebookingParams; + @Nullable + private DrtEstimatorParams drtEstimatorParams; + @Nullable private DrtRequestInsertionRetryParams drtRequestInsertionRetryParams; @@ -279,6 +283,12 @@ private void initSingletonParameterSets() { addDefinition(PrebookingParams.SET_NAME, PrebookingParams::new, () -> prebookingParams, params -> prebookingParams = (PrebookingParams)params); + + // estimator (optional) + addDefinition(DrtEstimatorParams.SET_NAME, DrtEstimatorParams::new, + () -> drtEstimatorParams, + params -> drtEstimatorParams = (DrtEstimatorParams) params); + } @Override @@ -358,6 +368,10 @@ public Optional getPrebookingParams() { return Optional.ofNullable(prebookingParams); } + public Optional getDrtEstimatorParams() { + return Optional.ofNullable(drtEstimatorParams); + } + /** * Convenience method that brings syntax closer to syntax in, e.g., {@link RoutingConfigGroup} or {@link ScoringConfigGroup} */ diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeModule.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeModule.java index a0cb1fc007c..f10262787a4 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeModule.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeModule.java @@ -25,6 +25,8 @@ import com.google.inject.name.Names; import org.matsim.api.core.v01.network.Network; import org.matsim.contrib.drt.analysis.DrtEventSequenceCollector; +import org.matsim.contrib.drt.estimator.DrtEstimatorModule; +import org.matsim.contrib.drt.estimator.EstimationRoutingModuleProvider; import org.matsim.contrib.drt.fare.DrtFareHandler; import org.matsim.contrib.drt.optimizer.rebalancing.RebalancingModule; import org.matsim.contrib.drt.prebooking.analysis.PrebookingModeAnalysisModule; @@ -33,6 +35,7 @@ import org.matsim.contrib.dvrp.fleet.FleetModule; import org.matsim.contrib.dvrp.fleet.FleetSpecification; import org.matsim.contrib.dvrp.router.DvrpModeRoutingNetworkModule; +import org.matsim.contrib.dvrp.router.DvrpRoutingModuleProvider; import org.matsim.contrib.dvrp.router.TimeAsTravelDisutility; import org.matsim.contrib.dvrp.run.AbstractDvrpModeModule; import org.matsim.contrib.dvrp.run.DvrpModes; @@ -104,5 +107,15 @@ public void install() { } install(new AdaptiveTravelTimeMatrixModule(drtCfg.mode)); + + if (drtCfg.getDrtEstimatorParams().isPresent()) { + install(new DrtEstimatorModule(getMode(), drtCfg, drtCfg.getDrtEstimatorParams().get())); + + if (drtCfg.getDrtEstimatorParams().get().teleport) { + addRoutingModuleBinding(getMode()).toProvider(new EstimationRoutingModuleProvider(getMode()));// not singleton + } + + } + } } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeQSimModule.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeQSimModule.java index 526c75d8020..073f1133212 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeQSimModule.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeQSimModule.java @@ -62,14 +62,21 @@ public DrtModeQSimModule(DrtConfigGroup drtCfg, AbstractQSimModule optimizerQSim @Override protected void configureQSim() { - boolean teleportDrtUsers = drtCfg.getDrtSpeedUpParams().isPresent() && DrtSpeedUp.isTeleportDrtUsers( + boolean teleportSpeedup = drtCfg.getDrtSpeedUpParams().isPresent() && DrtSpeedUp.isTeleportDrtUsers( drtCfg.getDrtSpeedUpParams().get(), getConfig().controller(), getIterationNumber()); - if (teleportDrtUsers) { + + boolean teleportEstimate = drtCfg.getDrtEstimatorParams().isPresent() && drtCfg.getDrtEstimatorParams().get().teleport; + + if (teleportSpeedup) { install(new PassengerEngineQSimModule(getMode(), - PassengerEngineQSimModule.PassengerEngineType.TELEPORTING)); + PassengerEngineQSimModule.PassengerEngineType.TELEPORTING_SPEED_UP)); bindModal(TeleportedRouteCalculator.class).toProvider( modalProvider(getter -> getter.getModal(DrtSpeedUp.class).createTeleportedRouteCalculator())) .asEagerSingleton(); + } else if (teleportEstimate) { + + install(new PassengerEngineQSimModule(getMode(), PassengerEngineQSimModule.PassengerEngineType.TELEPORTING_ESTIMATION)); + } else { install(new VrpAgentSourceQSimModule(getMode())); install(new PassengerEngineQSimModule(getMode())); @@ -94,7 +101,7 @@ public DrtRequestCreator get() { return new DrtRequestCreator(getMode(), events); } }).asEagerSingleton(); - + // this is not the actual selection which DynActionCreator is used, see // DrtModeOptimizerQSimModule bindModal(DrtActionCreator.class) diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeRoutingModule.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeRoutingModule.java index af56b5e3e38..978daf3e205 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeRoutingModule.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeRoutingModule.java @@ -78,7 +78,8 @@ public DrtModeRoutingModule(DrtConfigGroup drtCfg) { @Override public void install() { - addRoutingModuleBinding(getMode()).toProvider(new DvrpRoutingModuleProvider(getMode()));// not singleton + // TODO just for testing +// addRoutingModuleBinding(getMode()).toProvider(new DvrpRoutingModuleProvider(getMode()));// not singleton // (this is the normal routing module binding) modalMapBinder(DvrpRoutingModuleProvider.Stage.class, RoutingModule.class).addBinding( diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/PassengerEngineQSimModule.java b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/PassengerEngineQSimModule.java index 25372c12000..97cfb948c10 100644 --- a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/PassengerEngineQSimModule.java +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/PassengerEngineQSimModule.java @@ -12,7 +12,7 @@ */ public class PassengerEngineQSimModule extends AbstractDvrpModeQSimModule { public enum PassengerEngineType { - DEFAULT, WITH_PREBOOKING, TELEPORTING + DEFAULT, WITH_PREBOOKING, TELEPORTING_SPEED_UP, TELEPORTING_ESTIMATION } private final PassengerEngineType type; @@ -36,19 +36,10 @@ protected void configureQSim() { addMobsimScopeEventHandlerBinding().to(modalKey(PassengerEngine.class)); switch( type ){ - case DEFAULT -> { - addModalComponent( PassengerEngine.class, DefaultPassengerEngine.createProvider( getMode() ) ); - return; - } - case WITH_PREBOOKING -> { - addModalComponent( PassengerEngine.class, PassengerEngineWithPrebooking.createProvider( getMode() ) ); - return; - } - case TELEPORTING -> { - addModalComponent( PassengerEngine.class, TeleportingPassengerEngine.createProvider( getMode() ) ); - return; - } - default -> throw new IllegalStateException( "Type: " + type + " is not supported" ); + case DEFAULT -> addModalComponent( PassengerEngine.class, DefaultPassengerEngine.createProvider( getMode() ) ); + case WITH_PREBOOKING -> addModalComponent( PassengerEngine.class, PassengerEngineWithPrebooking.createProvider( getMode() ) ); + case TELEPORTING_SPEED_UP -> addModalComponent( PassengerEngine.class, TeleportingPassengerEngine.createProvider( getMode() ) ); + case TELEPORTING_ESTIMATION -> addModalComponent( PassengerEngine.class, TeleportingEstimationPassengerEngine.createProvider( getMode() )); } } } diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/TeleportingEstimationPassengerEngine.java b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/TeleportingEstimationPassengerEngine.java new file mode 100644 index 00000000000..140a7248e1a --- /dev/null +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/TeleportingEstimationPassengerEngine.java @@ -0,0 +1,213 @@ +/* + * *********************************************************************** * + * project: org.matsim.* + * *********************************************************************** * + * * + * copyright : (C) 2020 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** * + */ + +package org.matsim.contrib.dvrp.passenger; + +import com.google.common.base.Preconditions; +import com.google.common.base.Verify; +import jakarta.inject.Inject; +import jakarta.inject.Provider; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.api.core.v01.population.Leg; +import org.matsim.api.core.v01.population.Person; +import org.matsim.api.core.v01.population.Route; +import org.matsim.contrib.dvrp.optimizer.Request; +import org.matsim.contrib.dvrp.run.DvrpModes; +import org.matsim.core.api.experimental.events.EventsManager; +import org.matsim.core.mobsim.framework.*; +import org.matsim.core.mobsim.qsim.DefaultTeleportationEngine; +import org.matsim.core.mobsim.qsim.InternalInterface; +import org.matsim.core.mobsim.qsim.TeleportationEngine; +import org.matsim.core.mobsim.qsim.agents.WithinDayAgentUtils; +import org.matsim.core.modal.ModalProviders; +import org.matsim.vis.snapshotwriters.AgentSnapshotInfo; +import org.matsim.vis.snapshotwriters.VisData; + +import java.util.*; + +/** + * @author Michal Maciejewski (michalm) + */ +public class TeleportingEstimationPassengerEngine implements PassengerEngine, VisData { + public static final String ORIGINAL_ROUTE_ATTRIBUTE = "originalRoute"; + + private final String mode; + private final EventsManager eventsManager; + private final MobsimTimer mobsimTimer; + + private final PassengerRequestCreator requestCreator; + private final Network network; + private final PassengerRequestValidator requestValidator; + + private final InternalPassengerHandling internalPassengerHandling; + private final TeleportationEngine teleportationEngine; + private final Queue> teleportedRequests = new PriorityQueue<>( + Comparator.comparingDouble(Pair::getLeft)); + + private InternalInterface internalInterface; + + TeleportingEstimationPassengerEngine(String mode, EventsManager eventsManager, MobsimTimer mobsimTimer, + PassengerRequestCreator requestCreator, + Network network, PassengerRequestValidator requestValidator, Scenario scenario) { + this(mode, eventsManager, mobsimTimer, requestCreator, network, requestValidator, + new DefaultTeleportationEngine(scenario, eventsManager, false)); + } + + TeleportingEstimationPassengerEngine(String mode, EventsManager eventsManager, MobsimTimer mobsimTimer, + PassengerRequestCreator requestCreator, + Network network, PassengerRequestValidator requestValidator, TeleportationEngine teleportationEngine) { + this.mode = mode; + this.eventsManager = eventsManager; + this.mobsimTimer = mobsimTimer; + this.requestCreator = requestCreator; + this.network = network; + this.requestValidator = requestValidator; + this.teleportationEngine = teleportationEngine; + + internalPassengerHandling = new InternalPassengerHandling(mode, eventsManager); + } + + @Override + public void setInternalInterface(InternalInterface internalInterface) { + this.internalInterface = internalInterface; + internalPassengerHandling.setInternalInterface(internalInterface); + teleportationEngine.setInternalInterface(internalInterface); + } + + @Override + public void onPrepareSim() { + teleportationEngine.onPrepareSim(); + } + + @Override + public void doSimStep(double time) { + //first process passenger dropoff events + while (!teleportedRequests.isEmpty() && teleportedRequests.peek().getLeft() <= time) { + PassengerRequest request = teleportedRequests.poll().getRight(); + for (Id passenger : request.getPassengerIds()) { + eventsManager.processEvent( + new PassengerDroppedOffEvent(time, mode, request.getId(), passenger, null)); + } + } + + //then end teleported rides + teleportationEngine.doSimStep(time); + } + + @Override + public void afterSim() { + teleportationEngine.afterSim(); + } + + @Override + public boolean handleDeparture(double now, MobsimAgent agent, Id fromLinkId) { + if (!agent.getMode().equals(mode)) { + return false; + } + + MobsimPassengerAgent passenger = (MobsimPassengerAgent)agent; + Id toLinkId = passenger.getDestinationLinkId(); + Leg leg = (Leg) ((PlanAgent) passenger).getCurrentPlanElement(); + Route route = leg.getRoute(); + PassengerRequest request = requestCreator.createRequest(internalPassengerHandling.createRequestId(), + List.of(passenger.getId()), route, getLink(fromLinkId), getLink(toLinkId), now, now); + + eventsManager.processEvent(new PassengerWaitingEvent(now, mode, request.getId(), request.getPassengerIds())); + + if (internalPassengerHandling.validateRequest(request, requestValidator, now)) { + adaptLegRouteForTeleportation(List.of(passenger), leg, request, now); + + eventsManager.processEvent(new PassengerPickedUpEvent(now, mode, request.getId(), passenger.getId(), null)); + teleportationEngine.handleDeparture(now, passenger, fromLinkId); + teleportedRequests.add(ImmutablePair.of(now + route.getTravelTime().seconds(), request)); + } else { + //not much else can be done for immediate requests + //set the passenger agent to abort - the event will be thrown by the QSim + passenger.setStateToAbort(mobsimTimer.getTimeOfDay()); + internalInterface.arrangeNextAgentState(passenger); + } + + return true; + } + + private void adaptLegRouteForTeleportation(List passengers, Leg leg, PassengerRequest request, double now) { + Route route = leg.getRoute(); + + // TODO retrieve information from the leg + + eventsManager.processEvent(new PassengerRequestScheduledEvent(mobsimTimer.getTimeOfDay(), mode, request.getId(), + request.getPassengerIds(), null, now, now + route.getTravelTime().seconds())); + + } + + private Link getLink(Id linkId) { + return Preconditions.checkNotNull(network.getLinks().get(linkId), + "Link id=%s does not exist in network for mode %s. Agent departs from a link that does not belong to that network?", + linkId, mode); + } + + @Override + public boolean notifyWaitForPassengers(PassengerPickupActivity pickupActivity, MobsimDriverAgent driver, + Id requestId) { + throw new UnsupportedOperationException("No notifying when teleporting"); + } + + @Override + public boolean tryPickUpPassengers(PassengerPickupActivity pickupActivity, MobsimDriverAgent driver, + Id requestId, double now) { + throw new UnsupportedOperationException("No picking-up when teleporting"); + } + + @Override + public void dropOffPassengers(MobsimDriverAgent driver, Id requestId, double now) { + throw new UnsupportedOperationException("No dropping-off when teleporting"); + } + + @Override + public Collection addAgentSnapshotInfo(Collection positions) { + return teleportationEngine.addAgentSnapshotInfo(positions); + } + + public static Provider createProvider(String mode) { + return new ModalProviders.AbstractProvider<>(mode, DvrpModes::mode) { + @Inject + private EventsManager eventsManager; + + @Inject + private MobsimTimer mobsimTimer; + + @Inject + private Scenario scenario; + + @Override + public TeleportingEstimationPassengerEngine get() { + return new TeleportingEstimationPassengerEngine(getMode(), eventsManager, mobsimTimer, + getModalInstance(PassengerRequestCreator.class), + getModalInstance(Network.class), + getModalInstance(PassengerRequestValidator.class), scenario); + } + }; + } +} diff --git a/contribs/dvrp/src/test/java/org/matsim/contrib/dvrp/passenger/TeleportingPassengerEngineTest.java b/contribs/dvrp/src/test/java/org/matsim/contrib/dvrp/passenger/TeleportingPassengerEngineTest.java index e26364800ab..eac96fb7bbe 100644 --- a/contribs/dvrp/src/test/java/org/matsim/contrib/dvrp/passenger/TeleportingPassengerEngineTest.java +++ b/contribs/dvrp/src/test/java/org/matsim/contrib/dvrp/passenger/TeleportingPassengerEngineTest.java @@ -102,7 +102,7 @@ void test_invalid_rejected() { private QSim createQSim(TeleportedRouteCalculator teleportedRouteCalculator, PassengerRequestValidator requestValidator) { return new QSimBuilder(fixture.config).useDefaults() - .addQSimModule(new PassengerEngineQSimModule(MODE, PassengerEngineType.TELEPORTING)) + .addQSimModule(new PassengerEngineQSimModule(MODE, PassengerEngineType.TELEPORTING_SPEED_UP)) .addQSimModule(new AbstractDvrpModeQSimModule(MODE) { @Override protected void configureQSim() { From 19ddedf9b143de1c57e035056cfcda4998dec1f7 Mon Sep 17 00:00:00 2001 From: Chengqi Lu <43133404+luchengqi7@users.noreply.github.com> Date: Mon, 26 Feb 2024 12:26:28 +0100 Subject: [PATCH 07/19] WIP --- .../contrib/drt/teleportation/Test2.java | 86 +------------------ .../drt/estimator/DrtEstimatorModule.java | 26 +++--- .../drt/estimator/DrtEstimatorParams.java | 34 -------- .../estimator/EstimationRoutingModule.java | 14 ++- .../EstimationRoutingModuleProvider.java | 9 +- .../estimator/impl/RealisticDrtEstimator.java | 72 ++++++++++++++++ .../contrib/drt/run/DrtConfigGroup.java | 13 +++ .../matsim/contrib/drt/run/DrtModeModule.java | 5 -- .../contrib/drt/run/DrtModeQSimModule.java | 2 +- .../contrib/drt/run/DrtModeRoutingModule.java | 7 +- .../core/modal/AbstractModalModule.java | 1 + 11 files changed, 125 insertions(+), 144 deletions(-) create mode 100644 contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/RealisticDrtEstimator.java diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/Test2.java b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/Test2.java index 89acd867dd2..91952f6394f 100644 --- a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/Test2.java +++ b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/Test2.java @@ -49,8 +49,9 @@ void test1() { DrtConfigGroup drtConfigGroup = DrtConfigGroup.getSingleModeDrtConfig(config); + drtConfigGroup.simulationType = DrtConfigGroup.SimulationType.estimateAndTeleport; + DrtEstimatorParams params = new DrtEstimatorParams(); - params.teleport=true; drtConfigGroup.addParameterSet(params); System.out.println(config); @@ -68,90 +69,7 @@ void test1() { // this would be more general, could be useful for other use cases? // but we only need it for DRT for now? - /* - controler.addOverridingModule( new AbstractModule(){ - @Override public void install(){ - this.addRoutingModuleBinding( "drt" ).to( DrtEstimatingRoutingModule.class ); - } - } ); - */ - controler.run(); } - - - public record EstimatedDrtTeleportationInfo(double estTotalTravelTime, double estWaitTime, double estRideTime, double estRideDistance) { - // The teleportation info refers to the main DRT leg (accessLink -> egressLink, departing at departureTime) - // The info teleportation engine can make use of this data to generate a teleport leg - // wait time and ride time are specified, such that we can score them differently (if required) - } - - public record DrtRouteInfoEstimator(LeastCostPathCalculator router, TravelTime travelTime, DistributionGenerator distributionGenerator) { - // This record/class is to be created before (each?) MobSim/QSim. - public EstimatedDrtTeleportationInfo estimateDrtRoute(Link accessLink, Link egressLink, double departureTime) { - double waitTime = distributionGenerator.generateWaitTime(); - double directRideTime = VrpPaths.calcAndCreatePath(accessLink, egressLink, departureTime + waitTime, router, travelTime).getTravelTime(); - double rideTime = distributionGenerator.generateRideTime(directRideTime); - - // since VrpPath does not contain Path information. We need to calculate this manually. - // VRP path logic: toNode of fromLink -> fromNode of toLink -> toNode of toLink - LeastCostPathCalculator.Path path = router.calcLeastCostPath(accessLink.getToNode(), egressLink.getFromNode(), - departureTime + waitTime, null, null); - path.links.add(egressLink); - - double directRideDistance = path.links.stream().mapToDouble(Link::getLength).sum(); - double rideDistance = distributionGenerator.generateRideDistance(rideTime, directRideTime, directRideDistance); - - return new EstimatedDrtTeleportationInfo(waitTime + rideTime, waitTime, rideTime, rideDistance); - } - } - - public static class DistributionGenerator { - private final Random random = new Random(4711); - private final double estRideTimeAlpha; - private final double estRideTimeBeta; - private final double rideTimeStd; - private final double estMeanWaitTime; - private final double waitTimeStd; - private final double probabilityRejection; - - public DistributionGenerator(double estRideTimeAlpha, double estRideTimeBeta, double rideTimeStd, double estMeanWaitTime, - double waitTimeStd, double probabilityRejection) { - this.estRideTimeAlpha = estRideTimeAlpha; - this.estRideTimeBeta = estRideTimeBeta; - this.rideTimeStd = rideTimeStd; - this.estMeanWaitTime = estMeanWaitTime; - this.waitTimeStd = waitTimeStd; - this.probabilityRejection = probabilityRejection; - } - - public DistributionGenerator generateExampleDistributionGenerator() { - return new DistributionGenerator(1.5, 300, 0.2, 300, 0.4, 0.0); - } - - public double generateRideTime(double directRideTime) { - // TODO improve this distribution - double estMeanRideTime = estRideTimeAlpha * directRideTime + estRideTimeBeta; - return Math.max(directRideTime, estMeanRideTime * (1 + random.nextGaussian() * rideTimeStd)); - } - - public double generateRideDistance(double estRideTime, double directRideTime, double directRideDistance) { - // TODO Currently, same ratio is used as in the ride time estimation; improve this distribution - double ratio = estRideTime / directRideTime; - return ratio * directRideDistance; - } - - public double generateWaitTime() { - // TODO improve this distribution - return Math.max(estMeanWaitTime * (1 + random.nextGaussian() * waitTimeStd), 0); - } - - public boolean generateIsTripAccepted() { - // TODO maybe incorporate this into the estimated wait time, ride time and ride distance - return random.nextDouble() >= probabilityRejection; - } - } - - } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimatorModule.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimatorModule.java index 734e6895136..ad017796ace 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimatorModule.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimatorModule.java @@ -1,5 +1,6 @@ package org.matsim.contrib.drt.estimator; +import com.google.inject.Binder; import com.google.inject.Singleton; import com.google.inject.multibindings.MapBinder; import org.matsim.contrib.drt.analysis.DrtEventSequenceCollector; @@ -9,6 +10,7 @@ import org.matsim.contrib.dvrp.run.AbstractDvrpModeModule; import org.matsim.contrib.dvrp.run.DvrpMode; import org.matsim.contrib.dvrp.run.DvrpModes; +import org.matsim.core.modal.ModalProviders; /** * Main module that needs to be installed if any estimator is to be used. @@ -24,24 +26,22 @@ public DrtEstimatorModule(String mode, DrtConfigGroup drtCfg, DrtEstimatorParams this.params = params; } + public static Object bindEstimator(Binder binder, String mode){ + + // TODO create helper method for binding + +// DvrpMode key = DvrpModes.mode(mode); +// binder.bind(key) +// ModalProviders.createProvider(mode, DvrpModes::mode); + return null; + } + @Override public void install() { - // try with default injections and overwrite - if (params.estimator == DrtEstimatorParams.EstimatorType.BASIC) { - bindModal(DrtEstimator.class).toProvider(modalProvider( - getter -> new BasicDrtEstimator( - getter.getModal(DrtEventSequenceCollector.class), - getter.getModal(DrtInitialEstimator.class), - params, drtCfg - ) - )).in(Singleton.class); - } else if (params.estimator == DrtEstimatorParams.EstimatorType.INITIAL) { - bindModal(DrtEstimator.class).to(modalKey(DrtInitialEstimator.class)); - } - // TODO decide how initial estimators are defined bindModal(DrtInitialEstimator.class).toInstance(new PessimisticDrtEstimator(drtCfg)); + bindModal(DrtEstimator.class).toInstance(new PessimisticDrtEstimator(drtCfg)); // DRT Estimators will be available as Map MapBinder.newMapBinder(this.binder(), DvrpMode.class, DrtEstimator.class) diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimatorParams.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimatorParams.java index b0331389345..4a892e1a0e4 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimatorParams.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimatorParams.java @@ -7,33 +7,12 @@ public class DrtEstimatorParams extends ReflectiveConfigGroup { - /** - * Type of estimator, which will be installed in {@link DrtEstimatorModule}. - */ - public enum EstimatorType { - BASIC, - - /** - * Will use the bound initial estimator, without any updates. - */ - INITIAL, - - /** - * Custom estimator, that needs to provided via binding. - */ - CUSTOM - } - public static final String SET_NAME = "estimator"; public DrtEstimatorParams() { super(SET_NAME); } - @Parameter - @Comment("Estimator typed to be used. In case of 'CUSTOM', guice bindings needs to be provided.") - @NotNull - public EstimatorType estimator = EstimatorType.BASIC; @Parameter @Comment("Decay of the exponential moving average.") @@ -45,18 +24,5 @@ public DrtEstimatorParams() { @PositiveOrZero public double randomization = 0.1; - // TODO think about enum, or different place / name for this option - @Parameter - @Comment("Whether drt passengers should be teleported based on estimation") - @Deprecated - public boolean teleport = false; - - /** - * Set estimator type and return same instance. - */ - public DrtEstimatorParams withEstimator(EstimatorType estimator) { - this.estimator = estimator; - return this; - } } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/EstimationRoutingModule.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/EstimationRoutingModule.java index 133fb6db5cf..602c3cdd3e2 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/EstimationRoutingModule.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/EstimationRoutingModule.java @@ -1,6 +1,8 @@ package org.matsim.contrib.drt.estimator; +import org.matsim.api.core.v01.population.Leg; import org.matsim.api.core.v01.population.PlanElement; +import org.matsim.contrib.drt.routing.DrtRoute; import org.matsim.contrib.dvrp.router.DvrpRoutingModule; import org.matsim.core.router.RoutingModule; import org.matsim.core.router.RoutingRequest; @@ -12,9 +14,11 @@ * */ public class EstimationRoutingModule implements RoutingModule { private final DvrpRoutingModule delegate; + private final DrtEstimator estimator; - public EstimationRoutingModule(DvrpRoutingModule delegate) { + public EstimationRoutingModule(DvrpRoutingModule delegate, DrtEstimator estimator) { this.delegate = delegate; + this.estimator = estimator; } @Override @@ -22,6 +26,14 @@ public List calcRoute(RoutingRequest request) { List route = delegate.calcRoute(request); + Leg mainDrtLeg = (Leg) route.get(2); + DrtRoute drtRoute = (DrtRoute) mainDrtLeg.getRoute(); + DrtEstimator.Estimate estimate = estimator.estimate(drtRoute, mainDrtLeg.getDepartureTime()); + + mainDrtLeg.getAttributes().putAttribute("travel_time", estimate.travelTime()); + mainDrtLeg.getAttributes().putAttribute("travel_distance", estimate.distance()); + mainDrtLeg.getAttributes().putAttribute("wait_time", estimate.waitingTime()); + return route; } } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/EstimationRoutingModuleProvider.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/EstimationRoutingModuleProvider.java index b9e68e64e2e..4427c080c02 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/EstimationRoutingModuleProvider.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/EstimationRoutingModuleProvider.java @@ -36,9 +36,7 @@ import java.util.Map; import java.util.Objects; -/** - * @author Michal Maciejewski (michalm) - */ + public class EstimationRoutingModuleProvider extends ModalProviders.AbstractProvider { @Inject @@ -48,6 +46,9 @@ public class EstimationRoutingModuleProvider extends ModalProviders.AbstractProv @Inject private TimeInterpretation timeInterpretation; + @Inject + private Map estimators; + public EstimationRoutingModuleProvider(String mode) { super(mode, DvrpModes::mode); } @@ -63,6 +64,6 @@ public EstimationRoutingModule get() { DvrpRoutingModule routingModule = new DvrpRoutingModule(mainRouter, accessRouter, egressRouter, getModalInstance(DvrpRoutingModule.AccessEgressFacilityFinder.class), getMode(), timeInterpretation); - return new EstimationRoutingModule(routingModule); + return new EstimationRoutingModule(routingModule, estimators.get(DvrpModes.mode(getMode()))); } } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/RealisticDrtEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/RealisticDrtEstimator.java new file mode 100644 index 00000000000..b9ff529d3e1 --- /dev/null +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/RealisticDrtEstimator.java @@ -0,0 +1,72 @@ +package org.matsim.contrib.drt.estimator.impl; + +import org.matsim.contrib.drt.estimator.DrtInitialEstimator; +import org.matsim.contrib.drt.routing.DrtRoute; +import org.matsim.core.utils.misc.OptionalTime; + +import java.util.Random; + +public class RealisticDrtEstimator implements DrtInitialEstimator { + + private final DistributionGenerator distributionGenerator; + + public RealisticDrtEstimator(DistributionGenerator distributionGenerator) { + this.distributionGenerator = distributionGenerator; + } + + @Override + public Estimate estimate(DrtRoute route, OptionalTime departureTime) { + double directRideTIme = route.getDirectRideTime(); + double directDistance = route.getDistance(); + double waitTime = distributionGenerator.generateWaitTime(); + double rideTime = distributionGenerator.generateRideTime(directRideTIme); + double rideDistance = distributionGenerator.generateRideDistance(rideTime, directRideTIme, directDistance); + double acceptanceRate = distributionGenerator.generateAcceptanceRate(); + + return new Estimate(rideDistance, waitTime + rideTime, waitTime, 0, acceptanceRate); + } + + + public static class DistributionGenerator { + private final Random random = new Random(4711); + private final double estRideTimeAlpha; + private final double estRideTimeBeta; + private final double rideTimeStd; + private final double estMeanWaitTime; + private final double waitTimeStd; + + public DistributionGenerator(double estRideTimeAlpha, double estRideTimeBeta, double rideTimeStd, double estMeanWaitTime, + double waitTimeStd) { + this.estRideTimeAlpha = estRideTimeAlpha; + this.estRideTimeBeta = estRideTimeBeta; + this.rideTimeStd = rideTimeStd; + this.estMeanWaitTime = estMeanWaitTime; + this.waitTimeStd = waitTimeStd; + } + + public DistributionGenerator generateExampleDistributionGenerator() { + return new DistributionGenerator(1.5, 300, 0.2, 300, 0.4); + } + + public double generateRideTime(double directRideTime) { + // TODO improve this distribution + double estMeanRideTime = estRideTimeAlpha * directRideTime + estRideTimeBeta; + return Math.max(directRideTime, estMeanRideTime * (1 + random.nextGaussian() * rideTimeStd)); + } + + public double generateRideDistance(double estRideTime, double directRideTime, double directRideDistance) { + // TODO Currently, same ratio is used as in the ride time estimation; improve this distribution + double ratio = estRideTime / directRideTime; + return ratio * directRideDistance; + } + + public double generateWaitTime() { + // TODO improve this distribution + return Math.max(estMeanWaitTime * (1 + random.nextGaussian() * waitTimeStd), 0); + } + + public double generateAcceptanceRate() { + return random.nextDouble(); + } + } +} diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtConfigGroup.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtConfigGroup.java index 78b23e54bd1..52a8f6febd7 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtConfigGroup.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtConfigGroup.java @@ -28,6 +28,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.checkerframework.checker.units.qual.C; import org.matsim.api.core.v01.TransportMode; import org.matsim.contrib.drt.analysis.zonal.DrtZonalSystemParams; import org.matsim.contrib.drt.estimator.DrtEstimatorParams; @@ -217,6 +218,15 @@ public enum OperationalScheme { @Comment("Store planned unshared drt route as a link sequence") public boolean storeUnsharedPath = false; // If true, the planned unshared path is stored and exported in plans + + public enum SimulationType { + fullSimulation, estimateAndTeleport + } + + @Parameter + @Comment("Whether full simulation drt is employed") + public SimulationType simulationType = SimulationType.fullSimulation; + @NotNull private DrtInsertionSearchParams drtInsertionSearchParams; @@ -333,6 +343,9 @@ protected void checkConsistency(Config config) { if (useModeFilteredSubnetwork) { DvrpModeRoutingNetworkModule.checkUseModeFilteredSubnetworkAllowed(config, mode); } + + + // TODO if we teleport we need to check if estimates are present } @Override diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeModule.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeModule.java index f10262787a4..9479c43be56 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeModule.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeModule.java @@ -110,11 +110,6 @@ public void install() { if (drtCfg.getDrtEstimatorParams().isPresent()) { install(new DrtEstimatorModule(getMode(), drtCfg, drtCfg.getDrtEstimatorParams().get())); - - if (drtCfg.getDrtEstimatorParams().get().teleport) { - addRoutingModuleBinding(getMode()).toProvider(new EstimationRoutingModuleProvider(getMode()));// not singleton - } - } } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeQSimModule.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeQSimModule.java index 073f1133212..d3af6cb8283 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeQSimModule.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeQSimModule.java @@ -65,7 +65,7 @@ protected void configureQSim() { boolean teleportSpeedup = drtCfg.getDrtSpeedUpParams().isPresent() && DrtSpeedUp.isTeleportDrtUsers( drtCfg.getDrtSpeedUpParams().get(), getConfig().controller(), getIterationNumber()); - boolean teleportEstimate = drtCfg.getDrtEstimatorParams().isPresent() && drtCfg.getDrtEstimatorParams().get().teleport; + boolean teleportEstimate = drtCfg.getDrtEstimatorParams().isPresent() && drtCfg.simulationType == DrtConfigGroup.SimulationType.estimateAndTeleport; if (teleportSpeedup) { install(new PassengerEngineQSimModule(getMode(), diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeRoutingModule.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeRoutingModule.java index 978daf3e205..8fae5fb3f3f 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeRoutingModule.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeRoutingModule.java @@ -28,6 +28,7 @@ import org.matsim.api.core.v01.Scenario; import org.matsim.api.core.v01.network.Network; import org.matsim.api.core.v01.population.Population; +import org.matsim.contrib.drt.estimator.EstimationRoutingModuleProvider; import org.matsim.contrib.drt.routing.DefaultDrtRouteUpdater; import org.matsim.contrib.drt.routing.DrtRouteCreator; import org.matsim.contrib.drt.routing.DrtRouteUpdater; @@ -78,8 +79,10 @@ public DrtModeRoutingModule(DrtConfigGroup drtCfg) { @Override public void install() { - // TODO just for testing -// addRoutingModuleBinding(getMode()).toProvider(new DvrpRoutingModuleProvider(getMode()));// not singleton + switch (drtCfg.simulationType){ + case fullSimulation -> addRoutingModuleBinding(getMode()).toProvider(new DvrpRoutingModuleProvider(getMode()));// not singleton + case estimateAndTeleport -> addRoutingModuleBinding(getMode()).toProvider(new EstimationRoutingModuleProvider(getMode()));// not singleton + } // (this is the normal routing module binding) modalMapBinder(DvrpRoutingModuleProvider.Stage.class, RoutingModule.class).addBinding( diff --git a/matsim/src/main/java/org/matsim/core/modal/AbstractModalModule.java b/matsim/src/main/java/org/matsim/core/modal/AbstractModalModule.java index b7fe58794bd..b45cef6d761 100644 --- a/matsim/src/main/java/org/matsim/core/modal/AbstractModalModule.java +++ b/matsim/src/main/java/org/matsim/core/modal/AbstractModalModule.java @@ -23,6 +23,7 @@ import java.lang.annotation.Annotation; import java.util.function.Function; +import com.google.inject.Binder; import org.matsim.core.controler.AbstractModule; import com.google.inject.Key; From 3efb4424b30f4dbed17039bf908ad95ad39a9eeb Mon Sep 17 00:00:00 2001 From: Chengqi Lu <43133404+luchengqi7@users.noreply.github.com> Date: Mon, 26 Feb 2024 17:17:53 +0100 Subject: [PATCH 08/19] WIP --- .../modechoice/MultiModalDrtLegEstimator.java | 6 +- .../{Test2.java => DrtTeleportationTest.java} | 45 +-- .../contrib/drt/teleportation/Test.java | 322 ------------------ .../drt/estimator/DrtEstimateAnalyzer.java | 2 +- .../contrib/drt/estimator/DrtEstimator.java | 23 +- .../drt/estimator/DrtEstimatorModule.java | 4 - .../drt/estimator/DrtEstimatorParams.java | 30 +- .../drt/estimator/DrtInitialEstimator.java | 9 - .../drt/estimator/DrtOnlineEstimator.java | 7 + .../estimator/EstimationRoutingModule.java | 18 +- .../drt/estimator/impl/BasicDrtEstimator.java | 8 +- .../estimator/impl/ConstantDrtEstimator.java | 4 +- .../impl/PessimisticDrtEstimator.java | 4 +- .../estimator/impl/RealisticDrtEstimator.java | 4 +- .../contrib/drt/run/DrtConfigGroup.java | 7 +- .../matsim/contrib/drt/run/DrtModeModule.java | 2 +- .../TeleportingEstimationPassengerEngine.java | 79 +++-- 17 files changed, 156 insertions(+), 418 deletions(-) rename contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/{Test2.java => DrtTeleportationTest.java} (70%) delete mode 100644 contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/Test.java delete mode 100644 contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtInitialEstimator.java create mode 100644 contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtOnlineEstimator.java diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/modechoice/MultiModalDrtLegEstimator.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/modechoice/MultiModalDrtLegEstimator.java index 02708c65115..4d3980d5d24 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/modechoice/MultiModalDrtLegEstimator.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/modechoice/MultiModalDrtLegEstimator.java @@ -49,10 +49,10 @@ public double estimate(EstimatorContext context, String mode, Leg leg, ModeAvail // By default, waiting time is scored as travel time return params.constant + - params.marginalUtilityOfDistance_m * est.distance() + - params.marginalUtilityOfTraveling_s * est.travelTime() + + params.marginalUtilityOfDistance_m * est.rideDistance() + + params.marginalUtilityOfTraveling_s * est.rideTime() + params.marginalUtilityOfTraveling_s * est.waitingTime() + - context.scoring.marginalUtilityOfMoney * params.monetaryDistanceCostRate * est.distance() + + context.scoring.marginalUtilityOfMoney * params.monetaryDistanceCostRate * est.rideDistance() + context.scoring.marginalUtilityOfMoney * est.fare(); } diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/Test2.java b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationTest.java similarity index 70% rename from contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/Test2.java rename to contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationTest.java index 91952f6394f..7fafa3637ca 100644 --- a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/Test2.java +++ b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationTest.java @@ -1,58 +1,61 @@ package org.matsim.contrib.drt.teleportation; +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; -import org.matsim.api.core.v01.network.Link; -import org.matsim.api.core.v01.population.Leg; -import org.matsim.api.core.v01.population.PlanElement; +import org.matsim.contrib.drt.estimator.DrtEstimator; import org.matsim.contrib.drt.estimator.DrtEstimatorParams; -import org.matsim.contrib.drt.routing.*; +import org.matsim.contrib.drt.estimator.impl.PessimisticDrtEstimator; +import org.matsim.contrib.drt.fare.DrtFareParams; import org.matsim.contrib.drt.run.DrtConfigGroup; import org.matsim.contrib.drt.run.DrtControlerCreator; import org.matsim.contrib.drt.run.MultiModeDrtConfigGroup; -import org.matsim.contrib.drt.speedup.DrtSpeedUpParams; -import org.matsim.contrib.dvrp.path.VrpPaths; +import org.matsim.contrib.dvrp.run.AbstractDvrpModeModule; import org.matsim.contrib.dvrp.run.DvrpConfigGroup; import org.matsim.core.config.Config; import org.matsim.core.config.ConfigUtils; import org.matsim.core.controler.Controler; -import org.matsim.core.router.*; -import org.matsim.core.router.util.LeastCostPathCalculator; -import org.matsim.core.router.util.TravelTime; import org.matsim.core.utils.io.IOUtils; import org.matsim.examples.ExamplesUtils; import org.matsim.testcases.MatsimTestUtils; import org.matsim.vis.otfvis.OTFVisConfigGroup; import java.net.URL; -import java.util.*; -class Test2 { +class DrtTeleportationTest { @RegisterExtension public MatsimTestUtils utils = new MatsimTestUtils(); - @org.junit.jupiter.api.Test - void test1() { - + @Test + void testPessimisticEstimator() { URL url = IOUtils.extendUrl(ExamplesUtils.getTestScenarioURL("mielec"), "mielec_drt_config.xml"); Config config = ConfigUtils.loadConfig(url, new MultiModeDrtConfigGroup(), new DvrpConfigGroup(), new OTFVisConfigGroup()); - config.network().setInputFile("network.xml"); config.plans().setInputFile("plans_only_drt_1.0.xml.gz"); - config.controller().setOutputDirectory(utils.getOutputDirectory()); - config.controller().setLastIteration(0); + config.controller().setLastIteration(3); // install the drt routing stuff, but not the mobsim stuff! Controler controler = DrtControlerCreator.createControler(config, false); + DrtConfigGroup drtConfigGroup = DrtConfigGroup.getSingleModeDrtConfig(config); + drtConfigGroup.maxTravelTimeAlpha = 1.1; + drtConfigGroup.simulationType = DrtConfigGroup.SimulationType.estimateAndTeleport; +// DrtEstimatorParams params = new DrtEstimatorParams(); +// drtConfigGroup.addParameterSet(params); - DrtConfigGroup drtConfigGroup = DrtConfigGroup.getSingleModeDrtConfig(config); + DrtFareParams fareParams = new DrtFareParams(); + fareParams.baseFare = 1.0; + fareParams.distanceFare_m = 0.001; + drtConfigGroup.addParameterSet(fareParams); - drtConfigGroup.simulationType = DrtConfigGroup.SimulationType.estimateAndTeleport; + controler.addOverridingModule(new AbstractDvrpModeModule(drtConfigGroup.mode) { + @Override + public void install() { + bindModal(DrtEstimator.class).toInstance(new PessimisticDrtEstimator(drtConfigGroup)); + } + }); - DrtEstimatorParams params = new DrtEstimatorParams(); - drtConfigGroup.addParameterSet(params); System.out.println(config); diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/Test.java b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/Test.java deleted file mode 100644 index 57539c3796b..00000000000 --- a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/Test.java +++ /dev/null @@ -1,322 +0,0 @@ -package org.matsim.contrib.drt.teleportation; - -import com.google.common.collect.ImmutableMap; -import com.google.inject.Inject; -import com.google.inject.Provider; -import com.google.inject.TypeLiteral; -import com.google.inject.name.Named; -import org.apache.commons.lang3.tuple.Pair; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.junit.jupiter.api.extension.RegisterExtension; -import org.locationtech.jts.geom.prep.PreparedGeometry; -import org.matsim.api.core.v01.Id; -import org.matsim.api.core.v01.Scenario; -import org.matsim.api.core.v01.TransportMode; -import org.matsim.api.core.v01.network.Network; -import org.matsim.api.core.v01.population.Activity; -import org.matsim.api.core.v01.population.Person; -import org.matsim.api.core.v01.population.PlanElement; -import org.matsim.contrib.drt.routing.DrtRouteCreator; -import org.matsim.contrib.drt.routing.DrtStopFacility; -import org.matsim.contrib.drt.routing.DrtStopFacilityImpl; -import org.matsim.contrib.drt.routing.DrtStopNetwork; -import org.matsim.contrib.drt.run.DrtConfigGroup; -import org.matsim.contrib.drt.run.DrtControlerCreator; -import org.matsim.contrib.drt.run.DrtModeRoutingModule; -import org.matsim.contrib.dvrp.router.*; -import org.matsim.contrib.dvrp.run.AbstractDvrpModeModule; -import org.matsim.contrib.dvrp.run.DvrpMode; -import org.matsim.contrib.dvrp.run.DvrpModes; -import org.matsim.core.config.Config; -import org.matsim.core.config.ConfigGroup; -import org.matsim.core.config.ConfigUtils; -import org.matsim.core.controler.AbstractModule; -import org.matsim.core.controler.Controler; -import org.matsim.core.modal.ModalProviders; -import org.matsim.core.population.PopulationUtils; -import org.matsim.core.router.DefaultRoutingRequest; -import org.matsim.core.router.RoutingModule; -import org.matsim.core.router.RoutingRequest; -import org.matsim.core.router.TripRouter; -import org.matsim.core.router.costcalculators.TravelDisutilityFactory; -import org.matsim.core.router.speedy.SpeedyALTFactory; -import org.matsim.core.router.util.LeastCostPathCalculatorFactory; -import org.matsim.core.router.util.TravelTime; -import org.matsim.core.scenario.ScenarioUtils; -import org.matsim.core.utils.collections.QuadTrees; -import org.matsim.core.utils.io.IOUtils; -import org.matsim.core.utils.timing.TimeInterpretation; -import org.matsim.examples.ExamplesUtils; -import org.matsim.facilities.Facility; -import org.matsim.pt.transitSchedule.api.TransitScheduleReader; -import org.matsim.testcases.MatsimTestUtils; -import org.matsim.utils.gis.shp2matsim.ShpGeometryUtils; -import org.matsim.utils.objectattributes.attributable.Attributes; - -import java.net.URL; -import java.util.*; - -class Test{ - - @RegisterExtension public MatsimTestUtils utils = new MatsimTestUtils(); - - @org.junit.jupiter.api.Test void test1() { - - URL url = IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "mielec" ), "empty_config.xml" ); - Config config = ConfigUtils.loadConfig( url ); - - config.network().setInputFile( "network.xml" ); - config.plans().setInputFile( "plans_only_drt_1.0.xml.gz" ); - - config.controller().setOutputDirectory( utils.getOutputDirectory() ); - config.controller().setLastIteration( 0 ); - - Scenario scenario = DrtControlerCreator.createScenarioWithDrtRouteFactory( config ); - ScenarioUtils.loadScenario( scenario ); - - Controler controler = new Controler( scenario ); - controler.addOverridingModule( new AbstractDvrpModeModule("drt"){ - @Override public void install(){ - DrtConfigGroup drtCfg = ConfigUtils.addOrGetModule( this.getConfig(), DrtConfigGroup.class ); - - this.addRoutingModuleBinding( "drt" ).toProvider( new DrtEstimatingRoutingModuleProvider( "drt" ) ); - - modalMapBinder(DvrpRoutingModuleProvider.Stage.class, RoutingModule.class).addBinding( - DvrpRoutingModuleProvider.Stage.MAIN) - .toProvider(new DvrpModeRoutingModule.DefaultMainLegRouterProvider(getMode()) );// not singleton - // this seems to bind an enum. maybe more heavyweight than necessary? - - bindModal( DefaultMainLegRouter.RouteCreator.class ).toProvider( - new DrtRouteCreatorProvider(drtCfg) );// not singleton - // this is used in DvrpModeRoutingModule (recruited by the DvrpRoutingModuleProvider above) - - bindModal( DrtStopNetwork.class ).toProvider(new DrtStopNetworkProvider(getConfig(), drtCfg) ).asEagerSingleton(); - // yyyy possibly not used for door2door; try to move inside the corresponding switch statement below. kai, feb'24 - - switch( drtCfg.operationalScheme ){ - case door2door -> bindModal( DvrpRoutingModule.AccessEgressFacilityFinder.class ).toProvider( - modalProvider( getter -> new DecideOnLinkAccessEgressFacilityFinder( getter.getModal( Network.class ) ) ) ) - .asEagerSingleton(); - case stopbased, serviceAreaBased -> { - bindModal( DvrpRoutingModule.AccessEgressFacilityFinder.class ).toProvider( modalProvider( - getter -> new ClosestAccessEgressFacilityFinder( drtCfg.maxWalkDistance, - getter.get( Network.class ), - QuadTrees.createQuadTree( getter.getModal( DrtStopNetwork.class ).getDrtStops().values() ) ) ) ) - .asEagerSingleton(); - } - default -> throw new IllegalStateException( "Unexpected value: " + drtCfg.operationalScheme ); - } - - } - } ); - - controler.run(); - - } - - private static class DrtEstimatingRoutingModule implements RoutingModule { - private static final Logger logger = LogManager.getLogger( DrtEstimatingRoutingModule.class ); - - public interface AccessEgressFacilityFinder { - Optional> findFacilities( Facility fromFacility, Facility toFacility, - Attributes tripAttributes ); - } - - private final AccessEgressFacilityFinder stopFinder; - private final String mode; - private final RoutingModule mainRouter; - private final RoutingModule accessRouter; - private final RoutingModule egressRouter; - private final TimeInterpretation timeInterpretation; - - public DrtEstimatingRoutingModule( RoutingModule mainRouter, RoutingModule accessRouter, RoutingModule egressRouter, - AccessEgressFacilityFinder stopFinder, String mode, TimeInterpretation timeInterpretation ) { - this.mainRouter = mainRouter; - this.stopFinder = stopFinder; - this.mode = mode; - this.accessRouter = accessRouter; - this.egressRouter = egressRouter; - this.timeInterpretation = timeInterpretation; - } - - @Override - public List calcRoute(RoutingRequest request) { - final Facility fromFacility = request.getFromFacility(); - final Facility toFacility = request.getToFacility(); - final double departureTime = request.getDepartureTime(); - final Person person = request.getPerson(); - - Optional> stops = stopFinder.findFacilities( - Objects.requireNonNull(fromFacility, "fromFacility is null" ), - Objects.requireNonNull(toFacility, "toFacility is null"), request.getAttributes()); - if (stops.isEmpty()) { - logger.debug("No access/egress stops found, agent will use fallback mode as leg mode (usually " - + TransportMode.walk - + ") and routing mode " - + mode - + ". Agent Id:\t" - + person.getId()); - return null; - } - - Facility accessFacility = stops.get().getLeft(); - Facility egressFacility = stops.get().getRight(); - if (accessFacility.getLinkId().equals(egressFacility.getLinkId())) { - logger.debug("Start and end stop are the same, agent will use fallback mode as leg mode (usually " - + TransportMode.walk - + ") and routing mode " - + mode - + ". Agent Id:\t" - + person.getId()); - return null; - } - - List trip = new ArrayList<>(); - - double now = departureTime; - - // access (sub-)trip: - List accessTrip = accessRouter.calcRoute( - DefaultRoutingRequest.of(fromFacility, accessFacility, now, person, request.getAttributes() ) ); - if (!accessTrip.isEmpty()) { - trip.addAll(accessTrip); - now = timeInterpretation.decideOnElementsEndTime(accessTrip, now).seconds(); - - // interaction activity: - trip.add(createDrtStageActivity(accessFacility, now)); - } - - // dvrp proper leg: - List drtLeg = mainRouter.calcRoute( - DefaultRoutingRequest.of(accessFacility, egressFacility, now, person, request.getAttributes())); - trip.addAll(drtLeg); - now = timeInterpretation.decideOnElementsEndTime(drtLeg, now).seconds(); - - // egress (sub-)trip: - List egressTrip = egressRouter.calcRoute( - DefaultRoutingRequest.of(egressFacility, toFacility, now, person, request.getAttributes())); - if (!egressTrip.isEmpty()) { - // interaction activity: - trip.add(createDrtStageActivity(egressFacility, now)); - - trip.addAll(egressTrip); - } - - return trip; - } - - private Activity createDrtStageActivity( Facility stopFacility, double now ) { - return PopulationUtils.createStageActivityFromCoordLinkIdAndModePrefix(stopFacility.getCoord(), - stopFacility.getLinkId(), mode ); - } - } - - private static class DrtEstimatingRoutingModuleProvider extends ModalProviders.AbstractProvider { - public enum Stage {ACCESS, MAIN, EGRESS} - - @Inject - @Named(TransportMode.walk) - private RoutingModule walkRouter; - - @Inject private TimeInterpretation timeInterpretation; - - @Inject private TripRouter tripRouter; - - public DrtEstimatingRoutingModuleProvider(String mode) { - super(mode, DvrpModes::mode ); - } - - @Override - public DrtEstimatingRoutingModule get() { - - RoutingModule drtRoutingModule = tripRouter.getRoutingModule( "drt" ); -// drtRoutingModule.c - - Map stageRouters = getModalInstance( new TypeLiteral>() { - } ); - RoutingModule mainRouter = Objects.requireNonNull(stageRouters.get( DvrpRoutingModuleProvider.Stage.MAIN ), - "Main mode router must be explicitly bound"); - RoutingModule accessRouter = stageRouters.getOrDefault( DvrpRoutingModuleProvider.Stage.ACCESS, walkRouter ); - RoutingModule egressRouter = stageRouters.getOrDefault( DvrpRoutingModuleProvider.Stage.EGRESS, walkRouter ); - - return new DrtEstimatingRoutingModule(mainRouter, accessRouter, egressRouter, - getModalInstance( DrtEstimatingRoutingModule.AccessEgressFacilityFinder.class ), getMode(), timeInterpretation); - } - - } - - private static class DrtRouteCreatorProvider extends ModalProviders.AbstractProvider { - private final LeastCostPathCalculatorFactory leastCostPathCalculatorFactory; - - private final DrtConfigGroup drtCfg; - - private DrtRouteCreatorProvider(DrtConfigGroup drtCfg) { - super(drtCfg.getMode(), DvrpModes::mode); - this.drtCfg = drtCfg; - leastCostPathCalculatorFactory = new SpeedyALTFactory(); - } - - @Override - public DrtRouteCreator get() { - var travelTime = getModalInstance( TravelTime.class ); - return new DrtRouteCreator(drtCfg, getModalInstance(Network.class), leastCostPathCalculatorFactory, - travelTime, getModalInstance( TravelDisutilityFactory.class )); - } - } - - private static class DrtStopNetworkProvider extends ModalProviders.AbstractProvider { - - private final DrtConfigGroup drtCfg; - private final Config config; - - private DrtStopNetworkProvider(Config config, DrtConfigGroup drtCfg) { - super(drtCfg.getMode(), DvrpModes::mode); - this.drtCfg = drtCfg; - this.config = config; - } - - @Override - public DrtStopNetwork get() { - switch (drtCfg.operationalScheme) { - case door2door: - return ImmutableMap::of; - case stopbased: - return createDrtStopNetworkFromTransitSchedule(config, drtCfg); - case serviceAreaBased: - return createDrtStopNetworkFromServiceArea(config, drtCfg, getModalInstance(Network.class)); - default: - throw new RuntimeException("Unsupported operational scheme: " + drtCfg.operationalScheme); - } - } - } - - private static DrtStopNetwork createDrtStopNetworkFromServiceArea(Config config, DrtConfigGroup drtCfg, - Network drtNetwork) { - final List preparedGeometries = ShpGeometryUtils.loadPreparedGeometries( - ConfigGroup.getInputFileURL(config.getContext(), drtCfg.drtServiceAreaShapeFile ) ); - ImmutableMap, DrtStopFacility> drtStops = drtNetwork.getLinks() - .values() - .stream() - .filter(link -> ShpGeometryUtils.isCoordInPreparedGeometries(link.getToNode().getCoord(), - preparedGeometries)) - .map( DrtStopFacilityImpl::createFromLink ) - .collect(ImmutableMap.toImmutableMap(DrtStopFacility::getId, f -> f)); - return () -> drtStops; - } - - private static DrtStopNetwork createDrtStopNetworkFromTransitSchedule(Config config, DrtConfigGroup drtCfg) { - URL url = ConfigGroup.getInputFileURL(config.getContext(), drtCfg.transitStopFile); - Scenario scenario = ScenarioUtils.createScenario(ConfigUtils.createConfig()); - new TransitScheduleReader(scenario).readURL(url ); - ImmutableMap, DrtStopFacility> drtStops = scenario.getTransitSchedule() - .getFacilities() - .values() - .stream() - .map(DrtStopFacilityImpl::createFromFacility) - .collect(ImmutableMap.toImmutableMap(DrtStopFacility::getId, f -> f)); - return () -> drtStops; - } - - -} diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimateAnalyzer.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimateAnalyzer.java index 0a249b9eace..f0ff2c8b5d0 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimateAnalyzer.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimateAnalyzer.java @@ -114,7 +114,7 @@ private Iterable calcMetrics(int iteration) { 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)); + travelTime.addValue(Math.abs(estimate.rideTime() - valTravelTime)); fare.addValue(Math.abs(estimate.fare() - valFare)); } } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimator.java index c7b2e9e3d76..b54841d987f 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimator.java @@ -1,8 +1,10 @@ package org.matsim.contrib.drt.estimator; +import org.matsim.api.core.v01.population.Leg; import org.matsim.contrib.drt.routing.DrtRoute; import org.matsim.core.controler.listener.ControlerListener; import org.matsim.core.utils.misc.OptionalTime; +import org.matsim.utils.objectattributes.attributable.Attributable; /** * Interface to estimate a DRT service's detour, waiting time and costs. @@ -22,14 +24,25 @@ public interface DrtEstimator extends ControlerListener { /** * Estimate for various attributes for a drt trip. * - * @param distance travel distance in meter - * @param travelTime travel time in seconds - * @param waitingTime waiting time in seconds - * @param fare money, which is negative if the customer needs to pay it + * @param rideDistance travel distance in meter + * @param rideTime ride time in seconds + * @param waitingTime waiting time in seconds + * @param fare money, which is negative if the customer needs to pay it * @param rejectionRate probability of a trip being rejected */ - record Estimate(double distance, double travelTime, double waitingTime, double fare, double rejectionRate) { + record Estimate(double rideDistance, double rideTime, double waitingTime, double fare, double rejectionRate) { } + /** + * Write estimate information into the leg attributes. + */ + static void setEstimateAttributes(Leg leg, Estimate estimate) { + leg.getAttributes().putAttribute("ride_time", estimate.rideTime()); + leg.getAttributes().putAttribute("ride_distance", estimate.rideDistance()); + leg.getAttributes().putAttribute("wait_time", estimate.waitingTime()); + // TODO: fare might not be needed + leg.getAttributes().putAttribute("fare", estimate.fare()); + } + } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimatorModule.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimatorModule.java index ad017796ace..4406c1d5321 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimatorModule.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimatorModule.java @@ -39,10 +39,6 @@ public static Object bindEstimator(Binder binder, String mode){ @Override public void install() { - // TODO decide how initial estimators are defined - bindModal(DrtInitialEstimator.class).toInstance(new PessimisticDrtEstimator(drtCfg)); - bindModal(DrtEstimator.class).toInstance(new PessimisticDrtEstimator(drtCfg)); - // DRT Estimators will be available as Map MapBinder.newMapBinder(this.binder(), DvrpMode.class, DrtEstimator.class) .addBinding(DvrpModes.mode(getMode())) diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimatorParams.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimatorParams.java index 4a892e1a0e4..9f43dd158c5 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimatorParams.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimatorParams.java @@ -1,8 +1,5 @@ package org.matsim.contrib.drt.estimator; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Positive; -import jakarta.validation.constraints.PositiveOrZero; import org.matsim.core.config.ReflectiveConfigGroup; public class DrtEstimatorParams extends ReflectiveConfigGroup { @@ -13,16 +10,29 @@ public DrtEstimatorParams() { super(SET_NAME); } - - @Parameter - @Comment("Decay of the exponential moving average.") - @Positive +// @Parameter +// @Comment("Decay of the exponential moving average.") +// @Positive public double decayFactor = 0.7; - @Parameter - @Comment("Factor multiplied with standard deviation to randomize estimates.") - @PositiveOrZero +// @Parameter +// @Comment("Factor multiplied with standard deviation to randomize estimates.") +// @PositiveOrZero public double randomization = 0.1; + public double getDecayFactor() { + return decayFactor; + } + + public void setDecayFactor(double decayFactor) { + this.decayFactor = decayFactor; + } + public double getRandomization() { + return randomization; + } + + public void setRandomization(double randomization) { + this.randomization = randomization; + } } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtInitialEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtInitialEstimator.java deleted file mode 100644 index 395ef79ff75..00000000000 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtInitialEstimator.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.matsim.contrib.drt.estimator; - -/** - * This interface is used to provide an initial estimate for the drt service. - * Supposed to be used when no data is available from the simulation yet. - * The interface is exactly the same as {@link DrtEstimator}, but this class won't be called with update events. - */ -public interface DrtInitialEstimator extends DrtEstimator { -} diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtOnlineEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtOnlineEstimator.java new file mode 100644 index 00000000000..4364cde359e --- /dev/null +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtOnlineEstimator.java @@ -0,0 +1,7 @@ +package org.matsim.contrib.drt.estimator; + +/** + * Interface to mark an estimator that will update its estimates during simulation. + */ +public interface DrtOnlineEstimator extends DrtEstimator { +} diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/EstimationRoutingModule.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/EstimationRoutingModule.java index 602c3cdd3e2..3bfa4ce5152 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/EstimationRoutingModule.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/EstimationRoutingModule.java @@ -11,7 +11,7 @@ /** * Delegates routing to the original dvrp router and adds estimations to the leg. - * */ + */ public class EstimationRoutingModule implements RoutingModule { private final DvrpRoutingModule delegate; private final DrtEstimator estimator; @@ -26,14 +26,14 @@ public List calcRoute(RoutingRequest request) { List route = delegate.calcRoute(request); - Leg mainDrtLeg = (Leg) route.get(2); - DrtRoute drtRoute = (DrtRoute) mainDrtLeg.getRoute(); - DrtEstimator.Estimate estimate = estimator.estimate(drtRoute, mainDrtLeg.getDepartureTime()); - - mainDrtLeg.getAttributes().putAttribute("travel_time", estimate.travelTime()); - mainDrtLeg.getAttributes().putAttribute("travel_distance", estimate.distance()); - mainDrtLeg.getAttributes().putAttribute("wait_time", estimate.waitingTime()); - + for (PlanElement el : route) { + if (el instanceof Leg leg) { + if (leg.getRoute() instanceof DrtRoute drtRoute) { + DrtEstimator.Estimate estimate = estimator.estimate(drtRoute, leg.getDepartureTime()); + DrtEstimator.setEstimateAttributes(leg, estimate); + } + } + } return route; } } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/BasicDrtEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/BasicDrtEstimator.java index cf8cb5416cd..f5e64306201 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/BasicDrtEstimator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/BasicDrtEstimator.java @@ -10,8 +10,8 @@ import org.matsim.api.core.v01.population.Person; import org.matsim.contrib.drt.analysis.DrtEventSequenceCollector; import org.matsim.contrib.drt.estimator.DrtEstimator; -import org.matsim.contrib.drt.estimator.DrtInitialEstimator; import org.matsim.contrib.drt.estimator.DrtEstimatorParams; +import org.matsim.contrib.drt.estimator.DrtOnlineEstimator; import org.matsim.contrib.drt.routing.DrtRoute; import org.matsim.contrib.drt.run.DrtConfigGroup; import org.matsim.contrib.drt.speedup.DrtSpeedUp; @@ -26,14 +26,14 @@ * 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 { +public class BasicDrtEstimator implements DrtOnlineEstimator, IterationEndsListener { private static final Logger log = LogManager.getLogger(BasicDrtEstimator.class); private final DrtEventSequenceCollector collector; private final DrtEstimatorParams config; private final DrtConfigGroup drtConfig; - private final DrtInitialEstimator initial; + private final DrtEstimator initial; private final SplittableRandom rnd = new SplittableRandom(); /** @@ -42,7 +42,7 @@ public class BasicDrtEstimator implements DrtEstimator, IterationEndsListener { private GlobalEstimate currentEst; private RegressionResults fare; - public BasicDrtEstimator(DrtEventSequenceCollector collector, DrtInitialEstimator initial, + public BasicDrtEstimator(DrtEventSequenceCollector collector, DrtEstimator initial, DrtEstimatorParams config, DrtConfigGroup drtConfig) { //zones = injector.getModal(DrtZonalSystem.class); this.collector = collector; diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/ConstantDrtEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/ConstantDrtEstimator.java index 02363c67ea1..2587bf7723f 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/ConstantDrtEstimator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/ConstantDrtEstimator.java @@ -1,6 +1,6 @@ package org.matsim.contrib.drt.estimator.impl; -import org.matsim.contrib.drt.estimator.DrtInitialEstimator; +import org.matsim.contrib.drt.estimator.DrtEstimator; import org.matsim.contrib.drt.fare.DrtFareParams; import org.matsim.contrib.drt.routing.DrtRoute; import org.matsim.contrib.drt.run.DrtConfigGroup; @@ -9,7 +9,7 @@ /** * Estimates using a constant detour factor and waiting time. */ -public class ConstantDrtEstimator implements DrtInitialEstimator { +public class ConstantDrtEstimator implements DrtEstimator { private final DrtConfigGroup drtConfig; diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/PessimisticDrtEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/PessimisticDrtEstimator.java index c9cee293ceb..150b8674b71 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/PessimisticDrtEstimator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/PessimisticDrtEstimator.java @@ -1,6 +1,6 @@ package org.matsim.contrib.drt.estimator.impl; -import org.matsim.contrib.drt.estimator.DrtInitialEstimator; +import org.matsim.contrib.drt.estimator.DrtEstimator; import org.matsim.contrib.drt.fare.DrtFareParams; import org.matsim.contrib.drt.routing.DrtRoute; import org.matsim.contrib.drt.run.DrtConfigGroup; @@ -9,7 +9,7 @@ /** * Uses the upper bounds from config for the initial estimate. */ -public class PessimisticDrtEstimator implements DrtInitialEstimator { +public class PessimisticDrtEstimator implements DrtEstimator { private final DrtConfigGroup drtConfig; public PessimisticDrtEstimator(DrtConfigGroup drtConfig) { diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/RealisticDrtEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/RealisticDrtEstimator.java index b9ff529d3e1..e5ba30e3a2f 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/RealisticDrtEstimator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/RealisticDrtEstimator.java @@ -1,12 +1,12 @@ package org.matsim.contrib.drt.estimator.impl; -import org.matsim.contrib.drt.estimator.DrtInitialEstimator; +import org.matsim.contrib.drt.estimator.DrtEstimator; import org.matsim.contrib.drt.routing.DrtRoute; import org.matsim.core.utils.misc.OptionalTime; import java.util.Random; -public class RealisticDrtEstimator implements DrtInitialEstimator { +public class RealisticDrtEstimator implements DrtEstimator { private final DistributionGenerator distributionGenerator; diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtConfigGroup.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtConfigGroup.java index 52a8f6febd7..9d133a32603 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtConfigGroup.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtConfigGroup.java @@ -220,7 +220,7 @@ public enum OperationalScheme { public enum SimulationType { - fullSimulation, estimateAndTeleport + fullSimulation, drtSpeedup, estimateAndTeleport } @Parameter @@ -246,7 +246,7 @@ public enum SimulationType { private PrebookingParams prebookingParams; @Nullable - private DrtEstimatorParams drtEstimatorParams; + private DrtEstimatorParams drtEstimatorParams = new DrtEstimatorParams(); @Nullable private DrtRequestInsertionRetryParams drtRequestInsertionRetryParams; @@ -344,8 +344,7 @@ protected void checkConsistency(Config config) { DvrpModeRoutingNetworkModule.checkUseModeFilteredSubnetworkAllowed(config, mode); } - - // TODO if we teleport we need to check if estimates are present + // TODO: check for new speed up params } @Override diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeModule.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeModule.java index 9479c43be56..e5a828836f0 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeModule.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeModule.java @@ -108,7 +108,7 @@ public void install() { install(new AdaptiveTravelTimeMatrixModule(drtCfg.mode)); - if (drtCfg.getDrtEstimatorParams().isPresent()) { + if (drtCfg.simulationType == DrtConfigGroup.SimulationType.estimateAndTeleport ) { install(new DrtEstimatorModule(getMode(), drtCfg, drtCfg.getDrtEstimatorParams().get())); } diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/TeleportingEstimationPassengerEngine.java b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/TeleportingEstimationPassengerEngine.java index 140a7248e1a..4209ab356ad 100644 --- a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/TeleportingEstimationPassengerEngine.java +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/TeleportingEstimationPassengerEngine.java @@ -22,6 +22,7 @@ import com.google.common.base.Preconditions; import com.google.common.base.Verify; +import it.unimi.dsi.fastutil.doubles.DoubleObjectPair; import jakarta.inject.Inject; import jakarta.inject.Provider; import org.apache.commons.lang3.tuple.ImmutablePair; @@ -42,6 +43,7 @@ import org.matsim.core.mobsim.qsim.TeleportationEngine; import org.matsim.core.mobsim.qsim.agents.WithinDayAgentUtils; import org.matsim.core.modal.ModalProviders; +import org.matsim.utils.objectattributes.attributable.Attributable; import org.matsim.vis.snapshotwriters.AgentSnapshotInfo; import org.matsim.vis.snapshotwriters.VisData; @@ -63,8 +65,18 @@ public class TeleportingEstimationPassengerEngine implements PassengerEngine, Vi private final InternalPassengerHandling internalPassengerHandling; private final TeleportationEngine teleportationEngine; - private final Queue> teleportedRequests = new PriorityQueue<>( - Comparator.comparingDouble(Pair::getLeft)); + + /** + * Request currently waiting for pickup. + */ + private final Queue> waitingRequests = new PriorityQueue<>( + Comparator.comparingDouble(DoubleObjectPair::keyDouble)); + + /** + * Request currently onboard a vehicle and waiting for drop-off. + */ + private final Queue> ridingRequests = new PriorityQueue<>( + Comparator.comparingDouble(DoubleObjectPair::keyDouble)); private InternalInterface internalInterface; @@ -103,12 +115,21 @@ public void onPrepareSim() { @Override public void doSimStep(double time) { + + // process waiting passengers + while (!waitingRequests.isEmpty() && waitingRequests.peek().keyDouble() <= time) { + PassengerRequest request = waitingRequests.poll().value(); + for (Id passenger : request.getPassengerIds()) { + //TODO: check whether to use first passenger Id + eventsManager.processEvent(new PassengerPickedUpEvent(time, mode, request.getId(), request.getPassengerIds().get(0), null)); + } + } + //first process passenger dropoff events - while (!teleportedRequests.isEmpty() && teleportedRequests.peek().getLeft() <= time) { - PassengerRequest request = teleportedRequests.poll().getRight(); + while (!ridingRequests.isEmpty() && ridingRequests.peek().keyDouble() <= time) { + PassengerRequest request = ridingRequests.poll().value(); for (Id passenger : request.getPassengerIds()) { - eventsManager.processEvent( - new PassengerDroppedOffEvent(time, mode, request.getId(), passenger, null)); + eventsManager.processEvent(new PassengerDroppedOffEvent(time, mode, request.getId(), passenger, null)); } } @@ -137,11 +158,23 @@ public boolean handleDeparture(double now, MobsimAgent agent, Id fromLinkI eventsManager.processEvent(new PassengerWaitingEvent(now, mode, request.getId(), request.getPassengerIds())); if (internalPassengerHandling.validateRequest(request, requestValidator, now)) { - adaptLegRouteForTeleportation(List.of(passenger), leg, request, now); - eventsManager.processEvent(new PassengerPickedUpEvent(now, mode, request.getId(), passenger.getId(), null)); + double waitTime = getEstimatedWaitTime(leg); + double travelTime = waitTime + getEstimatedRideTime(leg); + + // Set information in the route for the teleportation engine + leg.setTravelTime(travelTime); + route.setTravelTime(travelTime); + route.setDistance(getEstimatedRideDistance(leg)); + + eventsManager.processEvent(new PassengerRequestScheduledEvent(mobsimTimer.getTimeOfDay(), mode, request.getId(), + request.getPassengerIds(), null, now, now + travelTime)); + teleportationEngine.handleDeparture(now, passenger, fromLinkId); - teleportedRequests.add(ImmutablePair.of(now + route.getTravelTime().seconds(), request)); + + waitingRequests.add(DoubleObjectPair.of(now + waitTime, request)); + ridingRequests.add(DoubleObjectPair.of(now + travelTime, request)); + } else { //not much else can be done for immediate requests //set the passenger agent to abort - the event will be thrown by the QSim @@ -152,16 +185,6 @@ public boolean handleDeparture(double now, MobsimAgent agent, Id fromLinkI return true; } - private void adaptLegRouteForTeleportation(List passengers, Leg leg, PassengerRequest request, double now) { - Route route = leg.getRoute(); - - // TODO retrieve information from the leg - - eventsManager.processEvent(new PassengerRequestScheduledEvent(mobsimTimer.getTimeOfDay(), mode, request.getId(), - request.getPassengerIds(), null, now, now + route.getTravelTime().seconds())); - - } - private Link getLink(Id linkId) { return Preconditions.checkNotNull(network.getLinks().get(linkId), "Link id=%s does not exist in network for mode %s. Agent departs from a link that does not belong to that network?", @@ -210,4 +233,22 @@ public TeleportingEstimationPassengerEngine get() { } }; } + + static double getEstimatedRideTime(Attributable element) { + return (double) element.getAttributes().getAttribute("ride_time"); + } + + static double getEstimatedRideDistance(Attributable element){ + return (double) element.getAttributes().getAttribute("ride_distance"); + } + + static double getEstimatedWaitTime(Attributable element){ + return (double) element.getAttributes().getAttribute("wait_time"); + } + + static double getEstimatedFare(Attributable element){ + return (double) element.getAttributes().getAttribute("fare"); + } + + } From 0bd74b0336b7feeb8399ff9143eab86043d371ca Mon Sep 17 00:00:00 2001 From: Chengqi Lu <43133404+luchengqi7@users.noreply.github.com> Date: Tue, 5 Mar 2024 17:46:08 +0100 Subject: [PATCH 09/19] Work in progress --- .../modechoice/MultiModalDrtLegEstimator.java | 5 +- .../teleportation/DrtTeleportationTest.java | 53 +++++++---- .../DrtTeleportationWithModeChoiceTest.java | 88 +++++++++++++++++++ .../drt/estimator/DrtEstimateAnalyzer.java | 3 +- .../contrib/drt/estimator/DrtEstimator.java | 12 ++- .../drt/estimator/impl/BasicDrtEstimator.java | 13 +-- .../estimator/impl/ConstantDrtEstimator.java | 15 +--- .../impl/PessimisticDrtEstimator.java | 2 +- .../estimator/impl/RealisticDrtEstimator.java | 2 +- .../drt/routing/DefaultDrtRouteUpdater.java | 18 +++- .../contrib/drt/run/DrtModeRoutingModule.java | 5 +- .../TeleportingEstimationPassengerEngine.java | 11 +-- 12 files changed, 160 insertions(+), 67 deletions(-) create mode 100644 contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationWithModeChoiceTest.java diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/modechoice/MultiModalDrtLegEstimator.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/modechoice/MultiModalDrtLegEstimator.java index 4d3980d5d24..b87211638ee 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/modechoice/MultiModalDrtLegEstimator.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/modechoice/MultiModalDrtLegEstimator.java @@ -52,8 +52,9 @@ public double estimate(EstimatorContext context, String mode, Leg leg, ModeAvail params.marginalUtilityOfDistance_m * est.rideDistance() + params.marginalUtilityOfTraveling_s * est.rideTime() + params.marginalUtilityOfTraveling_s * est.waitingTime() + - context.scoring.marginalUtilityOfMoney * params.monetaryDistanceCostRate * est.rideDistance() + - context.scoring.marginalUtilityOfMoney * est.fare(); + context.scoring.marginalUtilityOfMoney * params.monetaryDistanceCostRate * est.rideDistance(); + // TODO: add a new fare estimator? +// context.scoring.marginalUtilityOfMoney * est.fare(); } } diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationTest.java b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationTest.java index 7fafa3637ca..2a55df3ed10 100644 --- a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationTest.java +++ b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationTest.java @@ -3,8 +3,8 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import org.matsim.contrib.drt.estimator.DrtEstimator; -import org.matsim.contrib.drt.estimator.DrtEstimatorParams; import org.matsim.contrib.drt.estimator.impl.PessimisticDrtEstimator; +import org.matsim.contrib.drt.estimator.impl.RealisticDrtEstimator; import org.matsim.contrib.drt.fare.DrtFareParams; import org.matsim.contrib.drt.run.DrtConfigGroup; import org.matsim.contrib.drt.run.DrtControlerCreator; @@ -13,7 +13,9 @@ import org.matsim.contrib.dvrp.run.DvrpConfigGroup; import org.matsim.core.config.Config; import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.ReplanningConfigGroup; import org.matsim.core.controler.Controler; +import org.matsim.core.replanning.strategies.DefaultPlanStrategiesModule; import org.matsim.core.utils.io.IOUtils; import org.matsim.examples.ExamplesUtils; import org.matsim.testcases.MatsimTestUtils; @@ -38,12 +40,11 @@ void testPessimisticEstimator() { // install the drt routing stuff, but not the mobsim stuff! Controler controler = DrtControlerCreator.createControler(config, false); DrtConfigGroup drtConfigGroup = DrtConfigGroup.getSingleModeDrtConfig(config); - drtConfigGroup.maxTravelTimeAlpha = 1.1; + drtConfigGroup.maxTravelTimeAlpha = 1.2; + drtConfigGroup.maxTravelTimeBeta = 600; + drtConfigGroup.maxWaitTime = 300; drtConfigGroup.simulationType = DrtConfigGroup.SimulationType.estimateAndTeleport; -// DrtEstimatorParams params = new DrtEstimatorParams(); -// drtConfigGroup.addParameterSet(params); - DrtFareParams fareParams = new DrtFareParams(); fareParams.baseFare = 1.0; fareParams.distanceFare_m = 0.001; @@ -56,23 +57,41 @@ public void install() { } }); - System.out.println(config); + controler.run(); + } - // TODO - // We want to use DRT infrastructure (routing) so we need to integrate into drt teleportation - // Write our own TeleportingPassengerEngine - // this engine can either calc estimates beforehand or during departure (using information of drt router) + @Test + void testRealisticEstimator() { + URL url = IOUtils.extendUrl(ExamplesUtils.getTestScenarioURL("mielec"), "mielec_drt_config.xml"); + Config config = ConfigUtils.loadConfig(url, new MultiModeDrtConfigGroup(), new DvrpConfigGroup(), new OTFVisConfigGroup()); + config.network().setInputFile("network.xml"); + config.plans().setInputFile("plans_only_drt_1.0.xml.gz"); + config.controller().setOutputDirectory(utils.getOutputDirectory()); + config.controller().setLastIteration(3); + // install the drt routing stuff, but not the mobsim stuff! + Controler controler = DrtControlerCreator.createControler(config, false); + DrtConfigGroup drtConfigGroup = DrtConfigGroup.getSingleModeDrtConfig(config); + drtConfigGroup.maxTravelTimeAlpha = 1.2; + drtConfigGroup.maxTravelTimeBeta = 600; + drtConfigGroup.maxWaitTime = 300; + drtConfigGroup.simulationType = DrtConfigGroup.SimulationType.estimateAndTeleport; - // alternative: implement our own router - // do nothing drt specific -> calculate travel time information during routing - // can use standard teleportation engines given route information - // we need to update routes ourself, we have no drt access egress, no waiting times, no drt output or requests - // this would be more general, could be useful for other use cases? - // but we only need it for DRT for now? + DrtFareParams fareParams = new DrtFareParams(); + fareParams.baseFare = 1.0; + fareParams.distanceFare_m = 0.001; + drtConfigGroup.addParameterSet(fareParams); - controler.run(); + controler.addOverridingModule(new AbstractDvrpModeModule(drtConfigGroup.mode) { + @Override + public void install() { + bindModal(DrtEstimator.class).toInstance(new RealisticDrtEstimator( + new RealisticDrtEstimator.DistributionGenerator(1.2, 150, 0.1, 180, 0.2))); + } + }); + System.out.println(config); + controler.run(); } } diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationWithModeChoiceTest.java b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationWithModeChoiceTest.java new file mode 100644 index 00000000000..1cfd8b3b501 --- /dev/null +++ b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationWithModeChoiceTest.java @@ -0,0 +1,88 @@ +package org.matsim.contrib.drt.teleportation; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.contrib.drt.estimator.DrtEstimator; +import org.matsim.contrib.drt.estimator.impl.PessimisticDrtEstimator; +import org.matsim.contrib.drt.estimator.impl.RealisticDrtEstimator; +import org.matsim.contrib.drt.fare.DrtFareParams; +import org.matsim.contrib.drt.run.DrtConfigGroup; +import org.matsim.contrib.drt.run.DrtControlerCreator; +import org.matsim.contrib.drt.run.MultiModeDrtConfigGroup; +import org.matsim.contrib.dvrp.run.AbstractDvrpModeModule; +import org.matsim.contrib.dvrp.run.DvrpConfigGroup; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.ReplanningConfigGroup; +import org.matsim.core.config.groups.ScoringConfigGroup; +import org.matsim.core.controler.Controler; +import org.matsim.core.replanning.strategies.DefaultPlanStrategiesModule; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.testcases.MatsimTestUtils; +import org.matsim.vis.otfvis.OTFVisConfigGroup; + +import java.net.URL; + +public class DrtTeleportationWithModeChoiceTest { + + @RegisterExtension + public MatsimTestUtils utils = new MatsimTestUtils(); + + @Test + void testModeChoice() { + URL url = IOUtils.extendUrl(ExamplesUtils.getTestScenarioURL("mielec"), "mielec_drt_config.xml"); + Config config = ConfigUtils.loadConfig(url, new MultiModeDrtConfigGroup(), new DvrpConfigGroup(), new OTFVisConfigGroup()); + config.network().setInputFile("network.xml"); + config.plans().setInputFile("plans_only_drt_4.0.xml.gz"); + config.controller().setOutputDirectory(utils.getOutputDirectory()); + config.controller().setLastIteration(100); + + config.replanning().setFractionOfIterationsToDisableInnovation(0.8); + config.replanning().setMaxAgentPlanMemorySize(3); + config.replanning().clearStrategySettings(); + + ReplanningConfigGroup.StrategySettings changeSingleTripMode = new ReplanningConfigGroup.StrategySettings(); + changeSingleTripMode.setStrategyName(DefaultPlanStrategiesModule.DefaultStrategy.ChangeSingleTripMode); + changeSingleTripMode.setWeight(0.1); + config.replanning().addStrategySettings(changeSingleTripMode); + + ReplanningConfigGroup.StrategySettings changeExpBeta = new ReplanningConfigGroup.StrategySettings(); + changeExpBeta.setStrategyName(DefaultPlanStrategiesModule.DefaultSelector.ChangeExpBeta); + changeExpBeta.setWeight(0.9); + config.replanning().addStrategySettings(changeExpBeta); + + // Introduce a dummy alternative mode: bike (also teleported) + ScoringConfigGroup.ModeParams bikeModeParams = new ScoringConfigGroup.ModeParams(TransportMode.bike); + bikeModeParams.setConstant(1.); + bikeModeParams.setMarginalUtilityOfTraveling(-6.); + config.scoring().addModeParams(bikeModeParams); + + // Update change mode + config.changeMode().setModes( new String[] { TransportMode.drt, TransportMode.bike }); + + Controler controler = DrtControlerCreator.createControler(config, false); + DrtConfigGroup drtConfigGroup = DrtConfigGroup.getSingleModeDrtConfig(config); + drtConfigGroup.maxTravelTimeAlpha = 1.1; + drtConfigGroup.maxTravelTimeBeta = 200; + drtConfigGroup.maxWaitTime = 180; + drtConfigGroup.simulationType = DrtConfigGroup.SimulationType.estimateAndTeleport; + + controler.addOverridingModule(new AbstractDvrpModeModule(drtConfigGroup.mode) { + @Override + public void install() { + bindModal(DrtEstimator.class).toInstance(new RealisticDrtEstimator( + new RealisticDrtEstimator.DistributionGenerator(1.2, 200, + 0.2, 180, 0.3))); + } + +// public void install() { +// bindModal(DrtEstimator.class).toInstance(new PessimisticDrtEstimator(drtConfigGroup)); +// } + }); + + System.out.println(config); + controler.run(); + } +} diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimateAnalyzer.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimateAnalyzer.java index f0ff2c8b5d0..39880674f8a 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimateAnalyzer.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimateAnalyzer.java @@ -115,7 +115,8 @@ private Iterable calcMetrics(int iteration) { waitTime.addValue(Math.abs(estimate.waitingTime() - valWaitTime)); travelTime.addValue(Math.abs(estimate.rideTime() - valTravelTime)); - fare.addValue(Math.abs(estimate.fare() - valFare)); + // TODO add fare estimator? +// fare.addValue(Math.abs(estimate.fare() - valFare)); } } } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimator.java index b54841d987f..b1c218ed4d2 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimator.java @@ -27,10 +27,10 @@ public interface DrtEstimator extends ControlerListener { * @param rideDistance travel distance in meter * @param rideTime ride time in seconds * @param waitingTime waiting time in seconds - * @param fare money, which is negative if the customer needs to pay it +// * @param fare money, which is negative if the customer needs to pay it * @param rejectionRate probability of a trip being rejected */ - record Estimate(double rideDistance, double rideTime, double waitingTime, double fare, double rejectionRate) { + record Estimate(double rideDistance, double rideTime, double waitingTime, double rejectionRate) { } @@ -38,11 +38,9 @@ record Estimate(double rideDistance, double rideTime, double waitingTime, double * Write estimate information into the leg attributes. */ static void setEstimateAttributes(Leg leg, Estimate estimate) { - leg.getAttributes().putAttribute("ride_time", estimate.rideTime()); - leg.getAttributes().putAttribute("ride_distance", estimate.rideDistance()); - leg.getAttributes().putAttribute("wait_time", estimate.waitingTime()); - // TODO: fare might not be needed - leg.getAttributes().putAttribute("fare", estimate.fare()); + leg.getAttributes().putAttribute("est_ride_time", estimate.rideTime()); + leg.getAttributes().putAttribute("est_ride_distance", estimate.rideDistance()); + leg.getAttributes().putAttribute("est_wait_time", estimate.waitingTime()); } } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/BasicDrtEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/BasicDrtEstimator.java index f5e64306201..f02c4ee59b2 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/BasicDrtEstimator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/BasicDrtEstimator.java @@ -40,7 +40,6 @@ public class BasicDrtEstimator implements DrtOnlineEstimator, IterationEndsListe * Currently valid estimates. */ private GlobalEstimate currentEst; - private RegressionResults fare; public BasicDrtEstimator(DrtEventSequenceCollector collector, DrtEstimator initial, DrtEstimatorParams config, DrtConfigGroup drtConfig) { @@ -92,8 +91,6 @@ public void notifyIterationEnds(IterationEndsEvent event) { if (n <= 3) return; - fare = est.fare.regress(); - double rejectionRate = (double) nRejections / nSubmitted; if (currentEst == null) { @@ -122,18 +119,10 @@ public Estimate estimate(DrtRoute route, OptionalTime departureTime) { return initial.estimate(route, departureTime); } - 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); + return new Estimate(route.getDistance() * detour, route.getDirectRideTime() * detour, waitTime, currentEst.rejectionRate); } /** diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/ConstantDrtEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/ConstantDrtEstimator.java index 2587bf7723f..a51f93be2d8 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/ConstantDrtEstimator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/ConstantDrtEstimator.java @@ -1,7 +1,6 @@ package org.matsim.contrib.drt.estimator.impl; import org.matsim.contrib.drt.estimator.DrtEstimator; -import org.matsim.contrib.drt.fare.DrtFareParams; import org.matsim.contrib.drt.routing.DrtRoute; import org.matsim.contrib.drt.run.DrtConfigGroup; import org.matsim.core.utils.misc.OptionalTime; @@ -31,20 +30,8 @@ public ConstantDrtEstimator(DrtConfigGroup drtConfig, double detourFactor, doubl @Override public Estimate estimate(DrtRoute route, OptionalTime departureTime) { - double distance = route.getDistance() * detourFactor; double travelTime = route.getDirectRideTime() * detourFactor; - - double fare = 0; - if (drtConfig.getDrtFareParams().isPresent()) { - DrtFareParams fareParams = drtConfig.getDrtFareParams().get(); - fare = fareParams.distanceFare_m * distance - + fareParams.timeFare_h * travelTime / 3600.0 - + fareParams.baseFare; - - fare = Math.max(fare, fareParams.minFarePerTrip); - } - - return new Estimate(distance, travelTime, waitingTime, fare, 0); + return new Estimate(distance, travelTime, waitingTime, 0); } } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/PessimisticDrtEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/PessimisticDrtEstimator.java index 150b8674b71..553844f2dc9 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/PessimisticDrtEstimator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/PessimisticDrtEstimator.java @@ -34,7 +34,7 @@ public Estimate estimate(DrtRoute route, OptionalTime departureTime) { } // for distance, also use the max travel time alpha - return new Estimate(route.getDistance() * drtConfig.maxTravelTimeAlpha, travelTime, drtConfig.maxWaitTime, fare, 0); + return new Estimate(route.getDistance() * drtConfig.maxTravelTimeAlpha, travelTime, drtConfig.maxWaitTime, 0); } } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/RealisticDrtEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/RealisticDrtEstimator.java index e5ba30e3a2f..2701999c0ca 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/RealisticDrtEstimator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/RealisticDrtEstimator.java @@ -23,7 +23,7 @@ public Estimate estimate(DrtRoute route, OptionalTime departureTime) { double rideDistance = distributionGenerator.generateRideDistance(rideTime, directRideTIme, directDistance); double acceptanceRate = distributionGenerator.generateAcceptanceRate(); - return new Estimate(rideDistance, waitTime + rideTime, waitTime, 0, acceptanceRate); + return new Estimate(rideDistance, waitTime + rideTime, waitTime, acceptanceRate); } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/routing/DefaultDrtRouteUpdater.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/routing/DefaultDrtRouteUpdater.java index 67bb5753c5f..72aea1a829d 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/routing/DefaultDrtRouteUpdater.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/routing/DefaultDrtRouteUpdater.java @@ -29,6 +29,8 @@ import org.matsim.api.core.v01.population.Leg; import org.matsim.api.core.v01.population.Person; import org.matsim.api.core.v01.population.Population; +import org.matsim.api.core.v01.population.Route; +import org.matsim.contrib.drt.estimator.DrtEstimator; import org.matsim.contrib.drt.run.DrtConfigGroup; import org.matsim.contrib.dvrp.router.DefaultMainLegRouter.RouteCreator; import org.matsim.contrib.util.ExecutorServiceWithResource; @@ -50,13 +52,15 @@ public class DefaultDrtRouteUpdater implements ShutdownListener, DrtRouteUpdater private final DrtConfigGroup drtCfg; private final Network network; private final Population population; + private final DrtEstimator drtEstimator; private final ExecutorServiceWithResource executorService; public DefaultDrtRouteUpdater(DrtConfigGroup drtCfg, Network network, Population population, Config config, - Supplier drtRouteCreatorSupplier) { + Supplier drtRouteCreatorSupplier, DrtEstimator drtEstimator) { this.drtCfg = drtCfg; this.network = network; this.population = population; + this.drtEstimator = drtEstimator; // XXX uses the global.numberOfThreads, not drt.numberOfThreads, as this is executed in the replanning phase executorService = new ExecutorServiceWithResource<>(IntStream.range(0, config.global().getNumberOfThreads()) @@ -86,8 +90,16 @@ private void updateDrtRoute(RouteCreator drtRouteCreator, Person person, Attribu Link fromLink = network.getLinks().get(drtLeg.getRoute().getStartLinkId()); Link toLink = network.getLinks().get(drtLeg.getRoute().getEndLinkId()); RouteFactories routeFactories = population.getFactory().getRouteFactories(); - drtLeg.setRoute(drtRouteCreator.createRoute(drtLeg.getDepartureTime().seconds(), fromLink, toLink, person, - tripAttributes, routeFactories)); + + Route drtRoute = drtRouteCreator.createRoute(drtLeg.getDepartureTime().seconds(), fromLink, toLink, person, + tripAttributes, routeFactories); + drtLeg.setRoute(drtRoute); + + // update DRT estimate + if (drtEstimator != null) { + DrtEstimator.Estimate estimate = drtEstimator.estimate((DrtRoute) drtRoute, drtLeg.getDepartureTime()); + DrtEstimator.setEstimateAttributes(drtLeg, estimate); + } } @Override diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeRoutingModule.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeRoutingModule.java index 8fae5fb3f3f..8d037b171dc 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeRoutingModule.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeRoutingModule.java @@ -28,6 +28,7 @@ import org.matsim.api.core.v01.Scenario; import org.matsim.api.core.v01.network.Network; import org.matsim.api.core.v01.population.Population; +import org.matsim.contrib.drt.estimator.DrtEstimator; import org.matsim.contrib.drt.estimator.EstimationRoutingModuleProvider; import org.matsim.contrib.drt.routing.DefaultDrtRouteUpdater; import org.matsim.contrib.drt.routing.DrtRouteCreator; @@ -124,7 +125,9 @@ public void install() { public DefaultDrtRouteUpdater get() { var network = getModalInstance(Network.class); var routeCreatorProvider = getModalProvider(DefaultMainLegRouter.RouteCreator.class); - return new DefaultDrtRouteUpdater(drtCfg, network, population, config, routeCreatorProvider::get); + DrtEstimator drtEstimator = drtCfg.simulationType == DrtConfigGroup.SimulationType.estimateAndTeleport? + getModalInstance(DrtEstimator.class) : null; + return new DefaultDrtRouteUpdater(drtCfg, network, population, config, routeCreatorProvider::get, drtEstimator); } }).asEagerSingleton(); diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/TeleportingEstimationPassengerEngine.java b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/TeleportingEstimationPassengerEngine.java index 4209ab356ad..52df574a1d8 100644 --- a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/TeleportingEstimationPassengerEngine.java +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/TeleportingEstimationPassengerEngine.java @@ -235,20 +235,15 @@ public TeleportingEstimationPassengerEngine get() { } static double getEstimatedRideTime(Attributable element) { - return (double) element.getAttributes().getAttribute("ride_time"); + return (double) element.getAttributes().getAttribute("est_ride_time"); } static double getEstimatedRideDistance(Attributable element){ - return (double) element.getAttributes().getAttribute("ride_distance"); + return (double) element.getAttributes().getAttribute("est_ride_distance"); } static double getEstimatedWaitTime(Attributable element){ - return (double) element.getAttributes().getAttribute("wait_time"); + return (double) element.getAttributes().getAttribute("est_wait_time"); } - static double getEstimatedFare(Attributable element){ - return (double) element.getAttributes().getAttribute("fare"); - } - - } From d580bff70fe00e19b75aa586d97ce56ac223f827 Mon Sep 17 00:00:00 2001 From: Chengqi Lu <43133404+luchengqi7@users.noreply.github.com> Date: Thu, 7 Mar 2024 11:08:43 +0100 Subject: [PATCH 10/19] Preparation for merging --- .../teleportation/DrtTeleportationTest.java | 17 +++++++------ .../DrtTeleportationWithModeChoiceTest.java | 24 +++++++------------ 2 files changed, 17 insertions(+), 24 deletions(-) diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationTest.java b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationTest.java index 2a55df3ed10..d8cedad2550 100644 --- a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationTest.java +++ b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationTest.java @@ -35,21 +35,20 @@ void testPessimisticEstimator() { config.network().setInputFile("network.xml"); config.plans().setInputFile("plans_only_drt_1.0.xml.gz"); config.controller().setOutputDirectory(utils.getOutputDirectory()); - config.controller().setLastIteration(3); + config.controller().setLastIteration(2); - // install the drt routing stuff, but not the mobsim stuff! Controler controler = DrtControlerCreator.createControler(config, false); DrtConfigGroup drtConfigGroup = DrtConfigGroup.getSingleModeDrtConfig(config); drtConfigGroup.maxTravelTimeAlpha = 1.2; drtConfigGroup.maxTravelTimeBeta = 600; drtConfigGroup.maxWaitTime = 300; - drtConfigGroup.simulationType = DrtConfigGroup.SimulationType.estimateAndTeleport; - DrtFareParams fareParams = new DrtFareParams(); fareParams.baseFare = 1.0; fareParams.distanceFare_m = 0.001; drtConfigGroup.addParameterSet(fareParams); + // Setup to enable estimator and teleportation + drtConfigGroup.simulationType = DrtConfigGroup.SimulationType.estimateAndTeleport; controler.addOverridingModule(new AbstractDvrpModeModule(drtConfigGroup.mode) { @Override public void install() { @@ -57,8 +56,8 @@ public void install() { } }); - System.out.println(config); controler.run(); + // TODO add a check } @Test @@ -68,7 +67,7 @@ void testRealisticEstimator() { config.network().setInputFile("network.xml"); config.plans().setInputFile("plans_only_drt_1.0.xml.gz"); config.controller().setOutputDirectory(utils.getOutputDirectory()); - config.controller().setLastIteration(3); + config.controller().setLastIteration(2); // install the drt routing stuff, but not the mobsim stuff! Controler controler = DrtControlerCreator.createControler(config, false); @@ -76,13 +75,13 @@ void testRealisticEstimator() { drtConfigGroup.maxTravelTimeAlpha = 1.2; drtConfigGroup.maxTravelTimeBeta = 600; drtConfigGroup.maxWaitTime = 300; - drtConfigGroup.simulationType = DrtConfigGroup.SimulationType.estimateAndTeleport; - DrtFareParams fareParams = new DrtFareParams(); fareParams.baseFare = 1.0; fareParams.distanceFare_m = 0.001; drtConfigGroup.addParameterSet(fareParams); + // Setup to enable estimator and teleportation + drtConfigGroup.simulationType = DrtConfigGroup.SimulationType.estimateAndTeleport; controler.addOverridingModule(new AbstractDvrpModeModule(drtConfigGroup.mode) { @Override public void install() { @@ -91,7 +90,7 @@ public void install() { } }); - System.out.println(config); controler.run(); + // TODO add a check } } diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationWithModeChoiceTest.java b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationWithModeChoiceTest.java index 1cfd8b3b501..7dee5b27ce4 100644 --- a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationWithModeChoiceTest.java +++ b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationWithModeChoiceTest.java @@ -4,9 +4,7 @@ import org.junit.jupiter.api.extension.RegisterExtension; import org.matsim.api.core.v01.TransportMode; import org.matsim.contrib.drt.estimator.DrtEstimator; -import org.matsim.contrib.drt.estimator.impl.PessimisticDrtEstimator; import org.matsim.contrib.drt.estimator.impl.RealisticDrtEstimator; -import org.matsim.contrib.drt.fare.DrtFareParams; import org.matsim.contrib.drt.run.DrtConfigGroup; import org.matsim.contrib.drt.run.DrtControlerCreator; import org.matsim.contrib.drt.run.MultiModeDrtConfigGroup; @@ -30,7 +28,7 @@ public class DrtTeleportationWithModeChoiceTest { @RegisterExtension public MatsimTestUtils utils = new MatsimTestUtils(); - @Test +// @Test void testModeChoice() { URL url = IOUtils.extendUrl(ExamplesUtils.getTestScenarioURL("mielec"), "mielec_drt_config.xml"); Config config = ConfigUtils.loadConfig(url, new MultiModeDrtConfigGroup(), new DvrpConfigGroup(), new OTFVisConfigGroup()); @@ -52,34 +50,30 @@ void testModeChoice() { changeExpBeta.setStrategyName(DefaultPlanStrategiesModule.DefaultSelector.ChangeExpBeta); changeExpBeta.setWeight(0.9); config.replanning().addStrategySettings(changeExpBeta); - // Introduce a dummy alternative mode: bike (also teleported) ScoringConfigGroup.ModeParams bikeModeParams = new ScoringConfigGroup.ModeParams(TransportMode.bike); bikeModeParams.setConstant(1.); bikeModeParams.setMarginalUtilityOfTraveling(-6.); config.scoring().addModeParams(bikeModeParams); - // Update change mode config.changeMode().setModes( new String[] { TransportMode.drt, TransportMode.bike }); - Controler controler = DrtControlerCreator.createControler(config, false); + // Setting DRT config group DrtConfigGroup drtConfigGroup = DrtConfigGroup.getSingleModeDrtConfig(config); - drtConfigGroup.maxTravelTimeAlpha = 1.1; - drtConfigGroup.maxTravelTimeBeta = 200; - drtConfigGroup.maxWaitTime = 180; + + // Copy this line to Leipzig run script!!! drtConfigGroup.simulationType = DrtConfigGroup.SimulationType.estimateAndTeleport; + Controler controler = DrtControlerCreator.createControler(config, false); + + // Copy this overriding module to Leipzig run script!!! controler.addOverridingModule(new AbstractDvrpModeModule(drtConfigGroup.mode) { @Override public void install() { bindModal(DrtEstimator.class).toInstance(new RealisticDrtEstimator( - new RealisticDrtEstimator.DistributionGenerator(1.2, 200, - 0.2, 180, 0.3))); + new RealisticDrtEstimator.DistributionGenerator(1.2, 32, + 0.3, 300, 0.4))); } - -// public void install() { -// bindModal(DrtEstimator.class).toInstance(new PessimisticDrtEstimator(drtConfigGroup)); -// } }); System.out.println(config); From 746b0556aafb82cb245e4479d69fda4980eb4663 Mon Sep 17 00:00:00 2001 From: rakow Date: Tue, 12 Mar 2024 10:22:50 +0100 Subject: [PATCH 11/19] revert speed-up changes done during testing --- .../java/org/matsim/contrib/drt/speedup/DrtSpeedUp.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/speedup/DrtSpeedUp.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/speedup/DrtSpeedUp.java index fd5ed666740..5ad8dd776af 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/speedup/DrtSpeedUp.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/speedup/DrtSpeedUp.java @@ -53,7 +53,14 @@ public final class DrtSpeedUp implements IterationStartsListener, IterationEndsL public static boolean isTeleportDrtUsers(DrtSpeedUpParams drtSpeedUpParams, ControllerConfigGroup controlerConfig, int iteration) { - return true; + int lastIteration = controlerConfig.getLastIteration(); + if (iteration < drtSpeedUpParams.fractionOfIterationsSwitchOn * lastIteration + || iteration >= drtSpeedUpParams.fractionOfIterationsSwitchOff * lastIteration) { + return false; // full drt simulation + } + + //full drt simulation only with a defined interval + return iteration % drtSpeedUpParams.intervalDetailedIteration != 0; } private final String mode; From b6e0812d9210dda4cbef4436554ad8754c8fa86f Mon Sep 17 00:00:00 2001 From: rakow Date: Tue, 12 Mar 2024 10:43:40 +0100 Subject: [PATCH 12/19] improved drt teleportation test --- .../teleportation/DrtTeleportationTest.java | 54 +++++++------------ .../DrtTeleportationWithModeChoiceTest.java | 6 +-- 2 files changed, 21 insertions(+), 39 deletions(-) rename contribs/{drt-extensions => drt}/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationTest.java (56%) rename contribs/{drt-extensions => drt}/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationWithModeChoiceTest.java (96%) diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationTest.java b/contribs/drt/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationTest.java similarity index 56% rename from contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationTest.java rename to contribs/drt/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationTest.java index d8cedad2550..90aeea377e5 100644 --- a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationTest.java +++ b/contribs/drt/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationTest.java @@ -1,10 +1,10 @@ package org.matsim.contrib.drt.teleportation; +import org.assertj.core.data.Offset; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import org.matsim.contrib.drt.estimator.DrtEstimator; import org.matsim.contrib.drt.estimator.impl.PessimisticDrtEstimator; -import org.matsim.contrib.drt.estimator.impl.RealisticDrtEstimator; import org.matsim.contrib.drt.fare.DrtFareParams; import org.matsim.contrib.drt.run.DrtConfigGroup; import org.matsim.contrib.drt.run.DrtControlerCreator; @@ -13,15 +13,19 @@ import org.matsim.contrib.dvrp.run.DvrpConfigGroup; import org.matsim.core.config.Config; import org.matsim.core.config.ConfigUtils; -import org.matsim.core.config.groups.ReplanningConfigGroup; import org.matsim.core.controler.Controler; -import org.matsim.core.replanning.strategies.DefaultPlanStrategiesModule; import org.matsim.core.utils.io.IOUtils; import org.matsim.examples.ExamplesUtils; import org.matsim.testcases.MatsimTestUtils; import org.matsim.vis.otfvis.OTFVisConfigGroup; +import java.io.IOException; import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; class DrtTeleportationTest { @@ -29,13 +33,13 @@ class DrtTeleportationTest { public MatsimTestUtils utils = new MatsimTestUtils(); @Test - void testPessimisticEstimator() { + void testTeleportationEngine() throws IOException { URL url = IOUtils.extendUrl(ExamplesUtils.getTestScenarioURL("mielec"), "mielec_drt_config.xml"); Config config = ConfigUtils.loadConfig(url, new MultiModeDrtConfigGroup(), new DvrpConfigGroup(), new OTFVisConfigGroup()); config.network().setInputFile("network.xml"); config.plans().setInputFile("plans_only_drt_1.0.xml.gz"); config.controller().setOutputDirectory(utils.getOutputDirectory()); - config.controller().setLastIteration(2); + config.controller().setLastIteration(1); Controler controler = DrtControlerCreator.createControler(config, false); DrtConfigGroup drtConfigGroup = DrtConfigGroup.getSingleModeDrtConfig(config); @@ -57,40 +61,18 @@ public void install() { }); controler.run(); - // TODO add a check - } - @Test - void testRealisticEstimator() { - URL url = IOUtils.extendUrl(ExamplesUtils.getTestScenarioURL("mielec"), "mielec_drt_config.xml"); - Config config = ConfigUtils.loadConfig(url, new MultiModeDrtConfigGroup(), new DvrpConfigGroup(), new OTFVisConfigGroup()); - config.network().setInputFile("network.xml"); - config.plans().setInputFile("plans_only_drt_1.0.xml.gz"); - config.controller().setOutputDirectory(utils.getOutputDirectory()); - config.controller().setLastIteration(2); + List csv = Files.readAllLines(Path.of(utils.getOutputDirectory()).resolve("drt_customer_stats_drt.csv")); + String[] columns = csv.get(csv.size() - 1).split(";"); - // install the drt routing stuff, but not the mobsim stuff! - Controler controler = DrtControlerCreator.createControler(config, false); - DrtConfigGroup drtConfigGroup = DrtConfigGroup.getSingleModeDrtConfig(config); - drtConfigGroup.maxTravelTimeAlpha = 1.2; - drtConfigGroup.maxTravelTimeBeta = 600; - drtConfigGroup.maxWaitTime = 300; - DrtFareParams fareParams = new DrtFareParams(); - fareParams.baseFare = 1.0; - fareParams.distanceFare_m = 0.001; - drtConfigGroup.addParameterSet(fareParams); + double waitAvg = Double.parseDouble(columns[3]); - // Setup to enable estimator and teleportation - drtConfigGroup.simulationType = DrtConfigGroup.SimulationType.estimateAndTeleport; - controler.addOverridingModule(new AbstractDvrpModeModule(drtConfigGroup.mode) { - @Override - public void install() { - bindModal(DrtEstimator.class).toInstance(new RealisticDrtEstimator( - new RealisticDrtEstimator.DistributionGenerator(1.2, 150, 0.1, 180, 0.2))); - } - }); + assertThat(waitAvg).isEqualTo(drtConfigGroup.maxWaitTime); + + double distMean = Double.parseDouble(columns[11]); + double directDistMean = Double.parseDouble(columns[12]); + + assertThat(distMean / directDistMean).isCloseTo(drtConfigGroup.maxTravelTimeAlpha, Offset.offset(0.0001)); - controler.run(); - // TODO add a check } } diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationWithModeChoiceTest.java b/contribs/drt/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationWithModeChoiceTest.java similarity index 96% rename from contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationWithModeChoiceTest.java rename to contribs/drt/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationWithModeChoiceTest.java index 7dee5b27ce4..b271fca1d42 100644 --- a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationWithModeChoiceTest.java +++ b/contribs/drt/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationWithModeChoiceTest.java @@ -1,5 +1,6 @@ package org.matsim.contrib.drt.teleportation; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import org.matsim.api.core.v01.TransportMode; @@ -28,7 +29,8 @@ public class DrtTeleportationWithModeChoiceTest { @RegisterExtension public MatsimTestUtils utils = new MatsimTestUtils(); -// @Test + @Disabled("This test is for example purposes only") + @Test void testModeChoice() { URL url = IOUtils.extendUrl(ExamplesUtils.getTestScenarioURL("mielec"), "mielec_drt_config.xml"); Config config = ConfigUtils.loadConfig(url, new MultiModeDrtConfigGroup(), new DvrpConfigGroup(), new OTFVisConfigGroup()); @@ -61,12 +63,10 @@ void testModeChoice() { // Setting DRT config group DrtConfigGroup drtConfigGroup = DrtConfigGroup.getSingleModeDrtConfig(config); - // Copy this line to Leipzig run script!!! drtConfigGroup.simulationType = DrtConfigGroup.SimulationType.estimateAndTeleport; Controler controler = DrtControlerCreator.createControler(config, false); - // Copy this overriding module to Leipzig run script!!! controler.addOverridingModule(new AbstractDvrpModeModule(drtConfigGroup.mode) { @Override public void install() { From e70140c075e5f2fa1d6c0efcbe89f67f838f0472 Mon Sep 17 00:00:00 2001 From: rakow Date: Tue, 12 Mar 2024 10:59:20 +0100 Subject: [PATCH 13/19] improved naming of estimators --- ...ator.java => DetourBasedDrtEstimator.java} | 28 +++++++++++-------- .../DrtTeleportationWithModeChoiceTest.java | 7 ++--- 2 files changed, 19 insertions(+), 16 deletions(-) rename contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/{RealisticDrtEstimator.java => DetourBasedDrtEstimator.java} (66%) diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/RealisticDrtEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/DetourBasedDrtEstimator.java similarity index 66% rename from contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/RealisticDrtEstimator.java rename to contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/DetourBasedDrtEstimator.java index 2701999c0ca..e85e5595930 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/RealisticDrtEstimator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/DetourBasedDrtEstimator.java @@ -6,12 +6,21 @@ import java.util.Random; -public class RealisticDrtEstimator implements DrtEstimator { +/** + * A simple DRT estimator that uses normal distributions to estimate the ride time, wait time, ride distance and acceptance. + */ +public final class DetourBasedDrtEstimator implements DrtEstimator { - private final DistributionGenerator distributionGenerator; + private final NormalDistributionGenerator distributionGenerator; - public RealisticDrtEstimator(DistributionGenerator distributionGenerator) { - this.distributionGenerator = distributionGenerator; + private DetourBasedDrtEstimator(double estRideTimeAlpha, double estRideTimeBeta, double rideTimeStd, double estMeanWaitTime, + double waitTimeStd) { + this.distributionGenerator = new NormalDistributionGenerator(estRideTimeAlpha, estRideTimeBeta, rideTimeStd, estMeanWaitTime, waitTimeStd); + } + + public static DetourBasedDrtEstimator normalDistributed(double estRideTimeAlpha, double estRideTimeBeta, double rideTimeStd, double estMeanWaitTime, + double waitTimeStd) { + return new DetourBasedDrtEstimator(estRideTimeAlpha, estRideTimeBeta, rideTimeStd, estMeanWaitTime, waitTimeStd); } @Override @@ -26,8 +35,7 @@ public Estimate estimate(DrtRoute route, OptionalTime departureTime) { return new Estimate(rideDistance, waitTime + rideTime, waitTime, acceptanceRate); } - - public static class DistributionGenerator { + private static class NormalDistributionGenerator { private final Random random = new Random(4711); private final double estRideTimeAlpha; private final double estRideTimeBeta; @@ -35,7 +43,7 @@ public static class DistributionGenerator { private final double estMeanWaitTime; private final double waitTimeStd; - public DistributionGenerator(double estRideTimeAlpha, double estRideTimeBeta, double rideTimeStd, double estMeanWaitTime, + public NormalDistributionGenerator(double estRideTimeAlpha, double estRideTimeBeta, double rideTimeStd, double estMeanWaitTime, double waitTimeStd) { this.estRideTimeAlpha = estRideTimeAlpha; this.estRideTimeBeta = estRideTimeBeta; @@ -44,10 +52,6 @@ public DistributionGenerator(double estRideTimeAlpha, double estRideTimeBeta, do this.waitTimeStd = waitTimeStd; } - public DistributionGenerator generateExampleDistributionGenerator() { - return new DistributionGenerator(1.5, 300, 0.2, 300, 0.4); - } - public double generateRideTime(double directRideTime) { // TODO improve this distribution double estMeanRideTime = estRideTimeAlpha * directRideTime + estRideTimeBeta; @@ -66,7 +70,7 @@ public double generateWaitTime() { } public double generateAcceptanceRate() { - return random.nextDouble(); + return 1; } } } diff --git a/contribs/drt/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationWithModeChoiceTest.java b/contribs/drt/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationWithModeChoiceTest.java index b271fca1d42..461a5c78192 100644 --- a/contribs/drt/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationWithModeChoiceTest.java +++ b/contribs/drt/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationWithModeChoiceTest.java @@ -5,7 +5,7 @@ import org.junit.jupiter.api.extension.RegisterExtension; import org.matsim.api.core.v01.TransportMode; import org.matsim.contrib.drt.estimator.DrtEstimator; -import org.matsim.contrib.drt.estimator.impl.RealisticDrtEstimator; +import org.matsim.contrib.drt.estimator.impl.DetourBasedDrtEstimator; import org.matsim.contrib.drt.run.DrtConfigGroup; import org.matsim.contrib.drt.run.DrtControlerCreator; import org.matsim.contrib.drt.run.MultiModeDrtConfigGroup; @@ -70,9 +70,8 @@ void testModeChoice() { controler.addOverridingModule(new AbstractDvrpModeModule(drtConfigGroup.mode) { @Override public void install() { - bindModal(DrtEstimator.class).toInstance(new RealisticDrtEstimator( - new RealisticDrtEstimator.DistributionGenerator(1.2, 32, - 0.3, 300, 0.4))); + bindModal(DrtEstimator.class).toInstance(DetourBasedDrtEstimator.normalDistributed(1.2, 32, + 0.3, 300, 0.4)); } }); From 928d2764266acec9114d1d902e99915085ec4b22 Mon Sep 17 00:00:00 2001 From: rakow Date: Tue, 12 Mar 2024 11:32:11 +0100 Subject: [PATCH 14/19] finished some todos, added config check --- .../drt/estimator/DrtEstimatorModule.java | 25 +++++++++++-------- .../contrib/drt/run/DrtConfigGroup.java | 7 ++++-- .../speedup/DrtTeleportedRouteCalculator.java | 1 + .../teleportation/DrtTeleportationTest.java | 10 +++++--- 4 files changed, 27 insertions(+), 16 deletions(-) diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimatorModule.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimatorModule.java index 4406c1d5321..ee6302313cc 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimatorModule.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimatorModule.java @@ -1,16 +1,18 @@ package org.matsim.contrib.drt.estimator; import com.google.inject.Binder; +import com.google.inject.Key; import com.google.inject.Singleton; +import com.google.inject.binder.LinkedBindingBuilder; import com.google.inject.multibindings.MapBinder; import org.matsim.contrib.drt.analysis.DrtEventSequenceCollector; -import org.matsim.contrib.drt.estimator.impl.BasicDrtEstimator; -import org.matsim.contrib.drt.estimator.impl.PessimisticDrtEstimator; import org.matsim.contrib.drt.run.DrtConfigGroup; import org.matsim.contrib.dvrp.run.AbstractDvrpModeModule; import org.matsim.contrib.dvrp.run.DvrpMode; import org.matsim.contrib.dvrp.run.DvrpModes; -import org.matsim.core.modal.ModalProviders; +import org.matsim.core.modal.ModalAnnotationCreator; + +import java.lang.annotation.Annotation; /** * Main module that needs to be installed if any estimator is to be used. @@ -26,14 +28,17 @@ public DrtEstimatorModule(String mode, DrtConfigGroup drtCfg, DrtEstimatorParams this.params = params; } - public static Object bindEstimator(Binder binder, String mode){ - - // TODO create helper method for binding + /** + * Create binder for estimator to a specific mode. This is a helper method to use binding without creating + * a separate modal module. + */ + public static LinkedBindingBuilder bindEstimator(Binder binder, String mode) { + Key key = modalKey(DvrpModes::mode, mode); + return binder.bind(key); + } -// DvrpMode key = DvrpModes.mode(mode); -// binder.bind(key) -// ModalProviders.createProvider(mode, DvrpModes::mode); - return null; + private static Key modalKey(ModalAnnotationCreator f, String mode) { + return f.key(DrtEstimator.class, mode); } @Override diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtConfigGroup.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtConfigGroup.java index 9d133a32603..4d83fc47ab4 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtConfigGroup.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtConfigGroup.java @@ -220,7 +220,7 @@ public enum OperationalScheme { public enum SimulationType { - fullSimulation, drtSpeedup, estimateAndTeleport + fullSimulation, estimateAndTeleport } @Parameter @@ -344,7 +344,10 @@ protected void checkConsistency(Config config) { DvrpModeRoutingNetworkModule.checkUseModeFilteredSubnetworkAllowed(config, mode); } - // TODO: check for new speed up params + if (simulationType == SimulationType.estimateAndTeleport) { + Verify.verify(drtSpeedUpParams == null, "Simulation type is estimateAndTeleport, but drtSpeedUpParams is set. " + + "Please remove drtSpeedUpParams from the config, as these two functionalities are not compatible."); + } } @Override diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/speedup/DrtTeleportedRouteCalculator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/speedup/DrtTeleportedRouteCalculator.java index eca53f0c0d7..bd13a75d383 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/speedup/DrtTeleportedRouteCalculator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/speedup/DrtTeleportedRouteCalculator.java @@ -45,6 +45,7 @@ public class DrtTeleportedRouteCalculator implements TeleportedRouteCalculator { // it could be possible to integrate the drt estimators used by the informed mode-choice // this router should probably not use the beeline distance but the direct travel route // speed-up would still be significant (oct'23) + // estimator have been moved to drt contrib, one can now use estimateAndTeleport for new functionality (mar'24) @Override public Route calculateRoute(PassengerRequest request) { diff --git a/contribs/drt/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationTest.java b/contribs/drt/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationTest.java index 90aeea377e5..67a8bfc424c 100644 --- a/contribs/drt/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationTest.java +++ b/contribs/drt/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationTest.java @@ -3,16 +3,16 @@ import org.assertj.core.data.Offset; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; -import org.matsim.contrib.drt.estimator.DrtEstimator; +import org.matsim.contrib.drt.estimator.DrtEstimatorModule; import org.matsim.contrib.drt.estimator.impl.PessimisticDrtEstimator; import org.matsim.contrib.drt.fare.DrtFareParams; import org.matsim.contrib.drt.run.DrtConfigGroup; import org.matsim.contrib.drt.run.DrtControlerCreator; import org.matsim.contrib.drt.run.MultiModeDrtConfigGroup; -import org.matsim.contrib.dvrp.run.AbstractDvrpModeModule; import org.matsim.contrib.dvrp.run.DvrpConfigGroup; import org.matsim.core.config.Config; import org.matsim.core.config.ConfigUtils; +import org.matsim.core.controler.AbstractModule; import org.matsim.core.controler.Controler; import org.matsim.core.utils.io.IOUtils; import org.matsim.examples.ExamplesUtils; @@ -53,10 +53,12 @@ void testTeleportationEngine() throws IOException { // Setup to enable estimator and teleportation drtConfigGroup.simulationType = DrtConfigGroup.SimulationType.estimateAndTeleport; - controler.addOverridingModule(new AbstractDvrpModeModule(drtConfigGroup.mode) { + + // This uses the helper method to bind an estimator. Alternatively a separate modal module could also be created. + controler.addOverridingModule(new AbstractModule() { @Override public void install() { - bindModal(DrtEstimator.class).toInstance(new PessimisticDrtEstimator(drtConfigGroup)); + DrtEstimatorModule.bindEstimator(binder(), drtConfigGroup.mode).toInstance(new PessimisticDrtEstimator(drtConfigGroup)); } }); From bc79d036fc04d8066898ff2a44d4cec557e32e69 Mon Sep 17 00:00:00 2001 From: rakow Date: Tue, 12 Mar 2024 12:08:38 +0100 Subject: [PATCH 15/19] update multi modal leg estimator for mode choice --- .../modechoice/MultiModalDrtLegEstimator.java | 30 +++++- .../MultiModaFixedDrtLegEstimatorTest.java | 94 ------------------- .../MultiModalDrtLegEstimatorTest.java | 68 ++++++++------ .../drt/estimator/DrtEstimatorModule.java | 24 ++--- .../estimator/impl/ConstantDrtEstimator.java | 9 +- .../impl/PessimisticDrtEstimator.java | 10 -- 6 files changed, 80 insertions(+), 155 deletions(-) delete mode 100644 contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/estimator/MultiModaFixedDrtLegEstimatorTest.java diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/modechoice/MultiModalDrtLegEstimator.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/modechoice/MultiModalDrtLegEstimator.java index b87211638ee..b868cf4556f 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/modechoice/MultiModalDrtLegEstimator.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/modechoice/MultiModalDrtLegEstimator.java @@ -5,8 +5,13 @@ import org.apache.logging.log4j.Logger; import org.matsim.api.core.v01.population.Leg; import org.matsim.contrib.drt.estimator.DrtEstimator; +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.run.MultiModeDrtConfigGroup; import org.matsim.contrib.dvrp.run.DvrpMode; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; import org.matsim.core.scoring.functions.ModeUtilityParameters; import org.matsim.core.utils.misc.OptionalTime; import org.matsim.modechoice.EstimatorContext; @@ -26,12 +31,20 @@ public class MultiModalDrtLegEstimator implements LegEstimator { private static final Logger log = LogManager.getLogger(MultiModalDrtLegEstimator.class); protected final Map estimators = new HashMap<>(); + protected final Map fareParams = new HashMap<>(); @Inject - public MultiModalDrtLegEstimator(Map estimators) { + public MultiModalDrtLegEstimator(Config config, Map estimators) { for (Map.Entry e : estimators.entrySet()) { this.estimators.put(e.getKey().value(), e.getValue()); } + + MultiModeDrtConfigGroup drtConfigs = ConfigUtils.addOrGetModule(config, MultiModeDrtConfigGroup.class); + for (DrtConfigGroup modal : drtConfigs.getModalElements()) { + if (modal.getDrtFareParams().isPresent()) { + fareParams.put(modal.getMode(), modal.getDrtFareParams().get()); + } + } } @Override @@ -47,14 +60,23 @@ public double estimate(EstimatorContext context, String mode, Leg leg, ModeAvail DrtEstimator.Estimate est = estimator.estimate(route, departureTime); ModeUtilityParameters params = context.scoring.modeParams.get(mode); + double fare = 0; + if (fareParams.containsKey(mode)) { + DrtFareParams fareParams = this.fareParams.get(mode); + fare = fareParams.distanceFare_m * route.getDistance() + + fareParams.timeFare_h * route.getDirectRideTime() / 3600.0 + + fareParams.baseFare; + + fare = Math.max(fare, fareParams.minFarePerTrip); + } + // By default, waiting time is scored as travel time return params.constant + params.marginalUtilityOfDistance_m * est.rideDistance() + params.marginalUtilityOfTraveling_s * est.rideTime() + params.marginalUtilityOfTraveling_s * est.waitingTime() + - context.scoring.marginalUtilityOfMoney * params.monetaryDistanceCostRate * est.rideDistance(); - // TODO: add a new fare estimator? -// context.scoring.marginalUtilityOfMoney * est.fare(); + context.scoring.marginalUtilityOfMoney * params.monetaryDistanceCostRate * est.rideDistance() + + context.scoring.marginalUtilityOfMoney * fare; } } diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/estimator/MultiModaFixedDrtLegEstimatorTest.java b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/estimator/MultiModaFixedDrtLegEstimatorTest.java deleted file mode 100644 index 2b0cb230683..00000000000 --- a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/estimator/MultiModaFixedDrtLegEstimatorTest.java +++ /dev/null @@ -1,94 +0,0 @@ -package org.matsim.contrib.drt.extension.estimator; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; -import org.matsim.application.MATSimApplication; -import org.matsim.contrib.drt.extension.modechoice.MultiModalDrtLegEstimator; -import org.matsim.contrib.drt.extension.DrtTestScenario; -import org.matsim.contrib.drt.estimator.impl.ConstantDrtEstimator; -import org.matsim.contrib.drt.estimator.DrtEstimatorParams; -import org.matsim.contrib.drt.estimator.DrtEstimatorModule; -import org.matsim.core.config.Config; -import org.matsim.core.config.ConfigUtils; -import org.matsim.core.config.groups.ReplanningConfigGroup; -import org.matsim.core.controler.Controler; -import org.matsim.modechoice.InformedModeChoiceModule; -import org.matsim.modechoice.ModeOptions; -import org.matsim.modechoice.estimators.DefaultLegScoreEstimator; -import org.matsim.modechoice.estimators.FixedCostsEstimator; -import org.matsim.testcases.MatsimTestUtils; - -import java.io.File; -import java.util.List; -import java.util.stream.Collectors; - -import static org.assertj.core.api.Assertions.assertThat; - -public class MultiModaFixedDrtLegEstimatorTest { - - @RegisterExtension - private MatsimTestUtils utils = new MatsimTestUtils(); - - private Controler controler; - - private static void prepare(Controler controler) { - InformedModeChoiceModule.Builder builder = InformedModeChoiceModule.newBuilder() - .withFixedCosts(FixedCostsEstimator.DailyConstant.class, "car") - .withLegEstimator(DefaultLegScoreEstimator.class, ModeOptions.AlwaysAvailable.class, "bike", "walk", "pt") - .withLegEstimator(DefaultLegScoreEstimator.class, ModeOptions.ConsiderYesAndNo.class, "car") - .withLegEstimator(MultiModalDrtLegEstimator.class, ModeOptions.AlwaysAvailable.class, "drt", "av"); - - controler.addOverridingModule(builder.build()); - //TODO fix later -// controler.addOverridingModule(new DrtEstimatorModule() -// .withInitialEstimator(cfg -> new ConstantDrtEstimator(cfg, 1.05, 300), "drt", "av")); - } - - private static void prepare(Config config) { - -// MultiModeDrtEstimatorConfigGroup estimators = ConfigUtils.addOrGetModule(config, MultiModeDrtEstimatorConfigGroup.class); -// -// estimators.addParameterSet(new DrtEstimatorParams("drt") -// .withEstimator(DrtEstimatorParams.EstimatorType.INITIAL)); -// estimators.addParameterSet(new DrtEstimatorParams("av")); - - // Set subtour mode selection as strategy - List strategies = config.replanning().getStrategySettings().stream() - .filter(s -> !s.getStrategyName().toLowerCase().contains("mode") - ).collect(Collectors.toList()); - - strategies.add(new ReplanningConfigGroup.StrategySettings() - .setStrategyName(InformedModeChoiceModule.SELECT_SUBTOUR_MODE_STRATEGY) - .setSubpopulation("person") - .setWeight(0.2)); - - config.replanning().clearStrategySettings(); - strategies.forEach(s -> config.replanning().addStrategySettings(s)); - - } - - @BeforeEach - public void setUp() throws Exception { - - Config config = DrtTestScenario.loadConfig(utils); - - config.controller().setLastIteration(3); - - controler = MATSimApplication.prepare(new DrtTestScenario(MultiModaFixedDrtLegEstimatorTest::prepare, MultiModaFixedDrtLegEstimatorTest::prepare), config); - } - - @Test - void run() { - - String out = utils.getOutputDirectory(); - - controler.run(); - - assertThat(new File(out, "kelheim-mini-drt.drt_estimates_drt.csv")) - .exists() - .isNotEmpty(); - - - } -} diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/estimator/MultiModalDrtLegEstimatorTest.java b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/estimator/MultiModalDrtLegEstimatorTest.java index bdc314bb112..f925ed604dd 100644 --- a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/estimator/MultiModalDrtLegEstimatorTest.java +++ b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/estimator/MultiModalDrtLegEstimatorTest.java @@ -5,10 +5,15 @@ import org.junit.jupiter.api.extension.RegisterExtension; import org.matsim.application.MATSimApplication; import org.matsim.contrib.drt.estimator.DrtEstimatorModule; +import org.matsim.contrib.drt.estimator.impl.ConstantDrtEstimator; import org.matsim.contrib.drt.extension.DrtTestScenario; import org.matsim.contrib.drt.extension.modechoice.MultiModalDrtLegEstimator; +import org.matsim.contrib.drt.run.DrtConfigGroup; +import org.matsim.contrib.drt.run.MultiModeDrtConfigGroup; import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; import org.matsim.core.config.groups.ReplanningConfigGroup; +import org.matsim.core.controler.AbstractModule; import org.matsim.core.controler.Controler; import org.matsim.modechoice.InformedModeChoiceModule; import org.matsim.modechoice.ModeOptions; @@ -25,52 +30,57 @@ public class MultiModalDrtLegEstimatorTest { @RegisterExtension - private MatsimTestUtils utils = new MatsimTestUtils(); + public MatsimTestUtils utils = new MatsimTestUtils(); private Controler controler; - @BeforeEach - public void setUp() throws Exception { - - Config config = DrtTestScenario.loadConfig(utils); - - config.controller().setLastIteration(3); - - controler = MATSimApplication.prepare(new DrtTestScenario(MultiModalDrtLegEstimatorTest::prepare, MultiModalDrtLegEstimatorTest::prepare), config); - } - private static void prepare(Controler controler) { InformedModeChoiceModule.Builder builder = InformedModeChoiceModule.newBuilder() - .withFixedCosts(FixedCostsEstimator.DailyConstant.class, "car") - .withLegEstimator(DefaultLegScoreEstimator.class, ModeOptions.AlwaysAvailable.class, "bike", "walk", "pt") - .withLegEstimator(DefaultLegScoreEstimator.class, ModeOptions.ConsiderYesAndNo.class, "car") - .withLegEstimator(MultiModalDrtLegEstimator.class, ModeOptions.AlwaysAvailable.class, "drt", "av"); + .withFixedCosts(FixedCostsEstimator.DailyConstant.class, "car") + .withLegEstimator(DefaultLegScoreEstimator.class, ModeOptions.AlwaysAvailable.class, "bike", "walk", "pt") + .withLegEstimator(DefaultLegScoreEstimator.class, ModeOptions.ConsiderYesAndNo.class, "car") + .withLegEstimator(MultiModalDrtLegEstimator.class, ModeOptions.AlwaysAvailable.class, "drt", "av"); controler.addOverridingModule(builder.build()); -// controler.addOverridingModule(new DrtEstimatorModule()); + + MultiModeDrtConfigGroup drtConfig = ConfigUtils.addOrGetModule(controler.getConfig(), MultiModeDrtConfigGroup.class); + + controler.addOverridingModule(new AbstractModule() { + @Override + public void install() { + + for (DrtConfigGroup el : drtConfig.getModalElements()) { + install(new DrtEstimatorModule(el.mode, el, el.getDrtEstimatorParams().get())); + DrtEstimatorModule.bindEstimator(binder(), el.mode).toInstance(new ConstantDrtEstimator(1.05, 300)); + } + } + }); } private static void prepare(Config config) { -// MultiModeDrtEstimatorConfigGroup estimators = ConfigUtils.addOrGetModule(config, MultiModeDrtEstimatorConfigGroup.class); -// -// estimators.addParameterSet(new DrtEstimatorParams("drt")); -// estimators.addParameterSet(new DrtEstimatorParams("av")); - // TODO fix later - // Set subtour mode selection as strategy List strategies = config.replanning().getStrategySettings().stream() - .filter(s -> !s.getStrategyName().toLowerCase().contains("mode") - ).collect(Collectors.toList()); + .filter(s -> !s.getStrategyName().toLowerCase().contains("mode") + ).collect(Collectors.toList()); strategies.add(new ReplanningConfigGroup.StrategySettings() - .setStrategyName(InformedModeChoiceModule.SELECT_SUBTOUR_MODE_STRATEGY) - .setSubpopulation("person") - .setWeight(0.2)); + .setStrategyName(InformedModeChoiceModule.SELECT_SUBTOUR_MODE_STRATEGY) + .setSubpopulation("person") + .setWeight(0.2)); config.replanning().clearStrategySettings(); strategies.forEach(s -> config.replanning().addStrategySettings(s)); + } + + @BeforeEach + public void setUp() throws Exception { + Config config = DrtTestScenario.loadConfig(utils); + + config.controller().setLastIteration(3); + + controler = MATSimApplication.prepare(new DrtTestScenario(MultiModalDrtLegEstimatorTest::prepare, MultiModalDrtLegEstimatorTest::prepare), config); } @Test @@ -81,8 +91,8 @@ void run() { controler.run(); assertThat(new File(out, "kelheim-mini-drt.drt_estimates_drt.csv")) - .exists() - .isNotEmpty(); + .exists() + .isNotEmpty(); } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimatorModule.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimatorModule.java index ee6302313cc..3ca93742137 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimatorModule.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimatorModule.java @@ -53,17 +53,17 @@ public void install() { bindModal(DrtEstimatorParams.class).toInstance(params); - // Needs to run before estimators - bindModal(DrtEstimateAnalyzer.class) - .toProvider( - modalProvider(getter -> new DrtEstimateAnalyzer(getter.getModal(DrtEstimator.class), - getter.getModal(DrtEventSequenceCollector.class), getMode())) - ) - .in(Singleton.class); - - addControlerListenerBinding().to(modalKey(DrtEstimateAnalyzer.class)); - + // Analyze quality of estimates, this is only useful if an online estimator is used + // TODO: updating estimation as in drt speed up is not fully implemented yet + if (drtCfg.simulationType == DrtConfigGroup.SimulationType.fullSimulation) { + bindModal(DrtEstimateAnalyzer.class) + .toProvider( + modalProvider(getter -> new DrtEstimateAnalyzer(getter.getModal(DrtEstimator.class), + getter.getModal(DrtEventSequenceCollector.class), getMode())) + ) + .in(Singleton.class); + + addControlerListenerBinding().to(modalKey(DrtEstimateAnalyzer.class)); + } } - - } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/ConstantDrtEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/ConstantDrtEstimator.java index a51f93be2d8..20ea18ee120 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/ConstantDrtEstimator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/ConstantDrtEstimator.java @@ -10,9 +10,7 @@ */ public class ConstantDrtEstimator implements DrtEstimator { - private final DrtConfigGroup drtConfig; - - /** + /** * Detour factor for the estimate. 1.0 means no detour, 2.0 means twice the distance. */ private final double detourFactor; @@ -22,9 +20,8 @@ public class ConstantDrtEstimator implements DrtEstimator { */ private final double waitingTime; - public ConstantDrtEstimator(DrtConfigGroup drtConfig, double detourFactor, double waitingTime) { - this.drtConfig = drtConfig; - this.detourFactor = detourFactor; + public ConstantDrtEstimator(double detourFactor, double waitingTime) { + this.detourFactor = detourFactor; this.waitingTime = waitingTime; } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/PessimisticDrtEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/PessimisticDrtEstimator.java index 553844f2dc9..6d12e59292a 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/PessimisticDrtEstimator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/PessimisticDrtEstimator.java @@ -23,16 +23,6 @@ public Estimate estimate(DrtRoute route, OptionalTime departureTime) { 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, 0); } From 7e76cf9e4ac9050f082b61abc2d264b1546b72fd Mon Sep 17 00:00:00 2001 From: rakow Date: Tue, 12 Mar 2024 13:21:36 +0100 Subject: [PATCH 16/19] remove added import that is not needed --- .../src/main/java/org/matsim/core/modal/AbstractModalModule.java | 1 - 1 file changed, 1 deletion(-) diff --git a/matsim/src/main/java/org/matsim/core/modal/AbstractModalModule.java b/matsim/src/main/java/org/matsim/core/modal/AbstractModalModule.java index b45cef6d761..b7fe58794bd 100644 --- a/matsim/src/main/java/org/matsim/core/modal/AbstractModalModule.java +++ b/matsim/src/main/java/org/matsim/core/modal/AbstractModalModule.java @@ -23,7 +23,6 @@ import java.lang.annotation.Annotation; import java.util.function.Function; -import com.google.inject.Binder; import org.matsim.core.controler.AbstractModule; import com.google.inject.Key; From 73437c676c5de345a622395c5f5bd65fb94cb170 Mon Sep 17 00:00:00 2001 From: rakow Date: Tue, 12 Mar 2024 14:35:48 +0100 Subject: [PATCH 17/19] fix tests due to changed column names --- .../teleportation/DrtTeleportationTest.java | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/contribs/drt/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationTest.java b/contribs/drt/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationTest.java index 67a8bfc424c..4cd79608057 100644 --- a/contribs/drt/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationTest.java +++ b/contribs/drt/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationTest.java @@ -1,5 +1,9 @@ package org.matsim.contrib.drt.teleportation; +import com.google.common.collect.Iterables; +import org.apache.commons.csv.CSVFormat; +import org.apache.commons.csv.CSVParser; +import org.apache.commons.csv.CSVRecord; import org.assertj.core.data.Offset; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -21,9 +25,7 @@ import java.io.IOException; import java.net.URL; -import java.nio.file.Files; import java.nio.file.Path; -import java.util.List; import static org.assertj.core.api.Assertions.assertThat; @@ -64,17 +66,23 @@ public void install() { controler.run(); - List csv = Files.readAllLines(Path.of(utils.getOutputDirectory()).resolve("drt_customer_stats_drt.csv")); - String[] columns = csv.get(csv.size() - 1).split(";"); + Path csvPath = Path.of(utils.getOutputDirectory()).resolve("drt_customer_stats_drt.csv"); - double waitAvg = Double.parseDouble(columns[3]); + try (CSVParser csv = new CSVParser(IOUtils.getBufferedReader(csvPath.toString()), + CSVFormat.DEFAULT.builder().setHeader().setSkipHeaderRecord(true).setDelimiter(';').build())) { - assertThat(waitAvg).isEqualTo(drtConfigGroup.maxWaitTime); + CSVRecord row = Iterables.getLast(csv); - double distMean = Double.parseDouble(columns[11]); - double directDistMean = Double.parseDouble(columns[12]); + double waitAvg = Double.parseDouble(row.get("wait_average")); - assertThat(distMean / directDistMean).isCloseTo(drtConfigGroup.maxTravelTimeAlpha, Offset.offset(0.0001)); + assertThat(waitAvg).isEqualTo(drtConfigGroup.maxWaitTime); + + double distMean = Double.parseDouble(row.get("distance_m_mean")); + double directDistMean = Double.parseDouble(row.get("directDistance_m_mean")); + + assertThat(distMean / directDistMean).isCloseTo(drtConfigGroup.maxTravelTimeAlpha, Offset.offset(0.0001)); + + } } } From 0ad7c9fe54fd2462a8c7ac3f36a7a49ba98f8918 Mon Sep 17 00:00:00 2001 From: Chengqi Lu <43133404+luchengqi7@users.noreply.github.com> Date: Wed, 13 Mar 2024 18:26:32 +0100 Subject: [PATCH 18/19] Update EstimationRoutingModule.java When no DRT suitable DRT is found, the route will be null. We need to be able to handle this situation. --- .../contrib/drt/estimator/EstimationRoutingModule.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/EstimationRoutingModule.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/EstimationRoutingModule.java index 3bfa4ce5152..a024cae0101 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/EstimationRoutingModule.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/EstimationRoutingModule.java @@ -26,6 +26,11 @@ public List calcRoute(RoutingRequest request) { List route = delegate.calcRoute(request); + if (route == null) { + // no suitable DRT connection found (e.g., can't find DRT stops nearby), will fall back to walk mode. + return null; + } + for (PlanElement el : route) { if (el instanceof Leg leg) { if (leg.getRoute() instanceof DrtRoute drtRoute) { From b14a3824abdab43d02ddef4fda43dd1f9c8b8a33 Mon Sep 17 00:00:00 2001 From: Chengqi Lu <43133404+luchengqi7@users.noreply.github.com> Date: Thu, 11 Apr 2024 11:42:17 +0200 Subject: [PATCH 19/19] Add a new estimator approach --- .../EuclideanDistanceBasedDrtEstimator.java | 78 +++++++++++++++++++ .../DrtTeleportationWithModeChoiceTest.java | 13 +++- 2 files changed, 87 insertions(+), 4 deletions(-) create mode 100644 contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/EuclideanDistanceBasedDrtEstimator.java diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/EuclideanDistanceBasedDrtEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/EuclideanDistanceBasedDrtEstimator.java new file mode 100644 index 00000000000..dd3a2492ce9 --- /dev/null +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/EuclideanDistanceBasedDrtEstimator.java @@ -0,0 +1,78 @@ +package org.matsim.contrib.drt.estimator.impl; + +import org.matsim.api.core.v01.Coord; +import org.matsim.api.core.v01.network.Network; +import org.matsim.contrib.drt.estimator.DrtEstimator; +import org.matsim.contrib.drt.routing.DrtRoute; +import org.matsim.core.utils.geometry.CoordUtils; +import org.matsim.core.utils.misc.OptionalTime; + +import java.util.Random; + +public class EuclideanDistanceBasedDrtEstimator implements DrtEstimator { + private final Network network; + /** + * For travel distance related scoring (e.g., marginal utility distance), we need estimated network distance: + * Estimated network distance = Euclidean distance * network distance factor + */ + private final double networkDistanceFactor; + /** + * Slope of the linear regression + */ + private final double slope; + /** + * Intercept of the linear regression + */ + private final double intercept; + + private final double estimatedMeanWaitTime; + + private final double waitTimeStd; + + private final double mu; + private final double sigma; + private final Random random = new Random(1234); + + /** + * We use log normal distribution to estimate the ride duration of each individual trip. The distribution + * is based on the linear regression. + * @params networkDistanceFactor: Estimated network distance = Euclidean distance * network distance factor + * @params slope: slope for the linear regression + * @params intercept: intercept for linear regression + * @params mu: mu for log normal distribution + * @params sigma: sigma for log normal distribution. + */ + public EuclideanDistanceBasedDrtEstimator(Network network, double networkDistanceFactor, double slope, + double intercept, double estimatedMeanWaitTime, double waitTimeStd, + double mu, double sigma) { + this.network = network; + this.networkDistanceFactor = networkDistanceFactor; + this.slope = slope; + this.intercept = intercept; + this.estimatedMeanWaitTime = estimatedMeanWaitTime; + this.waitTimeStd = waitTimeStd; + this.mu = mu; + this.sigma = sigma; + } + + @Override + public Estimate estimate(DrtRoute route, OptionalTime departureTime) { + Coord fromCoord = network.getLinks().get(route.getStartLinkId()).getToNode().getCoord(); + Coord toCoord = network.getLinks().get(route.getEndLinkId()).getToNode().getCoord(); + double euclideanDistance = CoordUtils.calcEuclideanDistance(fromCoord, toCoord); + double typicalRideDuration = euclideanDistance * slope + intercept; + double typicalRideDistance = networkDistanceFactor * euclideanDistance; + double randomFactor = nextLogNormal(mu, sigma); + double waitTime = Math.max(estimatedMeanWaitTime * (1 + random.nextGaussian() * waitTimeStd), 0); + + return new Estimate(typicalRideDistance * randomFactor, typicalRideDuration * randomFactor, + waitTime, 0); + } + + public double nextLogNormal(double mu, double sigma) { + if (sigma == 0) + return Math.exp(mu); + + return Math.exp(sigma * random.nextGaussian() + mu); + } +} diff --git a/contribs/drt/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationWithModeChoiceTest.java b/contribs/drt/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationWithModeChoiceTest.java index 461a5c78192..effd09b64ac 100644 --- a/contribs/drt/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationWithModeChoiceTest.java +++ b/contribs/drt/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationWithModeChoiceTest.java @@ -4,8 +4,10 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Network; import org.matsim.contrib.drt.estimator.DrtEstimator; import org.matsim.contrib.drt.estimator.impl.DetourBasedDrtEstimator; +import org.matsim.contrib.drt.estimator.impl.EuclideanDistanceBasedDrtEstimator; import org.matsim.contrib.drt.run.DrtConfigGroup; import org.matsim.contrib.drt.run.DrtControlerCreator; import org.matsim.contrib.drt.run.MultiModeDrtConfigGroup; @@ -37,7 +39,7 @@ void testModeChoice() { config.network().setInputFile("network.xml"); config.plans().setInputFile("plans_only_drt_4.0.xml.gz"); config.controller().setOutputDirectory(utils.getOutputDirectory()); - config.controller().setLastIteration(100); + config.controller().setLastIteration(3); config.replanning().setFractionOfIterationsToDisableInnovation(0.8); config.replanning().setMaxAgentPlanMemorySize(3); @@ -58,7 +60,7 @@ void testModeChoice() { bikeModeParams.setMarginalUtilityOfTraveling(-6.); config.scoring().addModeParams(bikeModeParams); // Update change mode - config.changeMode().setModes( new String[] { TransportMode.drt, TransportMode.bike }); + config.changeMode().setModes(new String[]{TransportMode.drt, TransportMode.bike}); // Setting DRT config group DrtConfigGroup drtConfigGroup = DrtConfigGroup.getSingleModeDrtConfig(config); @@ -70,8 +72,11 @@ void testModeChoice() { controler.addOverridingModule(new AbstractDvrpModeModule(drtConfigGroup.mode) { @Override public void install() { - bindModal(DrtEstimator.class).toInstance(DetourBasedDrtEstimator.normalDistributed(1.2, 32, - 0.3, 300, 0.4)); +// bindModal(DrtEstimator.class).toInstance(DetourBasedDrtEstimator.normalDistributed(1.2, 32, +// 0.3, 300, 0.4)); + bindModal(DrtEstimator.class).toProvider(modalProvider(getter -> new + EuclideanDistanceBasedDrtEstimator(getter.getModal(Network.class), 2.0, 0.1577493, + 103.0972273, 120, 0.3, -0.1, 0.28))); } });