Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add pt flat #9

Merged
merged 8 commits into from
Jun 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 75 additions & 9 deletions src/main/java/org/matsim/run/RunGladbeckScenario.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
import org.matsim.api.core.v01.TransportMode;
import org.matsim.api.core.v01.network.Link;
import org.matsim.api.core.v01.population.Activity;
import org.matsim.api.core.v01.population.Person;
import org.matsim.application.MATSimApplication;
import org.matsim.application.analysis.HomeLocationFilter;
import org.matsim.application.analysis.emissions.AirPollutionByVehicleCategory;
import org.matsim.application.analysis.emissions.AirPollutionSpatialAggregation;
import org.matsim.application.analysis.noise.NoiseAnalysis;
Expand All @@ -21,6 +23,7 @@
import org.matsim.core.config.groups.PlansCalcRouteConfigGroup;
import org.matsim.core.controler.AbstractModule;
import org.matsim.core.controler.Controler;
import org.matsim.core.gbl.MatsimRandom;
import org.matsim.core.population.PopulationUtils;
import org.matsim.core.router.MultimodalLinkChooser;
import org.matsim.core.utils.io.IOUtils;
Expand All @@ -29,15 +32,15 @@
import org.matsim.prepare.PrepareOpenPopulation;
import org.matsim.prepare.ScenarioCutOut;
import org.matsim.run.policies.KlimaTaler;
import org.matsim.run.policies.PtFlatrate;
import org.matsim.run.policies.ReduceSpeed;
import org.matsim.run.policies.SchoolRoadsClosure;
import org.matsim.utils.gis.shp2matsim.ShpGeometryUtils;
import picocli.CommandLine;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.io.BufferedWriter;
import java.io.IOException;
import java.util.*;

@CommandLine.Command(header = ":: Gladbeck Scenario ::", version = RunGladbeckScenario.VERSION)
@MATSimApplication.Prepare({ScenarioCutOut.class, DownSamplePopulation.class, FixSubtourModes.class, XYToLinks.class, ExtractHomeCoordinates.class, BicyclePolicies.class, PrepareOpenPopulation.class})
Expand All @@ -51,17 +54,23 @@ public class RunGladbeckScenario extends RunMetropoleRuhrScenario {
@CommandLine.Option(names = "--schoolClosure", defaultValue = "false", description = "measures to ban car on certain links")
boolean schoolClosure;

@CommandLine.Option(names = "--tempo30Zone", defaultValue = "false", description = "measures to reduce car speed to 30 km/h")
@CommandLine.Option(names = "--tempo30Zone", defaultValue = "false", description = "measures to reduce car speed to 30 km/h in a zone")
boolean slowSpeedZone;

@CommandLine.Option(names = "--tempo30Streets", defaultValue = "false", description = "measures to reduce car speed to 30 km/h")
@CommandLine.Option(names = "--tempo30Streets", defaultValue = "false", description = "measures to reduce car speed to 30 km/h on links definded by a shape file")
boolean slowSpeedOnDefinedLinks;

@CommandLine.Mixin
private ShpOptions shp;

@CommandLine.Option(names = "--simplePtFlat", defaultValue = "false", description = "measures to allow everyone to have free pt")
boolean simplePtFlat;
boolean scenarioWidePtFlat;

@CommandLine.Option(names = "--ptFlat", defaultValue = "0", description = "measures to allow people in Gladbeck to have free pt, if set to zero no agent will have free pt")
int ptFlat;

@CommandLine.Option(names = "--cityWidePtFlat", defaultValue = "false", description = "measures to allow every resident in Gladbeck to have free pt")
boolean cityWidePtFlat;

@CommandLine.Option(names = "--cyclingCourse", defaultValue = "false", description = "measures to increase the ")
boolean cyclingCourse;
Expand Down Expand Up @@ -101,7 +110,7 @@ protected Config prepareConfig(Config config) {
// so we don´t use the rvr accessEgressModeToLinkPlusTimeConstant
config.plansCalcRoute().setAccessEgressType(PlansCalcRouteConfigGroup.AccessEgressType.accessEgressModeToLink);

if (simplePtFlat) {
if (scenarioWidePtFlat) {
config.planCalcScore().getModes().get(TransportMode.pt).setDailyMonetaryConstant(0.0);
}

Expand All @@ -122,7 +131,6 @@ protected void prepareScenario(Scenario scenario) {
ReduceSpeed.implementPushMeasuresByModifyingNetworkInArea(scenario.getNetwork(), ShpGeometryUtils.loadPreparedGeometries(IOUtils.resolveFileOrResource(shp.getShapeFile().toString())));
}


if (schoolClosure) {
List<Id<Link>> listOfSchoolLinks = new ArrayList<>();
//TODO switch to shp file
Expand Down Expand Up @@ -190,6 +198,41 @@ public void install() {
bind(MultimodalLinkChooser.class).to(NearestLinkChooser.class);
}
});


if (ptFlat !=0 || cityWidePtFlat) {

List<Id<Person>> agentsLivingInGladbeck = new ArrayList<>();
List<Id<Person>> agentsWithPtFlat = new ArrayList<>();
HomeLocationFilter homeLocationFilter = new HomeLocationFilter(shp, controler.getScenario().getConfig().global().getCoordinateSystem(), controler.getScenario().getPopulation());

for (Person person: controler.getScenario().getPopulation().getPersons().values()) {
if (homeLocationFilter.test(controler.getScenario().getPopulation().getPersons().get(person.getId()))) {
agentsLivingInGladbeck.add(person.getId());
}
}


if (cityWidePtFlat) {
agentsWithPtFlat.addAll(agentsLivingInGladbeck);
} else {
for (int ii= 0; ii < ptFlat; ii++) {
Random generator = MatsimRandom.getRandom();
Object[] values = agentsLivingInGladbeck.toArray();
var randomPerson = (Id<Person>) values[generator.nextInt(values.length)];
agentsWithPtFlat.add(randomPerson);
agentsLivingInGladbeck.remove(randomPerson);
}
}
log.info("adding pt flat." + agentsWithPtFlat.size() +" agents will pay no pt cost");
try {
writeOutAgents(agentsWithPtFlat);
} catch (IOException e) {
throw new RuntimeException(e);
}
addPtFlat(controler, new PtFlatrate(agentsWithPtFlat, controler.getConfig().planCalcScore().getModes().get(TransportMode.pt).getDailyMonetaryConstant()));

}
super.prepareControler(controler);
}

Expand All @@ -203,4 +246,27 @@ public void install() {
}
});
}

