Skip to content

Commit

Permalink
add scenario specific RoadPricingModule to prevent using 2 ControlerL…
Browse files Browse the repository at this point in the history
…isteners for the same purpose at the same time. This is ugly, but a quick fix is needed.
  • Loading branch information
simei94 committed Mar 30, 2024
1 parent a956bf2 commit 4c8b575
Show file tree
Hide file tree
Showing 10 changed files with 498 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ private void writeIncomeDistr(Table joined) {
aggr.sortOn(this.share);

List<String> incomeDistr = new ArrayList<>();
incomeDistr.add("incomeGroup,Count [person],share");

for (String k : labels.keySet()) {
for (int i = 0; i < aggr.rowCount() - 1; i++) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
* *
* *********************************************************************** */

package org.matsim.run;
package org.matsim.run.MexicoCityRoadPricing;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
* *
* *********************************************************************** */

package org.matsim.run;
package org.matsim.run.MexicoCityRoadPricing;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
* *********************************************************************** *
* * project: org.matsim.*
* * PlansCalcRouteWithTollOrNot.java
* * *
* * *********************************************************************** *
* * *
* * copyright : (C) 2015 by the members listed in the COPYING, *
* * LICENSE and WARRANTY file. *
* * email : info at matsim dot org *
* * *
* * *********************************************************************** *
* * *
* * This program is free software; you can redistribute it and/or modify *
* * it under the terms of the GNU General Public License as published by *
* * the Free Software Foundation; either version 2 of the License, or *
* * (at your option) any later version. *
* * See also COPYING, LICENSE and WARRANTY file *
* * *
* * ***********************************************************************
*/

package org.matsim.run.MexicoCityRoadPricing;

import jakarta.inject.Inject;
import jakarta.inject.Provider;
import org.matsim.api.core.v01.TransportMode;
import org.matsim.api.core.v01.population.Leg;
import org.matsim.api.core.v01.population.Plan;
import org.matsim.api.core.v01.population.PlanElement;
import org.matsim.contrib.roadpricing.RoadPricingScheme;
import org.matsim.core.population.algorithms.PlanAlgorithm;
import org.matsim.core.population.routes.NetworkRoute;
import org.matsim.core.router.PlanRouter;
import org.matsim.core.router.TripRouter;
import org.matsim.core.router.TripStructureUtils;
import org.matsim.core.utils.timing.TimeInterpretation;


/**
* copied from org.matsim.contrib.roadpricing.
*/
class MexicoCityPlansCalcRouteWithTollOrNot implements PlanAlgorithm {

static final String CAR_WITH_PAYED_AREA_TOLL = "car_with_payed_area_toll";
private RoadPricingScheme roadPricingScheme;
private final PlanRouter planRouter ;

@Inject
MexicoCityPlansCalcRouteWithTollOrNot(RoadPricingScheme roadPricingScheme, Provider<TripRouter> tripRouterProvider, TimeInterpretation timeInterpretation) {
this.roadPricingScheme = roadPricingScheme;
this.planRouter = new PlanRouter( tripRouterProvider.get(), timeInterpretation ) ;
}

@Override
public void run(final Plan plan) {
handlePlan(plan);
}

private void handlePlan(Plan plan) {
// This calculates a best-response plan from the two options, paying area toll or not.
// From what I understand, it may be simpler/better to just throw a coin and produce
// one of the two options.
replaceCarModeWithTolledCarMode(plan);
planRouter.run( plan );
double areaToll = roadPricingScheme.getTypicalCosts().iterator().next().amount;
double routeCostWithAreaToll = sumNetworkModeCosts(plan) + areaToll;
replaceTolledCarModeWithCarMode(plan);
planRouter.run( plan );
double routeCostWithoutAreaToll = sumNetworkModeCosts(plan);
if (routeCostWithAreaToll < routeCostWithoutAreaToll) {
replaceCarModeWithTolledCarMode(plan);
planRouter.run( plan );
}
}

// This most likely will not work for intermodal setups with car e.g. as access mode to pt and routing mode of the trip
// something else than car.
// However, it did not work before the switch to routing mode either. - gl-nov'19
private void replaceCarModeWithTolledCarMode(Plan plan) {
for (PlanElement planElement : plan.getPlanElements()) {
if (planElement instanceof Leg) {
if (TripStructureUtils.getRoutingMode((Leg) planElement).equals(TransportMode.car)) {
TripStructureUtils.setRoutingMode( (Leg) planElement , CAR_WITH_PAYED_AREA_TOLL );
}
}
}
}

private void replaceTolledCarModeWithCarMode(Plan plan) {
for (PlanElement planElement : plan.getPlanElements()) {
if (planElement instanceof Leg) {
if (TripStructureUtils.getRoutingMode((Leg) planElement).equals(CAR_WITH_PAYED_AREA_TOLL)) {
TripStructureUtils.setRoutingMode( (Leg) planElement , TransportMode.car );
}
}
}
}

private double sumNetworkModeCosts(Plan plan) {
double sum = 0.0;
for (PlanElement planElement : plan.getPlanElements()) {
if (planElement instanceof Leg) {
Leg leg = (Leg) planElement;
if (leg.getRoute() instanceof NetworkRoute) {
NetworkRoute networkRoute = (NetworkRoute) leg.getRoute();
sum += networkRoute.getTravelCost();
}
}
}
return sum;
}

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* *********************************************************************** *
* * project: org.matsim.*
* * ReRouteAreaToll.java
* * *
* * *********************************************************************** *
* * *
* * copyright : (C) 2015 by the members listed in the COPYING, *
* * LICENSE and WARRANTY file. *
* * email : info at matsim dot org *
* * *
* * *********************************************************************** *
* * *
* * This program is free software; you can redistribute it and/or modify *
* * it under the terms of the GNU General Public License as published by *
* * the Free Software Foundation; either version 2 of the License, or *
* * (at your option) any later version. *
* * See also COPYING, LICENSE and WARRANTY file *
* * *
* * ***********************************************************************
*/

package org.matsim.run.MexicoCityRoadPricing;

import jakarta.inject.Inject;
import jakarta.inject.Provider;
import org.matsim.contrib.roadpricing.RoadPricingScheme;
import org.matsim.core.config.Config;
import org.matsim.core.population.algorithms.PlanAlgorithm;
import org.matsim.core.replanning.PlanStrategy;
import org.matsim.core.replanning.PlanStrategyImpl;
import org.matsim.core.replanning.modules.AbstractMultithreadedModule;
import org.matsim.core.replanning.selectors.RandomPlanSelector;
import org.matsim.core.router.TripRouter;
import org.matsim.core.utils.timing.TimeInterpretation;

/**
* copied from org.matsim.contrib.roadpricing.
*/
class MexicoCityReRouteAreaToll implements Provider<PlanStrategy> {

private final Config config;
private RoadPricingScheme roadPricingScheme;
private Provider<TripRouter> tripRouterFactory;
private final TimeInterpretation timeInterpretation;
// private final Provider<PlansCalcRouteWithTollOrNot> factory;

@Inject
MexicoCityReRouteAreaToll(Config config, RoadPricingScheme roadPricingScheme, Provider<TripRouter> tripRouterFactory, TimeInterpretation timeInterpretation ) {
this.config = config;
// this.factory = factory;
this.roadPricingScheme = roadPricingScheme;
this.tripRouterFactory = tripRouterFactory;
this.timeInterpretation = timeInterpretation;
}

@Override
public PlanStrategy get() {
PlanStrategyImpl.Builder builder = new PlanStrategyImpl.Builder(new RandomPlanSelector<>());
builder.addStrategyModule(new AbstractMultithreadedModule(config.global()) {
@Override
public PlanAlgorithm getPlanAlgoInstance() {
return new MexicoCityPlansCalcRouteWithTollOrNot( roadPricingScheme, tripRouterFactory, timeInterpretation ) ;
}
});
return builder.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
* *
* *********************************************************************** */

package org.matsim.run;
package org.matsim.run.MexicoCityRoadPricing;

import jakarta.inject.Inject;
import org.apache.logging.log4j.LogManager;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package org.matsim.run.MexicoCityRoadPricing;

import com.google.inject.Singleton;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.matsim.api.core.v01.TransportMode;
import org.matsim.contrib.roadpricing.*;
import org.matsim.core.config.ConfigUtils;
import org.matsim.core.controler.AbstractModule;
import org.matsim.core.router.costcalculators.RandomizingTimeDistanceTravelDisutilityFactory;
import org.matsim.run.MexicoCityRoadPricing.MexicoCityRoadPricingModuleDefaults.*;

/**
* copied from org.matsim.contrib.roadpricing.
*/
public final class MexicoCityRoadPricingModule extends AbstractModule {
final Logger log = LogManager.getLogger(MexicoCityRoadPricingModule.class);

private RoadPricingScheme scheme;

public MexicoCityRoadPricingModule() {}

/* For the time being this has to be public, otherwise the roadpricing TollFactor
cannot be considered, rendering integration tests useless, JWJ Jan'20 */
public MexicoCityRoadPricingModule(RoadPricingScheme scheme ) {
this.scheme = scheme;
}

@Override
public void install() {
ConfigUtils.addOrGetModule(getConfig(), RoadPricingConfigGroup.class);

// TODO sort out different ways to set toll schemes; reduce automagic
// TODO JWJ: is this still too "automagic"?
if ( scheme != null) {
// scheme has come in from the constructor, use that one:
bind(RoadPricingScheme.class).toInstance(scheme);
} else {
// no scheme has come in from the constructor, use a class that reads it from file:
bind(RoadPricingScheme.class).toProvider(RoadPricingSchemeProvider.class).in(Singleton.class);
}
// also add RoadPricingScheme as ScenarioElement. yyyy TODO might try to get rid of this; binding it is safer
// (My personal preference is actually to have it as scenario element ... since then it can be set before controler is even called. Which
// certainly makes more sense for a clean build sequence. kai, oct'19)
bind(RoadPricingInitializer.class).in( Singleton.class );

// add the toll to the routing disutility. also includes "randomizing":
addTravelDisutilityFactoryBinding(TransportMode.car).toProvider(TravelDisutilityIncludingTollFactoryProvider.class);

// // specific re-routing strategy for area toll:
// // yyyy TODO could probably combine them somewhat
addPlanStrategyBinding("ReRouteAreaToll").toProvider(MexicoCityReRouteAreaToll.class);
addTravelDisutilityFactoryBinding( MexicoCityPlansCalcRouteWithTollOrNot.CAR_WITH_PAYED_AREA_TOLL ).toInstance(new RandomizingTimeDistanceTravelDisutilityFactory(TransportMode.car, getConfig()) );
addRoutingModuleBinding( MexicoCityPlansCalcRouteWithTollOrNot.CAR_WITH_PAYED_AREA_TOLL ).toProvider(new MexicoCityRoadPricingNetworkRouting() );

// yyyy TODO It might be possible that the area stuff is adequately resolved by the randomizing approach. Would need to try
// that out. kai, sep'16

// this is what makes the mobsim compute tolls and generate money events
addControlerListenerBinding().to(MexicoCityRoadPricingControlerListener.class);

}
}
Loading

0 comments on commit 4c8b575

Please sign in to comment.