Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add scaling/normalisation of KPI outputs #77

Merged
merged 33 commits into from
Apr 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
a054240
add linear scaling factor class
KasiaKoz Mar 13, 2024
28eb327
simplify if statements for reversed scaling factor by multiplying by -1
KasiaKoz Mar 13, 2024
1ff7a66
add a couple more test for linear scale factor
KasiaKoz Mar 14, 2024
bbd765b
add tests for affordability KPI
KasiaKoz Mar 15, 2024
66b84ed
add scaling for affordability KPI
KasiaKoz Mar 15, 2024
f092004
refactor to make it more obvious we're testing with linear scaling fa…
KasiaKoz Mar 15, 2024
f65eaaa
no test in test names
KasiaKoz Mar 15, 2024
d6bdf97
add tests for pt wait time
KasiaKoz Mar 15, 2024
2ecd790
add scaling for pt wait time kpi
KasiaKoz Mar 15, 2024
587543f
rename pt wait test
KasiaKoz Mar 15, 2024
d7cb640
add test for occupancy rate kpi
KasiaKoz Mar 15, 2024
c538374
add scaling for occupancy rate kpi
KasiaKoz Mar 15, 2024
c1e432a
fix typo in occupancy test file
KasiaKoz Mar 15, 2024
f4af05f
improve vehicles builder
KasiaKoz Mar 15, 2024
32e160a
add test for ghg, find and fix bug when calculating per capita
KasiaKoz Mar 15, 2024
43f663b
update changelog with ghg bug fix #73
KasiaKoz Mar 18, 2024
6d5541b
add scaling for GHG KPI
KasiaKoz Mar 19, 2024
70e494d
add tests for Travel Time KPI
KasiaKoz Mar 25, 2024
7ca4cb5
add scaling to travel time
KasiaKoz Mar 25, 2024
18140e3
add test for mobility access KPI
KasiaKoz Mar 25, 2024
d78d6a6
add scaling for mobility access KPI output
KasiaKoz Mar 25, 2024
40f8663
add more tests for congestion
KasiaKoz Mar 25, 2024
4de1e03
add scaling for congestion KPi output
KasiaKoz Mar 25, 2024
dac3e25
rename scaling to normalisation
KasiaKoz Mar 25, 2024
db691b2
output actual and normalised KPI outputs
KasiaKoz Mar 26, 2024
2d608fe
update changelog with scaling/normalisation
KasiaKoz Mar 26, 2024
cef5bd9
remove more mentions of scaling
KasiaKoz Mar 26, 2024
81a712b
use camel case
KasiaKoz Mar 26, 2024
ab5646d
apply PR comment changes: docs tidy
KasiaKoz Mar 28, 2024
616ac28
apply PR comment changes: fewer magic numbers
KasiaKoz Mar 28, 2024
bed3a50
apply PR comment changes: refactor builders
KasiaKoz Mar 28, 2024
a93c313
apply PR comment changes: extra test and remove useless constructor
KasiaKoz Apr 8, 2024
4e2cc85
apply PR comment changes: refactor access to mobility tests to assert…
KasiaKoz Apr 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,20 @@ 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).

## [Unreleased] -

### 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`

### Fixed

- GHG Emissions KPI under-reporting bug ([#73](https://github.com/arup-group/gelato/issues/73))

### Changed

-

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

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);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.arup.cml.abm.kpi.matsim.run;

import com.arup.cml.abm.kpi.KpiCalculator;
import com.arup.cml.abm.kpi.LinearNormaliser;
import com.arup.cml.abm.kpi.data.MoneyLog;
import com.arup.cml.abm.kpi.domain.NetworkLinkLog;
import com.arup.cml.abm.kpi.matsim.MatsimUtils;
Expand Down Expand Up @@ -92,17 +93,20 @@ public void run() {
CompressionType.gzip
);

kpiCalculator.writeAffordabilityKpi(outputDir);
kpiCalculator.writePtWaitTimeKpi(outputDir);
double leftIntervalBound = 0.0;
double rightIntervalBound = 10.0;
double secondsInAMinute = 60.0;
kpiCalculator.writeAffordabilityKpi(outputDir, new LinearNormaliser(leftIntervalBound, rightIntervalBound, 1.25, 1));
kpiCalculator.writePtWaitTimeKpi(outputDir, new LinearNormaliser(leftIntervalBound, rightIntervalBound, 15 * secondsInAMinute, 5 * secondsInAMinute));
kpiCalculator.writeModalSplitKpi(outputDir);
kpiCalculator.writeOccupancyRateKpi(outputDir);
kpiCalculator.writeOccupancyRateKpi(outputDir, new LinearNormaliser(leftIntervalBound, rightIntervalBound, 0.2, 0.6));
kpiCalculator.writeVehicleKMKpi(outputDir);
kpiCalculator.writePassengerKMKpi(outputDir);
kpiCalculator.writeSpeedKpi(outputDir);
kpiCalculator.writeGHGKpi(outputDir);
kpiCalculator.writeAccessToMobilityServicesKpi(outputDir);
kpiCalculator.writeCongestionKpi(outputDir);
kpiCalculator.writeTravelTimeKpi(outputDir);
kpiCalculator.writeGHGKpi(outputDir, new LinearNormaliser(leftIntervalBound, rightIntervalBound, 8.87, 0.0));
kpiCalculator.writeAccessToMobilityServicesKpi(outputDir, new LinearNormaliser(leftIntervalBound, rightIntervalBound, 0.0, 100.0));
kpiCalculator.writeCongestionKpi(outputDir, new LinearNormaliser(leftIntervalBound, rightIntervalBound, 3.0, 1.25));
kpiCalculator.writeTravelTimeKpi(outputDir, new LinearNormaliser(leftIntervalBound, rightIntervalBound, 90.0, 10.0));
kpiCalculator.writeMobilitySpaceUsageKpi(outputDir);
MemoryObserver.stop();
}
Expand Down
Loading