public static void addPtFlat(Controler controler, PtFlatrate ptFlatrate) {
controler.addOverridingModule(new AbstractModule() {
@Override
public void install() {
addEventHandlerBinding().toInstance(ptFlatrate);
addControlerListenerBinding().toInstance(ptFlatrate);
new PersonMoneyEventsAnalysisModule();
}
});
}

private static void writeOutAgents(List<Id<Person>> listOfIds) throws IOException {
BufferedWriter writer = IOUtils.getBufferedWriter("agentsWithFreePt.tsv");

writer.write("Id");
writer.newLine();
for (Id<Person> listOfId : listOfIds) {
writer.write(listOfId.toString());
writer.newLine();
}
writer.close();
}
}
28 changes: 12 additions & 16 deletions src/main/java/org/matsim/run/policies/PtFlatrate.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,45 +10,41 @@
import org.matsim.core.controler.listener.AfterMobsimListener;
import org.matsim.core.utils.misc.Time;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class PtFlatrate implements PersonDepartureEventHandler, AfterMobsimListener {

private final Map<Id<Person>, Integer> personsEligibleForPtFiltrate;
private final Map<Id<Person>, Integer> currentIterationForPtFlatrate = new HashMap<>();
private final double ptConstant;
private final List<Id<Person>> personsEligibleForPtFlatrate;
private final List<Id<Person>> currentIterationForPtFlatrate = new ArrayList<>();
private final double ptDailyMonetaryConstant;

public PtFlatrate(Map<Id<Person>, Integer> personsEligibleForPtFiltrate, double ptConstant, double ptDailyMonetaryConstant) {
this.personsEligibleForPtFiltrate = personsEligibleForPtFiltrate;
this.ptConstant = ptConstant;
public PtFlatrate(List<Id<Person>> personsEligibleForPtFlatrate, double ptDailyMonetaryConstant) {
this.personsEligibleForPtFlatrate = personsEligibleForPtFlatrate;
this.ptDailyMonetaryConstant = ptDailyMonetaryConstant;
}

@Override
public void handleEvent(PersonDepartureEvent personDepartureEvent) {
if (currentIterationForPtFlatrate.containsKey(personDepartureEvent.getPersonId())
if (currentIterationForPtFlatrate.contains(personDepartureEvent.getPersonId())
&& personDepartureEvent.getLegMode().equals(TransportMode.pt)) {
int numberOfPtTrips = currentIterationForPtFlatrate.get(personDepartureEvent.getPersonId());
numberOfPtTrips++;
currentIterationForPtFlatrate.replace(personDepartureEvent.getPersonId(),numberOfPtTrips);
currentIterationForPtFlatrate.add(personDepartureEvent.getPersonId());
}
}

@Override
public void notifyAfterMobsim(AfterMobsimEvent afterMobsimEvent) {
for (Map.Entry<Id<Person>, Integer> idDoubleEntry : currentIterationForPtFlatrate.entrySet()) {
Id<Person> person = idDoubleEntry.getKey();
Integer numberOfPtTrips = idDoubleEntry.getValue();
double ptFlat = numberOfPtTrips * ptConstant + ptDailyMonetaryConstant;
afterMobsimEvent.getServices().getEvents().processEvent(new PersonMoneyEvent(Time.MIDNIGHT, person, ptFlat, "ptFlat",null, null ));
for (Id person: currentIterationForPtFlatrate) {
// multiplied by -1 to throw positiv person money event
afterMobsimEvent.getServices().getEvents().processEvent(new PersonMoneyEvent(Time.MIDNIGHT, person, (-1) * ptDailyMonetaryConstant, "ptFlat",null, null ));
}
}

@Override
public void reset(int iteration) {
currentIterationForPtFlatrate.clear();
currentIterationForPtFlatrate.putAll(personsEligibleForPtFiltrate);
currentIterationForPtFlatrate.addAll(personsEligibleForPtFlatrate);
}
}
2 changes: 1 addition & 1 deletion src/test/java/org/matsim/run/GladbeckIntegrationTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import playground.vsp.openberlinscenario.cemdap.output.ActivityTypes;
import playground.vsp.scoring.IncomeDependentUtilityOfMoneyPersonScoringParameters;

@Ignore

public class GladbeckIntegrationTest {
@Rule
public MatsimTestUtils utils = new MatsimTestUtils();
Expand Down
57 changes: 45 additions & 12 deletions src/test/java/org/matsim/run/TestPtFlat.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@

import static org.junit.Assert.assertTrue;

//test runs too long...
@Ignore
public class TestPtFlat {

private static final Id<Person> personId = Id.createPersonId("test-person");
private static final String inputNetworkFile = "https://svn.vsp.tu-berlin.de/repos/public-svn/matsim/scenarios/countries/de/metropole-ruhr/metropole-ruhr-v1.0/input/metropole-ruhr-v1.0.network_resolutionHigh-with-pt.xml.gz";
private static final String inputNetworkFile = "https://svn.vsp.tu-berlin.de/repos/public-svn/matsim/scenarios/countries/de/gladbeck/glamobi/input/gladbeck-v1.0-10pct.network.xml.gz";

@Rule
public MatsimTestUtils testUtils = new MatsimTestUtils();
Expand All @@ -32,20 +33,33 @@ public void testPtFlat() {

var outputDir = testUtils.getOutputDirectory();

MATSimApplication.execute(TestApplication.class, "--output=" + outputDir + "withPtFlat", "--simplePtFlat=true", "--download-input", "--1pct", "--config:network.inputNetworkFile=" + inputNetworkFile);
MATSimApplication.execute(TestApplication.class, "--output=" + outputDir + "withoutPtFlat", "--simplePtFlat=false", "--download-input", "--1pct", "--config:network.inputNetworkFile=" + inputNetworkFile);
MATSimApplication.execute(TestApplication.class, "--output=" + outputDir + "withPtFlat", "--ptFlat", "1", "--1pct", "--config:network.inputNetworkFile=" + inputNetworkFile,
"--shp", "/Users/gregorr/Documents/work/respos/shared-svn/projects/GlaMoBi/data/shp-files/Gladbeck.shp",
"--shp-crs", "EPSG:25832"
);
MATSimApplication.execute(TestApplication.class, "--output=" + outputDir + "withoutPtFlat", "--1pct", "--config:network.inputNetworkFile=" + inputNetworkFile,
"--shp", "/Users/gregorr/Documents/work/respos/shared-svn/projects/GlaMoBi/data/shp-files/Gladbeck.shp",
"--shp-crs", "EPSG:25832"
);

// load output of both runs
var scenarioWithPtFlat = ScenarioUtils.createScenario(ConfigUtils.createConfig());
new PopulationReader(scenarioWithPtFlat).readFile(outputDir + "withPtFlat/" + TestApplication.RUN_ID + ".output_plans.xml.gz");
var scenarioWithoutPtFlat = ScenarioUtils.createScenario(ConfigUtils.createConfig());
new PopulationReader(scenarioWithoutPtFlat).readFile(outputDir + "withoutPtFlat/" + TestApplication.RUN_ID + ".output_plans.xml.gz");
// somehow compare the two routes
var personWithPtFlat = scenarioWithPtFlat.getPopulation().getPersons().get(personId);
var personWithoutPtFlat = scenarioWithoutPtFlat.getPopulation().getPersons().get(personId);
// somehow compare the two plans
var unaffectedAgentScenario1 = scenarioWithPtFlat.getPopulation().getPersons().get(personId);
var unaffectedAgentScenario2 = scenarioWithoutPtFlat.getPopulation().getPersons().get(personId);

assertTrue(personWithPtFlat.getSelectedPlan().getScore() > personWithoutPtFlat.getSelectedPlan().getScore());
assertTrue(unaffectedAgentScenario1.getSelectedPlan().getScore().equals(unaffectedAgentScenario2.getSelectedPlan().getScore()));

System.out.printf(scenarioWithPtFlat.getPopulation().getPersons().toString() + "\n");
var agentWithPtFlat = scenarioWithPtFlat.getPopulation().getPersons().get(Id.createPersonId(personId+"inside"));
var agentWithoutPtFlat = scenarioWithoutPtFlat.getPopulation().getPersons().get(Id.createPersonId(personId+"inside"));



assertTrue(agentWithPtFlat.getSelectedPlan().getScore() > agentWithoutPtFlat.getSelectedPlan().getScore());
}

public static class TestApplication extends RunGladbeckScenario {
Expand All @@ -54,8 +68,8 @@ public static class TestApplication extends RunGladbeckScenario {
@Override
public Config prepareConfig(Config config) {
Config preparedConfig = super.prepareConfig(config);
preparedConfig.global().setNumberOfThreads(1);
preparedConfig.qsim().setNumberOfThreads(1);
//preparedConfig.global().setNumberOfThreads(1);
//preparedConfig.qsim().setNumberOfThreads(1);
preparedConfig.plans().setInputFile(null);
preparedConfig.controler().setLastIteration(0);
preparedConfig.controler().setRunId(RUN_ID);
Expand All @@ -66,24 +80,43 @@ public Config prepareConfig(Config config) {
protected void prepareScenario(Scenario scenario) {
// Other agents are not needed for the test
scenario.getPopulation().getPersons().clear();
// add single person with two activities
// add single person with two activities living outside gladbeck
var factory = scenario.getPopulation().getFactory();
var plan = factory.createPlan();
var homeCoord = scenario.getNetwork().getLinks().get( Id.createLinkId("pt_65711")).getCoord();
var home = factory.createActivityFromCoord("home_600.0", homeCoord);
var home = factory.createActivityFromCoord("home_600", homeCoord);
home.setEndTime(50400);
plan.addActivity(home);
var leg = factory.createLeg(TransportMode.pt);
leg.setMode(TransportMode.pt);
plan.addLeg(leg);
var otherCoord = scenario.getNetwork().getLinks().get( Id.createLinkId("pt_65377")).getCoord();
var other = factory.createActivityFromCoord("other_3600.0",otherCoord);
var other = factory.createActivityFromCoord("other_3600",otherCoord);
other.setEndTime(54000);
plan.addActivity(other);
var person = factory.createPerson(personId);
person.addPlan(plan);
person.getAttributes().putAttribute("subpopulation", "person");
person.getAttributes().putAttribute(IncomeDependentUtilityOfMoneyPersonScoringParameters.PERSONAL_INCOME_ATTRIBUTE_NAME, 1.0);

// add single person with two activities living inside gladbeck
var planInsider = factory.createPlan();
var homeCoordInsider = scenario.getNetwork().getLinks().get(Id.createLinkId("pt_65455")).getCoord();
var homeInsider = factory.createActivityFromCoord("home_600", homeCoordInsider);
homeInsider.setEndTime(50400);
planInsider.addActivity(homeInsider);
var legInsider = factory.createLeg(TransportMode.pt);
legInsider.setMode(TransportMode.pt);
planInsider.addLeg(legInsider);
var otherCoordInsider = scenario.getNetwork().getLinks().get( Id.createLinkId("pt_65377")).getCoord();
var otherInsider = factory.createActivityFromCoord("other_3600",otherCoordInsider);
otherInsider.setEndTime(54000);
planInsider.addActivity(otherInsider);
var personInsider = factory.createPerson(Id.createPersonId(personId+"inside"));
personInsider.addPlan(planInsider);
personInsider.getAttributes().putAttribute("subpopulation", "person");
personInsider.getAttributes().putAttribute(IncomeDependentUtilityOfMoneyPersonScoringParameters.PERSONAL_INCOME_ATTRIBUTE_NAME, 1.0);
scenario.getPopulation().addPerson(personInsider);
scenario.getPopulation().addPerson(person);
super.prepareScenario(scenario);

Expand Down
Loading