Skip to content

Commit

Permalink
Merge branch 'main' into potential-performance
Browse files Browse the repository at this point in the history
  • Loading branch information
marecabo committed Apr 30, 2024
2 parents 377ef8c + cfc5639 commit 29e72b9
Show file tree
Hide file tree
Showing 51 changed files with 1,940 additions and 303 deletions.
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,19 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.0.4-alpha] - 2024-04-16

### Added

- Normalisation to values between `0` and `10` for metrics ([#69](https://github.com/arup-group/gelato/issues/69)):
`Affordability`, `PT Wait Time`, `Occupancy`, `GHG`, `Travel Time`, `Access to Mobility services`, `Congestion`
- EV emissions factors for DRT [#81](https://github.com/arup-group/gelato/issues/81)

### Fixed

- GHG Emissions KPI under-reporting bug ([#73](https://github.com/arup-group/gelato/issues/73))
- Added default values for DRT (previously assumed as zero) [#81](https://github.com/arup-group/gelato/issues/81)


## [0.0.3-alpha] - 2024-03-07

Expand Down Expand Up @@ -34,6 +47,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- vehicles get fuel types and emission factors ([#60](https://github.com/arup-group/gelato/issues/60))
- trips and legs have an additional column reporting monetary cost of the trip or leg ([#59](https://github.com/arup-group/gelato/issues/59))


## [0.0.2-alpha] - 2024-02-21

### Added
Expand Down
18 changes: 12 additions & 6 deletions KPI_Data_Requirements_and_Expectations.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ In general the following outputs from a MATSim model are expected on top of the
- `output_households.xml.gz` (can be empty)
- `output_facilities.xml.gz` (can be empty)
- `output_vehicles.xml.gz`
- `soutput_persons.csv.gz`
- `soutput_legs.xml.gz`
- `soutput_trips.xml.gz`
- `output_persons.csv.gz`
- `output_legs.xml.gz`
- `output_trips.xml.gz`
- `drt_vehicles.xml.gz` (for simulations with DRT mode)

Please note, if you are using a simulation configuration that modifies the inherent structure of the above MATsim outputs, that will impact your KPI calculation. For example, if you have used the Eqasim Cutter extension ([link](https://github.com/eqasim-org/eqasim-java/blob/develop/docs/cutting.md)), this will increase the number of trips in your `output_trips.xml.gz` file and relabel some to an `outside` mode or activity. This will impact how the KPI is structured and calculated, and you will need to validate the outputs are as you intend.

## Affordability

### Cost of Travel
Expand Down Expand Up @@ -70,16 +72,20 @@ way:
</vehicleType>
```

Otherwise, the factors will default to `"fuelType"="petrol"` and `"emissionsFactor"=0.222` for personal agent's cars and
Otherwise, the factors will default to `"fuelType"="petrol"` and `"emissionsFactor"=0.222` for personal agent's cars, `"fuelType"="ev"` and `"emissionsFactor"=0.076` for
drt vehicles, and `"fuelType"="cng"` and `"emissionsFactor"=1.372` for buses.
Other PT vehicles are not defaulted and do not contribute to emission calculations.

We recommend setting fuel types and emission factors for LGVs and HGVs, otherwise they may will regarded as personal cars.
The defaults we use are:
We recommend setting fuel types and emission factors for LGVs and HGVs, otherwise they will not have an emissions estimate.
The defaults we suggest are:

- LGV: `"fuelType"="petrol"`, `"emissionsFactor"=0.317`
- HGV: `"fuelType"="diesel"`, `"emissionsFactor"=0.761`

The above values are all based on the European Environmental Agency guidebook.
Car, LGV, HGV, and Buses emissions factors are derived from Tables 3-12 and 3-15 from their [guidebook](https://www.eea.europa.eu/publications/emep-eea-guidebook-2023/part-b-sectoral-guidance-chapters/1-energy/1-a-combustion/1-a-3-b-i/view)
EV emissions factors for cars are from page 32 of their [report](https://www.eea.europa.eu/publications/electric-vehicles-from-life-cycle) estimating life cycle emissions.

# Access to Mobility Services

The $(x, y)$ spatial coordinates are assumed to be in metre-based, distance-preserving projection.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ We will add more KPIs as we go, but for now, these are the KPIs generated by Gel
| Quality of Life | Access to Mobility Services | `kpi-access-to-mobility-services-access-to-{bus,rail,pt-and-pt-used}.csv.gz` | Percentage of agents whose homes are within 400m of bus stops, 800m of rail stops, and whether they used PT for travel | From trip logs, we obtain agents' 'home' activity locations. We find whether there is a stop that serves transit services of modes 'bus' and 'rail', within distances of 400 and 800 metres of person's home location, respectively. | `intermediate-access-to-mobility-services.csv.gz` |
| <ul><li>Quality of Life</li><li>Mobility System Performance</li></ul> | Affordability | `kpi-affordability.csv.gz` | Ratio of average spend on transport of low income agents : overall average spend on transport of all agents | Using leg logs and monetary scoring values per mode and person's subpopulation (per distance unit and constant), and/or Person Money Events, compute monetary cost for each leg. We compute total and average daily spend on transport by income brackets (numeric values for income are required) or subpopulation, if not available, (if `low income` subpopulation is available, otherwise only intermediate output is generated). Read more: [KPI Data Requirements and Expectations: Affordability](KPI_Data_Requirements_and_Expectations.md#affordability). | `intermediate-affordability.csv.gz` |
| <ul><li>Global Environment</li><li>Mobility System Performance</li></ul> | Congestion | `kpi-congestion.csv.gz` | Delays in road traffic and in public transport during peak hours compared to free flow travel | Capture free-flow time at the link level, subtract congested time from this value. Congested time is the difference between link entry and exit time. | `intermediate-congestion.csv.gz` |
| Global Environment | GHG Emissions | `kpi-ghg-emissions.csv.gz` | Total Emissions emitted by vehicles | Total kilometres travelled by vehicles multiplied by default emission factors of 0.222 (car) and 1.372 (bus), respectively; or as set by you - read more in [KPI Data Requirements and Expectations: GHG Emissions](KPI_Data_Requirements_and_Expectations.md#ghg-emissions). | `intermediate-ghg-emissions.csv.gz` |
| Global Environment | GHG Emissions | `kpi-ghg-emissions.csv.gz` | Total Emissions emitted by vehicles | Total kilometres travelled by vehicles multiplied by default emission factors of 0.222 kg C02/km (car) and 1.372 kg CO2/km (bus), respectively; or as set by you - read more in [KPI Data Requirements and Expectations: GHG Emissions](KPI_Data_Requirements_and_Expectations.md#ghg-emissions). | `intermediate-ghg-emissions.csv.gz` |
| <ul><li>Global Environment</li><li>Mobility System Performance</li></ul> | Mobility Space Usage | `kpi-mobility-space-usage{-per-activity-type}.csv.gz` | Estimated parking space demand per capita | Number of persons at facilities, per activity type, who arrived there by car. We use a parking space factor of 11.5 ([link](https://www.interparking-france.com/en/what-are-the-dimensions-of-a-parking-space/)) to calculate total parking demand and weigh it by number of trips. | `intermediate-mobility-space-usage.csv.gz` |
| <ul><li>Social</li><li>Mobility System Performance</li></ul> | PT Wait Time | `kpi-pt-wait-time.csv.gz` | Average time waiting for a PT boarding | Average trip wait times by transport mode. | `intermediate-pt-wait-time.csv.gz` |
| <ul><li>Quality of Life</li><li>Economic Success</li></ul> | Travel Time | `kpi-travel-time.csv.gz` | Average travel time across all trips, in minutes | Using trip logs, convert travel time to minutes, average across the trips. | `intermediate-travel-time.csv.gz` |
Expand Down
2 changes: 1 addition & 1 deletion dependency-reduced-pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<groupId>com.arup.cml</groupId>
<artifactId>gelato</artifactId>
<name>Gelato</name>
<version>0.0.3-alpha</version>
<version>0.0.4-alpha</version>
<description>A command-line post-processing tool to turn MATSim ABM outputs into KPI metrics</description>
<inceptionYear>2023</inceptionYear>
<licenses>
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<groupId>com.arup.cml</groupId>
<artifactId>gelato</artifactId>
<packaging>jar</packaging>
<version>0.0.3-alpha</version>
<version>0.0.4-alpha</version>

<name>Gelato</name>
<description>A command-line post-processing tool to turn MATSim ABM outputs into KPI metrics</description>
Expand Down
15 changes: 8 additions & 7 deletions src/main/java/com/arup/cml/abm/kpi/KpiCalculator.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,30 @@
import tech.tablesaw.api.Table;

import java.nio.file.Path;
import java.util.Map;

public interface KpiCalculator {
double writeAffordabilityKpi(Path outputDirectory);
Map<String, Double> writeAffordabilityKpi(Path outputDirectory, Normaliser normaliser);

void writePtWaitTimeKpi(Path outputDirectory);
Map<String, Double> writePtWaitTimeKpi(Path outputDirectory, Normaliser normaliser);

void writeModalSplitKpi(Path outputDirectory);

void writeOccupancyRateKpi(Path outputDirectory);
Map<String, Double> writeOccupancyRateKpi(Path outputDirectory, Normaliser normaliser);

double writeVehicleKMKpi(Path outputDirectory);

void writePassengerKMKpi(Path outputDirectory);

void writeSpeedKpi(Path outputDirectory);

double writeGHGKpi(Path outputDirectory);
Map<String, Double> writeGHGKpi(Path outputDirectory, Normaliser normaliser);

double writeTravelTimeKpi(Path outputDirectory);
Map<String, Double> writeTravelTimeKpi(Path outputDirectory, Normaliser normaliser);

Table writeAccessToMobilityServicesKpi(Path outputDirectory);
Map<String, Map<String, Double>> writeAccessToMobilityServicesKpi(Path outputDirectory, Normaliser normaliser);

Table writeCongestionKpi(Path directory);
Table writeCongestionKpi(Path directory, Normaliser normaliser);

double writeMobilitySpaceUsageKpi(Path outputDirectory);
}
91 changes: 91 additions & 0 deletions src/main/java/com/arup/cml/abm/kpi/LinearNormaliser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package com.arup.cml.abm.kpi;

public class LinearNormaliser implements Normaliser {
private double leftIntervalBound;
private double rightIntervalBound;
private double leftValueBound;
private double rightValueBound;
private boolean isReversed = false;

/**
* Provides 1D affine transformation: M * value + C
* mapping values: [leftValueBound, rightValueBound] -> [leftIntervalBound, rightIntervalBound]
* leftValueBound can be larger than rightValueBound, a given value will be scaled reversely.
* Values outside the boundaries, are mapped to their closest bound.
* E.g.
* If [0, 1] -> [0, 10] then 0.4 -> 4, -5 -> 0, 2 -> 10
* If [1, 0] -> [0, 10] then 0.4 -> 6, -5 -> 10, 2 -> 0
* @param leftIntervalBound left bound of the destination interval,
* leftIntervalBound < rightIntervalBound, necessarily.
* @param rightIntervalBound right bound of the destination interval,
* rightIntervalBound > leftIntervalBound, necessarily.
* @param leftValueBound left bound of the origin interval, it is mapped to leftIntervalBound.
* @param rightValueBound right bound of the origin interval, it is mapped to rightIntervalBound.
*/
public LinearNormaliser(double leftIntervalBound, double rightIntervalBound, double leftValueBound, double rightValueBound) {
if (leftIntervalBound > rightIntervalBound) {
throw new IllegalArgumentException("leftIntervalBound cannot be larger than rightValueBound");
}
if (leftValueBound == rightValueBound && leftIntervalBound != rightIntervalBound) {
throw new IllegalArgumentException("The bounds given for linear interval are invalid. " +
"Left and right bounds cannot both be the same value.");
}
if (leftValueBound > rightValueBound) {
this.isReversed = true;
leftValueBound = -leftValueBound;
rightValueBound = -rightValueBound;
}

this.leftIntervalBound = leftIntervalBound;
this.rightIntervalBound = rightIntervalBound;
this.leftValueBound = leftValueBound;
this.rightValueBound = rightValueBound;
}

/**
* Provides 1D affine transformation: M * value + C
* mapping values: [leftValueBound, rightValueBound] -> [0, 10]
* leftValueBound can be larger than rightValueBound, a given value will be scaled reversely.
* Values outside the boundaries, are mapped to their closest bound.
* E.g.
* If [0, 1] -> [0, 10] then 0.4 -> 4, -5 -> 0, 2 -> 10
* If [1, 0] -> [0, 10] then 0.4 -> 6, -5 -> 10, 2 -> 0
* @param leftValueBound left bound of the origin interval, it is mapped to 0.
* @param rightValueBound right bound of the origin interval, it is mapped to 10.
*/
public LinearNormaliser(double leftValueBound, double rightValueBound) {
this(0, 10, leftValueBound, rightValueBound);
}

private boolean isReversed() {
return this.isReversed;
}

public double getLowerIntervalBound() {
return leftIntervalBound;
}

public double getUpperIntervalBound() {
return rightIntervalBound;
}

private boolean isWithinBounds(double value) {
return value >= leftValueBound && value <= rightValueBound;
}

@Override
public double normalise(double value) {
if (this.isReversed()) {
value = -value;
}
if (this.isWithinBounds(value)) {
return ((value - leftValueBound) / (rightValueBound - leftValueBound)) * (rightIntervalBound - leftIntervalBound);
} else {
if (value > rightValueBound) {
return rightIntervalBound;
} else {
return leftIntervalBound;
}
}
}
}
5 changes: 5 additions & 0 deletions src/main/java/com/arup/cml/abm/kpi/Normaliser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.arup.cml.abm.kpi;

public interface Normaliser {
double normalise(double value);
}
3 changes: 3 additions & 0 deletions src/main/java/com/arup/cml/abm/kpi/matsim/MatsimUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ public class MatsimUtils {
public static final double DEFAULT_CAR_EMISSIONS_FACTOR = 0.222;
public static final String DEFAULT_BUS_FUEL_TYPE = "cng";
public static final double DEFAULT_BUS_EMISSIONS_FACTOR = 1.372;
public static final String DEFAULT_DRT_FUEL_TYPE = "ev";
public static final double DEFAULT_DRT_EMISSIONS_FACTOR = 0.076;
private Path matsimOutputDir;
private Config matsimConfig;
private Scenario matsimScenario;
Expand Down Expand Up @@ -252,6 +254,7 @@ private Vehicles collectVehicles(Scenario scenario) {
switch (vehicleType.getNetworkMode()) {
case "car" -> setDefaultsForEngineInformationIfNotAvailable(vehicleType, DEFAULT_CAR_FUEL_TYPE, DEFAULT_CAR_EMISSIONS_FACTOR);
case "bus" -> setDefaultsForEngineInformationIfNotAvailable(vehicleType, DEFAULT_BUS_FUEL_TYPE, DEFAULT_BUS_EMISSIONS_FACTOR);
case "drt" -> setDefaultsForEngineInformationIfNotAvailable(vehicleType, DEFAULT_DRT_FUEL_TYPE, DEFAULT_DRT_EMISSIONS_FACTOR);
}
});
return vehicles;
Expand Down
Loading

0 comments on commit 29e72b9

Please sign in to comment.