diff --git a/CHANGELOG.md b/CHANGELOG.md index b151a0381..49ca521cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ included in the (note yet determined) next version number. **Development version** +- Add the motorcycle mode - Updated to MATSim 14 - Isolated the mode choice model in a standalone runnable script - Fixed LegIndex count between iterations in legs analysis diff --git a/core/src/main/java/org/eqasim/core/scenario/cutter/ConfigCutter.java b/core/src/main/java/org/eqasim/core/scenario/cutter/ConfigCutter.java index 3514f3da4..1a72a2c78 100644 --- a/core/src/main/java/org/eqasim/core/scenario/cutter/ConfigCutter.java +++ b/core/src/main/java/org/eqasim/core/scenario/cutter/ConfigCutter.java @@ -1,6 +1,7 @@ package org.eqasim.core.scenario.cutter; import org.matsim.core.config.Config; +import org.matsim.core.config.groups.QSimConfigGroup; public class ConfigCutter { private final String prefix; @@ -16,5 +17,8 @@ public void run(Config config) { config.households().setInputFile(prefix + "households.xml.gz"); config.transit().setTransitScheduleFile(prefix + "transit_schedule.xml.gz"); config.transit().setVehiclesFile(prefix + "transit_vehicles.xml.gz"); + if (config.qsim().getVehiclesSource() == QSimConfigGroup.VehiclesSource.fromVehiclesData) { + config.vehicles().setVehiclesFile(prefix + "vehicles.xml.gz"); + } } } diff --git a/core/src/main/java/org/eqasim/core/simulation/analysis/AnalysisOutputListener.java b/core/src/main/java/org/eqasim/core/simulation/analysis/AnalysisOutputListener.java index 8d50fd40a..09674e353 100644 --- a/core/src/main/java/org/eqasim/core/simulation/analysis/AnalysisOutputListener.java +++ b/core/src/main/java/org/eqasim/core/simulation/analysis/AnalysisOutputListener.java @@ -37,6 +37,7 @@ public class AnalysisOutputListener implements IterationStartsListener, Iteratio private final int analysisInterval; private boolean isAnalysisActive = false; + private boolean doPtAnalysis = true; private final DistanceUnit scenarioDistanceUnit; private final DistanceUnit analysisDistanceUnit; @@ -51,6 +52,9 @@ public AnalysisOutputListener(EqasimConfigGroup config, OutputDirectoryHierarchy this.analysisInterval = config.getAnalysisInterval(); + // pt analysis throws an error when simulating pt in Qsim + this.doPtAnalysis = config.getUseScheduleBasedTransport(); + this.tripAnalysisListener = tripListener; this.legAnalysisListener = legListener; this.ptAnalysisListener = ptListener; @@ -65,7 +69,9 @@ public void notifyIterationStarts(IterationStartsEvent event) { isAnalysisActive = true; event.getServices().getEvents().addHandler(tripAnalysisListener); event.getServices().getEvents().addHandler(legAnalysisListener); - event.getServices().getEvents().addHandler(ptAnalysisListener); + if (this.doPtAnalysis) { + event.getServices().getEvents().addHandler(ptAnalysisListener); + } } } } @@ -84,8 +90,10 @@ public void notifyIterationEnds(IterationEndsEvent event) { new LegWriter(legAnalysisListener.getLegItems(), scenarioDistanceUnit, analysisDistanceUnit) .write(outputDirectory.getIterationFilename(event.getIteration(), LEGS_FILE_NAME)); - new PublicTransportLegWriter(ptAnalysisListener.getTripItems()) - .write(outputDirectory.getIterationFilename(event.getIteration(), PT_FILE_NAME)); + if (this.doPtAnalysis) { + new PublicTransportLegWriter(ptAnalysisListener.getTripItems()) + .write(outputDirectory.getIterationFilename(event.getIteration(), PT_FILE_NAME)); + } } } catch (IOException e) { throw new RuntimeException(e); @@ -99,8 +107,10 @@ public void notifyShutdown(ShutdownEvent event) { new File(outputDirectory.getOutputFilename(TRIPS_FILE_NAME)).toPath()); Files.copy(new File(outputDirectory.getIterationFilename(event.getIteration(), LEGS_FILE_NAME)).toPath(), new File(outputDirectory.getOutputFilename(LEGS_FILE_NAME)).toPath()); - Files.copy(new File(outputDirectory.getIterationFilename(event.getIteration(), PT_FILE_NAME)).toPath(), - new File(outputDirectory.getOutputFilename(PT_FILE_NAME)).toPath()); + if (this.doPtAnalysis) { + Files.copy(new File(outputDirectory.getIterationFilename(event.getIteration(), PT_FILE_NAME)).toPath(), + new File(outputDirectory.getOutputFilename(PT_FILE_NAME)).toPath()); + } } catch (IOException e) { } } diff --git a/core/src/main/java/org/eqasim/core/simulation/mode_choice/EqasimModeChoiceModule.java b/core/src/main/java/org/eqasim/core/simulation/mode_choice/EqasimModeChoiceModule.java index b6bdf3773..85a5027ba 100644 --- a/core/src/main/java/org/eqasim/core/simulation/mode_choice/EqasimModeChoiceModule.java +++ b/core/src/main/java/org/eqasim/core/simulation/mode_choice/EqasimModeChoiceModule.java @@ -16,11 +16,13 @@ import org.eqasim.core.simulation.mode_choice.utilities.UtilityEstimator; import org.eqasim.core.simulation.mode_choice.utilities.estimators.BikeUtilityEstimator; import org.eqasim.core.simulation.mode_choice.utilities.estimators.CarUtilityEstimator; +import org.eqasim.core.simulation.mode_choice.utilities.estimators.MotorcycleUtilityEstimator; import org.eqasim.core.simulation.mode_choice.utilities.estimators.PtUtilityEstimator; import org.eqasim.core.simulation.mode_choice.utilities.estimators.WalkUtilityEstimator; import org.eqasim.core.simulation.mode_choice.utilities.estimators.ZeroUtilityEstimator; import org.eqasim.core.simulation.mode_choice.utilities.predictors.BikePredictor; import org.eqasim.core.simulation.mode_choice.utilities.predictors.CarPredictor; +import org.eqasim.core.simulation.mode_choice.utilities.predictors.MotorcyclePredictor; import org.eqasim.core.simulation.mode_choice.utilities.predictors.PersonPredictor; import org.eqasim.core.simulation.mode_choice.utilities.predictors.PtPredictor; import org.eqasim.core.simulation.mode_choice.utilities.predictors.WalkPredictor; @@ -46,6 +48,7 @@ public class EqasimModeChoiceModule extends AbstractEqasimExtension { public static final String UTILITY_ESTIMATOR_NAME = "EqasimUtilityEstimator"; public static final String CAR_ESTIMATOR_NAME = "CarUtilityEstimator"; + public static final String MOTORCYCLE_ESTIMATOR_NAME = "MotorcycleUtilityEstimator"; public static final String PT_ESTIMATOR_NAME = "PtUtilityEstimator"; public static final String BIKE_ESTIMATOR_NAME = "BikeUtilityEstimator"; public static final String WALK_ESTIMATOR_NAME = "WalkUtilityEstimator"; @@ -67,6 +70,7 @@ protected void installEqasimExtension() { bindTripEstimator(UTILITY_ESTIMATOR_NAME).to(ModalUtilityEstimator.class); bind(CarPredictor.class); + bind(MotorcyclePredictor.class); bind(PtPredictor.class); bind(BikePredictor.class); bind(WalkPredictor.class); @@ -74,6 +78,7 @@ protected void installEqasimExtension() { bindUtilityEstimator(ZERO_ESTIMATOR_NAME).to(ZeroUtilityEstimator.class); bindUtilityEstimator(CAR_ESTIMATOR_NAME).to(CarUtilityEstimator.class); + bindUtilityEstimator(MOTORCYCLE_ESTIMATOR_NAME).to(MotorcycleUtilityEstimator.class); bindUtilityEstimator(PT_ESTIMATOR_NAME).to(PtUtilityEstimator.class); bindUtilityEstimator(BIKE_ESTIMATOR_NAME).to(BikeUtilityEstimator.class); bindUtilityEstimator(WALK_ESTIMATOR_NAME).to(WalkUtilityEstimator.class); @@ -111,6 +116,12 @@ public CostModel provideCarCostModel(Map> factory, E return getCostModel(factory, config, "car"); } + @Provides + @Named("motorcycle") + public CostModel provideMotorcycleCostModel(Map> factory, EqasimConfigGroup config) { + return getCostModel(factory, config, "motorcycle"); + } + @Provides @Named("pt") public CostModel providePtCostModel(Map> factory, EqasimConfigGroup config) { diff --git a/core/src/main/java/org/eqasim/core/simulation/mode_choice/parameters/ModeParameters.java b/core/src/main/java/org/eqasim/core/simulation/mode_choice/parameters/ModeParameters.java index fb1edf678..68d646635 100644 --- a/core/src/main/java/org/eqasim/core/simulation/mode_choice/parameters/ModeParameters.java +++ b/core/src/main/java/org/eqasim/core/simulation/mode_choice/parameters/ModeParameters.java @@ -11,6 +11,14 @@ public class CarParameters { public double constantParkingSearchPenalty_min = 0.0; } + public class MotorcycleParameters { + public double alpha_u = 0.0; + public double betaTravelTime_u_min = 0.0; + + public double constantAccessEgressWalkTime_min = 0.0; + public double constantParkingSearchPenalty_min = 0.0; + } + public class PtParameters { public double alpha_u = 0.0; public double betaLineSwitch_u = 0.0; @@ -36,6 +44,7 @@ public class WalkParameters { public double betaCost_u_MU = 0.0; public final CarParameters car = new CarParameters(); + public final MotorcycleParameters motorcycle = new MotorcycleParameters(); public final PtParameters pt = new PtParameters(); public final BikeParameters bike = new BikeParameters(); public final WalkParameters walk = new WalkParameters(); diff --git a/core/src/main/java/org/eqasim/core/simulation/mode_choice/utilities/estimators/MotorcycleUtilityEstimator.java b/core/src/main/java/org/eqasim/core/simulation/mode_choice/utilities/estimators/MotorcycleUtilityEstimator.java new file mode 100644 index 000000000..57b95118d --- /dev/null +++ b/core/src/main/java/org/eqasim/core/simulation/mode_choice/utilities/estimators/MotorcycleUtilityEstimator.java @@ -0,0 +1,54 @@ +package org.eqasim.core.simulation.mode_choice.utilities.estimators; + +import com.google.inject.Inject; +import org.eqasim.core.simulation.mode_choice.parameters.ModeParameters; +import org.eqasim.core.simulation.mode_choice.utilities.UtilityEstimator; +import org.eqasim.core.simulation.mode_choice.utilities.predictors.MotorcyclePredictor; +import org.eqasim.core.simulation.mode_choice.utilities.variables.MotorcycleVariables; +import org.matsim.api.core.v01.population.Person; +import org.matsim.api.core.v01.population.PlanElement; +import org.matsim.contribs.discrete_mode_choice.model.DiscreteModeChoiceTrip; + +import java.util.List; + +public class MotorcycleUtilityEstimator implements UtilityEstimator { + private final ModeParameters parameters; + private final MotorcyclePredictor predictor; + + @Inject + public MotorcycleUtilityEstimator(ModeParameters parameters, MotorcyclePredictor predictor) { + this.parameters = parameters; + this.predictor = predictor; + } + + protected double estimateConstantUtility() { + return parameters.motorcycle.alpha_u; + } + + protected double estimateTravelTimeUtility(MotorcycleVariables variables) { + return parameters.motorcycle.betaTravelTime_u_min * variables.travelTime_min; + } + + protected double estimateAccessEgressTimeUtility(MotorcycleVariables variables) { + return parameters.walk.betaTravelTime_u_min * variables.accessEgressTime_min; + } + + protected double estimateMonetaryCostUtility(MotorcycleVariables variables) { + return parameters.betaCost_u_MU * EstimatorUtils.interaction(variables.euclideanDistance_km, + parameters.referenceEuclideanDistance_km, parameters.lambdaCostEuclideanDistance) * variables.cost_MU; + } + + @Override + public double estimateUtility(Person person, DiscreteModeChoiceTrip trip, List elements) { + MotorcycleVariables variables = predictor.predictVariables(person, trip, elements); + + double utility = 0.0; + + utility += estimateConstantUtility(); + utility += estimateTravelTimeUtility(variables); + utility += estimateAccessEgressTimeUtility(variables); + utility += estimateMonetaryCostUtility(variables); + + return utility; + } +} diff --git a/core/src/main/java/org/eqasim/core/simulation/mode_choice/utilities/predictors/MotorcyclePredictor.java b/core/src/main/java/org/eqasim/core/simulation/mode_choice/utilities/predictors/MotorcyclePredictor.java new file mode 100644 index 000000000..cd00acb58 --- /dev/null +++ b/core/src/main/java/org/eqasim/core/simulation/mode_choice/utilities/predictors/MotorcyclePredictor.java @@ -0,0 +1,41 @@ +package org.eqasim.core.simulation.mode_choice.utilities.predictors; + +import com.google.inject.Inject; +import com.google.inject.name.Named; +import org.eqasim.core.simulation.mode_choice.cost.CostModel; +import org.eqasim.core.simulation.mode_choice.parameters.ModeParameters; +import org.eqasim.core.simulation.mode_choice.utilities.variables.MotorcycleVariables; +import org.matsim.api.core.v01.population.Leg; +import org.matsim.api.core.v01.population.Person; +import org.matsim.api.core.v01.population.PlanElement; +import org.matsim.contribs.discrete_mode_choice.model.DiscreteModeChoiceTrip; + +import java.util.List; + +public class MotorcyclePredictor extends CachedVariablePredictor { + private final CostModel costModel; + private final ModeParameters parameters; + + @Inject + public MotorcyclePredictor(ModeParameters parameters, @Named("motorcycle") CostModel costModel) { + this.costModel = costModel; + this.parameters = parameters; + } + + @Override + public MotorcycleVariables predict(Person person, DiscreteModeChoiceTrip trip, List elements) { + if (elements.size() > 1) { + throw new IllegalStateException("We do not support multi-stage car trips yet."); + } + + Leg leg = (Leg) elements.get(0); + + double travelTime_min = leg.getTravelTime().seconds() / 60.0 + parameters.motorcycle.constantParkingSearchPenalty_min; + double cost_MU = costModel.calculateCost_MU(person, trip, elements); + + double euclideanDistance_km = PredictorUtils.calculateEuclideanDistance_km(trip); + double accessEgressTime_min = parameters.motorcycle.constantAccessEgressWalkTime_min; + + return new MotorcycleVariables(travelTime_min, cost_MU, euclideanDistance_km, accessEgressTime_min); + } +} diff --git a/core/src/main/java/org/eqasim/core/simulation/mode_choice/utilities/variables/MotorcycleVariables.java b/core/src/main/java/org/eqasim/core/simulation/mode_choice/utilities/variables/MotorcycleVariables.java new file mode 100644 index 000000000..0f08beaf3 --- /dev/null +++ b/core/src/main/java/org/eqasim/core/simulation/mode_choice/utilities/variables/MotorcycleVariables.java @@ -0,0 +1,16 @@ +package org.eqasim.core.simulation.mode_choice.utilities.variables; + +public class MotorcycleVariables implements BaseVariables { + final public double travelTime_min; + final public double cost_MU; + final public double euclideanDistance_km; + final public double accessEgressTime_min; + + public MotorcycleVariables(double travelTime_min, double cost_MU, double euclideanDistance_km, + double accessEgressTime_min) { + this.travelTime_min = travelTime_min; + this.cost_MU = cost_MU; + this.euclideanDistance_km = euclideanDistance_km; + this.accessEgressTime_min = accessEgressTime_min; + } +} diff --git a/ile_de_france/src/main/java/org/eqasim/ile_de_france/IDFConfigurator.java b/ile_de_france/src/main/java/org/eqasim/ile_de_france/IDFConfigurator.java index 044312764..a01a65ea7 100644 --- a/ile_de_france/src/main/java/org/eqasim/ile_de_france/IDFConfigurator.java +++ b/ile_de_france/src/main/java/org/eqasim/ile_de_france/IDFConfigurator.java @@ -1,16 +1,22 @@ package org.eqasim.ile_de_france; +import org.eqasim.core.components.config.EqasimConfigGroup; import org.eqasim.core.simulation.EqasimConfigurator; +import org.eqasim.ile_de_france.mode_choice.IDFModeChoiceModule; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; import org.matsim.api.core.v01.population.Person; +import org.matsim.contribs.discrete_mode_choice.modules.config.DiscreteModeChoiceConfigGroup; import org.matsim.core.config.Config; +import org.matsim.core.config.groups.PlanCalcScoreConfigGroup; import org.matsim.core.config.groups.QSimConfigGroup; import org.matsim.vehicles.Vehicle; import org.matsim.vehicles.VehicleUtils; -import java.util.HashMap; -import java.util.Map; +import java.util.*; public class IDFConfigurator extends EqasimConfigurator { public void adjustScenario(Scenario scenario) { @@ -18,11 +24,73 @@ public void adjustScenario(Scenario scenario) { Config config = scenario.getConfig(); if (config.qsim().getVehiclesSource() == QSimConfigGroup.VehiclesSource.fromVehiclesData) { for (Person person : scenario.getPopulation().getPersons().values()) { - Id vehicleId = Id.createVehicleId(person.getId()); + Id carId = Id.createVehicleId(person.getId()); + Id motorcycleId = Id.createVehicleId(String.format("m_%s", person.getId())); Map> modeVehicle = new HashMap<>(); - modeVehicle.put("car", vehicleId); + modeVehicle.put("car", carId); + if (person.getAttributes().getAsMap().containsKey("motorcycleAvailability")) { + if (!((String) person.getAttributes().getAttribute("motorcycleAvailability")).equals("none")) { + modeVehicle.put("motorcycle", motorcycleId); + } + } VehicleUtils.insertVehicleIdsIntoAttributes(person, modeVehicle); } } } + + public void adjustScenarioMotorcycle(Scenario scenario) { + // add motorcycle stuff + Config config = scenario.getConfig(); + { // QSim + List qsimMainModes = new ArrayList<>(config.qsim().getMainModes()); + qsimMainModes.add("motorcycle"); + config.qsim().setMainModes(qsimMainModes); + + config.qsim().setLinkDynamics(QSimConfigGroup.LinkDynamics.SeepageQ); + + List qsimSeepModes = new ArrayList<>(config.qsim().getSeepModes()); + qsimSeepModes.add("motorcycle"); + config.qsim().setSeepModes(qsimSeepModes); + } + { // DMC + DiscreteModeChoiceConfigGroup dmcConfig = (DiscreteModeChoiceConfigGroup) config.getModules() + .get(DiscreteModeChoiceConfigGroup.GROUP_NAME); + Collection cachedModes = dmcConfig.getCachedModes(); + cachedModes.add("motorcycle"); + dmcConfig.setCachedModes(cachedModes); + + List vehicleConstraintModes = new ArrayList<>(dmcConfig.getVehicleTourConstraintConfig().getRestrictedModes()); + vehicleConstraintModes.add("motorcycle"); + dmcConfig.getVehicleTourConstraintConfig().setRestrictedModes(vehicleConstraintModes); + } + { // Eqasim + EqasimConfigGroup eqasimConfig = EqasimConfigGroup.get(config); + eqasimConfig.setEstimator(TransportMode.motorcycle, IDFModeChoiceModule.MOTORCYCLE_ESTIMATOR_NAME); + eqasimConfig.setCostModel(TransportMode.motorcycle, IDFModeChoiceModule.MOTORCYCLE_COST_MODEL_NAME); + } + { // planCalcScore + PlanCalcScoreConfigGroup.ModeParams modeParameters = new PlanCalcScoreConfigGroup.ModeParams("motorcycle"); + modeParameters.setConstant(0.0); + modeParameters.setMarginalUtilityOfDistance(0.0); + modeParameters.setMonetaryDistanceRate(0.0); + config.planCalcScore().addModeParams(modeParameters); + + config.planCalcScore().setWriteExperiencedPlans(true); + } + { // plansCalcRoute + List networkModes = new ArrayList<>(config.plansCalcRoute().getNetworkModes()); + networkModes.add("motorcycle"); + config.plansCalcRoute().setNetworkModes(networkModes); + } + { // Network + Network network = scenario.getNetwork(); + for (Link link : network.getLinks().values()) { + Set modes = new HashSet<>(link.getAllowedModes()); + if (modes.contains("car")) { + modes.add("motorcycle"); + link.setAllowedModes(modes); + } + } + } + } } diff --git a/ile_de_france/src/main/java/org/eqasim/ile_de_france/RunSimulation.java b/ile_de_france/src/main/java/org/eqasim/ile_de_france/RunSimulation.java index 2a5dd8362..9f4e49553 100644 --- a/ile_de_france/src/main/java/org/eqasim/ile_de_france/RunSimulation.java +++ b/ile_de_france/src/main/java/org/eqasim/ile_de_france/RunSimulation.java @@ -15,6 +15,7 @@ public class RunSimulation { static public void main(String[] args) throws ConfigurationException { CommandLine cmd = new CommandLine.Builder(args) // .requireOptions("config-path") // + .allowOptions("with-motorcycles") .allowPrefixes("mode-choice-parameter", "cost-parameter") // .build(); @@ -27,6 +28,11 @@ static public void main(String[] args) throws ConfigurationException { ScenarioUtils.loadScenario(scenario); configurator.adjustScenario(scenario); + boolean withMotorcycles = cmd.hasOption("with-motorcycles"); + if (withMotorcycles) { + configurator.adjustScenarioMotorcycle(scenario); + } + Controler controller = new Controler(scenario); configurator.configureController(controller); controller.addOverridingModule(new EqasimAnalysisModule()); diff --git a/ile_de_france/src/main/java/org/eqasim/ile_de_france/mode_choice/IDFModeAvailability.java b/ile_de_france/src/main/java/org/eqasim/ile_de_france/mode_choice/IDFModeAvailability.java index b193c2bb6..a502a5404 100644 --- a/ile_de_france/src/main/java/org/eqasim/ile_de_france/mode_choice/IDFModeAvailability.java +++ b/ile_de_france/src/main/java/org/eqasim/ile_de_france/mode_choice/IDFModeAvailability.java @@ -34,6 +34,26 @@ public Collection getAvailableModes(Person person, List elements) { + return costParameters.motorcycleCost_EUR_km * getInVehicleDistance_km(elements); + } +} diff --git a/ile_de_france/src/main/java/org/eqasim/ile_de_france/mode_choice/parameters/IDFCostParameters.java b/ile_de_france/src/main/java/org/eqasim/ile_de_france/mode_choice/parameters/IDFCostParameters.java index 4e2563840..deaa70604 100644 --- a/ile_de_france/src/main/java/org/eqasim/ile_de_france/mode_choice/parameters/IDFCostParameters.java +++ b/ile_de_france/src/main/java/org/eqasim/ile_de_france/mode_choice/parameters/IDFCostParameters.java @@ -4,11 +4,13 @@ public class IDFCostParameters implements ParameterDefinition { public double carCost_EUR_km = 0.0; + public double motorcycleCost_EUR_km = 0.0; public static IDFCostParameters buildDefault() { IDFCostParameters parameters = new IDFCostParameters(); parameters.carCost_EUR_km = 0.15; + parameters.motorcycleCost_EUR_km = 0.15; return parameters; } diff --git a/ile_de_france/src/main/java/org/eqasim/ile_de_france/mode_choice/parameters/IDFModeParameters.java b/ile_de_france/src/main/java/org/eqasim/ile_de_france/mode_choice/parameters/IDFModeParameters.java index bf948e053..dab7abf47 100644 --- a/ile_de_france/src/main/java/org/eqasim/ile_de_france/mode_choice/parameters/IDFModeParameters.java +++ b/ile_de_france/src/main/java/org/eqasim/ile_de_france/mode_choice/parameters/IDFModeParameters.java @@ -8,11 +8,17 @@ public class IDFCarParameters { public double betaCrossingUrbanArea; } + public class IDFMotorcycleParameters { + public double betaInsideUrbanArea; + public double betaCrossingUrbanArea; + } + public class IDFBikeParameters { public double betaInsideUrbanArea; } public final IDFCarParameters idfCar = new IDFCarParameters(); + public final IDFMotorcycleParameters idfMotorcycle = new IDFMotorcycleParameters(); public final IDFBikeParameters idfBike = new IDFBikeParameters(); public static IDFModeParameters buildDefault() { @@ -33,6 +39,16 @@ public static IDFModeParameters buildDefault() { parameters.idfCar.betaInsideUrbanArea = -0.5; parameters.idfCar.betaCrossingUrbanArea = -1.0; + // Motorcycle ; copy of Car for now + parameters.motorcycle.alpha_u = 1.35; + parameters.motorcycle.betaTravelTime_u_min = -0.06; + + parameters.motorcycle.constantAccessEgressWalkTime_min = 4.0; + parameters.motorcycle.constantParkingSearchPenalty_min = 4.0; + + parameters.idfMotorcycle.betaInsideUrbanArea = -0.5; + parameters.idfMotorcycle.betaCrossingUrbanArea = -1.0; + // PT parameters.pt.alpha_u = 0.0; parameters.pt.betaLineSwitch_u = -0.17; diff --git a/ile_de_france/src/main/java/org/eqasim/ile_de_france/mode_choice/utilities/estimators/IDFMotorcycleUtilityEstimator.java b/ile_de_france/src/main/java/org/eqasim/ile_de_france/mode_choice/utilities/estimators/IDFMotorcycleUtilityEstimator.java new file mode 100644 index 000000000..367eaaa36 --- /dev/null +++ b/ile_de_france/src/main/java/org/eqasim/ile_de_france/mode_choice/utilities/estimators/IDFMotorcycleUtilityEstimator.java @@ -0,0 +1,53 @@ +package org.eqasim.ile_de_france.mode_choice.utilities.estimators; + +import com.google.inject.Inject; +import org.eqasim.core.simulation.mode_choice.utilities.estimators.MotorcycleUtilityEstimator; +import org.eqasim.core.simulation.mode_choice.utilities.predictors.MotorcyclePredictor; +import org.eqasim.ile_de_france.mode_choice.parameters.IDFModeParameters; +import org.eqasim.ile_de_france.mode_choice.utilities.predictors.IDFSpatialPredictor; +import org.eqasim.ile_de_france.mode_choice.utilities.variables.IDFSpatialVariables; +import org.matsim.api.core.v01.population.Person; +import org.matsim.api.core.v01.population.PlanElement; +import org.matsim.contribs.discrete_mode_choice.model.DiscreteModeChoiceTrip; + +import java.util.List; + +public class IDFMotorcycleUtilityEstimator extends MotorcycleUtilityEstimator { + private final IDFModeParameters parameters; + private final IDFSpatialPredictor spatialPredictor; + + @Inject + public IDFMotorcycleUtilityEstimator(IDFModeParameters parameters, IDFSpatialPredictor spatialPredictor, + MotorcyclePredictor motorcyclePredictor) { + super(parameters, motorcyclePredictor); + + this.parameters = parameters; + this.spatialPredictor = spatialPredictor; + } + + protected double estimateUrbanUtility(IDFSpatialVariables variables) { + double utility = 0.0; + + if (variables.hasUrbanOrigin && variables.hasUrbanDestination) { + utility += parameters.idfMotorcycle.betaInsideUrbanArea; + } + + if (variables.hasUrbanOrigin || variables.hasUrbanDestination) { + utility += parameters.idfMotorcycle.betaCrossingUrbanArea; + } + + return utility; + } + + @Override + public double estimateUtility(Person person, DiscreteModeChoiceTrip trip, List elements) { + IDFSpatialVariables variables = spatialPredictor.predictVariables(person, trip, elements); + + double utility = 0.0; + + utility += super.estimateUtility(person, trip, elements); + utility += estimateUrbanUtility(variables); + + return utility; + } +}