diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 9fa228d5..eca85b37 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -103,4 +103,4 @@ jobs: path: staging env: - MAVEN_OPTS: -Xmx10G \ No newline at end of file + MAVEN_OPTS: -Xmx512m \ No newline at end of file diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 4ef94b1d..55ba46d1 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -17,4 +17,4 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} env: - MAVEN_OPTS: -Xmx10G \ No newline at end of file + MAVEN_OPTS: -Xmx512m \ No newline at end of file diff --git a/.gitignore b/.gitignore index eb435ff8..93e8b24a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,11 @@ # Add own ignores on top, don't edit the template +input/*stops.xml +input/*stops.csv +*.Rhistory +*.RProj + + # Common files to ignore when working with matsim diff --git a/Makefile b/Makefile index 12a29f6f..07b722f2 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ osmosis := osmosis/bin/osmosis NETWORK := germany-220327.osm.pbf germany := ../shared-svn/projects/matsim-germany -shared := ../shared-svn/projects/NaMAV +shared ?= ../shared-svn/projects/NaMAV .PHONY: prepare @@ -70,13 +70,13 @@ input/sumo.net.xml: input/network.osm input/$V/leipzig-$V-network.xml.gz: input/sumo.net.xml - $(sc) prepare network-from-sumo $< --output $@ + $(sc) prepare network-from-sumo $< --output $@ --free-speed-factor 0.75 $(sc) prepare fix-network $@ --output $@ $(sc) prepare clean-network $@ --output $@ --modes bike input/$V/leipzig-$V-network-with-pt.xml.gz: input/$V/leipzig-$V-network.xml.gz input/gtfs-lvb.zip $(sc) prepare transit-from-gtfs --network $< $(filter-out $<,$^)\ - --name leipzig-$V --date "2019-06-05" --target-crs $(CRS)\ + --name leipzig-$V --date "2023-04-19" --target-crs $(CRS)\ --output input/$V $(sc) prepare prepare-transit-schedule\ @@ -90,27 +90,28 @@ input/plans-longHaulFreight.xml.gz: input/$V/leipzig-$V-network.xml.gz --input-crs $(CRS)\ --target-crs $(CRS)\ --shp ../shared-svn/projects/NaMAV/data/shapefiles/freight-area/freight-area.shp\ + --cut-on-boundary\ --output $@ -input/plans-commercialTraffic.xml.gz: +input/plans-completeSmallScaleCommercialTraffic.xml.gz: $(sc) prepare generate-small-scale-commercial-traffic\ input/commercialTraffic\ --sample 0.25\ --jspritIterations 1\ --creationOption createNewCarrierFile\ --landuseConfiguration useOSMBuildingsAndLanduse\ - --trafficType commercialTraffic\ + --smallScaleCommercialTrafficType completeSmallScaleCommercialTraffic\ --zoneShapeFileName $(shared)/data/input-commercialTraffic/leipzig_zones_25832.shp\ --buildingsShapeFileName $(shared)/data/input-commercialTraffic/leipzig_buildings_25832.shp\ --landuseShapeFileName $(shared)/data/input-commercialTraffic/leipzig_landuse_25832.shp\ --shapeCRS "EPSG:25832"\ --resistanceFactor "0.005"\ --nameOutputPopulation $(notdir $@)\ - --PathOutput output/commercialTraffic + --pathOutput output/commercialTraffic mv output/commercialTraffic/$(notdir $@) $@ -input/$V/leipzig-$V-25pct.plans-initial.xml.gz: input/plans-longHaulFreight.xml.gz input/plans-commercialTraffic.xml.gz +input/$V/leipzig-$V-25pct.plans-initial.xml.gz: input/plans-longHaulFreight.xml.gz input/plans-completeSmallScaleCommercialTraffic.xml.gz $(sc) prepare trajectory-to-plans\ --name prepare --sample-size 0.25\ --max-typical-duration 0\ @@ -118,7 +119,7 @@ input/$V/leipzig-$V-25pct.plans-initial.xml.gz: input/plans-longHaulFreight.xml. --population $(shared)/matsim-input-files/senozon/20210520_leipzig/population.xml.gz\ --attributes $(shared)/matsim-input-files/senozon/20210520_leipzig/personAttributes.xml.gz - $(sc) prepare population input/prepare-25pct.plans.xml.gz\ + $(sc) prepare population input/prepare-25pct.plans.xml.gz --phase pre\ --shp $(shared)/matsim-input-files/senozon/20210520_leipzig/dilutionArea.shp --shp-crs $(CRS)\ --output input/prepare-25pct.plans.xml.gz @@ -143,11 +144,16 @@ input/$V/leipzig-$V-25pct.plans-initial.xml.gz: input/plans-longHaulFreight.xml. $(sc) prepare split-activity-types-duration\ --input input/prepare-25pct.plans-with-trips.xml.gz\ + --exclude commercial_start,commercial_end,freight_start,freight_end\ --output $@ - $(sc) prepare fix-subtour-modes --input $@ --coord-dist 100 --output $@ + $(sc) prepare merge-populations $@ $^ --output $@ - $(sc) prepare merge-populations $@ $< --output $@ + $(sc) prepare population $@ --phase post\ + --shp $(shared)/matsim-input-files/senozon/20210520_leipzig/dilutionArea.shp --shp-crs $(CRS)\ + --output $@ + + $(sc) prepare fix-subtour-modes --input $@ --coord-dist 100 --output $@ $(sc) prepare extract-home-coordinates $@ --csv input/$V/leipzig-$V-homes.csv @@ -166,8 +172,8 @@ check: input/$V/leipzig-$V-25pct.plans-initial.xml.gz $(sc) analysis check-population $<\ --input-crs $(CRS)\ --attribute carAvail\ - --shp ../shared-svn/projects/NaMAV/data/leipzig-utm32n/leipzig-utm32n.shp\ + --shp ../shared-svn/projects/NaMAV/data/shapefiles/leipzig-utm32n/leipzig-utm32n.shp\ # Aggregated target prepare: input/$V/leipzig-$V-25pct.plans-initial.xml.gz input/$V/leipzig-$V-network-with-pt.xml.gz - echo "Done" \ No newline at end of file + echo "Done" diff --git a/input/v1.2/drtServiceArea/preliminary-serviceArea-leipzig-utm32n.cpg b/input/v1.2/drtServiceArea/Leipzig_stadt.cpg similarity index 100% rename from input/v1.2/drtServiceArea/preliminary-serviceArea-leipzig-utm32n.cpg rename to input/v1.2/drtServiceArea/Leipzig_stadt.cpg diff --git a/input/v1.2/drtServiceArea/Leipzig_stadt.dbf b/input/v1.2/drtServiceArea/Leipzig_stadt.dbf new file mode 100644 index 00000000..c768f03d Binary files /dev/null and b/input/v1.2/drtServiceArea/Leipzig_stadt.dbf differ diff --git a/input/v1.2/drtServiceArea/preliminary-serviceArea-leipzig-utm32n.prj b/input/v1.2/drtServiceArea/Leipzig_stadt.prj similarity index 100% rename from input/v1.2/drtServiceArea/preliminary-serviceArea-leipzig-utm32n.prj rename to input/v1.2/drtServiceArea/Leipzig_stadt.prj diff --git a/input/v1.2/drtServiceArea/Leipzig_stadt.shp b/input/v1.2/drtServiceArea/Leipzig_stadt.shp new file mode 100644 index 00000000..81c592e1 Binary files /dev/null and b/input/v1.2/drtServiceArea/Leipzig_stadt.shp differ diff --git a/input/v1.2/drtServiceArea/Leipzig_stadt.shx b/input/v1.2/drtServiceArea/Leipzig_stadt.shx new file mode 100644 index 00000000..591b1878 Binary files /dev/null and b/input/v1.2/drtServiceArea/Leipzig_stadt.shx differ diff --git a/input/v1.2/drtServiceArea/leipzig_flexa_service_area_2021.cpg b/input/v1.2/drtServiceArea/leipzig_flexa_service_area_2021.cpg new file mode 100644 index 00000000..3ad133c0 --- /dev/null +++ b/input/v1.2/drtServiceArea/leipzig_flexa_service_area_2021.cpg @@ -0,0 +1 @@ +UTF-8 \ No newline at end of file diff --git a/input/v1.2/drtServiceArea/leipzig_flexa_service_area_2021.dbf b/input/v1.2/drtServiceArea/leipzig_flexa_service_area_2021.dbf new file mode 100644 index 00000000..20e71302 Binary files /dev/null and b/input/v1.2/drtServiceArea/leipzig_flexa_service_area_2021.dbf differ diff --git a/input/v1.2/drtServiceArea/leipzig_flexa_service_area_2021.prj b/input/v1.2/drtServiceArea/leipzig_flexa_service_area_2021.prj new file mode 100644 index 00000000..bd846aeb --- /dev/null +++ b/input/v1.2/drtServiceArea/leipzig_flexa_service_area_2021.prj @@ -0,0 +1 @@ +PROJCS["ETRS_1989_UTM_Zone_32N",GEOGCS["GCS_ETRS_1989",DATUM["D_ETRS_1989",SPHEROID["GRS_1980",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",500000.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",9.0],PARAMETER["Scale_Factor",0.9996],PARAMETER["Latitude_Of_Origin",0.0],UNIT["Meter",1.0]] \ No newline at end of file diff --git a/input/v1.2/drtServiceArea/leipzig_flexa_service_area_2021.shp b/input/v1.2/drtServiceArea/leipzig_flexa_service_area_2021.shp new file mode 100644 index 00000000..037b6b7d Binary files /dev/null and b/input/v1.2/drtServiceArea/leipzig_flexa_service_area_2021.shp differ diff --git a/input/v1.2/drtServiceArea/leipzig_flexa_service_area_2021.shx b/input/v1.2/drtServiceArea/leipzig_flexa_service_area_2021.shx new file mode 100644 index 00000000..547a740e Binary files /dev/null and b/input/v1.2/drtServiceArea/leipzig_flexa_service_area_2021.shx differ diff --git a/input/v1.2/drtServiceArea/preliminary-serviceArea-leipzig-utm32n.dbf b/input/v1.2/drtServiceArea/preliminary-serviceArea-leipzig-utm32n.dbf deleted file mode 100644 index fe21f612..00000000 Binary files a/input/v1.2/drtServiceArea/preliminary-serviceArea-leipzig-utm32n.dbf and /dev/null differ diff --git a/input/v1.2/drtServiceArea/preliminary-serviceArea-leipzig-utm32n.shp b/input/v1.2/drtServiceArea/preliminary-serviceArea-leipzig-utm32n.shp deleted file mode 100644 index 23fbbb3a..00000000 Binary files a/input/v1.2/drtServiceArea/preliminary-serviceArea-leipzig-utm32n.shp and /dev/null differ diff --git a/input/v1.2/drtServiceArea/preliminary-serviceArea-leipzig-utm32n.shx b/input/v1.2/drtServiceArea/preliminary-serviceArea-leipzig-utm32n.shx deleted file mode 100644 index 32c2fb6a..00000000 Binary files a/input/v1.2/drtServiceArea/preliminary-serviceArea-leipzig-utm32n.shx and /dev/null differ diff --git a/input/v1.2/leipzig-test.with-drt.config.xml b/input/v1.2/leipzig-test.with-drt.config.xml deleted file mode 100644 index 0c72c39e..00000000 --- a/input/v1.2/leipzig-test.with-drt.config.xml +++ /dev/null @@ -1,359 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/input/v1.2/leipzig-v1.2-25pct.config.xml b/input/v1.2/leipzig-v1.2-25pct.config.xml index d8de8daf..6c556cd0 100644 --- a/input/v1.2/leipzig-v1.2-25pct.config.xml +++ b/input/v1.2/leipzig-v1.2-25pct.config.xml @@ -19,32 +19,36 @@ - + - + + value="https://svn.vsp.tu-berlin.de/repos/public-svn/matsim/scenarios/countries/de/leipzig/leipzig-v1.2/input/leipzig-v1.2-25pct.plans-initial.xml.gz"/> - + + value="https://svn.vsp.tu-berlin.de/repos/public-svn/matsim/scenarios/countries/de/leipzig/leipzig-v1.2/input/leipzig-v1.2-transitSchedule.xml.gz"/> + value="https://svn.vsp.tu-berlin.de/repos/public-svn/matsim/scenarios/countries/de/leipzig/leipzig-v1.2/input/leipzig-v1.2-transitVehicles.xml.gz"/> + + + + @@ -57,11 +61,11 @@ + - @@ -70,11 +74,24 @@ - + + + + + + + + + + + + + + @@ -87,43 +104,26 @@ - - - - - - - - - - - - - - + + - + - - - - - - + @@ -149,45 +149,55 @@ + + - - - - - - + + + + + + - - - - - - + + + + + + + + - - - - - + + + + + - - - + + + + + - + + + + + - - + + @@ -199,113 +209,4 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + diff --git a/input/v1.2/leipzig-v1.2-25pct_prices2021.config.xml b/input/v1.2/leipzig-v1.2-25pct_prices2021.config.xml deleted file mode 100644 index 0bfe9fcc..00000000 --- a/input/v1.2/leipzig-v1.2-25pct_prices2021.config.xml +++ /dev/null @@ -1,311 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/input/v1.2/leipzig-v1.2-counts-car-bast.xml.gz b/input/v1.2/leipzig-v1.2-counts-car-bast.xml.gz new file mode 100644 index 00000000..b06a2be9 Binary files /dev/null and b/input/v1.2/leipzig-v1.2-counts-car-bast.xml.gz differ diff --git a/input/v1.2/leipzig-v1.2-counts-hgv-bast.xml.gz b/input/v1.2/leipzig-v1.2-counts-hgv-bast.xml.gz new file mode 100644 index 00000000..e54fb45b Binary files /dev/null and b/input/v1.2/leipzig-v1.2-counts-hgv-bast.xml.gz differ diff --git a/input/v1.2/leipzig-v1.2-drt.config.xml b/input/v1.2/leipzig-v1.2-drt.config.xml new file mode 100644 index 00000000..f003057a --- /dev/null +++ b/input/v1.2/leipzig-v1.2-drt.config.xml @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/input/v1.2/leipzig-v1.2-routes-ref.csv.gz b/input/v1.2/leipzig-v1.2-routes-ref.csv.gz new file mode 100644 index 00000000..c5f45fbc Binary files /dev/null and b/input/v1.2/leipzig-v1.2-routes-ref.csv.gz differ diff --git a/input/v1.2/parkingCostArea/Bewohnerparken_2020.cpg b/input/v1.2/parkingCostArea/Bewohnerparken_2020.cpg new file mode 100644 index 00000000..3ad133c0 --- /dev/null +++ b/input/v1.2/parkingCostArea/Bewohnerparken_2020.cpg @@ -0,0 +1 @@ +UTF-8 \ No newline at end of file diff --git a/input/v1.2/parkingCostArea/Bewohnerparken_2020.dbf b/input/v1.2/parkingCostArea/Bewohnerparken_2020.dbf new file mode 100644 index 00000000..69dff29a Binary files /dev/null and b/input/v1.2/parkingCostArea/Bewohnerparken_2020.dbf differ diff --git a/input/v1.2/parkingCostArea/Bewohnerparken_2020.prj b/input/v1.2/parkingCostArea/Bewohnerparken_2020.prj new file mode 100644 index 00000000..bd846aeb --- /dev/null +++ b/input/v1.2/parkingCostArea/Bewohnerparken_2020.prj @@ -0,0 +1 @@ +PROJCS["ETRS_1989_UTM_Zone_32N",GEOGCS["GCS_ETRS_1989",DATUM["D_ETRS_1989",SPHEROID["GRS_1980",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",500000.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",9.0],PARAMETER["Scale_Factor",0.9996],PARAMETER["Latitude_Of_Origin",0.0],UNIT["Meter",1.0]] \ No newline at end of file diff --git a/input/v1.2/parkingCostArea/Bewohnerparken_2020.qmd b/input/v1.2/parkingCostArea/Bewohnerparken_2020.qmd new file mode 100644 index 00000000..a18ad236 --- /dev/null +++ b/input/v1.2/parkingCostArea/Bewohnerparken_2020.qmd @@ -0,0 +1,26 @@ + + + + + + dataset + + + + + + + + + + 0 + 0 + + + + + false + + + + diff --git a/input/v1.2/parkingCostArea/Bewohnerparken_2020.shp b/input/v1.2/parkingCostArea/Bewohnerparken_2020.shp new file mode 100644 index 00000000..24c433fd Binary files /dev/null and b/input/v1.2/parkingCostArea/Bewohnerparken_2020.shp differ diff --git a/input/v1.2/parkingCostArea/Bewohnerparken_2020.shx b/input/v1.2/parkingCostArea/Bewohnerparken_2020.shx new file mode 100644 index 00000000..2dedd5b1 Binary files /dev/null and b/input/v1.2/parkingCostArea/Bewohnerparken_2020.shx differ diff --git a/pom.xml b/pom.xml index 320c70bd..33211c13 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,8 @@ org.matsim matsim-all - 16.0-PR2653 + 16.0-PR2745 + 4.0.0 @@ -111,6 +112,11 @@ ${matsim.version} compile + + org.matsim.contrib + drt-extensions + ${matsim.version} + org.matsim.contrib @@ -272,7 +278,7 @@ 1 false - @{argLine} -Xmx9500m -Djava.awt.headless=true -Dmatsim.preferLocalDtds=true + @{argLine} -Xmx6500m -Djava.awt.headless=true -Dmatsim.preferLocalDtds=true diff --git a/src/main/R/Analysis/srv.R b/src/main/R/Analysis/srv.R index 7c095772..2e427457 100644 --- a/src/main/R/Analysis/srv.R +++ b/src/main/R/Analysis/srv.R @@ -7,12 +7,12 @@ library(ggsci) library(sf) -# setwd("C:/Users/chris/Development/matsim-scenarios/matsim-leipzig/src/main/R") +# setwd("~/Development/matsim-scenarios/matsim-leipzig/src/main/R") # Person data from srv ############################ -persons <- read_delim("../../../../../shared-svn/projects/NaMAV/data/SrV_2018/SrV2018_Einzeldaten_Leipzig_LE_SciUse_P2018.csv", delim = ";", +persons <- read_delim("../../../../shared-svn/projects/NaMAV/data/SrV_2018/SrV2018_Einzeldaten_Leipzig_LE_SciUse_P2018.csv", delim = ";", locale = locale(decimal_mark = ",")) %>% filter(ST_CODE_NAME=="Leipzig") %>% filter(STICHTAG_WTAG <= 5) %>% @@ -29,7 +29,7 @@ tt <- per_day * 600000 # Trip data from srV ############################# -trips <- read_delim("../../../../../shared-svn/projects/NaMAV/data/SrV_2018/SrV2018_Einzeldaten_Leipzig_LE_SciUse_W2018.csv", delim = ";", +trips <- read_delim("../../../../shared-svn/projects/NaMAV/data/SrV_2018/SrV2018_Einzeldaten_Leipzig_LE_SciUse_W2018.csv", delim = ";", col_types = cols( V_ZIEL_LAND = col_character(), GIS_LAENGE = col_double(), @@ -51,10 +51,10 @@ breaks = c(0, 1, 3, 5, 10, 20, Inf) relevant <- trips %>% filter(ST_CODE_NAME=="Leipzig") %>% filter(E_HVM < 70) %>% - filter(V_VM_LAENG < 70) %>% - filter(GIS_LAENGE >= 0 & GIS_LAENGE_GUELTIG == -1) %>% + filter(GIS_LAENGE >= 0 & E_DAUER > 0) %>% + filter(GIS_LAENGE < 100) %>% filter(STICHTAG_WTAG <= 5) %>% - mutate(dist_group = cut(GIS_LAENGE, breaks=breaks, labels=levels, right=T)) + mutate(dist_group = cut(GIS_LAENGE, breaks=breaks, labels=levels, right=F)) matched <- relevant %>% left_join(lookup, by=c("E_HVM"="category")) diff --git a/src/main/java/org/matsim/analysis/ParkingLocation.java b/src/main/java/org/matsim/analysis/ParkingLocation.java new file mode 100644 index 00000000..2dbd797f --- /dev/null +++ b/src/main/java/org/matsim/analysis/ParkingLocation.java @@ -0,0 +1,121 @@ +package org.matsim.analysis; + +import org.matsim.api.core.v01.Coord; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.events.ActivityStartEvent; +import org.matsim.api.core.v01.events.handler.ActivityStartEventHandler; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.api.core.v01.population.Person; +import org.matsim.api.core.v01.population.Population; +import org.matsim.application.MATSimAppCommand; +import org.matsim.core.api.experimental.events.EventsManager; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.events.EventsUtils; +import org.matsim.core.events.MatsimEventsReader; +import org.matsim.core.network.NetworkUtils; +import org.matsim.core.population.PopulationUtils; +import org.matsim.core.utils.io.IOUtils; +import picocli.CommandLine; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static org.matsim.application.ApplicationUtils.globFile; + +/** + * Creates a tsv file donating the location of parking activities. + * Can be used for visualizations. + */ +public class ParkingLocation implements MATSimAppCommand { + + @CommandLine.Option(names = "--directory", description = "path to matsim output directory", required = true) + private Path directory; + + public static void main(String[] args) { + new ParkingLocation().execute(args); + } + + @Override + public Integer call() throws Exception { + Path eventsPath = globFile(directory, "*output_events.*"); + Path networkPath = globFile(directory, "*output_network.*"); + Path popPath = globFile(directory, "*output_plans.*"); + EventsManager manager = EventsUtils.createEventsManager(); + Network network = NetworkUtils.readNetwork(String.valueOf(networkPath)); + List listOfParkingActivities = new ArrayList<>(); + List> listOfRelevantPersons = new ArrayList<>(); + manager.addHandler(new ParkingActivities(listOfParkingActivities, network, listOfRelevantPersons)); + manager.initProcessing(); + MatsimEventsReader matsimEventsReader = new MatsimEventsReader(manager); + matsimEventsReader.readFile(eventsPath.toString()); + manager.finishProcessing(); + writeResults(directory, listOfParkingActivities); + + if (listOfRelevantPersons.size() > 0) { + Population population = PopulationUtils.readPopulation(String.valueOf(popPath)); + Population reducedPop = PopulationUtils.createPopulation(ConfigUtils.createConfig()); + for (Person p : population.getPersons().values()) { + if (listOfRelevantPersons.contains(p.getId())) { + reducedPop.addPerson(p); + } + } + PopulationUtils.writePopulation(reducedPop, directory.resolve("reducedPlans.xml").toString()); + } + + return null; + } + + private static void writeResults(Path outputFolder, List listOfParkingData) throws IOException { + BufferedWriter writer = IOUtils.getBufferedWriter(outputFolder.resolve("parkingActivities.tsv").toString()); + writer.write("personId\tx\ty\tlinkId"); + writer.newLine(); + for (ParkingData pd : listOfParkingData) { + writer.write(pd.personId + "\t" + pd.coord.getX() + "\t" + pd.coord.getY() + "\t" + pd.linkId); + writer.newLine(); + } + writer.close(); + + Map duplicateCountMap = listOfParkingData + .stream() + .collect( + Collectors.toMap(Function.identity(), company -> 1, Math::addExact) + ); + + BufferedWriter writerWithCounts = IOUtils.getBufferedWriter(outputFolder.resolve("parkingActivitiesWithCount.tsv").toString()); + + writerWithCounts.write(("x\ty\tlinkId\tcount")); + writerWithCounts.newLine(); + for (ParkingData parkingData : duplicateCountMap.keySet()) { + writerWithCounts.write(parkingData.coord.getX() + "\t" + parkingData.coord.getY() + "\t" + + parkingData.linkId + "\t" + duplicateCountMap.get(parkingData)); + writerWithCounts.newLine(); + } + writerWithCounts.close(); + } + + private record ParkingActivities(List listOfParkingData, Network network, List> listOfRelevantPersons) implements ActivityStartEventHandler { + + @Override + public void handleEvent(ActivityStartEvent activityStartEvent) { + if (activityStartEvent.getActType().equals("parking interaction")) { + Link l = network.getLinks().get(activityStartEvent.getLinkId()); + ParkingData pd = new ParkingData(activityStartEvent.getPersonId(), l.getCoord(), activityStartEvent.getLinkId()); + listOfParkingData.add(pd); + + if (l.getAttributes().getAttribute("linkParkingType") != null) { + listOfRelevantPersons.add(activityStartEvent.getPersonId()); + } + } + } + } + + private record ParkingData(Id personId, Coord coord, Id linkId) { + } +} diff --git a/src/main/java/org/matsim/dashboard/LeipzigDashboardProvider.java b/src/main/java/org/matsim/dashboard/LeipzigDashboardProvider.java new file mode 100644 index 00000000..8005f0cd --- /dev/null +++ b/src/main/java/org/matsim/dashboard/LeipzigDashboardProvider.java @@ -0,0 +1,30 @@ +package org.matsim.dashboard; + +import org.matsim.application.ApplicationUtils; +import org.matsim.core.config.Config; +import org.matsim.run.RunLeipzigScenario; +import org.matsim.simwrapper.Dashboard; +import org.matsim.simwrapper.DashboardProvider; +import org.matsim.simwrapper.SimWrapper; +import org.matsim.simwrapper.dashboard.TravelTimeComparisonDashboard; +import org.matsim.simwrapper.dashboard.TripDashboard; + +import java.util.List; + +/** + * Provider for default dashboards in the scenario. + * Declared in META-INF/services + */ +public class LeipzigDashboardProvider implements DashboardProvider { + + @Override + public List getDashboards(Config config, SimWrapper simWrapper) { + + TripDashboard trips = new TripDashboard("mode_share_ref.csv", "mode_share_per_dist_ref.csv", "mode_users_ref.csv"); + + return List.of(trips, + new TravelTimeComparisonDashboard(ApplicationUtils.resolve(config.getContext(), "leipzig-v" + RunLeipzigScenario.VERSION + "-routes-ref.csv.gz")) + ); + } + +} diff --git a/src/main/java/org/matsim/run/LeipzigPtFareModule.java b/src/main/java/org/matsim/run/LeipzigPtFareModule.java index d3601300..e1dd603e 100644 --- a/src/main/java/org/matsim/run/LeipzigPtFareModule.java +++ b/src/main/java/org/matsim/run/LeipzigPtFareModule.java @@ -13,6 +13,13 @@ */ public class LeipzigPtFareModule extends AbstractModule { + final double minFare = 2.0; + final int longDistanceThreshold = 50000; + final double normalTripSlope = 0.00017987993018495408; + final double longTripSlope = 0.000; + final double normalBaseFare = 2.4710702921120262; + final double longBaseFare = 18.90; + @Override public void install() { // Set the money related thing in the config (planCalcScore) file to 0. @@ -31,20 +38,20 @@ public void install() { // https://www.mdv.de/site/uploads/tarifzonenplan.pdf // Minimum fare (e.g. short trip or 1 zone ticket) - distanceBasedPtFareParams.setMinFare(2.0); + distanceBasedPtFareParams.setMinFare(minFare); // Division between long trip and short trip (unit: m) - distanceBasedPtFareParams.setLongDistanceTripThreshold(50000); + distanceBasedPtFareParams.setLongDistanceTripThreshold(longDistanceThreshold); // y = ax + b --> a value, for short trips - distanceBasedPtFareParams.setNormalTripSlope(0.00017987993018495408); + distanceBasedPtFareParams.setNormalTripSlope(normalTripSlope); // y = ax + b --> b value, for short trips - distanceBasedPtFareParams.setNormalTripIntercept(2.4710702921120262); + distanceBasedPtFareParams.setNormalTripIntercept(normalBaseFare); // Base price is the daily ticket for long trips // y = ax + b --> a value, for long trips - distanceBasedPtFareParams.setLongDistanceTripSlope(0.000); + distanceBasedPtFareParams.setLongDistanceTripSlope(longTripSlope); // y = ax + b --> b value, for long trips - distanceBasedPtFareParams.setLongDistanceTripIntercept(18.90); + distanceBasedPtFareParams.setLongDistanceTripIntercept(longBaseFare); // Add bindings @@ -55,4 +62,18 @@ public void install() { addControlerListenerBinding().toInstance(ptFareUpperBoundHandler); } } + + /** + * base fare for pt ride. + */ + public Double getNormalPtBaseFare() { + return normalBaseFare; + } + + /** + * distance based fare for pt ride. + */ + public Double getNormalDistanceBasedFare() { + return normalTripSlope; + } } diff --git a/src/main/java/org/matsim/run/LeipzigRouterPlanAlgorithm.java b/src/main/java/org/matsim/run/LeipzigRouterPlanAlgorithm.java index 6644dc1e..c3bd8ee1 100644 --- a/src/main/java/org/matsim/run/LeipzigRouterPlanAlgorithm.java +++ b/src/main/java/org/matsim/run/LeipzigRouterPlanAlgorithm.java @@ -5,10 +5,10 @@ import org.matsim.api.core.v01.TransportMode; import org.matsim.api.core.v01.network.Link; import org.matsim.api.core.v01.network.Network; -import org.matsim.api.core.v01.network.Node; import org.matsim.api.core.v01.population.*; +import org.matsim.contrib.vsp.scenario.SnzActivities; import org.matsim.core.controler.PersonPrepareForSimAlgorithm; -import org.matsim.core.network.NetworkUtils; +import org.matsim.core.network.filter.NetworkFilterManager; import org.matsim.core.population.algorithms.PlanAlgorithm; import org.matsim.core.population.algorithms.XY2Links; import org.matsim.core.router.MultimodalLinkChooser; @@ -20,7 +20,6 @@ import org.matsim.facilities.ActivityFacilities; import org.matsim.facilities.FacilitiesUtils; import org.matsim.facilities.Facility; -import playground.vsp.openberlinscenario.cemdap.output.ActivityTypes; import java.util.ArrayList; import java.util.List; @@ -47,20 +46,22 @@ final class LeipzigRouterPlanAlgorithm implements PlanAlgorithm, PersonPrepareFo this.timeInterpretation = timeInterpretation; this.scenario = scenario; this.fullModalNetwork = singleModeNetworksCache.getSingleModeNetworksCache().get(TransportMode.car); + this.linkChooser = linkChooser; + // yyyy one should look at the networks cache and see how the following is done. And maybe even register it there. - this.reducedNetwork = NetworkUtils.createNetwork(scenario.getConfig().network()); - this.linkChooser = linkChooser; - for (Node node : this.fullModalNetwork.getNodes().values()) { - reducedNetwork.addNode(node); - } - for (Link link : this.fullModalNetwork.getLinks().values()) { - if (!LeipzigUtils.isLinkParkingTypeInsideResidentialArea(link)) { - reducedNetwork.addLink(link); - } - } + NetworkFilterManager networkFilterManager = new NetworkFilterManager(fullModalNetwork, scenario.getConfig().network()); + + networkFilterManager.addLinkFilter(link -> !LeipzigUtils.isLinkParkingTypeInsideResidentialArea(link)); + + // keep all nodes that have no in and out links inside parking area + // otherwise nearest link might crash if it finds an empty node + networkFilterManager.addNodeFilter(n -> + n.getInLinks().values().stream().noneMatch(LeipzigUtils::isLinkParkingTypeInsideResidentialArea) && + n.getOutLinks().values().stream().noneMatch(LeipzigUtils::isLinkParkingTypeInsideResidentialArea)); - xy2Links = new XY2Links(fullModalNetwork, scenario.getActivityFacilities()); + this.reducedNetwork = networkFilterManager.applyFilters(); + this.xy2Links = new XY2Links(fullModalNetwork, scenario.getActivityFacilities()); } private static LeipzigUtils.PersonParkingBehaviour getParkingBehaviour(Network fullModalNetwork, Activity originActivity, String routingMode) { @@ -71,7 +72,9 @@ private static LeipzigUtils.PersonParkingBehaviour getParkingBehaviour(Network f // an dieser stelle waere es besser abzufragen, ob die person in der naehe wohnt anstatt nur die home act -> residential parking zuzuordnen // check if non-home activity (since otherwise we assume that there is no parking restriction): - if (!originActivity.getType().equals(ActivityTypes.HOME)) { + if (!originActivity.getType().startsWith(SnzActivities.home.name()) && + !originActivity.getType().startsWith(SnzActivities.shop_daily.name()) && + !originActivity.getType().startsWith(SnzActivities.shop_other.name())) { Link link = fullModalNetwork.getLinks().get(originActivity.getLinkId()); if (isLinkParkingTypeInsideResidentialArea(link)) { diff --git a/src/main/java/org/matsim/run/LeipzigSubtourModeChoice.java b/src/main/java/org/matsim/run/LeipzigSubtourModeChoice.java new file mode 100644 index 00000000..bbec7421 --- /dev/null +++ b/src/main/java/org/matsim/run/LeipzigSubtourModeChoice.java @@ -0,0 +1,62 @@ +package org.matsim.run; + +import jakarta.inject.Inject; +import jakarta.inject.Provider; +import org.matsim.api.core.v01.Scenario; +import org.matsim.core.config.groups.GlobalConfigGroup; +import org.matsim.core.config.groups.SubtourModeChoiceConfigGroup; +import org.matsim.core.population.algorithms.PermissibleModesCalculator; +import org.matsim.core.population.algorithms.PlanAlgorithm; +import org.matsim.core.replanning.PlanStrategy; +import org.matsim.core.replanning.PlanStrategyImpl; +import org.matsim.core.replanning.modules.AbstractMultithreadedModule; +import org.matsim.core.replanning.selectors.RandomPlanSelector; +import org.matsim.core.router.MultimodalLinkChooser; +import org.matsim.core.router.SingleModeNetworksCache; +import org.matsim.core.router.TripRouter; +import org.matsim.core.utils.timing.TimeInterpretation; +import org.matsim.facilities.ActivityFacilities; + +/** + * Standard subtour mode choice, but replaced the re-routing. + */ +public class LeipzigSubtourModeChoice implements Provider { + + public static final String STRATEGY_NAME = "SubTourModeChoiceLeipzig"; + + @Inject + private Provider tripRouterProvider; + @Inject + private GlobalConfigGroup globalConfigGroup; + @Inject + private SubtourModeChoiceConfigGroup subtourModeChoiceConfigGroup; + @Inject + private ActivityFacilities facilities; + @Inject + private PermissibleModesCalculator permissibleModesCalculator; + @Inject + private TimeInterpretation timeInterpretation; + @Inject + private SingleModeNetworksCache singleModeNetworksCache; + @Inject + private Scenario scenario; + @Inject + private MultimodalLinkChooser linkChooser; + + @Override + public PlanStrategy get() { + PlanStrategyImpl.Builder builder = new PlanStrategyImpl.Builder(new RandomPlanSelector<>()); + builder.addStrategyModule(new org.matsim.core.replanning.modules.SubtourModeChoice(globalConfigGroup, subtourModeChoiceConfigGroup, permissibleModesCalculator)); + + // Re-routing + builder.addStrategyModule(new AbstractMultithreadedModule(globalConfigGroup) { + @Override + public PlanAlgorithm getPlanAlgoInstance() { + return new LeipzigRouterPlanAlgorithm(tripRouterProvider.get(), facilities, timeInterpretation, singleModeNetworksCache, scenario, linkChooser); + } + }); + + return builder.build(); + } + +} diff --git a/src/main/java/org/matsim/run/RunLeipzigScenario.java b/src/main/java/org/matsim/run/RunLeipzigScenario.java index 285d9f52..cceec884 100644 --- a/src/main/java/org/matsim/run/RunLeipzigScenario.java +++ b/src/main/java/org/matsim/run/RunLeipzigScenario.java @@ -1,12 +1,6 @@ package org.matsim.run; -import ch.sbb.matsim.config.SwissRailRaptorConfigGroup; -import ch.sbb.matsim.routing.pt.raptor.RaptorIntermodalAccessEgress; -import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; -import com.google.inject.Singleton; -import com.google.inject.TypeLiteral; -import com.google.inject.multibindings.Multibinder; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.matsim.analysis.*; @@ -14,9 +8,6 @@ import org.matsim.analysis.pt.stop2stop.PtStop2StopAnalysisModule; import org.matsim.api.core.v01.Scenario; import org.matsim.api.core.v01.TransportMode; -import org.matsim.api.core.v01.network.Link; -import org.matsim.api.core.v01.population.Person; -import org.matsim.api.core.v01.population.Plan; import org.matsim.application.MATSimApplication; import org.matsim.application.analysis.CheckPopulation; import org.matsim.application.analysis.noise.NoiseAnalysis; @@ -33,42 +24,29 @@ import org.matsim.application.prepare.pt.CreateTransitScheduleFromGtfs; import org.matsim.contrib.bicycle.BicycleConfigGroup; import org.matsim.contrib.bicycle.BicycleModule; -import org.matsim.contrib.drt.fare.DrtFareParams; -import org.matsim.contrib.drt.routing.DrtRoute; -import org.matsim.contrib.drt.routing.DrtRouteFactory; -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.contrib.vsp.scenario.SnzActivities; import org.matsim.core.config.Config; import org.matsim.core.config.ConfigUtils; import org.matsim.core.config.groups.*; import org.matsim.core.controler.AbstractModule; import org.matsim.core.controler.Controler; -import org.matsim.core.replanning.choosers.ForceInnovationStrategyChooser; -import org.matsim.core.replanning.choosers.StrategyChooser; +import org.matsim.core.population.algorithms.PermissibleModesCalculator; +import org.matsim.core.population.algorithms.PermissibleModesCalculatorImpl; import org.matsim.core.replanning.strategies.DefaultPlanStrategiesModule; import org.matsim.core.router.AnalysisMainModeIdentifier; import org.matsim.core.router.MultimodalLinkChooser; import org.matsim.core.router.TripStructureUtils; import org.matsim.core.scoring.functions.ScoringParametersForPerson; -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.run.prepare.*; +import org.matsim.simwrapper.SimWrapperConfigGroup; import org.matsim.simwrapper.SimWrapperModule; -import org.matsim.smallScaleCommercialTrafficGeneration.CreateSmallScaleCommercialTrafficDemand; +import org.matsim.smallScaleCommercialTrafficGeneration.GenerateSmallScaleCommercialTrafficDemand; import picocli.CommandLine; import playground.vsp.scoring.IncomeDependentUtilityOfMoneyPersonScoringParameters; import playground.vsp.simpleParkingCostHandler.ParkingCostConfigGroup; import javax.annotation.Nullable; +import java.net.URISyntaxException; import java.util.*; /** @@ -81,7 +59,7 @@ MergePopulations.class, ExtractRelevantFreightTrips.class, DownSamplePopulation.class, PrepareNetwork.class, CleanNetwork.class, CreateLandUseShp.class, ResolveGridCoordinates.class, PreparePopulation.class, CleanPopulation.class, AdjustActivityToLinkDistances.class, SplitActivityTypesDuration.class, ExtractHomeCoordinates.class, FixSubtourModes.class, FixNetwork.class, PrepareTransitSchedule.class, - CreateSmallScaleCommercialTrafficDemand.class + GenerateSmallScaleCommercialTrafficDemand.class }) @MATSimApplication.Analysis({ CheckPopulation.class, LinkStats.class, SubTourAnalysis.class, DrtServiceQualityAnalysis.class, @@ -93,18 +71,16 @@ public class RunLeipzigScenario extends MATSimApplication { * Coordinate system used in the scenario. */ public static final String CRS = "EPSG:25832"; - - static final String VERSION = "1.1"; - + /** + * Current version number. + */ + public static final String VERSION = "1.2"; private static final Logger log = LogManager.getLogger(RunLeipzigScenario.class); - @CommandLine.Mixin private final SampleOptions sample = new SampleOptions(1, 10, 25); @CommandLine.ArgGroup(heading = "%nNetwork options%n", exclusive = false, multiplicity = "0..1") private final NetworkOptions networkOpt = new NetworkOptions(); - @CommandLine.Option(names = "--relativeSpeedChange", defaultValue = "1", description = "provide a value that is bigger then 0.0 and smaller then 1.0, else the speed will be reduced to 20 km/h") - Double relativeSpeedChange; @CommandLine.Option(names = "--bikes", defaultValue = "onNetworkWithStandardMatsim", description = "Define how bicycles are handled") private BicycleHandling bike; @@ -113,8 +89,15 @@ public class RunLeipzigScenario extends MATSimApplication { private Double parkingCostTimePeriodStart; @CommandLine.Option(names = "--parking-cost-time-period-end", defaultValue = "0", description = "End of time period for which parking cost will be charged.") private Double parkingCostTimePeriodEnd; - @CommandLine.Mixin - private ShpOptions shp; + + @CommandLine.Option(names = "--drt-case", defaultValue = "oneServiceArea", description = "Defines how drt is modelled. For a more detailed description see class DrtCaseSetup.") + private DrtCaseSetup.DrtCase drtCase; + + @CommandLine.Option(names = "--intermodality", defaultValue = "drtAndPtSeparateFromEachOther", description = "Define if drt should be used as access and egress mode for pt.") + private DrtCaseSetup.PtDrtIntermodality ptDrtIntermodality; + + @CommandLine.Option(names = "--initial-reroute", defaultValue = "false", description = "Define whether ALL trips should be rerouted prior to the simulation. use for base case calibration only.") + private boolean initialReroute; public RunLeipzigScenario(@Nullable Config config) { super(config); @@ -137,16 +120,15 @@ private static void adjustStrategiesForParking(Config config) { config.strategy().clearStrategySettings(); for (StrategyConfigGroup.StrategySettings strategySetting : modifiableCollectionOfOldStrategySettings) { + if (strategySetting.getStrategyName().equals("ReRoute")) { - StrategyConfigGroup.StrategySettings newReRouteStrategy = new StrategyConfigGroup.StrategySettings(); - newReRouteStrategy.setStrategyName(LeipzigRoutingStrategyProvider.STRATEGY_NAME); - newReRouteStrategy.setSubpopulation(strategySetting.getSubpopulation()); - newReRouteStrategy.setWeight(strategySetting.getWeight()); - newReRouteStrategy.setDisableAfter(strategySetting.getDisableAfter()); - config.strategy().addStrategySettings(newReRouteStrategy); - } else { - config.strategy().addStrategySettings(strategySetting); + strategySetting.setStrategyName(LeipzigRoutingStrategyProvider.STRATEGY_NAME); + } else if (strategySetting.getStrategyName().equals("SubtourModeChoice")) { + strategySetting.setStrategyName(LeipzigSubtourModeChoice.STRATEGY_NAME); } + + config.strategy().addStrategySettings(strategySetting); + } } @@ -154,8 +136,35 @@ private static void adjustStrategiesForParking(Config config) { @Override protected Config prepareConfig(Config config) { - SnzActivities.addScoringParams(config); // senozon activity types that are always the same. Differentiated by typical duration. + SnzActivities.addScoringParams(config); + + // Prepare commercial config + config.planCalcScore().addActivityParams(new PlanCalcScoreConfigGroup.ActivityParams("service").setTypicalDuration(3600)); + config.planCalcScore().addActivityParams(new PlanCalcScoreConfigGroup.ActivityParams("commercial_start").setTypicalDuration(3600)); + config.planCalcScore().addActivityParams(new PlanCalcScoreConfigGroup.ActivityParams("commercial_end").setTypicalDuration(3600)); + + SimWrapperConfigGroup simWrapper = ConfigUtils.addOrGetModule(config, SimWrapperConfigGroup.class); + + // Path is relative to config + simWrapper.defaultParams().shp = "../leipzig-utm32n/leipzig-utm32n.shp"; + simWrapper.defaultParams().mapCenter = "12.38,51.34"; + simWrapper.defaultParams().mapZoomLevel = 10.3; + + for (String subpopulation : List.of("outside_person", "freight", "goodsTraffic", "commercialPersonTraffic", "commercialPersonTraffic_service")) { + config.strategy().addStrategySettings( + new StrategyConfigGroup.StrategySettings() + .setStrategyName(DefaultPlanStrategiesModule.DefaultSelector.ChangeExpBeta) + .setWeight(0.95) + .setSubpopulation(subpopulation) + ); + config.strategy().addStrategySettings( + new StrategyConfigGroup.StrategySettings() + .setStrategyName(DefaultPlanStrategiesModule.DefaultStrategy.ReRoute) + .setWeight(0.05) + .setSubpopulation(subpopulation) + ); + } if (sample.isSet()) { // in [%]. adjust if sample size is less than 100% @@ -166,6 +175,8 @@ protected Config prepareConfig(Config config) { config.qsim().setFlowCapFactor(sample.getSize() / 100.0); config.qsim().setStorageCapFactor(sample.getSize() / 100.0); + + simWrapper.defaultParams().sampleSize = sample.getSample(); } @@ -178,9 +189,12 @@ protected Config prepareConfig(Config config) { // but we do not know where the facilities are. (Facilities are not written to file.) if (networkOpt.hasDrtArea()) { - MultiModeDrtConfigGroup multiModeDrtConfigGroup = ConfigUtils.addOrGetModule(config, MultiModeDrtConfigGroup.class); - ConfigUtils.addOrGetModule(config, DvrpConfigGroup.class); - DrtConfigs.adjustMultiModeDrtConfig(multiModeDrtConfigGroup, config.planCalcScore(), config.plansCalcRoute()); + //drt + try { + DrtCaseSetup.prepareConfig(config, drtCase, new ShpOptions(networkOpt.getDrtArea(), null, null)); + } catch (URISyntaxException e) { + log.fatal(e); + } } config.qsim().setUsingTravelTimeCheckInTeleportation(true); @@ -188,10 +202,10 @@ protected Config prepareConfig(Config config) { config.qsim().setUsePersonIdForMissingVehicleId(false); - // this is how it is supposed to be - config.facilities().setFacilitiesSource(FacilitiesConfigGroup.FacilitiesSource.onePerActivityLinkInPlansFile); + // We need to use coordinates only, otherwise subtour constraints will be violated by the parking re-routing, because it may change link/facility ids + config.facilities().setFacilitiesSource(FacilitiesConfigGroup.FacilitiesSource.none); - switch ((bike)) { + switch (bike) { case onNetworkWithStandardMatsim -> { // bike is routed on the network per the xml config. @@ -221,7 +235,33 @@ protected Config prepareConfig(Config config) { BicycleConfigGroup bikeConfigGroup = ConfigUtils.addOrGetModule(config, BicycleConfigGroup.class); bikeConfigGroup.setBicycleMode(TransportMode.bike); } - default -> throw new IllegalStateException("Unexpected value: " + (bike)); + case bikeTeleportedStandardMatsim -> { + + log.info("Simulating with bikes teleported"); + PlansCalcRouteConfigGroup plansCalcRouteConfigGroup = ConfigUtils.addOrGetModule(config, PlansCalcRouteConfigGroup.class); + + if (plansCalcRouteConfigGroup.getNetworkModes().contains(TransportMode.bike)) { + + Collection networkModes = Sets.newHashSet(); + + for (String mode : plansCalcRouteConfigGroup.getNetworkModes()) { + if (!mode.equals(TransportMode.bike)) { + networkModes.add(mode); + } + } + plansCalcRouteConfigGroup.setNetworkModes(networkModes); + } + + if (!plansCalcRouteConfigGroup.getTeleportedModeParams().containsKey(TransportMode.bike)) { + PlansCalcRouteConfigGroup.TeleportedModeParams teleportedModeParams = new PlansCalcRouteConfigGroup.TeleportedModeParams(); + teleportedModeParams.setMode(TransportMode.bike); + teleportedModeParams.setBeelineDistanceFactor(1.3); + teleportedModeParams.setTeleportedModeSpeed(3.1388889); + plansCalcRouteConfigGroup.addTeleportedModeParams(teleportedModeParams); + } + } + + default -> throw new IllegalStateException("Unexpected value: " + bike); } if (networkOpt.hasParkingCostArea()) { @@ -237,32 +277,19 @@ protected Config prepareConfig(Config config) { @Override protected void prepareScenario(Scenario scenario) { - - // TODO: can be removed once v1.2 is done, because this is done in the preparation phase - for (Link link : scenario.getNetwork().getLinks().values()) { - Set modes = link.getAllowedModes(); - - // allow freight traffic together with cars - if (modes.contains("car")) { - Set newModes = Sets.newHashSet(modes); - newModes.add("freight"); - - link.setAllowedModes(newModes); - } - } + //this has to be executed before DrtCaseSetup.prepareScenario() as the latter method relies on the drt mode being added to the network + networkOpt.prepare(scenario.getNetwork()); + // (passt das Netz an aus den mitgegebenen shape files, z.B. parking area, car-free area, ...) if (networkOpt.hasDrtArea()) { - scenario.getPopulation().getFactory().getRouteFactories().setRouteFactory(DrtRoute.class, new DrtRouteFactory()); - // (matsim core does not know about DRT routes. This makes it possible to read them before the controler is there.) + DrtCaseSetup.prepareScenario(scenario, drtCase, new ShpOptions(networkOpt.getDrtArea(), null, null), VERSION); } - networkOpt.prepare(scenario.getNetwork()); - // (passt das Netz an aus den mitgegebenen shape files, z.B. parking area, car-free area, ...) + } @Override protected void prepareControler(Controler controler) { - Config config = controler.getConfig(); controler.addOverridingModule(new SimWrapperModule()); controler.addOverridingModule(new PtStop2StopAnalysisModule()); @@ -282,6 +309,19 @@ public void install() { // Plots how many different modes agents tried out addControlerListenerBinding().to(ModeChoiceCoverageControlerListener.class); + // Leipzig specific planning strategies + + if(initialReroute){ + //re-route prior to simulation + this.addPersonPrepareForSimAlgorithm().to(LeipzigRouterPlanAlgorithm.class); + } + + this.addPlanStrategyBinding(LeipzigRoutingStrategyProvider.STRATEGY_NAME).toProvider(LeipzigRoutingStrategyProvider.class); + this.addPlanStrategyBinding(LeipzigSubtourModeChoice.STRATEGY_NAME).toProvider(LeipzigSubtourModeChoice.class); + + // Normally this is bound with the default subtour mode choice, because we use our own variant this is bound again here + bind(PermissibleModesCalculator.class).to(PermissibleModesCalculatorImpl.class); + if (networkOpt.hasCarFreeArea()) { bind(MultimodalLinkChooser.class).to(CarfreeMultimodalLinkChooser.class); } @@ -289,63 +329,14 @@ public void install() { if (networkOpt.hasParkingCostArea()) { this.addEventHandlerBinding().toInstance(new TimeRestrictedParkingCostHandler(parkingCostTimePeriodStart, parkingCostTimePeriodEnd)); - this.addPersonPrepareForSimAlgorithm().to(LeipzigRouterPlanAlgorithm.class); - this.addPlanStrategyBinding(LeipzigRoutingStrategyProvider.STRATEGY_NAME).toProvider(LeipzigRoutingStrategyProvider.class); install(new PersonMoneyEventsAnalysisModule()); - - } - - // TODO FIXME yyyyyy replace by config option - { - addControlerListenerBinding().to(StrategyWeightFadeout.class).in(Singleton.class); - - Multibinder schedules = StrategyWeightFadeout.getBinder(binder()); - - // Mode-choice fades out earlier than the other strategies - // Given a fixed mode, the "less disruptive" choice dimensions will be weighted higher during the end - schedules.addBinding().toInstance(new StrategyWeightFadeout.Schedule(DefaultPlanStrategiesModule.DefaultStrategy.SubtourModeChoice, "person", 0.65, 0.80)); - - // Fades out until 0.9 (innovation switch off) - //TODO switch no new ReRoute!!!! - schedules.addBinding().toInstance(new StrategyWeightFadeout.Schedule(LeipzigRoutingStrategyProvider.STRATEGY_NAME, "person", 0.75)); - schedules.addBinding().toInstance(new StrategyWeightFadeout.Schedule(DefaultPlanStrategiesModule.DefaultStrategy.TimeAllocationMutator, "person", 0.75)); - } - bind(new TypeLiteral>() { - }).toInstance(new ForceInnovationStrategyChooser<>(10, ForceInnovationStrategyChooser.Permute.yes)); } }); if (networkOpt.hasDrtArea()) { - // FIXME yyyyyy move above into prepareConfig - // FIXME will be integrated into DrtCaseSetup class - - MultiModeDrtConfigGroup multiModeDrtConfigGroup = ConfigUtils.addOrGetModule(config, MultiModeDrtConfigGroup.class); - - //set fare params; flexa has the same prices as leipzig PT: Values taken out of LeipzigPtFareModule -sm0522 - Double ptBaseFare = 2.4710702921120262; - Double ptDistanceFare = 0.00017987993018495408; - - DrtFareParams drtFareParams = new DrtFareParams(); - drtFareParams.baseFare = ptBaseFare; - drtFareParams.distanceFare_m = ptDistanceFare; - drtFareParams.timeFare_h = 0.; - drtFareParams.dailySubscriptionFee = 0.; - - Set drtModes = new HashSet<>(); - - multiModeDrtConfigGroup.getModalElements().forEach(drtConfigGroup -> { - drtConfigGroup.addParameterSet(drtFareParams); - DrtConfigs.adjustDrtConfig(drtConfigGroup, config.planCalcScore(), config.plansCalcRoute()); - drtModes.add(drtConfigGroup.getMode()); - }); - - controler.addOverridingModule(new DvrpModule()); - controler.addOverridingModule(new MultiModeDrtModule()); - controler.configureQSimComponents(DvrpQSimComponents.activateAllModes(multiModeDrtConfigGroup)); - - prepareDrtFareCompensation(config, controler, drtModes, ptBaseFare); + DrtCaseSetup.prepareControler(controler, drtCase, new ShpOptions(networkOpt.getDrtArea(), null, null), ptDrtIntermodality); } if (bike == BicycleHandling.onNetworkWithBicycleContrib) { @@ -353,69 +344,8 @@ public void install() { } } - /** - * FIXME: will be moved into separate class. - */ - private void prepareDrtFareCompensation(Config config, Controler controler, Set nonPtModes, Double ptBaseFare) { - IntermodalTripFareCompensatorsConfigGroup intermodalTripFareCompensatorsConfigGroup = - ConfigUtils.addOrGetModule(config, IntermodalTripFareCompensatorsConfigGroup.class); - - IntermodalTripFareCompensatorConfigGroup drtFareCompensator = new IntermodalTripFareCompensatorConfigGroup(); - drtFareCompensator.setCompensationCondition(IntermodalTripFareCompensatorConfigGroup.CompensationCondition.PtModeUsedAnywhereInTheDay); - - //Flexa is integrated into pt system, so users only pay once - drtFareCompensator.setCompensationMoneyPerTrip(ptBaseFare); - drtFareCompensator.setNonPtModes(ImmutableSet.copyOf(nonPtModes)); - - intermodalTripFareCompensatorsConfigGroup.addParameterSet(drtFareCompensator); - controler.addOverridingModule(new IntermodalTripFareCompensatorsModule()); - - //for intermodality between pt and drt the following modules have to be installed and configured - String artificialPtMode = "pt_w_drt_allowed"; - PtIntermodalRoutingModesConfigGroup ptIntermodalRoutingModesConfig = ConfigUtils.addOrGetModule(config, PtIntermodalRoutingModesConfigGroup.class); - PtIntermodalRoutingModesConfigGroup.PtIntermodalRoutingModeParameterSet ptIntermodalRoutingModesParamSet - = new PtIntermodalRoutingModesConfigGroup.PtIntermodalRoutingModeParameterSet(); - - ptIntermodalRoutingModesParamSet.setDelegateMode(TransportMode.pt); - ptIntermodalRoutingModesParamSet.setRoutingMode(artificialPtMode); - - PtIntermodalRoutingModesConfigGroup.PersonAttribute2ValuePair personAttrParamSet - = new PtIntermodalRoutingModesConfigGroup.PersonAttribute2ValuePair(); - personAttrParamSet.setPersonFilterAttribute("canUseDrt"); - personAttrParamSet.setPersonFilterValue("true"); - ptIntermodalRoutingModesParamSet.addPersonAttribute2ValuePair(personAttrParamSet); - - ptIntermodalRoutingModesConfig.addParameterSet(ptIntermodalRoutingModesParamSet); - - controler.addOverridingModule(new PtIntermodalRoutingModesModule()); - - //SRRConfigGroup needs to have the same personFilterAttr and Value as PtIntermodalRoutingModesConfigGroup - SwissRailRaptorConfigGroup ptConfig = ConfigUtils.addOrGetModule(config, SwissRailRaptorConfigGroup.class); - for (SwissRailRaptorConfigGroup.IntermodalAccessEgressParameterSet paramSet : ptConfig.getIntermodalAccessEgressParameterSets()) { - if (paramSet.getMode().contains("drt")) { - paramSet.setPersonFilterAttribute("canUseDrt"); - paramSet.setPersonFilterValue("true"); - } - } - - controler.addOverridingModule(new AbstractModule() { - @Override - public void install() { - bind(RaptorIntermodalAccessEgress.class).to(EnhancedRaptorIntermodalAccessEgress.class); - } - }); - - //finally the new pt mode has to be added to subtourModeChoice - SubtourModeChoiceConfigGroup modeChoiceConfigGroup = ConfigUtils.addOrGetModule(config, SubtourModeChoiceConfigGroup.class); - List modes = new ArrayList<>(); - Collections.addAll(modes, modeChoiceConfigGroup.getModes()); - modes.add(artificialPtMode); - modeChoiceConfigGroup.setModes(modes.toArray(new String[0])); - } - /** * Defines how bicycles are scored. */ - enum BicycleHandling {onNetworkWithStandardMatsim, onNetworkWithBicycleContrib} - + enum BicycleHandling {onNetworkWithStandardMatsim, onNetworkWithBicycleContrib, bikeTeleportedStandardMatsim} } diff --git a/src/main/java/org/matsim/run/StrategyWeightFadeout.java b/src/main/java/org/matsim/run/StrategyWeightFadeout.java deleted file mode 100644 index 45563553..00000000 --- a/src/main/java/org/matsim/run/StrategyWeightFadeout.java +++ /dev/null @@ -1,167 +0,0 @@ -/* *********************************************************************** * - * 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 com.google.inject.Binder; -import com.google.inject.Inject; -import com.google.inject.multibindings.Multibinder; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.matsim.api.core.v01.population.Person; -import org.matsim.api.core.v01.population.Plan; -import org.matsim.core.config.Config; -import org.matsim.core.config.groups.StrategyConfigGroup; -import org.matsim.core.controler.events.IterationStartsEvent; -import org.matsim.core.controler.listener.IterationStartsListener; -import org.matsim.core.replanning.GenericPlanStrategy; -import org.matsim.core.replanning.PlanStrategy; -import org.matsim.core.replanning.StrategyManager; - -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; - -/** - * Fade-out the strategy weight during the simulation. - * This class as well as the {@link Schedule}s has be bound with guice in the controller. - */ -public final class StrategyWeightFadeout implements IterationStartsListener { - - private final Logger log = LogManager.getLogger(StrategyWeightFadeout.class); - - @Inject - private Map planStrategies; - - @Inject - private Config config; - - @Inject - private StrategyManager strategyManager; - - @Inject - private Set schedules; - - @Override - public void notifyIterationStarts(IterationStartsEvent iterationStartsEvent) { - - for (Schedule s : schedules) { - - StrategyConfigGroup.StrategySettings settings = null; - - for (StrategyConfigGroup.StrategySettings strategySettings : planStrategies.keySet()) { - if (strategySettings.getStrategyName().equals(s.name) && strategySettings.getSubpopulation().equals(s.subpopulation)) { - settings = strategySettings; - break; - } - } - - if (settings == null) { - log.info("Strategy settings for {} not found", s.name); - continue; - } - - String strategyName = settings.getStrategyName(); - - if (Double.isNaN(s.initialWeight)) { - s.initialWeight = settings.getWeight(); - s.startIteration = (int) (config.controler().getLastIteration() * s.startAt); - double disable = config.strategy().getFractionOfIterationsToDisableInnovation(); - - // use disable after if it is set - if (!Double.isNaN(s.endAt)) - s.endIteration = (int) (config.controler().getLastIteration() * s.endAt); - else if (settings.getDisableAfter() > 0 && settings.getDisableAfter() < Integer.MAX_VALUE && settings.getDisableAfter() <= disable) - s.endIteration = settings.getDisableAfter(); - else if (Double.isFinite(disable) && disable < Integer.MAX_VALUE) - s.endIteration = (int) (config.controler().getLastIteration() * disable); - else - s.endIteration = settings.getDisableAfter(); - - log.info("{} fadeout from iteration {} to {} with start weight {}", strategyName, s.startIteration, s.endIteration, s.initialWeight); - } - - // Find the implementation to update the strategy weight - List> strategies = strategyManager.getStrategies(s.subpopulation); - Optional> strategy = strategies.stream().filter(st -> st.toString().contains(strategyName)).findFirst(); - - if (strategy.isEmpty()) { - log.warn("Could not find loaded strategy for {}", strategy); - return; - } - - if (iterationStartsEvent.getIteration() > s.startIteration && iterationStartsEvent.getIteration() <= s.endIteration) { - double step = s.initialWeight / (s.endIteration - s.startIteration); - double weight = s.initialWeight + step * (s.startIteration - iterationStartsEvent.getIteration()); - - log.info("Setting {} weight at iteration {} to {}", strategyName, iterationStartsEvent.getIteration(), weight); - - strategyManager.changeWeightOfStrategy(strategy.get(), s.subpopulation, weight); - } - } - } - - /** - * Get the binder which is needed to add {@link Schedule}. - */ - public static Multibinder getBinder(Binder binder) { - return Multibinder.newSetBinder(binder, StrategyWeightFadeout.Schedule.class); - } - - /** - * Defines the fade-out schedule for certain strategies. - */ - public static class Schedule { - - /** - * Start weight for fade-out. - */ - private double initialWeight = Double.NaN; - - /** - * Start and end iteration for fade-out. - */ - private int startIteration; - private int endIteration; - - private final String name; - private final String subpopulation; - private final double startAt; - private final double endAt; - - /** - * Constructor where the end is taken from the config and not given explicitly. - */ - public Schedule(String name, String subpopulation, double startAt) { - this.name = name; - this.subpopulation = subpopulation; - this.startAt = startAt; - this.endAt = Double.NaN; - } - - public Schedule(String name, String subpopulation, double startAt, double endAt) { - this.name = name; - this.subpopulation = subpopulation; - this.startAt = startAt; - this.endAt = endAt; - } - } -} diff --git a/src/main/java/org/matsim/run/prepare/CreateDrtStopsFromNetwork.java b/src/main/java/org/matsim/run/prepare/CreateDrtStopsFromNetwork.java index 5f946aea..d1e747c6 100644 --- a/src/main/java/org/matsim/run/prepare/CreateDrtStopsFromNetwork.java +++ b/src/main/java/org/matsim/run/prepare/CreateDrtStopsFromNetwork.java @@ -48,8 +48,8 @@ public final class CreateDrtStopsFromNetwork implements MATSimAppCommand { @CommandLine.Option(names = "--min-distance", description = "minimal distance between two stops in m", defaultValue = "100.") private double minDistance; - @CommandLine.Option(names = "--output-folder", description = "path to output folder", required = true) - private String outputFolder; + @CommandLine.Option(names = "--output", description = "output file name", required = true) + private String outputFile; private static final Logger log = LogManager.getLogger(CreateDrtStopsFromNetwork.class); @@ -66,7 +66,6 @@ public Integer call() throws Exception { String stopsData = shp.getShapeFile().toString() + "_" + mode + "_stops.csv"; Geometry drtServiceArea = null; - Map, Node> stopNodes = new HashMap<>(); if (shp.getShapeFile() != null) { drtServiceArea = shp.getGeometry(); @@ -75,6 +74,24 @@ public Integer call() throws Exception { return 2; } + processNetworkForStopCreation(network, modeFilteredNetwork, drtServiceArea, stopsData, mode, outputFile, shp); + + return 0; + } + + /** + * method, which is called by @DrtCaseSetup for drt config / input automation. + * @param network input network, which is used to create stops. + * @param modeFilteredNetwork use mode filtered network yes / no. + * @param drtServiceArea shp with drt service area. + * @param stopsData csv file with stop coordinates for comparison. + * @param mode drt mode, for which stops are created. + * @param outputFile output stops file.xml. + */ + public void processNetworkForStopCreation(Network network, boolean modeFilteredNetwork, Geometry drtServiceArea, String stopsData, String mode, String outputFile, ShpOptions shp) { + + Map, Node> stopNodes = new HashMap<>(); + if (modeFilteredNetwork) { Network filteredNetwork = NetworkUtils.createNetwork(); Set modes = new HashSet<>(); @@ -125,16 +142,17 @@ public Integer call() throws Exception { csvWriter.append(";"); csvWriter.append(Double.toString(filteredNodes.get(nodeId).getCoord().getY())); } + } catch (IOException e) { + log.fatal(e); } MATSimAppCommand prepareDrtStops = new PrepareDrtStops(); - String outputNet = outputFolder + "/" + mode + "networkForDrtStopCreation.xml.gz"; + String outputNet = "./" + mode + "networkForDrtStopCreation.xml.gz"; NetworkUtils.writeNetwork(network, outputNet); prepareDrtStops.execute("--stops-data", stopsData, "--network", outputNet, "--mode", mode, - "--shp", shp.getShapeFile().toString(), "--output-folder", outputFolder); + "--shp", shp.getShapeFile().toString(), "--output", outputFile); - return 0; } Map, Node> filterDistance(Double minDistance, Map, Node> nodes) { diff --git a/src/main/java/org/matsim/run/prepare/DrtCaseSetup.java b/src/main/java/org/matsim/run/prepare/DrtCaseSetup.java new file mode 100644 index 00000000..d3d66a5d --- /dev/null +++ b/src/main/java/org/matsim/run/prepare/DrtCaseSetup.java @@ -0,0 +1,442 @@ +package org.matsim.run.prepare; + +import ch.sbb.matsim.config.SwissRailRaptorConfigGroup; +import ch.sbb.matsim.routing.pt.raptor.RaptorIntermodalAccessEgress; +import com.google.common.collect.ImmutableSet; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.locationtech.jts.geom.Geometry; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.application.options.ShpOptions; +import org.matsim.contrib.drt.analysis.zonal.DrtZonalSystemParams; +import org.matsim.contrib.drt.fare.DrtFareParams; +import org.matsim.contrib.drt.optimizer.insertion.extensive.ExtensiveInsertionSearchParams; +import org.matsim.contrib.drt.optimizer.rebalancing.RebalancingParams; +import org.matsim.contrib.drt.optimizer.rebalancing.mincostflow.MinCostFlowRebalancingStrategyParams; +import org.matsim.contrib.drt.routing.DrtRoute; +import org.matsim.contrib.drt.routing.DrtRouteFactory; +import org.matsim.contrib.drt.run.*; +import org.matsim.contrib.dvrp.run.AbstractDvrpModeModule; +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.ConfigUtils; +import org.matsim.core.config.groups.ChangeModeConfigGroup; +import org.matsim.core.config.groups.PlanCalcScoreConfigGroup; +import org.matsim.core.config.groups.SubtourModeChoiceConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy; +import org.matsim.core.controler.events.StartupEvent; +import org.matsim.core.controler.listener.StartupListener; +import org.matsim.core.utils.io.IOUtils; +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.run.LeipzigPtFareModule; +import org.opengis.feature.simple.SimpleFeature; + +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; + +/** + * This class configures drt config, stops, transitStopsFile and vehicles regarding enum DrtCase of RunLeipzigScenario. + */ +public final class DrtCaseSetup { + + private static final Logger log = LogManager.getLogger(DrtCaseSetup.class); + private static final ShpOptions flexaArea2021 = new ShpOptions(Path.of( + "input/v1.2/drtServiceArea/leipzig_flexa_service_area_2021.shp"), + null, null); + + private static final String errorMessage = "Unexpected value: "; + + static Set drtModes = new HashSet<>(); + + /** + * Defines if drt is modelled at all (none), with 2 separate modes (twoSeparateServiceAreas) or with 1 single drt mode (oneServiceArea). + * As this class is only triggered if a shp of the drt service area was provided, none is inactive for now + */ + public enum DrtCase {/*none,*/ twoSeparateServiceAreas, oneServiceArea} + + /** + * Defines if intermodality between drt and pt is modelled or not. + */ + public enum PtDrtIntermodality {drtAndPtSeparateFromEachOther, drtAsAccessEgressForPt} + + private DrtCaseSetup(){} + + /** + * prepare config for drt simulation. + */ + public static void prepareConfig(Config config, DrtCase drtCase, ShpOptions drtArea) throws URISyntaxException { + + MultiModeDrtConfigGroup multiModeDrtConfigGroup = ConfigUtils.addOrGetModule(config, MultiModeDrtConfigGroup.class); + DvrpConfigGroup dvrpConfigGroup = ConfigUtils.addOrGetModule(config, DvrpConfigGroup.class); + + LeipzigPtFareModule ptFareModule = new LeipzigPtFareModule(); + + //set fare params; flexa has the same prices as leipzig PT: Values taken out of LeipzigPtFareModule -sm0522 + Double ptBaseFare = ptFareModule.getNormalPtBaseFare(); + Double ptDistanceFare = ptFareModule.getNormalDistanceBasedFare(); + + DrtFareParams drtFareParams = new DrtFareParams(); + drtFareParams.baseFare = ptBaseFare; + drtFareParams.distanceFare_m = ptDistanceFare; + drtFareParams.timeFare_h = 0.; + drtFareParams.dailySubscriptionFee = 0.; + + switch (drtCase) { + case twoSeparateServiceAreas -> { + //flexa case with 2 separate drt bubbles (north and southeast) -> 2 separate drt modes + if (multiModeDrtConfigGroup.getModalElements().isEmpty()) { + createDrtModeConfigGroup(multiModeDrtConfigGroup, TransportMode.drt + "North", drtArea.getShapeFile().toString()); + createDrtModeConfigGroup(multiModeDrtConfigGroup, TransportMode.drt + "Southeast", drtArea.getShapeFile().toString()); + } + + multiModeDrtConfigGroup.getModalElements().forEach(drtConfigGroup -> { + drtConfigGroup.addParameterSet(drtFareParams); + DrtConfigs.adjustDrtConfig(drtConfigGroup, config.planCalcScore(), config.plansCalcRoute()); + drtModes.add(drtConfigGroup.getMode()); + + configureNecessaryConfigGroups(config, drtConfigGroup.getMode()); + }); + } + + case oneServiceArea -> { + //"normal" drt, modelled as one single drt mode + if (multiModeDrtConfigGroup.getModalElements().isEmpty()) { + createDrtModeConfigGroup(multiModeDrtConfigGroup, TransportMode.drt, drtArea.getShapeFile().toString()); + } + + multiModeDrtConfigGroup.getModalElements().forEach(drtConfigGroup -> { + drtConfigGroup.addParameterSet(drtFareParams); + DrtConfigs.adjustDrtConfig(drtConfigGroup, config.planCalcScore(), config.plansCalcRoute()); + drtModes.add(drtConfigGroup.getMode()); + + configureNecessaryConfigGroups(config, drtConfigGroup.getMode()); + }); + } + default -> throw new IllegalStateException(errorMessage + (drtCase)); + } + + //drt modes have to be set as network modes in dvrp CfgGroup + dvrpConfigGroup.networkModes = drtModes; + //after adding mode specific multiModeDrtParams -> adjust + } + + /** + * prepare scenario for drt simulation. + */ + public static void prepareScenario(Scenario scenario, DrtCase drtCase, ShpOptions drtArea, String version) { + + scenario.getPopulation().getFactory().getRouteFactories().setRouteFactory(DrtRoute.class, new DrtRouteFactory()); + // (matsim core does not know about DRT routes. This makes it possible to read them before the controler is there.) + + String drtMode = null; + Integer noVehicles = null; + + CreateDrtStopsFromNetwork drtStopsCreator = new CreateDrtStopsFromNetwork(); + MultiModeDrtConfigGroup multiModeDrtConfigGroup = ConfigUtils.addOrGetModule(scenario.getConfig(), MultiModeDrtConfigGroup.class); + + switch (drtCase) { + case twoSeparateServiceAreas -> { + //flexa case with 2 separate drt bubbles (north and southeast) -> 2 separate drt modes + + for (SimpleFeature feature : flexaArea2021.readFeatures()) { + if (feature.getAttribute("Name").equals("Nord")) { + drtMode = "drtNorth"; + noVehicles = 3; + + } else if (feature.getAttribute("Name").equals("Suedost")) { + drtMode = "drtSoutheast"; + noVehicles = 2; + } else { + log.fatal("Invalid shp feature name. Shp features must be named 'Nord' or 'Suedost'!"); + } + + new LeipzigDrtVehicleCreator().createDrtVehiclesForSingleArea(scenario.getVehicles(), scenario.getNetwork(), + feature, noVehicles, drtMode); + + //normally the following code would be set in prepareConfig, but.. + //.. the stops creator relies on a network with drt modes. Drt modes are added in RunLeipzigScenario.prepareScenario().. + //.. so stops are created after that step -sme0823 + multiModeDrtConfigGroup.getModalElements().forEach(drtConfigGroup -> { + + //path, tho which stops.xml is saved + URL path = IOUtils.extendUrl(scenario.getConfig().getContext(), "leipzig-v" + version + "-" + drtConfigGroup.getMode() + "-stops.xml"); + File stopsFile = null; + try { + stopsFile = new File(path.toURI()); + } catch (URISyntaxException e) { + log.fatal(e); + } + + //create drt stops and save them next to config -> put it as input stops file. + //unfortunately there is no scenario.setDrtStops, so we have to do this workaround. -sme0723 + drtStopsCreator.processNetworkForStopCreation(scenario.getNetwork(), true, (Geometry) feature.getDefaultGeometry(), + flexaArea2021.getShapeFile().toString() + "_" + drtConfigGroup.getMode() + "_stops.csv", drtConfigGroup.getMode(), + stopsFile.toString(), flexaArea2021); + + //naming pattern comes from @DrtStopsWriter line 81. Should be ok to hard code it here. -sme0523 + drtConfigGroup.transitStopFile = stopsFile.toString(); + + configureNecessaryConfigGroups(scenario.getConfig(), drtConfigGroup.getMode()); + }); + } + } + + case oneServiceArea -> { + //"normal" drt, modelled as one single drt mode + drtMode = TransportMode.drt; + + //make the 400 configurable??? -sme0723 + new LeipzigDrtVehicleCreator().createDrtVehicles(scenario.getVehicles(), scenario.getNetwork(), + drtArea, 400, drtMode); + + //normally the following code would be set in prepareConfig, but.. + //.. the stops creator relies on a network with drt modes. Drt modes are added in RunLeipzigScenario.prepareScenario().. + //.. so stops are created after that step -sme0823 + multiModeDrtConfigGroup.getModalElements().forEach(drtConfigGroup -> { + + //path, tho which stops.xml is saved + URL path = IOUtils.extendUrl(scenario.getConfig().getContext(), "leipzig-v" + version + "-" + drtConfigGroup.getMode() + "-stops.xml"); + File stopsFile = null; + try { + stopsFile = new File(path.toURI()); + } catch (URISyntaxException e) { + log.fatal(e); + } + + //create drt stops and save them next to config -> put it as input stops file. + //unfortunately there is no scenario.setDrtStops, so we have to do this workaround. -sme0723 + drtStopsCreator.processNetworkForStopCreation(scenario.getNetwork(), true, drtArea.getGeometry(), + drtArea.getShapeFile().toString() + "_" + drtConfigGroup.getMode() + "_stops.csv", drtConfigGroup.getMode(), + stopsFile.toString(), drtArea); + + //naming pattern comes from @DrtStopsWriter line 81. Should be ok to hard code it here. -sme0523 + drtConfigGroup.transitStopFile = stopsFile.toString(); + + }); + + } + default -> throw new IllegalStateException(errorMessage + (drtCase)); + } + } + + /** + * prepare controler for drt simulation. + */ + public static void prepareControler(Controler controler, DrtCase drtCase, ShpOptions drtArea, PtDrtIntermodality ptDrtIntermodality) { + + MultiModeDrtConfigGroup multiModeDrtConfigGroup = ConfigUtils.addOrGetModule(controler.getConfig(), MultiModeDrtConfigGroup.class); + controler.addOverridingModule(new DvrpModule()); + controler.addOverridingModule(new MultiModeDrtModule()); + controler.configureQSimComponents(DvrpQSimComponents.activateAllModes(multiModeDrtConfigGroup)); + + // if drt is stopBased, we want to write the drt stops into the global output -sme0723 + for (DrtConfigGroup drtCfg : multiModeDrtConfigGroup.getModalElements()) { + if (drtCfg.operationalScheme.equals(DrtConfigGroup.OperationalScheme.stopbased)) { + controler.addOverridingModule(new AbstractDvrpModeModule(drtCfg.getMode()) { + @Override + public void install() { + bindModal(DrtCaseSetup.StopsControlerListener.class).toProvider(modalProvider( + getter -> new DrtCaseSetup.StopsControlerListener(drtCfg.getMode(), + getter.get(OutputDirectoryHierarchy.class), drtCfg.transitStopFile + ))); + addControlerListenerBinding().to(modalKey(DrtCaseSetup.StopsControlerListener.class)); + } + }); + } + } + + switch (drtCase) { + case twoSeparateServiceAreas -> { + //flexa case with 2 separate drt bubbles (north and southeast) -> 2 separate drt modes + + //if intermodality between pt and drt -> only railways are tagged as intermodal stations (this is how it is handled in reality) -sme0723 + if (ptDrtIntermodality.equals(PtDrtIntermodality.drtAsAccessEgressForPt)) { + preparePtDrtIntermodality(controler, flexaArea2021, true); + } + } + + case oneServiceArea -> { + //"normal" drt, modelled as one single drt mode + + if (ptDrtIntermodality.equals(PtDrtIntermodality.drtAsAccessEgressForPt)) { + preparePtDrtIntermodality(controler, drtArea, false); + } + } + default -> throw new IllegalStateException(errorMessage + (drtCase)); + } + } + + /** + * if no modal params existing, we have to create them. + */ + private static void createDrtModeConfigGroup(MultiModeDrtConfigGroup multiModeDrtConfigGroup, String mode, String pathToShp) { + DrtConfigGroup drtConfigGroup = new DrtConfigGroup(); + drtConfigGroup.mode = mode; + drtConfigGroup.operationalScheme = DrtConfigGroup.OperationalScheme.stopbased; + drtConfigGroup.maxTravelTimeAlpha = 1.5; + drtConfigGroup.maxTravelTimeBeta = 1200.; + drtConfigGroup.maxWaitTime = 1200.; + drtConfigGroup.maxWalkDistance = 1500.; + drtConfigGroup.rejectRequestIfMaxWaitOrTravelTimeViolated = false; + drtConfigGroup.stopDuration = 60.; + drtConfigGroup.useModeFilteredSubnetwork = true; + + //add insertionSearch params + ExtensiveInsertionSearchParams insertionSearchParams = new ExtensiveInsertionSearchParams(); + drtConfigGroup.addParameterSet(insertionSearchParams); + + //add rebalancing params and configure standard values + RebalancingParams rebalancingParams = new RebalancingParams(); + + MinCostFlowRebalancingStrategyParams rebalancingStrategyParams = new MinCostFlowRebalancingStrategyParams(); + rebalancingStrategyParams.targetAlpha = 0.5; + rebalancingStrategyParams.targetBeta = 0.5; + rebalancingParams.addParameterSet(rebalancingStrategyParams); + drtConfigGroup.addParameterSet(rebalancingParams); + + DrtZonalSystemParams zonalSystemParams = new DrtZonalSystemParams(); + zonalSystemParams.zonesGeneration = DrtZonalSystemParams.ZoneGeneration.ShapeFile; + zonalSystemParams.zonesShapeFile = new File(pathToShp).getAbsolutePath(); + drtConfigGroup.addParameterSet(zonalSystemParams); + + multiModeDrtConfigGroup.addParameterSet(drtConfigGroup); + } + + /** + * configure all other config groups, where drt modes need to be included: SMC, ChangeMode, ModeParams. + */ + private static void configureNecessaryConfigGroups(Config config, String mode) { + + PlanCalcScoreConfigGroup planCalcScoreConfigGroup = ConfigUtils.addOrGetModule(config, PlanCalcScoreConfigGroup.class); + ChangeModeConfigGroup changeModeConfigGroup = ConfigUtils.addOrGetModule(config, ChangeModeConfigGroup.class); + SubtourModeChoiceConfigGroup smcCfg = ConfigUtils.addOrGetModule(config, SubtourModeChoiceConfigGroup.class); + + //add drt mode to modeParams if it does not exist yet + if (!planCalcScoreConfigGroup.getModes().containsKey(mode)) { + PlanCalcScoreConfigGroup.ModeParams modeParams = new PlanCalcScoreConfigGroup.ModeParams(mode); + modeParams.setConstant(planCalcScoreConfigGroup.getModes().get(TransportMode.pt).getConstant()); + modeParams.setMarginalUtilityOfTraveling(0.); + + PlanCalcScoreConfigGroup.ScoringParameterSet scoringParams = planCalcScoreConfigGroup.getOrCreateScoringParameters(null); + scoringParams.addModeParams(modeParams); + } + + //add drt modes to changeModeCfgGroup + if (!Arrays.stream(changeModeConfigGroup.getModes()).toList().contains(mode)) { + List modes = new ArrayList<>(Arrays.asList(changeModeConfigGroup.getModes())); + modes.add(mode); + changeModeConfigGroup.setModes(modes.toArray(new String[modes.size()])); + } + + //add drt modes to SMC + if (!Arrays.stream(smcCfg.getModes()).toList().contains(mode)) { + List modes = new ArrayList<>(Arrays.asList(smcCfg.getModes())); + modes.add(mode); + smcCfg.setModes(modes.toArray(new String[modes.size()])); + } + } + + private static void preparePtDrtIntermodality(Controler controler, ShpOptions shp, boolean railwaysOnly) { + + new PrepareTransitSchedule().prepareDrtIntermodality(controler.getScenario().getTransitSchedule(), shp, railwaysOnly); + + ConfigUtils.addOrGetModule(controler.getConfig(), MultiModeDrtConfigGroup.class).getModalElements().stream().findFirst().ifPresent(drtConfigGroup -> + drtConfigGroup.getDrtFareParams().ifPresent(drtFareParams -> + prepareDrtFareCompensation(controler, drtModes, drtFareParams.baseFare))); + } + + private static void prepareDrtFareCompensation(Controler controler, Set nonPtModes, Double ptBaseFare) { + IntermodalTripFareCompensatorsConfigGroup intermodalTripFareCompensatorsConfigGroup = + ConfigUtils.addOrGetModule(controler.getConfig(), IntermodalTripFareCompensatorsConfigGroup.class); + + IntermodalTripFareCompensatorConfigGroup drtFareCompensator = new IntermodalTripFareCompensatorConfigGroup(); + drtFareCompensator.setCompensationCondition(IntermodalTripFareCompensatorConfigGroup.CompensationCondition.PtModeUsedAnywhereInTheDay); + + //Flexa is integrated into pt system, so users only pay once + drtFareCompensator.setCompensationMoneyPerTrip(ptBaseFare); + drtFareCompensator.setNonPtModes(ImmutableSet.copyOf(nonPtModes)); + + intermodalTripFareCompensatorsConfigGroup.addParameterSet(drtFareCompensator); + controler.addOverridingModule(new IntermodalTripFareCompensatorsModule()); + + //for intermodality between pt and drt the following modules have to be installed and configured + String artificialPtMode = "pt_w_drt_allowed"; + PtIntermodalRoutingModesConfigGroup ptIntermodalRoutingModesConfig = ConfigUtils.addOrGetModule(controler.getConfig(), PtIntermodalRoutingModesConfigGroup.class); + PtIntermodalRoutingModesConfigGroup.PtIntermodalRoutingModeParameterSet ptIntermodalRoutingModesParamSet + = new PtIntermodalRoutingModesConfigGroup.PtIntermodalRoutingModeParameterSet(); + + ptIntermodalRoutingModesParamSet.setDelegateMode(TransportMode.pt); + ptIntermodalRoutingModesParamSet.setRoutingMode(artificialPtMode); + + PtIntermodalRoutingModesConfigGroup.PersonAttribute2ValuePair personAttrParamSet + = new PtIntermodalRoutingModesConfigGroup.PersonAttribute2ValuePair(); + personAttrParamSet.setPersonFilterAttribute("canUseDrt"); + personAttrParamSet.setPersonFilterValue("true"); + ptIntermodalRoutingModesParamSet.addPersonAttribute2ValuePair(personAttrParamSet); + + ptIntermodalRoutingModesConfig.addParameterSet(ptIntermodalRoutingModesParamSet); + + controler.addOverridingModule(new PtIntermodalRoutingModesModule()); + + //SRRConfigGroup needs to have the same personFilterAttr and Value as PtIntermodalRoutingModesConfigGroup + SwissRailRaptorConfigGroup ptConfig = ConfigUtils.addOrGetModule(controler.getConfig(), SwissRailRaptorConfigGroup.class); + ptConfig.setUseIntermodalAccessEgress(true); + + for (String drtMode : nonPtModes) { + SwissRailRaptorConfigGroup.IntermodalAccessEgressParameterSet intermodalParamSet = new SwissRailRaptorConfigGroup.IntermodalAccessEgressParameterSet(); + intermodalParamSet.setMode(drtMode); + ptConfig.addParameterSet(intermodalParamSet); + intermodalParamSet.setPersonFilterAttribute("canUseDrt"); + intermodalParamSet.setPersonFilterValue("true"); + intermodalParamSet.setInitialSearchRadius(10000.); + intermodalParamSet.setMaxRadius(10000.); + intermodalParamSet.setSearchExtensionRadius(1000.); + intermodalParamSet.setStopFilterAttribute("allowDrtAccessEgress"); + } + + controler.addOverridingModule(new AbstractModule() { + @Override + public void install() { + bind(RaptorIntermodalAccessEgress.class).to(EnhancedRaptorIntermodalAccessEgress.class); + } + }); + + //finally the new pt mode has to be added to subtourModeChoice + SubtourModeChoiceConfigGroup modeChoiceConfigGroup = ConfigUtils.addOrGetModule(controler.getConfig(), SubtourModeChoiceConfigGroup.class); + List modes = new ArrayList<>(); + Collections.addAll(modes, modeChoiceConfigGroup.getModes()); + modes.add(artificialPtMode); + modeChoiceConfigGroup.setModes(modes.toArray(new String[0])); + } + + private record StopsControlerListener(String mode, + OutputDirectoryHierarchy controlerIO, + String stopsFile) implements StartupListener { + + private static final String OUTPUT_FILE_NAME = "stops.xml"; + + @Override + public void notifyStartup(StartupEvent event) { + try { + Files.copy(Path.of(stopsFile), Path.of(controlerIO.getOutputFilename(mode + "_" + OUTPUT_FILE_NAME))); + } catch (IOException e) { + log.fatal(e); + } + } + } +} diff --git a/src/main/java/org/matsim/run/prepare/DrtStopsWriter.java b/src/main/java/org/matsim/run/prepare/DrtStopsWriter.java index 2ca310c0..21c33a5a 100644 --- a/src/main/java/org/matsim/run/prepare/DrtStopsWriter.java +++ b/src/main/java/org/matsim/run/prepare/DrtStopsWriter.java @@ -32,15 +32,16 @@ public final class DrtStopsWriter extends MatsimXmlWriter { private final String mode; private Geometry serviceArea = null; - private final String outputFolder; private final Network network; private final String stopsData; + private final String stopsFileName; - DrtStopsWriter(String stopsData, Network network, String mode, ShpOptions shp, String outputFolder) { + DrtStopsWriter(String stopsData, Network network, String mode, ShpOptions shp, String outputFile) { this.network = network; this.mode = mode; - this.outputFolder = outputFolder; this.stopsData = stopsData; + this.stopsFileName = outputFile; + //If you just say serviceArea = shp.getGeometry() instead of looping through features //somehow the first feature only is taken -sm0222 List features = shp.readFeatures(); @@ -56,7 +57,7 @@ public final class DrtStopsWriter extends MatsimXmlWriter { } void write() throws UncheckedIOException, IOException { - this.openFile(outputFolder + "/leipzig-v1.1-" + mode + "-stops.xml"); + this.openFile(this.stopsFileName); this.writeXmlHead(); this.writeDoctype("transitSchedule", "http://www.matsim.org/files/dtd/transitSchedule_v1.dtd"); this.writeStartTag("transitSchedule", null); @@ -69,51 +70,50 @@ void write() throws UncheckedIOException, IOException { private void writeTransitStops(Network network) throws IOException { // Write csv file for adjusted stop location - FileWriter csvWriter = new FileWriter(outputFolder + "/leipzig-v1.1-" - + mode + "-stops-locations.csv"); - csvWriter.append("Stop ID"); - csvWriter.append(","); - csvWriter.append("Link ID"); - csvWriter.append(","); - csvWriter.append("X"); - csvWriter.append(","); - csvWriter.append("Y"); - csvWriter.append("\n"); - - // Read original data csv - log.info("Start processing the network. This may take some time..."); - - BufferedReader csvReader = new BufferedReader(new FileReader(stopsData)); - csvReader.readLine(); - while (true) { - String stopEntry = csvReader.readLine(); - if (stopEntry == null) { - break; - } - String[] stopData = stopEntry.split(";"); - // write stop - Coord coord = new Coord(Double.parseDouble(stopData[2]), Double.parseDouble(stopData[3])); - - if (serviceArea == null || MGC.coord2Point(coord).within(serviceArea)) { - List> attributes = new ArrayList>(5); - attributes.add(createTuple("id", stopData[0])); - attributes.add(createTuple("x", stopData[2])); - attributes.add(createTuple("y", stopData[3])); - Link link = getStopLink(coord, network); - attributes.add(createTuple("linkRefId", link.getId().toString())); - this.writeStartTag("stopFacility", attributes, true); - - csvWriter.append(stopData[0]); - csvWriter.append(","); - csvWriter.append(link.getId().toString()); - csvWriter.append(","); - csvWriter.append(Double.toString(link.getToNode().getCoord().getX())); - csvWriter.append(","); - csvWriter.append(Double.toString(link.getToNode().getCoord().getY())); - csvWriter.append("\n"); + try (FileWriter csvWriter = new FileWriter(stopsFileName + "-stops-locations.csv")) { + csvWriter.append("Stop ID"); + csvWriter.append(","); + csvWriter.append("Link ID"); + csvWriter.append(","); + csvWriter.append("X"); + csvWriter.append(","); + csvWriter.append("Y"); + csvWriter.append("\n"); + + // Read original data csv + log.info("Start processing the network. This may take some time..."); + + BufferedReader csvReader = new BufferedReader(new FileReader(stopsData)); + csvReader.readLine(); + while (true) { + String stopEntry = csvReader.readLine(); + if (stopEntry == null) { + break; + } + String[] stopData = stopEntry.split(";"); + // write stop + Coord coord = new Coord(Double.parseDouble(stopData[2]), Double.parseDouble(stopData[3])); + + if (serviceArea == null || MGC.coord2Point(coord).within(serviceArea)) { + List> attributes = new ArrayList>(5); + attributes.add(createTuple("id", stopData[0])); + attributes.add(createTuple("x", stopData[2])); + attributes.add(createTuple("y", stopData[3])); + Link link = getStopLink(coord, network); + attributes.add(createTuple("linkRefId", link.getId().toString())); + this.writeStartTag("stopFacility", attributes, true); + + csvWriter.append(stopData[0]); + csvWriter.append(","); + csvWriter.append(link.getId().toString()); + csvWriter.append(","); + csvWriter.append(Double.toString(link.getToNode().getCoord().getX())); + csvWriter.append(","); + csvWriter.append(Double.toString(link.getToNode().getCoord().getY())); + csvWriter.append("\n"); + } } } - csvWriter.close(); } private Link getStopLink(Coord coord, Network network) { diff --git a/src/main/java/org/matsim/run/prepare/LeipzigDrtVehicleCreator.java b/src/main/java/org/matsim/run/prepare/LeipzigDrtVehicleCreator.java index 2b8f1aee..44713f01 100644 --- a/src/main/java/org/matsim/run/prepare/LeipzigDrtVehicleCreator.java +++ b/src/main/java/org/matsim/run/prepare/LeipzigDrtVehicleCreator.java @@ -1,5 +1,6 @@ package org.matsim.run.prepare; +import com.google.common.collect.Sets; import com.opencsv.CSVWriter; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -35,7 +36,7 @@ description = "Writes drt vehicles file" ) -public class LeipzigDrtVehicleCreator implements MATSimAppCommand { +public final class LeipzigDrtVehicleCreator implements MATSimAppCommand { private static final Logger log = LogManager.getLogger(LeipzigDrtVehicleCreator.class); @@ -82,11 +83,38 @@ public Integer call() throws Exception { TransportModeNetworkFilter filter = new TransportModeNetworkFilter(network); filter.filter(drtNetwork, modes); - List serviceAreas = shp.readFeatures(); - MatsimVehicleReader reader = new MatsimVehicleReader(vehicles); reader.readFile(vehTypesFile); + createDrtVehicles(vehicles, drtNetwork, shp, noVehiclesPerArea, drtMode); + + String string = vehTypesFile.split("xml")[0].substring(0, vehTypesFile.split("xml")[0].length() - 1) + "-scaledFleet-caseNamav-" + + noVehiclesPerArea + "veh.xml"; + + //write files + new MatsimVehicleWriter(vehicles).writeFile(vehTypesFile.split("xml")[0].substring(0, vehTypesFile.split("xml")[0].length() - 1) + "-scaledFleet-caseNamav-" + + noVehiclesPerArea + "veh.xml"); + writeVehStartPositionsCSV(drtNetwork, vehTypesFile.split("xml")[0].substring(0, vehTypesFile.split("xml")[0].length() - 1) + "-scaledFleet-caseNamav-" + + noVehiclesPerArea + "veh_startPositions.csv"); + + return 0; + } + + /** + * Creates Drt vehicles for an area, which can consist of multiple, connected single areas (features). + * Use this method if you want to create drt vehicles for one single service area. + */ + public void createDrtVehicles(Vehicles vehicles, Network network, ShpOptions shp, int noVehiclesPerArea, String drtMode) { + + List serviceAreas = shp.readFeatures(); + + //delete existing drtVehicles + for (Id vehId : vehicles.getVehicles().keySet()) { + vehicles.removeVehicle(vehId); + } + + createDrtVehTypeIfMissing(vehicles); + VehicleType drtType = null; //this is ugly hard coded and should maybe be converted into a run input parameter @@ -96,25 +124,43 @@ public Integer call() throws Exception { } } + Network filteredNetwork = NetworkUtils.createNetwork(); + TransportModeNetworkFilter filter = new TransportModeNetworkFilter(network); + filter.filter(filteredNetwork, Sets.newHashSet(drtMode)); + for (SimpleFeature serviceArea : serviceAreas) { - createVehiclesByRandomPointInShape(serviceArea, drtNetwork, noVehiclesPerArea, serviceStartTime, - serviceEndTime, serviceAreas.indexOf(serviceArea), drtType); + createVehiclesByRandomPointInShape(serviceArea, filteredNetwork, noVehiclesPerArea, serviceStartTime, + serviceEndTime, serviceAreas.indexOf(serviceArea), drtType, drtMode, vehicles); } + } - String string = vehTypesFile.split("xml")[0].substring(0, vehTypesFile.split("xml")[0].length() - 1) + "-scaledFleet-caseNamav-" - + noVehiclesPerArea + "veh.xml"; + /** + * Creates Drt vehicles for a single area (feature). + * Use this method if you want to create drt vehicles for one single, separated + independent service area. + */ + public void createDrtVehiclesForSingleArea(Vehicles vehicles, Network network, SimpleFeature feature, int noVehiclesPerArea, String drtMode) { - //write files - new MatsimVehicleWriter(vehicles).writeFile(vehTypesFile.split("xml")[0].substring(0, vehTypesFile.split("xml")[0].length() - 1) + "-scaledFleet-caseNamav-" - + noVehiclesPerArea + "veh.xml"); - writeVehStartPositionsCSV(drtNetwork, vehTypesFile.split("xml")[0].substring(0, vehTypesFile.split("xml")[0].length() - 1) + "-scaledFleet-caseNamav-" - + noVehiclesPerArea + "veh_startPositions.csv"); + createDrtVehTypeIfMissing(vehicles); - return 0; + VehicleType drtType = null; + + //this is ugly hard coded and should maybe be converted into a run input parameter + for (VehicleType type : vehicles.getVehicleTypes().values()) { + if (type.getId().toString().contains("conventional")) { + drtType = type; + } + } + + Network filteredNetwork = NetworkUtils.createNetwork(); + TransportModeNetworkFilter filter = new TransportModeNetworkFilter(network); + filter.filter(filteredNetwork, Sets.newHashSet(drtMode)); + + createVehiclesByRandomPointInShape(feature, filteredNetwork, noVehiclesPerArea, serviceStartTime, + serviceEndTime, 1, drtType, drtMode, vehicles); } private void createVehiclesByRandomPointInShape(SimpleFeature feature, Network network, int noVehiclesPerArea, - double serviceStartTime, double serviceEndTime, int serviceAreaCount, VehicleType drtType) { + double serviceStartTime, double serviceEndTime, int serviceAreaCount, VehicleType drtType, String drtMode, Vehicles vehicles) { Geometry geometry = (Geometry) feature.getDefaultGeometry(); for (int i = 0; i < noVehiclesPerArea; i++) { @@ -177,4 +223,18 @@ private void writeVehStartPositionsCSV(Network drtNetwork, String outputFile) { log.error(e); } } + + /** + *Creates a Leipzig standard drt vehicle type if its missing. + */ + private void createDrtVehTypeIfMissing(Vehicles vehicles) { + if (!vehicles.getVehicleTypes().containsKey(Id.create("conventional_vehicle", VehicleType.class))) { + VehicleType vehType = VehicleUtils.createVehicleType(Id.create("conventional_vehicle", VehicleType.class)); + VehicleCapacity capacity = vehType.getCapacity(); + capacity.setSeats(6); + + vehType.setDescription("conventional DRT"); + vehicles.addVehicleType(vehType); + } + } } diff --git a/src/main/java/org/matsim/run/prepare/NetworkOptions.java b/src/main/java/org/matsim/run/prepare/NetworkOptions.java index e5df8e7a..1f7b7591 100644 --- a/src/main/java/org/matsim/run/prepare/NetworkOptions.java +++ b/src/main/java/org/matsim/run/prepare/NetworkOptions.java @@ -4,6 +4,7 @@ import org.matsim.api.core.v01.network.Network; import org.matsim.application.options.ShpOptions; import org.matsim.core.utils.io.IOUtils; +import org.matsim.run.RunLeipzigScenario; import org.matsim.utils.gis.shp2matsim.ShpGeometryUtils; import picocli.CommandLine; @@ -27,7 +28,7 @@ public class NetworkOptions { private Path parkingCapacitiesArea; @CommandLine.Option(names = "--parking-capacities-input", description = "Path to csv file containing parking capacity data per link") private Path inputParkingCapacities; - @CommandLine.Option(names = "--parking-cost-area", description = "Path to SHP file specifying parking cost area") + @CommandLine.Option(names = "--parking-cost-area", description = "Path to SHP file specifying parking cost area", required = true, defaultValue = "input/v" + RunLeipzigScenario.VERSION + "/parkingCostArea/Bewohnerparken_2020.shp") private Path parkingCostArea; @CommandLine.Option(names = "--slow-speed-area", description = "Path to SHP file specifying area of adapted speed") private Path slowSpeedArea; @@ -45,14 +46,15 @@ public boolean hasCarFreeArea() { * Return whether a drt area is defined. */ public boolean hasDrtArea() { - return isDefined(drtArea); } + return isDefined(drtArea); + } /** * Return whether a parkingCost area is defined. */ public boolean hasParkingCostArea() { - return isDefined(parkingCostArea); } - + return isDefined(parkingCostArea); + } /** * Prepare network with given options. @@ -78,12 +80,12 @@ public void prepare(Network network) { if (isDefined(slowSpeedArea)) { if (!Files.exists(slowSpeedArea)) { throw new IllegalArgumentException("Path to slow speed area not found: " + slowSpeedArea); - } else if (slowSpeedRelativeChange==null) { + } else if (slowSpeedRelativeChange == null) { throw new IllegalArgumentException("No relative change value for freeSpeed defined: " + slowSpeedArea); } else { PrepareNetwork.prepareSlowSpeed(network, - ShpGeometryUtils.loadPreparedGeometries(IOUtils.resolveFileOrResource(new ShpOptions(slowSpeedArea, null, null).getShapeFile().toString())), - slowSpeedRelativeChange); + ShpGeometryUtils.loadPreparedGeometries(IOUtils.resolveFileOrResource(new ShpOptions(slowSpeedArea, null, null).getShapeFile().toString())), + slowSpeedRelativeChange); } } @@ -106,6 +108,13 @@ public void prepare(Network network) { } } + /** + * Return path to drt area. + */ + public Path getDrtArea() { + return drtArea; + } + private boolean isDefined(Path p) { return p != null; } diff --git a/src/main/java/org/matsim/run/prepare/ParkingCapacitiesAttacher.java b/src/main/java/org/matsim/run/prepare/ParkingCapacitiesAttacher.java index f1ce0bf9..c836e11c 100644 --- a/src/main/java/org/matsim/run/prepare/ParkingCapacitiesAttacher.java +++ b/src/main/java/org/matsim/run/prepare/ParkingCapacitiesAttacher.java @@ -23,6 +23,7 @@ /** * Attach parking information to links. */ +@Deprecated public final class ParkingCapacitiesAttacher { private static final Logger log = LogManager.getLogger(ParkingCapacitiesAttacher.class); diff --git a/src/main/java/org/matsim/run/prepare/PrepareDrtStops.java b/src/main/java/org/matsim/run/prepare/PrepareDrtStops.java index fe5f6ae9..59f8711e 100644 --- a/src/main/java/org/matsim/run/prepare/PrepareDrtStops.java +++ b/src/main/java/org/matsim/run/prepare/PrepareDrtStops.java @@ -29,8 +29,8 @@ public class PrepareDrtStops implements MATSimAppCommand { private String mode; // mode = "drt", "av" or other specific drt operator mode - @CommandLine.Option(names = "--output-folder", description = "path to output folder", required = true) - private String outputFolder; + @CommandLine.Option(names = "--output", description = "output file name", required = true) + private String outputFile; public static void main(String[] args) throws IOException { new PrepareDrtStops().execute(args); @@ -43,7 +43,7 @@ public Integer call() throws Exception { Scenario scenario = ScenarioUtils.loadScenario(config); Network network = scenario.getNetwork(); - DrtStopsWriter drtStopsWriter = new DrtStopsWriter(stopsData, network, mode, shp, outputFolder); + DrtStopsWriter drtStopsWriter = new DrtStopsWriter(stopsData, network, mode, shp, outputFile); drtStopsWriter.write(); return 0; } diff --git a/src/main/java/org/matsim/run/prepare/PrepareNetwork.java b/src/main/java/org/matsim/run/prepare/PrepareNetwork.java index d48b29bd..ba4a1799 100644 --- a/src/main/java/org/matsim/run/prepare/PrepareNetwork.java +++ b/src/main/java/org/matsim/run/prepare/PrepareNetwork.java @@ -166,17 +166,16 @@ static void prepareParkingCost(Network network, ShpOptions parkingCostShape) { if (!link.getAllowedModes().contains("pt")) { - GeometryFactory gf = new GeometryFactory(); - - LineString line = gf.createLineString(new Coordinate[]{MGC.coord2Coordinate(link.getFromNode().getCoord()), - MGC.coord2Coordinate(link.getToNode().getCoord())}); double oneHourPCost = 0.; double extraHourPCost = 0.; double resPFee = 0.; for (SimpleFeature feature : features) { Geometry geometry = (Geometry) feature.getDefaultGeometry(); - boolean linkInShp = line.intersects(geometry); + // Here we have to use a different logic for checking whether a link is inside the given geometry. + // The standard procedure (as used in the other methods of this class) did include some link out of the geometry. + //for this case we have to be more precise than that. -sme0723 + boolean linkInShp = MGC.coord2Point(link.getCoord()).within(geometry); if (linkInShp && feature.getAttribute(hourlyParkingCostAttrName) != null) { diff --git a/src/main/java/org/matsim/run/prepare/PreparePopulation.java b/src/main/java/org/matsim/run/prepare/PreparePopulation.java index cf274ab3..c7336ce0 100644 --- a/src/main/java/org/matsim/run/prepare/PreparePopulation.java +++ b/src/main/java/org/matsim/run/prepare/PreparePopulation.java @@ -42,6 +42,9 @@ public class PreparePopulation implements MATSimAppCommand { @CommandLine.Mixin private ShpOptions shp; + @CommandLine.Option(names = "--phase", description = "Run pre or post phase", required = true) + private Phase phase; + public static void main(String[] args) { new PreparePopulation().execute(args); } @@ -68,6 +71,23 @@ public Integer call() throws Exception { ShpOptions.Index index = shp.createIndex(RunLeipzigScenario.CRS, "_"); + switch (phase) { + case pre -> prePhase(population); + case post -> postPhase(population, index); + default -> throw new IllegalArgumentException("Illegal phase"); + } + + + PopulationUtils.writePopulation(population, output.toString()); + + return 0; + } + + /** + * This step runs before any other steps. + */ + private void prePhase(Population population) { + Set> toRemove = new HashSet<>(); for (Person person : population.getPersons().values()) { @@ -75,19 +95,8 @@ public Integer call() throws Exception { List activities = TripStructureUtils.getActivities(person.getSelectedPlan(), TripStructureUtils.StageActivityHandling.ExcludeStageActivities); for (Activity act : activities) { // Remove persons having activities after 27hours - if (act.getStartTime().isDefined() && act.getStartTime().seconds() > 27 * 3600) toRemove.add(person.getId()); - - // Reduce unnecessary precision - if (act.getCoord() != null) { - act.setCoord(new Coord(round(act.getCoord().getX()), round(act.getCoord().getY()))); - } - } - - Coord home = setHomeCoordinate(person); - if (home == null || !index.contains(home)) { - PopulationUtils.putSubpopulation(person, "outside_person"); } // Set car availability to "never" for agents below 18 years old @@ -154,9 +163,32 @@ public Integer call() throws Exception { log.info("Removing {} out of {} persons with activities outside valid range", toRemove.size(), population.getPersons().size()); toRemove.forEach(population::removePerson); - PopulationUtils.writePopulation(population, output.toString()); + } - return 0; + /** + * This step runs at the very end. + */ + private void postPhase(Population population, ShpOptions.Index index) { + + for (Person person : population.getPersons().values()) { + + List activities = TripStructureUtils.getActivities(person.getSelectedPlan(), TripStructureUtils.StageActivityHandling.ExcludeStageActivities); + for (Activity act : activities) { + // Reduce unnecessary precision + if (act.getCoord() != null) { + act.setCoord(new Coord(round(act.getCoord().getX()), round(act.getCoord().getY()))); + } + } + + // Only handles persons + if (!"person".equals(PopulationUtils.getSubpopulation(person))) + continue; + + Coord home = setHomeCoordinate(person); + if (home == null || !index.contains(home)) { + PopulationUtils.putSubpopulation(person, "outside_person"); + } + } } /** @@ -183,4 +215,7 @@ private Coord setHomeCoordinate(Person person) { return null; } + + enum Phase {pre, post} + } diff --git a/src/main/java/org/matsim/run/prepare/PrepareTransitSchedule.java b/src/main/java/org/matsim/run/prepare/PrepareTransitSchedule.java index bfc47cdb..698c6d48 100644 --- a/src/main/java/org/matsim/run/prepare/PrepareTransitSchedule.java +++ b/src/main/java/org/matsim/run/prepare/PrepareTransitSchedule.java @@ -46,6 +46,29 @@ public static void main(String[] args) { @Override public Integer call() throws Exception { + + Config config = ConfigUtils.createConfig(); + config.transit().setTransitScheduleFile(input); + config.global().setCoordinateSystem("EPSG:25832"); + Scenario scenario = ScenarioUtils.loadScenario(config); + TransitSchedule transitSchedule = scenario.getTransitSchedule(); + + prepareDrtIntermodality(transitSchedule, shp, railwaysOnly); + + TransitScheduleWriter writer = new TransitScheduleWriter(transitSchedule); + writer.writeFile(output); + + return 0; + } + + /** + * method for adapting an existing TransitSchedule such that transit stops are available for intermodality between. + * public transit and the modelled drt mode(s). + * @param transitSchedule transitSchedule loaded from scenario. + * @param shp shp file of drt service area + */ + public void prepareDrtIntermodality(TransitSchedule transitSchedule, ShpOptions shp, boolean railwaysOnly) { + Geometry intermodalArea = null; List features = shp.readFeatures(); for (SimpleFeature feature : features) { @@ -58,12 +81,6 @@ public Integer call() throws Exception { // Geometry intermodalArea = shp.getGeometry(); - Config config = ConfigUtils.createConfig(); - config.transit().setTransitScheduleFile(input); - config.global().setCoordinateSystem("EPSG:25832"); - Scenario scenario = ScenarioUtils.loadScenario(config); - TransitSchedule transitSchedule = scenario.getTransitSchedule(); - if (railwaysOnly) { filterRailboundTransitLines(transitSchedule); } else { @@ -81,10 +98,6 @@ public Integer call() throws Exception { ProjectionUtils.putCRS(transitSchedule, "EPSG:25832"); - TransitScheduleWriter writer = new TransitScheduleWriter(transitSchedule); - writer.writeFile(output); - - return 0; } private void filterRailboundTransitLines(TransitSchedule transitSchedule) { diff --git a/src/main/python/calibrate.py b/src/main/python/calibrate.py index 0db66fe6..ca498859 100644 --- a/src/main/python/calibrate.py +++ b/src/main/python/calibrate.py @@ -1,62 +1,33 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -import os - +import calibration import geopandas as gpd -import pandas as pd -from matsim import calibration - -# %% - -if os.path.exists("srv.csv"): - srv = pd.read_csv("srv.csv") - sim = pd.read_csv("sim.csv") - - _, adj = calibration.calc_adjusted_mode_share(sim, srv) - - print(srv.groupby("mode").sum()) - - print("Adjusted") - print(adj.groupby("mode").sum()) - - adj.to_csv("srv_adj.csv", index=False) # %% modes = ["walk", "car", "ride", "pt", "bike"] fixed_mode = "walk" initial = { - "bike": -1.9, - "pt": -0.7, - "car": -1.4, - "ride": -4 + "bike": 0.30, + "pt": -0.16, + "car": 0.39, + "ride": -1.42 } -# Original target +# Target from SrV target = { - "walk": 0.243, - "bike": 0.206, - "pt": 0.162, - "car": 0.301, - "ride": 0.086 + "walk": 0.270794, + "bike": 0.196723, + "pt": 0.166204, + "car": 0.286468, + "ride": 0.079811 } -# Adjusted for distance distribution -# target = { -# "bike": 0.205680, -# "car": 0.321617, -# "pt": 0.186261, -# "ride": 0.093713, -# "walk": 0.192729 -# } - city = gpd.read_file("../scenarios/input/leipzig-utm32n/leipzig-utm32n.shp") -homes = pd.read_csv("../input/v1.2/leipzig-v1.2-homes.csv", dtype={"person": "str"}) def f(persons): - persons = pd.merge(persons, homes, how="inner", left_on="person", right_on="person") persons = gpd.GeoDataFrame(persons, geometry=gpd.points_from_xy(persons.home_x, persons.home_y)) df = gpd.sjoin(persons.set_crs("EPSG:25832"), city, how="inner", op="intersects") @@ -70,15 +41,16 @@ def filter_modes(df): return df[df.main_mode.isin(modes)] -study, obj = calibration.create_mode_share_study("calib", "matsim-leipzig-1.2-SNAPSHOT-25ee44a.jar", +study, obj = calibration.create_mode_share_study("calib", "matsim-leipzig-1.2-SNAPSHOT-e85f5c7.jar", "../input/v1.2/leipzig-v1.2-25pct.config.xml", modes, target, initial_asc=initial, - args="--25pct --config:TimeAllocationMutator.mutationRange=900", + args="--10pct --parking-cost-area ../input/v1.2/parkingCostArea/Bewohnerparken_2020.shp --config:TimeAllocationMutator.mutationRange=900", jvm_args="-Xmx46G -Xms46G -XX:+AlwaysPreTouch -XX:+UseParallelGC", - person_filter=f, map_trips=filter_modes, + transform_persons=f, transform_trips=filter_modes, + lr=calibration.linear_lr_scheduler(start=0.3, interval=8), chain_runs=calibration.default_chain_scheduler) # %% -study.optimize(obj, 10) +study.optimize(obj, 4) diff --git a/src/main/python/create_ref.py b/src/main/python/create_ref.py new file mode 100644 index 00000000..f14677da --- /dev/null +++ b/src/main/python/create_ref.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from matsim.scenariogen.data import TripMode, run_create_ref_data + + +def person_filter(df): + """ Default person filter for reference data. """ + return df[df.reporting_day <= 5] + + +def trip_filter(df): + # Motorcycles are counted as cars + df.loc[df.main_mode == TripMode.MOTORCYCLE, "main_mode"] = TripMode.CAR + + # Other modes are ignored in the total share + # Long distance mode are ignored as well + return df[(df.main_mode != "other") & (df.gis_length < 100)] + + +if __name__ == "__main__": + person, trips, share = run_create_ref_data.create("../../../../shared-svn/projects/NaMAV/data/SrV_2018", + person_filter, trip_filter, + run_create_ref_data.InvalidHandling.REMOVE_PERSONS) + + print(share) diff --git a/src/main/resources/META-INF/services/org.matsim.simwrapper.DashboardProvider b/src/main/resources/META-INF/services/org.matsim.simwrapper.DashboardProvider new file mode 100644 index 00000000..8c8552bb --- /dev/null +++ b/src/main/resources/META-INF/services/org.matsim.simwrapper.DashboardProvider @@ -0,0 +1 @@ +org.matsim.dashboard.LeipzigDashboardProvider \ No newline at end of file diff --git a/src/main/resources/mode_share_per_dist_ref.csv b/src/main/resources/mode_share_per_dist_ref.csv new file mode 100644 index 00000000..7647d343 --- /dev/null +++ b/src/main/resources/mode_share_per_dist_ref.csv @@ -0,0 +1,31 @@ +dist_group,main_mode,mean_dist,share +0 - 1000,bike,625.6709239066038,0.1498342300634102 +0 - 1000,car,673.6384671092165,0.07636039086702505 +0 - 1000,pt,670.1827034315171,0.014101280024101288 +0 - 1000,ride,707.110835224723,0.024163955654332738 +0 - 1000,walk,476.61610403606227,0.7355401433911307 +1000 - 2000,bike,1413.529565635515,0.2976757821440052 +1000 - 2000,car,1516.4289451983675,0.18314890770726613 +1000 - 2000,pt,1518.669203788909,0.13345080823082492 +1000 - 2000,ride,1521.2388298001295,0.0799250711582756 +1000 - 2000,walk,1315.3774223589255,0.30579943075962823 +2000 - 5000,bike,3225.5356519111447,0.30772535018665886 +2000 - 5000,car,3428.1135956590256,0.2767741787199647 +2000 - 5000,pt,3500.8253179738435,0.2595885822887284 +2000 - 5000,ride,3486.3862346869414,0.10835558269878572 +2000 - 5000,walk,2801.165158479957,0.04755630610586222 +5000 - 10000,bike,6456.922399742452,0.115790702653595 +5000 - 10000,car,7169.54499240835,0.47486333861330693 +5000 - 10000,pt,6940.885272741965,0.2842637177313413 +5000 - 10000,ride,7038.083385646529,0.11736304734076954 +5000 - 10000,walk,8068.343472517595,0.00771919366098719 +10000 - 20000,bike,11501.183789143368,0.05251179348646703 +10000 - 20000,car,13226.472750426878,0.6472724582139662 +10000 - 20000,pt,12902.874110830719,0.2016743449840846 +10000 - 20000,ride,13106.119597514538,0.09771615235870768 +10000 - 20000,walk,13810.0,0.0008252509567746149 +20000+,bike,26308.486401621365,0.00416730209981478 +20000+,car,45398.01656256677,0.7394682209830556 +20000+,pt,49455.60522417894,0.1698405150810158 +20000+,ride,39425.596734908366,0.08652396183611383 +20000+,walk,,0.0 diff --git a/src/main/resources/mode_share_ref.csv b/src/main/resources/mode_share_ref.csv new file mode 100644 index 00000000..febdad6e --- /dev/null +++ b/src/main/resources/mode_share_ref.csv @@ -0,0 +1,31 @@ +dist_group,main_mode,mean_dist,share +0 - 1000,bike,625.6709239066038,0.042427666982270844 +0 - 1000,car,673.6384671092165,0.021622517317779033 +0 - 1000,pt,670.1827034315171,0.003992975521235183 +0 - 1000,ride,707.110835224723,0.006842363477574613 +0 - 1000,walk,476.61610403606227,0.20827852382385292 +1000 - 2000,bike,1413.529565635515,0.046904293446247414 +1000 - 2000,car,1516.4289451983675,0.028858478340389557 +1000 - 2000,pt,1518.669203788909,0.021027628867938655 +1000 - 2000,ride,1521.2388298001295,0.012593664705670988 +1000 - 2000,walk,1315.3774223589255,0.04818432367167251 +2000 - 5000,bike,3225.5356519111447,0.08381183999633887 +2000 - 5000,car,3428.1135956590256,0.07538200271094032 +2000 - 5000,pt,3500.8253179738435,0.07070134686811573 +2000 - 5000,ride,3486.3862346869414,0.02951164327005261 +2000 - 5000,walk,2801.165158479957,0.012952399000419555 +5000 - 10000,bike,6456.922399742452,0.019847375312634377 +5000 - 10000,car,7169.54499240835,0.081395057527758 +5000 - 10000,pt,6940.885272741965,0.04872488519615632 +5000 - 10000,ride,7038.083385646529,0.020116886719094527 +5000 - 10000,walk,8068.343472517595,0.0013231263839797098 +10000 - 20000,bike,11501.183789143368,0.003530790840523247 +10000 - 20000,car,13226.472750426878,0.0435213409226598 +10000 - 20000,pt,12902.874110830719,0.013560190630735951 +10000 - 20000,ride,13106.119597514538,0.006570243993060608 +10000 - 20000,walk,13810.0,5.548826893645858e-05 +20000+,bike,26308.486401621365,0.00020112627705902024 +20000+,car,45398.01656256677,0.035688914968844986 +20000+,pt,49455.60522417894,0.008197003642608329 +20000+,ride,39425.596734908366,0.004175901315450057 +20000+,walk,,0.0 diff --git a/src/main/resources/mode_users_ref.csv b/src/main/resources/mode_users_ref.csv new file mode 100644 index 00000000..b9fd3cfc --- /dev/null +++ b/src/main/resources/mode_users_ref.csv @@ -0,0 +1,6 @@ +main_mode,user +car,0.3114662795761375 +pt,0.2730115678797592 +ride,0.1377769897765719 +walk,0.3812113445425378 +bike,0.22968769172366532 diff --git a/src/test/java/org/matsim/run/ChessboardParkingTest.java b/src/test/java/org/matsim/run/ChessboardParkingTest.java index 71fd000a..bedc7eb5 100644 --- a/src/test/java/org/matsim/run/ChessboardParkingTest.java +++ b/src/test/java/org/matsim/run/ChessboardParkingTest.java @@ -13,153 +13,41 @@ import org.matsim.api.core.v01.network.Link; import org.matsim.api.core.v01.network.Network; import org.matsim.api.core.v01.population.*; +import org.matsim.contrib.vsp.scenario.SnzActivities; import org.matsim.core.config.Config; import org.matsim.core.config.ConfigUtils; -import org.matsim.core.config.groups.*; +import org.matsim.core.config.groups.FacilitiesConfigGroup; +import org.matsim.core.config.groups.PlansCalcRouteConfigGroup; +import org.matsim.core.config.groups.StrategyConfigGroup; +import org.matsim.core.config.groups.VspExperimentalConfigGroup; import org.matsim.core.controler.AbstractModule; import org.matsim.core.controler.Controler; import org.matsim.core.controler.OutputDirectoryHierarchy; import org.matsim.core.population.PopulationUtils; -import org.matsim.core.population.algorithms.ParallelPersonAlgorithmUtils; -import org.matsim.core.population.algorithms.PersonPrepareForSim; -import org.matsim.core.router.*; +import org.matsim.core.router.TripStructureUtils; import org.matsim.core.scenario.MutableScenario; import org.matsim.core.scenario.ScenarioUtils; import org.matsim.core.utils.io.IOUtils; import org.matsim.examples.ExamplesUtils; import org.matsim.testcases.MatsimTestUtils; -import playground.vsp.openberlinscenario.cemdap.output.ActivityTypes; import java.net.URL; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; -import static org.matsim.core.config.groups.PlanCalcScoreConfigGroup.*; +import static org.matsim.core.config.groups.PlanCalcScoreConfigGroup.ActivityParams; /** * Test class to test a parking logic, which included several areas where only residents are allowed to park */ public class ChessboardParkingTest { private static final Logger log = LogManager.getLogger(ChessboardParkingTest.class); + // private static final String HOME_ZONE_ID = "homeLinkId"; + final String RE_ROUTE_LEIPZIG = "ReRouteLeipzig"; @Rule public MatsimTestUtils utils = new MatsimTestUtils(); -// private static final String HOME_ZONE_ID = "homeLinkId"; - final String RE_ROUTE_LEIPZIG = "ReRouteLeipzig"; - - enum Situation { - //1) defaultLogic to defaultLogic - //1.1) defaultLogic linkInResidentialArea (=home act) to defaultLogic linkOutsideResidentialArea - defaultLogicLinkInResidentialAreaToDefaultLogicLinkOutsideResidentialArea, - //1.2) defaultLogic linkOutsideResidentialArea to defaultLogic linkInResidentialArea (=home act) - defaultLogicLinkOutsideResidentialAreaToDefaultLogicLinkInResidentialArea, - //1.3) defaultLogic linkOutsideResidentialArea to defaultLogic linkOutsideResidentialArea - defaultLogicLinkOutsideResidentialAreaToDefaultLogicLinkOutsideResidentialArea, - - //2) parkingSearchLogicLeipzig to defaultLogic - //2.1) parkingSearchLogicLeipzig linkInResidentialArea (!=home act) to defaultLogic linkOutsideResidentialArea - parkingSearchLogicLeipzigLinkInResidentialAreaToDefaultLogicLinkOutsideResidentialArea, - //2.2) parkingSearchLogicLeipzig linkInResidentialArea (!=home act) to defaultLogic linkInResidentialArea (=home act) - parkingSearchLogicLeipzigLinkInResidentialAreaToDefaultLogicLinkInResidentialArea, - - //3) defaultLogic to parkingSearchLogicLeipzig - //3.1) defaultLogic linkOutsideResidentialArea to parkingSearchLogicLeipzig linkInResidentialArea (!=home act) - defaultLogicLinkOutsideResidentialAreaToParkingSearchLogicLeipzigLinkInResidentialArea, - //3.2) defaultLogic linkInResidentialArea (=home act) to parkingSearchLogicLeipzig linkInResidentialArea (!=home act) - defaultLogicLinkInResidentialAreaToParkingSearchLogicLeipzigLinkInResidentialArea, - - //4) parkingSearchLogicLeipzig to parkingSearchLogicLeipzig - //4.1) parkingSearchLogicLeipzig linkInResidentialArea (!=home act) to parkingSearchLogicLeipzig linkInResidentialArea (!=home act) - parkingSearchLogicLeipzigLinkInResidentialAreaToParkingSearchLogicLeipzigLinkInResidentialArea - } - - @Test - public final void runChessboardParkingTest1() { - - URL url = IOUtils.extendUrl(ExamplesUtils.getTestScenarioURL("chessboard"), "config.xml"); - - for (Situation situation : Situation.values()) { - Config config = ConfigUtils.loadConfig(url); - config.controler().setLastIteration(1); - config.controler().setOutputDirectory(utils.getOutputDirectory() + "/" + situation.toString()); - config.global().setNumberOfThreads(0); - config.qsim().setNumberOfThreads(1); - config.controler().setOverwriteFileSetting(OutputDirectoryHierarchy.OverwriteFileSetting.deleteDirectoryIfExists); - config.plansCalcRoute().setAccessEgressType(PlansCalcRouteConfigGroup.AccessEgressType.accessEgressModeToLink); - - config.strategy().clearStrategySettings(); - { - StrategyConfigGroup.StrategySettings stratSets = new StrategyConfigGroup.StrategySettings(); - stratSets.setWeight(1.); - stratSets.setStrategyName(RE_ROUTE_LEIPZIG); - config.strategy().addStrategySettings(stratSets); - } - - config.facilities().setFacilitiesSource(FacilitiesConfigGroup.FacilitiesSource.onePerActivityLinkInPlansFile); - - config.planCalcScore().addActivityParams(new ActivityParams(TripStructureUtils.createStageActivityType("parking")).setScoringThisActivityAtAll(false)); - - config.vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); - - MutableScenario scenario = (MutableScenario) ScenarioUtils.loadScenario(config); - - Population population = PopulationUtils.createPopulation(config); - createExampleParkingPopulation(population, scenario.getNetwork(), situation); - scenario.setPopulation(population); - log.warn("population size=" + scenario.getPopulation().getPersons().size() +" for case" + situation); - -// System.exit(-1); - //why ist the above here? Doesn't it end the test / sim so it is of no use here?! -sme0523 - - - - Controler controler = new Controler(scenario); - controler.addOverridingModule(new AbstractModule() { - @Override - public void install() { -// this.bind( MultimodalLinkChooser.class ).toInstance( new LeipzigMultimodalLinkChooser() ); - this.addPlanStrategyBinding(RE_ROUTE_LEIPZIG).toProvider(LeipzigRoutingStrategyProvider.class); - // yyyy this only uses it during replanning!!! kai, apr'23 - } - }); - - TestParkingListener testParkingListener = new TestParkingListener(); - controler.addOverridingModule(new AbstractModule() { - @Override - public void install() { - addEventHandlerBinding().toInstance(testParkingListener); - } - }); - controler.run(); - - getAssertions(situation, testParkingListener); - } - - - } - - -// static final class LeipzigMultimodalLinkChooser implements MultimodalLinkChooser { -// -// private final MultimodalLinkChooser delegate; -// @Inject LeipzigMultimodalLinkChooser() { -// this.delegate = RouterUtils.getMultimodalLinkChooserDefault(); -// } -// -// @Override public Link decideOnLink( Facility facility, Network network, RoutingRequest routingRequest ){ -// Link result = null ; -// -//// Person person = routingRequest.getPerson(); -//// -//// String homeZoneId = (String) person.getAttributes().getAttribute( HOME_ZONE_ID ); -//// -//// if ( homeLinkId.equals( facility.getLinkId().toString() ) ) { -//// -//// fall back on default: -//// if ( result == null ){ -//// result = this.delegate.decideOnLink( facility, network, routingRequest ); -//// } -// return result; -// } -// } static void createExampleParkingPopulation(Population population, Network network, Situation situation) { @@ -174,8 +62,8 @@ static void createExampleParkingPopulation(Population population, Network networ switch (situation) { //1.1 case defaultLogicLinkInResidentialAreaToDefaultLogicLinkOutsideResidentialArea -> { - Activity originActivity = factory.createActivityFromLinkId(ActivityTypes.HOME, originLink.getId()); - Activity destinationActivity = factory.createActivityFromLinkId(ActivityTypes.LEISURE, destinationLink.getId()); + Activity originActivity = factory.createActivityFromLinkId(SnzActivities.home.name(), originLink.getId()); + Activity destinationActivity = factory.createActivityFromLinkId(SnzActivities.leisure.name(), destinationLink.getId()); originActivity.setEndTime(3600.); LeipzigUtils.setLinkParkingTypeToInsideResidentialArea(originLink); @@ -186,8 +74,8 @@ static void createExampleParkingPopulation(Population population, Network networ } //1.2 case defaultLogicLinkOutsideResidentialAreaToDefaultLogicLinkInResidentialArea -> { - Activity originActivity = factory.createActivityFromLinkId(ActivityTypes.LEISURE, originLink.getId()); - Activity destinationActivity = factory.createActivityFromLinkId(ActivityTypes.HOME, destinationLink.getId()); + Activity originActivity = factory.createActivityFromLinkId(SnzActivities.leisure.name(), originLink.getId()); + Activity destinationActivity = factory.createActivityFromLinkId(SnzActivities.home.name(), destinationLink.getId()); originActivity.setEndTime(3600.); LeipzigUtils.setLinkParkingTypeToInsideResidentialArea(destinationLink); @@ -198,8 +86,8 @@ static void createExampleParkingPopulation(Population population, Network networ } //1.3 case defaultLogicLinkOutsideResidentialAreaToDefaultLogicLinkOutsideResidentialArea -> { - Activity originActivity = factory.createActivityFromLinkId(ActivityTypes.LEISURE, originLink.getId()); - Activity destinationActivity = factory.createActivityFromLinkId(ActivityTypes.WORK, destinationLink.getId()); + Activity originActivity = factory.createActivityFromLinkId(SnzActivities.leisure.name(), originLink.getId()); + Activity destinationActivity = factory.createActivityFromLinkId(SnzActivities.work.name(), destinationLink.getId()); originActivity.setEndTime(3600.); plan.addActivity(originActivity); @@ -208,8 +96,8 @@ static void createExampleParkingPopulation(Population population, Network networ } //2.1 case parkingSearchLogicLeipzigLinkInResidentialAreaToDefaultLogicLinkOutsideResidentialArea -> { - Activity originActivity = factory.createActivityFromLinkId(ActivityTypes.LEISURE, originLink.getId()); - Activity destinationActivity = factory.createActivityFromLinkId(ActivityTypes.HOME, destinationLink.getId()); + Activity originActivity = factory.createActivityFromLinkId(SnzActivities.leisure.name(), originLink.getId()); + Activity destinationActivity = factory.createActivityFromLinkId(SnzActivities.home.name(), destinationLink.getId()); originActivity.setEndTime(3600.); LeipzigUtils.setLinkParkingTypeToInsideResidentialArea(originLink); @@ -220,8 +108,8 @@ static void createExampleParkingPopulation(Population population, Network networ } //2.2 case parkingSearchLogicLeipzigLinkInResidentialAreaToDefaultLogicLinkInResidentialArea -> { - Activity originActivity = factory.createActivityFromLinkId(ActivityTypes.LEISURE, originLink.getId()); - Activity destinationActivity = factory.createActivityFromLinkId(ActivityTypes.HOME, destinationLink.getId()); + Activity originActivity = factory.createActivityFromLinkId(SnzActivities.leisure.name(), originLink.getId()); + Activity destinationActivity = factory.createActivityFromLinkId(SnzActivities.home.name(), destinationLink.getId()); originActivity.setEndTime(3600.); LeipzigUtils.setLinkParkingTypeToInsideResidentialArea(originLink); @@ -233,8 +121,8 @@ static void createExampleParkingPopulation(Population population, Network networ } //3.1 case defaultLogicLinkOutsideResidentialAreaToParkingSearchLogicLeipzigLinkInResidentialArea -> { - Activity originActivity = factory.createActivityFromLinkId(ActivityTypes.LEISURE, originLink.getId()); - Activity destinationActivity = factory.createActivityFromLinkId(ActivityTypes.WORK, destinationLink.getId()); + Activity originActivity = factory.createActivityFromLinkId(SnzActivities.leisure.name(), originLink.getId()); + Activity destinationActivity = factory.createActivityFromLinkId(SnzActivities.work.name(), destinationLink.getId()); originActivity.setEndTime(3600.); LeipzigUtils.setLinkParkingTypeToInsideResidentialArea(destinationLink); @@ -245,8 +133,8 @@ static void createExampleParkingPopulation(Population population, Network networ } //3.2 case defaultLogicLinkInResidentialAreaToParkingSearchLogicLeipzigLinkInResidentialArea -> { - Activity originActivity = factory.createActivityFromLinkId(ActivityTypes.HOME, originLink.getId()); - Activity destinationActivity = factory.createActivityFromLinkId(ActivityTypes.LEISURE, destinationLink.getId()); + Activity originActivity = factory.createActivityFromLinkId(SnzActivities.home.name(), originLink.getId()); + Activity destinationActivity = factory.createActivityFromLinkId(SnzActivities.leisure.name(), destinationLink.getId()); originActivity.setEndTime(3600.); LeipzigUtils.setLinkParkingTypeToInsideResidentialArea(originLink); @@ -258,8 +146,8 @@ static void createExampleParkingPopulation(Population population, Network networ } //4.1 case parkingSearchLogicLeipzigLinkInResidentialAreaToParkingSearchLogicLeipzigLinkInResidentialArea -> { - Activity originActivity = factory.createActivityFromLinkId(ActivityTypes.LEISURE, originLink.getId()); - Activity destinationActivity = factory.createActivityFromLinkId(ActivityTypes.WORK, destinationLink.getId()); + Activity originActivity = factory.createActivityFromLinkId(SnzActivities.leisure.name(), originLink.getId()); + Activity destinationActivity = factory.createActivityFromLinkId(SnzActivities.work.name(), destinationLink.getId()); originActivity.setEndTime(3600.); LeipzigUtils.setLinkParkingTypeToInsideResidentialArea(originLink); @@ -277,25 +165,95 @@ static void createExampleParkingPopulation(Population population, Network networ population.addPerson(person); } - class TestParkingListener implements ActivityStartEventHandler { + @Test + public final void runChessboardParkingTest1() { - HashMap, List> parkingActivities = new HashMap<>(); + URL url = IOUtils.extendUrl(ExamplesUtils.getTestScenarioURL("chessboard"), "config.xml"); - @Override - public void handleEvent(ActivityStartEvent activityStartEvent) { - if (activityStartEvent.getActType().equals("parking interaction")) { - if (!parkingActivities.containsKey(activityStartEvent.getPersonId())) { - parkingActivities.put(activityStartEvent.getPersonId(), new ArrayList<>(Arrays.asList(activityStartEvent))); - } else parkingActivities.get(activityStartEvent.getPersonId()).add(activityStartEvent); + for (Situation situation : Situation.values()) { + Config config = ConfigUtils.loadConfig(url); + config.controler().setLastIteration(1); + config.controler().setOutputDirectory(utils.getOutputDirectory() + "/" + situation.toString()); + config.global().setNumberOfThreads(0); + config.qsim().setNumberOfThreads(1); + config.controler().setOverwriteFileSetting(OutputDirectoryHierarchy.OverwriteFileSetting.deleteDirectoryIfExists); + config.plansCalcRoute().setAccessEgressType(PlansCalcRouteConfigGroup.AccessEgressType.accessEgressModeToLink); + + config.strategy().clearStrategySettings(); + { + StrategyConfigGroup.StrategySettings stratSets = new StrategyConfigGroup.StrategySettings(); + stratSets.setWeight(1.); + stratSets.setStrategyName(RE_ROUTE_LEIPZIG); + config.strategy().addStrategySettings(stratSets); } - } - @Override - public void reset(int iteration) { - ActivityStartEventHandler.super.reset(iteration); + config.facilities().setFacilitiesSource(FacilitiesConfigGroup.FacilitiesSource.onePerActivityLinkInPlansFile); + + config.planCalcScore().addActivityParams(new ActivityParams(TripStructureUtils.createStageActivityType("parking")).setScoringThisActivityAtAll(false)); + + config.vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + + MutableScenario scenario = (MutableScenario) ScenarioUtils.loadScenario(config); + + Population population = PopulationUtils.createPopulation(config); + createExampleParkingPopulation(population, scenario.getNetwork(), situation); + scenario.setPopulation(population); + log.warn("population size=" + scenario.getPopulation().getPersons().size() + " for case" + situation); + +// System.exit(-1); + //why ist the above here? Doesn't it end the test / sim so it is of no use here?! -sme0523 + + + Controler controler = new Controler(scenario); + controler.addOverridingModule(new AbstractModule() { + @Override + public void install() { +// this.bind( MultimodalLinkChooser.class ).toInstance( new LeipzigMultimodalLinkChooser() ); + this.addPlanStrategyBinding(RE_ROUTE_LEIPZIG).toProvider(LeipzigRoutingStrategyProvider.class); + // yyyy this only uses it during replanning!!! kai, apr'23 + } + }); + + TestParkingListener testParkingListener = new TestParkingListener(); + controler.addOverridingModule(new AbstractModule() { + @Override + public void install() { + addEventHandlerBinding().toInstance(testParkingListener); + } + }); + controler.run(); + + getAssertions(situation, testParkingListener); } + + } + +// static final class LeipzigMultimodalLinkChooser implements MultimodalLinkChooser { +// +// private final MultimodalLinkChooser delegate; +// @Inject LeipzigMultimodalLinkChooser() { +// this.delegate = RouterUtils.getMultimodalLinkChooserDefault(); +// } +// +// @Override public Link decideOnLink( Facility facility, Network network, RoutingRequest routingRequest ){ +// Link result = null ; +// +//// Person person = routingRequest.getPerson(); +//// +//// String homeZoneId = (String) person.getAttributes().getAttribute( HOME_ZONE_ID ); +//// +//// if ( homeLinkId.equals( facility.getLinkId().toString() ) ) { +//// +//// fall back on default: +//// if ( result == null ){ +//// result = this.delegate.decideOnLink( facility, network, routingRequest ); +//// } +// return result; +// } +// } + private void getAssertions(Situation situation, TestParkingListener listener) { switch (situation) { @@ -303,65 +261,110 @@ private void getAssertions(Situation situation, TestParkingListener listener) { //1.1 case defaultLogicLinkInResidentialAreaToDefaultLogicLinkOutsideResidentialArea -> { Assert.assertFalse(listener.parkingActivities.containsKey(Id.createPersonId(String.valueOf( - Situation.defaultLogicLinkInResidentialAreaToDefaultLogicLinkOutsideResidentialArea)))); + Situation.defaultLogicLinkInResidentialAreaToDefaultLogicLinkOutsideResidentialArea)))); } //1.2 case defaultLogicLinkOutsideResidentialAreaToDefaultLogicLinkInResidentialArea -> { Assert.assertFalse(listener.parkingActivities.containsKey(Id.createPersonId(String.valueOf( - Situation.defaultLogicLinkOutsideResidentialAreaToDefaultLogicLinkInResidentialArea)))); + Situation.defaultLogicLinkOutsideResidentialAreaToDefaultLogicLinkInResidentialArea)))); } //1.3 case defaultLogicLinkOutsideResidentialAreaToDefaultLogicLinkOutsideResidentialArea -> { Assert.assertFalse(listener.parkingActivities.containsKey(Id.createPersonId(String.valueOf( - Situation.defaultLogicLinkOutsideResidentialAreaToDefaultLogicLinkOutsideResidentialArea)))); + Situation.defaultLogicLinkOutsideResidentialAreaToDefaultLogicLinkOutsideResidentialArea)))); } //2.1 case parkingSearchLogicLeipzigLinkInResidentialAreaToDefaultLogicLinkOutsideResidentialArea -> { Assert.assertTrue(listener.parkingActivities.containsKey(Id.createPersonId(String.valueOf - (Situation.parkingSearchLogicLeipzigLinkInResidentialAreaToDefaultLogicLinkOutsideResidentialArea)))); + (Situation.parkingSearchLogicLeipzigLinkInResidentialAreaToDefaultLogicLinkOutsideResidentialArea)))); Assert.assertEquals("wrong number of parking activites!", 1, listener.parkingActivities.get(Id.createPersonId(String.valueOf( - Situation.parkingSearchLogicLeipzigLinkInResidentialAreaToDefaultLogicLinkOutsideResidentialArea))).size()); + Situation.parkingSearchLogicLeipzigLinkInResidentialAreaToDefaultLogicLinkOutsideResidentialArea))).size()); Assert.assertEquals("wrong origin parking link", Id.createLinkId("169"), listener.parkingActivities.get(Id.createPersonId(String.valueOf( - Situation.parkingSearchLogicLeipzigLinkInResidentialAreaToDefaultLogicLinkOutsideResidentialArea))).get(0).getLinkId()); + Situation.parkingSearchLogicLeipzigLinkInResidentialAreaToDefaultLogicLinkOutsideResidentialArea))).get(0).getLinkId()); } //2.2 case parkingSearchLogicLeipzigLinkInResidentialAreaToDefaultLogicLinkInResidentialArea -> { Assert.assertTrue(listener.parkingActivities.containsKey(Id.createPersonId(String.valueOf - (Situation.parkingSearchLogicLeipzigLinkInResidentialAreaToDefaultLogicLinkInResidentialArea)))); + (Situation.parkingSearchLogicLeipzigLinkInResidentialAreaToDefaultLogicLinkInResidentialArea)))); Assert.assertEquals("wrong number of parking activites!", 1, listener.parkingActivities.get(Id.createPersonId(String.valueOf( - Situation.parkingSearchLogicLeipzigLinkInResidentialAreaToDefaultLogicLinkInResidentialArea))).size()); + Situation.parkingSearchLogicLeipzigLinkInResidentialAreaToDefaultLogicLinkInResidentialArea))).size()); Assert.assertEquals("wrong origin parking link", Id.createLinkId("169"), listener.parkingActivities.get(Id.createPersonId(String.valueOf( - Situation.parkingSearchLogicLeipzigLinkInResidentialAreaToDefaultLogicLinkInResidentialArea))).get(0).getLinkId()); + Situation.parkingSearchLogicLeipzigLinkInResidentialAreaToDefaultLogicLinkInResidentialArea))).get(0).getLinkId()); } //3.1 case defaultLogicLinkOutsideResidentialAreaToParkingSearchLogicLeipzigLinkInResidentialArea -> { Assert.assertTrue(listener.parkingActivities.containsKey(Id.createPersonId(String.valueOf - (Situation.defaultLogicLinkOutsideResidentialAreaToParkingSearchLogicLeipzigLinkInResidentialArea)))); + (Situation.defaultLogicLinkOutsideResidentialAreaToParkingSearchLogicLeipzigLinkInResidentialArea)))); Assert.assertEquals("wrong number of parking activites!", 1, listener.parkingActivities.get(Id.createPersonId(String.valueOf( - Situation.defaultLogicLinkOutsideResidentialAreaToParkingSearchLogicLeipzigLinkInResidentialArea))).size()); + Situation.defaultLogicLinkOutsideResidentialAreaToParkingSearchLogicLeipzigLinkInResidentialArea))).size()); Assert.assertEquals("wrong destination parking link", Id.createLinkId("133"), listener.parkingActivities.get(Id.createPersonId(String.valueOf( - Situation.defaultLogicLinkOutsideResidentialAreaToParkingSearchLogicLeipzigLinkInResidentialArea))).get(0).getLinkId()); + Situation.defaultLogicLinkOutsideResidentialAreaToParkingSearchLogicLeipzigLinkInResidentialArea))).get(0).getLinkId()); } //3.2 case defaultLogicLinkInResidentialAreaToParkingSearchLogicLeipzigLinkInResidentialArea -> { Assert.assertTrue(listener.parkingActivities.containsKey(Id.createPersonId(String.valueOf - (Situation.defaultLogicLinkInResidentialAreaToParkingSearchLogicLeipzigLinkInResidentialArea)))); + (Situation.defaultLogicLinkInResidentialAreaToParkingSearchLogicLeipzigLinkInResidentialArea)))); Assert.assertEquals("wrong number of parking activites!", 1, listener.parkingActivities.get(Id.createPersonId(String.valueOf( - Situation.defaultLogicLinkInResidentialAreaToParkingSearchLogicLeipzigLinkInResidentialArea))).size()); + Situation.defaultLogicLinkInResidentialAreaToParkingSearchLogicLeipzigLinkInResidentialArea))).size()); Assert.assertEquals("wrong destination parking link", Id.createLinkId("133"), listener.parkingActivities.get(Id.createPersonId(String.valueOf( - Situation.defaultLogicLinkInResidentialAreaToParkingSearchLogicLeipzigLinkInResidentialArea))).get(0).getLinkId()); + Situation.defaultLogicLinkInResidentialAreaToParkingSearchLogicLeipzigLinkInResidentialArea))).get(0).getLinkId()); } //4.1 case parkingSearchLogicLeipzigLinkInResidentialAreaToParkingSearchLogicLeipzigLinkInResidentialArea -> { Assert.assertTrue(listener.parkingActivities.containsKey(Id.createPersonId(String.valueOf - (Situation.parkingSearchLogicLeipzigLinkInResidentialAreaToParkingSearchLogicLeipzigLinkInResidentialArea)))); + (Situation.parkingSearchLogicLeipzigLinkInResidentialAreaToParkingSearchLogicLeipzigLinkInResidentialArea)))); Assert.assertEquals("wrong number of parking activites!", 2, listener.parkingActivities.get(Id.createPersonId(String.valueOf( - Situation.parkingSearchLogicLeipzigLinkInResidentialAreaToParkingSearchLogicLeipzigLinkInResidentialArea))).size()); + Situation.parkingSearchLogicLeipzigLinkInResidentialAreaToParkingSearchLogicLeipzigLinkInResidentialArea))).size()); Assert.assertEquals("wrong origin parking link", Id.createLinkId("169"), listener.parkingActivities.get(Id.createPersonId(String.valueOf( - Situation.parkingSearchLogicLeipzigLinkInResidentialAreaToParkingSearchLogicLeipzigLinkInResidentialArea))).get(0).getLinkId()); + Situation.parkingSearchLogicLeipzigLinkInResidentialAreaToParkingSearchLogicLeipzigLinkInResidentialArea))).get(0).getLinkId()); Assert.assertEquals("wrong destination parking link", Id.createLinkId("133"), listener.parkingActivities.get(Id.createPersonId(String.valueOf( - Situation.parkingSearchLogicLeipzigLinkInResidentialAreaToParkingSearchLogicLeipzigLinkInResidentialArea))).get(1).getLinkId()); + Situation.parkingSearchLogicLeipzigLinkInResidentialAreaToParkingSearchLogicLeipzigLinkInResidentialArea))).get(1).getLinkId()); } } } + + enum Situation { + //1) defaultLogic to defaultLogic + //1.1) defaultLogic linkInResidentialArea (=home act) to defaultLogic linkOutsideResidentialArea + defaultLogicLinkInResidentialAreaToDefaultLogicLinkOutsideResidentialArea, + //1.2) defaultLogic linkOutsideResidentialArea to defaultLogic linkInResidentialArea (=home act) + defaultLogicLinkOutsideResidentialAreaToDefaultLogicLinkInResidentialArea, + //1.3) defaultLogic linkOutsideResidentialArea to defaultLogic linkOutsideResidentialArea + defaultLogicLinkOutsideResidentialAreaToDefaultLogicLinkOutsideResidentialArea, + + //2) parkingSearchLogicLeipzig to defaultLogic + //2.1) parkingSearchLogicLeipzig linkInResidentialArea (!=home act) to defaultLogic linkOutsideResidentialArea + parkingSearchLogicLeipzigLinkInResidentialAreaToDefaultLogicLinkOutsideResidentialArea, + //2.2) parkingSearchLogicLeipzig linkInResidentialArea (!=home act) to defaultLogic linkInResidentialArea (=home act) + parkingSearchLogicLeipzigLinkInResidentialAreaToDefaultLogicLinkInResidentialArea, + + //3) defaultLogic to parkingSearchLogicLeipzig + //3.1) defaultLogic linkOutsideResidentialArea to parkingSearchLogicLeipzig linkInResidentialArea (!=home act) + defaultLogicLinkOutsideResidentialAreaToParkingSearchLogicLeipzigLinkInResidentialArea, + //3.2) defaultLogic linkInResidentialArea (=home act) to parkingSearchLogicLeipzig linkInResidentialArea (!=home act) + defaultLogicLinkInResidentialAreaToParkingSearchLogicLeipzigLinkInResidentialArea, + + //4) parkingSearchLogicLeipzig to parkingSearchLogicLeipzig + //4.1) parkingSearchLogicLeipzig linkInResidentialArea (!=home act) to parkingSearchLogicLeipzig linkInResidentialArea (!=home act) + parkingSearchLogicLeipzigLinkInResidentialAreaToParkingSearchLogicLeipzigLinkInResidentialArea + } + + class TestParkingListener implements ActivityStartEventHandler { + + HashMap, List> parkingActivities = new HashMap<>(); + + @Override + public void handleEvent(ActivityStartEvent activityStartEvent) { + if (activityStartEvent.getActType().equals("parking interaction")) { + if (!parkingActivities.containsKey(activityStartEvent.getPersonId())) { + parkingActivities.put(activityStartEvent.getPersonId(), new ArrayList<>(Arrays.asList(activityStartEvent))); + } else parkingActivities.get(activityStartEvent.getPersonId()).add(activityStartEvent); + } + } + + @Override + public void reset(int iteration) { + ActivityStartEventHandler.super.reset(iteration); + } + } } diff --git a/src/test/java/org/matsim/run/ParkingLeipzigTest.java b/src/test/java/org/matsim/run/ParkingLeipzigTest.java new file mode 100644 index 00000000..9e4fd243 --- /dev/null +++ b/src/test/java/org/matsim/run/ParkingLeipzigTest.java @@ -0,0 +1,44 @@ +package org.matsim.run; + +import org.junit.Test; +import org.matsim.analysis.ParkingLocation; +import org.matsim.api.core.v01.population.PlanElement; +import org.matsim.api.core.v01.population.Population; +import org.matsim.application.MATSimApplication; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.controler.OutputDirectoryHierarchy; +import org.matsim.core.population.PopulationUtils; +import org.matsim.simwrapper.SimWrapperConfigGroup; +import java.nio.file.Path; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertEquals; + + +public class ParkingLeipzigTest { + + private static final String URL = "https://svn.vsp.tu-berlin.de/repos/public-svn/matsim/scenarios/countries/de/leipzig/leipzig-v1.2/input/"; + private static final String exampleShp = "input/v1.2/drtServiceArea/Leipzig_stadt.shp"; + + @Test + public final void runPoint1pctIntegrationTest() { + Path output = Path.of("output-parking-test/it-1pct"); + Config config = ConfigUtils.loadConfig("input/v1.2/leipzig-v1.2-25pct.config.xml"); + config.global().setNumberOfThreads(1); + config.qsim().setNumberOfThreads(1); + config.controler().setLastIteration(0); + config.controler().setOverwriteFileSetting(OutputDirectoryHierarchy.OverwriteFileSetting.deleteDirectoryIfExists); + config.controler().setOutputDirectory(output.toString()); + ConfigUtils.addOrGetModule(config, SimWrapperConfigGroup.class).defaultDashboards = SimWrapperConfigGroup.Mode.disabled; + config.plans().setInputFile(URL + "leipzig-v1.2-0.1pct.plans-initial.xml.gz"); + + MATSimApplication.execute(RunLeipzigScenario.class, config, "run", "--1pct","--drt-area", exampleShp, "--post-processing", "disabled", + "--parking-cost-area", "input/v" + RunLeipzigScenario.VERSION + "/parkingCostArea/Bewohnerparken_2020.shp", + "--intermodality", "drtAsAccessEgressForPt"); + + assertThat(output) + .exists() + .isNotEmptyDirectory(); + new ParkingLocation().execute("--directory", output.toString()); + } +} diff --git a/src/test/java/org/matsim/run/RunLeipzigIntegrationTest.java b/src/test/java/org/matsim/run/RunLeipzigIntegrationTest.java index 65c91299..fb3802cf 100644 --- a/src/test/java/org/matsim/run/RunLeipzigIntegrationTest.java +++ b/src/test/java/org/matsim/run/RunLeipzigIntegrationTest.java @@ -3,16 +3,15 @@ import org.junit.Assert; import org.junit.Ignore; import org.junit.Test; +import org.matsim.analysis.ParkingLocation; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Network; import org.matsim.application.MATSimApplication; -import org.matsim.application.options.ShpOptions; import org.matsim.core.config.Config; import org.matsim.core.config.ConfigUtils; import org.matsim.core.controler.OutputDirectoryHierarchy; import org.matsim.core.network.NetworkUtils; import org.matsim.simwrapper.SimWrapperConfigGroup; -import picocli.CommandLine; import java.nio.file.Path; @@ -21,38 +20,34 @@ public class RunLeipzigIntegrationTest { - private static final String URL = "https://svn.vsp.tu-berlin.de/repos/public-svn/matsim/scenarios/countries/de/leipzig/leipzig-v1.1/input/"; - @CommandLine.Mixin - private ShpOptions shp; - private static final String exampleShp = "input/v1.2/drtServiceArea/preliminary-serviceArea-leipzig-utm32n.shp"; + private static final String URL = "https://svn.vsp.tu-berlin.de/repos/public-svn/matsim/scenarios/countries/de/leipzig/leipzig-v1.2/input/"; + private static final String exampleShp = "input/v1.2/drtServiceArea/Leipzig_stadt.shp"; @Test public final void runPoint1pctIntegrationTest() { Path output = Path.of("output/it-1pct"); - Config config = ConfigUtils.loadConfig("input/v1.2/leipzig-test.with-drt.config.xml"); + Config config = ConfigUtils.loadConfig("input/v1.2/leipzig-v1.2-25pct.config.xml"); config.global().setNumberOfThreads(1); config.qsim().setNumberOfThreads(1); config.controler().setLastIteration(1); config.controler().setOverwriteFileSetting(OutputDirectoryHierarchy.OverwriteFileSetting.deleteDirectoryIfExists); config.controler().setOutputDirectory(output.toString()); - config.network().setInputFile(URL + "drt-base-case/leipzig-v1.1-network-with-pt-drt.xml.gz"); - config.plans().setInputFile(URL + "leipzig-v1.1-0.1pct.plans.xml.gz"); - config.transit().setTransitScheduleFile(URL + "leipzig-v1.1-transitSchedule.xml.gz"); - config.transit().setVehiclesFile(URL + "leipzig-v1.1-transitVehicles.xml.gz"); - config.vehicles().setVehiclesFile(URL + "drt-base-case/leipzig-v1.1-vehicle-types-with-drt-scaledFleet.xml"); + config.plans().setInputFile(URL + "leipzig-v1.2-0.1pct.plans-initial.xml.gz"); ConfigUtils.addOrGetModule(config, SimWrapperConfigGroup.class).defaultDashboards = SimWrapperConfigGroup.Mode.disabled; MATSimApplication.execute(RunLeipzigScenario.class, config, "run", "--1pct", "--slow-speed-area", exampleShp, - "--slow-speed-relative-change", "0.5","--drt-area", exampleShp, "--drt-modes", "drtNorth,drtSoutheast", "--post-processing", "disabled", - "--parking-cost-area", exampleShp); + "--slow-speed-relative-change", "0.5","--drt-area", exampleShp, "--post-processing", "disabled", + "--parking-cost-area", exampleShp, "--intermodality", "drtAsAccessEgressForPt"); assertThat(output) .exists() .isNotEmptyDirectory(); + new ParkingLocation().execute("--directory", output.toString()); + Network network = NetworkUtils.readNetwork(output + "/" + config.controler().getRunId() + ".output_network.xml.gz"); assertTrue(network.getLinks().get(Id.createLinkId("24232899")).getFreespeed() < 12.501000000000001); assertTrue(network.getLinks().get(Id.createLinkId("24675139")).getFreespeed() < 7.497); diff --git a/src/test/java/org/matsim/run/RunModalExperimentTest.java b/src/test/java/org/matsim/run/RunModalExperimentTest.java index 5435e020..182f36bb 100644 --- a/src/test/java/org/matsim/run/RunModalExperimentTest.java +++ b/src/test/java/org/matsim/run/RunModalExperimentTest.java @@ -1,13 +1,11 @@ package org.matsim.run; import com.google.common.collect.Lists; -import org.checkerframework.checker.units.qual.C; import org.junit.Assert; import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.matsim.api.core.v01.Id; -import org.matsim.api.core.v01.Scenario; import org.matsim.api.core.v01.TransportMode; import org.matsim.api.core.v01.population.*; import org.matsim.application.MATSimApplication; @@ -16,21 +14,15 @@ import org.matsim.core.config.Config; import org.matsim.core.config.ConfigUtils; import org.matsim.core.config.groups.VspExperimentalConfigGroup; -import org.matsim.core.controler.Controler; -import org.matsim.core.controler.ControlerUtils; import org.matsim.core.controler.OutputDirectoryHierarchy; import org.matsim.core.population.PopulationUtils; -import org.matsim.core.scenario.ScenarioUtils; -import org.matsim.core.utils.io.IOUtils; import org.matsim.testcases.MatsimTestUtils; -import java.io.BufferedWriter; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; public class RunModalExperimentTest { diff --git a/src/test/java/org/matsim/run/TimeRestrictedParkingCostHandlerTest.java b/src/test/java/org/matsim/run/TimeRestrictedParkingCostHandlerTest.java index c5303636..016f9df9 100644 --- a/src/test/java/org/matsim/run/TimeRestrictedParkingCostHandlerTest.java +++ b/src/test/java/org/matsim/run/TimeRestrictedParkingCostHandlerTest.java @@ -13,6 +13,7 @@ import org.matsim.api.core.v01.events.handler.PersonMoneyEventHandler; import org.matsim.api.core.v01.network.Link; import org.matsim.api.core.v01.population.*; +import org.matsim.contrib.vsp.scenario.SnzActivities; import org.matsim.core.config.Config; import org.matsim.core.config.ConfigUtils; import org.matsim.core.config.groups.VspExperimentalConfigGroup; @@ -24,7 +25,6 @@ import org.matsim.core.utils.io.IOUtils; import org.matsim.examples.ExamplesUtils; import org.matsim.testcases.MatsimTestUtils; -import playground.vsp.openberlinscenario.cemdap.output.ActivityTypes; import playground.vsp.simpleParkingCostHandler.ParkingCostConfigGroup; import java.net.URL; @@ -57,8 +57,8 @@ void createExamplePopulation(Population population, Scenario scenario, Situation destinationLink.getAttributes().putAttribute(LeipzigUtils.getExtraHourParkingCostLinkAttributeName(), 1.); destinationLink.getAttributes().putAttribute(LeipzigUtils.getResidentialParkingFeeAttributeName(), 1.); - Activity originActivity = factory.createActivityFromLinkId(ActivityTypes.WORK, startLink.getId()); - Activity destinationActivity = factory.createActivityFromLinkId(ActivityTypes.LEISURE, destinationLink.getId()); + Activity originActivity = factory.createActivityFromLinkId(SnzActivities.work.name(), startLink.getId()); + Activity destinationActivity = factory.createActivityFromLinkId(SnzActivities.leisure.name(), destinationLink.getId()); Leg carLeg = factory.createLeg(TransportMode.car); @@ -87,7 +87,7 @@ void createExamplePopulation(Population population, Scenario scenario, Situation // 2.2) eventime outside parking period -> no charging // 3.2) eventTime is later than end of period -> no charging - Activity originActivity2 = factory.createActivityFromLinkId(ActivityTypes.WORK, startLink.getId()); + Activity originActivity2 = factory.createActivityFromLinkId(SnzActivities.work.name(), startLink.getId()); originActivity2.setEndTime(75700.); plan2.addActivity(originActivity2); plan2.addLeg(carLeg); @@ -106,7 +106,7 @@ void createExamplePopulation(Population population, Scenario scenario, Situation plan.addActivity(destinationActivity); // 4.2) eventTime is equal or later than start of period -> charging - Activity originActivity2 = factory.createActivityFromLinkId(ActivityTypes.WORK, startLink.getId()); + Activity originActivity2 = factory.createActivityFromLinkId(SnzActivities.work.name(), startLink.getId()); originActivity2.setEndTime(28900.); plan2.addActivity(originActivity2); plan2.addLeg(carLeg); diff --git a/src/test/java/org/matsim/run/prepare/NetworkOptionsTest.java b/src/test/java/org/matsim/run/prepare/NetworkOptionsTest.java index 5e1abed2..71bb00c3 100644 --- a/src/test/java/org/matsim/run/prepare/NetworkOptionsTest.java +++ b/src/test/java/org/matsim/run/prepare/NetworkOptionsTest.java @@ -22,7 +22,7 @@ public class NetworkOptionsTest { public MatsimTestUtils utils = new MatsimTestUtils(); private static final String URL = "https://svn.vsp.tu-berlin.de/repos/public-svn/matsim/scenarios/countries/de/leipzig/leipzig-v1.1/input/"; - private static final String shpPath = "./input/v1.2/drtServiceArea/preliminary-serviceArea-leipzig-utm32n.shp"; + private static final String shpPath = "./input/v1.2/drtServiceArea/leipzig_flexa_service_area_2021.shp"; private Network network; private NetworkOptions options;