Commit 6820556f authored by Sebastian Hörl's avatar Sebastian Hörl
Browse files

Implement SP model

parent 7b8d75e8
......@@ -59,19 +59,19 @@
<dependencies>
<dependency>
<groupId>ch.ethz.matsim</groupId>
<artifactId>av</artifactId>
<version>0.2.6</version>
<artifactId>discrete_mode_choice</artifactId>
<version>1.0.3</version>
</dependency>
<dependency>
<groupId>ch.ethz.matsim</groupId>
<artifactId>baseline_scenario</artifactId>
<version>0.2.0</version>
<artifactId>av</artifactId>
<version>0.2.6</version>
</dependency>
<dependency>
<groupId>ch.ethz.matsim</groupId>
<artifactId>mode_choice</artifactId>
<artifactId>baseline_scenario</artifactId>
<version>0.2.0</version>
</dependency>
......
......@@ -3,8 +3,7 @@ package ch.ethz.matsim.projects.astra_2018_002;
import org.matsim.api.core.v01.Scenario;
import org.matsim.core.config.Config;
import org.matsim.core.config.ConfigUtils;
import org.matsim.core.config.groups.QSimConfigGroup.VehiclesSource;
import org.matsim.core.config.groups.StrategyConfigGroup.StrategySettings;
import org.matsim.core.config.groups.ControlerConfigGroup.RoutingAlgorithmType;
import org.matsim.core.controler.Controler;
import org.matsim.core.scenario.ScenarioUtils;
......@@ -13,40 +12,23 @@ import ch.ethz.matsim.baseline_scenario.config.CommandLine.ConfigurationExceptio
import ch.ethz.matsim.baseline_scenario.transit.BaselineTransitModule;
import ch.ethz.matsim.baseline_scenario.transit.routing.DefaultEnrichedTransitRoute;
import ch.ethz.matsim.baseline_scenario.transit.routing.DefaultEnrichedTransitRouteFactory;
import ch.ethz.matsim.projects.astra_2018_002.mode_choice.ModeChoiceModule;
import ch.ethz.matsim.projects.astra_2018_002.pcu.PCUUtils;
import ch.ethz.matsim.projects.astra_2018_002.mode_choice.SwissDiscreteModeChoiceModule;
import ch.ethz.matsim.projects.astra_2018_002.mode_choice.SwissModeChoiceUtilities;
import ch.sbb.matsim.routing.pt.raptor.SwissRailRaptorModule;
public class RunASTRA2018002 {
static public void main(String[] args) throws ConfigurationException {
CommandLine cmd = new CommandLine.Builder(args) //
.requireOptions("config-path") //
.requireOptions("config-path", "model") //
.build();
// Load config
Config config = ConfigUtils.loadConfig(cmd.getOptionStrict("config-path"));
config.strategy().clearStrategySettings();
// Adjust config
SwissDiscreteModeChoiceModule.configure(config);
StrategySettings strategy = new StrategySettings();
strategy.setStrategyName("custom");
strategy.setWeight(0.2);
config.strategy().addStrategySettings(strategy);
strategy = new StrategySettings();
strategy.setStrategyName("SubtourModeChoice");
strategy.setWeight(0.0);
strategy.setDisableAfter(1);
config.strategy().addStrategySettings(strategy);
strategy = new StrategySettings();
strategy.setStrategyName("KeepLastSelected");
strategy.setWeight(0.8);
config.strategy().addStrategySettings(strategy);
config.qsim().setVehiclesSource(VehiclesSource.modeVehicleTypesFromVehiclesData);
config.travelTimeCalculator().setAnalyzedModes("car,private_av");
// config.travelTimeCalculator().setSeparateModes(true);
config.controler().setRoutingAlgorithmType(RoutingAlgorithmType.FastAStarLandmarks);
cmd.applyConfiguration(config);
......@@ -56,17 +38,25 @@ public class RunASTRA2018002 {
new DefaultEnrichedTransitRouteFactory());
ScenarioUtils.loadScenario(scenario);
// Set up scenario
PCUUtils.defineVehicleTypes(scenario);
// Adjust scenario
SwissModeChoiceUtilities.copyHousholdAttributes(scenario);
// Set up controller
Controler controler = new Controler(scenario);
controler.addOverridingModule(new SwissRailRaptorModule());
controler.addOverridingModule(new BaselineTransitModule());
controler.addOverridingModule(new ModeChoiceModule());
controler.addOverridingModule(new SwissDiscreteModeChoiceModule(cmd.getOptionStrict("model")));
// Run
controler.run();
// PCU
//
// config.qsim().setVehiclesSource(VehiclesSource.modeVehicleTypesFromVehiclesData);
// config.travelTimeCalculator().setAnalyzedModes("car,private_av");
// config.travelTimeCalculator().setSeparateModes(true);
// Set up scenario
// PCUUtils.defineVehicleTypes(scenario);
}
}
package ch.ethz.matsim.projects.astra_2018_002.mode_choice;
import java.util.Arrays;
import java.util.List;
import org.matsim.api.core.v01.network.Network;
import org.matsim.core.config.groups.PlansCalcRouteConfigGroup;
import org.matsim.core.controler.AbstractModule;
import org.matsim.core.router.TripRouter;
import org.matsim.core.router.util.TravelTime;
import org.matsim.facilities.ActivityFacilities;
import org.matsim.pt.transitSchedule.api.TransitSchedule;
import com.google.inject.Provides;
import com.google.inject.name.Named;
import ch.ethz.matsim.baseline_scenario.config.CommandLine.ConfigurationException;
import ch.ethz.matsim.mode_choice.constraints.CompositeTourConstraintFactory;
import ch.ethz.matsim.mode_choice.constraints.TourConstraintFromTripConstraint;
import ch.ethz.matsim.mode_choice.estimation.ModeAwareTripEstimator;
import ch.ethz.matsim.mode_choice.estimation.TourEstimatorFromTripEstimator;
import ch.ethz.matsim.mode_choice.estimation.TripEstimatorCache;
import ch.ethz.matsim.mode_choice.framework.ModeAvailability;
import ch.ethz.matsim.mode_choice.framework.ModeChoiceModel;
import ch.ethz.matsim.mode_choice.framework.ModeChoiceModel.FallbackBehaviour;
import ch.ethz.matsim.mode_choice.framework.tour_based.ActivityTourFinder;
import ch.ethz.matsim.mode_choice.framework.tour_based.TourBasedModel;
import ch.ethz.matsim.mode_choice.framework.tour_based.TourFinder;
import ch.ethz.matsim.mode_choice.framework.tour_based.constraints.TourConstraintFactory;
import ch.ethz.matsim.mode_choice.framework.tour_based.estimation.TourCandidate;
import ch.ethz.matsim.mode_choice.framework.tour_based.estimation.TourEstimator;
import ch.ethz.matsim.mode_choice.framework.trip_based.constraints.TripConstraintFactory;
import ch.ethz.matsim.mode_choice.framework.utilities.MultinomialSelector;
import ch.ethz.matsim.mode_choice.framework.utilities.UtilitySelectorFactory;
import ch.ethz.matsim.mode_choice.framework.utils.DefaultModeChainGenerator;
import ch.ethz.matsim.mode_choice.framework.utils.ModeChainGeneratorFactory;
import ch.ethz.matsim.mode_choice.mode_availability.LicenseAndOwnershipModeAvailability;
import ch.ethz.matsim.mode_choice.prediction.TeleportationPredictor;
import ch.ethz.matsim.mode_choice.replanning.ModeChoiceModelStrategy;
import ch.ethz.matsim.mode_choice.replanning.NonSelectedPlanSelector;
import ch.ethz.matsim.projects.astra_2018_002.mode_choice.constraints.AvoidOnlyWalkConstraint;
import ch.ethz.matsim.projects.astra_2018_002.mode_choice.constraints.VehicleTourConstraint;
import ch.ethz.matsim.projects.astra_2018_002.mode_choice.estimation.ModeChoiceParameters;
import ch.ethz.matsim.projects.astra_2018_002.mode_choice.estimation.car.CarEstimator;
import ch.ethz.matsim.projects.astra_2018_002.mode_choice.estimation.car.CarPredictor;
import ch.ethz.matsim.projects.astra_2018_002.mode_choice.estimation.other.BikeEstimator;
import ch.ethz.matsim.projects.astra_2018_002.mode_choice.estimation.other.WalkEstimator;
import ch.ethz.matsim.projects.astra_2018_002.mode_choice.estimation.pt.PublicTransportEstimator;
import ch.ethz.matsim.projects.astra_2018_002.mode_choice.estimation.pt.PublicTransportPredictor;
public class ModeChoiceModule extends AbstractModule {
private static final List<String> MODES = Arrays.asList("car", "pt", "bike", "walk");
private static final List<String> VEHICLE_MODES = Arrays.asList("car", "bike");
private static final List<String> CACHED_MODES = Arrays.asList("car", "pt", "bike", "walk");
@Override
public void install() {
addPlanStrategyBinding("custom").toProvider(ModeChoiceModelStrategy.class);
bindPlanSelectorForRemoval().to(NonSelectedPlanSelector.class);
bind(ModeChoiceParameters.class).asEagerSingleton();
}
@Provides
public ModeChoiceModel provideModeChoiceModel(PlansCalcRouteConfigGroup routeConfig,
ModeChoiceParameters parameters, TripRouter router, ActivityFacilities facilities, Network network,
@Named("car") TravelTime carTravelTime, TransitSchedule schedule) throws ConfigurationException {
// SET UP ESTIMATORS
// Walk estimator
double crowflyDistanceFactorWalk = routeConfig.getModeRoutingParams().get("walk").getBeelineDistanceFactor();
double speedWalk = routeConfig.getModeRoutingParams().get("walk").getTeleportedModeSpeed();
TeleportationPredictor teleportationPredictorWalk = new TeleportationPredictor(crowflyDistanceFactorWalk,
speedWalk);
WalkEstimator walkEstimator = new WalkEstimator(parameters, teleportationPredictorWalk);
// Bike estimator
double crowflyDistanceFactorBike = routeConfig.getModeRoutingParams().get("bike").getBeelineDistanceFactor();
double speedBike = routeConfig.getModeRoutingParams().get("bike").getTeleportedModeSpeed();
TeleportationPredictor teleportationPredictorBike = new TeleportationPredictor(crowflyDistanceFactorBike,
speedBike);
BikeEstimator bikeEstimator = new BikeEstimator(parameters, teleportationPredictorBike);
// Public transport estimator
PublicTransportPredictor publicTransportPredictor = new PublicTransportPredictor(router, facilities, network);
PublicTransportEstimator publicTransportEstimator = new PublicTransportEstimator(parameters,
publicTransportPredictor);
// Car estimator
CarPredictor carPredictor = new CarPredictor(router, facilities, carTravelTime, network);
CarEstimator carEstimator = new CarEstimator(parameters, carPredictor);
// Create composite estimator
ModeAwareTripEstimator modeAwareEstimator = new ModeAwareTripEstimator();
modeAwareEstimator.addEstimator("walk", walkEstimator);
modeAwareEstimator.addEstimator("bike", bikeEstimator);
modeAwareEstimator.addEstimator("pt", publicTransportEstimator);
modeAwareEstimator.addEstimator("car", carEstimator);
TripEstimatorCache estimator = new TripEstimatorCache(modeAwareEstimator, CACHED_MODES);
// Set up tour estimator
TourEstimator tourEstimator = new TourEstimatorFromTripEstimator(estimator);
// SET UP CONSTRAINTS
// Trip constraints
TripConstraintFactory avoidOnlyWalkConstraintFactory = new AvoidOnlyWalkConstraint.Factory();
// Tour constraints
TourConstraintFactory vehicleContinuityConstraintFactory = new VehicleTourConstraint.Factory(VEHICLE_MODES);
// Combine constraints
CompositeTourConstraintFactory constraintFactory = new CompositeTourConstraintFactory();
constraintFactory.addFactory(new TourConstraintFromTripConstraint.Factory(avoidOnlyWalkConstraintFactory));
constraintFactory.addFactory(vehicleContinuityConstraintFactory);
// SET UP MODEL
ModeAvailability modeAvailability = new LicenseAndOwnershipModeAvailability(MODES);
ModeChainGeneratorFactory modeChainGeneratorFactory = new DefaultModeChainGenerator.Factory();
TourFinder tourFinder = new ActivityTourFinder("home");
UtilitySelectorFactory<TourCandidate> tourSelectorFactory = new MultinomialSelector.Factory<>(700.0);
ModeChoiceModel model = new TourBasedModel(tourEstimator, modeAvailability, constraintFactory, tourFinder,
tourSelectorFactory, modeChainGeneratorFactory, FallbackBehaviour.EXCEPTION);
return model;
}
}
package ch.ethz.matsim.projects.astra_2018_002.mode_choice;
import java.util.Arrays;
import org.matsim.api.core.v01.TransportMode;
import org.matsim.api.core.v01.network.Network;
import org.matsim.core.config.Config;
import org.matsim.core.config.groups.PlanCalcScoreConfigGroup;
import org.matsim.core.config.groups.PlanCalcScoreConfigGroup.ModeParams;
import org.matsim.core.router.TripRouter;
import org.matsim.facilities.ActivityFacilities;
import org.matsim.pt.transitSchedule.api.TransitSchedule;
import com.google.inject.Provides;
import com.google.inject.Singleton;
import ch.ethz.matsim.discrete_mode_choice.modules.AbstractDiscreteModeChoiceExtension;
import ch.ethz.matsim.discrete_mode_choice.modules.ConstraintModule;
import ch.ethz.matsim.discrete_mode_choice.modules.DiscreteModeChoiceConfigurator;
import ch.ethz.matsim.discrete_mode_choice.modules.DiscreteModeChoiceModule;
import ch.ethz.matsim.discrete_mode_choice.modules.EstimatorModule;
import ch.ethz.matsim.discrete_mode_choice.modules.ModeAvailabilityModule;
import ch.ethz.matsim.discrete_mode_choice.modules.ModelModule.ModelType;
import ch.ethz.matsim.discrete_mode_choice.modules.SelectorModule;
import ch.ethz.matsim.discrete_mode_choice.modules.TourFinderModule;
import ch.ethz.matsim.discrete_mode_choice.modules.config.DiscreteModeChoiceConfigGroup;
import ch.ethz.matsim.discrete_mode_choice.modules.config.VehicleTourConstraintConfigGroup.HomeType;
import ch.ethz.matsim.projects.astra_2018_002.mode_choice.cost.CostModel;
import ch.ethz.matsim.projects.astra_2018_002.mode_choice.cost.CostParameters;
public class SwissDiscreteModeChoiceModule extends AbstractDiscreteModeChoiceExtension {
public static final String SWISS_ESTIMATOR_NAME = "Swiss";
private final String model;
public SwissDiscreteModeChoiceModule(String model) {
this.model = model;
}
@Override
protected void installExtension() {
install(new DiscreteModeChoiceModule());
bindTripEstimator(SWISS_ESTIMATOR_NAME).to(SwissUtilityEstimator.class);
}
@Provides
public SwissUtilityEstimator provideLinearWithoutSociodemographicsEstimator(TripRouter tripRouter, Network network,
ActivityFacilities facilities, CostModel costModel, TransitSchedule transitSchedule,
SwissUtilityParameters parameters) {
return new SwissUtilityEstimator(tripRouter, network, facilities, costModel, transitSchedule, parameters);
}
@Provides
@Singleton
public SwissUtilityParameters provideSwissUtilityParameters() {
/*
* TODO: We can make this configurable in a better way.
*/
switch (model) {
case "3.2.1":
return SwissUtilityParameters.buildLinearWithoutSociodemographics(true);
case "3.2.2":
return SwissUtilityParameters.buildLinearWithSociodemographics(true);
default:
throw new IllegalStateException();
}
}
@Provides
@Singleton
public CostModel provideCostModel(CostParameters parameters) {
return new CostModel(parameters);
}
@Provides
@Singleton
public CostParameters provideCostParameters() {
/*
* TODO: We can make this configurable from outside.
*/
return new CostParameters();
}
static public void configure(Config config) {
// Set up discrete choice
DiscreteModeChoiceConfigurator.configureAsModeChoiceInTheLoop(config);
DiscreteModeChoiceConfigGroup dmcConfig = (DiscreteModeChoiceConfigGroup) config.getModules()
.get(DiscreteModeChoiceConfigGroup.GROUP_NAME);
dmcConfig.setModelType(ModelType.Tour);
dmcConfig.setPerformReroute(false);
dmcConfig.setSelector(SelectorModule.MULTINOMIAL_LOGIT);
dmcConfig.setTripEstimator(SwissDiscreteModeChoiceModule.SWISS_ESTIMATOR_NAME);
dmcConfig.setTourEstimator(EstimatorModule.CUMULATIVE);
dmcConfig.setCachedModes(Arrays.asList("car", "bike", "pt", "walk"));
dmcConfig.setTourFinder(TourFinderModule.ACTIVITY_BASED);
dmcConfig.getActivityTourFinderConfigGroup().setActivityType("home");
dmcConfig.setModeAvailability(ModeAvailabilityModule.CAR);
dmcConfig.getCarModeAvailabilityConfig().setAvailableModes(Arrays.asList("car", "bike", "pt", "walk"));
dmcConfig.setTourConstraints(
Arrays.asList(ConstraintModule.VEHICLE_CONTINUITY, ConstraintModule.FROM_TRIP_BASED));
dmcConfig.setTripConstraints(Arrays.asList(ConstraintModule.TRANSIT_WALK));
dmcConfig.getVehicleTourConstraintConfig().setHomeType(HomeType.USE_ACTIVITY_TYPE);
dmcConfig.getVehicleTourConstraintConfig().setRestrictedModes(Arrays.asList("car", "bike"));
// These parameters are only used by SwissRailRaptor. We configure the
// parameters here in a way that SRR searches for the route with the shortest
// travel time.
PlanCalcScoreConfigGroup scoringConfig = config.planCalcScore();
ModeParams ptParams = scoringConfig.getModes().get(TransportMode.pt);
ptParams.setConstant(0.0);
ptParams.setMarginalUtilityOfDistance(0.0);
ptParams.setMarginalUtilityOfTraveling(1.0);
ptParams.setMonetaryDistanceRate(0.0);
scoringConfig.setMarginalUtilityOfMoney(0.0);
scoringConfig.setMarginalUtlOfWaitingPt_utils_hr(0.0);
}
}
package ch.ethz.matsim.projects.astra_2018_002.mode_choice;
import org.matsim.api.core.v01.Id;
import org.matsim.api.core.v01.Scenario;
import org.matsim.api.core.v01.population.Person;
import org.matsim.households.Household;
public class SwissModeChoiceUtilities {
static public void copyHousholdAttributes(Scenario scenario) {
for (Household household : scenario.getHouseholds().getHouseholds().values()) {
for (Id<Person> memberId : household.getMemberIds()) {
Person person = scenario.getPopulation().getPersons().get(memberId);
person.getAttributes().putAttribute("householdIncome", household.getIncome().getIncome());
person.getAttributes().putAttribute("spRegion", household.getAttributes().getAttribute("spRegion"));
person.getAttributes().putAttribute("municipalityType",
household.getAttributes().getAttribute("municipalityType"));
}
}
}
}
package ch.ethz.matsim.projects.astra_2018_002.mode_choice;
import org.matsim.api.core.v01.network.Network;
import org.matsim.core.router.TripRouter;
import org.matsim.facilities.ActivityFacilities;
import org.matsim.pt.transitSchedule.api.TransitSchedule;
import ch.ethz.matsim.discrete_mode_choice.model.DiscreteModeChoiceTrip;
import ch.ethz.matsim.projects.astra_2018_002.mode_choice.base.BaseUtilityEstimator;
import ch.ethz.matsim.projects.astra_2018_002.mode_choice.base.PersonVariables;
import ch.ethz.matsim.projects.astra_2018_002.mode_choice.base.TripVariablesBike;
import ch.ethz.matsim.projects.astra_2018_002.mode_choice.base.TripVariablesCar;
import ch.ethz.matsim.projects.astra_2018_002.mode_choice.base.TripVariablesPt;
import ch.ethz.matsim.projects.astra_2018_002.mode_choice.base.TripVariablesWalk;
import ch.ethz.matsim.projects.astra_2018_002.mode_choice.cost.CostModel;
/**
* Estimates trip utilities based on
*
* Bundesamt für Raumentwicklung (2017) Analyse der SP-Befragung 2015 zur
* Verkehrsmodus- und Routenwahl
*/
public class SwissUtilityEstimator extends BaseUtilityEstimator {
private final SwissUtilityParameters parameters;
public SwissUtilityEstimator(TripRouter tripRouter, Network network, ActivityFacilities facilities,
CostModel costModel, TransitSchedule transitSchedule, SwissUtilityParameters parameters) {
super(tripRouter, network, facilities, costModel, transitSchedule);
this.parameters = parameters;
}
private double estimateSociodemographics(SwissUtilityParameters.SociodemographicsParameters socioParameters,
PersonVariables personVariables) {
double utility = 0.0;
utility += socioParameters.betaAge * personVariables.age;
utility += socioParameters.betaAgeSquared * Math.pow(personVariables.age, 2.0);
utility += socioParameters.betaIncome * personVariables.income;
utility += socioParameters.betaIncomeSquared * Math.pow(personVariables.income, 2.0);
if (personVariables.isMale) {
utility += socioParameters.betaMale;
}
return utility;
}
private double estimatePurpose(SwissUtilityParameters.PurposeParameters purposeParameters,
DiscreteModeChoiceTrip trip) {
/*
* TODO: How is "purpose" defined in the choice model? What if the destination
* purpose is "home"? For now, we use the destination purpose.
*/
switch (trip.getDestinationActivity().getType()) {
case "work":
return purposeParameters.betaWork;
case "education":
return purposeParameters.betaEducation;
case "leisure":
return purposeParameters.betaLeisure;
case "errand":
return purposeParameters.betaErrand;
case "shop":
return purposeParameters.betaShop;
default:
return 0.0;
}
}
private double estimateRegion(SwissUtilityParameters.RegionParameters regionParameters,
PersonVariables personVariables) {
/*
* TODO: How is "region" defined in the choice model? Is it the home location of
* the respondent, the origin or destination of the trip?
*/
switch (personVariables.regionIndex) {
case 1:
return regionParameters.betaRegion1;
case 2:
return regionParameters.betaRegion2;
case 3:
return regionParameters.betaRegion3;
default:
// TODO: Theoretically, this should not happen. But it needs to be fixed in the
// scenario pipeline!
return 0.0;
}
}
private double estimateMunicipalityType(
SwissUtilityParameters.MunicipalityTypeParameters municipalityTypeParameters,
PersonVariables personVariables) {
/*
* TODO: How is "munipality type" defined in the choice model? Is it the home
* location of the respondent, the origin or destination of the trip?
*/
switch (personVariables.municipalityType) {
case Rural:
return municipalityTypeParameters.betaRural;
case SubUrban:
return municipalityTypeParameters.betaSubUrban;
case Urban:
return municipalityTypeParameters.betaUrban;
default:
throw new IllegalStateException();
}
}
@Override
protected double estimatePtTrip(DiscreteModeChoiceTrip trip, PersonVariables personVariables,
TripVariablesPt tripVariables) {
double utility = 0.0;
utility += parameters.pt.alpha;
utility += parameters.pt.betaAccessEgressTime * tripVariables.accessEgressTime_min;
utility += parameters.pt.betaTravelTime * tripVariables.inVehicleTime_min;
utility += parameters.pt.betaWaitingTime * tripVariables.waitingTime_min;
utility += parameters.betaCost * tripVariables.travelCost_CHF;
utility += parameters.pt.betaLineSwitch * tripVariables.lineSwitches;
utility += parameters.pt.betaHeadway * tripVariables.headway_min;
utility += parameters.pt.betaOccupancy * tripVariables.occupancy;
switch (tripVariables.mainMode) {
case Bus:
utility += parameters.pt.betaMainTransportModeBus;
break;
case Rail:
utility += parameters.pt.betaMainTransportModeRail;
break;
case Tram:
utility += parameters.pt.betaMainTransportModeTram;
break;
default:
throw new IllegalStateException();
}
utility += estimateSociodemographics(parameters.pt.sociodemographics, personVariables);
utility += estimatePurpose(parameters.pt.purpose, trip);
utility += estimateRegion(parameters.pt.region, personVariables);
utility += estimateMunicipalityType(parameters.pt.municipalityType, personVariables);
switch (personVariables.ptSubscription) {
case GA:
utility += parameters.pt.betaSubscriptionGA;
break;
case Halbtax:
utility += parameters.pt.betaSubscriptionHalbtax;
break;
case None:
utility += parameters.pt.betaSubscriptionNone;
break;
case Regional:
utility += parameters.pt.betaSubscriptionRegional;
break;
default:
throw new IllegalStateException();
}