diff --git a/input/v6.1/berlin-v6.1.drt-config.xml b/input/v6.1/berlin-v6.1.drt-config.xml new file mode 100644 index 00000000..3d6083f8 --- /dev/null +++ b/input/v6.1/berlin-v6.1.drt-config.xml @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pom.xml b/pom.xml index 402b7ab0..d3c53cff 100644 --- a/pom.xml +++ b/pom.xml @@ -144,6 +144,14 @@ compile + + + org.matsim.contrib + drt-extensions + ${matsim.version} + compile + + org.matsim.contrib roadpricing diff --git a/src/main/java/org/matsim/legacy/prepare/drt/DrtVehicleCreator.java b/src/main/java/org/matsim/legacy/prepare/drt/DrtVehicleCreator.java index bcec32bf..1fb65a1e 100644 --- a/src/main/java/org/matsim/legacy/prepare/drt/DrtVehicleCreator.java +++ b/src/main/java/org/matsim/legacy/prepare/drt/DrtVehicleCreator.java @@ -80,44 +80,45 @@ public class DrtVehicleCreator { public static void main(String[] args) { - String networkFile = "https://svn.vsp.tu-berlin.de/repos/public-svn/matsim/scenarios/countries/de/berlin/berlin-v5.5-10pct/input/berlin-v5.5-network.xml.gz"; - String populationFile = "https://svn.vsp.tu-berlin.de/repos/public-svn/matsim/scenarios/countries/de/berlin/berlin-v5.5-10pct/input/berlin-v5.5-10pct.plans.xml.gz"; - String facilitiesFile = ""; - String drtServiceAreaShapeFile = "https://svn.vsp.tu-berlin.de/repos/public-svn/matsim/scenarios/countries/de/berlin/berlin-v5.5-10pct/input/berlin-shp/berlin.shp"; - CoordinateTransformation ct = TransformationFactory.getCoordinateTransformation("EPSG:31468", "EPSG:31468"); + String networkFile = "https://svn.vsp.tu-berlin.de/repos/public-svn/matsim/scenarios/countries/de/berlin/berlin-v6.1/input/berlin-v6.1-network-with-pt.xml.gz"; +// String populationFile = ""; +// String facilitiesFile = ""; + String drtServiceAreaShapeFile = "https://svn.vsp.tu-berlin.de/repos/public-svn/matsim/scenarios/countries/de/berlin/berlin-v6.1/input/shp/Berlin_25832.shp"; + String scenarioCrs = "EPSG:25832"; + String shapeCrs = "EPSG:25832"; -// String vehiclesFilePrefix = "berlin-drt-v5.5.spandau_b-drt-by-actLocations-sqrt-"; - String vehiclesFilePrefix = "berlin-drt-v5.5.drt-by-rndLocations-"; +// String vehiclesFilePrefix = "berlin-v6.1.spandau_b-drt-by-actLocations-sqrt-"; + String vehiclesFilePrefix = "berlin-v6.1.drt-by-rndLocations-"; Set numbersOfVehicles = new HashSet<>(); - numbersOfVehicles.add(20); - numbersOfVehicles.add(30); - numbersOfVehicles.add(50); - numbersOfVehicles.add(80); +// numbersOfVehicles.add(20); +// numbersOfVehicles.add(30); +// numbersOfVehicles.add(50); +// numbersOfVehicles.add(80); numbersOfVehicles.add(100); - numbersOfVehicles.add(120); - numbersOfVehicles.add(150); - numbersOfVehicles.add(200); - numbersOfVehicles.add(250); - numbersOfVehicles.add(300); - numbersOfVehicles.add(400); - numbersOfVehicles.add(500); - numbersOfVehicles.add(600); - numbersOfVehicles.add(700); - numbersOfVehicles.add(800); - numbersOfVehicles.add(900); - numbersOfVehicles.add(1000); - numbersOfVehicles.add(1200); - numbersOfVehicles.add(1500); - numbersOfVehicles.add(2000); - numbersOfVehicles.add(2500); - numbersOfVehicles.add(3000); - numbersOfVehicles.add(4000); - numbersOfVehicles.add(5000); - numbersOfVehicles.add(10000); +// numbersOfVehicles.add(120); +// numbersOfVehicles.add(150); +// numbersOfVehicles.add(200); +// numbersOfVehicles.add(250); +// numbersOfVehicles.add(300); +// numbersOfVehicles.add(400); +// numbersOfVehicles.add(500); +// numbersOfVehicles.add(600); +// numbersOfVehicles.add(700); +// numbersOfVehicles.add(800); +// numbersOfVehicles.add(900); +// numbersOfVehicles.add(1000); +// numbersOfVehicles.add(1200); +// numbersOfVehicles.add(1500); +// numbersOfVehicles.add(2000); +// numbersOfVehicles.add(2500); +// numbersOfVehicles.add(3000); +// numbersOfVehicles.add(4000); +// numbersOfVehicles.add(5000); +// numbersOfVehicles.add(10000); int seats = 4; - DrtVehicleCreator tvc = new DrtVehicleCreator(networkFile, drtServiceAreaShapeFile, ct); + DrtVehicleCreator tvc = new DrtVehicleCreator(networkFile, drtServiceAreaShapeFile, shapeCrs, scenarioCrs); // tvc.setLinkWeightsByActivities(populationFile, facilitiesFile); // tvc.setWeightsToSquareRoot(); for (int numberOfVehicles: numbersOfVehicles) { @@ -126,10 +127,11 @@ public static void main(String[] args) { } } - public DrtVehicleCreator(String networkfile, String drtServiceAreaShapeFile, CoordinateTransformation ct) { - this.ct = ct; + public DrtVehicleCreator(String networkfile, String drtServiceAreaShapeFile, String shapeCrs, String scenarioCrs) { + this.ct = TransformationFactory.getCoordinateTransformation(shapeCrs, scenarioCrs); Config config = ConfigUtils.createConfig(); + config.global().setCoordinateSystem(scenarioCrs); config.network().setInputFile(networkfile); this.scenario = ScenarioUtils.loadScenario(config); diff --git a/src/main/java/org/matsim/legacy/run/drt/OpenBerlinIntermodalPtDrtRouterAnalysisModeIdentifier.java b/src/main/java/org/matsim/legacy/run/drt/OpenBerlinIntermodalPtDrtRouterAnalysisModeIdentifier.java index 643222c7..7f4d228d 100644 --- a/src/main/java/org/matsim/legacy/run/drt/OpenBerlinIntermodalPtDrtRouterAnalysisModeIdentifier.java +++ b/src/main/java/org/matsim/legacy/run/drt/OpenBerlinIntermodalPtDrtRouterAnalysisModeIdentifier.java @@ -52,7 +52,7 @@ public OpenBerlinIntermodalPtDrtRouterAnalysisModeIdentifier() { drtModes = Arrays.asList(TransportMode.drt, "drt2", "drt_teleportation"); modeHierarchy.add( TransportMode.walk ) ; - modeHierarchy.add( "bicycle" ); // TransportMode.bike is not registered as main mode, only "bicycle" ; + modeHierarchy.add( TransportMode.bike ); // TransportMode.bike is not registered as main mode, only "bicycle" ; modeHierarchy.add( TransportMode.ride ) ; modeHierarchy.add( TransportMode.car ) ; modeHierarchy.add( "car2" ) ; @@ -61,6 +61,7 @@ public OpenBerlinIntermodalPtDrtRouterAnalysisModeIdentifier() { } modeHierarchy.add( TransportMode.pt ) ; modeHierarchy.add( "freight" ); + modeHierarchy.add( "truck" ); // NOTE: This hierarchical stuff is not so great: is park-n-ride a car trip or a pt trip? Could weigh it by distance, or by time spent // in respective mode. Or have combined modes as separate modes. In any case, can't do it at the leg level, since it does not diff --git a/src/main/java/org/matsim/legacy/run/drt/OpenBerlinIntermodalPtDrtRouterModeIdentifier.java b/src/main/java/org/matsim/legacy/run/drt/OpenBerlinIntermodalPtDrtRouterModeIdentifier.java index 504e0d3b..0f9fe842 100644 --- a/src/main/java/org/matsim/legacy/run/drt/OpenBerlinIntermodalPtDrtRouterModeIdentifier.java +++ b/src/main/java/org/matsim/legacy/run/drt/OpenBerlinIntermodalPtDrtRouterModeIdentifier.java @@ -48,7 +48,7 @@ public OpenBerlinIntermodalPtDrtRouterModeIdentifier() { drtModes = Arrays.asList(TransportMode.drt, "drt2", "drt_teleportation"); modeHierarchy.add( TransportMode.walk ) ; - modeHierarchy.add( "bicycle" ); // TransportMode.bike is not registered as main mode, only "bicycle" ; + modeHierarchy.add( TransportMode.bike ); modeHierarchy.add( TransportMode.ride ) ; modeHierarchy.add( TransportMode.car ) ; modeHierarchy.add( "car2" ) ; diff --git a/src/main/java/org/matsim/run/OpenBerlinDrtScenario.java b/src/main/java/org/matsim/run/OpenBerlinDrtScenario.java new file mode 100644 index 00000000..24e9f5b6 --- /dev/null +++ b/src/main/java/org/matsim/run/OpenBerlinDrtScenario.java @@ -0,0 +1,262 @@ +/* *********************************************************************** * + * project: org.matsim.* + * Controler.java + * * + * *********************************************************************** * + * * + * copyright : (C) 2007 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.run; + +import ch.sbb.matsim.config.SwissRailRaptorConfigGroup; +import ch.sbb.matsim.routing.pt.raptor.RaptorIntermodalAccessEgress; +import com.beust.jcommander.internal.Lists; +import com.google.common.collect.ImmutableSet; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.application.MATSimApplication; +import org.matsim.contrib.drt.routing.DrtRoute; +import org.matsim.contrib.drt.routing.DrtRouteFactory; +import org.matsim.contrib.drt.run.DrtConfigGroup; +import org.matsim.contrib.drt.run.DrtConfigs; +import org.matsim.contrib.drt.run.MultiModeDrtConfigGroup; +import org.matsim.contrib.drt.run.MultiModeDrtModule; +import org.matsim.contrib.dvrp.run.DvrpConfigGroup; +import org.matsim.contrib.dvrp.run.DvrpModule; +import org.matsim.contrib.dvrp.run.DvrpQSimComponents; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigGroup; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.QSimConfigGroup; +import org.matsim.core.config.groups.ScoringConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.population.routes.RouteFactories; +import org.matsim.core.router.AnalysisMainModeIdentifier; +import org.matsim.core.router.MainModeIdentifier; +import org.matsim.extensions.pt.fare.intermodalTripFareCompensator.IntermodalTripFareCompensatorConfigGroup; +import org.matsim.extensions.pt.fare.intermodalTripFareCompensator.IntermodalTripFareCompensatorsConfigGroup; +import org.matsim.extensions.pt.fare.intermodalTripFareCompensator.IntermodalTripFareCompensatorsModule; +import org.matsim.extensions.pt.routing.EnhancedRaptorIntermodalAccessEgress; +import org.matsim.extensions.pt.routing.ptRoutingModes.PtIntermodalRoutingModesConfigGroup; +import org.matsim.extensions.pt.routing.ptRoutingModes.PtIntermodalRoutingModesModule; +import org.matsim.legacy.run.BerlinExperimentalConfigGroup; +import org.matsim.legacy.run.drt.BerlinShpUtils; +import org.matsim.legacy.run.drt.OpenBerlinIntermodalPtDrtRouterAnalysisModeIdentifier; +import org.matsim.legacy.run.drt.OpenBerlinIntermodalPtDrtRouterModeIdentifier; +import org.matsim.legacy.run.drt.RunDrtOpenBerlinScenario; +import org.matsim.pt.transitSchedule.api.TransitSchedule; +import org.matsim.pt.transitSchedule.api.TransitStopFacility; +import picocli.CommandLine; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * Extend the {@link OpenBerlinScenario} by DRT functionality.
+ * By default, a config is loaded where a drt mode is operated in all of Berlin with 10,000 vehicles.
+ * Alternatively, you can provide another drt-only config using the {@code --drt-config} comand line option.
+ * This run script then configures drt to be perceived just like pt and to be fully tariff-integrated into pt.
+ */ +public class OpenBerlinDrtScenario extends OpenBerlinScenario{ + + //TODO: write tests + + private static final Logger log = LogManager.getLogger(OpenBerlinDrtScenario.class); + + @CommandLine.Option(names = "--drt-config", + defaultValue = "input/v6.1/berlin-v6.1.drt-config.xml", + description = "Path to drt (only) config. Should contain only additional stuff to base config. Otherwise overrides.") + private String drtConfig; + + public static void main(String[] args) { + MATSimApplication.run(OpenBerlinDrtScenario.class, args); + } + + @Override + protected List getCustomModules() { + List customModules = super.getCustomModules(); + customModules.addAll(Lists.newArrayList( + new BerlinExperimentalConfigGroup(), + new DvrpConfigGroup(), + new MultiModeDrtConfigGroup(), + new SwissRailRaptorConfigGroup(), + new IntermodalTripFareCompensatorsConfigGroup(), + new PtIntermodalRoutingModesConfigGroup())); + return customModules; + } + + @Override + protected Config prepareConfig(Config config) { + super.prepareConfig(config); + + ConfigUtils.loadConfig(config, drtConfig); + + //modify output directory and runId + config.controller().setOutputDirectory(config.controller().getOutputDirectory() + "-drt"); + config.controller().setRunId(config.controller().getRunId() + "-drt"); + + //drt only works with the following sim start time interpretation + config.qsim().setSimStarttimeInterpretation(QSimConfigGroup.StarttimeInterpretation.onlyUseStarttime); + + MultiModeDrtConfigGroup multiModeDrtCfg = MultiModeDrtConfigGroup.get(config); + DrtConfigs.adjustMultiModeDrtConfig(multiModeDrtCfg, config.scoring(), config.routing()); + + Set drtModes = new HashSet<>(); + + ScoringConfigGroup.ModeParams ptParams = config.scoring().getModes().get(TransportMode.pt); + IntermodalTripFareCompensatorsConfigGroup compensatorsConfig = ConfigUtils.addOrGetModule(config, IntermodalTripFareCompensatorsConfigGroup.class); + + for (DrtConfigGroup drtCfg : multiModeDrtCfg.getModalElements()) { + drtModes.add(drtCfg.getMode()); + + //copy all scoring params from pt + ScoringConfigGroup.ModeParams modeParams = new ScoringConfigGroup.ModeParams(drtCfg.getMode()); + modeParams.setConstant(ptParams.getConstant()); + modeParams.setMarginalUtilityOfDistance(ptParams.getMarginalUtilityOfDistance()); + modeParams.setMarginalUtilityOfTraveling(ptParams.getMarginalUtilityOfTraveling()); + modeParams.setDailyUtilityConstant(ptParams.getDailyUtilityConstant()); + + //assume that the drt is fully integrated in pt, i.e. fare integration + modeParams.setMonetaryDistanceRate(ptParams.getMonetaryDistanceRate()); + modeParams.setDailyMonetaryConstant(ptParams.getDailyMonetaryConstant()); + config.scoring().addModeParams(modeParams); + } + + //assume that (all) the drt is fully integrated in pt, i.e. fare integration + IntermodalTripFareCompensatorConfigGroup drtCompensationCfg = new IntermodalTripFareCompensatorConfigGroup(); + drtCompensationCfg.setCompensationCondition(IntermodalTripFareCompensatorConfigGroup.CompensationCondition.PtModeUsedAnywhereInTheDay); + drtCompensationCfg.setCompensationMoneyPerDay(ptParams.getDailyMonetaryConstant()); + drtCompensationCfg.setNonPtModes(ImmutableSet + .builder() + .addAll(drtModes) + .build()); + compensatorsConfig.addParameterSet(drtCompensationCfg); + + //include drt in mode-choice and add mode params. + //by using a Set, it should be assured that they aren't included twice. + drtModes.addAll(Arrays.asList(config.subtourModeChoice().getModes())); + config.subtourModeChoice().setModes(drtModes.toArray(String[]::new)); + + //Here (or when extending this class), you can configure the dvrp and the drt config groups. + //Of course you can configure on the xml (config) level, alternatively. + //for example you can configure prices and compensations, service area etc., + //whether dvrp modes should operate on a mode-specific sub-network or on the entire car-network, + //how the time-constraints for the dispatch should be parameterized etc. + + return config; + } + + @Override + protected void prepareScenario(Scenario scenario) { + super.prepareScenario(scenario); + + //if the input plans contain DrtRoutes, this will cause problems later in the DrtRouteFactory + //to avoid this, the DrtRouteFactory would have to get set before loading the scenario, just like in Open Berlin v5.x + RouteFactories routeFactories = scenario.getPopulation().getFactory().getRouteFactories(); + routeFactories.setRouteFactory(DrtRoute.class, new DrtRouteFactory()); + + //if the drt mode is configured as a dvrp network mode and if it has a service area + //the drt mode is added to the links in the service area with a buffer of +2000 meter (per default or otherwise configured in BerlinExperimentalConfigGroup) + //and transit stops 200m around the service area are tagged to be be served by the corresponding drt. + prepareNetworkAndTransitScheduleForDrt(scenario); + + //Here (or when extending this class), you can mutate the scenario (e.g. population, network, ...) + } + + @Override + protected void prepareControler(Controler controler) { + super.prepareControler(controler); + + // drt + dvrp modules + controler.addOverridingModule(new MultiModeDrtModule()); + controler.addOverridingModule(new DvrpModule()); + controler.configureQSimComponents(DvrpQSimComponents.activateAllModes(MultiModeDrtConfigGroup.get(controler.getConfig()))); + + controler.addOverridingModule(new AbstractModule() { + + @Override + public void install() { + bind(AnalysisMainModeIdentifier.class).to(OpenBerlinIntermodalPtDrtRouterAnalysisModeIdentifier.class); + bind(MainModeIdentifier.class).to(OpenBerlinIntermodalPtDrtRouterModeIdentifier.class); + bind(RaptorIntermodalAccessEgress.class).to(EnhancedRaptorIntermodalAccessEgress.class); + + } + }); + + // yyyy there is fareSModule (with S) in config. ?!?! kai, jul'19 + controler.addOverridingModule(new IntermodalTripFareCompensatorsModule()); + controler.addOverridingModule(new PtIntermodalRoutingModesModule()); + } + + /** + * This code is copied from matsim-berlin v5.x {@code RunDrtOpenBerlinScenario.prepareScenario()} and sub-methods. + * @param scenario network and transit schedule are mutated as side effects. + */ + private static void prepareNetworkAndTransitScheduleForDrt(Scenario scenario) { + BerlinExperimentalConfigGroup berlinCfg = ConfigUtils.addOrGetModule(scenario.getConfig(), BerlinExperimentalConfigGroup.class); + DvrpConfigGroup dvrpConfigGroup = DvrpConfigGroup.get(scenario.getConfig()); + + for (DrtConfigGroup drtCfg : MultiModeDrtConfigGroup.get(scenario.getConfig()).getModalElements()) { + String drtServiceAreaShapeFile = drtCfg.drtServiceAreaShapeFile; + if (drtServiceAreaShapeFile != null && !drtServiceAreaShapeFile.equals("") && !drtServiceAreaShapeFile.equals("null")) { + + if (dvrpConfigGroup.networkModes.contains(drtCfg.getMode())){ + // Michal says restricting drt to a drt network roughly the size of the service area helps to speed up. + // This is even more true since drt started to route on a freespeed TT matrix (Nov '20). + // A buffer of 10km to the service area Berlin includes the A10 on some useful stretches outside Berlin. + if (berlinCfg.getTagDrtLinksBufferAroundServiceAreaShp() >= 0.0) { + //TODO: inline/move method ? + RunDrtOpenBerlinScenario.addDRTmode(scenario, drtCfg.getMode(), drtServiceAreaShapeFile, berlinCfg.getTagDrtLinksBufferAroundServiceAreaShp()); + } + } + + tagTransitStopsInServiceArea(scenario.getTransitSchedule(), + "drtStopFilter", "station_S/U/RE/RB_drtServiceArea", + drtServiceAreaShapeFile, + "stopFilter", "station_S/U/RE/RB", + // some S+U stations are located slightly outside the shp File, e.g. U7 Neukoelln, U8 + // Hermannstr., so allow buffer around the shape. + // This does not mean that a drt vehicle can pick the passenger up outside the service area, + // rather the passenger has to walk the last few meters from the drt drop off to the station. + 200.0); + } + } + } + + private static void tagTransitStopsInServiceArea(TransitSchedule transitSchedule, + String newAttributeName, String newAttributeValue, + String drtServiceAreaShapeFile, + String oldFilterAttribute, String oldFilterValue, + double bufferAroundServiceArea) { + log.info("Tagging pt stops marked for intermodal access/egress in the service area."); + BerlinShpUtils shpUtils = new BerlinShpUtils(drtServiceAreaShapeFile); + for (TransitStopFacility stop : transitSchedule.getFacilities().values()) { + if (stop.getAttributes().getAttribute(oldFilterAttribute) != null) { + if (stop.getAttributes().getAttribute(oldFilterAttribute).equals(oldFilterValue)) { + if (shpUtils.isCoordInDrtServiceAreaWithBuffer(stop.getCoord(), bufferAroundServiceArea)) { + stop.getAttributes().putAttribute(newAttributeName, newAttributeValue); + } + } + } + } + } + + +}