Skip to content

Commit

Permalink
Merge pull request #3013 from matsim-org/feature/improve-transfer-times
Browse files Browse the repository at this point in the history
Add PT Submode specific transfer constants
  • Loading branch information
jfbischoff authored Jan 5, 2024
2 parents 5bbad7c + ebbdf29 commit 9561281
Show file tree
Hide file tree
Showing 8 changed files with 145 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
*/
public class SwissRailRaptorConfigGroup extends ReflectiveConfigGroup {

private static final Logger log = LogManager.getLogger(SwissRailRaptorConfigGroup.class);
public static final String GROUP = "swissRailRaptor";

private static final String PARAM_USE_RANGE_QUERY = "useRangeQuery";
Expand Down Expand Up @@ -81,6 +80,7 @@ public class SwissRailRaptorConfigGroup extends ReflectiveConfigGroup {
private final Map<String, RangeQuerySettingsParameterSet> rangeQuerySettingsPerSubpop = new HashMap<>();
private final Map<String, RouteSelectorParameterSet> routeSelectorPerSubpop = new HashMap<>();
private final List<IntermodalAccessEgressParameterSet> intermodalAccessEgressSettings = new ArrayList<>();
private final List<ModeToModeTransferPenalty> modeToModeTransferPenaltyParameterSets = new ArrayList<>();
private final Map<String, ModeMappingForPassengersParameterSet> modeMappingForPassengersByRouteMode = new HashMap<>();


Expand Down Expand Up @@ -243,19 +243,19 @@ public void setTransferPenaltyCostPerTravelTimeHour(double hourlyCost) {
this.transferPenaltyHourlyCost = hourlyCost;
}

@Override

@Override
public ConfigGroup createParameterSet(String type) {
if (RangeQuerySettingsParameterSet.TYPE.equals(type)) {
return new RangeQuerySettingsParameterSet();
} else if (RouteSelectorParameterSet.TYPE.equals(type)) {
return new RouteSelectorParameterSet();
} else if (IntermodalAccessEgressParameterSet.TYPE.equals(type)) {
return new IntermodalAccessEgressParameterSet();
} else if (ModeMappingForPassengersParameterSet.TYPE.equals(type)) {
return new ModeMappingForPassengersParameterSet();
} else {
throw new IllegalArgumentException("Unsupported parameterset-type: " + type);
}
return switch (type){
case RangeQuerySettingsParameterSet.TYPE -> new RangeQuerySettingsParameterSet();
case RouteSelectorParameterSet.TYPE -> new RouteSelectorParameterSet();
case IntermodalAccessEgressParameterSet.TYPE -> new IntermodalAccessEgressParameterSet();
case ModeMappingForPassengersParameterSet.TYPE -> new ModeMappingForPassengersParameterSet();
case ModeToModeTransferPenalty.TYPE -> new ModeToModeTransferPenalty();
default -> throw new IllegalArgumentException("Unsupported parameterset-type: " + type);

};

}

@Override
Expand All @@ -267,13 +267,25 @@ public void addParameterSet(ConfigGroup set) {
} else if (set instanceof IntermodalAccessEgressParameterSet) {
addIntermodalAccessEgress((IntermodalAccessEgressParameterSet) set);
} else if (set instanceof ModeMappingForPassengersParameterSet) {
addModeMappingForPassengers((ModeMappingForPassengersParameterSet) set);
addModeMappingForPassengers((ModeMappingForPassengersParameterSet) set);}
else if (set instanceof ModeToModeTransferPenalty) {
addModeToModeTransferPenalty((ModeToModeTransferPenalty) set);
} else {
throw new IllegalArgumentException("Unsupported parameterset: " + set.getClass().getName());
}
}

public void addRangeQuerySettings(RangeQuerySettingsParameterSet settings) {
public void addModeToModeTransferPenalty(ModeToModeTransferPenalty set) {
this.modeToModeTransferPenaltyParameterSets.add(set);
super.addParameterSet(set);

}

public List<ModeToModeTransferPenalty> getModeToModeTransferPenaltyParameterSets() {
return modeToModeTransferPenaltyParameterSets;
}

public void addRangeQuerySettings(RangeQuerySettingsParameterSet settings) {
Set<String> subpops = settings.getSubpopulations();
if (subpops.isEmpty()) {
this.rangeQuerySettingsPerSubpop.put(null, settings);
Expand Down Expand Up @@ -662,12 +674,39 @@ public void setPassengerMode(String passengerMode) {
}
}

@Override
public static class ModeToModeTransferPenalty extends ReflectiveConfigGroup{
private static final String TYPE = "modeToModeTransferPenalty";
@Parameter
@Comment("from Transfer PT Sub-Mode")
public String fromMode;
@Parameter
@Comment("to Transfer PT Sub-Mode")
public String toMode;
@Parameter
@Comment("Transfer Penalty per Transfer between modes")
public double transferPenalty = 0.0;

public ModeToModeTransferPenalty() {
super(TYPE);
}

public ModeToModeTransferPenalty(String fromMode, String toMode, double transferPenalty) {
super(TYPE);
this.fromMode = fromMode;
this.toMode = toMode;
this.transferPenalty = transferPenalty;
}
}



@Override
public Map<String, String> getComments() {
Map<String, String> comments = super.getComments();
comments.put(PARAM_INTERMODAL_ACCESS_EGRESS_MODE_SELECTION, PARAM_INTERMODAL_ACCESS_EGRESS_MODE_SELECTION_DESC);
comments.put(PARAM_USE_CAPACITY_CONSTRAINTS, PARAM_USE_CAPACITY_CONSTRAINTS_DESC);
comments.put(PARAM_TRANSFER_WALK_MARGIN, PARAM_TRANSFER_WALK_MARGIN_DESC);
comments.put(PARAM_INTERMODAL_ACCESS_EGRESS_MODE_SELECTION,PARAM_INTERMODAL_ACCESS_EGRESS_MODE_SELECTION_DESC);
return comments;
}

Expand All @@ -679,7 +718,7 @@ protected void checkConsistency(Config config) {

Verify.verify(config.plans().getHandlingOfPlansWithoutRoutingMode().equals(HandlingOfPlansWithoutRoutingMode.reject), "Using intermodal access and egress in "
+ "combination with plans without a routing mode is not supported.");
Verify.verify(intermodalAccessEgressSettings.size() >= 1, "Using intermodal routing, but there are no access/egress "
Verify.verify(!intermodalAccessEgressSettings.isEmpty(), "Using intermodal routing, but there are no access/egress "
+ "modes defined. Add at least one parameterset with an access/egress mode and ensure "
+ "SwissRailRaptorConfigGroup is loaded correctly.");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,14 @@
*/
public class DefaultRaptorTransferCostCalculator implements RaptorTransferCostCalculator {
@Override
public double calcTransferCost(Supplier<Transfer> transfer, RaptorParameters raptorParams, int totalTravelTime, int transferCount, double existingTransferCosts, double currentTime) {
public double calcTransferCost(Supplier<Transfer> transfer, RaptorStaticConfig staticConfig, RaptorParameters raptorParams, int totalTravelTime, int transferCount, double existingTransferCosts, double currentTime) {
double transferCostBase = raptorParams.getTransferPenaltyFixCostPerTransfer();
double transferCostModeToMode = staticConfig.isUseModeToModeTransferPenalty()?staticConfig.getModeToModeTransferPenalty(transfer.get().getFromTransitRoute().getTransportMode(),transfer.get().getToTransitRoute().getTransportMode()):0.0;
double transferCostPerHour = raptorParams.getTransferPenaltyPerTravelTimeHour();
double transferCostMin = raptorParams.getTransferPenaltyMinimum();
double transferCostMax = raptorParams.getTransferPenaltyMaximum();

return (calcSingleTransferCost(transferCostBase, transferCostPerHour, transferCostMin, transferCostMax, totalTravelTime) * transferCount) - existingTransferCosts;
return (calcSingleTransferCost(transferCostBase+transferCostModeToMode, transferCostPerHour, transferCostMin, transferCostMax, totalTravelTime) * transferCount) - existingTransferCosts;
}

private double calcSingleTransferCost(double costBase, double costPerHour, double costMin, double costMax, double travelTime) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
package ch.sbb.matsim.routing.pt.raptor;

import ch.sbb.matsim.config.SwissRailRaptorConfigGroup;
import org.matsim.api.core.v01.population.Person;
import org.matsim.facilities.Facility;
import org.matsim.pt.transitSchedule.api.TransitStopFacility;
import org.matsim.utils.objectattributes.attributable.Attributes;

import java.util.HashMap;
import java.util.Map;
Expand All @@ -34,15 +38,17 @@
*/
public class RaptorStaticConfig {

public enum RaptorOptimization {


public enum RaptorOptimization {
/**
* Use this option if you plan to calculate simple from-to routes
* (see {@link SwissRailRaptor#calcRoute(org.matsim.facilities.Facility, org.matsim.facilities.Facility, double, org.matsim.api.core.v01.population.Person)}).
* (see {@link SwissRailRaptor#calcRoute(Facility, Facility, double, double, double, Person, Attributes, RaptorRouteSelector)}
*/
OneToOneRouting,
/**
* Use this option if you plan to calculate one-to-all least-cost-path-trees
* (see {@link SwissRailRaptor#calcTree(org.matsim.pt.transitSchedule.api.TransitStopFacility, double, RaptorParameters)}).
* (see {@link SwissRailRaptor#calcTree(TransitStopFacility, double, RaptorParameters, Person)} ).
*/
OneToAllRouting }

Expand All @@ -60,6 +66,7 @@ public enum RaptorOptimization {

private boolean useModeMappingForPassengers = false;
private final Map<String, String> passengerModeMappings = new HashMap<>();
private final Map<String, Map<String,Double>> modeToModeTransferPenalties = new HashMap<>();

private boolean useCapacityConstraints = false;

Expand Down Expand Up @@ -114,6 +121,20 @@ public boolean isUseModeMappingForPassengers() {
public void setUseModeMappingForPassengers(boolean useModeMappingForPassengers) {
this.useModeMappingForPassengers = useModeMappingForPassengers;
}
public void addModeToModeTransferPenalty(String fromMode, String toMode, double transferPenalty) {
this.modeToModeTransferPenalties.computeIfAbsent(fromMode,s->new HashMap<>()).put(toMode,transferPenalty);
}
public double getModeToModeTransferPenalty(String fromMode, String toMode){
var fromModeSet = this.modeToModeTransferPenalties.get(fromMode);
if (fromModeSet!=null){
return fromModeSet.getOrDefault(toMode,0.0);
}
else return 0.0;
}

public boolean isUseModeToModeTransferPenalty(){
return !this.modeToModeTransferPenalties.isEmpty();
}

public boolean isUseCapacityConstraints() {
return this.useCapacityConstraints;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@
*/
public interface RaptorTransferCostCalculator {

double calcTransferCost(Supplier<Transfer> transfer, RaptorParameters raptorParams, int totalTravelTime, int totalTransferCount, double existingTransferCosts, double currentTime);
double calcTransferCost(Supplier<Transfer> transfer, RaptorStaticConfig staticConfig, RaptorParameters raptorParams, int totalTravelTime, int totalTransferCount, double existingTransferCosts, double currentTime);

}
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ public static RaptorStaticConfig createStaticConfig(Config config) {
staticConfig.addModeMappingForPassengers(mapping.getRouteMode(), mapping.getPassengerMode());
}
}

for (SwissRailRaptorConfigGroup.ModeToModeTransferPenalty penalty : srrConfig.getModeToModeTransferPenaltyParameterSets()){
staticConfig.addModeToModeTransferPenalty(penalty.fromMode,penalty.toMode,penalty.transferPenalty);
}
staticConfig.setUseCapacityConstraints(srrConfig.isUseCapacityConstraints());

return staticConfig;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -637,7 +637,7 @@ private void exploreRoutes(RaptorParameters parameters, Person person) {
int inVehicleTime = arrivalTime - currentAgentBoardingTime;
double inVehicleCost = this.inVehicleCostCalculator.getInVehicleCost(inVehicleTime, marginalUtilityOfTravelTime_utl_s, person, currentVehicle, parameters, routeSegmentIterator);
double arrivalTravelCost = currentTravelCostWhenBoarding + inVehicleCost;
double arrivalTransferCost = (boardingPE.firstDepartureTime != TIME_UNDEFINED) ? (currentTransferCostWhenBoarding + this.transferCostCalculator.calcTransferCost(transferProvider, parameters, arrivalTime - firstDepartureTime, boardingPE.transferCount, boardingPE.arrivalTransferCost, boardingPE.arrivalTime)) : 0;
double arrivalTransferCost = (boardingPE.firstDepartureTime != TIME_UNDEFINED) ? (currentTransferCostWhenBoarding + this.transferCostCalculator.calcTransferCost(transferProvider, data.config, parameters, arrivalTime - firstDepartureTime, boardingPE.transferCount, boardingPE.arrivalTransferCost, boardingPE.arrivalTime)) : 0;
double previousArrivalCost = this.leastArrivalCostAtRouteStop[toRouteStopIndex];
double totalArrivalCost = arrivalTravelCost + arrivalTransferCost;
if (totalArrivalCost <= previousArrivalCost) {
Expand Down Expand Up @@ -758,7 +758,7 @@ private void handleTransfers(boolean strict, RaptorParameters raptorParams) {
transferProvider.reset(transfer);
int newArrivalTime = arrivalTime + transfer.transferTime;
double newArrivalTravelCost = arrivalTravelCost - transfer.transferTime * margUtilityTransitWalk;
double newArrivalTransferCost = (fromPE.firstDepartureTime != TIME_UNDEFINED) ? (arrivalTransferCost + this.transferCostCalculator.calcTransferCost(transferProvider, raptorParams, newArrivalTime - fromPE.firstDepartureTime, fromPE.transferCount + 1, arrivalTransferCost, arrivalTime)) : 0;
double newArrivalTransferCost = (fromPE.firstDepartureTime != TIME_UNDEFINED) ? (arrivalTransferCost + this.transferCostCalculator.calcTransferCost(transferProvider, data.config, raptorParams, newArrivalTime - fromPE.firstDepartureTime, fromPE.transferCount + 1, arrivalTransferCost, arrivalTime)) : 0;
double newTotalArrivalCost = newArrivalTravelCost + newArrivalTransferCost;
double prevLeastArrivalCost = this.leastArrivalCostAtRouteStop[toRouteStopIndex];
if (newTotalArrivalCost < prevLeastArrivalCost || (!strict && newTotalArrivalCost <= prevLeastArrivalCost)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.matsim.core.config.ConfigReader;
import org.matsim.core.config.ConfigUtils;
import org.matsim.core.config.ConfigWriter;
import org.matsim.testcases.MatsimTestUtils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
Expand Down Expand Up @@ -260,6 +261,25 @@ void testConfigIO_modeMappings() {
Assertions.assertNull(config2.getModeMappingForPassengersParameterSet("road"));
Assertions.assertNull(config2.getModeMappingForPassengersParameterSet("ship"));
}
@Test
void testConfigIO_ModeToModePenalties() {
SwissRailRaptorConfigGroup config1 = new SwissRailRaptorConfigGroup();

{ // prepare config1
config1.setUseModeMappingForPassengers(true);
SwissRailRaptorConfigGroup.ModeToModeTransferPenalty penalty = new SwissRailRaptorConfigGroup.ModeToModeTransferPenalty(TransportMode.airplane,TransportMode.ship,100);
config1.addParameterSet(penalty);
}

SwissRailRaptorConfigGroup config2 = writeRead(config1);

// do checks

SwissRailRaptorConfigGroup.ModeToModeTransferPenalty penalty = config2.getModeToModeTransferPenaltyParameterSets().get(0);
Assertions.assertEquals(penalty.transferPenalty,100.0, MatsimTestUtils.EPSILON);
Assertions.assertEquals(penalty.fromMode,TransportMode.airplane);
Assertions.assertEquals(penalty.toMode,TransportMode.ship);
}

private SwissRailRaptorConfigGroup writeRead(SwissRailRaptorConfigGroup config) {
Config fullConfig1 = ConfigUtils.createConfig(config);
Expand Down
Loading

0 comments on commit 9561281

Please sign in to comment.