From 4254dc4d81f763d058974dc36abf244b36c5d88c Mon Sep 17 00:00:00 2001 From: Ricardo Ewert Date: Thu, 22 Feb 2024 09:11:50 +0100 Subject: [PATCH 01/12] reorganize shape files input to reduce preprocessing of the shape files --- ...rateSmallScaleCommercialTrafficDemand.java | 22 +- .../LanduseBuildingAnalysis.java | 69 ++--- .../SmallScaleCommercialTrafficUtils.java | 33 ++- .../TrafficVolumeGeneration.java | 2 +- .../TripDistributionMatrix.java | 46 ++-- .../LanduseBuildingAnalysisTest.java | 255 +++++++++--------- ...nerateSmallScaleCommercialTrafficTest.java | 6 + .../SCTUtils.java | 7 +- .../SmallScaleCommercialTrafficUtilsTest.java | 16 +- .../TrafficVolumeGenerationTest.java | 75 +++--- .../TripDistributionMatrixTest.java | 37 +-- .../dataDistributionPerZone.csv | 8 +- .../investigationAreaData.csv | 6 +- .../shp/testRegions.cpg | 1 + .../shp/testRegions.dbf | Bin 0 -> 280 bytes .../shp/testRegions.prj | 1 + .../shp/testRegions.qmd | 26 ++ .../shp/testRegions.shp | Bin 0 -> 372 bytes .../shp/testRegions.shx | Bin 0 -> 116 bytes 19 files changed, 363 insertions(+), 247 deletions(-) create mode 100644 contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/shp/testRegions.cpg create mode 100644 contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/shp/testRegions.dbf create mode 100644 contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/shp/testRegions.prj create mode 100644 contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/shp/testRegions.qmd create mode 100644 contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/shp/testRegions.shp create mode 100644 contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/shp/testRegions.shx diff --git a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java index 46ec4a745b6..6cc38e81e97 100644 --- a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java +++ b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java @@ -135,9 +135,18 @@ private enum SmallScaleCommercialTrafficType { @CommandLine.Option(names = "--includeExistingModels", description = "If models for some segments exist they can be included.") private boolean includeExistingModels; + @CommandLine.Option(names = "--regionsShapeFileName", description = "Path of the region shape file.") + private Path shapeFileRegionsPath; + + @CommandLine.Option(names = "--regionsShapeRegionColumn", description = "Name of the region column in the region shape file.") + private String regionsShapeRegionColumn; + @CommandLine.Option(names = "--zoneShapeFileName", description = "Path of the zone shape file.") private Path shapeFileZonePath; + @CommandLine.Option(names = "--zoneShapeFileNameColumn", description = "Name of the unique column of the name/Id of each zone in the zones shape file.") + private String shapeFileZoneNameColumn; + @CommandLine.Option(names = "--buildingsShapeFileName", description = "Path of the buildings shape file") private Path shapeFileBuildingsPath; @@ -169,6 +178,7 @@ private enum SmallScaleCommercialTrafficType { private Index indexZones; private Index indexBuildings; private Index indexLanduse; + private Index indexInvestigationAreaRegions; public static void main(String[] args) { System.exit(new CommandLine(new GenerateSmallScaleCommercialTrafficDemand()).execute(args)); @@ -225,19 +235,23 @@ public Integer call() throws Exception { if (!Files.exists(shapeFileZonePath)) { throw new Exception("Required districts shape file {} not found" + shapeFileZonePath.toString()); } + if (!Files.exists(shapeFileRegionsPath)) { + throw new Exception("Required regions shape file {} not found" + shapeFileRegionsPath.toString()); + } Path inputDataDirectory = Path.of(config.getContext().toURI()).getParent(); ShpOptions shpZones = new ShpOptions(shapeFileZonePath, shapeCRS, StandardCharsets.UTF_8); - indexZones = SmallScaleCommercialTrafficUtils.getIndexZones(shapeFileZonePath, shapeCRS); + indexZones = SmallScaleCommercialTrafficUtils.getIndexZones(shapeFileZonePath, shapeCRS, shapeFileZoneNameColumn); indexBuildings = SmallScaleCommercialTrafficUtils.getIndexBuildings(shapeFileBuildingsPath, shapeCRS); indexLanduse = SmallScaleCommercialTrafficUtils.getIndexLanduse(shapeFileLandusePath, shapeCRS); + indexInvestigationAreaRegions = SmallScaleCommercialTrafficUtils.getIndexRegions(shapeFileRegionsPath, shapeCRS, regionsShapeRegionColumn); Map> resultingDataPerZone = LanduseBuildingAnalysis .createInputDataDistribution(output, landuseCategoriesAndDataConnection, inputDataDirectory, usedLanduseConfiguration.toString(), indexLanduse, indexZones, - indexBuildings, buildingsPerZone); - + indexBuildings, indexInvestigationAreaRegions, shapeFileZoneNameColumn, buildingsPerZone); + //TODO regionLinksMap umbenennen, da es alle Links einer Zone enthält Map, Link>> regionLinksMap = filterLinksForZones(scenario, indexZones, buildingsPerZone); switch (usedSmallScaleCommercialTrafficType) { @@ -971,7 +985,7 @@ private TripDistributionMatrix createTripDistribution( Collections.shuffle(listOfZones); for (String stopZone : listOfZones) { odMatrix.setTripDistributionValue(startZone, stopZone, modeORvehType, purpose, smallScaleCommercialTrafficType, - network, regionLinksMap, resistanceFactor); + network, regionLinksMap, resistanceFactor, shapeFileZoneNameColumn); } } } diff --git a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/LanduseBuildingAnalysis.java b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/LanduseBuildingAnalysis.java index faffac894c1..4104b09983a 100644 --- a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/LanduseBuildingAnalysis.java +++ b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/LanduseBuildingAnalysis.java @@ -56,11 +56,12 @@ public class LanduseBuildingAnalysis { static Map> createInputDataDistribution(Path output, Map> landuseCategoriesAndDataConnection, Path inputDataDirectory, String usedLanduseConfiguration, Index indexLanduse, Index indexZones, - Index indexBuildings, Map>> buildingsPerZone) + Index indexBuildings, Index indexInvestigationAreaRegions, + String shapeFileZoneNameColumn, Map>> buildingsPerZone) throws IOException { Map> resultingDataPerZone = new HashMap<>(); - Map zoneIdNameConnection = new HashMap<>(); + Map zoneIdRegionConnection = new HashMap<>(); Path outputFileInOutputFolder = output.resolve("calculatedData").resolve("dataDistributionPerZone.csv"); landuseCategoriesAndDataConnection.put("Inhabitants", @@ -91,7 +92,7 @@ static Map> createInputDataDistribution(Path ou .setSkipHeaderRecord(true).build().parse(reader); for (CSVRecord record : parse) { - String zoneID = record.get("areaID"); + String zoneID = record.get("zoneID"); resultingDataPerZone.put(zoneID, new Object2DoubleOpenHashMap<>()); for (int n = 2; n < parse.getHeaderMap().size(); n++) { resultingDataPerZone.get(zoneID).mergeDouble(parse.getHeaderNames().get(n), @@ -109,18 +110,18 @@ static Map> createInputDataDistribution(Path ou log.info("New analyze for data distribution is started. The used method is: " + usedLanduseConfiguration); Map> landuseCategoriesPerZone = new HashMap<>(); - createLanduseDistribution(landuseCategoriesPerZone, indexLanduse, indexZones, + createLanduseDistribution(landuseCategoriesPerZone, indexLanduse, indexZones, indexInvestigationAreaRegions, usedLanduseConfiguration, indexBuildings, landuseCategoriesAndDataConnection, - buildingsPerZone, zoneIdNameConnection); + buildingsPerZone, shapeFileZoneNameColumn, zoneIdRegionConnection); Map> investigationAreaData = new HashMap<>(); readAreaData(investigationAreaData, inputDataDirectory); createResultingDataForLanduseInZones(landuseCategoriesPerZone, investigationAreaData, resultingDataPerZone, - landuseCategoriesAndDataConnection); + landuseCategoriesAndDataConnection, zoneIdRegionConnection); SmallScaleCommercialTrafficUtils.writeResultOfDataDistribution(resultingDataPerZone, outputFileInOutputFolder, - zoneIdNameConnection); + zoneIdRegionConnection); } return resultingDataPerZone; @@ -131,10 +132,10 @@ static Map> createInputDataDistribution(Path ou * and the original data. */ private static void createResultingDataForLanduseInZones( - Map> landuseCategoriesPerZone, - Map> investigationAreaData, - Map> resultingDataPerZone, - Map> landuseCategoriesAndDataConnection) { + Map> landuseCategoriesPerZone, + Map> investigationAreaData, + Map> resultingDataPerZone, + Map> landuseCategoriesAndDataConnection, Map zoneIdRegionConnection) { Map> totalSquareMetersPerCategory = new HashMap>(); Map> totalEmployeesInCategoriesPerZone = new HashMap>(); @@ -149,7 +150,7 @@ private static void createResultingDataForLanduseInZones( // connects the collected landuse data with the needed categories for (String zoneId : landuseCategoriesPerZone.keySet()) { - String investigationArea = zoneId.split("_")[0]; + String regionOfZone = zoneIdRegionConnection.get(zoneId); resultingDataPerZone.put(zoneId, new Object2DoubleOpenHashMap<>()); for (String categoryLanduse : landuseCategoriesPerZone.get(zoneId).keySet()) for (String categoryData : landuseCategoriesAndDataConnection.keySet()) { @@ -161,7 +162,7 @@ private static void createResultingDataForLanduseInZones( if (categoryLanduse.equals("commercial")) additionalArea = additionalArea * 0.5; resultingDataPerZone.get(zoneId).mergeDouble(categoryData, additionalArea, Double::sum); - totalSquareMetersPerCategory.get(investigationArea).mergeDouble(categoryData, additionalArea, + totalSquareMetersPerCategory.get(regionOfZone).mergeDouble(categoryData, additionalArea, Double::sum); } } @@ -176,12 +177,12 @@ private static void createResultingDataForLanduseInZones( .forEach(c -> checkPercentages.computeIfAbsent(c, k -> new Object2DoubleOpenHashMap<>())); for (String zoneId : resultingDataPerZone.keySet()) for (String categoryData : resultingDataPerZone.get(zoneId).keySet()) { - String investigationArea = zoneId.split("_")[0]; + String regionOfZone = zoneIdRegionConnection.get(zoneId); double newValue = resultingDataPerZone.get(zoneId).getDouble(categoryData) - / totalSquareMetersPerCategory.get(investigationArea).getDouble(categoryData); + / totalSquareMetersPerCategory.get(regionOfZone).getDouble(categoryData); resultingDataPerZone.get(zoneId).replace(categoryData, resultingDataPerZone.get(zoneId).getDouble(categoryData), newValue); - checkPercentages.get(investigationArea).mergeDouble(categoryData, + checkPercentages.get(regionOfZone).mergeDouble(categoryData, resultingDataPerZone.get(zoneId).getDouble(categoryData), Double::sum); } // tests the result @@ -193,21 +194,21 @@ private static void createResultingDataForLanduseInZones( } // calculates the data per zone and category data for (String zoneId : resultingDataPerZone.keySet()) { - String investigationArea = zoneId.split("_")[0]; + String regionOfZone = zoneIdRegionConnection.get(zoneId); for (String categoryData : resultingDataPerZone.get(zoneId).keySet()) { double percentageValue = resultingDataPerZone.get(zoneId).getDouble(categoryData); - int inputDataForCategory = investigationAreaData.get(investigationArea).get(categoryData); + int inputDataForCategory = investigationAreaData.get(regionOfZone).get(categoryData); double resultingNumberPerCategory = percentageValue * inputDataForCategory; resultingDataPerZone.get(zoneId).replace(categoryData, percentageValue, resultingNumberPerCategory); - totalEmployeesPerCategories.get(investigationArea).mergeDouble(categoryData, resultingNumberPerCategory, + totalEmployeesPerCategories.get(regionOfZone).mergeDouble(categoryData, resultingNumberPerCategory, Double::sum); if (!categoryData.equals("Inhabitants")) - totalEmployeesInCategoriesPerZone.get(investigationArea).mergeDouble(zoneId, + totalEmployeesInCategoriesPerZone.get(regionOfZone).mergeDouble(zoneId, resultingNumberPerCategory, Double::sum); } - if (totalEmployeesInCategoriesPerZone.get(investigationArea).getDouble(zoneId) != 0) + if (totalEmployeesInCategoriesPerZone.get(regionOfZone).getDouble(zoneId) != 0) resultingDataPerZone.get(zoneId).mergeDouble("Employee", - totalEmployeesInCategoriesPerZone.get(investigationArea).getDouble(zoneId), Double::sum); + totalEmployeesInCategoriesPerZone.get(regionOfZone).getDouble(zoneId), Double::sum); } } @@ -216,10 +217,10 @@ private static void createResultingDataForLanduseInZones( * the sum of this category in all zones of the zone shape file */ private static void createLanduseDistribution(Map> landuseCategoriesPerZone, - Index indexLanduse, Index indexZones, String usedLanduseConfiguration, + Index indexLanduse, Index indexZones, Index indexInvestigationAreaRegions, String usedLanduseConfiguration, Index indexBuildings, Map> landuseCategoriesAndDataConnection, Map>> buildingsPerZone, - Map zoneIdNameConnection) { + String shapeFileZoneNameColumn, Map zoneIdRegionConnection) { List neededLanduseCategories = List.of("residential", "industrial", "commercial", "retail", "farmyard", "farmland", "construction"); @@ -227,12 +228,20 @@ private static void createLanduseDistribution(Map landuseFeatures = indexLanduse.getAllFeatures(); List zonesFeatures = indexZones.getAllFeatures(); - for (SimpleFeature singleZone : zonesFeatures) { - Object2DoubleMap landusePerCategory = new Object2DoubleOpenHashMap<>(); - landuseCategoriesPerZone.put((String) singleZone.getAttribute("areaID"), landusePerCategory); - zoneIdNameConnection.put((String) singleZone.getAttribute("areaID"), - (String) singleZone.getAttribute("name")); + // TODO comment + Coord middleCoordOfZone = MGC.point2Coord(((Geometry) singleZone.getDefaultGeometry()).getCentroid()); + String regionName = indexInvestigationAreaRegions.query(middleCoordOfZone); + if (regionName != null) { + Object2DoubleMap landusePerCategory = new Object2DoubleOpenHashMap<>(); + String zoneID = (String) singleZone.getAttribute(shapeFileZoneNameColumn); + var previousValue = landuseCategoriesPerZone.putIfAbsent(zoneID, landusePerCategory); + if (previousValue != null) { + throw new IllegalStateException( + "Key " + zoneID + " already exists in the zone map. This should not happen. Please check if the data in the column " + shapeFileZoneNameColumn + " is unique."); + } + zoneIdRegionConnection.put(zoneID, regionName); + } } if (usedLanduseConfiguration.equals("useOSMBuildingsAndLanduse")) { @@ -295,7 +304,7 @@ private static void readAreaData(Map> areaData, Pat if (parser.getHeaderMap().get(csvRecord) > 0) lookUpTable.put(csvRecord, Integer.valueOf(record.get(csvRecord))); } - areaData.put(record.get("Area"), lookUpTable); + areaData.put(record.get("Region"), lookUpTable); } } } diff --git a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/SmallScaleCommercialTrafficUtils.java b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/SmallScaleCommercialTrafficUtils.java index 1ea26e82ee3..690b4f68920 100644 --- a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/SmallScaleCommercialTrafficUtils.java +++ b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/SmallScaleCommercialTrafficUtils.java @@ -77,12 +77,15 @@ public class SmallScaleCommercialTrafficUtils { /** * Creates and return the Index of the zone shape. * + * @param shapeFileZonePath Path to the shape file of the zones + * @param shapeCRS CRS of the shape file + * @param shapeFileZoneNameColumn Column name of the zone in the shape file * @return indexZones */ - static Index getIndexZones(Path shapeFileZonePath, String shapeCRS) { + static Index getIndexZones(Path shapeFileZonePath, String shapeCRS, String shapeFileZoneNameColumn) { ShpOptions shpZones = new ShpOptions(shapeFileZonePath, shapeCRS, StandardCharsets.UTF_8); - return shpZones.createIndex(shapeCRS, "areaID"); + return shpZones.createIndex(shapeCRS, shapeFileZoneNameColumn); } /** @@ -107,14 +110,28 @@ static Index getIndexBuildings(Path shapeFileBuildingsPath, String shapeCRS) { return shpLanduse.createIndex(shapeCRS, "type"); } + + /** + * Creates and return the Index of the regions shape. + * + * @param shapeFileRegionsPath Path to the shape file of the regions + * @param shapeCRS CRS of the shape file + * @param regionsShapeRegionColumn Column name of the region in the shape file + * @return indexRegions + */ + public static Index getIndexRegions(Path shapeFileRegionsPath, String shapeCRS, String regionsShapeRegionColumn) { + ShpOptions shpLanduse = new ShpOptions(shapeFileRegionsPath, shapeCRS, StandardCharsets.UTF_8); + return shpLanduse.createIndex(shapeCRS, regionsShapeRegionColumn); + } + /** * Writes a csv file with the result of the distribution per zone of the input data. */ static void writeResultOfDataDistribution(Map> resultingDataPerZone, - Path outputFileInOutputFolder, Map zoneIdNameConnection) + Path outputFileInOutputFolder, Map zoneIdRegionConnection) throws IOException { - writeCSVWithCategoryHeader(resultingDataPerZone, outputFileInOutputFolder, zoneIdNameConnection); + writeCSVWithCategoryHeader(resultingDataPerZone, outputFileInOutputFolder, zoneIdRegionConnection); log.info("The data distribution is finished and written to: " + outputFileInOutputFolder); } @@ -158,11 +175,11 @@ static Id findNearestPossibleLink(String zone, List noPossibleLink */ private static void writeCSVWithCategoryHeader(Map> resultingDataPerZone, Path outputFileInInputFolder, - Map zoneIdNameConnection) throws MalformedURLException { + Map zoneIdRegionConnection) throws MalformedURLException { BufferedWriter writer = IOUtils.getBufferedWriter(outputFileInInputFolder.toUri().toURL(), StandardCharsets.UTF_8, true); try { - String[] header = new String[]{"areaID", "areaName", "Inhabitants", "Employee", "Employee Primary Sector", + String[] header = new String[]{"zoneID", "region", "Inhabitants", "Employee", "Employee Primary Sector", "Employee Construction", "Employee Secondary Sector Rest", "Employee Retail", "Employee Traffic/Parcels", "Employee Tertiary Sector Rest"}; JOIN.appendTo(writer, header); @@ -170,9 +187,9 @@ private static void writeCSVWithCategoryHeader(Map row = new ArrayList<>(); row.add(zone); - row.add(zoneIdNameConnection.get(zone)); + row.add(zoneIdRegionConnection.get(zone)); for (String category : header) { - if (!category.equals("areaID") && !category.equals("areaName")) + if (!category.equals("zoneID") && !category.equals("region")) row.add(String.valueOf((int) Math.round(resultingDataPerZone.get(zone).getDouble(category)))); } JOIN.appendTo(writer, row); diff --git a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/TrafficVolumeGeneration.java b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/TrafficVolumeGeneration.java index 7e9e591eabc..3ae24470958 100644 --- a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/TrafficVolumeGeneration.java +++ b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/TrafficVolumeGeneration.java @@ -221,7 +221,7 @@ private static void writeCSVTrafficVolume(Map, Link>> regionLinksMap, double resistanceFactor) { + Map, Link>> regionLinksMap, double resistanceFactor, String shapeFileZoneNameColumn) { double volumeStart = trafficVolume_start.get(TrafficVolumeGeneration.makeTrafficVolumeKey(startZone, modeORvehType)).getDouble(purpose); double volumeStop = trafficVolume_stop.get(TrafficVolumeGeneration.makeTrafficVolumeKey(stopZone, modeORvehType)).getDouble(purpose); int roundedVolume; if (volumeStart != 0 && volumeStop != 0) { - double resistanceValue = getResistanceFunktionValue(startZone, stopZone, network, regionLinksMap, resistanceFactor); + double resistanceValue = getResistanceFunktionValue(startZone, stopZone, network, regionLinksMap, resistanceFactor, shapeFileZoneNameColumn); double gravityConstantA = getGravityConstant(stopZone, trafficVolume_start, modeORvehType, purpose, network, regionLinksMap, - resistanceFactor); + resistanceFactor, shapeFileZoneNameColumn); roundingError.computeIfAbsent(stopZone, (k) -> new Object2DoubleOpenHashMap<>()); //Bisher: Gravity model mit fixem Zielverkehr @@ -336,11 +337,13 @@ Integer getTripDistributionValue(String startZone, String stopZone, String modeO /** * Calculates the values of the resistance function between two zones. * - * @param startZone start zone - * @param stopZone stop zone - * @param regionLinksMap links for each zone + * @param startZone start zone + * @param stopZone stop zone + * @param regionLinksMap links for each zone + * @param shapeFileZoneNameColumn Name of the unique column of the name/Id of each zone in the zones shape file */ - private Double getResistanceFunktionValue(String startZone, String stopZone, Network network, Map, Link>> regionLinksMap, double resistanceFactor) { + private Double getResistanceFunktionValue(String startZone, String stopZone, Network network, Map, Link>> regionLinksMap, + double resistanceFactor, String shapeFileZoneNameColumn) { //if false the calculation is faster; e.g. for debugging boolean useNetworkRoutesForResistanceFunction = true; @@ -353,11 +356,11 @@ private Double getResistanceFunktionValue(String startZone, String stopZone, Net } if (!resistanceFunktionCache.containsKey(makeResistanceFunktionKey(startZone, stopZone))) for (SimpleFeature startZoneFeature : zonesFeatures) { - String zone1 = String.valueOf(startZoneFeature.getAttribute("areaID")); + String zone1 = String.valueOf(startZoneFeature.getAttribute(shapeFileZoneNameColumn)); if (!startZone.equals(zone1)) continue; for (SimpleFeature stopZoneFeature : zonesFeatures) { - String zone2 = String.valueOf(stopZoneFeature.getAttribute("areaID")); + String zone2 = String.valueOf(stopZoneFeature.getAttribute(shapeFileZoneNameColumn)); if (!stopZone.equals(zone2)) continue; double distance = Double.MAX_VALUE; @@ -443,16 +446,17 @@ private VehicleImpl getExampleVehicle(Location fromId) { /** * Calculates the gravity constant. * - * @param baseZone base zone - * @param trafficVolume volume of the traffic - * @param modeORvehType selected mode or vehicle type - * @param purpose selected purpose - * @param regionLinksMap links for each zone + * @param baseZone base zone + * @param trafficVolume volume of the traffic + * @param modeORvehType selected mode or vehicle type + * @param purpose selected purpose + * @param regionLinksMap links for each zone + * @param shapeFileZoneNameColumn Name of the unique column of the name/Id of each zone in the zones shape file * @return gravity constant */ private double getGravityConstant(String baseZone, Map> trafficVolume, String modeORvehType, - Integer purpose, Network network, Map, Link>> regionLinksMap, double resistanceFactor) { + Integer purpose, Network network, Map, Link>> regionLinksMap, double resistanceFactor, String shapeFileZoneNameColumn) { GravityConstantKey gravityKey = makeGravityKey(baseZone, modeORvehType, purpose); if (!gravityConstantACache.containsKey(gravityKey)) { @@ -464,7 +468,7 @@ private double getGravityConstant(String baseZone, continue; else { double resistanceValue = getResistanceFunktionValue(baseZone, trafficVolumeKey.getZone(), network, - regionLinksMap, resistanceFactor); + regionLinksMap, resistanceFactor, shapeFileZoneNameColumn); sum = sum + (volume * resistanceValue); } } diff --git a/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/LanduseBuildingAnalysisTest.java b/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/LanduseBuildingAnalysisTest.java index be97112e74c..7762b156cc5 100644 --- a/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/LanduseBuildingAnalysisTest.java +++ b/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/LanduseBuildingAnalysisTest.java @@ -51,18 +51,20 @@ void testReadOfDataDistributionPerZoneAndBuildingAnalysis() throws IOException { assert(new File(output.resolve("calculatedData").toString()).mkdir()); Path inputDataDirectory = Path.of(utils.getPackageInputDirectory()); String usedLanduseConfiguration = "useExistingDataDistribution"; + String shapeFileZoneNameColumn = "name"; // Test if the reading of the existing data distribution works correctly Map> resultingDataPerZone = LanduseBuildingAnalysis .createInputDataDistribution(output, landuseCategoriesAndDataConnection, inputDataDirectory, usedLanduseConfiguration, - SCTUtils.getIndexLanduse(inputDataDirectory), SCTUtils.getZoneIndex(inputDataDirectory), SCTUtils.getIndexBuildings(inputDataDirectory), buildingsPerZone); + SCTUtils.getIndexLanduse(inputDataDirectory), SCTUtils.getZoneIndex(inputDataDirectory), SCTUtils.getIndexBuildings(inputDataDirectory), + SCTUtils.getIndexRegions(inputDataDirectory), shapeFileZoneNameColumn, buildingsPerZone); Assertions.assertEquals(3, resultingDataPerZone.size(), MatsimTestUtils.EPSILON); - Assertions.assertTrue(resultingDataPerZone.containsKey("testArea1_area1")); - Assertions.assertTrue(resultingDataPerZone.containsKey("testArea1_area2")); - Assertions.assertTrue(resultingDataPerZone.containsKey("testArea2_area3")); + Assertions.assertTrue(resultingDataPerZone.containsKey("area1")); + Assertions.assertTrue(resultingDataPerZone.containsKey("area2")); + Assertions.assertTrue(resultingDataPerZone.containsKey("area3")); for (String zone : resultingDataPerZone.keySet()) { Object2DoubleMap categories = resultingDataPerZone.get(zone); @@ -86,60 +88,64 @@ void testReadOfDataDistributionPerZoneAndBuildingAnalysis() throws IOException { Assertions.assertEquals(categories.getDouble("Employee"), employeeSum, MatsimTestUtils.EPSILON); - if (zone.equals("testArea1_area1")) { - Assertions.assertEquals(4000, resultingDataPerZone.get(zone).getDouble("Inhabitants"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(3500, resultingDataPerZone.get(zone).getDouble("Employee"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(0, resultingDataPerZone.get(zone).getDouble("Employee Primary Sector"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(500, resultingDataPerZone.get(zone).getDouble("Employee Construction"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(500, resultingDataPerZone.get(zone).getDouble("Employee Secondary Sector Rest"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(1000, resultingDataPerZone.get(zone).getDouble("Employee Retail"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(500, resultingDataPerZone.get(zone).getDouble("Employee Traffic/Parcels"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(1000, resultingDataPerZone.get(zone).getDouble("Employee Tertiary Sector Rest"), - MatsimTestUtils.EPSILON); - } - if (zone.equals("testArea1_area2")) { - Assertions.assertEquals(4000, resultingDataPerZone.get(zone).getDouble("Inhabitants"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(6500, resultingDataPerZone.get(zone).getDouble("Employee"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(500, resultingDataPerZone.get(zone).getDouble("Employee Primary Sector"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(1500, resultingDataPerZone.get(zone).getDouble("Employee Construction"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(500, resultingDataPerZone.get(zone).getDouble("Employee Secondary Sector Rest"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(500, resultingDataPerZone.get(zone).getDouble("Employee Retail"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(1500, resultingDataPerZone.get(zone).getDouble("Employee Traffic/Parcels"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(2000, resultingDataPerZone.get(zone).getDouble("Employee Tertiary Sector Rest"), - MatsimTestUtils.EPSILON); - } - if (zone.equals("testArea2_area3")) { - Assertions.assertEquals(800, resultingDataPerZone.get(zone).getDouble("Inhabitants"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(1000, resultingDataPerZone.get(zone).getDouble("Employee"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(50, resultingDataPerZone.get(zone).getDouble("Employee Primary Sector"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(200, resultingDataPerZone.get(zone).getDouble("Employee Construction"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(100, resultingDataPerZone.get(zone).getDouble("Employee Secondary Sector Rest"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(150, resultingDataPerZone.get(zone).getDouble("Employee Retail"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(200, resultingDataPerZone.get(zone).getDouble("Employee Traffic/Parcels"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(300, resultingDataPerZone.get(zone).getDouble("Employee Tertiary Sector Rest"), - MatsimTestUtils.EPSILON); - } + switch (zone) { + case "area1" -> { + Assertions.assertEquals(4000, resultingDataPerZone.get(zone).getDouble("Inhabitants"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(3500, resultingDataPerZone.get(zone).getDouble("Employee"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(0, resultingDataPerZone.get(zone).getDouble("Employee Primary Sector"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(500, resultingDataPerZone.get(zone).getDouble("Employee Construction"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(500, resultingDataPerZone.get(zone).getDouble("Employee Secondary Sector Rest"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(1000, resultingDataPerZone.get(zone).getDouble("Employee Retail"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(500, resultingDataPerZone.get(zone).getDouble("Employee Traffic/Parcels"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(1000, resultingDataPerZone.get(zone).getDouble("Employee Tertiary Sector Rest"), + MatsimTestUtils.EPSILON); + } + case "area2" -> { + Assertions.assertEquals(4000, resultingDataPerZone.get(zone).getDouble("Inhabitants"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(6500, resultingDataPerZone.get(zone).getDouble("Employee"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(500, resultingDataPerZone.get(zone).getDouble("Employee Primary Sector"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(1500, resultingDataPerZone.get(zone).getDouble("Employee Construction"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(500, resultingDataPerZone.get(zone).getDouble("Employee Secondary Sector Rest"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(500, resultingDataPerZone.get(zone).getDouble("Employee Retail"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(1500, resultingDataPerZone.get(zone).getDouble("Employee Traffic/Parcels"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(2000, resultingDataPerZone.get(zone).getDouble("Employee Tertiary Sector Rest"), + MatsimTestUtils.EPSILON); + } + case "area3" -> { + Assertions.assertEquals(800, resultingDataPerZone.get(zone).getDouble("Inhabitants"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(1000, resultingDataPerZone.get(zone).getDouble("Employee"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(50, resultingDataPerZone.get(zone).getDouble("Employee Primary Sector"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(200, resultingDataPerZone.get(zone).getDouble("Employee Construction"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(100, resultingDataPerZone.get(zone).getDouble("Employee Secondary Sector Rest"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(150, resultingDataPerZone.get(zone).getDouble("Employee Retail"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(200, resultingDataPerZone.get(zone).getDouble("Employee Traffic/Parcels"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(300, resultingDataPerZone.get(zone).getDouble("Employee Tertiary Sector Rest"), + MatsimTestUtils.EPSILON); + } + default -> Assertions.fail("Zone not found"); + } + } // tests if the reading of the buildings works correctly @@ -149,12 +155,12 @@ void testReadOfDataDistributionPerZoneAndBuildingAnalysis() throws IOException { landuseCategoriesAndDataConnection, SCTUtils.getIndexLanduse(inputDataDirectory), SCTUtils.getZoneIndex(inputDataDirectory)); Assertions.assertEquals(3, buildingsPerZone.size(), MatsimTestUtils.EPSILON); - Assertions.assertTrue(buildingsPerZone.containsKey("testArea1_area1")); - Assertions.assertTrue(buildingsPerZone.containsKey("testArea1_area2")); - Assertions.assertTrue(buildingsPerZone.containsKey("testArea2_area3")); + Assertions.assertTrue(buildingsPerZone.containsKey("area1")); + Assertions.assertTrue(buildingsPerZone.containsKey("area2")); + Assertions.assertTrue(buildingsPerZone.containsKey("area3")); // test for area1 - Map> builingsPerArea1 = buildingsPerZone.get("testArea1_area1"); + Map> builingsPerArea1 = buildingsPerZone.get("area1"); Assertions.assertEquals(7, builingsPerArea1.size(), MatsimTestUtils.EPSILON); List inhabitantsBuildings = builingsPerArea1.get("Inhabitants"); Assertions.assertEquals(4, inhabitantsBuildings.size(), MatsimTestUtils.EPSILON); @@ -184,7 +190,7 @@ void testReadOfDataDistributionPerZoneAndBuildingAnalysis() throws IOException { Assertions.assertEquals(6, builingsPerArea1.get("Employee").size(), MatsimTestUtils.EPSILON); // test for area2 - Map> builingsPerArea2 = buildingsPerZone.get("testArea1_area2"); + Map> builingsPerArea2 = buildingsPerZone.get("area2"); Assertions.assertEquals(8, builingsPerArea2.size(), MatsimTestUtils.EPSILON); List employeeRetail = builingsPerArea2.get("Employee Retail"); Assertions.assertEquals(2, employeeRetail.size(), MatsimTestUtils.EPSILON); @@ -208,7 +214,7 @@ void testReadOfDataDistributionPerZoneAndBuildingAnalysis() throws IOException { Assertions.assertEquals(8, builingsPerArea2.get("Employee").size(), MatsimTestUtils.EPSILON); // test for area3 - Map> builingsPerArea3 = buildingsPerZone.get("testArea2_area3"); + Map> builingsPerArea3 = buildingsPerZone.get("area3"); Assertions.assertEquals(8, builingsPerArea3.size(), MatsimTestUtils.EPSILON); List tertiaryRetail = builingsPerArea3.get("Employee Tertiary Sector Rest"); Assertions.assertEquals(1, tertiaryRetail.size(), MatsimTestUtils.EPSILON); @@ -238,18 +244,20 @@ void testLanduseDistribution() throws IOException { assert(new File(output.resolve("calculatedData").toString()).mkdir()); Path inputDataDirectory = Path.of(utils.getPackageInputDirectory()); String usedLanduseConfiguration = "useOSMBuildingsAndLanduse"; + String shapeFileZoneNameColumn = "name"; // Analyze resultingData per zone Map> resultingDataPerZone = LanduseBuildingAnalysis .createInputDataDistribution(output, landuseCategoriesAndDataConnection, inputDataDirectory, usedLanduseConfiguration, - SCTUtils.getIndexLanduse(inputDataDirectory), SCTUtils.getZoneIndex(inputDataDirectory), SCTUtils.getIndexBuildings(inputDataDirectory), buildingsPerZone); + SCTUtils.getIndexLanduse(inputDataDirectory), SCTUtils.getZoneIndex(inputDataDirectory), SCTUtils.getIndexBuildings(inputDataDirectory), + SCTUtils.getIndexRegions(inputDataDirectory), shapeFileZoneNameColumn, buildingsPerZone); Assertions.assertEquals(3, resultingDataPerZone.size(), MatsimTestUtils.EPSILON); - Assertions.assertTrue(resultingDataPerZone.containsKey("testArea1_area1")); - Assertions.assertTrue(resultingDataPerZone.containsKey("testArea1_area2")); - Assertions.assertTrue(resultingDataPerZone.containsKey("testArea2_area3")); + Assertions.assertTrue(resultingDataPerZone.containsKey("area1")); + Assertions.assertTrue(resultingDataPerZone.containsKey("area2")); + Assertions.assertTrue(resultingDataPerZone.containsKey("area3")); for (String zone : resultingDataPerZone.keySet()) { Object2DoubleMap categories = resultingDataPerZone.get(zone); @@ -273,60 +281,63 @@ void testLanduseDistribution() throws IOException { Assertions.assertEquals(categories.getDouble("Employee"), employeeSum, MatsimTestUtils.EPSILON); - if (zone.equals("testArea1_area1")) { - Assertions.assertEquals(4000, resultingDataPerZone.get(zone).getDouble("Inhabitants"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(3500, resultingDataPerZone.get(zone).getDouble("Employee"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(0, resultingDataPerZone.get(zone).getDouble("Employee Primary Sector"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(500, resultingDataPerZone.get(zone).getDouble("Employee Construction"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(500, resultingDataPerZone.get(zone).getDouble("Employee Secondary Sector Rest"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(1000, resultingDataPerZone.get(zone).getDouble("Employee Retail"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(500, resultingDataPerZone.get(zone).getDouble("Employee Traffic/Parcels"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(1000, resultingDataPerZone.get(zone).getDouble("Employee Tertiary Sector Rest"), - MatsimTestUtils.EPSILON); - } - if (zone.equals("testArea1_area2")) { - Assertions.assertEquals(4000, resultingDataPerZone.get(zone).getDouble("Inhabitants"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(6500, resultingDataPerZone.get(zone).getDouble("Employee"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(500, resultingDataPerZone.get(zone).getDouble("Employee Primary Sector"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(1500, resultingDataPerZone.get(zone).getDouble("Employee Construction"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(500, resultingDataPerZone.get(zone).getDouble("Employee Secondary Sector Rest"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(500, resultingDataPerZone.get(zone).getDouble("Employee Retail"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(1500, resultingDataPerZone.get(zone).getDouble("Employee Traffic/Parcels"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(2000, resultingDataPerZone.get(zone).getDouble("Employee Tertiary Sector Rest"), - MatsimTestUtils.EPSILON); - } - if (zone.equals("testArea2_area3")) { - Assertions.assertEquals(800, resultingDataPerZone.get(zone).getDouble("Inhabitants"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(1000, resultingDataPerZone.get(zone).getDouble("Employee"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(50, resultingDataPerZone.get(zone).getDouble("Employee Primary Sector"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(200, resultingDataPerZone.get(zone).getDouble("Employee Construction"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(100, resultingDataPerZone.get(zone).getDouble("Employee Secondary Sector Rest"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(150, resultingDataPerZone.get(zone).getDouble("Employee Retail"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(200, resultingDataPerZone.get(zone).getDouble("Employee Traffic/Parcels"), - MatsimTestUtils.EPSILON); - Assertions.assertEquals(300, resultingDataPerZone.get(zone).getDouble("Employee Tertiary Sector Rest"), - MatsimTestUtils.EPSILON); - } + switch (zone) { + case "area1" -> { + Assertions.assertEquals(4000, resultingDataPerZone.get(zone).getDouble("Inhabitants"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(3500, resultingDataPerZone.get(zone).getDouble("Employee"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(0, resultingDataPerZone.get(zone).getDouble("Employee Primary Sector"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(500, resultingDataPerZone.get(zone).getDouble("Employee Construction"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(500, resultingDataPerZone.get(zone).getDouble("Employee Secondary Sector Rest"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(1000, resultingDataPerZone.get(zone).getDouble("Employee Retail"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(500, resultingDataPerZone.get(zone).getDouble("Employee Traffic/Parcels"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(1000, resultingDataPerZone.get(zone).getDouble("Employee Tertiary Sector Rest"), + MatsimTestUtils.EPSILON); + } + case "area2" -> { + Assertions.assertEquals(4000, resultingDataPerZone.get(zone).getDouble("Inhabitants"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(6500, resultingDataPerZone.get(zone).getDouble("Employee"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(500, resultingDataPerZone.get(zone).getDouble("Employee Primary Sector"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(1500, resultingDataPerZone.get(zone).getDouble("Employee Construction"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(500, resultingDataPerZone.get(zone).getDouble("Employee Secondary Sector Rest"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(500, resultingDataPerZone.get(zone).getDouble("Employee Retail"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(1500, resultingDataPerZone.get(zone).getDouble("Employee Traffic/Parcels"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(2000, resultingDataPerZone.get(zone).getDouble("Employee Tertiary Sector Rest"), + MatsimTestUtils.EPSILON); + } + case "area3" -> { + Assertions.assertEquals(800, resultingDataPerZone.get(zone).getDouble("Inhabitants"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(1000, resultingDataPerZone.get(zone).getDouble("Employee"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(50, resultingDataPerZone.get(zone).getDouble("Employee Primary Sector"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(200, resultingDataPerZone.get(zone).getDouble("Employee Construction"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(100, resultingDataPerZone.get(zone).getDouble("Employee Secondary Sector Rest"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(150, resultingDataPerZone.get(zone).getDouble("Employee Retail"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(200, resultingDataPerZone.get(zone).getDouble("Employee Traffic/Parcels"), + MatsimTestUtils.EPSILON); + Assertions.assertEquals(300, resultingDataPerZone.get(zone).getDouble("Employee Tertiary Sector Rest"), + MatsimTestUtils.EPSILON); + } + default -> Assertions.fail("Zone not found"); + } } } } diff --git a/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/RunGenerateSmallScaleCommercialTrafficTest.java b/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/RunGenerateSmallScaleCommercialTrafficTest.java index 62127e7e2f5..75665b3a809 100644 --- a/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/RunGenerateSmallScaleCommercialTrafficTest.java +++ b/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/RunGenerateSmallScaleCommercialTrafficTest.java @@ -55,7 +55,10 @@ void testMainRunAndResults() { String creationOption = "createNewCarrierFile"; String landuseConfiguration = "useExistingDataDistribution"; String smallScaleCommercialTrafficType = "commercialPersonTraffic"; + String regionsShapeFileName = utils.getPackageInputDirectory() + "/shp/testRegions.shp"; + String regionsShapeRegionColumn = "region"; String zoneShapeFileName = utils.getPackageInputDirectory() + "/shp/testZones.shp"; + String zoneShapeFileNameColumn = "name"; String buildingsShapeFileName = utils.getPackageInputDirectory() + "/shp/testBuildings.shp"; String landuseShapeFileName = utils.getPackageInputDirectory() + "/shp/testLanduse.shp"; String shapeCRS = "EPSG:4326"; @@ -68,7 +71,10 @@ void testMainRunAndResults() { "--landuseConfiguration", landuseConfiguration, "--smallScaleCommercialTrafficType", smallScaleCommercialTrafficType, "--includeExistingModels", + "--regionsShapeFileName", regionsShapeFileName, + "--regionsShapeRegionColumn", regionsShapeRegionColumn, "--zoneShapeFileName", zoneShapeFileName, + "--zoneShapeFileNameColumn", zoneShapeFileNameColumn, "--buildingsShapeFileName", buildingsShapeFileName, "--landuseShapeFileName", landuseShapeFileName, "--shapeCRS", shapeCRS); diff --git a/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/SCTUtils.java b/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/SCTUtils.java index 7b16b902d08..843a690196d 100644 --- a/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/SCTUtils.java +++ b/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/SCTUtils.java @@ -11,7 +11,7 @@ public class SCTUtils { static ShpOptions.Index getZoneIndex(Path inputDataDirectory) { Path shapeFileZonePath = inputDataDirectory.resolve("shp/testZones.shp"); - return new ShpOptions(shapeFileZonePath, null, null).createIndex("areaID"); + return new ShpOptions(shapeFileZonePath, null, null).createIndex("name"); } static ShpOptions.Index getIndexLanduse(Path inputDataDirectory) { @@ -24,4 +24,9 @@ static ShpOptions.Index getIndexBuildings(Path inputDataDirectory) { return new ShpOptions(shapeFileBuildingsPath, null, null).createIndex("type"); } + static ShpOptions.Index getIndexRegions(Path inputDataDirectory) { + Path shapeFileRegionsPath = inputDataDirectory.resolve("shp/testRegions.shp"); + return new ShpOptions(shapeFileRegionsPath, null, null).createIndex("region"); + } + } diff --git a/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/SmallScaleCommercialTrafficUtilsTest.java b/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/SmallScaleCommercialTrafficUtilsTest.java index 61d3f759aac..5aa06d111fc 100644 --- a/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/SmallScaleCommercialTrafficUtilsTest.java +++ b/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/SmallScaleCommercialTrafficUtilsTest.java @@ -59,19 +59,21 @@ void findZoneOfLinksTest() throws IOException, URISyntaxException { config.network().setInputCRS("EPSG:4326"); Scenario scenario = ScenarioUtils.loadScenario(config); Map>> buildingsPerZone = new HashMap<>(); + String shapeFileZoneNameColumn = "name"; Map, Link>> regionLinksMap = GenerateSmallScaleCommercialTrafficDemand - .filterLinksForZones(scenario, SmallScaleCommercialTrafficUtils.getIndexZones(shapeFileZonePath, config.global().getCoordinateSystem()), + .filterLinksForZones(scenario, SmallScaleCommercialTrafficUtils.getIndexZones(shapeFileZonePath, config.global().getCoordinateSystem(), + shapeFileZoneNameColumn), buildingsPerZone); Assertions.assertEquals(3, regionLinksMap.size(), MatsimTestUtils.EPSILON); - Assertions.assertEquals(60, regionLinksMap.get("testArea1_area1").size(), MatsimTestUtils.EPSILON); - Assertions.assertEquals(41, regionLinksMap.get("testArea1_area2").size(), MatsimTestUtils.EPSILON); - Assertions.assertEquals(28, regionLinksMap.get("testArea2_area3").size(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(60, regionLinksMap.get("area1").size(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(41, regionLinksMap.get("area2").size(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(28, regionLinksMap.get("area3").size(), MatsimTestUtils.EPSILON); Assertions.assertNull(SmallScaleCommercialTrafficUtils.findZoneOfLink(Id.createLinkId("j(5,4)"), regionLinksMap)); - Assertions.assertEquals("testArea1_area1", SmallScaleCommercialTrafficUtils.findZoneOfLink(Id.createLinkId("j(6,5)R"), regionLinksMap)); - Assertions.assertEquals("testArea1_area2", SmallScaleCommercialTrafficUtils.findZoneOfLink(Id.createLinkId("j(2,7)R"), regionLinksMap)); - Assertions.assertEquals("testArea2_area3", SmallScaleCommercialTrafficUtils.findZoneOfLink(Id.createLinkId("j(2,2)R"), regionLinksMap)); + Assertions.assertEquals("area1", SmallScaleCommercialTrafficUtils.findZoneOfLink(Id.createLinkId("j(6,5)R"), regionLinksMap)); + Assertions.assertEquals("area2", SmallScaleCommercialTrafficUtils.findZoneOfLink(Id.createLinkId("j(2,7)R"), regionLinksMap)); + Assertions.assertEquals("area3", SmallScaleCommercialTrafficUtils.findZoneOfLink(Id.createLinkId("j(2,2)R"), regionLinksMap)); } } diff --git a/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/TrafficVolumeGenerationTest.java b/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/TrafficVolumeGenerationTest.java index b1646548777..cfac585157a 100644 --- a/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/TrafficVolumeGenerationTest.java +++ b/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/TrafficVolumeGenerationTest.java @@ -60,11 +60,13 @@ void testTrafficVolumeGenerationCommercialPersonTraffic() throws IOException { assert(new File(output.resolve("calculatedData").toString()).mkdir()); Path inputDataDirectory = Path.of(utils.getPackageInputDirectory()); String usedLanduseConfiguration = "useExistingDataDistribution"; + String shapeFileZoneNameColumn = "name"; Map> resultingDataPerZone = LanduseBuildingAnalysis .createInputDataDistribution(output, landuseCategoriesAndDataConnection, inputDataDirectory, usedLanduseConfiguration, - SCTUtils.getIndexLanduse(inputDataDirectory), SCTUtils.getZoneIndex(inputDataDirectory), SCTUtils.getIndexBuildings(inputDataDirectory), buildingsPerZone); + SCTUtils.getIndexLanduse(inputDataDirectory), SCTUtils.getZoneIndex(inputDataDirectory), SCTUtils.getIndexBuildings(inputDataDirectory), + SCTUtils.getIndexRegions(inputDataDirectory), shapeFileZoneNameColumn, buildingsPerZone); String usedTrafficType = "commercialPersonTraffic"; @@ -86,7 +88,7 @@ void testTrafficVolumeGenerationCommercialPersonTraffic() throws IOException { Assertions.assertTrue(trafficVolumePerTypeAndZone_start.containsKey(trafficVolumeKey)); Assertions.assertTrue(trafficVolumePerTypeAndZone_stop.containsKey(trafficVolumeKey)); } - TrafficVolumeKey trafficVolumeKey = TrafficVolumeGeneration.makeTrafficVolumeKey("testArea1_area1", modesORvehTypes.get(0)); + TrafficVolumeKey trafficVolumeKey = TrafficVolumeGeneration.makeTrafficVolumeKey("area1", modesORvehTypes.get(0)); Assertions.assertEquals(30, trafficVolumePerTypeAndZone_start.get(trafficVolumeKey).getDouble(1), MatsimTestUtils.EPSILON); Assertions.assertEquals(124, trafficVolumePerTypeAndZone_start.get(trafficVolumeKey).getDouble(2), MatsimTestUtils.EPSILON); Assertions.assertEquals(277, trafficVolumePerTypeAndZone_start.get(trafficVolumeKey).getDouble(3), MatsimTestUtils.EPSILON); @@ -99,7 +101,7 @@ void testTrafficVolumeGenerationCommercialPersonTraffic() throws IOException { Assertions.assertEquals(121, trafficVolumePerTypeAndZone_stop.get(trafficVolumeKey).getDouble(4), MatsimTestUtils.EPSILON); Assertions.assertEquals(65, trafficVolumePerTypeAndZone_stop.get(trafficVolumeKey).getDouble(5), MatsimTestUtils.EPSILON); - trafficVolumeKey = TrafficVolumeGeneration.makeTrafficVolumeKey("testArea1_area2", modesORvehTypes.get(0)); + trafficVolumeKey = TrafficVolumeGeneration.makeTrafficVolumeKey("area2", modesORvehTypes.get(0)); Assertions.assertEquals(30, trafficVolumePerTypeAndZone_start.get(trafficVolumeKey).getDouble(1), MatsimTestUtils.EPSILON); Assertions.assertEquals(211, trafficVolumePerTypeAndZone_start.get(trafficVolumeKey).getDouble(2), MatsimTestUtils.EPSILON); Assertions.assertEquals(514, trafficVolumePerTypeAndZone_start.get(trafficVolumeKey).getDouble(3), MatsimTestUtils.EPSILON); @@ -112,7 +114,7 @@ void testTrafficVolumeGenerationCommercialPersonTraffic() throws IOException { Assertions.assertEquals(246, trafficVolumePerTypeAndZone_stop.get(trafficVolumeKey).getDouble(4), MatsimTestUtils.EPSILON); Assertions.assertEquals(102, trafficVolumePerTypeAndZone_stop.get(trafficVolumeKey).getDouble(5), MatsimTestUtils.EPSILON); - trafficVolumeKey = TrafficVolumeGeneration.makeTrafficVolumeKey("testArea2_area3", modesORvehTypes.get(0)); + trafficVolumeKey = TrafficVolumeGeneration.makeTrafficVolumeKey("area3", modesORvehTypes.get(0)); Assertions.assertEquals(6, trafficVolumePerTypeAndZone_start.get(trafficVolumeKey).getDouble(1), MatsimTestUtils.EPSILON); Assertions.assertEquals(34, trafficVolumePerTypeAndZone_start.get(trafficVolumeKey).getDouble(2), MatsimTestUtils.EPSILON); Assertions.assertEquals(79, trafficVolumePerTypeAndZone_start.get(trafficVolumeKey).getDouble(3), MatsimTestUtils.EPSILON); @@ -136,7 +138,7 @@ void testTrafficVolumeGenerationCommercialPersonTraffic() throws IOException { Assertions.assertEquals(3, trafficVolumePerTypeAndZone_start.size()); Assertions.assertEquals(3, trafficVolumePerTypeAndZone_stop.size()); - trafficVolumeKey = TrafficVolumeGeneration.makeTrafficVolumeKey("testArea1_area1", modesORvehTypes.get(0)); + trafficVolumeKey = TrafficVolumeGeneration.makeTrafficVolumeKey("area1", modesORvehTypes.get(0)); Assertions.assertEquals(7, trafficVolumePerTypeAndZone_start.get(trafficVolumeKey).getDouble(1), MatsimTestUtils.EPSILON); Assertions.assertEquals(31, trafficVolumePerTypeAndZone_start.get(trafficVolumeKey).getDouble(2), MatsimTestUtils.EPSILON); Assertions.assertEquals(69, trafficVolumePerTypeAndZone_start.get(trafficVolumeKey).getDouble(3), MatsimTestUtils.EPSILON); @@ -149,7 +151,7 @@ void testTrafficVolumeGenerationCommercialPersonTraffic() throws IOException { Assertions.assertEquals(30, trafficVolumePerTypeAndZone_stop.get(trafficVolumeKey).getDouble(4), MatsimTestUtils.EPSILON); Assertions.assertEquals(16, trafficVolumePerTypeAndZone_stop.get(trafficVolumeKey).getDouble(5), MatsimTestUtils.EPSILON); - trafficVolumeKey = TrafficVolumeGeneration.makeTrafficVolumeKey("testArea1_area2", modesORvehTypes.get(0)); + trafficVolumeKey = TrafficVolumeGeneration.makeTrafficVolumeKey("area2", modesORvehTypes.get(0)); Assertions.assertEquals(7, trafficVolumePerTypeAndZone_start.get(trafficVolumeKey).getDouble(1), MatsimTestUtils.EPSILON); Assertions.assertEquals(53, trafficVolumePerTypeAndZone_start.get(trafficVolumeKey).getDouble(2), MatsimTestUtils.EPSILON); Assertions.assertEquals(129, trafficVolumePerTypeAndZone_start.get(trafficVolumeKey).getDouble(3), MatsimTestUtils.EPSILON); @@ -162,7 +164,7 @@ void testTrafficVolumeGenerationCommercialPersonTraffic() throws IOException { Assertions.assertEquals(61, trafficVolumePerTypeAndZone_stop.get(trafficVolumeKey).getDouble(4), MatsimTestUtils.EPSILON); Assertions.assertEquals(25, trafficVolumePerTypeAndZone_stop.get(trafficVolumeKey).getDouble(5), MatsimTestUtils.EPSILON); - trafficVolumeKey = TrafficVolumeGeneration.makeTrafficVolumeKey("testArea2_area3", modesORvehTypes.get(0)); + trafficVolumeKey = TrafficVolumeGeneration.makeTrafficVolumeKey("area3", modesORvehTypes.get(0)); Assertions.assertEquals(1, trafficVolumePerTypeAndZone_start.get(trafficVolumeKey).getDouble(1), MatsimTestUtils.EPSILON); Assertions.assertEquals(8, trafficVolumePerTypeAndZone_start.get(trafficVolumeKey).getDouble(2), MatsimTestUtils.EPSILON); Assertions.assertEquals(20, trafficVolumePerTypeAndZone_start.get(trafficVolumeKey).getDouble(3), MatsimTestUtils.EPSILON); @@ -186,11 +188,13 @@ void testTrafficVolumeGenerationGoodsTraffic() throws IOException { assert(new File(output.resolve("calculatedData").toString()).mkdir()); Path inputDataDirectory = Path.of(utils.getPackageInputDirectory()); String usedLanduseConfiguration = "useExistingDataDistribution"; + String shapeFileZoneNameColumn = "name"; Map> resultingDataPerZone = LanduseBuildingAnalysis .createInputDataDistribution(output, landuseCategoriesAndDataConnection, inputDataDirectory, usedLanduseConfiguration, - SCTUtils.getIndexLanduse(inputDataDirectory), SCTUtils.getZoneIndex(inputDataDirectory), SCTUtils.getIndexBuildings(inputDataDirectory), buildingsPerZone); + SCTUtils.getIndexLanduse(inputDataDirectory), SCTUtils.getZoneIndex(inputDataDirectory), SCTUtils.getIndexBuildings(inputDataDirectory), + SCTUtils.getIndexRegions(inputDataDirectory), shapeFileZoneNameColumn, buildingsPerZone); String usedTrafficType = "goodsTraffic"; double sample = 1.; @@ -214,7 +218,7 @@ void testTrafficVolumeGenerationGoodsTraffic() throws IOException { } } - // test for "testArea1_area1" + // test for "area1" HashMap estimatesStart = new HashMap<>(); estimatesStart.put(1, 12.); estimatesStart.put(2, 30.); @@ -234,7 +238,7 @@ void testTrafficVolumeGenerationGoodsTraffic() throws IOException { double sumStart = 0; double sumStop = 0; for (String modeORvehType : modesORvehTypes) { - TrafficVolumeKey trafficVolumeKey = TrafficVolumeGeneration.makeTrafficVolumeKey("testArea1_area1", modeORvehType); + TrafficVolumeKey trafficVolumeKey = TrafficVolumeGeneration.makeTrafficVolumeKey("area1", modeORvehType); sumStart += trafficVolumePerTypeAndZone_start.get(trafficVolumeKey).getDouble(i); sumStop += trafficVolumePerTypeAndZone_stop.get(trafficVolumeKey).getDouble(i); if (modeORvehType.equals("vehTyp1")) { @@ -317,7 +321,7 @@ void testTrafficVolumeGenerationGoodsTraffic() throws IOException { Assertions.assertEquals(estimatesStop.get(i), sumStop, MatsimTestUtils.EPSILON); } - // test for "testArea1_area2" + // test for "area2" estimatesStart = new HashMap<>(); estimatesStart.put(1, 12.); estimatesStart.put(2, 37.); @@ -337,7 +341,7 @@ void testTrafficVolumeGenerationGoodsTraffic() throws IOException { double sumStart = 0; double sumStop = 0; for (String modeORvehType : modesORvehTypes) { - TrafficVolumeKey trafficVolumeKey = TrafficVolumeGeneration.makeTrafficVolumeKey("testArea1_area2", modeORvehType); + TrafficVolumeKey trafficVolumeKey = TrafficVolumeGeneration.makeTrafficVolumeKey("area2", modeORvehType); sumStart += trafficVolumePerTypeAndZone_start.get(trafficVolumeKey).getDouble(i); sumStop += trafficVolumePerTypeAndZone_stop.get(trafficVolumeKey).getDouble(i); } @@ -345,7 +349,7 @@ void testTrafficVolumeGenerationGoodsTraffic() throws IOException { Assertions.assertEquals(estimatesStop.get(i), sumStop, MatsimTestUtils.EPSILON); } - // test for "testArea2_area3" + // test for "area3" estimatesStart = new HashMap<>(); estimatesStart.put(1, 2.); estimatesStart.put(2, 7.); @@ -365,7 +369,7 @@ void testTrafficVolumeGenerationGoodsTraffic() throws IOException { double sumStart = 0; double sumStop = 0; for (String modeORvehType : modesORvehTypes) { - TrafficVolumeKey trafficVolumeKey = TrafficVolumeGeneration.makeTrafficVolumeKey("testArea2_area3", modeORvehType); + TrafficVolumeKey trafficVolumeKey = TrafficVolumeGeneration.makeTrafficVolumeKey("area3", modeORvehType); sumStart += trafficVolumePerTypeAndZone_start.get(trafficVolumeKey).getDouble(i); sumStop += trafficVolumePerTypeAndZone_stop.get(trafficVolumeKey).getDouble(i); } @@ -388,9 +392,11 @@ void testAddingExistingScenarios() throws Exception { config.setContext(inputDataDirectory.resolve("config.xml").toUri().toURL()); Scenario scenario = ScenarioUtils.loadScenario(config); Map>> buildingsPerZone = new HashMap<>(); + String shapeFileZoneNameColumn = "name"; Map, Link>> regionLinksMap = GenerateSmallScaleCommercialTrafficDemand - .filterLinksForZones(scenario, SmallScaleCommercialTrafficUtils.getIndexZones(shapeFileZonePath, config.global().getCoordinateSystem()), + .filterLinksForZones(scenario, SmallScaleCommercialTrafficUtils.getIndexZones(shapeFileZonePath, config.global().getCoordinateSystem(), + shapeFileZoneNameColumn), buildingsPerZone); SmallScaleCommercialTrafficUtils.readExistingModels(scenario, sample, regionLinksMap); @@ -414,7 +420,7 @@ void testAddingExistingScenarios() throws Exception { Assertions.assertEquals("exampleServiceCarrier", addedCarrier1.getAttributes().getAttribute("existingModel")); Assertions.assertEquals("car", addedCarrier1.getAttributes().getAttribute("networkMode")); Assertions.assertNull(addedCarrier1.getAttributes().getAttribute("vehicleType")); - Assertions.assertEquals("testArea2_area3", addedCarrier1.getAttributes().getAttribute("tourStartArea")); + Assertions.assertEquals("area3", addedCarrier1.getAttributes().getAttribute("tourStartArea")); Carrier addedCarrier2 = CarriersUtils.getCarriers(scenario).getCarriers().get(Id.create("exampleServiceCarrier_carrier2", Carrier.class)); Assertions.assertNotNull(addedCarrier2.getSelectedPlan()); @@ -428,7 +434,7 @@ void testAddingExistingScenarios() throws Exception { Assertions.assertEquals("exampleServiceCarrier", addedCarrier2.getAttributes().getAttribute("existingModel")); Assertions.assertEquals("car", addedCarrier2.getAttributes().getAttribute("networkMode")); Assertions.assertNull(addedCarrier2.getAttributes().getAttribute("vehicleType")); - Assertions.assertEquals("testArea2_area3", addedCarrier2.getAttributes().getAttribute("tourStartArea")); + Assertions.assertEquals("area3", addedCarrier2.getAttributes().getAttribute("tourStartArea")); Carrier addedCarrier3 = CarriersUtils.getCarriers(scenario).getCarriers().get(Id.create("exampleShipmentCarrier_carrier1", Carrier.class)); Assertions.assertNull(addedCarrier3.getSelectedPlan()); @@ -447,6 +453,8 @@ void testAddingExistingScenariosWithSample() throws Exception { Path shapeFileZonePath = inputDataDirectory.resolve("shp/testZones.shp"); String networkPath = "https://raw.githubusercontent.com/matsim-org/matsim-libs/master/examples/scenarios/freight-chessboard-9x9/grid9x9.xml"; double sample = 0.2; + String shapeFileZoneNameColumn = "name"; + Config config = ConfigUtils.createConfig(); config.global().setCoordinateSystem("EPSG:4326"); config.network().setInputFile(networkPath); @@ -455,7 +463,8 @@ void testAddingExistingScenariosWithSample() throws Exception { Scenario scenario = ScenarioUtils.loadScenario(config); Map>> buildingsPerZone = new HashMap<>(); Map, Link>> regionLinksMap = GenerateSmallScaleCommercialTrafficDemand - .filterLinksForZones(scenario, SmallScaleCommercialTrafficUtils.getIndexZones(shapeFileZonePath, config.global().getCoordinateSystem()), + .filterLinksForZones(scenario, SmallScaleCommercialTrafficUtils.getIndexZones(shapeFileZonePath, config.global().getCoordinateSystem(), + shapeFileZoneNameColumn), buildingsPerZone); SmallScaleCommercialTrafficUtils.readExistingModels(scenario, sample, regionLinksMap); @@ -478,7 +487,7 @@ void testAddingExistingScenariosWithSample() throws Exception { Assertions.assertEquals("exampleServiceCarrier", addedCarrier1.getAttributes().getAttribute("existingModel")); Assertions.assertEquals("car", addedCarrier1.getAttributes().getAttribute("networkMode")); Assertions.assertNull(addedCarrier1.getAttributes().getAttribute("vehicleType")); - Assertions.assertEquals("testArea2_area3", addedCarrier1.getAttributes().getAttribute("tourStartArea")); + Assertions.assertEquals("area3", addedCarrier1.getAttributes().getAttribute("tourStartArea")); Carrier addedCarrier3 = CarriersUtils.getCarriers(scenario).getCarriers().get(Id.create("exampleShipmentCarrier_carrier1", Carrier.class)); Assertions.assertNull(addedCarrier3.getSelectedPlan()); @@ -502,6 +511,8 @@ void testReducingDemandAfterAddingExistingScenarios_goods() throws Exception { String networkPath = "https://raw.githubusercontent.com/matsim-org/matsim-libs/master/examples/scenarios/freight-chessboard-9x9/grid9x9.xml"; String usedTrafficType = "goodsTraffic"; double sample = 1.; + String shapeFileZoneNameColumn = "name"; + ArrayList modesORvehTypes = new ArrayList<>( Arrays.asList("vehTyp1", "vehTyp2", "vehTyp3", "vehTyp4", "vehTyp5")); Config config = ConfigUtils.createConfig(); @@ -515,7 +526,8 @@ void testReducingDemandAfterAddingExistingScenarios_goods() throws Exception { Map> resultingDataPerZone = LanduseBuildingAnalysis .createInputDataDistribution(output, landuseCategoriesAndDataConnection, inputDataDirectory, usedLanduseConfiguration, - SCTUtils.getIndexLanduse(inputDataDirectory), SCTUtils.getZoneIndex(inputDataDirectory), SCTUtils.getIndexBuildings(inputDataDirectory), buildingsPerZone); + SCTUtils.getIndexLanduse(inputDataDirectory), SCTUtils.getZoneIndex(inputDataDirectory), SCTUtils.getIndexBuildings(inputDataDirectory), + SCTUtils.getIndexRegions(inputDataDirectory), shapeFileZoneNameColumn, buildingsPerZone); Map> trafficVolumePerTypeAndZone_start = TrafficVolumeGeneration .createTrafficVolume_start(resultingDataPerZone, output, sample, modesORvehTypes, usedTrafficType); @@ -530,7 +542,7 @@ void testReducingDemandAfterAddingExistingScenarios_goods() throws Exception { TrafficVolumeGeneration.reduceDemandBasedOnExistingCarriers(scenario, regionLinksMap, usedTrafficType, trafficVolumePerTypeAndZone_start, trafficVolumePerTypeAndZone_stop); - // test for "testArea1_area1" + // test for "area1" HashMap estimatesStart = new HashMap<>(); estimatesStart.put(1, 12.); estimatesStart.put(2, 30.); @@ -550,7 +562,7 @@ void testReducingDemandAfterAddingExistingScenarios_goods() throws Exception { double sumStart = 0; double sumStop = 0; for (String modeORvehType : modesORvehTypes) { - TrafficVolumeKey trafficVolumeKey = TrafficVolumeGeneration.makeTrafficVolumeKey("testArea1_area1", modeORvehType); + TrafficVolumeKey trafficVolumeKey = TrafficVolumeGeneration.makeTrafficVolumeKey("area1", modeORvehType); sumStart += trafficVolumePerTypeAndZone_start.get(trafficVolumeKey).getDouble(i); sumStop += trafficVolumePerTypeAndZone_stop.get(trafficVolumeKey).getDouble(i); if (modeORvehType.equals("vehTyp3")) { @@ -573,7 +585,7 @@ void testReducingDemandAfterAddingExistingScenarios_goods() throws Exception { Assertions.assertEquals(estimatesStop.get(i), sumStop, MatsimTestUtils.EPSILON); } - // test for "testArea1_area2" + // test for "area2" estimatesStart = new HashMap<>(); estimatesStart.put(1, 12.); estimatesStart.put(2, 37.); @@ -593,7 +605,7 @@ void testReducingDemandAfterAddingExistingScenarios_goods() throws Exception { double sumStart = 0; double sumStop = 0; for (String modeORvehType : modesORvehTypes) { - TrafficVolumeKey trafficVolumeKey = TrafficVolumeGeneration.makeTrafficVolumeKey("testArea1_area2", modeORvehType); + TrafficVolumeKey trafficVolumeKey = TrafficVolumeGeneration.makeTrafficVolumeKey("area2", modeORvehType); sumStart += trafficVolumePerTypeAndZone_start.get(trafficVolumeKey).getDouble(i); sumStop += trafficVolumePerTypeAndZone_stop.get(trafficVolumeKey).getDouble(i); } @@ -601,7 +613,7 @@ void testReducingDemandAfterAddingExistingScenarios_goods() throws Exception { Assertions.assertEquals(estimatesStop.get(i), sumStop, MatsimTestUtils.EPSILON); } - // test for "testArea2_area3" + // test for "area3" estimatesStart = new HashMap<>(); estimatesStart.put(1, 2.); estimatesStart.put(2, 7.); @@ -621,7 +633,7 @@ void testReducingDemandAfterAddingExistingScenarios_goods() throws Exception { double sumStart = 0; double sumStop = 0; for (String modeORvehType : modesORvehTypes) { - TrafficVolumeKey trafficVolumeKey = TrafficVolumeGeneration.makeTrafficVolumeKey("testArea2_area3", modeORvehType); + TrafficVolumeKey trafficVolumeKey = TrafficVolumeGeneration.makeTrafficVolumeKey("area3", modeORvehType); sumStart += trafficVolumePerTypeAndZone_start.get(trafficVolumeKey).getDouble(i); sumStop += trafficVolumePerTypeAndZone_stop.get(trafficVolumeKey).getDouble(i); if (modeORvehType.equals("vehTyp3")) { @@ -657,6 +669,8 @@ void testReducingDemandAfterAddingExistingScenarios_commercialPersonTraffic() th String networkPath = "https://raw.githubusercontent.com/matsim-org/matsim-libs/master/examples/scenarios/freight-chessboard-9x9/grid9x9.xml"; String usedTrafficType = "commercialPersonTraffic"; double sample = 1.; + String shapeFileZoneNameColumn = "name"; + ArrayList modesORvehTypes = new ArrayList<>( List.of("total")); Config config = ConfigUtils.createConfig(); @@ -670,7 +684,8 @@ void testReducingDemandAfterAddingExistingScenarios_commercialPersonTraffic() th Map> resultingDataPerZone = LanduseBuildingAnalysis .createInputDataDistribution(output, landuseCategoriesAndDataConnection, inputDataDirectory, usedLanduseConfiguration, - SCTUtils.getIndexLanduse(inputDataDirectory), SCTUtils.getZoneIndex(inputDataDirectory), SCTUtils.getIndexBuildings(inputDataDirectory), buildingsPerZone); + SCTUtils.getIndexLanduse(inputDataDirectory), SCTUtils.getZoneIndex(inputDataDirectory), SCTUtils.getIndexBuildings(inputDataDirectory), + SCTUtils.getIndexRegions(inputDataDirectory), shapeFileZoneNameColumn, buildingsPerZone); Map> trafficVolumePerTypeAndZone_start = TrafficVolumeGeneration .createTrafficVolume_start(resultingDataPerZone, output, sample, modesORvehTypes, usedTrafficType); @@ -688,7 +703,7 @@ void testReducingDemandAfterAddingExistingScenarios_commercialPersonTraffic() th //because the reduction of the start volume in zone3 (purpose 2) is higher than the value, a start reduction will be distributed over other zones double sumOfStartOtherAreas = 0; - TrafficVolumeKey trafficVolumeKey = TrafficVolumeGeneration.makeTrafficVolumeKey("testArea1_area1", modesORvehTypes.get(0)); + TrafficVolumeKey trafficVolumeKey = TrafficVolumeGeneration.makeTrafficVolumeKey("area1", modesORvehTypes.get(0)); Assertions.assertEquals(30, trafficVolumePerTypeAndZone_start.get(trafficVolumeKey).getDouble(1), MatsimTestUtils.EPSILON); sumOfStartOtherAreas += trafficVolumePerTypeAndZone_start.get(trafficVolumeKey).getDouble(2); Assertions.assertEquals(277, trafficVolumePerTypeAndZone_start.get(trafficVolumeKey).getDouble(3), MatsimTestUtils.EPSILON); @@ -701,7 +716,7 @@ void testReducingDemandAfterAddingExistingScenarios_commercialPersonTraffic() th Assertions.assertEquals(121, trafficVolumePerTypeAndZone_stop.get(trafficVolumeKey).getDouble(4), MatsimTestUtils.EPSILON); Assertions.assertEquals(65, trafficVolumePerTypeAndZone_stop.get(trafficVolumeKey).getDouble(5), MatsimTestUtils.EPSILON); - trafficVolumeKey = TrafficVolumeGeneration.makeTrafficVolumeKey("testArea1_area2", modesORvehTypes.get(0)); + trafficVolumeKey = TrafficVolumeGeneration.makeTrafficVolumeKey("area2", modesORvehTypes.get(0)); Assertions.assertEquals(30, trafficVolumePerTypeAndZone_start.get(trafficVolumeKey).getDouble(1), MatsimTestUtils.EPSILON); sumOfStartOtherAreas += trafficVolumePerTypeAndZone_start.get(trafficVolumeKey).getDouble(2); Assertions.assertEquals(514, trafficVolumePerTypeAndZone_start.get(trafficVolumeKey).getDouble(3), MatsimTestUtils.EPSILON); @@ -714,7 +729,7 @@ void testReducingDemandAfterAddingExistingScenarios_commercialPersonTraffic() th Assertions.assertEquals(246, trafficVolumePerTypeAndZone_stop.get(trafficVolumeKey).getDouble(4), MatsimTestUtils.EPSILON); Assertions.assertEquals(102, trafficVolumePerTypeAndZone_stop.get(trafficVolumeKey).getDouble(5), MatsimTestUtils.EPSILON); - trafficVolumeKey = TrafficVolumeGeneration.makeTrafficVolumeKey("testArea2_area3", modesORvehTypes.get(0)); + trafficVolumeKey = TrafficVolumeGeneration.makeTrafficVolumeKey("area3", modesORvehTypes.get(0)); Assertions.assertEquals(6, trafficVolumePerTypeAndZone_start.get(trafficVolumeKey).getDouble(1), MatsimTestUtils.EPSILON); Assertions.assertEquals(0, trafficVolumePerTypeAndZone_start.get(trafficVolumeKey).getDouble(2), MatsimTestUtils.EPSILON); sumOfStartOtherAreas += trafficVolumePerTypeAndZone_start.get(trafficVolumeKey).getDouble(2); diff --git a/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/TripDistributionMatrixTest.java b/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/TripDistributionMatrixTest.java index adc41f61191..3c449937d90 100644 --- a/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/TripDistributionMatrixTest.java +++ b/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/TripDistributionMatrixTest.java @@ -59,10 +59,13 @@ void testTripDistributionCommercialPersonTrafficTraffic() throws IOException { String usedLanduseConfiguration = "useExistingDataDistribution"; String networkLocation = "https://raw.githubusercontent.com/matsim-org/matsim-libs/master/examples/scenarios/freight-chessboard-9x9/grid9x9.xml"; Network network = NetworkUtils.readNetwork(networkLocation); + String shapeFileZoneNameColumn = "name"; + Map> resultingDataPerZone = LanduseBuildingAnalysis .createInputDataDistribution(output, landuseCategoriesAndDataConnection, inputDataDirectory, usedLanduseConfiguration, - getIndexLanduse(inputDataDirectory), getZoneIndex(inputDataDirectory), getIndexBuildings(inputDataDirectory), buildingsPerZone); + getIndexLanduse(inputDataDirectory), getZoneIndex(inputDataDirectory), getIndexBuildings(inputDataDirectory), + SCTUtils.getIndexRegions(inputDataDirectory), shapeFileZoneNameColumn, buildingsPerZone); String usedTrafficType = "commercialPersonTraffic"; double sample = 1.; @@ -79,12 +82,12 @@ void testTripDistributionCommercialPersonTrafficTraffic() throws IOException { .newInstance(getZoneIndex(inputDataDirectory), trafficVolumePerTypeAndZone_start, trafficVolumePerTypeAndZone_stop, usedTrafficType).build(); Map, Link>> regionLinksMap = new HashMap<>(); - regionLinksMap.put("testArea1_area1", new HashMap<>()); - regionLinksMap.get("testArea1_area1").put(Id.createLinkId("i(8,6)"), network.getLinks().get(Id.createLinkId("i(8,6)"))); - regionLinksMap.put("testArea1_area2", new HashMap<>()); - regionLinksMap.get("testArea1_area2").put(Id.createLinkId("i(2,7)R"), network.getLinks().get(Id.createLinkId("i(2,7)R"))); - regionLinksMap.put("testArea2_area3", new HashMap<>()); - regionLinksMap.get("testArea2_area3").put(Id.createLinkId("i(2,1)R"), network.getLinks().get(Id.createLinkId("i(2,7)R"))); + regionLinksMap.put("area1", new HashMap<>()); + regionLinksMap.get("area1").put(Id.createLinkId("i(8,6)"), network.getLinks().get(Id.createLinkId("i(8,6)"))); + regionLinksMap.put("area2", new HashMap<>()); + regionLinksMap.get("area2").put(Id.createLinkId("i(2,7)R"), network.getLinks().get(Id.createLinkId("i(2,7)R"))); + regionLinksMap.put("area3", new HashMap<>()); + regionLinksMap.get("area3").put(Id.createLinkId("i(2,1)R"), network.getLinks().get(Id.createLinkId("i(2,7)R"))); for (String startZone : resultingDataPerZone.keySet()) { for (String stopZone : resultingDataPerZone.keySet()) { @@ -92,7 +95,7 @@ void testTripDistributionCommercialPersonTrafficTraffic() throws IOException { for (Integer purpose : trafficVolumePerTypeAndZone_start .get(TrafficVolumeGeneration.makeTrafficVolumeKey(startZone, modeORvehType)).keySet()) { odMatrix.setTripDistributionValue(startZone, stopZone, modeORvehType, purpose, usedTrafficType, - network, regionLinksMap, resistanceFactor); + network, regionLinksMap, resistanceFactor, shapeFileZoneNameColumn); } } } @@ -144,10 +147,12 @@ void testTripDistributionGoodsTraffic() throws IOException { String usedLanduseConfiguration = "useExistingDataDistribution"; String networkLocation = "https://raw.githubusercontent.com/matsim-org/matsim-libs/master/examples/scenarios/freight-chessboard-9x9/grid9x9.xml"; Network network = NetworkUtils.readNetwork(networkLocation); + String shapeFileZoneNameColumn = "name"; Map> resultingDataPerZone = LanduseBuildingAnalysis .createInputDataDistribution(output, landuseCategoriesAndDataConnection, inputDataDirectory, usedLanduseConfiguration, - getIndexLanduse(inputDataDirectory), getZoneIndex(inputDataDirectory), getIndexBuildings(inputDataDirectory), buildingsPerZone); + getIndexLanduse(inputDataDirectory), getZoneIndex(inputDataDirectory), getIndexBuildings(inputDataDirectory), + SCTUtils.getIndexRegions(inputDataDirectory), shapeFileZoneNameColumn, buildingsPerZone); String usedTrafficType = "goodsTraffic"; double sample = 1.; @@ -165,12 +170,12 @@ void testTripDistributionGoodsTraffic() throws IOException { .newInstance(getZoneIndex(inputDataDirectory), trafficVolumePerTypeAndZone_start, trafficVolumePerTypeAndZone_stop, usedTrafficType).build(); Map, Link>> regionLinksMap = new HashMap<>(); - regionLinksMap.put("testArea1_area1", new HashMap<>()); - regionLinksMap.get("testArea1_area1").put(Id.createLinkId("i(8,6)"), network.getLinks().get(Id.createLinkId("i(8,6)"))); - regionLinksMap.put("testArea1_area2", new HashMap<>()); - regionLinksMap.get("testArea1_area2").put(Id.createLinkId("i(2,7)R"), network.getLinks().get(Id.createLinkId("i(2,7)R"))); - regionLinksMap.put("testArea2_area3", new HashMap<>()); - regionLinksMap.get("testArea2_area3").put(Id.createLinkId("i(2,1)R"), network.getLinks().get(Id.createLinkId("i(2,7)R"))); + regionLinksMap.put("area1", new HashMap<>()); + regionLinksMap.get("area1").put(Id.createLinkId("i(8,6)"), network.getLinks().get(Id.createLinkId("i(8,6)"))); + regionLinksMap.put("area2", new HashMap<>()); + regionLinksMap.get("area2").put(Id.createLinkId("i(2,7)R"), network.getLinks().get(Id.createLinkId("i(2,7)R"))); + regionLinksMap.put("area3", new HashMap<>()); + regionLinksMap.get("area3").put(Id.createLinkId("i(2,1)R"), network.getLinks().get(Id.createLinkId("i(2,7)R"))); for (String startZone : resultingDataPerZone.keySet()) { for (String stopZone : resultingDataPerZone.keySet()) { @@ -178,7 +183,7 @@ void testTripDistributionGoodsTraffic() throws IOException { for (Integer purpose : trafficVolumePerTypeAndZone_start .get(TrafficVolumeGeneration.makeTrafficVolumeKey(startZone, modeORvehType)).keySet()) { odMatrix.setTripDistributionValue(startZone, stopZone, modeORvehType, purpose, usedTrafficType, - network, regionLinksMap, resistanceFactor); + network, regionLinksMap, resistanceFactor, shapeFileZoneNameColumn); } } } diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/dataDistributionPerZone.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/dataDistributionPerZone.csv index 70857ece6c1..0a841cc7dd0 100644 --- a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/dataDistributionPerZone.csv +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/dataDistributionPerZone.csv @@ -1,4 +1,4 @@ -areaID areaName Inhabitants Employee Employee Primary Sector Employee Construction Employee Secondary Sector Rest Employee Retail Employee Traffic/Parcels Employee Tertiary Sector Rest -testArea1_area2 area2 4000 6500 500 1500 500 500 1500 2000 -testArea2_area3 area3 800 1000 50 200 100 150 200 300 -testArea1_area1 area1 4000 3500 0 500 500 1000 500 1000 \ No newline at end of file +zoneID region Inhabitants Employee Employee Primary Sector Employee Construction Employee Secondary Sector Rest Employee Retail Employee Traffic/Parcels Employee Tertiary Sector Rest +area2 region1 4000 6500 500 1500 500 500 1500 2000 +area3 region2 800 1000 50 200 100 150 200 300 +area1 region1 4000 3500 0 500 500 1000 500 1000 \ No newline at end of file diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/investigationAreaData.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/investigationAreaData.csv index e8dd1cb57ff..97fe8fd80b7 100644 --- a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/investigationAreaData.csv +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/investigationAreaData.csv @@ -1,3 +1,3 @@ -Area Inhabitants Employee Employee Primary Sector Employee Construction Employee Secondary Sector Rest Employee Retail Employee Traffic/Parcels Employee Tertiary Sector Rest -testArea1 8000 10000 500 2000 1000 1500 2000 3000 -testArea2 800 1000 50 200 100 150 200 300 \ No newline at end of file +Region Inhabitants Employee Employee Primary Sector Employee Construction Employee Secondary Sector Rest Employee Retail Employee Traffic/Parcels Employee Tertiary Sector Rest +region1 8000 10000 500 2000 1000 1500 2000 3000 +region2 800 1000 50 200 100 150 200 300 \ No newline at end of file diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/shp/testRegions.cpg b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/shp/testRegions.cpg new file mode 100644 index 00000000000..3ad133c048f --- /dev/null +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/shp/testRegions.cpg @@ -0,0 +1 @@ +UTF-8 \ No newline at end of file diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/shp/testRegions.dbf b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/shp/testRegions.dbf new file mode 100644 index 0000000000000000000000000000000000000000..c97184381a41f9d0de4adfc94eab0598ade608bc GIT binary patch literal 280 zcmZRsVG?CxU|>jOhz63FATtFn<_BVN!MPAdQEGZ-ejb?Z3?c&{!f=vT0S*iyY7OB6 O)MFSyj5ea0iBbS8U?4^S literal 0 HcmV?d00001 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/shp/testRegions.prj b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/shp/testRegions.prj new file mode 100644 index 00000000000..f45cbadf007 --- /dev/null +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/shp/testRegions.prj @@ -0,0 +1 @@ +GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]] \ No newline at end of file diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/shp/testRegions.qmd b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/shp/testRegions.qmd new file mode 100644 index 00000000000..d8b7603dead --- /dev/null +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/shp/testRegions.qmd @@ -0,0 +1,26 @@ + + + + + + dataset + + + + + + + + + + 0 + 0 + + + + + false + + + + diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/shp/testRegions.shp b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/shp/testRegions.shp new file mode 100644 index 0000000000000000000000000000000000000000..50121591ca3edcf4cfebddeeeb717c5a517ad0bc GIT binary patch literal 372 zcmZQzQ0HR64tBj@W?*0i$`#nWJ#H&gc0gf8GS4*s`UBe{*1cKIe%PVj?aYBTt3wXh zwWEkK0(lM~vlImV>@*Bh4tRX(v;VVcg#)@-AcY`xU?6w;UVpFh0T;=TC9>j&Fx0~I z!pwr1y(YKgndre)4h(4efo3uRG1wjGe(IComHr}Tg9C@4;nbJWs~nKsaUec2CZ9X^ p08EY}f4SNZ?hOtl|9@PR$Xw|F(+dk9nAr)tG9KkQKNcIH5v)gcG$ P+EGM}fIN`8G7t>_bVw39 literal 0 HcmV?d00001 From 678d802f06290479415150bf059fe7ca9f6f8920 Mon Sep 17 00:00:00 2001 From: Ricardo Ewert Date: Thu, 22 Feb 2024 09:12:48 +0100 Subject: [PATCH 02/12] use recent methods --- .../SmallScaleCommercialTrafficUtils.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/SmallScaleCommercialTrafficUtils.java b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/SmallScaleCommercialTrafficUtils.java index 690b4f68920..d862d842dad 100644 --- a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/SmallScaleCommercialTrafficUtils.java +++ b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/SmallScaleCommercialTrafficUtils.java @@ -273,8 +273,8 @@ else if (subpopulation.contains("goodsTraffic")) Id vehicleId = Id.createVehicleId(person.getId().toString()); - VehicleUtils.insertVehicleIdsIntoAttributes(newPerson, Map.of(mode, vehicleId)); - VehicleUtils.insertVehicleTypesIntoAttributes(newPerson, Map.of(mode, allVehicles.getVehicles().get(vehicleId).getType().getId())); + VehicleUtils.insertVehicleIdsIntoPersonAttributes(newPerson, Map.of(mode, vehicleId)); + VehicleUtils.insertVehicleTypesIntoPersonAttributes(newPerson, Map.of(mode, allVehicles.getVehicles().get(vehicleId).getType().getId())); population.addPerson(newPerson); } From 63455403e38b531e8fcd6f63ccd9e9f27b4fdb91 Mon Sep 17 00:00:00 2001 From: Ricardo Ewert Date: Thu, 22 Feb 2024 16:07:22 +0100 Subject: [PATCH 03/12] adjust test --- .../TripDistributionMatrixTest.java | 4 ++-- ...icVolume_commercialPersonTraffic_startPerZone_10pt.csv | 8 ++++---- ...ficVolume_commercialPersonTraffic_stopPerZone_10pt.csv | 8 ++++---- .../calculatedData/dataDistributionPerZone.csv | 8 ++++---- .../odMatrix_commercialPersonTraffic_total_purpose1.csv | 8 ++++---- .../odMatrix_commercialPersonTraffic_total_purpose2.csv | 8 ++++---- .../odMatrix_commercialPersonTraffic_total_purpose3.csv | 8 ++++---- .../odMatrix_commercialPersonTraffic_total_purpose4.csv | 8 ++++---- .../odMatrix_commercialPersonTraffic_total_purpose5.csv | 8 ++++---- 9 files changed, 34 insertions(+), 34 deletions(-) diff --git a/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/TripDistributionMatrixTest.java b/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/TripDistributionMatrixTest.java index 51ec2149f3e..76f6c0b6cd8 100644 --- a/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/TripDistributionMatrixTest.java +++ b/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/TripDistributionMatrixTest.java @@ -78,7 +78,7 @@ void testTripDistributionCommercialPersonTrafficTraffic() throws IOException { .createTrafficVolume_start(resultingDataPerZone, output, sample, modesORvehTypes, usedTrafficType); Map> trafficVolumePerTypeAndZone_stop = TrafficVolumeGeneration .createTrafficVolume_stop(resultingDataPerZone, output, sample, modesORvehTypes, usedTrafficType); - ArrayList listOfZones = new ArrayList<>( List.of("testArea1_area1", "testArea1_area2", "testArea2_area3")); + ArrayList listOfZones = new ArrayList<>( List.of("area1", "area2", "area3")); final TripDistributionMatrix odMatrix = TripDistributionMatrix.Builder .newInstance(getZoneIndex(inputDataDirectory), trafficVolumePerTypeAndZone_start, trafficVolumePerTypeAndZone_stop, usedTrafficType, listOfZones).build(); @@ -162,7 +162,7 @@ void testTripDistributionGoodsTraffic() throws IOException { ArrayList modesORvehTypes = new ArrayList( Arrays.asList("vehTyp1", "vehTyp2", "vehTyp3", "vehTyp4", "vehTyp5")); - ArrayList listOfZones = new ArrayList<>( List.of("testArea1_area1", "testArea1_area2", "testArea2_area3")); + ArrayList listOfZones = new ArrayList<>( List.of("area1", "area2", "area3")); TrafficVolumeGeneration.setInputParameters(usedTrafficType); diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/TrafficVolume_commercialPersonTraffic_startPerZone_10pt.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/TrafficVolume_commercialPersonTraffic_startPerZone_10pt.csv index bfdf8e63f8c..d946fd0733e 100644 --- a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/TrafficVolume_commercialPersonTraffic_startPerZone_10pt.csv +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/TrafficVolume_commercialPersonTraffic_startPerZone_10pt.csv @@ -1,4 +1,4 @@ -areaID mode/vehType 1 2 3 4 5 -testArea2_area3 total 1 3 8 6 9 -testArea1_area2 total 3 21 51 44 63 -testArea1_area1 total 3 12 28 18 25 +zoneID mode/vehType 1 2 3 4 5 +area3 total 1 3 8 6 9 +area2 total 3 21 51 44 63 +area1 total 3 12 28 18 25 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/TrafficVolume_commercialPersonTraffic_stopPerZone_10pt.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/TrafficVolume_commercialPersonTraffic_stopPerZone_10pt.csv index 0c53286d73b..b9bc1b4faed 100644 --- a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/TrafficVolume_commercialPersonTraffic_stopPerZone_10pt.csv +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/TrafficVolume_commercialPersonTraffic_stopPerZone_10pt.csv @@ -1,4 +1,4 @@ -areaID mode/vehType 1 2 3 4 5 -testArea2_area3 total 0 3 13 4 2 -testArea1_area2 total 1 20 86 25 10 -testArea1_area1 total 1 10 43 12 6 +zoneID mode/vehType 1 2 3 4 5 +area3 total 0 3 13 4 2 +area2 total 1 20 86 25 10 +area1 total 1 10 43 12 6 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/dataDistributionPerZone.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/dataDistributionPerZone.csv index 70857ece6c1..0a841cc7dd0 100644 --- a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/dataDistributionPerZone.csv +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/dataDistributionPerZone.csv @@ -1,4 +1,4 @@ -areaID areaName Inhabitants Employee Employee Primary Sector Employee Construction Employee Secondary Sector Rest Employee Retail Employee Traffic/Parcels Employee Tertiary Sector Rest -testArea1_area2 area2 4000 6500 500 1500 500 500 1500 2000 -testArea2_area3 area3 800 1000 50 200 100 150 200 300 -testArea1_area1 area1 4000 3500 0 500 500 1000 500 1000 \ No newline at end of file +zoneID region Inhabitants Employee Employee Primary Sector Employee Construction Employee Secondary Sector Rest Employee Retail Employee Traffic/Parcels Employee Tertiary Sector Rest +area2 region1 4000 6500 500 1500 500 500 1500 2000 +area3 region2 800 1000 50 200 100 150 200 300 +area1 region1 4000 3500 0 500 500 1000 500 1000 \ No newline at end of file diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose1.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose1.csv index 38573c7f4c0..05a9702515f 100644 --- a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose1.csv +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose1.csv @@ -1,4 +1,4 @@ - testArea2_area3 testArea1_area2 testArea1_area1 -testArea2_area3 0 0 0 -testArea1_area2 0 1 0 -testArea1_area1 0 0 1 + area3 area2 area1 +area3 0 0 0 +area2 0 1 0 +area1 0 0 1 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose2.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose2.csv index 30cf57e5fc3..2d38380ff79 100644 --- a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose2.csv +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose2.csv @@ -1,4 +1,4 @@ - testArea2_area3 testArea1_area2 testArea1_area1 -testArea2_area3 0 0 0 -testArea1_area2 0 8 7 -testArea1_area1 1 5 3 + area3 area2 area1 +area3 0 0 0 +area2 0 8 7 +area1 1 5 3 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose3.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose3.csv index 44108374c44..b2faebe2b79 100644 --- a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose3.csv +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose3.csv @@ -1,4 +1,4 @@ - testArea2_area3 testArea1_area2 testArea1_area1 -testArea2_area3 2 7 3 -testArea1_area2 7 52 25 -testArea1_area1 4 27 15 + area3 area2 area1 +area3 2 7 3 +area2 7 52 25 +area1 4 27 15 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose4.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose4.csv index 6cebadd2f70..315a6675069 100644 --- a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose4.csv +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose4.csv @@ -1,4 +1,4 @@ - testArea2_area3 testArea1_area2 testArea1_area1 -testArea2_area3 0 2 2 -testArea1_area2 2 17 7 -testArea1_area1 2 6 3 + area3 area2 area1 +area3 0 2 2 +area2 2 17 7 +area1 2 6 3 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose5.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose5.csv index 5d7cb865fbf..3024476606f 100644 --- a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose5.csv +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose5.csv @@ -1,4 +1,4 @@ - testArea2_area3 testArea1_area2 testArea1_area1 -testArea2_area3 0 0 0 -testArea1_area2 1 7 4 -testArea1_area1 1 3 2 + area3 area2 area1 +area3 0 0 0 +area2 1 7 4 +area1 1 3 2 From 58f3f2f7ec1e20ea6e78bf59ca470000b812650d Mon Sep 17 00:00:00 2001 From: Ricardo Ewert Date: Thu, 22 Feb 2024 16:07:58 +0100 Subject: [PATCH 04/12] typo --- .../RunGenerateSmallScaleCommercialTrafficTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/RunGenerateSmallScaleCommercialTrafficTest.java b/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/RunGenerateSmallScaleCommercialTrafficTest.java index be8228818e9..52a9ab55185 100644 --- a/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/RunGenerateSmallScaleCommercialTrafficTest.java +++ b/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/RunGenerateSmallScaleCommercialTrafficTest.java @@ -115,11 +115,11 @@ void testMainRunAndResults() { } Assertions.assertEquals(population.getPersons().size(), countedTours, 0); - for (File caculatedFile : Objects.requireNonNull( + for (File calculatedFile : Objects.requireNonNull( Objects.requireNonNull(new File(utils.getOutputDirectory() + "calculatedData").listFiles()))) { MatsimTestUtils.assertEqualFilesLineByLine( - utils.getPackageInputDirectory() + "calculatedData/" + caculatedFile.getName(), - caculatedFile.getAbsolutePath()); + utils.getPackageInputDirectory() + "calculatedData/" + calculatedFile.getName(), + calculatedFile.getAbsolutePath()); } // compare events From ae0bc3eaef6cbb32f4fc28c0a2021e35b16f774f Mon Sep 17 00:00:00 2001 From: Ricardo Ewert Date: Thu, 22 Feb 2024 16:08:30 +0100 Subject: [PATCH 05/12] add missing parameter --- .../GenerateSmallScaleCommercialTrafficDemand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java index 836a90894c5..1cde92e04aa 100644 --- a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java +++ b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java @@ -241,7 +241,7 @@ public Integer call() throws Exception { } Path inputDataDirectory = Path.of(config.getContext().toURI()).getParent(); - indexZones = SmallScaleCommercialTrafficUtils.getIndexZones(shapeFileZonePath, shapeCRS); + indexZones = SmallScaleCommercialTrafficUtils.getIndexZones(shapeFileZonePath, shapeCRS, shapeFileZoneNameColumn); indexBuildings = SmallScaleCommercialTrafficUtils.getIndexBuildings(shapeFileBuildingsPath, shapeCRS); indexLanduse = SmallScaleCommercialTrafficUtils.getIndexLanduse(shapeFileLandusePath, shapeCRS); indexInvestigationAreaRegions = SmallScaleCommercialTrafficUtils.getIndexRegions(shapeFileRegionsPath, shapeCRS, regionsShapeRegionColumn); From 81ad86260f9f162270ffdf789110646d6f20f2de Mon Sep 17 00:00:00 2001 From: Ricardo Ewert Date: Thu, 22 Feb 2024 21:26:34 +0100 Subject: [PATCH 06/12] adjust tests for new structure of generation --- ...nerateSmallScaleCommercialTrafficTest.java | 66 ++++++++++++++++-- ...mercialPersonTraffic_startPerZone_10pt.csv | 2 +- ...mmercialPersonTraffic_stopPerZone_10pt.csv | 2 +- ...commercialPersonTraffic_total_purpose1.csv | 6 +- ...commercialPersonTraffic_total_purpose2.csv | 6 +- ...commercialPersonTraffic_total_purpose3.csv | 8 +-- ...commercialPersonTraffic_total_purpose4.csv | 8 +-- ...commercialPersonTraffic_total_purpose5.csv | 8 +-- .../test.output_events.xml.gz | Bin 35753 -> 31240 bytes 9 files changed, 82 insertions(+), 24 deletions(-) diff --git a/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/RunGenerateSmallScaleCommercialTrafficTest.java b/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/RunGenerateSmallScaleCommercialTrafficTest.java index 52a9ab55185..ad41064119a 100644 --- a/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/RunGenerateSmallScaleCommercialTrafficTest.java +++ b/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/RunGenerateSmallScaleCommercialTrafficTest.java @@ -19,6 +19,11 @@ * *********************************************************************** */ package org.matsim.smallScaleCommercialTrafficGeneration; +import it.unimi.dsi.fastutil.objects.Object2DoubleMap; +import it.unimi.dsi.fastutil.objects.Object2DoubleOpenHashMap; +import org.apache.commons.csv.CSVFormat; +import org.apache.commons.csv.CSVParser; +import org.apache.commons.csv.CSVRecord; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -30,13 +35,18 @@ import org.matsim.core.events.EventsUtils; import org.matsim.core.population.PopulationUtils; import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; import org.matsim.freight.carriers.Carrier; import org.matsim.freight.carriers.CarriersUtils; import org.matsim.freight.carriers.FreightCarriersConfigGroup; import org.matsim.testcases.MatsimTestUtils; import org.matsim.utils.eventsfilecomparison.EventsFileComparator; +import java.io.BufferedReader; import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; import java.util.Objects; /** @@ -117,15 +127,63 @@ void testMainRunAndResults() { for (File calculatedFile : Objects.requireNonNull( Objects.requireNonNull(new File(utils.getOutputDirectory() + "calculatedData").listFiles()))) { - MatsimTestUtils.assertEqualFilesLineByLine( - utils.getPackageInputDirectory() + "calculatedData/" + calculatedFile.getName(), - calculatedFile.getAbsolutePath()); + Map> existingDataDistribution = readCSVInputAndCreateMap(calculatedFile.getAbsolutePath()); + Map> simulatedDataDistribution = readCSVInputAndCreateMap( + utils.getPackageInputDirectory() + "calculatedData/" + calculatedFile.getName()); + compareDataDistribution(calculatedFile.getName(), existingDataDistribution, simulatedDataDistribution); } // compare events - String expected = utils.getPackageInputDirectory() + "test.output_events.xml.gz" ; + String expected = utils.getPackageInputDirectory() + "test.output_events.xml.gz"; String actual = utils.getOutputDirectory() + "test.output_events.xml.gz" ; EventsFileComparator.Result result = EventsUtils.compareEventsFiles( expected, actual ); Assertions.assertEquals( EventsFileComparator.Result.FILES_ARE_EQUAL, result ); } + + /** + * Reads a CSV file and creates a map with the first column as key and the rest as a map with the header as key and the value as value + * + * @param calculatedFile the file to read + * @return + */ + private static Map> readCSVInputAndCreateMap(String calculatedFile) { + Map> dataDistribution = new HashMap<>(); + try (BufferedReader reader = IOUtils.getBufferedReader(calculatedFile)) { + CSVParser parse = CSVFormat.Builder.create(CSVFormat.DEFAULT).setDelimiter('\t').setHeader() + .setSkipHeaderRecord(true).build().parse(reader); + for (CSVRecord record : parse) { + System.out.println(record); + dataDistribution.computeIfAbsent(record.get(0), k -> new Object2DoubleOpenHashMap<>()); + for (int i = 1; i < record.size(); i++) { + if (i == 1 && (calculatedFile.contains("dataDistributionPerZone") || calculatedFile.contains("TrafficVolume_"))) + continue; + dataDistribution.get(record.get(0)).put(parse.getHeaderNames().get(i), Double.parseDouble(record.get(i))); + } + } + } catch (IOException e) { + throw new RuntimeException(e); + } + return dataDistribution; + } + + /** + * Compares the data distribution of two files + * + * @param calculatedFile the file to compare + * @param existingDataDistribution the existing data distribution + * @param simulatedDataDistribution the simulated data distribution + */ + private void compareDataDistribution(String calculatedFile, Map> existingDataDistribution, + Map> simulatedDataDistribution) { + Assertions.assertEquals(existingDataDistribution.size(), simulatedDataDistribution.size()); + for (String key : existingDataDistribution.keySet()) { + Object2DoubleMap existingMap = existingDataDistribution.get(key); + Object2DoubleMap simulatedMap = simulatedDataDistribution.get(key); + for (String subKey : existingMap.keySet()) { + Assertions.assertEquals(existingMap.getDouble(subKey), simulatedMap.getDouble(subKey), + "File: " + calculatedFile + "; Expected: " + existingMap.getDouble(subKey) + " but was: " + simulatedMap.getDouble( + subKey) + " for key: " + key + " and subKey: " + subKey); + } + } + } } diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/TrafficVolume_commercialPersonTraffic_startPerZone_10pt.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/TrafficVolume_commercialPersonTraffic_startPerZone_10pt.csv index d946fd0733e..76905762d24 100644 --- a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/TrafficVolume_commercialPersonTraffic_startPerZone_10pt.csv +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/TrafficVolume_commercialPersonTraffic_startPerZone_10pt.csv @@ -1,4 +1,4 @@ zoneID mode/vehType 1 2 3 4 5 -area3 total 1 3 8 6 9 area2 total 3 21 51 44 63 area1 total 3 12 28 18 25 +area3 total 1 3 8 6 9 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/TrafficVolume_commercialPersonTraffic_stopPerZone_10pt.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/TrafficVolume_commercialPersonTraffic_stopPerZone_10pt.csv index b9bc1b4faed..837a7d38659 100644 --- a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/TrafficVolume_commercialPersonTraffic_stopPerZone_10pt.csv +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/TrafficVolume_commercialPersonTraffic_stopPerZone_10pt.csv @@ -1,4 +1,4 @@ zoneID mode/vehType 1 2 3 4 5 -area3 total 0 3 13 4 2 area2 total 1 20 86 25 10 area1 total 1 10 43 12 6 +area3 total 0 3 13 4 2 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose1.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose1.csv index 05a9702515f..1bc43756980 100644 --- a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose1.csv +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose1.csv @@ -1,4 +1,4 @@ - area3 area2 area1 +O/D area2 area1 area3 +area2 1 0 0 +area1 0 1 0 area3 0 0 0 -area2 0 1 0 -area1 0 0 1 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose2.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose2.csv index 2d38380ff79..5b49558b3a5 100644 --- a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose2.csv +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose2.csv @@ -1,4 +1,4 @@ - area3 area2 area1 +O/D area2 area1 area3 +area2 8 6 0 +area1 5 4 1 area3 0 0 0 -area2 0 8 7 -area1 1 5 3 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose3.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose3.csv index b2faebe2b79..04d2d8af059 100644 --- a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose3.csv +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose3.csv @@ -1,4 +1,4 @@ - area3 area2 area1 -area3 2 7 3 -area2 7 52 25 -area1 4 27 15 +O/D area2 area1 area3 +area2 51 24 7 +area1 27 15 4 +area3 8 4 2 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose4.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose4.csv index 315a6675069..3d2f4777106 100644 --- a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose4.csv +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose4.csv @@ -1,4 +1,4 @@ - area3 area2 area1 -area3 0 2 2 -area2 2 17 7 -area1 2 6 3 +O/D area2 area1 area3 +area2 16 7 2 +area1 7 3 1 +area3 2 2 1 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose5.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose5.csv index 3024476606f..ac996432028 100644 --- a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose5.csv +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose5.csv @@ -1,4 +1,4 @@ - area3 area2 area1 -area3 0 0 0 -area2 1 7 4 -area1 1 3 2 +O/D area2 area1 area3 +area2 7 4 1 +area1 3 2 0 +area3 0 0 1 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/test.output_events.xml.gz b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/test.output_events.xml.gz index a3f7231747b670ea68e7ba42dd8450140bb559ba..cedefa5d9a5ec188923a208878e0c7c869076d31 100644 GIT binary patch literal 31240 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 literal 35753 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 From 0a286030c64a8960dd280757ab3a12cd9cf88795 Mon Sep 17 00:00:00 2001 From: Ricardo Ewert Date: Thu, 22 Feb 2024 21:26:47 +0100 Subject: [PATCH 07/12] add column name --- .../TripDistributionMatrix.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/TripDistributionMatrix.java b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/TripDistributionMatrix.java index 991c6d9a39d..c2a032545b5 100644 --- a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/TripDistributionMatrix.java +++ b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/TripDistributionMatrix.java @@ -605,7 +605,7 @@ void writeODMatrices(Path output, String smallScaleCommercialTrafficType) throws try { List headerRow = new ArrayList<>(); - headerRow.add(""); + headerRow.add("O/D"); headerRow.addAll(usedZones); JOIN.appendTo(writer, headerRow); writer.write("\n"); From 7c8b142639290030c227b7df9602d0cbda2cc538 Mon Sep 17 00:00:00 2001 From: Ricardo Ewert Date: Thu, 22 Feb 2024 21:32:38 +0100 Subject: [PATCH 08/12] change name --- ...rateSmallScaleCommercialTrafficDemand.java | 21 ++++++++-------- .../SmallScaleCommercialTrafficUtils.java | 16 ++++++------- .../TrafficVolumeGeneration.java | 20 ++++++++-------- .../TripDistributionMatrix.java | 24 +++++++++---------- 4 files changed, 40 insertions(+), 41 deletions(-) diff --git a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java index 1cde92e04aa..15455c08a70 100644 --- a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java +++ b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java @@ -250,19 +250,18 @@ public Integer call() throws Exception { .createInputDataDistribution(output, landuseCategoriesAndDataConnection, inputDataDirectory, usedLanduseConfiguration.toString(), indexLanduse, indexZones, indexBuildings, indexInvestigationAreaRegions, shapeFileZoneNameColumn, buildingsPerZone); - //TODO regionLinksMap umbenennen, da es alle Links einer Zone enthält - Map, Link>> regionLinksMap = filterLinksForZones(scenario, indexZones, buildingsPerZone); + Map, Link>> linksPerZone = filterLinksForZones(scenario, indexZones, buildingsPerZone); switch (usedSmallScaleCommercialTrafficType) { case commercialPersonTraffic, goodsTraffic -> - createCarriersAndDemand(output, scenario, resultingDataPerZone, regionLinksMap, + createCarriersAndDemand(output, scenario, resultingDataPerZone, linksPerZone, usedSmallScaleCommercialTrafficType.toString(), includeExistingModels); case completeSmallScaleCommercialTraffic -> { - createCarriersAndDemand(output, scenario, resultingDataPerZone, regionLinksMap, "commercialPersonTraffic", + createCarriersAndDemand(output, scenario, resultingDataPerZone, linksPerZone, "commercialPersonTraffic", includeExistingModels); includeExistingModels = false; // because already included in the step before - createCarriersAndDemand(output, scenario, resultingDataPerZone, regionLinksMap, "goodsTraffic", + createCarriersAndDemand(output, scenario, resultingDataPerZone, linksPerZone, "goodsTraffic", includeExistingModels); } default -> throw new RuntimeException("No traffic type selected."); @@ -274,7 +273,7 @@ public Integer call() throws Exception { new CarrierPlanWriter(CarriersUtils.addOrGetCarriers(scenario)) .write(scenario.getConfig().controller().getOutputDirectory() + "/" + scenario.getConfig().controller().getRunId() + ".output_CarrierDemand.xml"); - solveSeparatedVRPs(scenario, regionLinksMap); + solveSeparatedVRPs(scenario, linksPerZone); } } if (config.controller().getRunId() == null) @@ -438,7 +437,7 @@ private void solveSeparatedVRPs(Scenario originalScenario, Map> resultingDataPerZone, - Map, Link>> regionLinksMap, String smallScaleCommercialTrafficType, + Map, Link>> linksPerZone, String smallScaleCommercialTrafficType, boolean includeExistingModels) throws Exception { ArrayList modesORvehTypes; @@ -458,13 +457,13 @@ else if (smallScaleCommercialTrafficType.equals("commercialPersonTraffic")) .createTrafficVolume_stop(resultingDataPerZone, output, sample, modesORvehTypes, smallScaleCommercialTrafficType); if (includeExistingModels) { - SmallScaleCommercialTrafficUtils.readExistingModels(scenario, sample, regionLinksMap); - TrafficVolumeGeneration.reduceDemandBasedOnExistingCarriers(scenario, regionLinksMap, smallScaleCommercialTrafficType, + SmallScaleCommercialTrafficUtils.readExistingModels(scenario, sample, linksPerZone); + TrafficVolumeGeneration.reduceDemandBasedOnExistingCarriers(scenario, linksPerZone, smallScaleCommercialTrafficType, trafficVolumePerTypeAndZone_start, trafficVolumePerTypeAndZone_stop); } final TripDistributionMatrix odMatrix = createTripDistribution(trafficVolumePerTypeAndZone_start, - trafficVolumePerTypeAndZone_stop, smallScaleCommercialTrafficType, scenario, output, regionLinksMap); - createCarriers(scenario, odMatrix, resultingDataPerZone, smallScaleCommercialTrafficType, regionLinksMap); + trafficVolumePerTypeAndZone_stop, smallScaleCommercialTrafficType, scenario, output, linksPerZone); + createCarriers(scenario, odMatrix, resultingDataPerZone, smallScaleCommercialTrafficType, linksPerZone); } /** diff --git a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/SmallScaleCommercialTrafficUtils.java b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/SmallScaleCommercialTrafficUtils.java index d862d842dad..1b43d411522 100644 --- a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/SmallScaleCommercialTrafficUtils.java +++ b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/SmallScaleCommercialTrafficUtils.java @@ -135,11 +135,11 @@ static void writeResultOfDataDistribution(Map> log.info("The data distribution is finished and written to: " + outputFileInOutputFolder); } - static Id findNearestPossibleLink(String zone, List noPossibleLinks, Map, Link>> regionLinksMap, + static Id findNearestPossibleLink(String zone, List noPossibleLinks, Map, Link>> linksPerZone, Id newLink, Coord centroidPointOfBuildingPolygon, int numberOfPossibleLinks) { double minDistance = Double.MAX_VALUE; searchLink: - for (Link possibleLink : regionLinksMap.get(zone).values()) { + for (Link possibleLink : linksPerZone.get(zone).values()) { if (possibleLink.getToNode().getOutLinks() == null) continue; if (noPossibleLinks != null && numberOfPossibleLinks > noPossibleLinks.size()) @@ -157,7 +157,7 @@ static Id findNearestPossibleLink(String zone, List noPossibleLink } } if (newLink == null && numberOfPossibleLinks > 0) { - for (Link possibleLink : regionLinksMap.get(zone).values()) { + for (Link possibleLink : linksPerZone.get(zone).values()) { double distance = NetworkUtils.getEuclideanDistance(centroidPointOfBuildingPolygon, (Coord) possibleLink.getAttributes().getAttribute("newCoord")); if (distance < minDistance) { @@ -314,7 +314,7 @@ static String getSampleNameOfOutputFolder(double sample) { * dispersedTraffic will be added additionally. */ static void readExistingModels(Scenario scenario, double sampleScenario, - Map, Link>> regionLinksMap) throws Exception { + Map, Link>> linksPerZone) throws Exception { Path existingModelsFolder = Path.of(scenario.getConfig().getContext().toURI()).getParent().resolve("existingModels"); String locationOfExistingModels = existingModelsFolder.resolve("existingModels.csv").toString(); @@ -515,7 +515,7 @@ else if (!carrier.getShipments().isEmpty()) List startAreas = new ArrayList<>(); for (ScheduledTour tour : newCarrier.getSelectedPlan().getScheduledTours()) { - String tourStartZone = findZoneOfLink(tour.getTour().getStartLinkId(), regionLinksMap); + String tourStartZone = findZoneOfLink(tour.getTour().getStartLinkId(), linksPerZone); if (!startAreas.contains(tourStartZone)) startAreas.add(tourStartZone); } @@ -543,9 +543,9 @@ else if (!carrier.getShipments().isEmpty()) /** * Find the zone where the link is located */ - static String findZoneOfLink(Id linkId, Map, Link>> regionLinksMap) { - for (String area : regionLinksMap.keySet()) { - if (regionLinksMap.get(area).containsKey(linkId)) + static String findZoneOfLink(Id linkId, Map, Link>> linksPerZone) { + for (String area : linksPerZone.keySet()) { + if (linksPerZone.get(area).containsKey(linkId)) return area; } return null; diff --git a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/TrafficVolumeGeneration.java b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/TrafficVolumeGeneration.java index 3d4588c5300..b376d16d176 100644 --- a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/TrafficVolumeGeneration.java +++ b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/TrafficVolumeGeneration.java @@ -267,13 +267,13 @@ static void setInputParameters(String smallScaleCommercialTrafficType) { * Reduces the traffic volumes based on the added existing models. * * @param scenario scenario - * @param regionLinksMap links for each zone + * @param linksPerZone links for each zone * @param smallScaleCommercialTrafficType used trafficType (commercialPersonTraffic or goodsTraffic) * @param trafficVolumePerTypeAndZone_start trafficVolume for start potentials for each zone * @param trafficVolumePerTypeAndZone_stop trafficVolume for stop potentials for each zone */ static void reduceDemandBasedOnExistingCarriers(Scenario scenario, - Map, Link>> regionLinksMap, String smallScaleCommercialTrafficType, + Map, Link>> linksPerZone, String smallScaleCommercialTrafficType, Map> trafficVolumePerTypeAndZone_start, Map> trafficVolumePerTypeAndZone_stop) { @@ -290,11 +290,11 @@ static void reduceDemandBasedOnExistingCarriers(Scenario scenario, if (carrier.getSelectedPlan() != null) { for (ScheduledTour tour : carrier.getSelectedPlan().getScheduledTours()) { String startZone = SmallScaleCommercialTrafficUtils.findZoneOfLink(tour.getTour().getStartLinkId(), - regionLinksMap); + linksPerZone); for (TourElement tourElement : tour.getTour().getTourElements()) { if (tourElement instanceof ServiceActivity service) { String stopZone = SmallScaleCommercialTrafficUtils.findZoneOfLink(service.getLocation(), - regionLinksMap); + linksPerZone); try { reduceVolumeForThisExistingJobElement(trafficVolumePerTypeAndZone_start, trafficVolumePerTypeAndZone_stop, modeORvehType, purpose, startZone, stopZone); @@ -306,9 +306,9 @@ static void reduceDemandBasedOnExistingCarriers(Scenario scenario, } if (tourElement instanceof Pickup pickup) { startZone = SmallScaleCommercialTrafficUtils.findZoneOfLink(pickup.getShipment().getFrom(), - regionLinksMap); + linksPerZone); String stopZone = SmallScaleCommercialTrafficUtils.findZoneOfLink(pickup.getShipment().getTo(), - regionLinksMap); + linksPerZone); try { reduceVolumeForThisExistingJobElement(trafficVolumePerTypeAndZone_start, trafficVolumePerTypeAndZone_stop, modeORvehType, purpose, startZone, stopZone); @@ -325,13 +325,13 @@ static void reduceDemandBasedOnExistingCarriers(Scenario scenario, List possibleStartAreas = new ArrayList<>(); for (CarrierVehicle vehicle : carrier.getCarrierCapabilities().getCarrierVehicles().values()) { possibleStartAreas - .add(SmallScaleCommercialTrafficUtils.findZoneOfLink(vehicle.getLinkId(), regionLinksMap)); + .add(SmallScaleCommercialTrafficUtils.findZoneOfLink(vehicle.getLinkId(), linksPerZone)); } for (CarrierService service : carrier.getServices().values()) { String startZone = (String) possibleStartAreas.toArray()[MatsimRandom.getRandom() .nextInt(possibleStartAreas.size())]; String stopZone = SmallScaleCommercialTrafficUtils.findZoneOfLink(service.getLocationLinkId(), - regionLinksMap); + linksPerZone); try { reduceVolumeForThisExistingJobElement(trafficVolumePerTypeAndZone_start, trafficVolumePerTypeAndZone_stop, modeORvehType, purpose, startZone, stopZone); @@ -344,9 +344,9 @@ static void reduceDemandBasedOnExistingCarriers(Scenario scenario, } else if (!carrier.getShipments().isEmpty()) { for (CarrierShipment shipment : carrier.getShipments().values()) { String startZone = SmallScaleCommercialTrafficUtils.findZoneOfLink(shipment.getFrom(), - regionLinksMap); + linksPerZone); String stopZone = SmallScaleCommercialTrafficUtils.findZoneOfLink(shipment.getTo(), - regionLinksMap); + linksPerZone); try { reduceVolumeForThisExistingJobElement(trafficVolumePerTypeAndZone_start, trafficVolumePerTypeAndZone_stop, modeORvehType, purpose, startZone, stopZone); diff --git a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/TripDistributionMatrix.java b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/TripDistributionMatrix.java index c2a032545b5..f577c73deaa 100644 --- a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/TripDistributionMatrix.java +++ b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/TripDistributionMatrix.java @@ -289,18 +289,18 @@ private TripDistributionMatrix(Builder builder) { * @param modeORvehType selected mode or vehicle type * @param purpose selected purpose * @param smallScaleCommercialTrafficType goodsTraffic or commercialPersonTraffic - * @param regionLinksMap links in each zone - * @param shapeFileZoneNameColumn Name of the unique column of the name/Id of each zone in the zones shape file + * @param linksPerZone links in each zone + * @param shapeFileZoneNameColumn Name of the unique column of the name/Id of each zone in the zones shape file */ void setTripDistributionValue(String startZone, String stopZone, String modeORvehType, Integer purpose, String smallScaleCommercialTrafficType, Network network, - Map, Link>> regionLinksMap, double resistanceFactor, String shapeFileZoneNameColumn) { + Map, Link>> linksPerZone, double resistanceFactor, String shapeFileZoneNameColumn) { double volumeStart = trafficVolume_start.get(TrafficVolumeGeneration.makeTrafficVolumeKey(startZone, modeORvehType)).getDouble(purpose); double volumeStop = trafficVolume_stop.get(TrafficVolumeGeneration.makeTrafficVolumeKey(stopZone, modeORvehType)).getDouble(purpose); int roundedVolume; if (volumeStart != 0 && volumeStop != 0) { - double resistanceValue = getResistanceFunktionValue(startZone, stopZone, network, regionLinksMap, resistanceFactor, shapeFileZoneNameColumn); - double gravityConstantA = getGravityConstant(stopZone, trafficVolume_start, modeORvehType, purpose, network, regionLinksMap, + double resistanceValue = getResistanceFunktionValue(startZone, stopZone, network, linksPerZone, resistanceFactor, shapeFileZoneNameColumn); + double gravityConstantA = getGravityConstant(stopZone, trafficVolume_start, modeORvehType, purpose, network, linksPerZone, resistanceFactor, shapeFileZoneNameColumn); roundingError.computeIfAbsent(stopZone, (k) -> new Object2DoubleOpenHashMap<>()); @@ -339,10 +339,10 @@ Integer getTripDistributionValue(String startZone, String stopZone, String modeO * * @param startZone start zone * @param stopZone stop zone - * @param regionLinksMap links for each zone + * @param linksPerZone links for each zone * @param shapeFileZoneNameColumn Name of the unique column of the name/Id of each zone in the zones shape file */ - private Double getResistanceFunktionValue(String startZone, String stopZone, Network network, Map, Link>> regionLinksMap, + private Double getResistanceFunktionValue(String startZone, String stopZone, Network network, Map, Link>> linksPerZone, double resistanceFactor, String shapeFileZoneNameColumn) { //if false the calculation is faster; e.g. for debugging @@ -371,8 +371,8 @@ private Double getResistanceFunktionValue(String startZone, String stopZone, Net } else { if (useNetworkRoutesForResistanceFunction) { - Location startLocation = Location.newInstance(regionLinksMap.get(startZone).keySet().iterator().next().toString()); - Location stopLocation = Location.newInstance(regionLinksMap.get(stopZone).keySet().iterator().next().toString()); + Location startLocation = Location.newInstance(linksPerZone.get(startZone).keySet().iterator().next().toString()); + Location stopLocation = Location.newInstance(linksPerZone.get(stopZone).keySet().iterator().next().toString()); Vehicle exampleVehicle = getExampleVehicle(startLocation); // distance = netBasedCosts.getDistance(startLocation, stopLocation, 21600., exampleVehicle); travelCosts = netBasedCosts.getTransportCost(startLocation, stopLocation, 21600., null, exampleVehicle); @@ -450,13 +450,13 @@ private VehicleImpl getExampleVehicle(Location fromId) { * @param trafficVolume volume of the traffic * @param modeORvehType selected mode or vehicle type * @param purpose selected purpose - * @param regionLinksMap links for each zone + * @param linksPerZone links for each zone * @param shapeFileZoneNameColumn Name of the unique column of the name/Id of each zone in the zones shape file * @return gravity constant */ private double getGravityConstant(String baseZone, Map> trafficVolume, String modeORvehType, - Integer purpose, Network network, Map, Link>> regionLinksMap, double resistanceFactor, String shapeFileZoneNameColumn) { + Integer purpose, Network network, Map, Link>> linksPerZone, double resistanceFactor, String shapeFileZoneNameColumn) { GravityConstantKey gravityKey = makeGravityKey(baseZone, modeORvehType, purpose); if (!gravityConstantACache.containsKey(gravityKey)) { @@ -468,7 +468,7 @@ private double getGravityConstant(String baseZone, continue; else { double resistanceValue = getResistanceFunktionValue(baseZone, trafficVolumeKey.getZone(), network, - regionLinksMap, resistanceFactor, shapeFileZoneNameColumn); + linksPerZone, resistanceFactor, shapeFileZoneNameColumn); sum = sum + (volume * resistanceValue); } } From 2cf9f4cb7f7eef5ba1cd81ed68f2812e6af1c271 Mon Sep 17 00:00:00 2001 From: Ricardo Ewert Date: Tue, 27 Feb 2024 16:06:18 +0100 Subject: [PATCH 09/12] add comment --- .../GenerateSmallScaleCommercialTrafficDemand.java | 2 +- .../SmallScaleCommercialTrafficUtils.java | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java index 15455c08a70..7ffec55f486 100644 --- a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java +++ b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java @@ -36,7 +36,6 @@ import org.matsim.api.core.v01.population.Activity; import org.matsim.api.core.v01.population.Leg; import org.matsim.application.MATSimAppCommand; -import org.matsim.application.options.ShpOptions; import org.matsim.application.options.ShpOptions.Index; import org.matsim.core.config.consistency.UnmaterializedConfigGroupChecker; import org.matsim.core.gbl.MatsimRandom; @@ -101,6 +100,7 @@ public class GenerateSmallScaleCommercialTrafficDemand implements MATSimAppComma // Option 3: Leerkamp (nur in RVR Modell). + // Option: Add prepare class with OSM Analyse and create facility file with results private static final Logger log = LogManager.getLogger(GenerateSmallScaleCommercialTrafficDemand.class); private enum CreationOption { diff --git a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/SmallScaleCommercialTrafficUtils.java b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/SmallScaleCommercialTrafficUtils.java index 1b43d411522..0b355bdc7c5 100644 --- a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/SmallScaleCommercialTrafficUtils.java +++ b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/SmallScaleCommercialTrafficUtils.java @@ -135,6 +135,15 @@ static void writeResultOfDataDistribution(Map> log.info("The data distribution is finished and written to: " + outputFileInOutputFolder); } + /** Finds the nearest possible link for the building polygon. + * @param zone + * @param noPossibleLinks + * @param linksPerZone + * @param newLink + * @param centroidPointOfBuildingPolygon + * @param numberOfPossibleLinks + * @return + */ static Id findNearestPossibleLink(String zone, List noPossibleLinks, Map, Link>> linksPerZone, Id newLink, Coord centroidPointOfBuildingPolygon, int numberOfPossibleLinks) { double minDistance = Double.MAX_VALUE; @@ -206,7 +215,6 @@ private static void writeCSVWithCategoryHeader(Map Date: Tue, 19 Mar 2024 16:27:01 +0100 Subject: [PATCH 10/12] add input parameter for selecting needed column names of input shapes --- ...rateSmallScaleCommercialTrafficDemand.java | 29 +++++++++------- .../SmallScaleCommercialTrafficUtils.java | 34 +++++++++++++------ ...nerateSmallScaleCommercialTrafficTest.java | 4 +++ 3 files changed, 44 insertions(+), 23 deletions(-) diff --git a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java index 7ffec55f486..1a2191b1542 100644 --- a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java +++ b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java @@ -37,23 +37,16 @@ import org.matsim.api.core.v01.population.Leg; import org.matsim.application.MATSimAppCommand; import org.matsim.application.options.ShpOptions.Index; -import org.matsim.core.config.consistency.UnmaterializedConfigGroupChecker; -import org.matsim.core.gbl.MatsimRandom; -import org.matsim.core.scenario.ProjectionUtils; -import org.matsim.core.utils.geometry.CoordUtils; -import org.matsim.core.utils.geometry.CoordinateTransformation; -import org.matsim.freight.carriers.*; -import org.matsim.freight.carriers.controler.*; -import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; -import org.matsim.freight.carriers.usecases.chessboard.CarrierTravelDisutilities; import org.matsim.core.config.Config; import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.consistency.UnmaterializedConfigGroupChecker; import org.matsim.core.config.groups.ControllerConfigGroup; 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.gbl.Gbl; +import org.matsim.core.gbl.MatsimRandom; import org.matsim.core.network.NetworkUtils; import org.matsim.core.population.routes.NetworkRoute; import org.matsim.core.replanning.GenericPlanStrategyImpl; @@ -63,10 +56,17 @@ import org.matsim.core.router.util.LeastCostPathCalculatorFactory; import org.matsim.core.router.util.TravelDisutility; import org.matsim.core.router.util.TravelTime; +import org.matsim.core.scenario.ProjectionUtils; import org.matsim.core.scenario.ScenarioUtils; import org.matsim.core.scoring.ScoringFunction; import org.matsim.core.scoring.SumScoringFunction; +import org.matsim.core.utils.geometry.CoordUtils; +import org.matsim.core.utils.geometry.CoordinateTransformation; import org.matsim.core.utils.geometry.geotools.MGC; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.carriers.controler.*; +import org.matsim.freight.carriers.usecases.chessboard.CarrierTravelDisutilities; import org.matsim.vehicles.CostInformation; import org.matsim.vehicles.Vehicle; import org.matsim.vehicles.VehicleType; @@ -76,7 +76,6 @@ import java.io.File; import java.net.URISyntaxException; -import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.*; @@ -151,9 +150,15 @@ private enum SmallScaleCommercialTrafficType { @CommandLine.Option(names = "--buildingsShapeFileName", description = "Path of the buildings shape file") private Path shapeFileBuildingsPath; + @CommandLine.Option(names = "--shapeFileBuildingTypeColumn", description = "Name of the unique column of the building type in the buildings shape file.") + private String shapeFileBuildingTypeColumn; + @CommandLine.Option(names = "--landuseShapeFileName", description = "Path of the landuse shape file") private Path shapeFileLandusePath; + @CommandLine.Option(names = "--shapeFileLanduseTypeColumn", description = "Name of the unique column of the landuse type in the landuse shape file.") + private String shapeFileLanduseTypeColumn; + @CommandLine.Option(names = "--shapeCRS", description = "CRS of the three input shape files (zones, landuse, buildings") private String shapeCRS; @@ -242,8 +247,8 @@ public Integer call() throws Exception { Path inputDataDirectory = Path.of(config.getContext().toURI()).getParent(); indexZones = SmallScaleCommercialTrafficUtils.getIndexZones(shapeFileZonePath, shapeCRS, shapeFileZoneNameColumn); - indexBuildings = SmallScaleCommercialTrafficUtils.getIndexBuildings(shapeFileBuildingsPath, shapeCRS); - indexLanduse = SmallScaleCommercialTrafficUtils.getIndexLanduse(shapeFileLandusePath, shapeCRS); + indexBuildings = SmallScaleCommercialTrafficUtils.getIndexBuildings(shapeFileBuildingsPath, shapeCRS, shapeFileBuildingTypeColumn); + indexLanduse = SmallScaleCommercialTrafficUtils.getIndexLanduse(shapeFileLandusePath, shapeCRS, shapeFileLanduseTypeColumn); indexInvestigationAreaRegions = SmallScaleCommercialTrafficUtils.getIndexRegions(shapeFileRegionsPath, shapeCRS, regionsShapeRegionColumn); Map> resultingDataPerZone = LanduseBuildingAnalysis diff --git a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/SmallScaleCommercialTrafficUtils.java b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/SmallScaleCommercialTrafficUtils.java index 0b355bdc7c5..f00dcd020e5 100644 --- a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/SmallScaleCommercialTrafficUtils.java +++ b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/SmallScaleCommercialTrafficUtils.java @@ -85,32 +85,42 @@ public class SmallScaleCommercialTrafficUtils { static Index getIndexZones(Path shapeFileZonePath, String shapeCRS, String shapeFileZoneNameColumn) { ShpOptions shpZones = new ShpOptions(shapeFileZonePath, shapeCRS, StandardCharsets.UTF_8); + if (shpZones.readFeatures().iterator().next().getAttribute(shapeFileZoneNameColumn) == null) + throw new NullPointerException("The column '" + shapeFileZoneNameColumn + "' does not exist in the zones shape file. Please check the input."); return shpZones.createIndex(shapeCRS, shapeFileZoneNameColumn); } /** * Creates and return the Index of the landuse shape. * - * @return indexLanduse + * @param shapeFileLandusePath Path to the shape file of the landuse + * @param shapeCRS CRS of the shape file + * @param shapeFileLanduseTypeColumn Column name of the landuse in the shape file + * @return indexLanduse */ - static Index getIndexLanduse(Path shapeFileLandusePath, String shapeCRS) { - + static Index getIndexLanduse(Path shapeFileLandusePath, String shapeCRS, String shapeFileLanduseTypeColumn) { ShpOptions shpLanduse = new ShpOptions(shapeFileLandusePath, shapeCRS, StandardCharsets.UTF_8); - return shpLanduse.createIndex(shapeCRS, "fclass"); + if (shpLanduse.readFeatures().iterator().next().getAttribute(shapeFileLanduseTypeColumn) == null) + throw new NullPointerException("The column '" + shapeFileLanduseTypeColumn + "' does not exist in the landuse shape file. Please check the input."); + return shpLanduse.createIndex(shapeCRS, shapeFileLanduseTypeColumn); } /** * Creates and return the Index of the building shape. * - * @return indexBuildings + * @param shapeFileBuildingsPath Path to the shape file of the buildings + * @param shapeCRS CRS of the shape file + * @param shapeFileBuildingTypeColumn Column name of the building in the shape file + * @return indexBuildings */ - static Index getIndexBuildings(Path shapeFileBuildingsPath, String shapeCRS) { + static Index getIndexBuildings(Path shapeFileBuildingsPath, String shapeCRS, String shapeFileBuildingTypeColumn) { + ShpOptions shpBuildings = new ShpOptions(shapeFileBuildingsPath, shapeCRS, StandardCharsets.UTF_8); + if (shpBuildings.readFeatures().iterator().next().getAttribute(shapeFileBuildingTypeColumn) == null) + throw new NullPointerException("The column '" + shapeFileBuildingTypeColumn + "' does not exist in the building shape file. Please check the input."); - ShpOptions shpLanduse = new ShpOptions(shapeFileBuildingsPath, shapeCRS, StandardCharsets.UTF_8); - return shpLanduse.createIndex(shapeCRS, "type"); + return shpBuildings.createIndex(shapeCRS, shapeFileBuildingTypeColumn); } - /** * Creates and return the Index of the regions shape. * @@ -120,8 +130,10 @@ static Index getIndexBuildings(Path shapeFileBuildingsPath, String shapeCRS) { * @return indexRegions */ public static Index getIndexRegions(Path shapeFileRegionsPath, String shapeCRS, String regionsShapeRegionColumn) { - ShpOptions shpLanduse = new ShpOptions(shapeFileRegionsPath, shapeCRS, StandardCharsets.UTF_8); - return shpLanduse.createIndex(shapeCRS, regionsShapeRegionColumn); + ShpOptions shpRegions = new ShpOptions(shapeFileRegionsPath, shapeCRS, StandardCharsets.UTF_8); + if (shpRegions.readFeatures().iterator().next().getAttribute(regionsShapeRegionColumn) == null) + throw new NullPointerException("The column '" + regionsShapeRegionColumn + "' does not exist in the region shape file. Please check the input."); + return shpRegions.createIndex(shapeCRS, regionsShapeRegionColumn); } /** diff --git a/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/RunGenerateSmallScaleCommercialTrafficTest.java b/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/RunGenerateSmallScaleCommercialTrafficTest.java index f23d6c57ad7..a521917e8de 100644 --- a/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/RunGenerateSmallScaleCommercialTrafficTest.java +++ b/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/RunGenerateSmallScaleCommercialTrafficTest.java @@ -72,7 +72,9 @@ void testMainRunAndResults() { String zoneShapeFileName = utils.getPackageInputDirectory() + "/shp/testZones.shp"; String zoneShapeFileNameColumn = "name"; String buildingsShapeFileName = utils.getPackageInputDirectory() + "/shp/testBuildings.shp"; + String shapeFileBuildingTypeColumn = "type"; String landuseShapeFileName = utils.getPackageInputDirectory() + "/shp/testLanduse.shp"; + String shapeFileLanduseTypeColumn = "fclass"; String shapeCRS = "EPSG:4326"; String resultPopulation = "testPopulation.xml.gz"; @@ -89,7 +91,9 @@ void testMainRunAndResults() { "--zoneShapeFileName", zoneShapeFileName, "--zoneShapeFileNameColumn", zoneShapeFileNameColumn, "--buildingsShapeFileName", buildingsShapeFileName, + "--shapeFileBuildingTypeColumn", shapeFileBuildingTypeColumn, "--landuseShapeFileName", landuseShapeFileName, + "--shapeFileLanduseTypeColumn", shapeFileLanduseTypeColumn, "--shapeCRS", shapeCRS, "--nameOutputPopulation", resultPopulation, "--pathOutput", output); From cf1ae7bfa6060acdd9bf48e66e5100b626e148e4 Mon Sep 17 00:00:00 2001 From: Ricardo Ewert Date: Tue, 19 Mar 2024 22:45:58 +0100 Subject: [PATCH 11/12] add comment --- .../LanduseBuildingAnalysis.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/LanduseBuildingAnalysis.java b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/LanduseBuildingAnalysis.java index 4104b09983a..b0af262a7b8 100644 --- a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/LanduseBuildingAnalysis.java +++ b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/LanduseBuildingAnalysis.java @@ -227,9 +227,8 @@ private static void createLanduseDistribution(Map landuseFeatures = indexLanduse.getAllFeatures(); List zonesFeatures = indexZones.getAllFeatures(); - for (SimpleFeature singleZone : zonesFeatures) { - // TODO comment + // get the region of the zone Coord middleCoordOfZone = MGC.point2Coord(((Geometry) singleZone.getDefaultGeometry()).getCentroid()); String regionName = indexInvestigationAreaRegions.query(middleCoordOfZone); if (regionName != null) { From 4616b1ea68870e2cec4f5fa5e9c6ce7b185c5257 Mon Sep 17 00:00:00 2001 From: Ricardo Ewert Date: Wed, 20 Mar 2024 09:34:06 +0100 Subject: [PATCH 12/12] make the path of input data configurable --- ...rateSmallScaleCommercialTrafficDemand.java | 12 +++++-- .../LanduseBuildingAnalysis.java | 31 ++++++++++--------- .../LanduseBuildingAnalysisTest.java | 14 +++++---- ...nerateSmallScaleCommercialTrafficTest.java | 9 ++++-- .../TrafficVolumeGenerationTest.java | 24 +++++++++----- .../TripDistributionMatrixTest.java | 12 ++++--- 6 files changed, 64 insertions(+), 38 deletions(-) diff --git a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java index 1a2191b1542..e5b6a27b774 100644 --- a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java +++ b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java @@ -117,6 +117,12 @@ private enum SmallScaleCommercialTrafficType { @CommandLine.Parameters(arity = "1", paramLabel = "INPUT", description = "Path to the config for small scale commercial generation") private Path configPath; + @CommandLine.Option(names = "--pathToInvestigationAreaData", description = "Path to the investigation area data") + private Path pathToInvestigationAreaData; + + @CommandLine.Option(names = "--pathToExistingDataDistributionToZones", description = "Path to the existing data distribution to zones. This is only needed if the option useExistingDataDistribution is selected.") + private Path pathToExistingDataDistributionToZones; + @CommandLine.Option(names = "--sample", description = "Scaling factor of the small scale commercial traffic (0, 1)", required = true) private double sample; @@ -244,7 +250,6 @@ public Integer call() throws Exception { if (!Files.exists(shapeFileRegionsPath)) { throw new Exception("Required regions shape file {} not found" + shapeFileRegionsPath.toString()); } - Path inputDataDirectory = Path.of(config.getContext().toURI()).getParent(); indexZones = SmallScaleCommercialTrafficUtils.getIndexZones(shapeFileZonePath, shapeCRS, shapeFileZoneNameColumn); indexBuildings = SmallScaleCommercialTrafficUtils.getIndexBuildings(shapeFileBuildingsPath, shapeCRS, shapeFileBuildingTypeColumn); @@ -252,9 +257,10 @@ public Integer call() throws Exception { indexInvestigationAreaRegions = SmallScaleCommercialTrafficUtils.getIndexRegions(shapeFileRegionsPath, shapeCRS, regionsShapeRegionColumn); Map> resultingDataPerZone = LanduseBuildingAnalysis - .createInputDataDistribution(output, landuseCategoriesAndDataConnection, inputDataDirectory, + .createInputDataDistribution(output, landuseCategoriesAndDataConnection, usedLanduseConfiguration.toString(), indexLanduse, indexZones, - indexBuildings, indexInvestigationAreaRegions, shapeFileZoneNameColumn, buildingsPerZone); + indexBuildings, indexInvestigationAreaRegions, shapeFileZoneNameColumn, buildingsPerZone, pathToInvestigationAreaData, + pathToExistingDataDistributionToZones); Map, Link>> linksPerZone = filterLinksForZones(scenario, indexZones, buildingsPerZone); switch (usedSmallScaleCommercialTrafficType) { diff --git a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/LanduseBuildingAnalysis.java b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/LanduseBuildingAnalysis.java index b0af262a7b8..7e26668438e 100644 --- a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/LanduseBuildingAnalysis.java +++ b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/LanduseBuildingAnalysis.java @@ -54,11 +54,14 @@ public class LanduseBuildingAnalysis { * used OSM data. */ static Map> createInputDataDistribution(Path output, - Map> landuseCategoriesAndDataConnection, Path inputDataDirectory, + Map> landuseCategoriesAndDataConnection, String usedLanduseConfiguration, Index indexLanduse, Index indexZones, Index indexBuildings, Index indexInvestigationAreaRegions, - String shapeFileZoneNameColumn, Map>> buildingsPerZone) - throws IOException { + String shapeFileZoneNameColumn, + Map>> buildingsPerZone, + Path pathToInvestigationAreaData, + Path pathToExistingDataDistributionToZones) + throws IOException { Map> resultingDataPerZone = new HashMap<>(); Map zoneIdRegionConnection = new HashMap<>(); @@ -81,13 +84,12 @@ static Map> createInputDataDistribution(Path ou Arrays.asList("commercial", "embassy", "foundation", "government", "office", "townhall"))); if (usedLanduseConfiguration.equals("useExistingDataDistribution")) { - Path existingDataDistribution = inputDataDirectory.resolve("dataDistributionPerZone.csv"); - if (!Files.exists(existingDataDistribution)) { - log.error("Required data per zone file {} not found", existingDataDistribution); + if (!Files.exists(pathToExistingDataDistributionToZones)) { + log.error("Required data per zone file {} not found", pathToExistingDataDistributionToZones); } - try (BufferedReader reader = IOUtils.getBufferedReader(existingDataDistribution.toString())) { + try (BufferedReader reader = IOUtils.getBufferedReader(pathToExistingDataDistributionToZones.toString())) { CSVParser parse = CSVFormat.Builder.create(CSVFormat.DEFAULT).setDelimiter('\t').setHeader() .setSkipHeaderRecord(true).build().parse(reader); @@ -101,8 +103,8 @@ static Map> createInputDataDistribution(Path ou } } log.info("Data distribution for " + resultingDataPerZone.size() + " zones was imported from " + - existingDataDistribution); - Files.copy(existingDataDistribution, outputFileInOutputFolder, StandardCopyOption.COPY_ATTRIBUTES); + pathToExistingDataDistributionToZones); + Files.copy(pathToExistingDataDistributionToZones, outputFileInOutputFolder, StandardCopyOption.COPY_ATTRIBUTES); } else { @@ -115,7 +117,7 @@ static Map> createInputDataDistribution(Path ou buildingsPerZone, shapeFileZoneNameColumn, zoneIdRegionConnection); Map> investigationAreaData = new HashMap<>(); - readAreaData(investigationAreaData, inputDataDirectory); + readAreaData(investigationAreaData, pathToInvestigationAreaData); createResultingDataForLanduseInZones(landuseCategoriesPerZone, investigationAreaData, resultingDataPerZone, landuseCategoriesAndDataConnection, zoneIdRegionConnection); @@ -287,14 +289,13 @@ private static void createLanduseDistribution(Map> areaData, Path inputDataDirectory) + private static void readAreaData(Map> areaData, Path pathToInvestigationAreaData) throws IOException { - Path areaDataPath = inputDataDirectory.resolve("investigationAreaData.csv"); - if (!Files.exists(areaDataPath)) { - log.error("Required input data file {} not found", areaDataPath); + if (!Files.exists(pathToInvestigationAreaData)) { + log.error("Required input data file {} not found", pathToInvestigationAreaData); } - try (CSVParser parser = new CSVParser(Files.newBufferedReader(areaDataPath), + try (CSVParser parser = new CSVParser(Files.newBufferedReader(pathToInvestigationAreaData), CSVFormat.Builder.create(CSVFormat.TDF).setHeader().setSkipHeaderRecord(true).build())) { for (CSVRecord record : parser) { diff --git a/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/LanduseBuildingAnalysisTest.java b/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/LanduseBuildingAnalysisTest.java index 7762b156cc5..fa640744c92 100644 --- a/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/LanduseBuildingAnalysisTest.java +++ b/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/LanduseBuildingAnalysisTest.java @@ -52,13 +52,15 @@ void testReadOfDataDistributionPerZoneAndBuildingAnalysis() throws IOException { Path inputDataDirectory = Path.of(utils.getPackageInputDirectory()); String usedLanduseConfiguration = "useExistingDataDistribution"; String shapeFileZoneNameColumn = "name"; - + Path pathToInvestigationAreaData = Path.of(utils.getPackageInputDirectory()).resolve("investigationAreaData.csv"); + Path pathToExistingDataDistributionToZones = Path.of(utils.getPackageInputDirectory()).resolve("dataDistributionPerZone.csv"); // Test if the reading of the existing data distribution works correctly + Map> resultingDataPerZone = LanduseBuildingAnalysis .createInputDataDistribution(output, landuseCategoriesAndDataConnection, - inputDataDirectory, usedLanduseConfiguration, + usedLanduseConfiguration, SCTUtils.getIndexLanduse(inputDataDirectory), SCTUtils.getZoneIndex(inputDataDirectory), SCTUtils.getIndexBuildings(inputDataDirectory), - SCTUtils.getIndexRegions(inputDataDirectory), shapeFileZoneNameColumn, buildingsPerZone); + SCTUtils.getIndexRegions(inputDataDirectory), shapeFileZoneNameColumn, buildingsPerZone, pathToInvestigationAreaData, pathToExistingDataDistributionToZones); Assertions.assertEquals(3, resultingDataPerZone.size(), MatsimTestUtils.EPSILON); @@ -245,13 +247,13 @@ void testLanduseDistribution() throws IOException { Path inputDataDirectory = Path.of(utils.getPackageInputDirectory()); String usedLanduseConfiguration = "useOSMBuildingsAndLanduse"; String shapeFileZoneNameColumn = "name"; - + Path pathToInvestigationAreaData = Path.of(utils.getPackageInputDirectory()).resolve("investigationAreaData.csv"); // Analyze resultingData per zone Map> resultingDataPerZone = LanduseBuildingAnalysis .createInputDataDistribution(output, landuseCategoriesAndDataConnection, - inputDataDirectory, usedLanduseConfiguration, + usedLanduseConfiguration, SCTUtils.getIndexLanduse(inputDataDirectory), SCTUtils.getZoneIndex(inputDataDirectory), SCTUtils.getIndexBuildings(inputDataDirectory), - SCTUtils.getIndexRegions(inputDataDirectory), shapeFileZoneNameColumn, buildingsPerZone); + SCTUtils.getIndexRegions(inputDataDirectory), shapeFileZoneNameColumn, buildingsPerZone, pathToInvestigationAreaData, null); Assertions.assertEquals(3, resultingDataPerZone.size(), MatsimTestUtils.EPSILON); diff --git a/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/RunGenerateSmallScaleCommercialTrafficTest.java b/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/RunGenerateSmallScaleCommercialTrafficTest.java index a521917e8de..c664ba46440 100644 --- a/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/RunGenerateSmallScaleCommercialTrafficTest.java +++ b/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/RunGenerateSmallScaleCommercialTrafficTest.java @@ -45,6 +45,7 @@ import java.io.BufferedReader; import java.io.File; import java.io.IOException; +import java.nio.file.Path; import java.util.HashMap; import java.util.Map; import java.util.Objects; @@ -60,7 +61,9 @@ public class RunGenerateSmallScaleCommercialTrafficTest { @Test void testMainRunAndResults() { - String inputDataDirectory = utils.getPackageInputDirectory() + "config_demand.xml"; + String pathToConfig = utils.getPackageInputDirectory() + "config_demand.xml"; + Path pathToInvestigationAreaData = Path.of(utils.getPackageInputDirectory()).resolve("investigationAreaData.csv"); + Path pathToExistingDataDistributionToZones = Path.of(utils.getPackageInputDirectory()).resolve("dataDistributionPerZone.csv"); String output = utils.getOutputDirectory(); String sample = "0.1"; String jspritIterations = "2"; @@ -79,7 +82,9 @@ void testMainRunAndResults() { String resultPopulation = "testPopulation.xml.gz"; new GenerateSmallScaleCommercialTrafficDemand().execute( - inputDataDirectory, + pathToConfig, + "--pathToInvestigationAreaData", pathToInvestigationAreaData.toString(), + "--pathToExistingDataDistributionToZones", pathToExistingDataDistributionToZones.toString(), "--sample", sample, "--jspritIterations", jspritIterations, "--creationOption", creationOption, diff --git a/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/TrafficVolumeGenerationTest.java b/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/TrafficVolumeGenerationTest.java index cfac585157a..b680e568ffb 100644 --- a/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/TrafficVolumeGenerationTest.java +++ b/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/TrafficVolumeGenerationTest.java @@ -61,12 +61,14 @@ void testTrafficVolumeGenerationCommercialPersonTraffic() throws IOException { Path inputDataDirectory = Path.of(utils.getPackageInputDirectory()); String usedLanduseConfiguration = "useExistingDataDistribution"; String shapeFileZoneNameColumn = "name"; + Path pathToInvestigationAreaData = Path.of(utils.getPackageInputDirectory()).resolve("investigationAreaData.csv"); + Path pathToExistingDataDistributionToZones = Path.of(utils.getPackageInputDirectory()).resolve("dataDistributionPerZone.csv"); Map> resultingDataPerZone = LanduseBuildingAnalysis .createInputDataDistribution(output, landuseCategoriesAndDataConnection, - inputDataDirectory, usedLanduseConfiguration, + usedLanduseConfiguration, SCTUtils.getIndexLanduse(inputDataDirectory), SCTUtils.getZoneIndex(inputDataDirectory), SCTUtils.getIndexBuildings(inputDataDirectory), - SCTUtils.getIndexRegions(inputDataDirectory), shapeFileZoneNameColumn, buildingsPerZone); + SCTUtils.getIndexRegions(inputDataDirectory), shapeFileZoneNameColumn, buildingsPerZone, pathToInvestigationAreaData, pathToExistingDataDistributionToZones); String usedTrafficType = "commercialPersonTraffic"; @@ -189,12 +191,14 @@ void testTrafficVolumeGenerationGoodsTraffic() throws IOException { Path inputDataDirectory = Path.of(utils.getPackageInputDirectory()); String usedLanduseConfiguration = "useExistingDataDistribution"; String shapeFileZoneNameColumn = "name"; + Path pathToInvestigationAreaData = Path.of(utils.getPackageInputDirectory()).resolve("investigationAreaData.csv"); + Path pathToExistingDataDistributionToZones = Path.of(utils.getPackageInputDirectory()).resolve("dataDistributionPerZone.csv"); Map> resultingDataPerZone = LanduseBuildingAnalysis .createInputDataDistribution(output, landuseCategoriesAndDataConnection, - inputDataDirectory, usedLanduseConfiguration, + usedLanduseConfiguration, SCTUtils.getIndexLanduse(inputDataDirectory), SCTUtils.getZoneIndex(inputDataDirectory), SCTUtils.getIndexBuildings(inputDataDirectory), - SCTUtils.getIndexRegions(inputDataDirectory), shapeFileZoneNameColumn, buildingsPerZone); + SCTUtils.getIndexRegions(inputDataDirectory), shapeFileZoneNameColumn, buildingsPerZone, pathToInvestigationAreaData, pathToExistingDataDistributionToZones); String usedTrafficType = "goodsTraffic"; double sample = 1.; @@ -512,6 +516,8 @@ void testReducingDemandAfterAddingExistingScenarios_goods() throws Exception { String usedTrafficType = "goodsTraffic"; double sample = 1.; String shapeFileZoneNameColumn = "name"; + Path pathToInvestigationAreaData = Path.of(utils.getPackageInputDirectory()).resolve("investigationAreaData.csv"); + Path pathToExistingDataDistributionToZones = Path.of(utils.getPackageInputDirectory()).resolve("dataDistributionPerZone.csv"); ArrayList modesORvehTypes = new ArrayList<>( Arrays.asList("vehTyp1", "vehTyp2", "vehTyp3", "vehTyp4", "vehTyp5")); @@ -525,9 +531,9 @@ void testReducingDemandAfterAddingExistingScenarios_goods() throws Exception { Map> resultingDataPerZone = LanduseBuildingAnalysis .createInputDataDistribution(output, landuseCategoriesAndDataConnection, - inputDataDirectory, usedLanduseConfiguration, + usedLanduseConfiguration, SCTUtils.getIndexLanduse(inputDataDirectory), SCTUtils.getZoneIndex(inputDataDirectory), SCTUtils.getIndexBuildings(inputDataDirectory), - SCTUtils.getIndexRegions(inputDataDirectory), shapeFileZoneNameColumn, buildingsPerZone); + SCTUtils.getIndexRegions(inputDataDirectory), shapeFileZoneNameColumn, buildingsPerZone, pathToInvestigationAreaData, pathToExistingDataDistributionToZones); Map> trafficVolumePerTypeAndZone_start = TrafficVolumeGeneration .createTrafficVolume_start(resultingDataPerZone, output, sample, modesORvehTypes, usedTrafficType); @@ -670,6 +676,8 @@ void testReducingDemandAfterAddingExistingScenarios_commercialPersonTraffic() th String usedTrafficType = "commercialPersonTraffic"; double sample = 1.; String shapeFileZoneNameColumn = "name"; + Path pathToInvestigationAreaData = Path.of(utils.getPackageInputDirectory()).resolve("investigationAreaData.csv"); + Path pathToExistingDataDistributionToZones = Path.of(utils.getPackageInputDirectory()).resolve("dataDistributionPerZone.csv"); ArrayList modesORvehTypes = new ArrayList<>( List.of("total")); @@ -683,9 +691,9 @@ void testReducingDemandAfterAddingExistingScenarios_commercialPersonTraffic() th Map> resultingDataPerZone = LanduseBuildingAnalysis .createInputDataDistribution(output, landuseCategoriesAndDataConnection, - inputDataDirectory, usedLanduseConfiguration, + usedLanduseConfiguration, SCTUtils.getIndexLanduse(inputDataDirectory), SCTUtils.getZoneIndex(inputDataDirectory), SCTUtils.getIndexBuildings(inputDataDirectory), - SCTUtils.getIndexRegions(inputDataDirectory), shapeFileZoneNameColumn, buildingsPerZone); + SCTUtils.getIndexRegions(inputDataDirectory), shapeFileZoneNameColumn, buildingsPerZone, pathToInvestigationAreaData, pathToExistingDataDistributionToZones); Map> trafficVolumePerTypeAndZone_start = TrafficVolumeGeneration .createTrafficVolume_start(resultingDataPerZone, output, sample, modesORvehTypes, usedTrafficType); diff --git a/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/TripDistributionMatrixTest.java b/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/TripDistributionMatrixTest.java index 76f6c0b6cd8..7190ba7350d 100644 --- a/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/TripDistributionMatrixTest.java +++ b/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/TripDistributionMatrixTest.java @@ -60,12 +60,14 @@ void testTripDistributionCommercialPersonTrafficTraffic() throws IOException { String networkLocation = "https://raw.githubusercontent.com/matsim-org/matsim-libs/master/examples/scenarios/freight-chessboard-9x9/grid9x9.xml"; Network network = NetworkUtils.readNetwork(networkLocation); String shapeFileZoneNameColumn = "name"; + Path pathToInvestigationAreaData = Path.of(utils.getPackageInputDirectory()).resolve("investigationAreaData.csv"); + Path pathToExistingDataDistributionToZones = Path.of(utils.getPackageInputDirectory()).resolve("dataDistributionPerZone.csv"); Map> resultingDataPerZone = LanduseBuildingAnalysis .createInputDataDistribution(output, landuseCategoriesAndDataConnection, - inputDataDirectory, usedLanduseConfiguration, + usedLanduseConfiguration, getIndexLanduse(inputDataDirectory), getZoneIndex(inputDataDirectory), getIndexBuildings(inputDataDirectory), - SCTUtils.getIndexRegions(inputDataDirectory), shapeFileZoneNameColumn, buildingsPerZone); + SCTUtils.getIndexRegions(inputDataDirectory), shapeFileZoneNameColumn, buildingsPerZone, pathToInvestigationAreaData, pathToExistingDataDistributionToZones); String usedTrafficType = "commercialPersonTraffic"; double sample = 1.; @@ -150,11 +152,13 @@ void testTripDistributionGoodsTraffic() throws IOException { String networkLocation = "https://raw.githubusercontent.com/matsim-org/matsim-libs/master/examples/scenarios/freight-chessboard-9x9/grid9x9.xml"; Network network = NetworkUtils.readNetwork(networkLocation); String shapeFileZoneNameColumn = "name"; + Path pathToInvestigationAreaData = Path.of(utils.getPackageInputDirectory()).resolve("investigationAreaData.csv"); + Path pathToExistingDataDistributionToZones = Path.of(utils.getPackageInputDirectory()).resolve("dataDistributionPerZone.csv"); Map> resultingDataPerZone = LanduseBuildingAnalysis .createInputDataDistribution(output, landuseCategoriesAndDataConnection, - inputDataDirectory, usedLanduseConfiguration, + usedLanduseConfiguration, getIndexLanduse(inputDataDirectory), getZoneIndex(inputDataDirectory), getIndexBuildings(inputDataDirectory), - SCTUtils.getIndexRegions(inputDataDirectory), shapeFileZoneNameColumn, buildingsPerZone); + SCTUtils.getIndexRegions(inputDataDirectory), shapeFileZoneNameColumn, buildingsPerZone, pathToInvestigationAreaData, pathToExistingDataDistributionToZones); String usedTrafficType = "goodsTraffic"; double sample = 1.;