Skip to content

Commit

Permalink
update matsim and dashboards
Browse files Browse the repository at this point in the history
  • Loading branch information
rakow committed Aug 8, 2024
1 parent f4e6984 commit dab2223
Show file tree
Hide file tree
Showing 10 changed files with 386 additions and 45 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ $p/berlin-$V-counts-vmz.xml.gz: $p/berlin-$V-network.xml.gz

$p/berlin-$V-facilities.xml.gz: $p/berlin-$V-network.xml.gz input/facilities.gpkg
$(sc) prepare facilities --network $< --shp $(word 2,$^)\
--facility-mapping input/activity_mapping.json\
--output $@

$p/berlin-only-$V-100pct.plans.xml.gz: input/PLR_2013_2020.csv $(berlin)/input/shp/Planungsraum_EPSG_25833.shp input/facilities.gpkg
Expand Down
8 changes: 7 additions & 1 deletion input/activity_mapping.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,13 @@
"college": ["edu_higher", "work"],
"sports_hall": ["leisure", "work"],
"stadium": ["leisure", "work"],
"apartments": ["resident"]
"apartments": ["resident"],
"house": ["resident"],
"detached": ["resident"],
"semidetached_house": ["resident"],
"bungalow": ["resident"],
"terrace": ["resident"],
"residential": ["resident"]
},
"amenity": {
"bar": ["leisure", "work", "delivery", "dining"],
Expand Down
14 changes: 14 additions & 0 deletions input/facility_mapping.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"work": ["work", "work_business"],
"shop": ["shop_other"],
"shop_daily": ["shop_other", "shop_daily"],
"leisure": ["leisure"],
"dining": ["dining"],
"edu_higher": ["edu_higher"],
"edu_prim": ["edu_primary", "edu_secondary"],
"edu_kiga": ["edu_kiga"],
"edu_other": ["edu_other"],
"p_business": ["personal_business", "work_business"],
"medical": ["personal_business"],
"religious": ["personal_business"]
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public List<Dashboard> getDashboards(Config config, SimWrapper simWrapper) {
TripDashboard trips = new TripDashboard("mode_share_ref.csv", "mode_share_per_dist_ref.csv", "mode_users_ref.csv")
.setAnalysisArgs("--match-id", "^berlin.+", "--shp-filter", "none")
.withChoiceEvaluation(true)
.withDistanceDistribution("mode_share_distance_distribution.csv")
.withGroupedRefData("mode_share_per_group_dist_ref.csv", "age", "income", "employment", "economic_status");

return List.of(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package org.matsim.prepare.facilities;

import com.google.common.math.Quantiles;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.databind.ObjectMapper;
import it.unimi.dsi.fastutil.objects.Object2DoubleMap;
import it.unimi.dsi.fastutil.objects.Object2DoubleOpenHashMap;
import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;
import org.apache.commons.math3.stat.descriptive.SummaryStatistics;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.geotools.api.feature.simple.SimpleFeature;
import org.locationtech.jts.geom.Envelope;
import org.locationtech.jts.geom.MultiPolygon;
import org.locationtech.jts.geom.TopologyException;
Expand All @@ -23,9 +25,10 @@
import org.matsim.core.utils.geometry.geotools.MGC;
import org.matsim.facilities.*;
import org.matsim.prepare.population.Attributes;
import org.geotools.api.feature.simple.SimpleFeature;
import picocli.CommandLine;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.file.Path;
import java.util.*;
import java.util.function.Function;
Expand All @@ -51,9 +54,14 @@ public class CreateMATSimFacilities implements MATSimAppCommand {
@CommandLine.Option(names = "--output", required = true, description = "Path to output facility file")
private Path output;

@CommandLine.Option(names = "--facility-mapping", description = "Path to facility napping json", required = true)
private Path mappingPath;

@CommandLine.Mixin
private ShpOptions shp;

private MappingConfig config;

public static void main(String[] args) {
new CreateMATSimFacilities().execute(args);
}
Expand Down Expand Up @@ -82,6 +90,8 @@ public Integer call() throws Exception {
return 2;
}

config = new ObjectMapper().readerFor(MappingConfig.class).readValue(mappingPath.toFile());

Network completeNetwork = NetworkUtils.readNetwork(this.network.toString());
TransportModeNetworkFilter filter = new TransportModeNetworkFilter(completeNetwork);
Network carOnlyNetwork = NetworkUtils.createNetwork();
Expand Down Expand Up @@ -133,10 +143,10 @@ public Integer call() throws Exception {
// Filter outliers from the attraction and normalize the attraction
// This warrant for further investigate as the best way to normalize the attraction is not yet known
facility.getAttributes().putAttribute(Attributes.ATTRACTION_WORK,
Math.min(Math.max(h.attractionWork / 5, 1), workUpper)
round(Math.min(Math.max(h.attractionWork / 5, 1), workUpper))
);
facility.getAttributes().putAttribute(Attributes.ATTRACTION_OTHER,
Math.min(Math.max(h.attractionOther / 5, 1), otherUpper)
round(Math.min(Math.max(h.attractionOther / 5, 1), otherUpper))
);

facilities.addActivityFacility(facility);
Expand All @@ -150,8 +160,12 @@ public Integer call() throws Exception {
return 0;
}

private static double round(double f) {
return BigDecimal.valueOf(f).setScale(4, RoundingMode.HALF_UP).doubleValue();
}

/**
* Sample points and choose link with the nearest points. Aggregate everything so there is at most one facility per link.
* Sample points and choose link with the nearest points.
*/
private Holder processFeature(SimpleFeature ft, Network network) {

Expand Down Expand Up @@ -240,43 +254,18 @@ private List<Coord> samplePoints(MultiPolygon geometry, int n) {
private Set<String> activities(SimpleFeature ft) {
Set<String> act = new HashSet<>();

if (hasAttribute(ft, "work")) {
act.add("work");
act.add("work_business");
}
if (hasAttribute(ft, "shop")) {
act.add("shop_other");
}
if (hasAttribute(ft, "shop_daily")) {
act.add("shop_other");
act.add("shop_daily");
}
if (hasAttribute(ft, "leisure"))
act.add("leisure");
if (hasAttribute(ft, "dining"))
act.add("dining");
if (hasAttribute(ft, "edu_higher"))
act.add("edu_higher");
if (hasAttribute(ft, "edu_prim")) {
act.add("edu_primary");
act.add("edu_secondary");
}
if (hasAttribute(ft, "edu_kiga"))
act.add("edu_kiga");
if (hasAttribute(ft, "edu_other"))
act.add("edu_other");
if (hasAttribute(ft, "p_business") || hasAttribute(ft, "medical") || hasAttribute(ft, "religious")) {
act.add("personal_business");
for (Map.Entry<String, Set<String>> entries : config.values.entrySet()) {
if (hasAttribute(ft, entries.getKey())) {
act.addAll(entries.getValue());
}
}
if (hasAttribute(ft, "p_business"))
act.add("work_business");

return act;
}

private static boolean hasAttribute(SimpleFeature ft, String name) {
return ft.getAttribute(name) != null &&
(Boolean.TRUE.equals(ft.getAttribute(name)) ||
(Boolean.TRUE.equals(ft.getAttribute(name)) || "1".equals(ft.getAttribute(name)) ||
(ft.getAttribute(name) instanceof Number number && number.intValue() > 0)
);
}
Expand All @@ -286,6 +275,24 @@ private static boolean hasAttribute(SimpleFeature ft, String name) {
*/
private record Holder(Id<Link> linkId, Set<String> activities, List<Coord> coords,
double attractionWork, double attractionOther) {
}

/**
* Helper class to define data structure for mapping.
*/
public static final class MappingConfig {

private final Map<String, Set<String>> values = new HashMap<>();

@JsonAnyGetter
public Set<String> getActivities(String value) {
return values.get(value);
}

@JsonAnySetter
private void setActivities(String value, Set<String> activities) {
values.put(value, activities);
}

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import org.matsim.application.options.ShpOptions;
import org.matsim.core.population.PopulationUtils;
import org.matsim.core.router.TripStructureUtils;
import org.matsim.run.OpenBerlinScenario;
import picocli.CommandLine;

import java.nio.file.Files;
Expand Down Expand Up @@ -79,7 +80,7 @@ public Integer call() throws Exception {

SplittableRandom rnd = new SplittableRandom(0);
persons = new PersonMatcher("idx", personsPath);
facilities = new FacilityIndex(facilityPath.toString());
facilities = new FacilityIndex(facilityPath.toString(), OpenBerlinScenario.CRS);

PlanBuilder planBuilder = new PlanBuilder(shp, facilities, activityPath);

Expand Down
20 changes: 14 additions & 6 deletions src/main/java/org/matsim/prepare/population/FacilityIndex.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import org.matsim.facilities.FacilitiesUtils;
import org.matsim.facilities.MatsimFacilitiesReader;
import org.matsim.prepare.facilities.AttributedActivityFacility;
import org.matsim.run.OpenBerlinScenario;

import java.util.*;
import java.util.function.Function;
Expand All @@ -20,7 +19,7 @@
/**
* Spatial index for facilities.
*/
final class FacilityIndex {
public final class FacilityIndex {

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

Expand All @@ -29,12 +28,11 @@ final class FacilityIndex {
/**
* Maps activity type to spatial index.
*/
final Map<String, STRtree> index = new HashMap<>();
public final Map<String, STRtree> index = new HashMap<>();

FacilityIndex(String facilityPath) {
public FacilityIndex(String facilityPath, String crs) {

new MatsimFacilitiesReader(OpenBerlinScenario.CRS, OpenBerlinScenario.CRS, all)
.readFile(facilityPath);
new MatsimFacilitiesReader(crs, crs, all).readFile(facilityPath);

Set<String> activities = all.getFacilities().values().stream()
.flatMap(a -> a.getActivityOptions().keySet().stream())
Expand Down Expand Up @@ -77,6 +75,16 @@ public static int sampleByWeight(List<AttributedActivityFacility> candidates, Fu
return idx;
}

/**
* Samples from list of candidates until one option is not rejected.
*/
public static ActivityFacility sample(List<ActivityFacility> candidates, SplittableRandom rnd) {
if (candidates.isEmpty())
return null;

return candidates.get(rnd.nextInt(candidates.size()));
}

/**
* Samples from list of candidates using weight until one option is not rejected.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.matsim.facilities.ActivityFacility;
import org.matsim.prepare.RunOpenBerlinCalibration;
import org.matsim.prepare.facilities.AttributedActivityFacility;
import org.matsim.run.OpenBerlinScenario;
import picocli.CommandLine;

import java.math.BigInteger;
Expand Down Expand Up @@ -136,7 +137,7 @@ public Integer call() throws Exception {
network = NetworkUtils.createNetwork();
filter.filter(network, Set.of(TransportMode.car));

facilities = new FacilityIndex(facilityPath.toString());
facilities = new FacilityIndex(facilityPath.toString(), OpenBerlinScenario.CRS);

zones = new Long2ObjectOpenHashMap<>(shp.readFeatures().stream()
.collect(Collectors.toMap(ft -> Long.parseLong((String) ft.getAttribute("ARS")), ft -> ft)));
Expand Down
2 changes: 2 additions & 0 deletions src/main/python/calibrate.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
}

# modal split according to SrV 2018 (shared-svn/projects/matsim-berlin/data/SrV)
# Also see https://www.berlin.de/sen/uvk/presse/pressemitteilungen/2020/pressemitteilung.906382.php
# The calibration only considers persons living in Berlin
target = {
"walk": 0.296769,
"bike": 0.177878,
Expand Down
Loading

0 comments on commit dab2223

Please sign in to comment.