Skip to content

Commit

Permalink
Added income-dependant marginalUtilityOfMoney and rewrote main class …
Browse files Browse the repository at this point in the history
…in RunVTTSAnalysis.java
  • Loading branch information
Aleksander1234519 committed Aug 22, 2024
1 parent b5b11c5 commit 7071877
Show file tree
Hide file tree
Showing 2 changed files with 135 additions and 17 deletions.
110 changes: 95 additions & 15 deletions src/main/java/org/matsim/analysis/RunVTTSAnalysis.java
Original file line number Diff line number Diff line change
@@ -1,40 +1,120 @@
package org.matsim.analysis;

import org.matsim.api.core.v01.Scenario;
import org.matsim.api.core.v01.TransportMode;
import org.matsim.application.MATSimAppCommand;
import org.matsim.contrib.vsp.scenario.SnzActivities;
import org.matsim.core.api.experimental.events.EventsManager;
import org.matsim.core.config.Config;
import org.matsim.core.config.ConfigUtils;
import org.matsim.core.config.groups.ScoringConfigGroup;
import org.matsim.core.events.EventsUtils;
import org.matsim.core.scenario.ScenarioUtils;
import org.matsim.core.utils.collections.Tuple;
import picocli.CommandLine;

public class RunVTTSAnalysis implements MATSimAppCommand {

@CommandLine.Option(names = "--config", description = "Path to config file", required = true)
private String configPath;

@CommandLine.Option(names = "--plans", description = "Path to plans file", required = true)
private String plansPath;

@CommandLine.Option(names = "--events", description = "Path to events file", required = true)
private String eventsPath;

@CommandLine.Option(names = "--out", description = "Path for the output", required = true)
private String outPath;

@CommandLine.Option(names = "--modes", description = "Analyse specified modes distinctly. If you want multiple analysis, write separated by semicolon. (e.g. 'bike;car;...')")
private String modes;

@CommandLine.Option(names = "--statistics", description = "Prints VTTS statistic for a specified mode in a specified time-frame. If you want multiple analysis, write separated by semicolon: 'mode1,start1,end1;mode2,start2,end2;...'. Unit is seconds (e.g. bike,0,10000;car,100,8000)")
private String statistics;

@CommandLine.Option(names = "--ignoredModes", description = "Modes that should be ignored (e.g. walk;...)")
private String ignoredModes;

@CommandLine.Option(names = "--ignoredActs", description = "Substrings of activities that should be ignored (e.g. interaction;...)")
private String ignoredActs;

@CommandLine.Option(names = "--snzScoring", description = "If activated, automatically applies scoring parameters to SnzActivities like home_3200, ...", defaultValue = "false")
private boolean snzScoring;

@CommandLine.Option(names = "--incomeDependantScoring", description = "If activated, a personal marginal utility of money is computed for every agent", defaultValue = "false")
private boolean incomeDependantScoring;

public class RunVTTSAnalysis {
public static void main(String[] args) {
//NOTE: This is not the regular config. I have changed it to work for this VTTS-analysis (removed all interaction activityParams). I will create a generic solution later. (aleks)
Config ruhrConfig = ConfigUtils.loadConfig("../VTTS/000.output_config_vtts.xml");
ruhrConfig.plans().setInputFile("../VTTS/000.output_plans.xml.gz");
ruhrConfig.network().setInputFile(null);;
new CommandLine(new RunVTTSAnalysis()).execute(args);
}

@Override
public Integer call() throws Exception {
/* Debug:
--config ../VTTS/000.output_config_vtts.xml
--plans ../VTTS/000.output_plans.xml.gz
--events ../VTTS/000.output_events.xml.gz
--out ../VTTS/
--modes bike,pt
--statistics bike,0,10000
--ignoredModes walk
--ignoredActs interaction
--incomeDependantScoring
*/
System.out.println(configPath);
System.out.println(plansPath);
System.out.println(eventsPath);
System.out.println(outPath);
System.out.println(modes);
System.out.println(statistics);
System.out.println(snzScoring);
System.out.println(ignoredModes);
System.out.println(ignoredActs);
System.out.println(incomeDependantScoring);

Config ruhrConfig = ConfigUtils.loadConfig(configPath);
ruhrConfig.plans().setInputFile(plansPath);
ruhrConfig.global().setNumberOfThreads(16);
ruhrConfig.network().setInputFile(null);
ruhrConfig.facilities().setInputFile(null);
ruhrConfig.transit().setTransitScheduleFile(null);
ruhrConfig.transit().setVehiclesFile(null);
ruhrConfig.counts().setInputFile(null);
ruhrConfig.vehicles().setVehiclesFile(null);
// TODO Removal of unnecessary acts
ruhrConfig.vspExperimental().setAbleToOverwritePtInteractionParams(true);

// Sets the typical durations of all activities, that should be ignored, to 0.1. This allows to use configs with interaction-acts-scoring-params.
// The value itself will never be used by the VTTSHandler.
for(ScoringConfigGroup.ActivityParams activityParams : ruhrConfig.scoring().getActivityParams().stream().toList()) {
for(String subIgnoredAct : ignoredActs.split(";")) {
if(activityParams.getActivityType().contains(subIgnoredAct)) activityParams.setTypicalDuration(0.1);
}
}

if(snzScoring) SnzActivities.addScoringParams(ruhrConfig);

//SnzActivities.addScoringParams(ruhrConfig); Not needed in this simulation setup
Scenario ruhrScenario = ScenarioUtils.loadScenario(ruhrConfig);

//
org.matsim.analysis.VTTSHandler handler = new org.matsim.analysis.VTTSHandler(ruhrScenario, new String[]{"walk"}, new String[]{"interaction"});
org.matsim.analysis.VTTSHandler handler = new org.matsim.analysis.VTTSHandler(ruhrScenario, ignoredModes.split(";"), ignoredActs.split(";"));
if(incomeDependantScoring) handler.applyIncomeDependantScoring();

EventsManager manager = EventsUtils.createEventsManager();
manager.addHandler(handler);
EventsUtils.readEvents(manager, eventsPath);

EventsUtils.readEvents(manager, "../VTTS/000.output_events.xml.gz");
handler.printVTTS(outPath + "VTTS");
handler.printCarVTTS(outPath + "carVTTS");
handler.printAvgVTTSperPerson(outPath + "avgVTTSperPerson");
for(String mode : modes.split(";")){
handler.printVTTS(outPath + "VTTS_" + mode, mode);
}
for(String stat : statistics.split(";")) {
handler.printVTTSstatistics(
outPath + "VTTSstatistics_" + stat.split(",")[0],
stat.split(",")[0],
new Tuple<>(Double.parseDouble(stat.split(",")[1]), Double.parseDouble(stat.split(",")[2])));
}

handler.printVTTS("../VTTS/testPrintVTTS");
handler.printCarVTTS("../VTTS/testPrintCarVTTS");
handler.printVTTS("../VTTS/testPrintVTTSMode2", TransportMode.bike);
handler.printAvgVTTSperPerson("../VTTS/testPrintAvgVTTSperPerson");
return 0;
}
}
42 changes: 40 additions & 2 deletions src/main/java/org/matsim/analysis/VTTSHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import java.util.Map;
import java.util.Set;

import com.google.inject.Singleton;
import org.apache.commons.math.stat.StatUtils;
//import org.apache.log4j.Logger;
import org.matsim.api.core.v01.Id;
Expand All @@ -47,11 +48,16 @@
import org.matsim.api.core.v01.population.Person;
import org.matsim.contrib.dvrp.vrpagent.VrpAgentLogic;
import org.matsim.contrib.vsp.scenario.SnzActivities;
import org.matsim.core.controler.AbstractModule;
import org.matsim.core.controler.Controler;
import org.matsim.core.controler.events.AfterMobsimEvent;
import org.matsim.core.events.handler.EventHandler;
import org.matsim.core.population.PopulationUtils;
import org.matsim.core.scoring.ScoringFunction;
import org.matsim.core.scoring.functions.ScoringParameters;
import org.matsim.core.scoring.functions.ScoringParametersForPerson;
import org.matsim.core.utils.collections.Tuple;
import playground.vsp.scoring.IncomeDependentUtilityOfMoneyPersonScoringParameters;


/**
Expand All @@ -74,9 +80,13 @@ public class VTTSHandler implements ActivityStartEventHandler, ActivityEndEventH
private static int noTripVTTSWarning = 0; // TODO #!
private static int noTripNrWarning = 0; // TODO #!

private final Controler controler;
private final Scenario scenario;
private int currentIteration;

//personalUtilityOfMoney for every agent
private final Map<Id<Person>, Double> personId2utilityOfMoney = new HashMap<>();

//Persons, acts and modes that should not be considered for VTTS
private final Set<Id<Person>> personIdsToBeIgnored = new HashSet<>();
private final String[] stageActivitiesSubStrings;
Expand All @@ -99,6 +109,8 @@ public class VTTSHandler implements ActivityStartEventHandler, ActivityEndEventH

private final double defaultVTTS_moneyPerHour; // for the car mode! TODO #?

// ===== Setup-methods ===========================================================================================================================

/**
* Returns an {@link EventHandler}-child for the VTTS-computation of a scenario for all agents.
* After reading an EventFile the <i>print</i>-methods ({@link #printVTTS}, {@link #printCarVTTS},
Expand All @@ -115,6 +127,7 @@ public VTTSHandler(Scenario scenario, String[] helpLegModes, String stageActivit
this.modesToBeSkipped = helpLegModes;
this.stageActivitiesSubStrings = new String[]{stageActivitySubString};
this.scenario = scenario;
this.controler = new Controler(scenario);
this.currentIteration = Integer.MIN_VALUE;
this.defaultVTTS_moneyPerHour =
(this.scenario.getConfig().scoring().getPerforming_utils_hr()
Expand All @@ -138,13 +151,34 @@ public VTTSHandler(Scenario scenario, String[] helpLegModes, String[] stageActiv
this.modesToBeSkipped = helpLegModes;
this.stageActivitiesSubStrings = stageActivitiesSubStrings;
this.scenario = scenario;
this.controler = new Controler(scenario);
this.currentIteration = Integer.MIN_VALUE;
this.defaultVTTS_moneyPerHour =
(this.scenario.getConfig().scoring().getPerforming_utils_hr()
+ this.scenario.getConfig().scoring().getModes().get( TransportMode.car ).getMarginalUtilityOfTraveling() * (-1.0)
) / this.scenario.getConfig().scoring().getMarginalUtilityOfMoney();
}

/**
* Once this method is called, the VTTS will compute the income-dependant marginal utility of money for every person,
* instead of using the marginal utility from the config.
*/
public void applyIncomeDependantScoring(){
controler.addOverridingModule(new AbstractModule() {
@Override
public void install() {
bind(ScoringParametersForPerson.class).to(IncomeDependentUtilityOfMoneyPersonScoringParameters.class).in(Singleton.class);
}
});
controler.getInjector(); //Initializes Injector
for(Person p : scenario.getPopulation().getPersons().values()){
ScoringFunction scoring = controler.getScoringFunctionFactory().createNewScoringFunction(p);
assert scoring.getScore() == 0; //If this fails, you should check your config for changes in the scoring-module
scoring.addMoney(1.0);
personId2utilityOfMoney.putIfAbsent(p.getId(), scoring.getScore());
}
}

// ===== Parsing-methods =========================================================================================================================

@Override
Expand Down Expand Up @@ -369,7 +403,9 @@ private void computeVTTS(Id<Person> personId, double activityEndTime) {
double tripDelayDisutilityOneSec = (1.0 / 3600.) * marginalUtilityOfTraveling * (-1);

// Translate the disutility into monetary units.
double delayCostPerSec_usingActivityDelayOneSec = (activityDelayDisutilityOneSec + tripDelayDisutilityOneSec) / this.scenario.getConfig().scoring().getMarginalUtilityOfMoney();
double delayCostPerSec_usingActivityDelayOneSec = (personId2utilityOfMoney.isEmpty()) ?
(activityDelayDisutilityOneSec + tripDelayDisutilityOneSec) / this.scenario.getConfig().scoring().getMarginalUtilityOfMoney() :
(activityDelayDisutilityOneSec + tripDelayDisutilityOneSec) / personId2utilityOfMoney.get(personId);

// Store the VTTS for analysis purposes
if (this.personId2VTTSh.containsKey(personId)) {
Expand Down Expand Up @@ -447,7 +483,9 @@ private void computeVTTS(Id<Person> personId) {
double tripDelayDisutilityOneSec = (1.0 / 3600.) * marginalUtilityOfTraveling * (-1);

// Translate the disutility into monetary units.
double delayCostPerSec_usingActivityDelayOneSec = (activityDelayDisutilityOneSec + tripDelayDisutilityOneSec) / this.scenario.getConfig().scoring().getMarginalUtilityOfMoney();
double delayCostPerSec_usingActivityDelayOneSec = (personId2utilityOfMoney.isEmpty()) ?
(activityDelayDisutilityOneSec + tripDelayDisutilityOneSec) / this.scenario.getConfig().scoring().getMarginalUtilityOfMoney() :
(activityDelayDisutilityOneSec + tripDelayDisutilityOneSec) / personId2utilityOfMoney.get(personId);

// Store the VTTS for analysis purposes
if (this.personId2VTTSh.containsKey(personId)) {
Expand Down

0 comments on commit 7071877

Please sign in to comment.