Skip to content

Commit

Permalink
Merge branch 'master' into german-freight-minor-update
Browse files Browse the repository at this point in the history
  • Loading branch information
luchengqi7 authored Aug 1, 2024
2 parents 1cd36bb + 84948be commit 40d14e4
Show file tree
Hide file tree
Showing 23 changed files with 643 additions and 91 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -205,11 +205,11 @@ private void writeOutput(Network network, EmissionsOnLinkEventHandler emissionsE
if (link2pollutants.get(linkId).get(pollutant) != null) {
emissionValue = link2pollutants.get(linkId).get(pollutant);
}
absolute.print(nf.format(emissionValue));
absolute.print(nf.format(emissionValue * sample.getUpscaleFactor()));

Link link = network.getLinks().get(linkId);
double emissionPerM = emissionValue / link.getLength();
perMeter.print(nf.format(emissionPerM));
perMeter.print(nf.format(emissionPerM * sample.getUpscaleFactor()));
}

absolute.println();
Expand Down Expand Up @@ -246,7 +246,7 @@ private void writeTotal(Network network, EmissionsOnLinkEventHandler emissionsEv

total.printRecord("Pollutant", "kg");
for (Pollutant p : Pollutant.values()) {
double val = (sum.getDouble(p) / sample.getSample()) / 1000;
double val = (sum.getDouble(p) * sample.getUpscaleFactor()) / 1000;
total.printRecord(p, val < 100_000 && val > 100 ? simple.format(val) : scientific.format(val));
}

Expand Down Expand Up @@ -286,7 +286,7 @@ private void writeAvroRaster(Network network, Config config, EmissionsOnLinkEven
for (int xi = 0; xi < xLength.get(0); xi++) {
for (int yi = 0; yi < yLength.get(0); yi++) {
Coord coord = raster.getCoordForIndex(xi, yi);
double value = rasterMap.get(Pollutant.CO2_TOTAL).getValueByIndex(xi, yi);
double value = rasterMap.get(Pollutant.CO2_TOTAL).getValueByIndex(xi, yi) * sample.getUpscaleFactor();
if (xi == 0) yCoords.add((float) coord.getY());
if (yi == 0) xCoords.add((float) coord.getX());
valuesList.add((float) value);
Expand Down Expand Up @@ -349,7 +349,7 @@ private void writeRaster(Network network, Config config, EmissionsOnLinkEventHan
for (int yi = 0; yi < yLength.get(0); yi++) {

Coord coord = raster.getCoordForIndex(xi, yi);
double value = rasterMap.get(Pollutant.CO2_TOTAL).getValueByIndex(xi, yi);
double value = rasterMap.get(Pollutant.CO2_TOTAL).getValueByIndex(xi, yi) * sample.getUpscaleFactor();

if (value == 0)
continue;
Expand Down Expand Up @@ -406,7 +406,7 @@ private void writeTimeDependentRaster(Network network, Config config, EmissionsO
for (TimeBinMap.TimeBin<Map<Pollutant, Raster>> timeBin : timeBinMap.getTimeBins()) {

Coord coord = raster.getCoordForIndex(xi, yi);
double value = timeBin.getValue().get(Pollutant.CO2_TOTAL).getValueByIndex(xi, yi);
double value = timeBin.getValue().get(Pollutant.CO2_TOTAL).getValueByIndex(xi, yi) * sample.getUpscaleFactor();

if (value == 0)
continue;
Expand Down Expand Up @@ -467,7 +467,8 @@ private void writeTimeDependentAvroRaster(Network network, Config config, Emissi
if (yi == 0 && isFirst)
xCoords.add((float) coord.getX());

valuesList.add((float) timeBin.getValue().get(Pollutant.CO2_TOTAL).getValueByIndex(xi, yi));
double value = timeBin.getValue().get(Pollutant.CO2_TOTAL).getValueByIndex(xi, yi) * sample.getUpscaleFactor();
valuesList.add((float) value);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;
import org.apache.commons.math3.analysis.interpolation.LoessInterpolator;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.locationtech.jts.geom.Coordinate;
Expand All @@ -32,6 +33,7 @@
import java.math.RoundingMode;
import java.nio.file.Files;
import java.util.*;
import java.util.stream.IntStream;

import static tech.tablesaw.aggregate.AggregateFunctions.count;

Expand All @@ -41,6 +43,7 @@
produces = {
"mode_share.csv", "mode_share_per_dist.csv", "mode_users.csv", "trip_stats.csv",
"mode_share_per_%s.csv", "population_trip_stats.csv", "trip_purposes_by_hour.csv",
"mode_share_distance_distribution.csv",
"mode_choices.csv", "mode_choice_evaluation.csv", "mode_choice_evaluation_per_mode.csv",
"mode_confusion_matrix.csv", "mode_prediction_error.csv"
}
Expand Down Expand Up @@ -109,6 +112,25 @@ private static int durationToSeconds(String d) {
return (Integer.parseInt(split[0]) * 60 * 60) + (Integer.parseInt(split[1]) * 60) + Integer.parseInt(split[2]);
}

private static double[] calcHistogram(double[] data, double[] bins) {

double[] hist = new double[bins.length - 1];

for (int i = 0; i < bins.length - 1; i++) {

double binStart = bins[i];
double binEnd = bins[i + 1];

// The last right bin edge is inclusive, which is consistent with the numpy implementation
if (i == bins.length - 2)
hist[i] = Arrays.stream(data).filter(d -> d >= binStart && d <= binEnd).count();
else
hist[i] = Arrays.stream(data).filter(d -> d >= binStart && d < binEnd).count();
}

return hist;
}

@Override
public Integer call() throws Exception {

Expand Down Expand Up @@ -247,6 +269,8 @@ public Integer call() throws Exception {

writeTripPurposes(joined);

writeTripDistribution(joined);

return 0;
}

Expand Down Expand Up @@ -293,13 +317,15 @@ private void writeTripStats(Table trips) throws IOException {
Object2IntMap<String> n = new Object2IntLinkedOpenHashMap<>();
Object2LongMap<String> travelTime = new Object2LongOpenHashMap<>();
Object2LongMap<String> travelDistance = new Object2LongOpenHashMap<>();
Object2LongMap<String> beelineDistance = new Object2LongOpenHashMap<>();

for (Row trip : trips) {
String mainMode = trip.getString("main_mode");

n.mergeInt(mainMode, 1, Integer::sum);
travelTime.mergeLong(mainMode, durationToSeconds(trip.getString("trav_time")), Long::sum);
travelDistance.mergeLong(mainMode, trip.getLong("traveled_distance"), Long::sum);
beelineDistance.mergeLong(mainMode, trip.getLong("euclidean_distance"), Long::sum);
}

try (CSVPrinter printer = new CSVPrinter(Files.newBufferedWriter(output.getPath("trip_stats.csv")), CSVFormat.DEFAULT)) {
Expand Down Expand Up @@ -338,6 +364,13 @@ private void writeTripStats(Table trips) throws IOException {
}
printer.println();

printer.print("Avg. beeline speed [km/h]");
for (String m : modeOrder) {
double speed = (beelineDistance.getLong(m) / 1000d) / (travelTime.getLong(m) / (60d * 60d));
printer.print(new BigDecimal(speed).setScale(2, RoundingMode.HALF_UP));
}
printer.println();

printer.print("Avg. distance per trip [km]");
for (String m : modeOrder) {
double avg = (travelDistance.getLong(m) / 1000d) / (n.getInt(m));
Expand Down Expand Up @@ -458,6 +491,55 @@ private void writeTripPurposes(Table trips) {

}

private void writeTripDistribution(Table trips) throws IOException {

Map<String, double[]> dists = new LinkedHashMap<>();

// Note that the results of this interpolator are consistent with the one performed in matsim-python-tools
// This makes the results comparable with reference data, changes here will also require changes in the python package
LoessInterpolator inp = new LoessInterpolator(0.05, 0);

long max = distGroups.get(distGroups.size() - 3) + distGroups.get(distGroups.size() - 2);

double[] bins = IntStream.range(0, (int) (max / 100)).mapToDouble(i -> i * 100).toArray();
double[] x = Arrays.copyOf(bins, bins.length - 1);

for (String mode : modeOrder) {
double[] distances = trips.where(
trips.stringColumn("main_mode").equalsIgnoreCase(mode))
.numberColumn("traveled_distance").asDoubleArray();

double[] hist = calcHistogram(distances, bins);

double[] y = inp.smooth(x, hist);
dists.put(mode, y);
}

try (CSVPrinter printer = new CSVPrinter(Files.newBufferedWriter(output.getPath("mode_share_distance_distribution.csv")), CSVFormat.DEFAULT)) {

printer.print("dist");
for (String s : modeOrder) {
printer.print(s);
}
printer.println();

for (int i = 0; i < x.length; i++) {

double sum = 0;
for (String s : modeOrder) {
sum += Math.max(0, dists.get(s)[i]);
}

printer.print(x[i]);
for (String s : modeOrder) {
double value = Math.max(0, dists.get(s)[i]) / sum;
printer.print(value);
}
printer.println();
}
}
}

/**
* How shape file filtering should be applied.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

/**
* Class to calculate the traffic congestion index based on the paper
* "A Traffic Congestion Assessment Method for Urban Road Networks Based on Speed Performance Index" by Feifei He, Xuedong Yan*, Yang Liu, Lu Ma.
* "A Traffic Congestion Assessment Method for Urban Road Networks Based on Speed Performance Index" by Feifei He, Xuedong Yan, Yang Liu, Lu Ma.
*/
public final class TrafficStatsCalculator {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,13 @@ public double getSample() {
return sample;
}

/**
* Return factor that is used to upscale the sample size.
*/
public double getUpscaleFactor() {
return 1.0 / sample;
}

private void setSize(double sample) {
this.set = true;
this.sample = sample;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ public final class BicycleLinkSpeedCalculatorDefaultImpl implements BicycleLinkS
private static final Logger log = LogManager.getLogger(BicycleLinkSpeedCalculatorDefaultImpl.class );
@Inject private BicycleConfigGroup bicycleConfigGroup;
@Inject private QSimConfigGroup qSimConfigGroup;
@Inject private BicycleLinkSpeedCalculatorDefaultImpl() { }
@Inject private Config config;
@Inject private BicycleLinkSpeedCalculatorDefaultImpl() {
}

/**
* for unit testing
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,12 @@
import com.google.inject.Singleton;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.checkerframework.checker.units.qual.C;
import org.matsim.api.core.v01.Id;
import org.matsim.api.core.v01.Scenario;
import org.matsim.core.config.Config;
import org.matsim.core.config.ConfigGroup;
import org.matsim.core.config.ConfigUtils;
import org.matsim.core.controler.AbstractModule;
import org.matsim.core.controler.events.StartupEvent;
import org.matsim.core.controler.listener.StartupListener;
Expand All @@ -34,37 +38,51 @@
* @author smetzler, dziemke
*/
public final class BicycleModule extends AbstractModule {

private static final Logger LOG = LogManager.getLogger(BicycleModule.class);

@Inject
private BicycleConfigGroup bicycleConfigGroup;
@Inject private BicycleConfigGroup bicycleConfigGroup;

@Override public void install() {
// BicycleConfigGroup bicycleConfigGroup = ConfigUtils.addOrGetModule( this.getConfig(), BicycleConfigGroup.class );
// this.bind( BicycleConfigGroup.class ).toInstance( bicycleConfigGroup );
// the above feels odd. But it seems to work. I actually have no idea where the config groups are bound, neither for the core config
// groups nor for the added config groups. In general, the original idea was that AbstractModule provides the config from
// getConfig(), not from injection. kai, jun'24

// It actually does not work in general. The ExplodedConfigModule injects all config groups that are materialized by then. Which
// means that it needs to be materialized "quite early", and in particular before this install method is called. For the time being,
// a run script using the contrib thus needs to materialize the config group. kai, jul'24


@Override
public void install() {
// The idea here is the following:
// * scores are just added as score events. no scoring function is replaced.

// * link speeds are computed via a plugin handler to the DefaultLinkSpeedCalculator. If the plugin handler returns a speed, it is
// used, otherwise the default speed is used. This has the advantage that multiple plugins can register such special link speed calculators.

// this gives the typical things to the router:
addTravelTimeBinding(bicycleConfigGroup.getBicycleMode()).to(BicycleTravelTime.class).in(Singleton.class);
addTravelDisutilityFactoryBinding(bicycleConfigGroup.getBicycleMode()).to(BicycleTravelDisutilityFactory.class).in(Singleton.class);
// (the BicycleTravelTime uses the BicycleLinkSpeed Calculator bound below)
// (the BicycleDisutility uses a BicycleTravelDisutility)

// compute and throw the additional score events:
this.addEventHandlerBinding().to( BicycleScoreEventsCreator.class );
// (the motorized interaction is in the BicycleScoreEventsCreator)
// (this uses the AdditionalBicycleLinkScore to compute and throw corresponding scoring events)
// (it also computes and throws the motorized interaction events, if they are switched on)

this.bind( AdditionalBicycleLinkScore.class ).to( AdditionalBicycleLinkScoreDefaultImpl.class );

bind( BicycleLinkSpeedCalculator.class ).to( BicycleLinkSpeedCalculatorDefaultImpl.class ) ;
// this is still needed because the bicycle travel time calculator for routing needs to use the same bicycle speed as the mobsim. kai, jun'23
// (this computes the value of the per-link scoring event. yyyy Very unfortunately, it is a re-implementation of the BicycleTravelDisutility (mentioned above).)

this.installOverridingQSimModule( new AbstractQSimModule(){
@Override protected void configureQSim(){
this.addLinkSpeedCalculator().to( BicycleLinkSpeedCalculator.class );
}
} );

bind( BicycleLinkSpeedCalculator.class ).to( BicycleLinkSpeedCalculatorDefaultImpl.class ) ;
// (both the router and the mobsim need this)

addControlerListenerBinding().to(ConsistencyCheck.class);
}

Expand All @@ -73,7 +91,6 @@ static class ConsistencyCheck implements StartupListener {
@Inject private Scenario scenario;

@Override public void notifyStartup(StartupEvent event) {

Id<VehicleType> bicycleVehTypeId = Id.create(bicycleConfigGroup.getBicycleMode(), VehicleType.class);
if (scenario.getVehicles().getVehicleTypes().get(bicycleVehTypeId) == null) {
LOG.warn("There is no vehicle type '" + bicycleConfigGroup.getBicycleMode() + "' specified in the vehicle types. "
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import com.google.inject.Inject;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.matsim.core.config.Config;
import org.matsim.core.config.ConfigUtils;
import org.matsim.core.config.groups.ScoringConfigGroup;
import org.matsim.core.config.groups.RoutingConfigGroup;
import org.matsim.core.router.costcalculators.TravelDisutilityFactory;
Expand All @@ -35,21 +37,20 @@
*/
public final class BicycleTravelDisutilityFactory implements TravelDisutilityFactory {
// public-final is ok since ctor is package-private: can only be used through injection

private static final Logger LOG = LogManager.getLogger(BicycleTravelDisutilityFactory.class);

@Inject BicycleConfigGroup bicycleConfigGroup;
@Inject
ScoringConfigGroup cnScoringGroup;
@Inject
RoutingConfigGroup routingConfigGroup;

private BicycleConfigGroup bicycleConfigGroup;
@Inject Config config;
@Inject ScoringConfigGroup cnScoringGroup;
@Inject RoutingConfigGroup routingConfigGroup;
private static int normalisationWrnCnt = 0;

/* package-private */ BicycleTravelDisutilityFactory(){}
/* package-private */ BicycleTravelDisutilityFactory(){
}

@Override
public TravelDisutility createTravelDisutility(TravelTime timeCalculator) {
this.bicycleConfigGroup = ConfigUtils.addOrGetModule( config, BicycleConfigGroup.class );

double sigma = routingConfigGroup.getRoutingRandomness();

double normalization = 1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,4 +127,11 @@ private static boolean hasNoCycleway( String cyclewayType ) {
}
return userDefinedNetworkAttributeFactor;
}
// ===
public static void setSmoothness( Link link, String smoothness ){
link.getAttributes().putAttribute( SMOOTHNESS, smoothness );
}
public static void setBicycleInfrastructureFactor( Link link, double factor ){
link.getAttributes().putAttribute( BICYCLE_INFRASTRUCTURE_SPEED_FACTOR, factor );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ protected void setOrModifyLinkAttributes(Link l, OsmWay way, boolean forwardDire
// Smoothness
String smoothness = way.tags.get(BicycleUtils.SMOOTHNESS);
if (smoothness != null) {
l.getAttributes().putAttribute(BicycleUtils.SMOOTHNESS, smoothness);
BicycleUtils.setSmoothness( l, smoothness );
this.countSmoothness++;
}

Expand Down
Loading

0 comments on commit 40d14e4

Please sign in to comment.