Skip to content

Commit

Permalink
Feat: Transit with abstract access (#214)
Browse files Browse the repository at this point in the history
* feat: TransitWithAbstractAccessModule

* refractoring
  • Loading branch information
tkchouaki authored Apr 23, 2024
1 parent 44fb3f1 commit 640b0c6
Show file tree
Hide file tree
Showing 29 changed files with 1,728 additions and 131 deletions.
237 changes: 125 additions & 112 deletions core/src/main/java/org/eqasim/core/simulation/EqasimConfigurator.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@
import org.eqasim.core.simulation.modes.feeder_drt.MultiModeFeederDrtModule;
import org.eqasim.core.simulation.modes.feeder_drt.config.MultiModeFeederDrtConfigGroup;
import org.eqasim.core.simulation.modes.feeder_drt.mode_choice.EqasimFeederDrtModeChoiceModule;
import org.eqasim.core.simulation.modes.transit_with_abstract_access.TransitWithAbstractAccessModule;
import org.eqasim.core.simulation.modes.transit_with_abstract_access.TransitWithAbstractAbstractAccessModuleConfigGroup;
import org.eqasim.core.simulation.modes.transit_with_abstract_access.TransitWithAbstractAccessQSimModule;
import org.eqasim.core.simulation.modes.transit_with_abstract_access.mode_choice.TransitWithAbstractAccessModeChoiceModule;
import org.eqasim.core.simulation.modes.transit_with_abstract_access.routing.AbstractAccessRouteFactory;
import org.eqasim.core.simulation.modes.transit_with_abstract_access.routing.DefaultAbstractAccessRoute;
import org.eqasim.core.simulation.termination.EqasimTerminationConfigGroup;
import org.eqasim.core.simulation.termination.EqasimTerminationModule;
import org.eqasim.core.simulation.termination.mode_share.ModeShareModule;
Expand Down Expand Up @@ -55,81 +61,87 @@ public class EqasimConfigurator {
private final Map<String, List<BiConsumer<Controler, QSimComponentsConfig>>> optionalQSimComponentConfigurationSteps = new HashMap<>();
private final Map<String, ConfigGroup> optionalConfigGroups = new HashMap<>();

public EqasimConfigurator() {
configGroups.addAll(Arrays.asList( //
new SwissRailRaptorConfigGroup(), //
new EqasimConfigGroup(), //
new DiscreteModeChoiceConfigGroup() //
));

modules.addAll(Arrays.asList( //
new SwissRailRaptorModule(), //
new EqasimTransitModule(), //
new DiscreteModeChoiceModule(), //
new EqasimComponentsModule(), //
new EpsilonModule() //
));

qsimModules.addAll(Arrays.asList( //
new EqasimTransitQSimModule(), //
new EqasimTrafficQSimModule() //
));

this.registerOptionalConfigGroup(new MultiModeDrtConfigGroup(),
Collections.singleton(new MultiModeDrtModule()),
Collections.emptyList(),
Collections.singletonList((controller, components) ->
DvrpQSimComponents.activateAllModes((MultiModal<?>) controller.getConfig().getModules().get(MultiModeDrtConfigGroup.GROUP_NAME)).configure(components)));

this.registerOptionalConfigGroup(new DvrpConfigGroup(), Collections.singleton(new DvrpModule()));
this.registerOptionalConfigGroup(new EqasimTerminationConfigGroup(), List.of(new EqasimTerminationModule(), new ModeShareModule()));
this.registerOptionalConfigGroup(new MultiModeFeederDrtConfigGroup(), List.of(new MultiModeFeederDrtModule(), new EqasimFeederDrtModeChoiceModule()));
}

public ConfigGroup[] getConfigGroups() {
return configGroups.toArray(ConfigGroup[]::new);
}

public List<AbstractModule> getModules() {
return modules;
}

public List<AbstractQSimModule> getQSimModules() {
return qsimModules;
}

public void configureController(Controler controller) {

// The optional modules are added after the non-optional ones because we consider that their bindings have less priority
this.optionalModules.entrySet().stream()
.filter(e -> controller.getConfig().getModules().containsKey(e.getKey()))
.map(Map.Entry::getValue)
.flatMap(Collection::stream)
.forEach(controller::addOverridingModule);

for (AbstractModule module : getModules()) {
controller.addOverridingModule(module);
}

this.optionalQSimModules.entrySet().stream()
.filter(e -> controller.getConfig().getModules().containsKey(e.getKey()))
.map(Map.Entry::getValue)
.flatMap(Collection::stream)
.forEach(controller::addOverridingQSimModule);

for (AbstractQSimModule module : getQSimModules()) {
controller.addOverridingQSimModule(module);
}

controller.configureQSimComponents(components -> {
optionalQSimComponentConfigurationSteps.entrySet().stream()
.filter(e -> controller.getConfig().getModules().containsKey(e.getKey()))
.map(Map.Entry::getValue)
.flatMap(Collection::stream)
.forEach(step -> step.accept(controller, components));
EqasimTransitQSimModule.configure(components, controller.getConfig());
});
}
public EqasimConfigurator() {
configGroups.addAll(Arrays.asList( //
new SwissRailRaptorConfigGroup(), //
new EqasimConfigGroup(), //
new DiscreteModeChoiceConfigGroup() //
));

modules.addAll(Arrays.asList( //
new SwissRailRaptorModule(), //
new EqasimTransitModule(), //
new DiscreteModeChoiceModule(), //
new EqasimComponentsModule(), //
new EpsilonModule() //
));

qsimModules.addAll(Arrays.asList( //
new EqasimTransitQSimModule(), //
new EqasimTrafficQSimModule() //
));

this.registerOptionalConfigGroup(new MultiModeDrtConfigGroup(),
Collections.singleton(new MultiModeDrtModule()),
Collections.emptyList(),
Collections.singletonList((controller, components) ->
DvrpQSimComponents.activateAllModes((MultiModal<?>) controller.getConfig().getModules().get(MultiModeDrtConfigGroup.GROUP_NAME)).configure(components)));

this.registerOptionalConfigGroup(new DvrpConfigGroup(), Collections.singleton(new DvrpModule()));
this.registerOptionalConfigGroup(new EqasimTerminationConfigGroup(), List.of(new EqasimTerminationModule(), new ModeShareModule()));
this.registerOptionalConfigGroup(new MultiModeFeederDrtConfigGroup(), List.of(new MultiModeFeederDrtModule(), new EqasimFeederDrtModeChoiceModule()));
this.registerOptionalConfigGroup(
new TransitWithAbstractAbstractAccessModuleConfigGroup(),
List.of(new TransitWithAbstractAccessModule(),
new TransitWithAbstractAccessModeChoiceModule()),
List.of(new TransitWithAbstractAccessQSimModule()),
Collections.singletonList((controller, components) -> TransitWithAbstractAccessQSimModule.configure(components, controller.getConfig())));
}

public ConfigGroup[] getConfigGroups() {
return configGroups.toArray(ConfigGroup[]::new);
}

public List<AbstractModule> getModules() {
return modules;
}

public List<AbstractQSimModule> getQSimModules() {
return qsimModules;
}

public void configureController(Controler controller) {

// The optional modules are added after the non-optional ones because we consider that their bindings have less priority
this.optionalModules.entrySet().stream()
.filter(e -> controller.getConfig().getModules().containsKey(e.getKey()))
.map(Map.Entry::getValue)
.flatMap(Collection::stream)
.forEach(controller::addOverridingModule);

for (AbstractModule module : getModules()) {
controller.addOverridingModule(module);
}

this.optionalQSimModules.entrySet().stream()
.filter(e -> controller.getConfig().getModules().containsKey(e.getKey()))
.map(Map.Entry::getValue)
.flatMap(Collection::stream)
.forEach(controller::addOverridingQSimModule);

for (AbstractQSimModule module : getQSimModules()) {
controller.addOverridingQSimModule(module);
}

controller.configureQSimComponents(components -> {
optionalQSimComponentConfigurationSteps.entrySet().stream()
.filter(e -> controller.getConfig().getModules().containsKey(e.getKey()))
.map(Map.Entry::getValue)
.flatMap(Collection::stream)
.forEach(step -> step.accept(controller, components));
EqasimTransitQSimModule.configure(components, controller.getConfig());
});
}

protected void registerOptionalConfigGroup(ConfigGroup configGroup) {
registerOptionalConfigGroup(configGroup, new ArrayList<>());
Expand All @@ -147,41 +159,42 @@ protected void registerOptionalConfigGroup(ConfigGroup configGroup, Collection<A
this.optionalModules.putIfAbsent(configGroup.getName(), new ArrayList<>());
this.optionalModules.get(configGroup.getName()).addAll(modules);

this.optionalQSimModules.putIfAbsent(configGroup.getName(), new ArrayList<>());
this.optionalQSimModules.get(configGroup.getName()).addAll(qsimModules);

this.optionalQSimComponentConfigurationSteps.putIfAbsent(configGroup.getName(), new ArrayList<>());
this.optionalQSimComponentConfigurationSteps.get(configGroup.getName()).addAll(componentsConsumers);
}

public void addOptionalConfigGroups(Config config) {
for(ConfigGroup configGroup: optionalConfigGroups.values()) {
if(config.getModules().get(configGroup.getName()) != null) {
config.addModule(configGroup);
}
}
}

public void configureScenario(Scenario scenario) {
scenario.getPopulation().getFactory().getRouteFactories().setRouteFactory(DrtRoute.class, new DrtRouteFactory());
}

public void adjustScenario(Scenario scenario) {
for (Household household : scenario.getHouseholds().getHouseholds().values()) {
for (Id<Person> memberId : household.getMemberIds()) {
Person person = scenario.getPopulation().getPersons().get(memberId);

if (person != null) {
copyAttribute(household, person, "bikeAvailability");
copyAttribute(household, person, "spRegion");
}
}
}
}

static protected void copyAttribute(Household household, Person person, String attribute) {
if (household.getAttributes().getAsMap().containsKey(attribute)) {
person.getAttributes().putAttribute(attribute, household.getAttributes().getAttribute(attribute));
}
}
this.optionalQSimModules.putIfAbsent(configGroup.getName(), new ArrayList<>());
this.optionalQSimModules.get(configGroup.getName()).addAll(qsimModules);

this.optionalQSimComponentConfigurationSteps.putIfAbsent(configGroup.getName(), new ArrayList<>());
this.optionalQSimComponentConfigurationSteps.get(configGroup.getName()).addAll(componentsConsumers);
}

public void addOptionalConfigGroups(Config config) {
for (ConfigGroup configGroup : optionalConfigGroups.values()) {
if (config.getModules().get(configGroup.getName()) != null) {
config.addModule(configGroup);
}
}
}

public void configureScenario(Scenario scenario) {
scenario.getPopulation().getFactory().getRouteFactories().setRouteFactory(DrtRoute.class, new DrtRouteFactory());
scenario.getPopulation().getFactory().getRouteFactories().setRouteFactory(DefaultAbstractAccessRoute.class, new AbstractAccessRouteFactory());
}

public void adjustScenario(Scenario scenario) {
for (Household household : scenario.getHouseholds().getHouseholds().values()) {
for (Id<Person> memberId : household.getMemberIds()) {
Person person = scenario.getPopulation().getPersons().get(memberId);

if (person != null) {
copyAttribute(household, person, "bikeAvailability");
copyAttribute(household, person, "spRegion");
}
}
}
}

static protected void copyAttribute(Household household, Person person, String attribute) {
if (household.getAttributes().getAsMap().containsKey(attribute)) {
person.getAttributes().putAttribute(attribute, household.getAttributes().getAttribute(attribute));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,17 @@
import com.google.inject.name.Named;

public class PtPredictor extends CachedVariablePredictor<PtVariables> {
private CostModel costModel;
private final CostModel costModel;

@Inject
public PtPredictor(@Named("pt") CostModel costModel) {
this.costModel = costModel;
}

protected CostModel getCostModel() {
return this.costModel;
}

@Override
public PtVariables predict(Person person, DiscreteModeChoiceTrip trip, List<? extends PlanElement> elements) {
/*
Expand All @@ -39,8 +43,7 @@ public PtVariables predict(Person person, DiscreteModeChoiceTrip trip, List<? ex
double accessEgressTime_min = 0.0;

for (PlanElement element : elements) {
if (element instanceof Leg) {
Leg leg = (Leg) element;
if (element instanceof Leg leg) {

switch (leg.getMode()) {
case TransportMode.walk:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package org.eqasim.core.simulation.modes.transit_with_abstract_access;

import com.google.inject.Inject;

import org.eqasim.core.simulation.modes.transit_with_abstract_access.events.AbstractAccessDepartureEvent;
import org.eqasim.core.simulation.modes.transit_with_abstract_access.routing.AbstractAccessRoute;
import org.eqasim.core.simulation.modes.transit_with_abstract_access.routing.TransitWithAbstractAccessRoutingModule;
import org.matsim.api.core.v01.Id;
import org.matsim.api.core.v01.network.Link;
import org.matsim.api.core.v01.population.Leg;
import org.matsim.core.api.experimental.events.EventsManager;
import org.matsim.core.mobsim.framework.MobsimAgent;
import org.matsim.core.mobsim.framework.PlanAgent;
import org.matsim.core.mobsim.qsim.interfaces.DepartureHandler;

public class AbstractAccessDepartureEventCreator implements DepartureHandler {

private final EventsManager eventsManager;
@Inject
public AbstractAccessDepartureEventCreator(EventsManager eventsManager) {
this.eventsManager = eventsManager;
}

@Override
public boolean handleDeparture(double now, MobsimAgent agent, Id<Link> linkId) {
if(agent.getMode().equals(TransitWithAbstractAccessRoutingModule.ABSTRACT_ACCESS_LEG_MODE_NAME)) {
Leg leg = (Leg) ((PlanAgent) agent).getCurrentPlanElement();
AbstractAccessRoute abstractAccessRoute = (AbstractAccessRoute) leg.getRoute();
this.eventsManager.processEvent(new AbstractAccessDepartureEvent(now, agent.getId(), abstractAccessRoute.getAbstractAccessItemId(), abstractAccessRoute.getStartLinkId(), abstractAccessRoute.getEndLinkId(), abstractAccessRoute.isLeavingAccessCenter(), abstractAccessRoute.isRouted(), abstractAccessRoute.getDistance()));
}
return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package org.eqasim.core.simulation.modes.transit_with_abstract_access;

import jakarta.validation.constraints.NotNull;
import org.matsim.core.config.ReflectiveConfigGroup;

public class TransitWithAbstractAbstractAccessModuleConfigGroup extends ReflectiveConfigGroup {

public static final String GROUP_NAME = "transitWithAbstractAccess";

private static final String ACCESS_ITEMS_FILE_PATH = "accessItemsFilePath";


private static final String MODE_NAME = "modeName";

@NotNull
private String accessItemsFilePath;

@NotNull
private String modeName;

public TransitWithAbstractAbstractAccessModuleConfigGroup() {
super(GROUP_NAME);
}

@StringSetter(ACCESS_ITEMS_FILE_PATH)
public void setAccessItemsFilePath(String accessItemsFilePath) {
this.accessItemsFilePath = accessItemsFilePath;
}

@StringGetter(ACCESS_ITEMS_FILE_PATH)
public String getAccessItemsFilePath() {
return this.accessItemsFilePath;
}

@StringSetter(MODE_NAME)
public void setModeName(String modeName) {
this.modeName = modeName;
}

@StringGetter(MODE_NAME)
public String getModeName() {
return this.modeName;
}
}
Loading

0 comments on commit 640b0c6

Please sign in to comment.