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"); + } + + }