Skip to content

Commit

Permalink
add advanced scoring
Browse files Browse the repository at this point in the history
  • Loading branch information
paulheinr committed Nov 15, 2024
1 parent 26b063a commit be9f369
Show file tree
Hide file tree
Showing 11 changed files with 1,048 additions and 5 deletions.
16 changes: 16 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,22 @@
<version>5.3.0</version>
</dependency>

<!-- for weighted random draw: https://mvnrepository.com/artifact/org.apache.commons/commons-math3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-math3</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-statistics-distribution</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-rng-simple</artifactId>
<version>1.5</version>
</dependency>

<dependency>
<groupId>com.github.matsim-vsp</groupId>
<artifactId>pt-extensions</artifactId>
Expand Down
25 changes: 20 additions & 5 deletions src/main/java/org/matsim/run/MetropoleRuhrScenario.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.apache.logging.log4j.Logger;
import org.matsim.analysis.ModeChoiceCoverageControlerListener;
import org.matsim.analysis.TripMatrix;
import org.matsim.analysis.linkpaxvolumes.LinkPaxVolumesAnalysisModule;
import org.matsim.analysis.personMoney.PersonMoneyEventsAnalysisModule;
import org.matsim.analysis.pt.stop2stop.PtStop2StopAnalysisModule;
import org.matsim.api.core.v01.Id;
Expand Down Expand Up @@ -58,6 +59,8 @@
import org.matsim.extensions.pt.routing.ptRoutingModes.PtIntermodalRoutingModesModule;
import org.matsim.prepare.AdjustDemand;
import org.matsim.prepare.RuhrUtils;
import org.matsim.run.scoring.AdvancedScoringConfigGroup;
import org.matsim.run.scoring.AdvancedScoringModule;
import org.matsim.simwrapper.SimWrapperConfigGroup;
import org.matsim.simwrapper.SimWrapperModule;
import org.matsim.vehicles.VehicleType;
Expand Down Expand Up @@ -345,11 +348,27 @@ protected void prepareControler(Controler controler) {
controler.addOverridingModule(new IntermodalTripFareCompensatorsModule());

// additional analysis output
//controler.addOverridingModule(new LinkPaxVolumesAnalysisModule());
controler.addOverridingModule(new LinkPaxVolumesAnalysisModule());
controler.addOverridingModule(new PtStop2StopAnalysisModule());

controler.addOverridingModule(new PtFareModule());

// AdvancedScoring as for matsim-berlin!
if (ConfigUtils.hasModule(controler.getConfig(), AdvancedScoringConfigGroup.class)) {
controler.addOverridingModule(new AdvancedScoringModule());
} else {
// if the above config group is not present we still need income dependent scoring
// this implementation also allows for person specific asc

// for income dependent scoring --> this works with the bicycle contrib as we don´t use the scoring in the bicycle contrib
controler.addOverridingModule(new AbstractModule() {
@Override
public void install() {
bind(ScoringParametersForPerson.class).to(IncomeDependentUtilityOfMoneyPersonScoringParameters.class).in(Singleton.class);
}
});
}

controler.addOverridingModule(new AbstractModule() {
@Override
public void install() {
Expand All @@ -364,10 +383,6 @@ public void install() {
bind(RaptorIntermodalAccessEgress.class).to(EnhancedRaptorIntermodalAccessEgress.class);
// separate pure walk+pt from intermodal pt in mode stats etc.
bind(AnalysisMainModeIdentifier.class).to(IntermodalPtAnalysisModeIdentifier.class);

// for income dependent scoring --> this works with the bicycle contrib as we don´t use the scoring in the bicycle contrib
bind(ScoringParametersForPerson.class).to(IncomeDependentUtilityOfMoneyPersonScoringParameters.class).in(Singleton.class);

}
});

Expand Down
182 changes: 182 additions & 0 deletions src/main/java/org/matsim/run/scoring/AdvancedScoringConfigGroup.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
package org.matsim.run.scoring;

import org.matsim.core.config.ConfigGroup;
import org.matsim.core.config.ReflectiveConfigGroup;

import java.util.*;

/**
* COPIED FROM BERLIN - DO NOT DEVELOP HERE. WILL BE DELETED AS SOON AS THIS FUNCTIONALITY IS MOVED THE MATSIM CORE.
*
* Stores scoring parameters for {@link AdvancedScoringModule}.
*/
@SuppressWarnings("checkstyle:VisibilityModifier")
public final class AdvancedScoringConfigGroup extends ReflectiveConfigGroup {

private static final String GROUP_NAME = "advancedScoring";

@Parameter
@Comment("The distance groups if marginal utility of distance is adjusted. In meters.")
public List<Integer> distGroups;

@Parameter
@Comment("Enable income dependent marginal utility of money.")
public IncomeDependentScoring incomeDependent = IncomeDependentScoring.avgByPersonalIncome;

@Parameter
@Comment("Exponent for (global_income / personal_income) ** x.")
public double incomeExponent = 1;

@Parameter
@Comment("Define how to load existing preferences.")
public LoadPreferences loadPreferences = LoadPreferences.none;

private final List<ScoringParameters> scoringParameters = new ArrayList<>();

public AdvancedScoringConfigGroup() {
super(GROUP_NAME);
}

/**
* Return the defined scoring parameters.
*/
public List<ScoringParameters> getScoringParameters() {
return Collections.unmodifiableList(scoringParameters);
}

@Override
public ConfigGroup createParameterSet(String type) {
if (type.equals(ScoringParameters.GROUP_NAME)) {
return new ScoringParameters();
} else {
throw new IllegalArgumentException("Unsupported parameter set type: " + type);
}
}

@Override
public void addParameterSet(ConfigGroup set) {
if (set instanceof ScoringParameters p) {
super.addParameterSet(set);
scoringParameters.add(p);
} else {
throw new IllegalArgumentException("Unsupported parameter set class: " + set);
}
}

/**
* Different options for income dependent scoring.
*/
public enum IncomeDependentScoring {
none,
avgByPersonalIncome
}

/**
* Define how existing preferences are loaded.
*/
public enum LoadPreferences {
none,
requireAttribute,
skipMissing,
skipRefPersons
}

/**
* Variate values with random draw from specific distribution.
*/
public enum VariationType {
fixed, normal, truncatedNormal
}

/**
* Scoring parameters for a specific group of agents.
* This group allows arbitrary attributes to be defined, which are matched against person attributes.
*/
public static final class ScoringParameters extends ReflectiveConfigGroup {

private static final String GROUP_NAME = "scoringParameters";

/**
* Params per mode.
*/
private final Map<String, ModeParams> modeParams = new HashMap<>();

public ScoringParameters() {
super(GROUP_NAME, true);
}

public Map<String, ModeParams> getModeParams() {
return modeParams;
}

@Override
public ConfigGroup createParameterSet(final String type) {
return switch (type) {
case ModeParams.GROUP_NAME -> new ModeParams();
default -> throw new IllegalArgumentException(type);
};
}

@Override
public void addParameterSet(ConfigGroup set) {
if (set instanceof ModeParams p) {
super.addParameterSet(set);
modeParams.put(p.mode, p);
} else {
throw new IllegalArgumentException("Unsupported parameter set class: " + set);
}
}

/**
* Retrieve mode parameters.
*/
public ModeParams getOrCreateModeParams(String mode) {
if (!modeParams.containsKey(mode)) {
ModeParams p = new ModeParams();
p.mode = mode;

addParameterSet(p);
return p;
}

return modeParams.get(mode);
}

}

/**
* Stores mode specific parameters and also attributes to whom to apply this specification.
*/
public static final class ModeParams extends ReflectiveConfigGroup {

private static final String GROUP_NAME = "modeParams";

@Parameter
@Comment("The mode for which the parameters are defined.")
public String mode;

@Parameter
@Comment("[utils/leg] alternative-specific constant.")
public double deltaConstant;

@Parameter
@Comment("Variation of the constant across individuals.")
public VariationType varConstant = VariationType.fixed;

@Parameter
@Comment("[utils/day] if the mode is used at least once.")
public double deltaDailyConstant;

@Parameter
@Comment("Variation of the daily constant across individuals.")
public VariationType varDailyConstant = VariationType.fixed;

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

public ModeParams() {
super(GROUP_NAME);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package org.matsim.run.scoring;

import com.google.inject.Inject;
import org.matsim.api.core.v01.network.Network;
import org.matsim.api.core.v01.population.Person;
import org.matsim.core.config.Config;
import org.matsim.core.scoring.ScoringFunction;
import org.matsim.core.scoring.ScoringFunctionFactory;
import org.matsim.core.scoring.SumScoringFunction;
import org.matsim.core.scoring.functions.*;

/**
* COPIED FROM BERLIN - DO NOT DEVELOP HERE. WILL BE DELETED AS SOON AS THIS FUNCTIONALITY IS MOVED THE MATSIM CORE.
*
* Same as {@link CharyparNagelScoringFunctionFactory} but with {@link PiecewiseLinearlLegScoring}.
*/
public class AdvancedScoringFunctionFactory implements ScoringFunctionFactory {

@Inject
private Config config;

@Inject
private ScoringParametersForPerson params;

@Inject
private Network network;

@Override
public ScoringFunction createNewScoringFunction(Person person) {
final ScoringParameters parameters = params.getScoringParameters(person);

SumScoringFunction sumScoringFunction = new SumScoringFunction();
sumScoringFunction.addScoringFunction(new CharyparNagelActivityScoring(parameters));
// replaced original leg scoring
sumScoringFunction.addScoringFunction(new PiecewiseLinearlLegScoring(parameters, this.network, config.transit().getTransitModes()));
sumScoringFunction.addScoringFunction(new CharyparNagelMoneyScoring(parameters));
sumScoringFunction.addScoringFunction(new CharyparNagelAgentStuckScoring(parameters));
sumScoringFunction.addScoringFunction(new ScoreEventScoring());
return sumScoringFunction;
}

}
26 changes: 26 additions & 0 deletions src/main/java/org/matsim/run/scoring/AdvancedScoringModule.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.matsim.run.scoring;

import jakarta.inject.Singleton;
import org.matsim.core.config.ConfigUtils;
import org.matsim.core.controler.AbstractModule;
import org.matsim.core.scoring.functions.ScoringParametersForPerson;

/**
* COPIED FROM BERLIN - DO NOT DEVELOP HERE. WILL BE DELETED AS SOON AS THIS FUNCTIONALITY IS MOVED THE MATSIM CORE.
*
* Module to bind components needed for advanced scoring functionality configured by {@link AdvancedScoringConfigGroup}.
*/
public class AdvancedScoringModule extends AbstractModule {

@Override
public void install() {

ConfigUtils.addOrGetModule(getConfig(), AdvancedScoringConfigGroup.class);

bind(ScoringParametersForPerson.class).to(IndividualPersonScoringParameters.class).in(Singleton.class);

addControlerListenerBinding().to(AdvancedScoringOutputWriter.class).in(Singleton.class);

bindScoringFunctionFactory().to(AdvancedScoringFunctionFactory.class).in(Singleton.class);
}
}
Loading

0 comments on commit be9f369

Please sign in to comment.