diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/DrtEstimator.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/DrtEstimator.java deleted file mode 100644 index fef209ed211..00000000000 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/DrtEstimator.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.matsim.contrib.drt.extension.estimator; - -import org.matsim.contrib.drt.routing.DrtRoute; -import org.matsim.core.controler.listener.ControlerListener; -import org.matsim.core.utils.misc.OptionalTime; - -/** - * Interface to estimate a DRT service's detour, waiting time and costs. - */ -public interface DrtEstimator extends ControlerListener { - - /** - * Provide an estimate for a drt route with specific pickup and dropoff point. - * - * @param route drt route - * @param departureTime estimated departure time - * @return An {@link Estimate} instance - */ - Estimate estimate(DrtRoute route, OptionalTime departureTime); - - - /** - * 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 rejectionRate probability of a trip being rejected - */ - record Estimate(double distance, double travelTime, double waitingTime, double fare, double rejectionRate) { - - } - -} diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/DrtInitialEstimator.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/DrtInitialEstimator.java deleted file mode 100644 index a826a936e46..00000000000 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/DrtInitialEstimator.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.matsim.contrib.drt.extension.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-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/impl/ConstantDrtEstimator.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/impl/ConstantDrtEstimator.java deleted file mode 100644 index d9a4d4be46f..00000000000 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/impl/ConstantDrtEstimator.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.matsim.contrib.drt.extension.estimator.impl; - -import org.matsim.contrib.drt.extension.estimator.DrtInitialEstimator; -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; - -/** - * Estimates using a constant detour factor and waiting time. - */ -public class ConstantDrtEstimator implements DrtInitialEstimator { - - private final DrtConfigGroup drtConfig; - - /** - * Detour factor for the estimate. 1.0 means no detour, 2.0 means twice the distance. - */ - private final double detourFactor; - - /** - * Constant waiting time estimate in seconds. - */ - private final double waitingTime; - - public ConstantDrtEstimator(DrtConfigGroup drtConfig, double detourFactor, double waitingTime) { - this.drtConfig = drtConfig; - this.detourFactor = detourFactor; - this.waitingTime = waitingTime; - } - - @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); - } -} diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/run/DrtEstimatorConfigGroup.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/run/DrtEstimatorConfigGroup.java deleted file mode 100644 index 26a4e754538..00000000000 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/estimator/run/DrtEstimatorConfigGroup.java +++ /dev/null @@ -1,74 +0,0 @@ -package org.matsim.contrib.drt.extension.estimator.run; - -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.common.util.ReflectiveConfigGroupWithConfigurableParameterSets; - -public class DrtEstimatorConfigGroup extends ReflectiveConfigGroupWithConfigurableParameterSets implements Modal { - - /** - * 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 GROUP_NAME = "drtEstimator"; - - public DrtEstimatorConfigGroup() { - super(GROUP_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 - public EstimatorType estimator = EstimatorType.BASIC; - - @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 - public double randomization = 0.1; - - @Override - public String getMode() { - return mode; - } - - /** - * Set estimator type and return same instance. - */ - public DrtEstimatorConfigGroup withEstimator(EstimatorType estimator) { - this.estimator = estimator; - return this; - } - -} 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 58% 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..b868cf4556f 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,11 +1,17 @@ -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.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; @@ -25,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 @@ -46,13 +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.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 * 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 5d4a8a1d5b6..00000000000 --- a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/estimator/MultiModaFixedDrtLegEstimatorTest.java +++ /dev/null @@ -1,93 +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.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.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()); - 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")); - - // 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 90601b72b29..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 @@ -4,13 +4,16 @@ 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.estimator.impl.ConstantDrtEstimator; 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.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; @@ -27,51 +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()); - } - private static void prepare(Config config) { + MultiModeDrtConfigGroup drtConfig = ConfigUtils.addOrGetModule(controler.getConfig(), MultiModeDrtConfigGroup.class); - MultiModeDrtEstimatorConfigGroup estimators = ConfigUtils.addOrGetModule(config, MultiModeDrtEstimatorConfigGroup.class); + controler.addOverridingModule(new AbstractModule() { + @Override + public void install() { - estimators.addParameterSet(new DrtEstimatorConfigGroup("drt")); - estimators.addParameterSet(new DrtEstimatorConfigGroup("av")); + 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) { // 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 @@ -82,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-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 91% 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..39880674f8a 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); @@ -115,8 +114,9 @@ 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)); - fare.addValue(Math.abs(estimate.fare() - valFare)); + travelTime.addValue(Math.abs(estimate.rideTime() - valTravelTime)); + // 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 new file mode 100644 index 00000000000..b1c218ed4d2 --- /dev/null +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimator.java @@ -0,0 +1,46 @@ +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. + */ +public interface DrtEstimator extends ControlerListener { + + /** + * Provide an estimate for a drt route with specific pickup and dropoff point. + * + * @param route drt route + * @param departureTime estimated departure time + * @return An {@link Estimate} instance + */ + Estimate estimate(DrtRoute route, OptionalTime departureTime); + + + /** + * Estimate for various attributes for a drt trip. + * + * @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 rideDistance, double rideTime, double waitingTime, double rejectionRate) { + + } + + /** + * Write estimate information into the leg attributes. + */ + static void setEstimateAttributes(Leg leg, Estimate estimate) { + 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/DrtEstimatorModule.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimatorModule.java new file mode 100644 index 00000000000..3ca93742137 --- /dev/null +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimatorModule.java @@ -0,0 +1,69 @@ +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.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.ModalAnnotationCreator; + +import java.lang.annotation.Annotation; + +/** + * 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; + } + + /** + * 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); + } + + private static Key modalKey(ModalAnnotationCreator f, String mode) { + return f.key(DrtEstimator.class, mode); + } + + @Override + public void install() { + + // 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); + + // 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/DrtEstimatorParams.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimatorParams.java new file mode 100644 index 00000000000..9f43dd158c5 --- /dev/null +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/DrtEstimatorParams.java @@ -0,0 +1,38 @@ +package org.matsim.contrib.drt.estimator; + +import org.matsim.core.config.ReflectiveConfigGroup; + +public class DrtEstimatorParams extends ReflectiveConfigGroup { + + public static final String SET_NAME = "estimator"; + + public DrtEstimatorParams() { + super(SET_NAME); + } + +// @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 + 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/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 new file mode 100644 index 00000000000..a024cae0101 --- /dev/null +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/EstimationRoutingModule.java @@ -0,0 +1,44 @@ +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; + +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; + private final DrtEstimator estimator; + + public EstimationRoutingModule(DvrpRoutingModule delegate, DrtEstimator estimator) { + this.delegate = delegate; + this.estimator = estimator; + } + + @Override + 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) { + 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/EstimationRoutingModuleProvider.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/EstimationRoutingModuleProvider.java new file mode 100644 index 00000000000..4427c080c02 --- /dev/null +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/EstimationRoutingModuleProvider.java @@ -0,0 +1,69 @@ +/* + * *********************************************************************** * + * 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; + + +public class EstimationRoutingModuleProvider extends ModalProviders.AbstractProvider { + + @Inject + @Named(TransportMode.walk) + private RoutingModule walkRouter; + + @Inject + private TimeInterpretation timeInterpretation; + + @Inject + private Map estimators; + + 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, estimators.get(DvrpModes.mode(getMode()))); + } +} 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 85% 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..f02c4ee59b2 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.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,24 +26,23 @@ * 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 DrtEstimatorConfigGroup config; + private final DrtEstimatorParams config; private final DrtConfigGroup drtConfig; - private final DrtInitialEstimator initial; + private final DrtEstimator initial; private final SplittableRandom rnd = new SplittableRandom(); /** * Currently valid estimates. */ private GlobalEstimate currentEst; - private RegressionResults fare; - public BasicDrtEstimator(DrtEventSequenceCollector collector, DrtInitialEstimator initial, - DrtEstimatorConfigGroup config, DrtConfigGroup drtConfig) { + public BasicDrtEstimator(DrtEventSequenceCollector collector, DrtEstimator initial, + DrtEstimatorParams config, DrtConfigGroup drtConfig) { //zones = injector.getModal(DrtZonalSystem.class); this.collector = collector; this.initial = initial; @@ -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 new file mode 100644 index 00000000000..20ea18ee120 --- /dev/null +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/ConstantDrtEstimator.java @@ -0,0 +1,34 @@ +package org.matsim.contrib.drt.estimator.impl; + +import org.matsim.contrib.drt.estimator.DrtEstimator; +import org.matsim.contrib.drt.routing.DrtRoute; +import org.matsim.contrib.drt.run.DrtConfigGroup; +import org.matsim.core.utils.misc.OptionalTime; + +/** + * Estimates using a constant detour factor and waiting time. + */ +public class ConstantDrtEstimator implements DrtEstimator { + + /** + * Detour factor for the estimate. 1.0 means no detour, 2.0 means twice the distance. + */ + private final double detourFactor; + + /** + * Constant waiting time estimate in seconds. + */ + private final double waitingTime; + + public ConstantDrtEstimator(double detourFactor, double waitingTime) { + this.detourFactor = detourFactor; + this.waitingTime = waitingTime; + } + + @Override + public Estimate estimate(DrtRoute route, OptionalTime departureTime) { + double distance = route.getDistance() * detourFactor; + double travelTime = route.getDirectRideTime() * detourFactor; + return new Estimate(distance, travelTime, waitingTime, 0); + } +} diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/DetourBasedDrtEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/DetourBasedDrtEstimator.java new file mode 100644 index 00000000000..e85e5595930 --- /dev/null +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/DetourBasedDrtEstimator.java @@ -0,0 +1,76 @@ +package org.matsim.contrib.drt.estimator.impl; + +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; + +/** + * 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 NormalDistributionGenerator 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 + 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, acceptanceRate); + } + + private static class NormalDistributionGenerator { + 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 NormalDistributionGenerator(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 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 1; + } + } +} 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-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 60% 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..6d12e59292a 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.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) { @@ -23,18 +23,8 @@ 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, 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/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/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/DrtConfigGroup.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtConfigGroup.java index 7d6f0b9cef4..2e1923688c6 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,8 +28,10 @@ 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.DrtZoneSystemParams; +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; @@ -216,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; @@ -234,6 +245,9 @@ public enum OperationalScheme { @Nullable private PrebookingParams prebookingParams; + @Nullable + private DrtEstimatorParams drtEstimatorParams = new DrtEstimatorParams(); + @Nullable private DrtRequestInsertionRetryParams drtRequestInsertionRetryParams; @@ -279,6 +293,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 @@ -329,6 +349,10 @@ protected void checkConsistency(Config config) { "maxAllowedPickupDelay must be specified! A value between 0 and 240 seconds can be a good choice for maxAllowedPickupDelay."); } + 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 @@ -364,6 +388,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 f667841b104..3acb9ac580a 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 @@ -26,6 +26,7 @@ import org.matsim.api.core.v01.network.Network; import org.matsim.contrib.drt.analysis.DrtEventSequenceCollector; import org.matsim.contrib.drt.analysis.zonal.DrtModeZonalSystemModule; +import org.matsim.contrib.drt.estimator.DrtEstimatorModule; import org.matsim.contrib.drt.fare.DrtFareHandler; import org.matsim.contrib.drt.optimizer.rebalancing.RebalancingModule; import org.matsim.contrib.drt.prebooking.analysis.PrebookingModeAnalysisModule; @@ -106,5 +107,10 @@ public void install() { } install(new AdaptiveTravelTimeMatrixModule(drtCfg.mode)); + + if (drtCfg.simulationType == DrtConfigGroup.SimulationType.estimateAndTeleport ) { + install(new DrtEstimatorModule(getMode(), drtCfg, drtCfg.getDrtEstimatorParams().get())); + } + } } 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..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 @@ -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.simulationType == DrtConfigGroup.SimulationType.estimateAndTeleport; + + 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 c83a66d072d..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,8 @@ 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; import org.matsim.contrib.drt.routing.DrtRouteUpdater; @@ -66,6 +68,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 +79,41 @@ public DrtModeRoutingModule(DrtConfigGroup drtCfg) { @Override public void install() { - 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( 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; @@ -108,10 +125,13 @@ 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(); + // this binds the above as a controler listener: addControlerListenerBinding().to(modalKey(DrtRouteUpdater.class)); } 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 new file mode 100644 index 00000000000..4cd79608057 --- /dev/null +++ b/contribs/drt/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationTest.java @@ -0,0 +1,88 @@ +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; +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.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; +import org.matsim.testcases.MatsimTestUtils; +import org.matsim.vis.otfvis.OTFVisConfigGroup; + +import java.io.IOException; +import java.net.URL; +import java.nio.file.Path; + +import static org.assertj.core.api.Assertions.assertThat; + +class DrtTeleportationTest { + + @RegisterExtension + public MatsimTestUtils utils = new MatsimTestUtils(); + + @Test + 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(1); + + 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); + + // Setup to enable estimator and teleportation + drtConfigGroup.simulationType = DrtConfigGroup.SimulationType.estimateAndTeleport; + + // 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() { + DrtEstimatorModule.bindEstimator(binder(), drtConfigGroup.mode).toInstance(new PessimisticDrtEstimator(drtConfigGroup)); + } + }); + + controler.run(); + + Path csvPath = Path.of(utils.getOutputDirectory()).resolve("drt_customer_stats_drt.csv"); + + try (CSVParser csv = new CSVParser(IOUtils.getBufferedReader(csvPath.toString()), + CSVFormat.DEFAULT.builder().setHeader().setSkipHeaderRecord(true).setDelimiter(';').build())) { + + CSVRecord row = Iterables.getLast(csv); + + double waitAvg = Double.parseDouble(row.get("wait_average")); + + 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)); + + } + + } +} 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 new file mode 100644 index 00000000000..effd09b64ac --- /dev/null +++ b/contribs/drt/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationWithModeChoiceTest.java @@ -0,0 +1,86 @@ +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; +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; +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(); + + @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()); + config.network().setInputFile("network.xml"); + config.plans().setInputFile("plans_only_drt_4.0.xml.gz"); + config.controller().setOutputDirectory(utils.getOutputDirectory()); + config.controller().setLastIteration(3); + + 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}); + + // Setting DRT config group + DrtConfigGroup drtConfigGroup = DrtConfigGroup.getSingleModeDrtConfig(config); + + drtConfigGroup.simulationType = DrtConfigGroup.SimulationType.estimateAndTeleport; + + Controler controler = DrtControlerCreator.createControler(config, false); + + 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).toProvider(modalProvider(getter -> new + EuclideanDistanceBasedDrtEstimator(getter.getModal(Network.class), 2.0, 0.1577493, + 103.0972273, 120, 0.3, -0.1, 0.28))); + } + }); + + System.out.println(config); + controler.run(); + } +} 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..52df574a1d8 --- /dev/null +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/TeleportingEstimationPassengerEngine.java @@ -0,0 +1,249 @@ +/* + * *********************************************************************** * + * 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 it.unimi.dsi.fastutil.doubles.DoubleObjectPair; +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.utils.objectattributes.attributable.Attributable; +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; + + /** + * 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; + + 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) { + + // 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 (!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)); + } + } + + //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)) { + + 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); + + 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 + passenger.setStateToAbort(mobsimTimer.getTimeOfDay()); + internalInterface.arrangeNextAgentState(passenger); + } + + return true; + } + + 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); + } + }; + } + + static double getEstimatedRideTime(Attributable element) { + return (double) element.getAttributes().getAttribute("est_ride_time"); + } + + static double getEstimatedRideDistance(Attributable element){ + return (double) element.getAttributes().getAttribute("est_ride_distance"); + } + + static double getEstimatedWaitTime(Attributable element){ + return (double) element.getAttributes().getAttribute("est_wait_time"); + } + +} 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(); 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() { 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 new file mode 100644 index 00000000000..a7240fffd87 --- /dev/null +++ b/examples/scenarios/mielec/empty_config.xml @@ -0,0 +1,4 @@ + + + +