Skip to content

Commit

Permalink
Merge pull request #3218 from matsim-org/createInterfaceForDifferentL…
Browse files Browse the repository at this point in the history
…anduseDataTypes_KWM

Create interface for different landuse/building input data types for small-scale commercial traffic
  • Loading branch information
rewertvsp authored Apr 17, 2024
2 parents 492985d + b4ecf02 commit 7bc9c2c
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ public class CreateDataDistributionOfStructureData implements MATSimAppCommand {

private static final Logger log = LogManager.getLogger(CreateDataDistributionOfStructureData.class);

private static LanduseDataConnectionCreator landuseDataConnectionCreator;

private enum LanduseConfiguration {
useOnlyOSMLanduse, useOSMBuildingsAndLanduse
}
Expand Down Expand Up @@ -69,11 +71,20 @@ private enum LanduseConfiguration {
@CommandLine.Option(names = "--pathToInvestigationAreaData", description = "Path to the investigation area data", defaultValue = "contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/investigationAreaData.csv")
private Path pathToInvestigationAreaData;

private final Map<String, List<String>> landuseCategoriesAndDataConnection = new HashMap<>();
private Map<String, List<String>> landuseCategoriesAndDataConnection;
private final Map<String, Map<String, List<SimpleFeature>>> buildingsPerZone = new HashMap<>();

public CreateDataDistributionOfStructureData(LanduseDataConnectionCreator landuseDataConnectionCreator) {
CreateDataDistributionOfStructureData.landuseDataConnectionCreator = landuseDataConnectionCreator;
log.info("Using LanduseDataConnectionCreator {} to connect the types of the landuse data to the categories of the small scale commercial traffic generation", landuseDataConnectionCreator.getClass().getSimpleName());
}
public CreateDataDistributionOfStructureData() {
landuseDataConnectionCreator = new LanduseDataConnectionCreatorForOSM_Data();
log.info("Using default LanduseDataConnectionCreatorForOSM_Data to connect the types of the landuse data to the categories of the small scale commercial traffic generation");
}

public static void main(String[] args) {
System.exit(new CommandLine(new CreateDataDistributionOfStructureData()).execute(args));
System.exit(new CommandLine(new CreateDataDistributionOfStructureData(landuseDataConnectionCreator)).execute(args));
}

@Override
Expand Down Expand Up @@ -104,7 +115,7 @@ public Integer call() throws Exception {
if(Files.notExists(output))
new File(output.toString()).mkdir();

createDefaultDataConnectionForOSM(landuseCategoriesAndDataConnection); //TODO: find way to import this connection
landuseCategoriesAndDataConnection = landuseDataConnectionCreator.createLanduseDataConnection();

Map<String, Object2DoubleMap<String>> resultingDataPerZone = LanduseBuildingAnalysis
.createInputDataDistribution(output, landuseCategoriesAndDataConnection,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,24 +90,6 @@ public static Map<String, Object2DoubleMap<String>> createInputDataDistribution(
return resultingDataPerZone;
}

public static void createDefaultDataConnectionForOSM(Map<String, List<String>> landuseCategoriesAndDataConnection) {
landuseCategoriesAndDataConnection.put("Inhabitants",
new ArrayList<>(Arrays.asList("residential", "apartments", "dormitory", "dwelling_house", "house",
"retirement_home", "semidetached_house", "detached")));
landuseCategoriesAndDataConnection.put("Employee Primary Sector", new ArrayList<>(
Arrays.asList("farmyard", "farmland", "farm", "farm_auxiliary", "greenhouse", "agricultural")));
landuseCategoriesAndDataConnection.put("Employee Construction",
new ArrayList<>(List.of("construction")));
landuseCategoriesAndDataConnection.put("Employee Secondary Sector Rest",
new ArrayList<>(Arrays.asList("industrial", "factory", "manufacture", "bakehouse")));
landuseCategoriesAndDataConnection.put("Employee Retail",
new ArrayList<>(Arrays.asList("retail", "kiosk", "mall", "shop", "supermarket")));
landuseCategoriesAndDataConnection.put("Employee Traffic/Parcels", new ArrayList<>(
Arrays.asList("commercial", "post_office", "storage", "storage_tank", "warehouse")));
landuseCategoriesAndDataConnection.put("Employee Tertiary Sector Rest", new ArrayList<>(
Arrays.asList("commercial", "embassy", "foundation", "government", "office", "townhall")));
}

/**
* Creates the resulting data for each zone based on the landuse distribution
* and the original data.
Expand Down Expand Up @@ -138,10 +120,8 @@ private static void createResultingDataForLanduseInZones(
resultingDataPerZone.get(zoneId).mergeDouble(categoryData, 0., Double::sum);
if (landuseCategoriesAndDataConnection.get(categoryData).contains(categoryLanduse)) {
double additionalArea = landuseCategoriesPerZone.get(zoneId).getDouble(categoryLanduse);
// because the category commercial is in two categories (traffic/parcels and
// Tertiary Sector Rest
if (categoryLanduse.equals("commercial"))
additionalArea = additionalArea * 0.5;
// // because the categoryLanduse can be in two categories (e.g., traffic/parcels and Tertiary Sector Rest
additionalArea = additionalArea / LanduseDataConnectionCreator.getNumberOfEmployeeCategoriesOfThisTyp(landuseCategoriesAndDataConnection, categoryLanduse);
resultingDataPerZone.get(zoneId).mergeDouble(categoryData, additionalArea, Double::sum);
totalSquareMetersPerCategory.get(regionOfZone).mergeDouble(categoryData, additionalArea,
Double::sum);
Expand Down Expand Up @@ -271,21 +251,31 @@ private static void createLanduseDistribution(Map<String, Object2DoubleMap<Strin
*
* @param building the building to be analyzed
* @param buildingTypes the types of the building
* @return
* @return the area of the building for each category
*/
public static int calculateAreaPerBuildingCategory(SimpleFeature building, String[] buildingTypes) {
double buildingLevels;
double buildingLevelsPerType;
if (building.getAttribute("levels") == null)
buildingLevels = 1;
else
buildingLevels = (long) building.getAttribute("levels")
/ (double) buildingTypes.length;
else {
Object levelsAttribute = building.getAttribute("levels");
if (levelsAttribute instanceof String) {
buildingLevels = Double.parseDouble((String) levelsAttribute);
} else if (levelsAttribute instanceof Long) {
buildingLevels = (long) levelsAttribute;
} else {
throw new RuntimeException("The attribute 'levels' of the building shape is not a string or a long.");
}
}
buildingLevelsPerType = buildingLevels / (double) buildingTypes.length;

double groundArea;
if (building.getAttribute("area") != null)
groundArea = (int) (long) building.getAttribute("area");
else
groundArea = ((Geometry) building.getDefaultGeometry()).getArea();
double area = groundArea * buildingLevels;
double area = groundArea * buildingLevelsPerType;
return (int) Math.round(area);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.matsim.smallScaleCommercialTrafficGeneration.prepare;

import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

/**
* Interface for creating the connection between landuse or building categories and the required employee data categories for the simulation.
*
* @author Ricardo Ewert
*/
public interface LanduseDataConnectionCreator {
Map<String, List<String>> createLanduseDataConnection();

/**
* Counts the number of employee categories in which a type is represented.
*
* @return
*/
static int getNumberOfEmployeeCategoriesOfThisTyp(Map<String, List<String>> landuseCategoriesAndDataConnection, String type) {
AtomicInteger count = new AtomicInteger();
landuseCategoriesAndDataConnection.values().forEach(list -> {
if (list.contains(type)) {
count.getAndIncrement();
}
});
return count.get();
}

;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.matsim.smallScaleCommercialTrafficGeneration.prepare;

import java.util.*;

/**
* This class creates the connection between the landuse categories of the OSM landuse data and the employee data.
*
* @author Ricardo Ewert
*/
public class LanduseDataConnectionCreatorForOSM_Data implements LanduseDataConnectionCreator{

@Override
public Map<String, List<String>> createLanduseDataConnection() {
Map<String, List<String>> landuseCategoriesAndDataConnection = new HashMap<>();
landuseCategoriesAndDataConnection.put("Inhabitants",
new ArrayList<>(Arrays.asList("residential", "apartments", "dormitory", "dwelling_house", "house",
"retirement_home", "semidetached_house", "detached")));
landuseCategoriesAndDataConnection.put("Employee Primary Sector", new ArrayList<>(
Arrays.asList("farmyard", "farmland", "farm", "farm_auxiliary", "greenhouse", "agricultural")));
landuseCategoriesAndDataConnection.put("Employee Construction",
new ArrayList<>(List.of("construction")));
landuseCategoriesAndDataConnection.put("Employee Secondary Sector Rest",
new ArrayList<>(Arrays.asList("industrial", "factory", "manufacture", "bakehouse")));
landuseCategoriesAndDataConnection.put("Employee Retail",
new ArrayList<>(Arrays.asList("retail", "kiosk", "mall", "shop", "supermarket")));
landuseCategoriesAndDataConnection.put("Employee Traffic/Parcels", new ArrayList<>(
Arrays.asList("commercial", "post_office", "storage", "storage_tank", "warehouse")));
landuseCategoriesAndDataConnection.put("Employee Tertiary Sector Rest", new ArrayList<>(
Arrays.asList("commercial", "embassy", "foundation", "government", "office", "townhall")));
return landuseCategoriesAndDataConnection;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
import org.matsim.freight.carriers.CarriersUtils;
import org.matsim.smallScaleCommercialTrafficGeneration.TrafficVolumeGeneration.TrafficVolumeKey;
import org.matsim.smallScaleCommercialTrafficGeneration.prepare.LanduseBuildingAnalysis;
import org.matsim.smallScaleCommercialTrafficGeneration.prepare.LanduseDataConnectionCreator;
import org.matsim.smallScaleCommercialTrafficGeneration.prepare.LanduseDataConnectionCreatorForOSM_Data;
import org.matsim.testcases.MatsimTestUtils;
import org.opengis.feature.simple.SimpleFeature;

Expand All @@ -43,8 +45,6 @@
import java.nio.file.Path;
import java.util.*;

import static org.matsim.smallScaleCommercialTrafficGeneration.prepare.LanduseBuildingAnalysis.createDefaultDataConnectionForOSM;

/**
* @author Ricardo Ewert
*
Expand All @@ -57,7 +57,6 @@ public class TrafficVolumeGenerationTest {
@Test
void testTrafficVolumeGenerationCommercialPersonTraffic() throws IOException {

Map<String, List<String>> landuseCategoriesAndDataConnection = new HashMap<>();
Map<String, Map<String, List<SimpleFeature>>> buildingsPerZone = new HashMap<>();

Path output = Path.of(utils.getOutputDirectory());
Expand All @@ -67,7 +66,8 @@ void testTrafficVolumeGenerationCommercialPersonTraffic() throws IOException {
String shapeFileZoneNameColumn = "name";
String shapeFileBuildingTypeColumn = "type";
Path pathToInvestigationAreaData = Path.of(utils.getPackageInputDirectory()).resolve("investigationAreaData.csv");
createDefaultDataConnectionForOSM(landuseCategoriesAndDataConnection);
LanduseDataConnectionCreator landuseDataConnectionCreator = new LanduseDataConnectionCreatorForOSM_Data();
Map<String, List<String>> landuseCategoriesAndDataConnection = landuseDataConnectionCreator.createLanduseDataConnection();

Map<String, Object2DoubleMap<String>> resultingDataPerZone = LanduseBuildingAnalysis
.createInputDataDistribution(output, landuseCategoriesAndDataConnection,
Expand Down Expand Up @@ -188,7 +188,6 @@ void testTrafficVolumeGenerationCommercialPersonTraffic() throws IOException {
@Test
void testTrafficVolumeGenerationGoodsTraffic() throws IOException {

Map<String, List<String>> landuseCategoriesAndDataConnection = new HashMap<>();
Map<String, Map<String, List<SimpleFeature>>> buildingsPerZone = new HashMap<>();

Path output = Path.of(utils.getOutputDirectory());
Expand All @@ -198,7 +197,8 @@ void testTrafficVolumeGenerationGoodsTraffic() throws IOException {
String shapeFileZoneNameColumn = "name";
String shapeFileBuildingTypeColumn = "type";
Path pathToInvestigationAreaData = Path.of(utils.getPackageInputDirectory()).resolve("investigationAreaData.csv");
createDefaultDataConnectionForOSM(landuseCategoriesAndDataConnection);
LanduseDataConnectionCreator landuseDataConnectionCreator = new LanduseDataConnectionCreatorForOSM_Data();
Map<String, List<String>> landuseCategoriesAndDataConnection = landuseDataConnectionCreator.createLanduseDataConnection();

Map<String, Object2DoubleMap<String>> resultingDataPerZone = LanduseBuildingAnalysis
.createInputDataDistribution(output, landuseCategoriesAndDataConnection,
Expand Down Expand Up @@ -510,7 +510,6 @@ void testAddingExistingScenariosWithSample() throws Exception {

@Test
void testReducingDemandAfterAddingExistingScenarios_goods() throws Exception {
Map<String, List<String>> landuseCategoriesAndDataConnection = new HashMap<>();
Map<String, Map<String, List<SimpleFeature>>> buildingsPerZone = new HashMap<>();

Path output = Path.of(utils.getOutputDirectory());
Expand All @@ -523,7 +522,8 @@ void testReducingDemandAfterAddingExistingScenarios_goods() throws Exception {
String shapeFileZoneNameColumn = "name";
String shapeFileBuildingTypeColumn = "type";
Path pathToInvestigationAreaData = Path.of(utils.getPackageInputDirectory()).resolve("investigationAreaData.csv");
createDefaultDataConnectionForOSM(landuseCategoriesAndDataConnection);
LanduseDataConnectionCreator landuseDataConnectionCreator = new LanduseDataConnectionCreatorForOSM_Data();
Map<String, List<String>> landuseCategoriesAndDataConnection = landuseDataConnectionCreator.createLanduseDataConnection();

ArrayList<String> modesORvehTypes = new ArrayList<>(
Arrays.asList("vehTyp1", "vehTyp2", "vehTyp3", "vehTyp4", "vehTyp5"));
Expand Down Expand Up @@ -672,7 +672,6 @@ void testReducingDemandAfterAddingExistingScenarios_goods() throws Exception {

@Test
void testReducingDemandAfterAddingExistingScenarios_commercialPersonTraffic() throws Exception {
Map<String, List<String>> landuseCategoriesAndDataConnection = new HashMap<>();
Map<String, Map<String, List<SimpleFeature>>> buildingsPerZone = new HashMap<>();
Map<String, Map<String, List<ActivityFacility>>> facilitiesPerZone = new HashMap<>();

Expand All @@ -697,7 +696,9 @@ void testReducingDemandAfterAddingExistingScenarios_commercialPersonTraffic() th
Scenario scenario = ScenarioUtils.loadScenario(config);
TrafficVolumeGeneration.setInputParameters(usedTrafficType);

createDefaultDataConnectionForOSM(landuseCategoriesAndDataConnection);
LanduseDataConnectionCreator landuseDataConnectionCreator = new LanduseDataConnectionCreatorForOSM_Data();
Map<String, List<String>> landuseCategoriesAndDataConnection = landuseDataConnectionCreator.createLanduseDataConnection();

Map<String, Object2DoubleMap<String>> resultingDataPerZone = LanduseBuildingAnalysis
.createInputDataDistribution(output, landuseCategoriesAndDataConnection,
usedLanduseConfiguration,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@
import java.util.List;
import java.util.Map;

import static org.matsim.smallScaleCommercialTrafficGeneration.prepare.LanduseBuildingAnalysis.createDefaultDataConnectionForOSM;

/**
* @author Ricardo Ewert
*
Expand All @@ -47,7 +45,6 @@ public class LanduseBuildingAnalysisTest {

@Test
void testReadOfDataDistributionPerZoneAndBuildingAnalysis() throws IOException {
Map<String, List<String>> landuseCategoriesAndDataConnection = new HashMap<>();
Map<String, Map<String, List<SimpleFeature>>> buildingsPerZone = new HashMap<>();

Path output = Path.of(utils.getOutputDirectory());
Expand All @@ -57,10 +54,10 @@ void testReadOfDataDistributionPerZoneAndBuildingAnalysis() throws IOException {
String shapeFileZoneNameColumn = "name";
String shapeFileBuildingTypeColumn = "type";
Path pathToInvestigationAreaData = Path.of(utils.getPackageInputDirectory()).getParent().resolve("investigationAreaData.csv");
LanduseDataConnectionCreator landuseDataConnectionCreator = new LanduseDataConnectionCreatorForOSM_Data();
Map<String, List<String>> landuseCategoriesAndDataConnection = landuseDataConnectionCreator.createLanduseDataConnection();
// Test if the reading of the existing data distribution works correctly

createDefaultDataConnectionForOSM(landuseCategoriesAndDataConnection);

Map<String, Object2DoubleMap<String>> resultingDataPerZone = LanduseBuildingAnalysis
.createInputDataDistribution(output, landuseCategoriesAndDataConnection,
usedLanduseConfiguration,
Expand Down Expand Up @@ -242,7 +239,6 @@ void testReadOfDataDistributionPerZoneAndBuildingAnalysis() throws IOException {

@Test
void testLanduseDistribution() throws IOException {
Map<String, List<String>> landuseCategoriesAndDataConnection = new HashMap<>();
Map<String, Map<String, List<SimpleFeature>>> buildingsPerZone = new HashMap<>();

Path output = Path.of(utils.getOutputDirectory());
Expand All @@ -252,7 +248,8 @@ void testLanduseDistribution() throws IOException {
String shapeFileZoneNameColumn = "name";
String shapeFileBuildingTypeColumn = "type";
Path pathToInvestigationAreaData = Path.of(utils.getPackageInputDirectory()).getParent().resolve("investigationAreaData.csv");
createDefaultDataConnectionForOSM(landuseCategoriesAndDataConnection);
LanduseDataConnectionCreator landuseDataConnectionCreator = new LanduseDataConnectionCreatorForOSM_Data();
Map<String, List<String>> landuseCategoriesAndDataConnection = landuseDataConnectionCreator.createLanduseDataConnection();

// Analyze resultingData per zone
Map<String, Object2DoubleMap<String>> resultingDataPerZone = LanduseBuildingAnalysis
Expand Down

0 comments on commit 7bc9c2c

Please sign in to comment.