Skip to content

Commit d1b19f6

Browse files
authored
Merge branch 'develop' into fix_emissions_osmhbefamapping
2 parents ec3ef18 + b338bf8 commit d1b19f6

31 files changed

+1045
-0
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ included in the (note yet determined) next version number.
77
**Development version**
88

99
- Improve Emissions tools in order to handle unknown Osm highway tag values when mapping HBEFA road types
10+
- add configurable policies for IDF
1011
- Introduce `travelTimeRecordingInterval` config option that decouples travel time writing from general analysis
1112
- Add eqasim_activities.csv for analysis
1213
- The cutters now take a GeoPackage file as an alterative to a ShapeFile
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
package org.eqasim.ile_de_france;
22

33
import org.eqasim.core.simulation.EqasimConfigurator;
4+
import org.eqasim.ile_de_france.policies.PoliciesConfigGroup;
45

56
public class IDFConfigurator extends EqasimConfigurator {
7+
public IDFConfigurator() {
8+
super();
69

10+
registerConfigGroup(new PoliciesConfigGroup(), true);
11+
}
712
}

ile_de_france/src/main/java/org/eqasim/ile_de_france/RunSimulation.java

+5
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import org.eqasim.core.simulation.analysis.EqasimAnalysisModule;
55
import org.eqasim.core.simulation.mode_choice.EqasimModeChoiceModule;
66
import org.eqasim.ile_de_france.mode_choice.IDFModeChoiceModule;
7+
import org.eqasim.ile_de_france.policies.PolicyExtension;
78
import org.matsim.api.core.v01.Scenario;
89
import org.matsim.core.config.CommandLine;
910
import org.matsim.core.config.CommandLine.ConfigurationException;
@@ -25,6 +26,9 @@ static public void main(String[] args) throws ConfigurationException {
2526
cmd.applyConfiguration(config);
2627
VehiclesValidator.validate(config);
2728

29+
PolicyExtension policies = new PolicyExtension();
30+
policies.adaptConfiguration(config);
31+
2832
Scenario scenario = ScenarioUtils.createScenario(config);
2933
configurator.configureScenario(scenario);
3034
ScenarioUtils.loadScenario(scenario);
@@ -35,6 +39,7 @@ static public void main(String[] args) throws ConfigurationException {
3539
controller.addOverridingModule(new EqasimAnalysisModule());
3640
controller.addOverridingModule(new EqasimModeChoiceModule());
3741
controller.addOverridingModule(new IDFModeChoiceModule(cmd));
42+
controller.addOverridingModule(policies);
3843
controller.run();
3944
}
4045
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package org.eqasim.ile_de_france.policies;
2+
3+
import org.eqasim.ile_de_france.policies.mode_choice.UtilityPenalty;
4+
import org.eqasim.ile_de_france.policies.routing.RoutingPenalty;
5+
6+
public class DefaultPolicy implements Policy {
7+
private final RoutingPenalty routingPenalty;
8+
private final UtilityPenalty utilityPenalty;
9+
10+
public DefaultPolicy(RoutingPenalty routingPenalty, UtilityPenalty utilityPenalty) {
11+
this.routingPenalty = routingPenalty;
12+
this.utilityPenalty = utilityPenalty;
13+
}
14+
15+
@Override
16+
public RoutingPenalty getRoutingPenalty() {
17+
return routingPenalty;
18+
}
19+
20+
@Override
21+
public UtilityPenalty getUtilityPenalty() {
22+
return utilityPenalty;
23+
}
24+
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package org.eqasim.ile_de_france.policies;
2+
3+
import org.eqasim.ile_de_france.policies.city_tax.CityTaxConfigGroup;
4+
import org.eqasim.ile_de_france.policies.city_tax.CityTaxPolicyFactory;
5+
import org.eqasim.ile_de_france.policies.limited_traffic_zone.LimitedTrafficZoneConfigGroup;
6+
import org.eqasim.ile_de_france.policies.limited_traffic_zone.LimitedTrafficZonePolicyFactory;
7+
import org.eqasim.ile_de_france.policies.transit_discount.TransitDiscountConfigGroup;
8+
import org.eqasim.ile_de_france.policies.transit_discount.TransitDiscountPolicyFactory;
9+
import org.matsim.core.config.Config;
10+
import org.matsim.core.config.ConfigGroup;
11+
import org.matsim.core.config.ReflectiveConfigGroup;
12+
13+
public class PoliciesConfigGroup extends ReflectiveConfigGroup {
14+
static public final String CONFIG_NAME = "eqasim:policies";
15+
16+
public PoliciesConfigGroup() {
17+
super(CONFIG_NAME);
18+
}
19+
20+
@Override
21+
public ConfigGroup createParameterSet(String type) {
22+
switch (type) {
23+
case CityTaxPolicyFactory.POLICY_NAME:
24+
return new CityTaxConfigGroup();
25+
case LimitedTrafficZonePolicyFactory.POLICY_NAME:
26+
return new LimitedTrafficZoneConfigGroup();
27+
case TransitDiscountPolicyFactory.POLICY_NAME:
28+
return new TransitDiscountConfigGroup();
29+
default:
30+
throw new IllegalStateException();
31+
}
32+
}
33+
34+
static public PoliciesConfigGroup get(Config config) {
35+
return (PoliciesConfigGroup) config.getModules().get(CONFIG_NAME);
36+
}
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package org.eqasim.ile_de_france.policies;
2+
3+
import org.eqasim.ile_de_france.policies.mode_choice.UtilityPenalty;
4+
import org.eqasim.ile_de_france.policies.routing.RoutingPenalty;
5+
6+
public interface Policy {
7+
RoutingPenalty getRoutingPenalty();
8+
9+
UtilityPenalty getUtilityPenalty();
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package org.eqasim.ile_de_france.policies;
2+
3+
import org.matsim.core.config.ReflectiveConfigGroup;
4+
5+
public abstract class PolicyConfigGroup extends ReflectiveConfigGroup {
6+
protected PolicyConfigGroup(String name) {
7+
super(name);
8+
}
9+
10+
@Parameter
11+
public String policyName;
12+
13+
@Parameter
14+
public boolean active = true;
15+
16+
@Parameter
17+
public String personFilter;
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
package org.eqasim.ile_de_france.policies;
2+
3+
import java.util.HashMap;
4+
import java.util.HashSet;
5+
import java.util.LinkedList;
6+
import java.util.List;
7+
import java.util.Map;
8+
import java.util.Set;
9+
10+
import org.eqasim.core.components.config.EqasimConfigGroup;
11+
import org.eqasim.core.simulation.mode_choice.AbstractEqasimExtension;
12+
import org.eqasim.core.simulation.mode_choice.utilities.UtilityEstimator;
13+
import org.eqasim.ile_de_france.policies.city_tax.CityTaxPolicyExtension;
14+
import org.eqasim.ile_de_france.policies.city_tax.CityTaxPolicyFactory;
15+
import org.eqasim.ile_de_france.policies.limited_traffic_zone.LimitedTrafficZonePolicyExtension;
16+
import org.eqasim.ile_de_france.policies.limited_traffic_zone.LimitedTrafficZonePolicyFactory;
17+
import org.eqasim.ile_de_france.policies.mode_choice.PolicyUtilityEstimator;
18+
import org.eqasim.ile_de_france.policies.mode_choice.SumUtilityPenalty;
19+
import org.eqasim.ile_de_france.policies.mode_choice.UtilityPenalty;
20+
import org.eqasim.ile_de_france.policies.routing.PolicyTravelDisutilityFactory;
21+
import org.eqasim.ile_de_france.policies.routing.RoutingPenalty;
22+
import org.eqasim.ile_de_france.policies.routing.SumRoutingPenalty;
23+
import org.eqasim.ile_de_france.policies.transit_discount.TransitDiscountPolicyExtension;
24+
import org.eqasim.ile_de_france.policies.transit_discount.TransitDiscountPolicyFactory;
25+
import org.matsim.api.core.v01.TransportMode;
26+
import org.matsim.api.core.v01.population.Population;
27+
import org.matsim.core.config.Config;
28+
import org.matsim.core.router.costcalculators.OnlyTimeDependentTravelDisutilityFactory;
29+
30+
import com.google.common.base.Verify;
31+
import com.google.inject.Key;
32+
import com.google.inject.Provider;
33+
import com.google.inject.Provides;
34+
import com.google.inject.Singleton;
35+
import com.google.inject.multibindings.MapBinder;
36+
import com.google.inject.name.Named;
37+
import com.google.inject.name.Names;
38+
39+
public class PolicyExtension extends AbstractEqasimExtension {
40+
private final static String ESTIMATOR_PREFIX = "policy:";
41+
42+
private String delegateCarEstimator;
43+
private String delegateTransitEstimator;
44+
45+
public void adaptConfiguration(Config config) {
46+
EqasimConfigGroup eqasimConfig = EqasimConfigGroup.get(config);
47+
48+
delegateCarEstimator = eqasimConfig.getEstimators().get(TransportMode.car);
49+
delegateTransitEstimator = eqasimConfig.getEstimators().get(TransportMode.pt);
50+
51+
delegateCarEstimator = delegateCarEstimator.replace(ESTIMATOR_PREFIX, "");
52+
delegateTransitEstimator = delegateTransitEstimator.replace(ESTIMATOR_PREFIX, "");
53+
54+
eqasimConfig.setEstimator(TransportMode.car, ESTIMATOR_PREFIX + delegateCarEstimator);
55+
eqasimConfig.setEstimator(TransportMode.pt, ESTIMATOR_PREFIX + delegateTransitEstimator);
56+
}
57+
58+
@Override
59+
protected void installEqasimExtension() {
60+
Verify.verifyNotNull(delegateCarEstimator, "Need to run PolicyExtension.adaptConfiguration first");
61+
Verify.verifyNotNull(delegateTransitEstimator, "Need to run PolicyExtension.adaptConfiguration first");
62+
63+
// set up travel disutility for routing
64+
addTravelDisutilityFactoryBinding(TransportMode.car).to(PolicyTravelDisutilityFactory.class);
65+
addTravelDisutilityFactoryBinding("car_passenger").to(OnlyTimeDependentTravelDisutilityFactory.class);
66+
67+
install(new CityTaxPolicyExtension());
68+
install(new LimitedTrafficZonePolicyExtension());
69+
install(new TransitDiscountPolicyExtension());
70+
71+
var policyBinder = MapBinder.newMapBinder(binder(), String.class, PolicyFactory.class);
72+
policyBinder.addBinding(CityTaxPolicyFactory.POLICY_NAME).to(CityTaxPolicyFactory.class);
73+
policyBinder.addBinding(LimitedTrafficZonePolicyFactory.POLICY_NAME).to(LimitedTrafficZonePolicyFactory.class);
74+
policyBinder.addBinding(TransitDiscountPolicyFactory.POLICY_NAME).to(TransitDiscountPolicyFactory.class);
75+
76+
bindUtilityEstimator(ESTIMATOR_PREFIX + delegateCarEstimator)
77+
.to(Key.get(PolicyUtilityEstimator.class, Names.named(TransportMode.car)));
78+
79+
bindUtilityEstimator(ESTIMATOR_PREFIX + delegateTransitEstimator)
80+
.to(Key.get(PolicyUtilityEstimator.class, Names.named(TransportMode.pt)));
81+
}
82+
83+
@Provides
84+
@Singleton
85+
Map<String, Policy> providePolicies(Map<String, PolicyFactory> factories, Population population) {
86+
PoliciesConfigGroup policyConfig = PoliciesConfigGroup.get(getConfig());
87+
Map<String, Policy> policies = new HashMap<>();
88+
89+
Set<String> names = new HashSet<>();
90+
91+
if (policyConfig != null) {
92+
for (var collection : policyConfig.getParameterSets().values()) {
93+
for (var raw : collection) {
94+
PolicyConfigGroup policy = (PolicyConfigGroup) raw;
95+
96+
if (policy.active) {
97+
Verify.verify(policy.policyName != null && policy.policyName.length() > 0,
98+
"Policy names must be set");
99+
100+
if (!names.add(policy.policyName)) {
101+
throw new IllegalStateException("Duplicate policy name: " + policy.policyName);
102+
}
103+
104+
PolicyPersonFilter filter = PolicyPersonFilter.create(population, policy);
105+
106+
policies.put(policy.policyName,
107+
factories.get(policy.getName()).createPolicy(policy.policyName, filter));
108+
}
109+
}
110+
}
111+
}
112+
113+
return policies;
114+
}
115+
116+
@Provides
117+
@Singleton
118+
PolicyTravelDisutilityFactory providePolicyTravelDisutilityFactory(RoutingPenalty linkPenalty) {
119+
return new PolicyTravelDisutilityFactory(linkPenalty);
120+
}
121+
122+
@Provides
123+
@Named(TransportMode.car)
124+
PolicyUtilityEstimator providePolicyUtilityEstimatorForCar(Map<String, Provider<UtilityEstimator>> providers,
125+
UtilityPenalty penalty) {
126+
UtilityEstimator delegate = providers.get(delegateCarEstimator).get();
127+
return new PolicyUtilityEstimator(delegate, penalty, TransportMode.car);
128+
}
129+
130+
@Provides
131+
@Named(TransportMode.pt)
132+
PolicyUtilityEstimator providePolicyUtilityEstimatorForTransit(Map<String, Provider<UtilityEstimator>> providers,
133+
UtilityPenalty penalty) {
134+
UtilityEstimator delegate = providers.get(delegateTransitEstimator).get();
135+
return new PolicyUtilityEstimator(delegate, penalty, TransportMode.pt);
136+
}
137+
138+
@Provides
139+
UtilityPenalty provideUtilityPenalty(Map<String, Policy> policies) {
140+
List<UtilityPenalty> penalties = new LinkedList<>();
141+
142+
for (Policy policy : policies.values()) {
143+
UtilityPenalty penalty = policy.getUtilityPenalty();
144+
145+
if (penalty != null) {
146+
penalties.add(penalty);
147+
}
148+
}
149+
150+
return new SumUtilityPenalty(penalties);
151+
}
152+
153+
@Provides
154+
RoutingPenalty provideRoutingPenalty(Map<String, Policy> policies) {
155+
List<RoutingPenalty> penalties = new LinkedList<>();
156+
157+
for (Policy policy : policies.values()) {
158+
RoutingPenalty penalty = policy.getRoutingPenalty();
159+
160+
if (penalty != null) {
161+
penalties.add(penalty);
162+
}
163+
}
164+
165+
return new SumRoutingPenalty(penalties);
166+
}
167+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package org.eqasim.ile_de_france.policies;
2+
3+
public interface PolicyFactory {
4+
Policy createPolicy(String name, PolicyPersonFilter personFilter);
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package org.eqasim.ile_de_france.policies;
2+
3+
import org.matsim.api.core.v01.Id;
4+
import org.matsim.api.core.v01.IdSet;
5+
import org.matsim.api.core.v01.population.Person;
6+
import org.matsim.api.core.v01.population.Population;
7+
8+
public class PolicyPersonFilter {
9+
private final IdSet<Person> selection;
10+
11+
PolicyPersonFilter(IdSet<Person> selection) {
12+
this.selection = selection;
13+
}
14+
15+
public boolean applies(Id<Person> personId) {
16+
return selection == null ? true : selection.contains(personId);
17+
}
18+
19+
static public PolicyPersonFilter create(Population population, PolicyConfigGroup policy) {
20+
if (policy.personFilter != null && policy.personFilter.length() > 0) {
21+
IdSet<Person> selection = new IdSet<>(Person.class);
22+
23+
for (Person person : population.getPersons().values()) {
24+
Boolean indicator = (Boolean) person.getAttributes().getAttribute(policy.personFilter);
25+
26+
if (indicator != null && indicator) {
27+
selection.add(person.getId());
28+
}
29+
}
30+
31+
return new PolicyPersonFilter(selection);
32+
} else {
33+
return new PolicyPersonFilter(null);
34+
}
35+
}
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package org.eqasim.ile_de_france.policies.city_tax;
2+
3+
import org.eqasim.ile_de_france.policies.PolicyConfigGroup;
4+
import org.matsim.core.config.ReflectiveConfigGroup.Parameter;
5+
6+
public class CityTaxConfigGroup extends PolicyConfigGroup {
7+
public CityTaxConfigGroup() {
8+
super(CityTaxPolicyFactory.POLICY_NAME);
9+
}
10+
11+
@Parameter
12+
public double tax_EUR = 0.0;
13+
14+
@Parameter
15+
public String perimetersPath;
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package org.eqasim.ile_de_france.policies.city_tax;
2+
3+
import org.eqasim.core.simulation.mode_choice.AbstractEqasimExtension;
4+
import org.eqasim.ile_de_france.mode_choice.parameters.IDFModeParameters;
5+
import org.matsim.api.core.v01.network.Network;
6+
7+
import com.google.inject.Provides;
8+
import com.google.inject.Singleton;
9+
10+
public class CityTaxPolicyExtension extends AbstractEqasimExtension {
11+
@Override
12+
protected void installEqasimExtension() {
13+
}
14+
15+
@Provides
16+
@Singleton
17+
CityTaxPolicyFactory provideCityTaxPolicyFactory(Network network, IDFModeParameters modeParameters) {
18+
return new CityTaxPolicyFactory(getConfig(), network, modeParameters);
19+
}
20+
}

0 commit comments

Comments
 (0)