Skip to content

Commit c575012

Browse files
samuelhoenleCopilot
andcommitted
feat(drt): config-based prebooking logic per DRT mode (#4545)
Add config parameter sets to define prebooking logic type and parameters per DRT mode via config.xml, removing the need for programmatic installation. New parameter sets inside <parameterset type="prebooking">: - <parameterset type="logic:probability"> with probability and submissionSlack - <parameterset type="logic:attributes"> with configurable attribute name prefixes Changes: - PrebookingParams: extend ReflectiveConfigGroupWithConfigurableParameterSets, register both logic param sets (one-of-many pattern) - DrtModeQSimModule: auto-install prebooking logic when config params present - AttributeBasedPrebookingLogic: support configurable attribute name prefixes - New ProbabilityBasedPrebookingLogicParams and AttributeBasedPrebookingLogicParams - New PrebookingLogicConfigTest with 10 unit tests Fully backward compatible: existing programmatic install() calls still work. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 8400d12 commit c575012

6 files changed

Lines changed: 440 additions & 9 deletions

File tree

contribs/drt/src/main/java/org/matsim/contrib/drt/prebooking/PrebookingParams.java

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,53 @@
11
package org.matsim.contrib.drt.prebooking;
22

3-
import org.matsim.core.config.ReflectiveConfigGroup;
3+
import java.util.Optional;
44

5+
import org.matsim.contrib.common.util.ReflectiveConfigGroupWithConfigurableParameterSets;
6+
import org.matsim.contrib.drt.prebooking.logic.AttributeBasedPrebookingLogicParams;
7+
import org.matsim.contrib.drt.prebooking.logic.ProbabilityBasedPrebookingLogicParams;
8+
import org.matsim.core.config.ConfigGroup;
9+
10+
import jakarta.annotation.Nullable;
511
import jakarta.validation.constraints.NotNull;
612
import jakarta.validation.constraints.Positive;
713

8-
public class PrebookingParams extends ReflectiveConfigGroup {
14+
public class PrebookingParams extends ReflectiveConfigGroupWithConfigurableParameterSets {
915
public static final String SET_NAME = "prebooking";
1016

17+
@Nullable
18+
private ConfigGroup logicParams;
19+
1120
public PrebookingParams() {
1221
super(SET_NAME);
22+
initLogicParameterSets();
23+
}
24+
25+
private void initLogicParameterSets() {
26+
addDefinition(ProbabilityBasedPrebookingLogicParams.SET_NAME,
27+
ProbabilityBasedPrebookingLogicParams::new,
28+
() -> logicParams,
29+
params -> logicParams = (ProbabilityBasedPrebookingLogicParams) params);
30+
31+
addDefinition(AttributeBasedPrebookingLogicParams.SET_NAME,
32+
AttributeBasedPrebookingLogicParams::new,
33+
() -> logicParams,
34+
params -> logicParams = (AttributeBasedPrebookingLogicParams) params);
35+
}
36+
37+
public Optional<ConfigGroup> getLogicParams() {
38+
return Optional.ofNullable(logicParams);
39+
}
40+
41+
public Optional<ProbabilityBasedPrebookingLogicParams> getProbabilityBasedLogicParams() {
42+
return getLogicParams()
43+
.filter(ProbabilityBasedPrebookingLogicParams.class::isInstance)
44+
.map(ProbabilityBasedPrebookingLogicParams.class::cast);
45+
}
46+
47+
public Optional<AttributeBasedPrebookingLogicParams> getAttributeBasedLogicParams() {
48+
return getLogicParams()
49+
.filter(AttributeBasedPrebookingLogicParams.class::isInstance)
50+
.map(AttributeBasedPrebookingLogicParams.class::cast);
1351
}
1452

1553
@Parameter

contribs/drt/src/main/java/org/matsim/contrib/drt/prebooking/logic/AttributeBasedPrebookingLogic.java

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,15 @@
3636
* @author Sebastian Hörl (sebhoerl), IRT SystemX
3737
*/
3838
public class AttributeBasedPrebookingLogic implements PrebookingLogic, MobsimInitializedListener {
39-
static private final String SUBMISSION_TIME_ATTRIBUTE_PREFIX = "prebooking:submissionTime:";
40-
static private final String PLANNED_DEPARTURE_ATTRIBUTE_PREFIX = "prebooking:plannedDepartureTime:";
39+
static private final String DEFAULT_SUBMISSION_TIME_ATTRIBUTE_PREFIX = "prebooking:submissionTime";
40+
static private final String DEFAULT_PLANNED_DEPARTURE_ATTRIBUTE_PREFIX = "prebooking:plannedDepartureTime";
4141

4242
static public String getSubmissionTimeAttribute(String mode) {
43-
return SUBMISSION_TIME_ATTRIBUTE_PREFIX + mode;
43+
return DEFAULT_SUBMISSION_TIME_ATTRIBUTE_PREFIX + ":" + mode;
4444
}
4545

4646
static public String getPlannedDepartureTimeAttribute(String mode) {
47-
return PLANNED_DEPARTURE_ATTRIBUTE_PREFIX + mode;
47+
return DEFAULT_PLANNED_DEPARTURE_ATTRIBUTE_PREFIX + ":" + mode;
4848
}
4949

5050
static public Optional<Double> getSubmissionTime(String mode, Trip trip) {
@@ -77,14 +77,24 @@ static public void setPlannedDepartureTime(String mode, Activity originActivity,
7777
private final TimeInterpretation timeInterpretation;
7878

7979
private final String mode;
80+
private final String submissionTimeAttribute;
81+
private final String plannedDepartureTimeAttribute;
8082

8183
private AttributeBasedPrebookingLogic(String mode, PrebookingQueue prebookingQueue,
8284
PopulationIteratorFactory populationIteratorFactory, TimeInterpretation timeInterpretation) {
85+
this(mode, prebookingQueue, populationIteratorFactory, timeInterpretation,
86+
DEFAULT_SUBMISSION_TIME_ATTRIBUTE_PREFIX, DEFAULT_PLANNED_DEPARTURE_ATTRIBUTE_PREFIX);
87+
}
88+
89+
private AttributeBasedPrebookingLogic(String mode, PrebookingQueue prebookingQueue,
90+
PopulationIteratorFactory populationIteratorFactory, TimeInterpretation timeInterpretation,
91+
String submissionTimeAttributePrefix, String plannedDepartureTimeAttributePrefix) {
8392
this.prebookingQueue = prebookingQueue;
8493
this.populationIteratorFactory = populationIteratorFactory;
8594
this.mode = mode;
8695
this.timeInterpretation = timeInterpretation;
87-
96+
this.submissionTimeAttribute = submissionTimeAttributePrefix + ":" + mode;
97+
this.plannedDepartureTimeAttribute = plannedDepartureTimeAttributePrefix + ":" + mode;
8898
}
8999

90100
@Override
@@ -109,8 +119,10 @@ public void notifyMobsimInitialized(@SuppressWarnings("rawtypes") MobsimInitiali
109119
"Attribute-based prebooking logic only works with one DRT leg per trip");
110120
foundLeg = true;
111121

112-
Optional<Double> submissionTime = getSubmissionTime(mode, trip);
113-
Optional<Double> plannedDepartureTime = getPlannedDepartureTime(mode, trip);
122+
Optional<Double> submissionTime = Optional.ofNullable(
123+
(Double) trip.getTripAttributes().getAttribute(submissionTimeAttribute));
124+
Optional<Double> plannedDepartureTime = Optional.ofNullable(
125+
(Double) trip.getTripAttributes().getAttribute(plannedDepartureTimeAttribute));
114126

115127
if (submissionTime.isPresent()) {
116128
if (plannedDepartureTime.isPresent()) {
@@ -149,6 +161,25 @@ protected void configureQSim() {
149161
};
150162
}
151163

164+
static public AbstractDvrpModeQSimModule createModule(DrtConfigGroup drtConfig,
165+
AttributeBasedPrebookingLogicParams logicParams) {
166+
return new AbstractDvrpModeQSimModule(drtConfig.getMode()) {
167+
@Override
168+
protected void configureQSim() {
169+
bindModal(AttributeBasedPrebookingLogic.class).toProvider(modalProvider(getter -> {
170+
Preconditions.checkState(drtConfig.getPrebookingParams().isPresent());
171+
172+
return new AttributeBasedPrebookingLogic(drtConfig.getMode(),
173+
getter.getModal(PrebookingQueue.class), getter.getModal(PopulationIteratorFactory.class),
174+
getter.get(TimeInterpretation.class),
175+
logicParams.getSubmissionTimeAttributePrefix(),
176+
logicParams.getPlannedDepartureTimeAttributePrefix());
177+
}));
178+
addModalQSimComponentBinding().to(modalKey(AttributeBasedPrebookingLogic.class));
179+
}
180+
};
181+
}
182+
152183
static public void install(Controler controller, DrtConfigGroup drtConfig) {
153184
controller.addOverridingQSimModule(createModule(drtConfig));
154185
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package org.matsim.contrib.drt.prebooking.logic;
2+
3+
import org.matsim.core.config.ReflectiveConfigGroup;
4+
5+
/**
6+
* Configuration parameters for {@link AttributeBasedPrebookingLogic}. Configures
7+
* the attribute name prefixes used to read submission time and planned departure
8+
* time from activity attributes. The full attribute name is formed by appending
9+
* a colon and the DRT mode name to the prefix.
10+
*
11+
* @author Samuel Hoenle (samuelhoenle)
12+
*/
13+
public class AttributeBasedPrebookingLogicParams extends ReflectiveConfigGroup {
14+
public static final String SET_NAME = "logic:attributes";
15+
16+
@Parameter
17+
@Comment("Attribute name prefix for submission time. The full attribute name is formed"
18+
+ " by appending a colon and the DRT mode name (e.g. 'prebooking:submissionTime:drt').")
19+
private String submissionTimeAttributePrefix = "prebooking:submissionTime";
20+
21+
@Parameter
22+
@Comment("Attribute name prefix for planned departure time. The full attribute name is formed"
23+
+ " by appending a colon and the DRT mode name (e.g. 'prebooking:plannedDepartureTime:drt').")
24+
private String plannedDepartureTimeAttributePrefix = "prebooking:plannedDepartureTime";
25+
26+
public AttributeBasedPrebookingLogicParams() {
27+
super(SET_NAME);
28+
}
29+
30+
public String getSubmissionTimeAttributePrefix() {
31+
return submissionTimeAttributePrefix;
32+
}
33+
34+
public void setSubmissionTimeAttributePrefix(String submissionTimeAttributePrefix) {
35+
this.submissionTimeAttributePrefix = submissionTimeAttributePrefix;
36+
}
37+
38+
public String getPlannedDepartureTimeAttributePrefix() {
39+
return plannedDepartureTimeAttributePrefix;
40+
}
41+
42+
public void setPlannedDepartureTimeAttributePrefix(String plannedDepartureTimeAttributePrefix) {
43+
this.plannedDepartureTimeAttributePrefix = plannedDepartureTimeAttributePrefix;
44+
}
45+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package org.matsim.contrib.drt.prebooking.logic;
2+
3+
import org.matsim.core.config.ReflectiveConfigGroup;
4+
5+
import jakarta.validation.constraints.DecimalMax;
6+
import jakarta.validation.constraints.DecimalMin;
7+
import jakarta.validation.constraints.PositiveOrZero;
8+
9+
/**
10+
* Configuration parameters for {@link ProbabilityBasedPrebookingLogic}. Defines
11+
* the probability that a DRT trip is prebooked and the time slack for
12+
* submission before departure.
13+
*
14+
* @author Samuel Hoenle (samuelhoenle)
15+
*/
16+
public class ProbabilityBasedPrebookingLogicParams extends ReflectiveConfigGroup {
17+
public static final String SET_NAME = "logic:probability";
18+
19+
@Parameter
20+
@Comment("Probability that a DRT trip is prebooked. A value of 0.0 means no trips are prebooked,"
21+
+ " a value of 1.0 means all trips are prebooked.")
22+
@DecimalMin("0.0")
23+
@DecimalMax("1.0")
24+
private double probability = 1.0;
25+
26+
@Parameter
27+
@Comment("Time in seconds before the planned departure time at which the prebooking request"
28+
+ " is submitted. For example, a value of 900 means the request is submitted 15 minutes"
29+
+ " before departure.")
30+
@PositiveOrZero
31+
private double submissionSlack = 900.0;
32+
33+
public ProbabilityBasedPrebookingLogicParams() {
34+
super(SET_NAME);
35+
}
36+
37+
public double getProbability() {
38+
return probability;
39+
}
40+
41+
public void setProbability(double probability) {
42+
this.probability = probability;
43+
}
44+
45+
@PositiveOrZero
46+
public double getSubmissionSlack() {
47+
return submissionSlack;
48+
}
49+
50+
public void setSubmissionSlack(@PositiveOrZero double submissionSlack) {
51+
this.submissionSlack = submissionSlack;
52+
}
53+
}

contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeQSimModule.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
import org.matsim.contrib.drt.passenger.DrtRequestCreator;
2626
import org.matsim.contrib.drt.prebooking.PrebookingManager;
2727
import org.matsim.contrib.drt.prebooking.PrebookingModeQSimModule;
28+
import org.matsim.contrib.drt.prebooking.logic.AttributeBasedPrebookingLogic;
29+
import org.matsim.contrib.drt.prebooking.logic.ProbabilityBasedPrebookingLogic;
2830
import org.matsim.contrib.drt.speedup.DrtSpeedUp;
2931
import org.matsim.contrib.drt.vrpagent.DrtActionCreator;
3032
import org.matsim.contrib.dvrp.load.DvrpLoadType;
@@ -101,6 +103,15 @@ protected void configureQSim() {
101103
if (drtCfg.getPrebookingParams().isPresent()) {
102104
install(new PrebookingModeQSimModule(getMode(), drtCfg.getPrebookingParams().get()));
103105
bindModal(AdvanceRequestProvider.class).to(modalKey(PrebookingManager.class));
106+
107+
// Auto-install prebooking logic if configured
108+
drtCfg.getPrebookingParams().get().getProbabilityBasedLogicParams().ifPresent(logicParams -> {
109+
install(ProbabilityBasedPrebookingLogic.createModule(drtCfg, logicParams.getProbability(),
110+
logicParams.getSubmissionSlack()));
111+
});
112+
drtCfg.getPrebookingParams().get().getAttributeBasedLogicParams().ifPresent(logicParams -> {
113+
install(AttributeBasedPrebookingLogic.createModule(drtCfg, logicParams));
114+
});
104115
} else {
105116
bindModal(AdvanceRequestProvider.class).toInstance(AdvanceRequestProvider.NONE);
106117
}

0 commit comments

Comments
 (0)