Skip to content

Commit

Permalink
use main mode in trip scorer, implement class for choice experiments
Browse files Browse the repository at this point in the history
  • Loading branch information
rakow committed Dec 13, 2024
1 parent 68e4ae3 commit 05ae1b0
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 15 deletions.
Original file line number Diff line number Diff line change
@@ -1,35 +1,80 @@
package org.matsim.run.policies;

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.population.Leg;
import org.matsim.api.core.v01.population.Person;
import org.matsim.api.core.v01.population.Plan;
import org.matsim.application.MATSimApplication;
import org.matsim.core.config.Config;
import org.matsim.core.config.ConfigUtils;
import org.matsim.core.controler.Controler;
import org.matsim.core.router.TripStructureUtils;
import org.matsim.modechoice.InformedModeChoiceConfigGroup;
import org.matsim.modechoice.InformedModeChoiceModule;
import org.matsim.modechoice.ModeOptions;
import org.matsim.modechoice.constraints.RelaxedMassConservationConstraint;
import org.matsim.modechoice.estimators.DefaultActivityEstimator;
import org.matsim.modechoice.estimators.DefaultLegScoreEstimator;
import org.matsim.modechoice.estimators.FixedCostsEstimator;
import org.matsim.run.OpenBerlinScenario;
import org.matsim.run.scoring.AdvancedScoringConfigGroup;
import org.matsim.vehicles.VehicleType;
import picocli.CommandLine;

