Skip to content

Commit

Permalink
prepare capacity models, use the new predictor interface
Browse files Browse the repository at this point in the history
  • Loading branch information
rakow committed May 9, 2024
1 parent fa11208 commit 51ebdfa
Show file tree
Hide file tree
Showing 11 changed files with 150 additions and 61 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import org.matsim.application.MATSimAppCommand;
import org.matsim.application.options.InputOptions;
import org.matsim.application.options.OutputOptions;
import org.matsim.application.prepare.Predictor;
import org.matsim.application.prepare.network.params.NetworkParamsOpt.Feature;
import org.matsim.core.network.NetworkUtils;
import org.matsim.core.utils.io.IOUtils;
Expand Down Expand Up @@ -74,12 +75,12 @@ public static void main(String[] args) {
/**
* Theoretical capacity.
*/
private static double capacityEstimate(double v) {
public static double capacityEstimate(double v) {

// headway
double tT = 1.2;

// car length
// car length + buffer
double lL = 7.0;

double Qc = v / (v * tT + lL);
Expand Down Expand Up @@ -117,9 +118,7 @@ public Integer call() throws Exception {

try {
applyChanges(link, ft);
} catch (UnsupportedOperationException u) {
// This will be ignored silently and should only be thrown if certain changes should not be applied
} catch (IllegalArgumentException e) {
} catch (IllegalArgumentException e) {
warn++;
log.warn("Error processing link {}", link.getId(), e);
}
Expand All @@ -141,26 +140,27 @@ private void applyChanges(Link link, Feature ft) {

if (params.contains(NetworkAttribute.capacity)) {

FeatureRegressor capacity = model.capacity(ft.junctionType(), ft.highwayType());
Predictor capacity = model.capacity(ft.junctionType(), ft.highwayType());
// No operation performed if not supported
if (capacity == null) {
throw new UnsupportedOperationException("Capacity model not available for " + ft.junctionType());
return;
}

double perLane = capacity.predict(ft.features());
double perLane = capacity.predict(ft.features(), ft.categories());

double cap = capacityEstimate(ft.features().getDouble("speed"));

if (perLane < cap * speedFactorBounds[0]) {
if (perLane < cap * capacityBounds[0]) {
log.warn("Increasing capacity per lane on {} ({}, {}) from {} to {}",
link.getId(), ft.highwayType(), ft.junctionType(), perLane, cap * speedFactorBounds[0]);
perLane = cap * speedFactorBounds[0];
link.getId(), ft.highwayType(), ft.junctionType(), perLane, cap * capacityBounds[0]);
perLane = cap * capacityBounds[0];
modified = true;
}

if (perLane > cap * speedFactorBounds[1]) {
if (perLane > cap * capacityBounds[1]) {
log.warn("Reducing capacity per lane on {} ({}, {}) from {} to {}",
link.getId(), ft.highwayType(), ft.junctionType(), perLane, cap * speedFactorBounds[1]);
perLane = cap * speedFactorBounds[1];
link.getId(), ft.highwayType(), ft.junctionType(), perLane, cap * capacityBounds[1]);
perLane = cap * capacityBounds[1];
modified = true;
}

Expand All @@ -170,16 +170,16 @@ private void applyChanges(Link link, Feature ft) {

if (params.contains(NetworkAttribute.freespeed)) {

double speedFactor = 1.0;
FeatureRegressor speedModel = model.speedFactor(ft.junctionType(), ft.highwayType());
Predictor speedModel = model.speedFactor(ft.junctionType(), ft.highwayType());

// No operation performed if not supported
if (speedModel == null) {
throw new UnsupportedOperationException("Speed model not available for " + ft.junctionType());
return;
}

speedFactor = paramsOpt != null ?
speedModel.predict(ft.features(), paramsOpt.getParams(ft.junctionType())) :
speedModel.predict(ft.features());
double speedFactor = paramsOpt != null ?
speedModel.predict(ft.features(), ft.categories(), paramsOpt.getParams(ft.junctionType())) :
speedModel.predict(ft.features(), ft.categories());

if (speedFactor > speedFactorBounds[1]) {
log.warn("Reducing speed factor on {} from {} to {}", link.getId(), speedFactor, speedFactorBounds[1]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.matsim.application.analysis.traffic.traveltime.SampleValidationRoutes;
import org.matsim.application.options.InputOptions;
import org.matsim.application.options.OutputOptions;
import org.matsim.application.prepare.Predictor;
import org.matsim.contrib.osm.networkReader.LinkProperties;
import org.matsim.core.network.NetworkUtils;
import picocli.CommandLine;
Expand Down Expand Up @@ -104,7 +105,7 @@ static Result applyAndEvaluateParams(
continue;
}

FeatureRegressor speedModel = model.speedFactor(ft.junctionType(), ft.highwayType());
Predictor speedModel = model.speedFactor(ft.junctionType(), ft.highwayType());

if (speedModel == null) {
link.setFreespeed(allowedSpeed);
Expand All @@ -115,15 +116,15 @@ static Result applyAndEvaluateParams(

if (request.hasParams()) {
double[] p = request.getParams(ft.junctionType());
speedFactor = speedModel.predict(ft.features(), p);
speedFactor = speedModel.predict(ft.features(), ft.categories(), p);
} else
speedFactor = speedModel.predict(ft.features());
speedFactor = speedModel.predict(ft.features(), ft.categories());

// apply lower and upper bound
speedFactor = Math.max(speedFactorBounds[0], speedFactor);
speedFactor = Math.min(speedFactorBounds[1], speedFactor);

attributes.put(link.getId(), speedModel.getData(ft.features()));
attributes.put(link.getId(), speedModel.getData(ft.features(), ft.categories()));

link.setFreespeed(allowedSpeed * speedFactor);
link.getAttributes().putAttribute("speed_factor", speedFactor);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package org.matsim.application.prepare.network.params;

import it.unimi.dsi.fastutil.objects.Object2DoubleMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
import org.matsim.application.prepare.Predictor;

/**
* Predictor interface for regression.
* @deprecated Use {@link Predictor} instead.
*/
public interface FeatureRegressor {
@Deprecated
public interface FeatureRegressor extends Predictor {


/**
Expand All @@ -28,4 +32,22 @@ default double[] getData(Object2DoubleMap<String> ft) {
throw new UnsupportedOperationException("Not implemented");
}

default double predict(Object2DoubleMap<String> features, Object2ObjectMap<String, String> categories) {
return predict(features);
}

/**
* Predict values with adjusted model params.
*/
default double predict(Object2DoubleMap<String> features, Object2ObjectMap<String, String> categories, double[] params) {
return predict(features, params);
}

/**
* Return data that is used for internal prediction function (normalization already applied).
*/
default double[] getData(Object2DoubleMap<String> features, Object2ObjectMap<String, String> categories) {
return getData(features);
}

}
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
package org.matsim.application.prepare.network.params;

import org.matsim.application.prepare.Predictor;

/**
* A model for estimating network parameters.
*/
public interface NetworkModel {

/**
* Flow Capacity (per lane)
* Flow Capacity (per lane).
*/
default FeatureRegressor capacity(String junctionType, String highwayType) {
return null;
default Predictor capacity(String junctionType, String highwayType) {
throw new UnsupportedOperationException("Capacity model not implemented for class: " + getClass().getName());
}

/**
* Speed factor (relative to free flow speed).
* Speed factor (relative to allowed speed).
*/
default FeatureRegressor speedFactor(String junctionType, String highwayType) {
return null;
default Predictor speedFactor(String junctionType, String highwayType) {
throw new UnsupportedOperationException("Speed factor model not implemented for class: " + getClass().getName());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.objects.Object2DoubleMap;
import it.unimi.dsi.fastutil.objects.Object2DoubleOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVPrinter;
Expand Down Expand Up @@ -74,6 +76,7 @@ static Map<Id<Link>, Feature> readFeatures(String input, Map<Id<Link>, ? extends

Object2DoubleOpenHashMap<String> ft = new Object2DoubleOpenHashMap<>();
ft.defaultReturnValue(Double.NaN);
Object2ObjectMap<String, String> categories = new Object2ObjectOpenHashMap<>();

for (String column : header) {
String v = row.get(column);
Expand All @@ -82,13 +85,14 @@ static Map<Id<Link>, Feature> readFeatures(String input, Map<Id<Link>, ? extends
} catch (NumberFormatException e) {
// every not equal to True will be false
ft.put(column, Boolean.parseBoolean(v) ? 1 : 0);
categories.put(column, v);
}
}

String highwayType = header.contains(NetworkUtils.TYPE) ? row.get(NetworkUtils.TYPE) :
(link != null ? NetworkUtils.getHighwayType(link) : null);

features.put(id, new Feature(row.get("junction_type"), highwayType, ft));
features.put(id, new Feature(row.get("junction_type").intern(), highwayType, ft, categories));
}
}

Expand Down Expand Up @@ -177,7 +181,7 @@ static Result evaluate(Network network, Object2DoubleMap<SampleValidationRoutes.
return new Result(rmse.getMean(), mse.getMean(), data);
}

record Feature(String junctionType, String highwayType, Object2DoubleMap<String> features) {
record Feature(String junctionType, String highwayType, Object2DoubleMap<String> features, Object2ObjectMap<String, String> categories) {
}

record Result(double rmse, double mae, Map<String, List<Data>> data) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.matsim.application.prepare.network.params.hbs;

import it.unimi.dsi.fastutil.objects.Object2DoubleMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
import org.matsim.application.prepare.Predictor;

/**
* Capacity for motorways.
*/
public class HBSMotorwayCapacity implements Predictor {
@Override
public double predict(Object2DoubleMap<String> features, Object2ObjectMap<String, String> categories) {
return 0;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.matsim.application.prepare.network.params.hbs;

import org.matsim.application.prepare.network.params.FeatureRegressor;
import org.matsim.application.prepare.Predictor;
import org.matsim.application.prepare.network.params.NetworkModel;

/**
Expand All @@ -9,20 +9,26 @@
*/
public class HBSNetworkParams implements NetworkModel {

private static final FeatureRegressor MOTORWAY = new HSBMotorwayCapacity();
private static final FeatureRegressor ROAD = new HBSRoadCapacity();
private static final Predictor MOTORWAY = new HBSMotorwayCapacity();
private static final Predictor ROAD = new HBSRoadCapacity();
private static final Predictor SIDEROAD = new HBSSideRoadCapacity();

@Override
public FeatureRegressor capacity(String junctionType, String highwayType) {
public Predictor capacity(String junctionType, String highwayType) {

// Traffic lights are not considered
if (junctionType.equals("traffic_light")) {
return null;
}

if (highwayType.startsWith("motorway")) {
return MOTORWAY;
} else if (junctionType.startsWith("priority")) {
// All other roads
} else if (highwayType.startsWith("trunk") || highwayType.startsWith("primary") || highwayType.startsWith("secondary")) {
return ROAD;
}

throw new UnsupportedOperationException("Unknown type: " + junctionType);
// All lower category roads
return SIDEROAD;
}

}
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
package org.matsim.application.prepare.network.params.hbs;

import it.unimi.dsi.fastutil.objects.Object2DoubleMap;
import org.matsim.application.prepare.network.params.FeatureRegressor;
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
import org.matsim.application.prepare.Predictor;

/**
* See {@link HBSNetworkParams}.
* Capacity for general roads, that are not motorways or residential roads.
*/
class HBSRoadCapacity implements FeatureRegressor {
public class HBSRoadCapacity implements Predictor {
@Override
public double predict(Object2DoubleMap<String> ft) {

public double predict(Object2DoubleMap<String> features, Object2ObjectMap<String, String> categories) {
return 0;

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package org.matsim.application.prepare.network.params.hbs;

import it.unimi.dsi.fastutil.objects.Object2DoubleMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
import org.matsim.application.prepare.Predictor;

/**
* Road capacity for residential roads or other of similar or lower category.
*/
public class HBSSideRoadCapacity implements Predictor {
@Override
public double predict(Object2DoubleMap<String> features, Object2ObjectMap<String, String> categories) {

return 0;


}

/**
* Capacity of a side road merging into a main road.
*/
public double capacityMerging(Object2DoubleMap<String> features) {

// See HBS page 5-20, eq. S5-12 table S5-5

// mean Folgezeitlücken of the different combinations
double tf = 3.5;

// mean Grenzzeitlücke
double tg = 6.36;

// traffic volume on the main road
// here an assumption needs to be made, normally the capacity of the side roads would not be constant
double qP = 400;

return Math.exp( (-qP/3600) * (tg - tf/2)) * 3600/tf;
}

}

This file was deleted.

Loading

0 comments on commit 51ebdfa

Please sign in to comment.