diff --git a/src/main/java/org/matsim/prepare/HomeMultipleLocationFilter.java b/src/main/java/org/matsim/prepare/HomeMultipleLocationFilter.java index 2665777..fef21c0 100644 --- a/src/main/java/org/matsim/prepare/HomeMultipleLocationFilter.java +++ b/src/main/java/org/matsim/prepare/HomeMultipleLocationFilter.java @@ -85,7 +85,7 @@ public HomeMultipleLocationFilter(ShpOptions analysisAreaShapeFile, String input * @param p Person to check * @param key Will search in all polygons, that have this {@code key} value in the {@code columnToMap} attribute. */ - public boolean checkIfPersonInPolygon(Person p, String key){ // TODO Replace by efficient solution + public boolean checkIfPersonInPolygon(Person p, String key){ return personMapping.get(key).contains(p.getId()); } diff --git a/src/main/java/org/matsim/prepare/MigrantBicycleChoiceHandler.java b/src/main/java/org/matsim/prepare/MigrantBicycleChoiceHandler.java new file mode 100644 index 0000000..fefcb41 --- /dev/null +++ b/src/main/java/org/matsim/prepare/MigrantBicycleChoiceHandler.java @@ -0,0 +1,77 @@ +package org.matsim.prepare; + +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.events.PersonDepartureEvent; +import org.matsim.api.core.v01.events.PersonMoneyEvent; +import org.matsim.api.core.v01.events.PersonScoreEvent; +import org.matsim.api.core.v01.events.handler.PersonDepartureEventHandler; +import org.matsim.api.core.v01.population.Population; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.controler.events.AfterMobsimEvent; +import org.matsim.core.controler.events.ReplanningEvent; +import org.matsim.core.controler.listener.AfterMobsimListener; +import org.matsim.core.controler.listener.ReplanningListener; +import org.matsim.core.events.EventsUtils; +import org.matsim.core.gbl.MatsimRandom; +import org.matsim.core.population.PopulationUtils; + +import java.util.LinkedList; +import java.util.List; +import java.util.Random; + +public class MigrantBicycleChoiceHandler implements PersonDepartureEventHandler, AfterMobsimListener { + private List migrantDepartures; + private Population population; + + public MigrantBicycleChoiceHandler(Population population) { + migrantDepartures = new LinkedList<>(); + this.population = population; + } + + public MigrantBicycleChoiceHandler(String populationPath) { + migrantDepartures = new LinkedList<>(); + this.population = PopulationUtils.readPopulation(populationPath); + } + + @Override + public void handleEvent(PersonDepartureEvent personDepartureEvent) { + // Do not do anything, if this Person is not a migrant + if( !population.getPersons().get(personDepartureEvent.getPersonId()).getAttributes().getAsMap().containsKey("subpopulation") + || !population.getPersons().get(personDepartureEvent.getPersonId()).getAttributes().getAttribute("subpopulation").equals("migrant") ){ + return; + } + + // Add to departures of migrants + Random rand = MatsimRandom.getRandom(); + if(personDepartureEvent.getLegMode().equals("bicycle") && rand.nextInt(1000) < 1000) new PersonMoneyEvent(personDepartureEvent.getTime(), personDepartureEvent.getPersonId(), 1000); //TODO what is kind?; set rand-value to 400 + // TODO TransportMode.bike + } + + + @Override + public void notifyAfterMobsim(AfterMobsimEvent afterMobsimEvent) { + for(PersonScoreEvent e : migrantDepartures){ + // TODO Check if this will actually influence the choice + // TODO Check what would be a useful value + // TODO Gibt es keine direktere Möglichkeit? Kann ich das Event nicht einfach irgendwie überschreiben? + afterMobsimEvent.getServices().getEvents().processEvent(e); + } + migrantDepartures.clear(); + } + + public static void main(String[] args) { + //MigrantBicycleChoiceHandler choiceHandler = new MigrantBicycleChoiceHandler(); + + } + +// @Override +// public void notifyReplanning(ReplanningEvent replanningEvent) { +// /*for(PersonScoreEvent e : migrantDepartures){ +// // TODO Check if this will actually influence the choice +// // TODO Check what would be a useful value +// // TODO Gibt es keine direktere Möglichkeit? Kann ich das Event nicht einfach irgendwie überschreiben? +// replanningEvent.getServices().getEvents().processEvent(e); +// }*/ +// } +} diff --git a/src/main/java/org/matsim/prepare/MigrantMapper.java b/src/main/java/org/matsim/prepare/MigrantMapper.java index 63231d8..31399cd 100644 --- a/src/main/java/org/matsim/prepare/MigrantMapper.java +++ b/src/main/java/org/matsim/prepare/MigrantMapper.java @@ -215,7 +215,8 @@ private void assignMigrantMapToPopulation(){ for(var e : migrantProbabilityMap.entrySet()){ double r = e.getValue(); boolean isMigrant = rand.nextInt(1000) < r*1000; - pop.getPersons().get(e.getKey()).getAttributes().putAttribute("isMigrant", isMigrant); + //pop.getPersons().get(e.getKey()).getAttributes().putAttribute("isMigrant", isMigrant); + pop.getPersons().get(e.getKey()).getAttributes().putAttribute("subpopulation", "migrant"); if (isMigrant) totalMigrants++; //TODO DEBUG if (isMigrant){ @@ -246,6 +247,8 @@ public static void main(String[] args) { "Name", "EPSG:25832" ); + PopulationUtils.writePopulation(detecter.getPopulation(), "output/gladbeck-v1.3-10pct.migrants-mapped.xml.gz"); + System.out.println(detecter.getMigrantAmount()); System.out.println(detecter.district_amounts); System.out.println(detecter.district_migrant_amounts); diff --git a/src/test/java/org/matsim/prepare/MigrantBicycleChoiceHandlerTest.java b/src/test/java/org/matsim/prepare/MigrantBicycleChoiceHandlerTest.java new file mode 100644 index 0000000..af9e562 --- /dev/null +++ b/src/test/java/org/matsim/prepare/MigrantBicycleChoiceHandlerTest.java @@ -0,0 +1,220 @@ +package org.matsim.prepare; + +import ch.sbb.matsim.routing.pt.raptor.RaptorIntermodalAccessEgress; +import ch.sbb.matsim.routing.pt.raptor.SwissRailRaptorModule; +import com.google.inject.Singleton; +import com.google.inject.multibindings.Multibinder; +import org.junit.Test; +import org.matsim.analysis.ModeChoiceCoverageControlerListener; +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; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.population.Person; +import org.matsim.api.core.v01.population.Population; +import org.matsim.api.core.v01.population.PopulationFactory; +import org.matsim.contrib.bicycle.BicycleConfigGroup; +import org.matsim.contrib.bicycle.Bicycles; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.StrategyConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy; +import org.matsim.core.events.EventsUtils; +import org.matsim.core.population.PopulationUtils; +import org.matsim.core.replanning.strategies.DefaultPlanStrategiesModule; +import org.matsim.core.router.AnalysisMainModeIdentifier; +import org.matsim.core.router.MultimodalLinkChooser; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.scoring.functions.ScoringParametersForPerson; +import org.matsim.examples.ExamplesUtils; +import org.matsim.extensions.pt.fare.intermodalTripFareCompensator.IntermodalTripFareCompensatorsModule; +import org.matsim.extensions.pt.routing.EnhancedRaptorIntermodalAccessEgress; +import org.matsim.extensions.pt.routing.ptRoutingModes.PtIntermodalRoutingModesModule; +import org.matsim.run.IntermodalPtAnalysisModeIdentifier; +import org.matsim.run.NearestLinkChooser; +import org.matsim.run.StrategyWeightFadeout; +import playground.vsp.scoring.IncomeDependentUtilityOfMoneyPersonScoringParameters; +import playground.vsp.simpleParkingCostHandler.ParkingCostConfigGroup; +import playground.vsp.simpleParkingCostHandler.ParkingCostModule; + +public class MigrantBicycleChoiceHandlerTest { + + String migrantPopulationPath = "gladbeck-v1.3-10pct.migrants-mapped.xml.gz"; // TODO Adjust path + + private void prepareConfig(Config config){} + + private void prepareScenario(Scenario scenario){} + + private void prepareControler(Controler controler){} + + @Test + public void testSubpopulationBiking() { + //TODO ... config.planCalcScore() + + //Setup simulation test-run + // ==CONFIG== + Config config = ConfigUtils.loadConfig("scenarios/gladbeck-v1.0/input/gladbeck-v1.0-10pct.config.xml"); + + config.controler().setLastIteration(0); + config.controler().setOutputDirectory("output/MigrantBicycleTest"); + config.global().setNumberOfThreads(1); + config.qsim().setNumberOfThreads(1); + config.controler().setOverwriteFileSetting(OutputDirectoryHierarchy.OverwriteFileSetting.deleteDirectoryIfExists); + config.plans().setInputFile(migrantPopulationPath); + //additional contribs + //bike + BicycleConfigGroup bikeConfigGroup = (BicycleConfigGroup)ConfigUtils.addOrGetModule(config, BicycleConfigGroup.class); + bikeConfigGroup.setBicycleMode("bike"); + //parking costs + ParkingCostConfigGroup parkingCostConfigGroup = (ParkingCostConfigGroup)ConfigUtils.addOrGetModule(config, ParkingCostConfigGroup.class); + parkingCostConfigGroup.setFirstHourParkingCostLinkAttributeName("oneHourPCost"); + parkingCostConfigGroup.setExtraHourParkingCostLinkAttributeName("extraHourPCost"); + parkingCostConfigGroup.setMaxDailyParkingCostLinkAttributeName("maxDailyPCost"); + parkingCostConfigGroup.setMaxParkingDurationAttributeName("maxPTime"); + parkingCostConfigGroup.setParkingPenaltyAttributeName("pFine"); + parkingCostConfigGroup.setResidentialParkingFeeAttributeName("resPCosts"); + + // ==SCENARIO== + Scenario scenario = ScenarioUtils.loadScenario(config); + + //Extract one test-person + Person migrant = null; + for(Person p : scenario.getPopulation().getPersons().values()){ + if(p.getAttributes().getAttribute("subpopulation").equals("migrant")){ + migrant = p; + break; + } + } + assert migrant != null; + + scenario.getPopulation().getPersons().clear(); + scenario.getPopulation().addPerson(migrant); + + //==CONTROL(L)ER== + Controler controler = new Controler(scenario); + + controler.addOverridingModule(new AbstractModule() { + @Override + public void install() { + bind(MultimodalLinkChooser.class).to(NearestLinkChooser.class); + } + }); + controler.addOverridingModule(new SwissRailRaptorModule()); + controler.addOverridingModule(new AbstractModule() { + public void install() { + this.bind(RaptorIntermodalAccessEgress.class).to(EnhancedRaptorIntermodalAccessEgress.class); + this.bind(AnalysisMainModeIdentifier.class).to(IntermodalPtAnalysisModeIdentifier.class); + } + }); + controler.addOverridingModule(new PtIntermodalRoutingModesModule()); + controler.addOverridingModule(new IntermodalTripFareCompensatorsModule()); + controler.addOverridingModule(new LinkPaxVolumesAnalysisModule()); + controler.addOverridingModule(new PtStop2StopAnalysisModule()); + controler.addOverridingModule(new AbstractModule() { + public void install() { + this.bind(ScoringParametersForPerson.class).to(IncomeDependentUtilityOfMoneyPersonScoringParameters.class).in(Singleton.class); + } + }); + controler.addOverridingModule(new AbstractModule() { + public void install() { + this.addTravelTimeBinding("ride").to(this.networkTravelTime()); + this.addTravelDisutilityFactoryBinding("ride").to(this.carTravelDisutilityFactoryKey()); + this.addTravelTimeBinding("bike").to(this.networkTravelTime()); + this.addControlerListenerBinding().to(ModeChoiceCoverageControlerListener.class); + this.addControlerListenerBinding().to(StrategyWeightFadeout.class).in(Singleton.class); + Multibinder schedules = Multibinder.newSetBinder(this.binder(), StrategyWeightFadeout.Schedule.class); + schedules.addBinding().toInstance(new StrategyWeightFadeout.Schedule("SubtourModeChoice", "person", 0.75, 0.85)); + schedules.addBinding().toInstance(new StrategyWeightFadeout.Schedule("ReRoute", "person", 0.78)); + } + }); + controler.addOverridingModule(new AbstractModule() { + public void install() { + this.install(new PersonMoneyEventsAnalysisModule()); + } + }); + controler.addOverridingModule(new ParkingCostModule()); + Bicycles.addAsOverridingModule(controler); + + //Setup Choice Handler + MigrantBicycleChoiceHandler choiceHandler = new MigrantBicycleChoiceHandler(scenario.getPopulation()); //TODO Make path universal + controler.addOverridingModule(new AbstractModule() { + @Override + public void install() { + addEventHandlerBinding().toInstance(choiceHandler); + } + }); + + //DEBUG{ + System.out.println(); + //config.getModules().values(); + //}END + + controler.run(); + } + + @Test + public void test2(){ + String inputPath = String.valueOf(ExamplesUtils.getTestScenarioURL("equil-mixedTraffic")); + Config config = ConfigUtils.loadConfig(inputPath + "config-with-mode-vehicles.xml"); + { + config.controler().setLastIteration(3); + config.controler().setOutputDirectory("output/MigrantBicycleTest/"); + config.global().setNumberOfThreads(1); + config.qsim().setNumberOfThreads(1); + config.controler().setOverwriteFileSetting(OutputDirectoryHierarchy.OverwriteFileSetting.deleteDirectoryIfExists); + //bike contrib + BicycleConfigGroup bikeConfigGroup = (BicycleConfigGroup)ConfigUtils.addOrGetModule(config, BicycleConfigGroup.class); + bikeConfigGroup.setBicycleMode("bike"); + config.changeMode().setModes(new String[]{"car", "pt", "bicycle"}); + + //Set the replanning strategy for migrants: All migrants will fully reroute their plan + StrategyConfigGroup.StrategySettings migrantStrategySettings = new StrategyConfigGroup.StrategySettings(ConfigUtils.createAvailableStrategyId(config)); + migrantStrategySettings.setStrategyName(DefaultPlanStrategiesModule.DefaultStrategy.ChangeTripMode); + migrantStrategySettings.setSubpopulation("migrant"); + migrantStrategySettings.setWeight(1); + config.strategy().addStrategySettings(migrantStrategySettings); + } + + Scenario scenario = ScenarioUtils.loadScenario(config); + //Person person = scenario.getPopulation().getPersons().get(Id.createPersonId("10")); + //scenario.getPopulation().getPersons().clear(); + //scenario.getPopulation().addPerson(person); + Person migrant = scenario.getPopulation().getPersons().get(Id.createPersonId("1")); + migrant.getAttributes().putAttribute("subpopulation", "migrant"); + + Controler controler = new Controler(scenario); + { + controler.addOverridingModule(new AbstractModule() { + public void install() { + this.addTravelTimeBinding("ride").to(this.networkTravelTime()); + this.addTravelDisutilityFactoryBinding("ride").to(this.carTravelDisutilityFactoryKey()); + this.addTravelTimeBinding("bike").to(this.networkTravelTime()); + this.addControlerListenerBinding().to(ModeChoiceCoverageControlerListener.class); + this.addControlerListenerBinding().to(StrategyWeightFadeout.class).in(Singleton.class); + Multibinder schedules = Multibinder.newSetBinder(this.binder(), StrategyWeightFadeout.Schedule.class); + schedules.addBinding().toInstance(new StrategyWeightFadeout.Schedule("SubtourModeChoice", "person", 0.75, 0.85)); + schedules.addBinding().toInstance(new StrategyWeightFadeout.Schedule("ReRoute", "person", 0.78)); + } + }); + Bicycles.addAsOverridingModule(controler); + } + + MigrantBicycleChoiceHandler choiceHandler = new MigrantBicycleChoiceHandler(scenario.getPopulation()); + + controler.addOverridingModule(new AbstractModule() { + @Override + public void install() { + addEventHandlerBinding().toInstance(choiceHandler); + addControlerListenerBinding().toInstance(choiceHandler); + } + }); + controler.run(); + + //Migrant should now have bike as the best plan + + System.out.println(); + } +} \ No newline at end of file