/**
* This class can be used to run some synthetic choice experiments on the OpenBerlin scenario.
* This class can be used to run some synthetic mode choice experiments on the OpenBerlin scenario.
*/
public class OpenBerlinChoiceExperiment extends OpenBerlinScenario {

@CommandLine.Option(names = "--bike-speed-factor", description = "Speed factor for bikes", defaultValue = "1.0")
private double bikeSpeedFactor = 1.0;
@CommandLine.Option(names = "--bike-speed-offset", description = "Offset the default bike speed in km/h", defaultValue = "0")
private double bikeSpeedOffset;

@CommandLine.Option(names = "--imc", description = "Enable informed-mode-choice functionality")
private boolean imc;

public static void main(String[] args) {
MATSimApplication.execute(OpenBerlinChoiceExperiment.class, args);
}

@Override
protected Config prepareConfig(Config config) {

if (imc) {

InformedModeChoiceConfigGroup imcConfig = ConfigUtils.addOrGetModule(config, InformedModeChoiceConfigGroup.class);

imcConfig.setConstraintCheck(InformedModeChoiceConfigGroup.ConstraintCheck.repair);

// TODO: enable pruning

// TODO: replace strategy

// TODO: start imc runs
// from uncalibrated population with baseline calibration

// next, with new mode scoring

// different number iterations x pruning thresholds/top k

}

return config;
}

@Override
protected void prepareScenario(Scenario scenario) {

super.prepareScenario(scenario);

// If bike speed is adjusted, we need to remove all bike routes and travel times
// These times will be recalculated by the router
if (bikeSpeedFactor != 1.0) {
if (bikeSpeedOffset != 0) {

VehicleType bike = scenario.getVehicles().getVehicleTypes().get(Id.create(TransportMode.bike, VehicleType.class));
bike.setMaximumVelocity(bike.getMaximumVelocity() + bikeSpeedOffset / 3.6);

for (Person person : scenario.getPopulation().getPersons().values()) {
for (Plan plan : person.getPlans()) {
for (Leg leg : TripStructureUtils.getLegs(plan)) {
Expand All @@ -42,4 +87,32 @@ protected void prepareScenario(Scenario scenario) {
}
}
}


@Override
protected void prepareControler(Controler controler) {
super.prepareControler(controler);

if (imc) {

InformedModeChoiceModule.Builder builder = InformedModeChoiceModule.newBuilder()
.withActivityEstimator(DefaultActivityEstimator.class)
.withFixedCosts(FixedCostsEstimator.DailyConstant.class, "car", "pt")
.withLegEstimator(DefaultLegScoreEstimator.class, ModeOptions.ConsiderIfCarAvailable.class, "car")
.withLegEstimator(DefaultLegScoreEstimator.class, ModeOptions.AlwaysAvailable.class, "pt", "walk", "bike", "ride")
.withConstraint(RelaxedMassConservationConstraint.class);

if (ConfigUtils.hasModule(controler.getConfig(), AdvancedScoringConfigGroup.class)) {

// TODO: add pseudo random errors to estimator
// Implement pseudo trip scoring into informed mode choice

// TODO: option for pruning

}

controler.addOverridingModule(builder.build());
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ public static final class ModeParams extends ReflectiveConfigGroup {
public VariationType varDailyConstant = VariationType.fixed;

@Parameter
@Comment("total delta utility per dist group.")
@Comment("Total delta utility per dist group.")
public List<Double> deltaPerDistGroup;

public ModeParams() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import org.matsim.api.core.v01.population.Person;
import org.matsim.core.config.Config;
import org.matsim.core.config.ConfigUtils;
import org.matsim.core.router.AnalysisMainModeIdentifier;
import org.matsim.core.scoring.ScoringFunction;
import org.matsim.core.scoring.ScoringFunctionFactory;
import org.matsim.core.scoring.SumScoringFunction;
Expand All @@ -16,13 +17,16 @@ public class AdvancedScoringFunctionFactory implements ScoringFunctionFactory {

private final Config config;
private final AdvancedScoringConfigGroup scoring;
private final AnalysisMainModeIdentifier mmi;
private final ScoringParametersForPerson params;
private final PseudoRandomScorer pseudoRNG;

@Inject
public AdvancedScoringFunctionFactory(Config config, ScoringParametersForPerson params, PseudoRandomScorer pseudoRNG) {
public AdvancedScoringFunctionFactory(Config config, AnalysisMainModeIdentifier mmi,
ScoringParametersForPerson params, PseudoRandomScorer pseudoRNG) {
this.config = config;
this.scoring = ConfigUtils.addOrGetModule(config, AdvancedScoringConfigGroup.class);
this.mmi = mmi;
this.params = params;
this.pseudoRNG = pseudoRNG;
}
Expand All @@ -35,7 +39,7 @@ public ScoringFunction createNewScoringFunction(Person person) {
sumScoringFunction.addScoringFunction(new CharyparNagelActivityScoring(parameters));

if (scoring.pseudoRamdomScale > 0) {
sumScoringFunction.addScoringFunction(new PseudoRandomTripScoring(person.getId(), pseudoRNG));
sumScoringFunction.addScoringFunction(new PseudoRandomTripScoring(person.getId(), mmi, pseudoRNG));
}

// replaced original leg scoring
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@
public final class DefaultPseudoRandomTripError implements PseudoRandomTripError {

@Override
public long getSeed(Id<Person> personId, String routingMode, TripStructureUtils.Trip trip) {
public long getSeed(Id<Person> personId, String mainMode, TripStructureUtils.Trip trip) {

int personHash = personId.toString().hashCode();

int modeHash = routingMode.hashCode();
int modeHash = mainMode.hashCode();
int modeAndActHash = 31 * modeHash + trip.getOriginActivity().getType().hashCode();

// Combine two integers to long
return (long) personHash << 32 | modeAndActHash & 0xFFFFFFFFL;
return ((long) personHash << 32) | (modeAndActHash & 0xFFFFFFFFL);
}
}
4 changes: 2 additions & 2 deletions src/main/java/org/matsim/run/scoring/PseudoRandomScorer.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,12 @@ public PseudoRandomScorer(PseudoRandomTripError tripScore, Config config) {
/**
* Calculates the pseudo random score of a trip.
*/
public double scoreTrip(Id<Person> personId, String routingMode, TripStructureUtils.Trip trip) {
public double scoreTrip(Id<Person> personId, String mainMode, TripStructureUtils.Trip trip) {

if (tripScore == null || scale == 0)
return 0;

long tripSeed = tripScore.getSeed(personId, routingMode, trip);
long tripSeed = tripScore.getSeed(personId, mainMode, trip);

// Need to create a new instance because reusing them will also create a lot of intermediate arrays
XoRoShiRo128PlusPlus rng = new XoRoShiRo128PlusPlus(seed, tripSeed);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public interface PseudoRandomTripError {
/**
* Return a seed for a trip. The seed must be designed such that it is constant for the same choice situations.
*/
long getSeed(Id<Person> personId, String routingMode, TripStructureUtils.Trip trip);
long getSeed(Id<Person> personId, String mainMode, TripStructureUtils.Trip trip);


}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.matsim.api.core.v01.Id;
import org.matsim.api.core.v01.population.Leg;
import org.matsim.api.core.v01.population.Person;
import org.matsim.core.router.MainModeIdentifier;
import org.matsim.core.router.TripStructureUtils;
import org.matsim.core.scoring.ScoringFunction;
import org.matsim.core.scoring.SumScoringFunction;
Expand All @@ -21,13 +22,15 @@ public class PseudoRandomTripScoring implements SumScoringFunction.TripScoring {
private static final Logger log = LogManager.getLogger(PseudoRandomTripScoring.class);

private final Id<Person> id;
private final MainModeIdentifier mmi;
private final PseudoRandomScorer rng;

private final DoubleList scores = new DoubleArrayList();
private double score;

public PseudoRandomTripScoring(Id<Person> id, PseudoRandomScorer rng) {
public PseudoRandomTripScoring(Id<Person> id, MainModeIdentifier mmi, PseudoRandomScorer rng) {
this.id = id;
this.mmi = mmi;
this.rng = rng;
}

Expand All @@ -49,7 +52,8 @@ public void handleTrip(TripStructureUtils.Trip trip) {
return;
}

double tripScore = rng.scoreTrip(id, legs.getFirst().getRoutingMode(), trip);
String mainMode = mmi.identifyMainMode(legs);
double tripScore = rng.scoreTrip(id, mainMode, trip);
scores.add(tripScore);
score += tripScore;
}
Expand Down

0 comments on commit 05ae1b0

Please sign in to comment.