diff --git a/.github/workflows/deploy-dtds.yaml b/.github/workflows/deploy-dtds.yaml
new file mode 100644
index 00000000000..bb48f61d27b
--- /dev/null
+++ b/.github/workflows/deploy-dtds.yaml
@@ -0,0 +1,24 @@
+name: deploy-dtds-on-website
+
+on:
+ push:
+ branches:
+ - master
+ paths:
+ - matsim/src/main/resources/dtd
+
+jobs:
+ rsync-dtds:
+ name: sync DTDs to website
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: rsync dtds
+ uses: burnett01/rsync-deployments@7.0.1
+ with:
+ switches: -avz
+ path: matsim/src/main/resources/dtd/
+ remote_path: ~/httpdocs/files/dtd/
+ remote_host: ${{ secrets.WEBSITE_DEPLOY_HOST }}
+ remote_user: ${{ secrets.WEBSITE_DEPLOY_USER }}
+ remote_key: ${{ secrets.WEBSITE_SSH_PRIVATE_KEY }}
diff --git a/contribs/application/pom.xml b/contribs/application/pom.xml
index 70a548c2dc7..4035f096a83 100644
--- a/contribs/application/pom.xml
+++ b/contribs/application/pom.xml
@@ -22,7 +22,7 @@
- 1.11.3
+ 1.12.0
diff --git a/contribs/application/src/main/java/org/matsim/application/MATSimApplication.java b/contribs/application/src/main/java/org/matsim/application/MATSimApplication.java
index 7d63518e323..2425a0f1491 100644
--- a/contribs/application/src/main/java/org/matsim/application/MATSimApplication.java
+++ b/contribs/application/src/main/java/org/matsim/application/MATSimApplication.java
@@ -153,7 +153,14 @@ public Integer call() throws Exception {
// load config if not present yet.
if (config == null) {
- config = loadConfig(Objects.requireNonNull( configPath, "No default scenario location given" ).getAbsoluteFile().toString() );
+ String path = Objects.requireNonNull( configPath, "No default scenario location given" ).getAbsoluteFile().toString();
+ List customModules = getCustomModules();
+
+ final Config config1 = ConfigUtils.loadConfig(path, customModules.toArray(new ConfigGroup[0] ) );
+ Config prepared = prepareConfig( config1 );
+
+ config = prepared != null ? prepared : config1;
+ // (The above lines of code come from inlining so maybe it happened there: I cannot see how prepared could be null but config1 not except if user code returns null which I would consider a bug. kai, aug'24)
} else {
Config tmp = prepareConfig(config);
config = tmp != null ? tmp : config;
@@ -306,15 +313,6 @@ protected final void addRunOption(Config config, String option) {
addRunOption(config, option, "");
}
- private Config loadConfig(String path) {
- List customModules = getCustomModules();
-
- final Config config = ConfigUtils.loadConfig(path, customModules.toArray(new ConfigGroup[0]));
- Config prepared = prepareConfig(config);
-
- return prepared != null ? prepared : config;
- }
-
@Override
public String defaultValue(CommandLine.Model.ArgSpec argSpec) throws Exception {
Object obj = argSpec.userObject();
@@ -374,8 +372,39 @@ public static void run(Class extends MATSimApplication> clazz, String... args)
}
/**
- * Convenience method to run a scenario from code or automatically with gui when desktop application is detected.
- * This method may also be used to predefine some default arguments.
+ *
Convenience method to run a scenario from code or automatically with gui when desktop application is detected.
+ * This method may also be used to predefine some default arguments.
+ *
+ *
With respect to args it looks like arguments are treated in the following sequence (programmed in the run method):
+ *
+ *
ConfigUtils.loadConfig without args
+ *
prepareConfig which is usually overwritten
+ *
config options from some yaml file which can be provided as a command line option
+ *
config options on command line
+ *
+ *
+ *
defaultArgs could be used to provide defaults when calling this method here; they would go in addition to what is coming in from "upstream" which is typically the command line.
+ *
+ *
There are many execution paths that can be reached from this class, but a typical one for matsim-scenarios seems to be:
+ *
This method runs MATSimApplication.run( TheScenarioClass.class , args ).
+ *
That run class will instantiate an instance of TheScenarioClass (*), then do some args consistenty checking, then call the piccoli execute method.
+ *
The piccoli execute method will essentially call the "call" method of MATSimApplication.
+ *
I think that in the described execution path, this.config in that call method will initially be null. (The ctor of MATSimApplication was called via reflection at (*); I think that it was called there without a config argument.)
+ *
This call method then will do:
+ *
getCustomModules() (which is empty by default but can be overriden)
+ *
ConfigUtils.loadConfig(...) _without_ passing on the args
+ *
prepareConfig(...) (which is empty by default but is typically overridden, in this case in OpenBerlinScenario). In our case, this sets the typical scoring params and the typical replanning strategies.
+ *
next one can override the config from some yaml file provided as a commandline option
+ *
next args is parsed and set
+ *
then some standard CL options are detected and set
+ *
then createScenario(config) is called (which can be overwritten but is not)
+ *
then prepareScenario(scenario) is called (which can be overwritten but is not)
+ *
then a standard controler is created from scenario
+ *
then prepareControler is called which can be overwritten
+ *
+ *
+ *
+ *
* @param clazz class of the scenario to run
* @param args pass arguments from the main method
* @param defaultArgs predefined default arguments that will always be present
@@ -384,6 +413,8 @@ public static void runWithDefaults(Class extends MATSimApplication> clazz, Str
if (ApplicationUtils.isRunFromDesktop() && args.length == 0) {
+ System.setProperty("MATSIM_GUI_DESKTOP", "true");
+
if (defaultArgs.length > 0) {
String value = String.join(ARGS_DELIMITER, defaultArgs);
System.setProperty("MATSIM_GUI_ARGS", value);
diff --git a/contribs/application/src/main/java/org/matsim/application/ShowGUI.java b/contribs/application/src/main/java/org/matsim/application/ShowGUI.java
index e394bfd7b79..6400262eb95 100644
--- a/contribs/application/src/main/java/org/matsim/application/ShowGUI.java
+++ b/contribs/application/src/main/java/org/matsim/application/ShowGUI.java
@@ -40,6 +40,13 @@ public Integer call() throws Exception {
Gui gui = f.get();
+ // Set the current working directory to be used in the gui, when run from the command line
+ // If the gui is run from desktop, the working directory is not overwritten
+
+ // Assumption is that starting something from command line, the user expects that the working directory remains the same
+ if (!System.getProperty("MATSIM_GUI_DESKTOP", "false").equals("true"))
+ gui.setWorkingDirectory(new File(""));
+
while (gui.isShowing())
Thread.sleep(250);
diff --git a/contribs/application/src/main/java/org/matsim/application/analysis/noise/MergeNoiseOutput.java b/contribs/application/src/main/java/org/matsim/application/analysis/noise/MergeNoiseOutput.java
index aef1ec23d05..b5b85336c1c 100644
--- a/contribs/application/src/main/java/org/matsim/application/analysis/noise/MergeNoiseOutput.java
+++ b/contribs/application/src/main/java/org/matsim/application/analysis/noise/MergeNoiseOutput.java
@@ -13,11 +13,14 @@
import org.apache.avro.file.DataFileWriter;
import org.apache.avro.io.DatumWriter;
import org.apache.avro.specific.SpecificDatumWriter;
+import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.matsim.api.core.v01.Coord;
import org.matsim.application.avro.XYTData;
+import org.matsim.core.config.Config;
import org.matsim.core.utils.io.IOUtils;
+import org.matsim.core.utils.misc.Time;
import tech.tablesaw.api.*;
import tech.tablesaw.io.csv.CsvReadOptions;
@@ -29,7 +32,8 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
-import java.util.stream.Collectors;
+
+import static org.geotools.gml3.v3_2.GML.coordinateSystem;
/**
* Merges noise data from multiple files into one file.
@@ -44,17 +48,16 @@ final class MergeNoiseOutput {
*/
private static final boolean CREATE_CSV_FILES = false;
- private final String[] inputPath;
private final Path outputDirectory;
private final String crs;
- private final String[] labels = {"immission", "emission"};
private final int minTime = 3600;
private int maxTime = 24 * 3600;
- MergeNoiseOutput(String[] inputPath, Path outputDirectory, String crs) {
- this.inputPath = inputPath;
- this.outputDirectory = outputDirectory;
- this.crs = crs;
+ private final Map totalReceiverPointValues = new HashMap<>();
+
+ MergeNoiseOutput(Path path, String coordinateSystem ) {
+ this.outputDirectory = path;
+ this.crs = coordinateSystem;
}
/**
@@ -90,25 +93,9 @@ public void setMaxTime(int maxTime) {
* Merges noise data from multiple files into one file.
*/
public void run() {
-
- // Loop over all paths
- for (int i = 0; i < labels.length; i++) {
-
- // Select the correct method based on the label
- switch (labels[i]) {
- case "immission" -> {
- if (CREATE_CSV_FILES) {
- mergeImmissionsCSV(inputPath[i], labels[i]);
- } else {
- mergeImissions(inputPath[i], labels[i]);
- }
-
- }
- case "emission" -> mergeEmissions(inputPath[i], labels[i]);
- default -> log.warn("Unknown path: " + inputPath[i]);
- }
-
- }
+ mergeReceiverPointData(outputDirectory + "/immissions/", "immission");
+ mergeReceiverPointData(outputDirectory + "/damages_receiverPoint/", "damages_receiverPoint");
+ mergeLinkData(outputDirectory.toString() + "/emissions/", "emission");
}
/**
@@ -118,6 +105,7 @@ public void run() {
* @param output
*/
private void writeAvro(XYTData xytData, File output) {
+ log.info(String.format("Start writing avro file to %s", output.toString() ));
DatumWriter datumWriter = new SpecificDatumWriter<>(XYTData.class);
try (DataFileWriter dataFileWriter = new DataFileWriter<>(datumWriter)) {
dataFileWriter.setCodec(CodecFactory.deflateCodec(9));
@@ -128,7 +116,7 @@ private void writeAvro(XYTData xytData, File output) {
}
}
- private void mergeEmissions(String pathParameter, String label) {
+ private void mergeLinkData(String pathParameter, String label) {
log.info("Merging emissions data for label {}", label);
Object2DoubleMap mergedData = new Object2DoubleOpenHashMap<>();
Table csvOutputMerged = Table.create(TextColumn.create("Link Id"), DoubleColumn.create("value"));
@@ -143,9 +131,8 @@ private void mergeEmissions(String pathParameter, String label) {
.separator(';').build());
for (Row row : table) {
- // index for Noise Emission xx:xx:xx -> 7
String linkId = row.getString("Link Id");
- double value = row.getDouble(7);
+ double value = row.getDouble(row.columnCount() - 1);
mergedData.mergeDouble(linkId, value, Double::max);
}
@@ -165,38 +152,49 @@ private void mergeEmissions(String pathParameter, String label) {
}
/**
- * Merges the immissions data
+ * Merges receiverPoint data (written by {@link org.matsim.contrib.noise.NoiseWriter}
*
- * @param pathParameter path to the immissions data
- * @param label label for the immissions data
+ * @param outputDir path to the receiverPoint data
+ * @param label label for the receiverPoint data (which kind of data)
*/
- private void mergeImissions(String pathParameter, String label) {
+ private void mergeReceiverPointData(String outputDir, String label) {
// data per time step, maps coord to value
Int2ObjectMap> data = new Int2ObjectOpenHashMap<>();
// Loop over all files
+ //TODO could be adjusted to time bin size from noise config group
+ String substrToCapitalize = null;
for (int time = minTime; time <= maxTime; time += 3600) {
- String path = pathParameter + label + "_" + round(time, 1) + ".csv";
+ String timeDataFile = outputDir + label + "_" + round(time, 1) + ".csv";
+
Object2FloatOpenHashMap values = new Object2FloatOpenHashMap<>();
- if (!Files.exists(Path.of(path))) {
- log.warn("File {} does not exist", path);
+ if (!Files.exists(Path.of(timeDataFile))) {
+ log.warn("File {} does not exist", timeDataFile);
continue;
}
- // Read the file
- Table table = Table.read().csv(CsvReadOptions.builder(IOUtils.getBufferedReader(path))
- .columnTypesPartial(Map.of("x", ColumnType.FLOAT, "y", ColumnType.FLOAT, "Receiver Point Id", ColumnType.INTEGER, "t", ColumnType.DOUBLE))
+ //we need "damages_receiverPoint" -> "Damages 01:00:00" and "immission" -> "Immision 01:00:00"
+ substrToCapitalize = label.contains("_") ? label.substring(0, label.lastIndexOf("_")) : label;
+ String valueHeader = StringUtils.capitalize(substrToCapitalize) + " " + Time.writeTime(time, Time.TIMEFORMAT_HHMMSS);
+
+ // Read the data file
+ Table dataTable = Table.read().csv(CsvReadOptions.builder(IOUtils.getBufferedReader(timeDataFile))
+ .columnTypesPartial(Map.of("x", ColumnType.FLOAT,
+ "y", ColumnType.FLOAT,
+ "Receiver Point Id", ColumnType.INTEGER,
+ "t", ColumnType.DOUBLE,
+ valueHeader, ColumnType.DOUBLE))
.sample(false)
.separator(';').build());
- // Loop over all rows in the file
- for (Row row : table) {
+ // Loop over all rows in the data file
+ for (Row row : dataTable) {
float x = row.getFloat("x");
float y = row.getFloat("y");
- float value = (float) row.getDouble(1); // 1
+ float value = (float) row.getDouble(valueHeader);
FloatFloatPair coord = FloatFloatPair.of(x, y);
values.put(coord, value);
}
@@ -232,7 +230,7 @@ private void mergeImissions(String pathParameter, String label) {
}
}
- xytHourData.setData(Map.of("imissions", raw));
+ xytHourData.setData(Map.of(label, raw));
xytHourData.setCrs(crs);
File out = outputDirectory.getParent().resolve(label + "_per_hour.avro").toFile();
@@ -254,15 +252,18 @@ private void mergeImissions(String pathParameter, String label) {
xytDayData.setTimestamps(List.of(0));
xytDayData.setXCoords(xCoords);
xytDayData.setYCoords(yCoords);
- xytDayData.setData(Map.of("imissions", raw));
+ xytDayData.setData(Map.of(label, raw));
xytDayData.setCrs(crs);
File outDay = outputDirectory.getParent().resolve(label + "_per_day.avro").toFile();
writeAvro(xytDayData, outDay);
+ //cache the overall sum
+ this.totalReceiverPointValues.put(substrToCapitalize, raw.stream().reduce(0f, Float::sum));
}
// Merges the immissions data
+
@Deprecated
private void mergeImmissionsCSV(String pathParameter, String label) {
log.info("Merging immissions data for label {}", label);
@@ -278,7 +279,10 @@ private void mergeImmissionsCSV(String pathParameter, String label) {
// Read the file
Table table = Table.read().csv(CsvReadOptions.builder(IOUtils.getBufferedReader(path))
- .columnTypesPartial(Map.of("x", ColumnType.DOUBLE, "y", ColumnType.DOUBLE, "Receiver Point Id", ColumnType.INTEGER, "t", ColumnType.DOUBLE))
+ .columnTypesPartial(Map.of("x", ColumnType.DOUBLE,
+ "y", ColumnType.DOUBLE,
+ "Receiver Point Id", ColumnType.INTEGER,
+ "t", ColumnType.DOUBLE))
.sample(false)
.separator(';').build());
@@ -319,4 +323,7 @@ private void mergeImmissionsCSV(String pathParameter, String label) {
log.info("Merged noise data written to {} ", outPerDay);
}
+ public Map getTotalReceiverPointValues() {
+ return totalReceiverPointValues;
+ }
}
diff --git a/contribs/application/src/main/java/org/matsim/application/analysis/noise/NoiseAnalysis.java b/contribs/application/src/main/java/org/matsim/application/analysis/noise/NoiseAnalysis.java
index c5927fcdb04..1892de7fb74 100644
--- a/contribs/application/src/main/java/org/matsim/application/analysis/noise/NoiseAnalysis.java
+++ b/contribs/application/src/main/java/org/matsim/application/analysis/noise/NoiseAnalysis.java
@@ -1,5 +1,9 @@
package org.matsim.application.analysis.noise;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVPrinter;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import org.locationtech.jts.geom.Envelope;
import org.matsim.api.core.v01.Coord;
import org.matsim.api.core.v01.Scenario;
@@ -8,6 +12,7 @@
import org.matsim.application.MATSimAppCommand;
import org.matsim.application.options.InputOptions;
import org.matsim.application.options.OutputOptions;
+import org.matsim.application.options.SampleOptions;
import org.matsim.application.options.ShpOptions;
import org.matsim.contrib.noise.NoiseConfigGroup;
import org.matsim.contrib.noise.NoiseOfflineCalculation;
@@ -16,9 +21,15 @@
import org.matsim.core.config.ConfigUtils;
import org.matsim.core.scenario.ScenarioUtils;
import org.matsim.core.utils.geometry.CoordinateTransformation;
+import org.matsim.core.utils.io.IOUtils;
import picocli.CommandLine;
+import java.io.IOException;
import java.nio.file.Path;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.util.Locale;
+import java.util.Map;
import java.util.Objects;
import java.util.Set;
@@ -33,11 +44,16 @@
produces = {
"emission_per_day.csv",
"immission_per_day.%s",
- "immission_per_hour.%s"
+ "immission_per_hour.%s",
+ "damages_receiverPoint_per_hour.%s",
+ "damages_receiverPoint_per_day.%s",
+ "noise_stats.csv"
}
)
public class NoiseAnalysis implements MATSimAppCommand {
+ private static final Logger log = LogManager.getLogger(NoiseAnalysis.class);
+
@CommandLine.Mixin
private final InputOptions input = InputOptions.ofCommand(NoiseAnalysis.class);
@CommandLine.Mixin
@@ -46,7 +62,11 @@ public class NoiseAnalysis implements MATSimAppCommand {
@CommandLine.Mixin
private final ShpOptions shp = new ShpOptions();
- @CommandLine.Option(names = "--consider-activities", split = ",", description = "Considered activities for noise calculation", defaultValue = "h,w,home,work")
+ @CommandLine.Mixin
+ private final SampleOptions sampleOptions = new SampleOptions();
+
+ @CommandLine.Option(names = "--consider-activities", split = ",", description = "Considered activities for noise calculation." +
+ " Use asterisk ('*') for acttype prefixes, if all such acts shall be considered.", defaultValue = "home*,work*,educ*,leisure*")
private Set considerActivities;
@CommandLine.Option(names = "--noise-barrier", description = "Path to the noise barrier File", defaultValue = "")
@@ -62,36 +82,72 @@ public Integer call() throws Exception {
config.controller().setOutputDirectory(input.getRunDirectory().toString());
- // adjust the default noise parameters
+ //trying to set noise parameters more explicitly, here...
+ //if NoiseConfigGroup was added before. do not override (most) parameters
+ boolean overrideParameters = ! ConfigUtils.hasModule(config, NoiseConfigGroup.class);
NoiseConfigGroup noiseParameters = ConfigUtils.addOrGetModule(config, NoiseConfigGroup.class);
- noiseParameters.setConsideredActivitiesForReceiverPointGridArray(considerActivities.toArray(String[]::new));
- noiseParameters.setConsideredActivitiesForDamageCalculationArray(considerActivities.toArray(String[]::new));
- if (shp.getShapeFile() != null) {
- CoordinateTransformation ct = shp.createInverseTransformation(config.global().getCoordinateSystem());
- Envelope bbox = shp.getGeometry().getEnvelopeInternal();
+ if(overrideParameters){
+ log.warn("no NoiseConfigGroup was configured before. Will set some standards. You should check the next lines in the log file!");
+ noiseParameters.setConsideredActivitiesForReceiverPointGridArray(considerActivities.toArray(String[]::new));
+ noiseParameters.setConsideredActivitiesForDamageCalculationArray(considerActivities.toArray(String[]::new));
- Coord minCoord = ct.transform(new Coord(bbox.getMinX(), bbox.getMinY()));
- Coord maxCoord = ct.transform(new Coord(bbox.getMaxX(), bbox.getMaxY()));
+ //use actual speed and not freespeed
+ noiseParameters.setUseActualSpeedLevel(true);
+ //use the valid speed range (recommended by IK)
+ noiseParameters.setAllowForSpeedsOutsideTheValidRange(false);
- noiseParameters.setReceiverPointsGridMinX(minCoord.getX());
- noiseParameters.setReceiverPointsGridMinY(minCoord.getY());
- noiseParameters.setReceiverPointsGridMaxX(maxCoord.getX());
- noiseParameters.setReceiverPointsGridMaxY(maxCoord.getY());
- }
+ if (shp.getShapeFile() != null) {
+ CoordinateTransformation ct = shp.createInverseTransformation(config.global().getCoordinateSystem());
+
+ Envelope bbox = shp.getGeometry().getEnvelopeInternal();
+
+ Coord minCoord = ct.transform(new Coord(bbox.getMinX(), bbox.getMinY()));
+ Coord maxCoord = ct.transform(new Coord(bbox.getMaxX(), bbox.getMaxY()));
- noiseParameters.setNoiseComputationMethod(NoiseConfigGroup.NoiseComputationMethod.RLS19);
+ noiseParameters.setReceiverPointsGridMinX(minCoord.getX());
+ noiseParameters.setReceiverPointsGridMinY(minCoord.getY());
+ noiseParameters.setReceiverPointsGridMaxX(maxCoord.getX());
+ noiseParameters.setReceiverPointsGridMaxY(maxCoord.getY());
+ }
- if (!Objects.equals(noiseBarrierFile, "")) {
- noiseParameters.setNoiseBarriersSourceCRS(config.global().getCoordinateSystem());
- noiseParameters.setConsiderNoiseBarriers(true);
- noiseParameters.setNoiseBarriersFilePath(noiseBarrierFile);
+ noiseParameters.setNoiseComputationMethod(NoiseConfigGroup.NoiseComputationMethod.RLS19);
+
+ if (!Objects.equals(noiseBarrierFile, "")) {
+ noiseParameters.setNoiseBarriersSourceCRS(config.global().getCoordinateSystem());
+ noiseParameters.setConsiderNoiseBarriers(true);
+ noiseParameters.setNoiseBarriersFilePath(noiseBarrierFile);
+ }
+ } else {
+ log.warn("will override a few settings in NoiseConfigGroup, as we are now doing postprocessing and do not want any internalization etc." +
+ " You should check the next lines in the log file!");
+ }
+
+ // we only mean to do postprocessing here, thus no internalization etc
+ noiseParameters.setInternalizeNoiseDamages(false);
+ noiseParameters.setComputeCausingAgents(false);
+ //we don't need events (for Dashboard) - spare disk space.
+ noiseParameters.setThrowNoiseEventsAffected(false);
+ noiseParameters.setThrowNoiseEventsCaused(false);
+ noiseParameters.setComputeNoiseDamages(true);
+
+ if(! sampleOptions.isSet() && noiseParameters.getScaleFactor() == 1d){
+ log.warn("You didn't provide the simulation sample size via command line option --sample-size! This means, noise damages are not scaled!!!");
+ } else if (noiseParameters.getScaleFactor() == 1d){
+ if (sampleOptions.getSample() == 1d){
+ log.warn("Be aware that the noise output is not scaled. This might be unintended. If so, assure to provide the sample size via command line option --sample-size, in the SimWrapperConfigGroup," +
+ "or provide the scaleFactor (the inverse of the sample size) in the NoiseConfigGroup!!!");
+ }
+ noiseParameters.setScaleFactor(sampleOptions.getUpscaleFactor());
}
Scenario scenario = ScenarioUtils.loadScenario(config);
String outputFilePath = output.getPath().getParent() == null ? "." : output.getPath().getParent().toString();
+ log.info("starting " + NoiseOfflineCalculation.class + " with the following parameters:\n"
+ + noiseParameters);
+
NoiseOfflineCalculation noiseCalculation = new NoiseOfflineCalculation(scenario, outputFilePath);
outputFilePath += "/noise-analysis";
noiseCalculation.run();
@@ -99,16 +155,25 @@ public Integer call() throws Exception {
ProcessNoiseImmissions process = new ProcessNoiseImmissions(outputFilePath + "/immissions/", outputFilePath + "/receiverPoints/receiverPoints.csv", noiseParameters.getReceiverPointGap());
process.run();
- final String[] paths = {outputFilePath + "/immissions/", outputFilePath + "/emissions/"};
- MergeNoiseOutput mergeNoiseOutput = new MergeNoiseOutput(paths, Path.of(outputFilePath), config.global().getCoordinateSystem());
+ MergeNoiseOutput mergeNoiseOutput = new MergeNoiseOutput(Path.of(outputFilePath), config.global().getCoordinateSystem());
mergeNoiseOutput.run();
+ // Total stats
+ DecimalFormat df = new DecimalFormat("#.###", DecimalFormatSymbols.getInstance(Locale.US));
+ try (CSVPrinter printer = new CSVPrinter(IOUtils.getBufferedWriter(output.getPath("noise_stats.csv").toString()), CSVFormat.DEFAULT)) {
+ printer.printRecord("Annual cost rate per pop. unit [€]:", df.format(noiseParameters.getAnnualCostRate()));
+ for (Map.Entry labelValueEntry : mergeNoiseOutput.getTotalReceiverPointValues().entrySet()) {
+ printer.printRecord("Total " + labelValueEntry.getKey() + " at receiver points", df.format(labelValueEntry.getValue()));
+ }
+ } catch (IOException ex) {
+ log.error(ex);
+ }
return 0;
}
private Config prepareConfig() {
- Config config = ConfigUtils.loadConfig(ApplicationUtils.matchInput("config.xml", input.getRunDirectory()).toAbsolutePath().toString(), new NoiseConfigGroup());
+ Config config = ConfigUtils.loadConfig(ApplicationUtils.matchInput("config.xml", input.getRunDirectory()).toAbsolutePath().toString());
//it is important to match "output_vehicles.xml.gz" specifically, because otherwise dvrpVehicle files might be matched and the code crashes later
config.vehicles().setVehiclesFile(ApplicationUtils.matchInput("output_vehicles.xml.gz", input.getRunDirectory()).toAbsolutePath().toString());
@@ -119,6 +184,7 @@ private Config prepareConfig() {
config.facilities().setInputFile(null);
config.eventsManager().setNumberOfThreads(null);
config.eventsManager().setEstimatedNumberOfEvents(null);
+ //ts, aug '24: not sure if and why we need to set 1 thread
config.global().setNumberOfThreads(1);
return config;
diff --git a/contribs/application/src/main/java/org/matsim/application/analysis/population/ActivityLengthAnalysis.java b/contribs/application/src/main/java/org/matsim/application/analysis/population/ActivityLengthAnalysis.java
new file mode 100644
index 00000000000..2e7418462fe
--- /dev/null
+++ b/contribs/application/src/main/java/org/matsim/application/analysis/population/ActivityLengthAnalysis.java
@@ -0,0 +1,82 @@
+package org.matsim.application.analysis.population;
+
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVPrinter;
+import org.matsim.api.core.v01.population.Activity;
+import org.matsim.api.core.v01.population.Person;
+import org.matsim.api.core.v01.population.PlanElement;
+import org.matsim.api.core.v01.population.Population;
+import org.matsim.application.MATSimAppCommand;
+import org.matsim.core.population.PopulationUtils;
+import picocli.CommandLine;
+
+import java.io.FileWriter;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+
+@CommandLine.Command(
+ name = "activity-length-analysis",
+ description = "Analyze the length of activity"
+)
+public class ActivityLengthAnalysis implements MATSimAppCommand {
+ @CommandLine.Option(names = "--population", description = "Path to input population", required = true)
+ private String populationPath;
+
+ @CommandLine.Option(names = "--reference-population", description = "Path to reference population", defaultValue = "")
+ private String referencePopulationPath;
+
+ @CommandLine.Option(names = "--output-folder", description = "Path to analysis output folder", required = true)
+ private Path outputFolder;
+
+ public static void main(String[] args) {
+ new ActivityLengthAnalysis().execute(args);
+ }
+
+ @Override
+ public Integer call() throws Exception {
+ List activityDurations = new ArrayList<>();
+ List referenceActivityDurations = new ArrayList<>();
+
+ Population population = PopulationUtils.readPopulation(populationPath);
+ for (Person person : population.getPersons().values()) {
+ for (PlanElement planElement : person.getSelectedPlan().getPlanElements()) {
+ if (planElement instanceof Activity) {
+ double startTime = ((Activity) planElement).getStartTime().orElse(0);
+ double endTime = ((Activity) planElement).getEndTime().orElse(30 * 3600);
+ double duration = endTime - startTime;
+ activityDurations.add(duration);
+ }
+ }
+ }
+
+ CSVPrinter csvWriter = new CSVPrinter(new FileWriter(outputFolder + "/activity-length.csv"), CSVFormat.TDF);
+ csvWriter.printRecord("activity_duration_in_seconds");
+ for (double activityDuration : activityDurations) {
+ csvWriter.printRecord(Double.toString(activityDuration));
+ }
+ csvWriter.close();
+
+ if (!referencePopulationPath.equals("")) {
+ Population referencePopulation = PopulationUtils.readPopulation(referencePopulationPath);
+ for (Person person : referencePopulation.getPersons().values()) {
+ for (PlanElement planElement : person.getSelectedPlan().getPlanElements()) {
+ if (planElement instanceof Activity) {
+ double startTime = ((Activity) planElement).getStartTime().orElse(0);
+ double endTime = ((Activity) planElement).getEndTime().orElse(30 * 3600);
+ double duration = endTime - startTime;
+ referenceActivityDurations.add(duration);
+ }
+ }
+ }
+
+ CSVPrinter csvWriter2 = new CSVPrinter(new FileWriter(outputFolder + "/reference-activity-length.csv"), CSVFormat.TDF);
+ csvWriter2.printRecord("activity_duration_in_seconds");
+ for (double activityDuration : referenceActivityDurations) {
+ csvWriter2.printRecord(Double.toString(activityDuration));
+ }
+ csvWriter2.close();
+ }
+ return 0;
+ }
+}
diff --git a/contribs/application/src/main/java/org/matsim/application/analysis/population/DepartureTimeAnalysis.java b/contribs/application/src/main/java/org/matsim/application/analysis/population/DepartureTimeAnalysis.java
new file mode 100644
index 00000000000..04e800872b9
--- /dev/null
+++ b/contribs/application/src/main/java/org/matsim/application/analysis/population/DepartureTimeAnalysis.java
@@ -0,0 +1,133 @@
+package org.matsim.application.analysis.population;
+
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVPrinter;
+import org.apache.commons.lang3.mutable.MutableInt;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.matsim.api.core.v01.population.Person;
+import org.matsim.api.core.v01.population.Plan;
+import org.matsim.api.core.v01.population.Population;
+import org.matsim.application.MATSimAppCommand;
+import org.matsim.core.population.PersonUtils;
+import org.matsim.core.population.PopulationUtils;
+import org.matsim.core.router.TripStructureUtils;
+import picocli.CommandLine;
+
+import java.io.FileWriter;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+@CommandLine.Command(
+ name = "analyze-departure-time",
+ description = "Analyze the departure time of the trips"
+)
+public class DepartureTimeAnalysis implements MATSimAppCommand {
+
+ private static final Logger log = LogManager.getLogger(DepartureTimeAnalysis.class);
+
+ @CommandLine.Option(names = "--plans", description = "Path to input population (plans) file", required = true)
+ private Path inputPlans;
+
+ @CommandLine.Option(names = "--output-folder", description = "Path to analysis output folder", required = true)
+ private Path outputFolder;
+
+ private static String[] ageGroups = new String[]{"0-17", "18-29", "30-49", "50-69", "70 or more"};
+
+
+ public static void main(String[] args) {
+ new DepartureTimeAnalysis().execute(args);
+ }
+
+ @Override
+ public Integer call() throws Exception {
+ Map> recordMap = initializeRecordMap();
+ Population population = PopulationUtils.readPopulation(inputPlans.toString());
+
+ int processedPerson = 0;
+ int tripsDepartAfter24h = 0;
+
+ for (Person person : population.getPersons().values()) {
+ //TODO potentially filter persons, e.g. by home location or by subpopulation
+
+ processedPerson++;
+ int age = PersonUtils.getAge(person);
+ String ageGroup = determineAgeGroup(age);
+ Plan plan = person.getSelectedPlan();
+ List trips = TripStructureUtils.getTrips(plan);
+ for (TripStructureUtils.Trip trip : trips) {
+ double departureTime = trip.getOriginActivity().getEndTime().seconds();
+ // maybe the Math.floor operation is not needed?
+ int timeBin = (int) Math.floor(departureTime / 3600);
+ if (timeBin >= 24) {
+ tripsDepartAfter24h++;
+ continue;
+ }
+ // 1 time bin = 1 hour
+ recordMap.get(ageGroup).get(timeBin).increment();
+ }
+ }
+
+ // write results
+ if (!Files.exists(outputFolder)) {
+ Files.createDirectory(outputFolder);
+ }
+ CSVPrinter tsvWriter = new CSVPrinter(new FileWriter(outputFolder + "/departure_time_analysis.csv"), CSVFormat.TDF);
+ List titleRow = new ArrayList<>();
+ titleRow.add("age_group");
+ for (int i = 0; i < 24; i++) {
+ titleRow.add(Integer.toString(i));
+ }
+ tsvWriter.printRecord(titleRow);
+ for (String ageGroup : ageGroups) {
+ List outputRow = new ArrayList<>();
+ outputRow.add(ageGroup);
+ for (int i = 0; i < 24; i++) {
+ outputRow.add(Integer.toString(recordMap.get(ageGroup).get(i).intValue()));
+ }
+ tsvWriter.printRecord(outputRow);
+ }
+ tsvWriter.close();
+
+ log.info("Person processed (living within the area): {}", processedPerson);
+ log.info("Number of trips that depart after 24 hours is {}", tripsDepartAfter24h);
+
+ return 0;
+ }
+
+ private Map> initializeRecordMap() {
+ Map> recordMap = new HashMap<>();
+ for (String ageGroup : ageGroups) {
+ recordMap.put(ageGroup, new HashMap<>());
+ for (int i = 0; i < 24; i++) {
+ recordMap.get(ageGroup).put(i, new MutableInt(0));
+ }
+ }
+ return recordMap;
+ }
+
+ private String determineAgeGroup(int age) {
+ if (age <= 17) {
+ return ageGroups[0];
+ }
+
+ if (age <= 29) {
+ return ageGroups[1];
+ }
+
+ if (age <= 49) {
+ return ageGroups[2];
+ }
+
+ if (age <= 69) {
+ return ageGroups[3];
+ }
+
+ return ageGroups[4];
+ }
+}
diff --git a/contribs/application/src/main/java/org/matsim/application/analysis/traffic/traveltime/SampleValidationRoutes.java b/contribs/application/src/main/java/org/matsim/application/analysis/traffic/traveltime/SampleValidationRoutes.java
index 0e6c0f2af59..aa3a1fc4ba0 100644
--- a/contribs/application/src/main/java/org/matsim/application/analysis/traffic/traveltime/SampleValidationRoutes.java
+++ b/contribs/application/src/main/java/org/matsim/application/analysis/traffic/traveltime/SampleValidationRoutes.java
@@ -19,10 +19,7 @@
import org.matsim.api.core.v01.network.Node;
import org.matsim.application.CommandSpec;
import org.matsim.application.MATSimAppCommand;
-import org.matsim.application.options.CrsOptions;
-import org.matsim.application.options.InputOptions;
-import org.matsim.application.options.OutputOptions;
-import org.matsim.application.options.ShpOptions;
+import org.matsim.application.options.*;
import org.matsim.application.prepare.network.SampleNetwork;
import org.matsim.core.network.NetworkUtils;
import org.matsim.core.router.costcalculators.OnlyTimeDependentTravelDisutility;
@@ -32,9 +29,11 @@
import org.matsim.core.trafficmonitoring.FreeSpeedTravelTime;
import org.matsim.core.utils.geometry.CoordUtils;
import org.matsim.core.utils.geometry.transformations.GeotoolsTransformation;
+import org.matsim.core.utils.io.IOUtils;
import picocli.CommandLine;
import java.io.IOException;
+import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
@@ -86,6 +85,8 @@ public class SampleValidationRoutes implements MATSimAppCommand {
@CommandLine.Option(names = "--mode", description = "Mode to validate", defaultValue = TransportMode.car)
private String mode;
+ @CommandLine.Option(names = "--input-od", description = "Use input fromNode,toNode instead of sampling", required = false)
+ private String inputOD;
public static void main(String[] args) {
new SampleValidationRoutes().execute(args);
@@ -142,9 +143,15 @@ public Integer call() throws Exception {
OnlyTimeDependentTravelDisutility util = new OnlyTimeDependentTravelDisutility(tt);
LeastCostPathCalculator router = new SpeedyALTFactory().createPathCalculator(network, util, tt);
- List routes = sampleRoutes(network, router, rnd);
- log.info("Sampled {} routes in range {}", routes.size(), distRange);
+ List routes;
+ if (inputOD != null) {
+ log.info("Using input OD file {}", inputOD);
+ routes = queryRoutes(network, router);
+ } else {
+ routes = sampleRoutes(network, router, rnd);
+ log.info("Sampled {} routes in range {}", routes.size(), distRange);
+ }
try (CSVPrinter csv = new CSVPrinter(Files.newBufferedWriter(output.getPath()), CSVFormat.DEFAULT)) {
csv.printRecord("from_node", "to_node", "beeline_dist", "dist", "travel_time", "geometry");
@@ -228,6 +235,7 @@ private List sampleRoutes(Network network, LeastCostPathCalculator router
ShpOptions.Index index = shp.isDefined() ? shp.createIndex(crs, "_") : null;
Predicate exclude = excludeRoads != null && !excludeRoads.isBlank() ? new Predicate<>() {
final Pattern p = Pattern.compile(excludeRoads, Pattern.CASE_INSENSITIVE);
+
@Override
public boolean test(Link link) {
return p.matcher(NetworkUtils.getHighwayType(link)).find();
@@ -282,6 +290,59 @@ public boolean test(Link link) {
return result;
}
+ /**
+ * Use given od pairs as input for validation.
+ */
+ private List queryRoutes(Network network, LeastCostPathCalculator router) {
+
+ List result = new ArrayList<>();
+ String crs = ProjectionUtils.getCRS(network);
+
+ if (this.crs.getInputCRS() != null)
+ crs = this.crs.getInputCRS();
+
+ if (crs == null) {
+ throw new IllegalArgumentException("Input CRS could not be detected. Please specify with --input-crs [EPSG:xxx]");
+ }
+
+ GeotoolsTransformation ct = new GeotoolsTransformation(crs, "EPSG:4326");
+
+ try (CSVParser parser = CSVParser.parse(IOUtils.getBufferedReader(inputOD), CSVFormat.DEFAULT.builder().setHeader().setSkipHeaderRecord(true).
+ setDelimiter(CsvOptions.detectDelimiter(inputOD)).build())) {
+
+ List header = parser.getHeaderNames();
+ if (!header.contains("from_node"))
+ throw new IllegalArgumentException("Missing 'from_node' column in input file");
+ if (!header.contains("to_node"))
+ throw new IllegalArgumentException("Missing 'to_node' column in input file");
+
+ for (CSVRecord r : parser) {
+ Node fromNode = network.getNodes().get(Id.createNodeId(r.get("from_node")));
+ Node toNode = network.getNodes().get(Id.createNodeId(r.get("to_node")));
+
+ if (fromNode == null)
+ throw new IllegalArgumentException("Node " + r.get("from_node") + " not found");
+ if (toNode == null)
+ throw new IllegalArgumentException("Node " + r.get("to_node") + " not found");
+
+ LeastCostPathCalculator.Path path = router.calcLeastCostPath(fromNode, toNode, 0, null, null);
+ result.add(new Route(
+ fromNode.getId(),
+ toNode.getId(),
+ ct.transform(fromNode.getCoord()),
+ ct.transform(toNode.getCoord()),
+ path.travelTime,
+ path.links.stream().mapToDouble(Link::getLength).sum()
+ ));
+ }
+
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+
+ return result;
+ }
+
/**
* Key as pair of from and to node.
*/
diff --git a/contribs/application/src/main/java/org/matsim/application/prepare/freight/tripExtraction/ExtractRelevantFreightTrips.java b/contribs/application/src/main/java/org/matsim/application/prepare/freight/tripExtraction/ExtractRelevantFreightTrips.java
index 12c7c03866e..84fce6b351a 100644
--- a/contribs/application/src/main/java/org/matsim/application/prepare/freight/tripExtraction/ExtractRelevantFreightTrips.java
+++ b/contribs/application/src/main/java/org/matsim/application/prepare/freight/tripExtraction/ExtractRelevantFreightTrips.java
@@ -74,6 +74,9 @@ private enum TripType {
@CommandLine.Option(names = "--tripType", description = "Set the tripType: OUTGOING, INCOMING, TRANSIT, INTERNAL, ALL", defaultValue = "ALL")
private TripType tripType;
+ @CommandLine.Option(names = "--LegMode", description = "Set leg mode for long distance freight legs.", defaultValue = "freight")
+ private String legMode;
+
private final SplittableRandom rnd = new SplittableRandom(4711);
private final List fromCoords = new ArrayList<>();
@@ -161,7 +164,7 @@ public Integer call() throws Exception {
boolean destinationIsInside = relevantArea.contains(MGC.coord2Point(sct.transform(endCoord)));
Activity act0 = populationFactory.createActivityFromCoord("freight_start", null);
- Leg leg = populationFactory.createLeg("freight");
+ Leg leg = populationFactory.createLeg(legMode);
Activity act1 = populationFactory.createActivityFromCoord("freight_end", null);
switch (tripType) {
@@ -312,7 +315,7 @@ private void createActivitiesForIncomingTrips(boolean originIsInside, boolean de
timeSpent += Math.floor(link.getLength() / link.getFreespeed()) + 1;
}
if (!isCoordSet) {
- Coord originalCoord = route.links.get(0).getCoord();
+ Coord originalCoord = route.links.getFirst().getCoord();
act0.setCoord(ct.transform(originalCoord));
act0.setEndTime(departureTime);
}
diff --git a/contribs/application/src/main/java/org/matsim/application/prepare/freight/tripGeneration/GenerateFreightPlans.java b/contribs/application/src/main/java/org/matsim/application/prepare/freight/tripGeneration/GenerateFreightPlans.java
index 0d4fa163ee1..e79d06632d6 100644
--- a/contribs/application/src/main/java/org/matsim/application/prepare/freight/tripGeneration/GenerateFreightPlans.java
+++ b/contribs/application/src/main/java/org/matsim/application/prepare/freight/tripGeneration/GenerateFreightPlans.java
@@ -35,7 +35,7 @@ public class GenerateFreightPlans implements MATSimAppCommand {
defaultValue = "https://svn.vsp.tu-berlin.de/repos/public-svn/matsim/scenarios/countries/de/german-wide-freight/v2/germany-europe-network.xml.gz")
private String networkPath;
- @CommandLine.Option(names = "--nuts", description = "Path to desired network file", required = true)
+ @CommandLine.Option(names = "--nuts", description = "Path to NUTS file (available on SVN: )", required = true)
// TODO Change this to URL pointing to SVN--> need to update the Location calculator
private Path shpPath;
@@ -48,8 +48,8 @@ public class GenerateFreightPlans implements MATSimAppCommand {
@CommandLine.Option(names = "--working-days", defaultValue = "260", description = "Number of working days in a year")
private int workingDays;
- @CommandLine.Option(names = "--sample", defaultValue = "1", description = "Scaling factor of the freight traffic (0, 1)")
- private double sample;
+ @CommandLine.Option(names = "--sample", defaultValue = "100", description = "Sample size of the freight plans (0, 100]")
+ private double pct;
@CommandLine.Mixin
private LanduseOptions landuse = new LanduseOptions();
@@ -60,7 +60,7 @@ public Integer call() throws Exception {
log.info("Network successfully loaded!");
log.info("preparing freight agent generator...");
- FreightAgentGenerator freightAgentGenerator = new FreightAgentGenerator(network, shpPath, landuse, averageTruckLoad, workingDays, sample);
+ FreightAgentGenerator freightAgentGenerator = new FreightAgentGenerator(network, shpPath, landuse, averageTruckLoad, workingDays, pct / 100);
log.info("Freight agent generator successfully created!");
log.info("Reading trip relations...");
@@ -84,7 +84,7 @@ public Integer call() throws Exception {
Files.createDirectory(output);
}
- String outputPlansPath = output.toString() + "/german_freight.25pct.plans.xml.gz";
+ String outputPlansPath = output.toString() + "/german_freight." + pct + "pct.plans.xml.gz";
PopulationWriter populationWriter = new PopulationWriter(outputPopulation);
populationWriter.write(outputPlansPath);
diff --git a/contribs/bicycle/src/main/java/org/matsim/contrib/bicycle/BicycleLinkSpeedCalculatorDefaultImpl.java b/contribs/bicycle/src/main/java/org/matsim/contrib/bicycle/BicycleLinkSpeedCalculatorDefaultImpl.java
index f580b7e77f1..f6e5104fa86 100644
--- a/contribs/bicycle/src/main/java/org/matsim/contrib/bicycle/BicycleLinkSpeedCalculatorDefaultImpl.java
+++ b/contribs/bicycle/src/main/java/org/matsim/contrib/bicycle/BicycleLinkSpeedCalculatorDefaultImpl.java
@@ -18,7 +18,10 @@ public final class BicycleLinkSpeedCalculatorDefaultImpl implements BicycleLinkS
private static final Logger log = LogManager.getLogger(BicycleLinkSpeedCalculatorDefaultImpl.class );
@Inject private BicycleConfigGroup bicycleConfigGroup;
@Inject private QSimConfigGroup qSimConfigGroup;
- @Inject private BicycleLinkSpeedCalculatorDefaultImpl() { }
+ @Inject private Config config;
+ @Inject private BicycleLinkSpeedCalculatorDefaultImpl() {
+ }
+
/**
* for unit testing
*/
diff --git a/contribs/bicycle/src/main/java/org/matsim/contrib/bicycle/BicycleModule.java b/contribs/bicycle/src/main/java/org/matsim/contrib/bicycle/BicycleModule.java
index 7bf5a766bf4..030a54935f5 100644
--- a/contribs/bicycle/src/main/java/org/matsim/contrib/bicycle/BicycleModule.java
+++ b/contribs/bicycle/src/main/java/org/matsim/contrib/bicycle/BicycleModule.java
@@ -22,8 +22,12 @@
import com.google.inject.Singleton;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import org.checkerframework.checker.units.qual.C;
import org.matsim.api.core.v01.Id;
import org.matsim.api.core.v01.Scenario;
+import org.matsim.core.config.Config;
+import org.matsim.core.config.ConfigGroup;
+import org.matsim.core.config.ConfigUtils;
import org.matsim.core.controler.AbstractModule;
import org.matsim.core.controler.events.StartupEvent;
import org.matsim.core.controler.listener.StartupListener;
@@ -34,30 +38,41 @@
* @author smetzler, dziemke
*/
public final class BicycleModule extends AbstractModule {
-
private static final Logger LOG = LogManager.getLogger(BicycleModule.class);
- @Inject
- private BicycleConfigGroup bicycleConfigGroup;
+ @Inject private BicycleConfigGroup bicycleConfigGroup;
+
+ @Override public void install() {
+// BicycleConfigGroup bicycleConfigGroup = ConfigUtils.addOrGetModule( this.getConfig(), BicycleConfigGroup.class );
+// this.bind( BicycleConfigGroup.class ).toInstance( bicycleConfigGroup );
+ // the above feels odd. But it seems to work. I actually have no idea where the config groups are bound, neither for the core config
+ // groups nor for the added config groups. In general, the original idea was that AbstractModule provides the config from
+ // getConfig(), not from injection. kai, jun'24
+
+ // It actually does not work in general. The ExplodedConfigModule injects all config groups that are materialized by then. Which
+ // means that it needs to be materialized "quite early", and in particular before this install method is called. For the time being,
+ // a run script using the contrib thus needs to materialize the config group. kai, jul'24
+
- @Override
- public void install() {
// The idea here is the following:
// * scores are just added as score events. no scoring function is replaced.
// * link speeds are computed via a plugin handler to the DefaultLinkSpeedCalculator. If the plugin handler returns a speed, it is
// used, otherwise the default speed is used. This has the advantage that multiple plugins can register such special link speed calculators.
+ // this gives the typical things to the router:
addTravelTimeBinding(bicycleConfigGroup.getBicycleMode()).to(BicycleTravelTime.class).in(Singleton.class);
addTravelDisutilityFactoryBinding(bicycleConfigGroup.getBicycleMode()).to(BicycleTravelDisutilityFactory.class).in(Singleton.class);
+ // (the BicycleTravelTime uses the BicycleLinkSpeed Calculator bound below)
+ // (the BicycleDisutility uses a BicycleTravelDisutility)
+ // compute and throw the additional score events:
this.addEventHandlerBinding().to( BicycleScoreEventsCreator.class );
- // (the motorized interaction is in the BicycleScoreEventsCreator)
+ // (this uses the AdditionalBicycleLinkScore to compute and throw corresponding scoring events)
+ // (it also computes and throws the motorized interaction events, if they are switched on)
this.bind( AdditionalBicycleLinkScore.class ).to( AdditionalBicycleLinkScoreDefaultImpl.class );
-
- bind( BicycleLinkSpeedCalculator.class ).to( BicycleLinkSpeedCalculatorDefaultImpl.class ) ;
- // this is still needed because the bicycle travel time calculator for routing needs to use the same bicycle speed as the mobsim. kai, jun'23
+ // (this computes the value of the per-link scoring event. yyyy Very unfortunately, it is a re-implementation of the BicycleTravelDisutility (mentioned above).)
this.installOverridingQSimModule( new AbstractQSimModule(){
@Override protected void configureQSim(){
@@ -65,6 +80,9 @@ public void install() {
}
} );
+ bind( BicycleLinkSpeedCalculator.class ).to( BicycleLinkSpeedCalculatorDefaultImpl.class ) ;
+ // (both the router and the mobsim need this)
+
addControlerListenerBinding().to(ConsistencyCheck.class);
}
@@ -73,7 +91,6 @@ static class ConsistencyCheck implements StartupListener {
@Inject private Scenario scenario;
@Override public void notifyStartup(StartupEvent event) {
-
Id bicycleVehTypeId = Id.create(bicycleConfigGroup.getBicycleMode(), VehicleType.class);
if (scenario.getVehicles().getVehicleTypes().get(bicycleVehTypeId) == null) {
LOG.warn("There is no vehicle type '" + bicycleConfigGroup.getBicycleMode() + "' specified in the vehicle types. "
diff --git a/contribs/bicycle/src/main/java/org/matsim/contrib/bicycle/BicycleTravelDisutilityFactory.java b/contribs/bicycle/src/main/java/org/matsim/contrib/bicycle/BicycleTravelDisutilityFactory.java
index 135bc7e011f..ab7ffad85ad 100644
--- a/contribs/bicycle/src/main/java/org/matsim/contrib/bicycle/BicycleTravelDisutilityFactory.java
+++ b/contribs/bicycle/src/main/java/org/matsim/contrib/bicycle/BicycleTravelDisutilityFactory.java
@@ -21,6 +21,8 @@
import com.google.inject.Inject;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import org.matsim.core.config.Config;
+import org.matsim.core.config.ConfigUtils;
import org.matsim.core.config.groups.ScoringConfigGroup;
import org.matsim.core.config.groups.RoutingConfigGroup;
import org.matsim.core.router.costcalculators.TravelDisutilityFactory;
@@ -35,21 +37,20 @@
*/
public final class BicycleTravelDisutilityFactory implements TravelDisutilityFactory {
// public-final is ok since ctor is package-private: can only be used through injection
-
private static final Logger LOG = LogManager.getLogger(BicycleTravelDisutilityFactory.class);
-
- @Inject BicycleConfigGroup bicycleConfigGroup;
- @Inject
- ScoringConfigGroup cnScoringGroup;
- @Inject
- RoutingConfigGroup routingConfigGroup;
-
+ private BicycleConfigGroup bicycleConfigGroup;
+ @Inject Config config;
+ @Inject ScoringConfigGroup cnScoringGroup;
+ @Inject RoutingConfigGroup routingConfigGroup;
private static int normalisationWrnCnt = 0;
- /* package-private */ BicycleTravelDisutilityFactory(){}
+ /* package-private */ BicycleTravelDisutilityFactory(){
+ }
@Override
public TravelDisutility createTravelDisutility(TravelTime timeCalculator) {
+ this.bicycleConfigGroup = ConfigUtils.addOrGetModule( config, BicycleConfigGroup.class );
+
double sigma = routingConfigGroup.getRoutingRandomness();
double normalization = 1;
diff --git a/contribs/bicycle/src/main/java/org/matsim/contrib/bicycle/BicycleUtils.java b/contribs/bicycle/src/main/java/org/matsim/contrib/bicycle/BicycleUtils.java
index 43bf5e63776..3af954d9c70 100644
--- a/contribs/bicycle/src/main/java/org/matsim/contrib/bicycle/BicycleUtils.java
+++ b/contribs/bicycle/src/main/java/org/matsim/contrib/bicycle/BicycleUtils.java
@@ -127,4 +127,11 @@ private static boolean hasNoCycleway( String cyclewayType ) {
}
return userDefinedNetworkAttributeFactor;
}
+ // ===
+ public static void setSmoothness( Link link, String smoothness ){
+ link.getAttributes().putAttribute( SMOOTHNESS, smoothness );
+ }
+ public static void setBicycleInfrastructureFactor( Link link, double factor ){
+ link.getAttributes().putAttribute( BICYCLE_INFRASTRUCTURE_SPEED_FACTOR, factor );
+ }
}
diff --git a/contribs/bicycle/src/main/java/org/matsim/contrib/bicycle/network/BicycleOsmNetworkReaderV2.java b/contribs/bicycle/src/main/java/org/matsim/contrib/bicycle/network/BicycleOsmNetworkReaderV2.java
index cd51b40275b..549f4c25656 100644
--- a/contribs/bicycle/src/main/java/org/matsim/contrib/bicycle/network/BicycleOsmNetworkReaderV2.java
+++ b/contribs/bicycle/src/main/java/org/matsim/contrib/bicycle/network/BicycleOsmNetworkReaderV2.java
@@ -225,7 +225,7 @@ protected void setOrModifyLinkAttributes(Link l, OsmWay way, boolean forwardDire
// Smoothness
String smoothness = way.tags.get(BicycleUtils.SMOOTHNESS);
if (smoothness != null) {
- l.getAttributes().putAttribute(BicycleUtils.SMOOTHNESS, smoothness);
+ BicycleUtils.setSmoothness( l, smoothness );
this.countSmoothness++;
}
diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/eshifts/run/ShiftEDrtModeOptimizerQSimModule.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/eshifts/run/ShiftEDrtModeOptimizerQSimModule.java
index aefdfeb5e6c..32bf96909bf 100644
--- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/eshifts/run/ShiftEDrtModeOptimizerQSimModule.java
+++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/eshifts/run/ShiftEDrtModeOptimizerQSimModule.java
@@ -17,15 +17,12 @@
import org.matsim.contrib.drt.extension.operations.operationFacilities.OperationFacilities;
import org.matsim.contrib.drt.extension.operations.operationFacilities.OperationFacilityFinder;
import org.matsim.contrib.drt.extension.operations.shifts.config.ShiftsParams;
-import org.matsim.contrib.drt.extension.operations.shifts.dispatcher.DefaultAssignShiftToVehicleLogic;
-import org.matsim.contrib.drt.extension.operations.shifts.dispatcher.DefaultShiftStartLogic;
-import org.matsim.contrib.drt.extension.operations.shifts.dispatcher.DrtShiftDispatcher;
-import org.matsim.contrib.drt.extension.operations.shifts.dispatcher.DrtShiftDispatcherImpl;
+import org.matsim.contrib.drt.extension.operations.shifts.dispatcher.*;
import org.matsim.contrib.drt.extension.operations.shifts.optimizer.ShiftVehicleDataEntryFactory;
import org.matsim.contrib.drt.extension.operations.shifts.schedule.ShiftDrtActionCreator;
import org.matsim.contrib.drt.extension.operations.shifts.schedule.ShiftDrtTaskFactory;
import org.matsim.contrib.drt.extension.operations.shifts.scheduler.ShiftTaskScheduler;
-import org.matsim.contrib.drt.extension.operations.shifts.shift.DrtShifts;
+import org.matsim.contrib.drt.extension.operations.shifts.shift.DrtShiftsSpecification;
import org.matsim.contrib.drt.optimizer.VehicleEntry;
import org.matsim.contrib.drt.prebooking.PrebookingActionCreator;
import org.matsim.contrib.drt.run.DrtConfigGroup;
@@ -67,19 +64,22 @@ protected void configureQSim() {
).asEagerSingleton();
bindModal(DrtShiftDispatcher.class).toProvider(modalProvider(
- getter -> new EDrtShiftDispatcherImpl(((EShiftTaskScheduler) getter.getModal(ShiftTaskScheduler.class)), getter.getModal(ChargingInfrastructure.class),
- drtShiftParams, getter.getModal(OperationFacilities.class), new DrtShiftDispatcherImpl(getMode(),
- getter.getModal(DrtShifts.class), getter.getModal(Fleet.class),
- getter.get(MobsimTimer.class), getter.getModal(OperationFacilities.class), getter.getModal(OperationFacilityFinder.class),
- getter.getModal(ShiftTaskScheduler.class), getter.getModal(Network.class), getter.get(EventsManager.class),
- drtShiftParams, new EDrtShiftStartLogic(new DefaultShiftStartLogic()),
- new EDrtAssignShiftToVehicleLogic(new DefaultAssignShiftToVehicleLogic(drtShiftParams), drtShiftParams)),
- getter.getModal(Fleet.class)))).asEagerSingleton();
+ getter -> new EDrtShiftDispatcherImpl(((EShiftTaskScheduler) getter.getModal(ShiftTaskScheduler.class)),
+ getter.getModal(ChargingInfrastructure.class), drtShiftParams, getter.getModal(OperationFacilities.class),
+ new DrtShiftDispatcherImpl(getMode(), getter.getModal(Fleet.class), getter.get(MobsimTimer.class),
+ getter.getModal(OperationFacilities.class), getter.getModal(OperationFacilityFinder.class),
+ getter.getModal(ShiftTaskScheduler.class), getter.getModal(Network.class), getter.get(EventsManager.class),
+ drtShiftParams, new EDrtShiftStartLogic(new DefaultShiftStartLogic()),
+ new EDrtAssignShiftToVehicleLogic(new DefaultAssignShiftToVehicleLogic(drtShiftParams), drtShiftParams),
+ getter.getModal(ShiftScheduler.class)),
+ getter.getModal(Fleet.class)))
+ ).asEagerSingleton();
bindModal(VehicleEntry.EntryFactory.class).toProvider(modalProvider(getter ->
new ShiftVehicleDataEntryFactory(new EDrtVehicleDataEntryFactory(0),
drtShiftParams.considerUpcomingShiftsForInsertion))).asEagerSingleton();
+
bindModal(DrtTaskFactory.class).toProvider(modalProvider(getter -> new ShiftEDrtTaskFactoryImpl(new EDrtTaskFactoryImpl(), getter.getModal(OperationFacilities.class)))).in(Singleton.class);
bindModal(ShiftDrtTaskFactory.class).toProvider(modalProvider(getter -> ((ShiftDrtTaskFactory) getter.getModal(DrtTaskFactory.class))));
diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/eshifts/scheduler/EShiftTaskScheduler.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/eshifts/scheduler/EShiftTaskScheduler.java
index a87c54a1be8..9c5a7172282 100644
--- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/eshifts/scheduler/EShiftTaskScheduler.java
+++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/eshifts/scheduler/EShiftTaskScheduler.java
@@ -62,17 +62,17 @@ public class EShiftTaskScheduler implements ShiftTaskScheduler {
private final Network network;
private final ChargingInfrastructure chargingInfrastructure;
- public EShiftTaskScheduler(Network network, TravelTime travelTime, TravelDisutility travelDisutility,
- MobsimTimer timer, ShiftDrtTaskFactory taskFactory, ShiftsParams shiftsParams,
- ChargingInfrastructure chargingInfrastructure, OperationFacilities operationFacilities, Fleet fleet) {
- this.travelTime = travelTime;
- this.timer = timer;
- this.taskFactory = taskFactory;
- this.network = network;
- this.shiftsParams = shiftsParams;
- this.router = new SpeedyALTFactory().createPathCalculator(network, travelDisutility, travelTime);
- this.chargingInfrastructure = chargingInfrastructure;
- }
+ public EShiftTaskScheduler(Network network, TravelTime travelTime, TravelDisutility travelDisutility,
+ MobsimTimer timer, ShiftDrtTaskFactory taskFactory, ShiftsParams shiftsParams,
+ ChargingInfrastructure chargingInfrastructure, OperationFacilities operationFacilities, Fleet fleet) {
+ this.travelTime = travelTime;
+ this.timer = timer;
+ this.taskFactory = taskFactory;
+ this.network = network;
+ this.shiftsParams = shiftsParams;
+ this.router = new SpeedyALTFactory().createPathCalculator(network, travelDisutility, travelTime);
+ this.chargingInfrastructure = chargingInfrastructure;
+ }
public void relocateForBreak(ShiftDvrpVehicle vehicle, OperationFacility breakFacility, DrtShift shift) {
final Schedule schedule = vehicle.getSchedule();
@@ -81,7 +81,7 @@ public void relocateForBreak(ShiftDvrpVehicle vehicle, OperationFacility breakFa
final Link toLink = network.getLinks().get(breakFacility.getLinkId());
if (currentTask instanceof DriveTask
&& currentTask.getTaskType().equals(EmptyVehicleRelocator.RELOCATE_VEHICLE_TASK_TYPE)
- && currentTask.equals(schedule.getTasks().get(schedule.getTaskCount()-2))) {
+ && currentTask.equals(schedule.getTasks().get(schedule.getTaskCount() - 2))) {
//try to divert/cancel relocation
LinkTimePair start = ((OnlineDriveTaskTracker) currentTask.getTaskTracker()).getDiversionPoint();
VrpPathWithTravelData path;
@@ -112,13 +112,13 @@ public void relocateForBreak(ShiftDvrpVehicle vehicle, OperationFacility breakFa
} else {
final Task task = schedule.getTasks().get(schedule.getTaskCount() - 1);
final Link lastLink = ((StayTask) task).getLink();
- double departureTime = task.getBeginTime();
+ double departureTime = task.getBeginTime();
- // @Nico Did I change something here?
- if (schedule.getCurrentTask() == task) {
- departureTime = Math.max(task.getBeginTime(), timer.getTimeOfDay());
- }
- if (lastLink.getId() != breakFacility.getLinkId()) {
+ // @Nico Did I change something here?
+ if (schedule.getCurrentTask() == task) {
+ departureTime = Math.max(task.getBeginTime(), timer.getTimeOfDay());
+ }
+ if (lastLink.getId() != breakFacility.getLinkId()) {
VrpPathWithTravelData path = VrpPaths.calcAndCreatePath(lastLink, toLink,
departureTime, router,
@@ -154,7 +154,7 @@ public void relocateForBreak(ShiftDvrpVehicle vehicle, OperationFacility breakFa
double endTime = startTime + shift.getBreak().orElseThrow().getDuration();
double latestDetourArrival = timer.getTimeOfDay();
- relocateForBreakImpl(vehicle, startTime, endTime, latestDetourArrival, toLink, shift, breakFacility);
+ relocateForBreakImpl(vehicle, startTime, endTime, latestDetourArrival, toLink, shift, breakFacility);
}
}
}
@@ -165,24 +165,24 @@ private void relocateForBreakImpl(ShiftDvrpVehicle vehicle, double startTime, do
Schedule schedule = vehicle.getSchedule();
// append SHIFT_BREAK task
- DrtShiftBreak shiftBreak = shift.getBreak().orElseThrow();
+ DrtShiftBreak shiftBreak = shift.getBreak().orElseThrow();
- ShiftBreakTask dropoffStopTask;
- ElectricVehicle ev = ((EvDvrpVehicle) vehicle).getElectricVehicle();
- Optional charger = charge(breakFacility, ev);
- if (charger.isPresent()) {
+ ShiftBreakTask dropoffStopTask;
+ ElectricVehicle ev = ((EvDvrpVehicle) vehicle).getElectricVehicle();
+ Optional charger = charge(breakFacility, ev);
+ if (charger.isPresent()) {
final Charger chargerImpl = charger.get();
- final double waitTime = ChargingEstimations
- .estimateMaxWaitTimeForNextVehicle(chargerImpl);
+ final double waitTime = ChargingEstimations
+ .estimateMaxWaitTimeForNextVehicle(chargerImpl);
- if (ev.getBattery().getCharge() / ev.getBattery().getCapacity() > shiftsParams.chargeDuringBreakThreshold ||
- waitTime > 0) {
+ if (ev.getBattery().getCharge() / ev.getBattery().getCapacity() > shiftsParams.chargeDuringBreakThreshold ||
+ waitTime > 0) {
dropoffStopTask = taskFactory.createShiftBreakTask(vehicle, startTime,
endTime, link, shiftBreak, breakFacility);
} else {
- double energyCharge = ((BatteryCharging) ev.getChargingPower()).calcEnergyCharged(chargerImpl.getSpecification(), endTime - startTime);
- double totalEnergy = -energyCharge;
+ double energyCharge = ((BatteryCharging) ev.getChargingPower()).calcEnergyCharged(chargerImpl.getSpecification(), endTime - startTime);
+ double totalEnergy = -energyCharge;
((ChargingWithAssignmentLogic) chargerImpl.getLogic()).assignVehicle(ev);
dropoffStopTask = ((ShiftEDrtTaskFactoryImpl) taskFactory).createChargingShiftBreakTask(vehicle,
startTime, endTime, link, shiftBreak, chargerImpl, totalEnergy, breakFacility);
@@ -199,32 +199,32 @@ private void relocateForBreakImpl(ShiftDvrpVehicle vehicle, double startTime, do
final double latestTimeConstraintArrival = shiftBreak.getLatestBreakEndTime() - shiftBreak.getDuration();
- shiftBreak.schedule(Math.min(latestDetourArrival, latestTimeConstraintArrival));
+ shiftBreak.schedule(Math.min(latestDetourArrival, latestTimeConstraintArrival));
}
private Optional charge(OperationFacility breakFacility, ElectricVehicle electricVehicle) {
if (chargingInfrastructure != null) {
- List> chargerIds = breakFacility.getChargers();
- if(!chargerIds.isEmpty()) {
- Optional selectedCharger = chargerIds
- .stream()
- .map(id -> chargingInfrastructure.getChargers().get(id))
- .filter(charger -> shiftsParams.breakChargerType.equals(charger.getChargerType()))
- .min((c1, c2) -> {
- final double waitTime = ChargingEstimations
- .estimateMaxWaitTimeForNextVehicle(c1);
- final double waitTime2 = ChargingEstimations
- .estimateMaxWaitTimeForNextVehicle(c2);
- return Double.compare(waitTime, waitTime2);
- });
- if(selectedCharger.isPresent()) {
- if (selectedCharger.get().getLogic().getChargingStrategy().isChargingCompleted(electricVehicle)) {
- return Optional.empty();
- }
- }
- return selectedCharger;
- }
- }
+ List> chargerIds = breakFacility.getChargers();
+ if (!chargerIds.isEmpty()) {
+ Optional selectedCharger = chargerIds
+ .stream()
+ .map(id -> chargingInfrastructure.getChargers().get(id))
+ .filter(charger -> shiftsParams.breakChargerType.equals(charger.getChargerType()))
+ .min((c1, c2) -> {
+ final double waitTime = ChargingEstimations
+ .estimateMaxWaitTimeForNextVehicle(c1);
+ final double waitTime2 = ChargingEstimations
+ .estimateMaxWaitTimeForNextVehicle(c2);
+ return Double.compare(waitTime, waitTime2);
+ });
+ if (selectedCharger.isPresent()) {
+ if (selectedCharger.get().getLogic().getChargingStrategy().isChargingCompleted(electricVehicle)) {
+ return Optional.empty();
+ }
+ }
+ return selectedCharger;
+ }
+ }
return Optional.empty();
}
@@ -234,7 +234,7 @@ public void relocateForShiftChange(DvrpVehicle vehicle, Link link, DrtShift shif
final Task currentTask = schedule.getCurrentTask();
if (currentTask instanceof DriveTask
&& currentTask.getTaskType().equals(EmptyVehicleRelocator.RELOCATE_VEHICLE_TASK_TYPE)
- && currentTask.equals(schedule.getTasks().get(schedule.getTaskCount()-2))) {
+ && currentTask.equals(schedule.getTasks().get(schedule.getTaskCount() - 2))) {
//try to divert/cancel relocation
LinkTimePair start = ((OnlineDriveTaskTracker) currentTask.getTaskTracker()).getDiversionPoint();
VrpPathWithTravelData path;
@@ -317,22 +317,22 @@ private void appendShiftChange(DvrpVehicle vehicle, DrtShift shift, OperationFac
// append SHIFT_CHANGEOVER task
- ElectricVehicle ev = ((EvDvrpVehicle) vehicle).getElectricVehicle();
- Optional charger = charge(breakFacility, ev);
- if (charger.isPresent()) {
- Charger chargingImpl = charger.get();
+ ElectricVehicle ev = ((EvDvrpVehicle) vehicle).getElectricVehicle();
+ Optional charger = charge(breakFacility, ev);
+ if (charger.isPresent()) {
+ Charger chargingImpl = charger.get();
- final double waitTime = ChargingEstimations
- .estimateMaxWaitTimeForNextVehicle(chargingImpl);
+ final double waitTime = ChargingEstimations
+ .estimateMaxWaitTimeForNextVehicle(chargingImpl);
- if (ev.getBattery().getCharge() / ev.getBattery().getCapacity() < shiftsParams.chargeDuringBreakThreshold
+ if (ev.getBattery().getCharge() / ev.getBattery().getCapacity() < shiftsParams.chargeDuringBreakThreshold
|| ((ChargingWithAssignmentLogic) chargingImpl.getLogic()).getAssignedVehicles().contains(ev)
- || waitTime >0) {
+ || waitTime > 0) {
dropoffStopTask = taskFactory.createShiftChangeoverTask(vehicle, startTime,
endTime, link, shift, breakFacility);
} else {
- double energyCharge = ((BatteryCharging) ev.getChargingPower()).calcEnergyCharged(chargingImpl.getSpecification(), endTime - startTime);
- double totalEnergy = -energyCharge;
+ double energyCharge = ((BatteryCharging) ev.getChargingPower()).calcEnergyCharged(chargingImpl.getSpecification(), endTime - startTime);
+ double totalEnergy = -energyCharge;
((ChargingWithAssignmentLogic) chargingImpl.getLogic()).assignVehicle(ev);
dropoffStopTask = ((ShiftEDrtTaskFactoryImpl) taskFactory).createChargingShiftChangeoverTask(vehicle,
startTime, endTime, link, chargingImpl, totalEnergy, shift, breakFacility);
@@ -353,9 +353,11 @@ public void startShift(ShiftDvrpVehicle vehicle, double now, DrtShift shift) {
if (stayTask instanceof WaitForShiftTask) {
((WaitForShiftTask) stayTask).getFacility().deregisterVehicle(vehicle.getId());
stayTask.setEndTime(now);
- if(Schedules.getLastTask(schedule).equals(stayTask)) {
+ if (Schedules.getLastTask(schedule).equals(stayTask)) {
//nothing planned yet.
schedule.addTask(taskFactory.createStayTask(vehicle, now, shift.getEndTime(), stayTask.getLink()));
+ } else {
+ Schedules.getNextTask(schedule).setBeginTime(now);
}
} else {
throw new IllegalStateException("Vehicle cannot start shift during task:" + stayTask.getTaskType().name());
@@ -370,9 +372,9 @@ public boolean updateShiftChange(ShiftDvrpVehicle vehicle, Link link, DrtShift s
VrpPathWithTravelData path = VrpPaths.calcAndCreatePath(start.link, link, Math.max(start.time, timer.getTimeOfDay()), router,
travelTime);
//if (path.getArrivalTime() <= shift.getEndTime()) {
- updateShiftChangeImpl(vehicle, path, shift, facility, lastTask);
- return true;
- // }
+ updateShiftChangeImpl(vehicle, path, shift, facility, lastTask);
+ return true;
+ // }
}
return false;
}
@@ -381,29 +383,28 @@ public boolean updateShiftChange(ShiftDvrpVehicle vehicle, Link link, DrtShift s
public void planAssignedShift(ShiftDvrpVehicle vehicle, double timeStep, DrtShift shift) {
Schedule schedule = vehicle.getSchedule();
StayTask stayTask = (StayTask) schedule.getCurrentTask();
- if (stayTask instanceof WaitForShiftTask waitForShiftTask) {
- if(waitForShiftTask instanceof EDrtWaitForShiftTask eDrtWaitForShiftTask) {
- if(eDrtWaitForShiftTask.getChargingTask() != null) {
- Task nextTask = Schedules.getNextTask(vehicle.getSchedule());
- if(nextTask instanceof WaitForShiftTask) {
- // set +1 to ensure this update happens after next shift start check
- nextTask.setEndTime(Math.max(timeStep + 1, shift.getStartTime()));
- //append stay task if required
- if(Schedules.getLastTask(schedule).equals(nextTask)) {
- schedule.addTask(taskFactory.createStayTask(vehicle, nextTask.getEndTime(), shift.getEndTime(), ((WaitForShiftTask) nextTask).getLink()));
- }
- } else {
- throw new RuntimeException();
- }
- } else {
- stayTask.setEndTime(Math.max(timeStep +1 , shift.getStartTime()));
+ if (stayTask instanceof EDrtWaitForShiftTask eDrtWaitForShiftTask) {
+ if (eDrtWaitForShiftTask.getChargingTask() != null) {
+ Task nextTask = Schedules.getNextTask(vehicle.getSchedule());
+ if (nextTask instanceof WaitForShiftTask) {
+ // set +1 to ensure this update happens after next shift start check
+ nextTask.setEndTime(Math.max(timeStep + 1, shift.getStartTime()));
//append stay task if required
- if(Schedules.getLastTask(schedule).equals(stayTask)) {
- schedule.addTask(taskFactory.createStayTask(vehicle, stayTask.getEndTime(), shift.getEndTime(), stayTask.getLink()));
+ if (Schedules.getLastTask(schedule).equals(nextTask)) {
+ schedule.addTask(taskFactory.createStayTask(vehicle, nextTask.getEndTime(), shift.getEndTime(), ((WaitForShiftTask) nextTask).getLink()));
}
+ } else {
+ throw new RuntimeException();
+ }
+ } else {
+ stayTask.setEndTime(Math.max(timeStep + 1, shift.getStartTime()));
+ //append stay task if required
+ if (Schedules.getLastTask(schedule).equals(stayTask)) {
+ schedule.addTask(taskFactory.createStayTask(vehicle, stayTask.getEndTime(), shift.getEndTime(), stayTask.getLink()));
}
}
}
+
}
@@ -412,10 +413,10 @@ public void cancelAssignedShift(ShiftDvrpVehicle vehicle, double timeStep, DrtSh
Schedule schedule = vehicle.getSchedule();
StayTask stayTask = (StayTask) schedule.getCurrentTask();
if (stayTask instanceof WaitForShiftTask waitForShiftTask) {
- if(waitForShiftTask instanceof EDrtWaitForShiftTask eDrtWaitForShiftTask) {
- if(eDrtWaitForShiftTask.getChargingTask() != null) {
+ if (waitForShiftTask instanceof EDrtWaitForShiftTask eDrtWaitForShiftTask) {
+ if (eDrtWaitForShiftTask.getChargingTask() != null) {
Task nextTask = Schedules.getNextTask(vehicle.getSchedule());
- if(nextTask instanceof WaitForShiftTask) {
+ if (nextTask instanceof WaitForShiftTask) {
nextTask.setEndTime(vehicle.getServiceEndTime());
} else {
throw new RuntimeException();
@@ -433,15 +434,15 @@ private void updateShiftChangeImpl(DvrpVehicle vehicle, VrpPathWithTravelData vr
DrtShift shift, OperationFacility facility, Task lastTask) {
Schedule schedule = vehicle.getSchedule();
- Optional oldChangeOver = ShiftSchedules.getNextShiftChangeover(schedule);
- if(oldChangeOver.isPresent() && oldChangeOver.get() instanceof EDrtShiftChangeoverTaskImpl) {
- if(((EDrtShiftChangeoverTaskImpl) oldChangeOver.get()).getChargingTask() != null) {
- ElectricVehicle ev = ((EvDvrpVehicle) vehicle).getElectricVehicle();
- ((EDrtShiftChangeoverTaskImpl) oldChangeOver.get()).getChargingTask().getChargingLogic().unassignVehicle(ev);
- }
- }
+ Optional oldChangeOver = ShiftSchedules.getNextShiftChangeover(schedule);
+ if (oldChangeOver.isPresent() && oldChangeOver.get() instanceof EDrtShiftChangeoverTaskImpl) {
+ if (((EDrtShiftChangeoverTaskImpl) oldChangeOver.get()).getChargingTask() != null) {
+ ElectricVehicle ev = ((EvDvrpVehicle) vehicle).getElectricVehicle();
+ ((EDrtShiftChangeoverTaskImpl) oldChangeOver.get()).getChargingTask().getChargingLogic().unassignVehicle(ev);
+ }
+ }
- List copy = new ArrayList<>(schedule.getTasks().subList(lastTask.getTaskIdx() + 1, schedule.getTasks().size()));
+ List copy = new ArrayList<>(schedule.getTasks().subList(lastTask.getTaskIdx() + 1, schedule.getTasks().size()));
for (Task task : copy) {
schedule.removeTask(task);
}
@@ -449,7 +450,7 @@ private void updateShiftChangeImpl(DvrpVehicle vehicle, VrpPathWithTravelData vr
((OnlineDriveTaskTracker) lastTask.getTaskTracker()).divertPath(vrpPath);
} else {
//add drive to break location
- lastTask.setEndTime(vrpPath.getDepartureTime());
+ lastTask.setEndTime(vrpPath.getDepartureTime());
schedule.addTask(taskFactory.createDriveTask(vehicle, vrpPath, RELOCATE_VEHICLE_SHIFT_CHANGEOVER_TASK_TYPE)); // add RELOCATE
}
diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/analysis/DumpShiftDataAtEndImpl.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/analysis/DumpShiftDataAtEndImpl.java
index 0960125e49d..ee65d26d4fd 100644
--- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/analysis/DumpShiftDataAtEndImpl.java
+++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/analysis/DumpShiftDataAtEndImpl.java
@@ -2,16 +2,14 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import org.matsim.contrib.drt.extension.operations.operationFacilities.OperationFacilitiesSpecification;
import org.matsim.contrib.drt.extension.operations.shifts.io.DrtShiftsWriter;
import org.matsim.contrib.drt.extension.operations.shifts.io.OperationFacilitiesWriter;
-import org.matsim.contrib.drt.extension.operations.operationFacilities.OperationFacilitiesSpecification;
import org.matsim.contrib.drt.extension.operations.shifts.shift.DrtShiftsSpecification;
import org.matsim.core.controler.OutputDirectoryHierarchy;
import org.matsim.core.controler.events.ShutdownEvent;
import org.matsim.core.controler.listener.ShutdownListener;
-import jakarta.inject.Provider;
-
/**
* Dumps DRT shift related data at end. Based on {@link org.matsim.core.controler.corelisteners.DumpDataAtEndImpl}
*
@@ -20,13 +18,13 @@
final public class DumpShiftDataAtEndImpl implements ShutdownListener {
private static final Logger log = LogManager.getLogger( DumpShiftDataAtEndImpl.class );
- private final Provider shifts;
+ private final DrtShiftsSpecification shifts;
private final OperationFacilitiesSpecification operationFacilities;
private final OutputDirectoryHierarchy controlerIO;
- public DumpShiftDataAtEndImpl(Provider shifts, OperationFacilitiesSpecification operationFacilities, OutputDirectoryHierarchy controlerIO) {
+ public DumpShiftDataAtEndImpl(DrtShiftsSpecification shifts, OperationFacilitiesSpecification operationFacilities, OutputDirectoryHierarchy controlerIO) {
this.shifts = shifts;
this.operationFacilities = operationFacilities;
this.controlerIO = controlerIO;
@@ -44,7 +42,7 @@ public void notifyShutdown(ShutdownEvent event) {
private void dumpShiftPans() {
try {
if ( this.shifts!=null){
- new DrtShiftsWriter(shifts.get()).writeFile(this.controlerIO.getOutputFilename("output_shifts.xml.gz"));
+ new DrtShiftsWriter(shifts).writeFile(this.controlerIO.getOutputFilename("output_shifts.xml.gz"));
}
} catch ( Exception ee ) {
log.error("Exception writing shifts.", ee);
diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/analysis/RegularShiftDump.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/analysis/RegularShiftDump.java
new file mode 100644
index 00000000000..908f66d0008
--- /dev/null
+++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/analysis/RegularShiftDump.java
@@ -0,0 +1,44 @@
+package org.matsim.contrib.drt.extension.operations.shifts.analysis;
+
+import com.google.inject.Provider;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.matsim.contrib.drt.extension.operations.shifts.io.DrtShiftsWriter;
+import org.matsim.contrib.drt.extension.operations.shifts.shift.DrtShiftsSpecification;
+import org.matsim.core.controler.OutputDirectoryHierarchy;
+import org.matsim.core.controler.events.IterationEndsEvent;
+import org.matsim.core.controler.listener.IterationEndsListener;
+
+
+/**
+ *
+ * @author nkuehnel / MOIA
+ */
+final public class RegularShiftDump implements IterationEndsListener {
+ private static final Logger log = LogManager.getLogger( RegularShiftDump.class );
+
+ private final Provider shifts;
+
+ private final OutputDirectoryHierarchy controlerIO;
+
+ public RegularShiftDump(Provider shifts, OutputDirectoryHierarchy controlerIO) {
+ this.shifts = shifts;
+ this.controlerIO = controlerIO;
+ }
+
+ private void dumpShiftPans(int iteration) {
+ try {
+ if ( this.shifts!=null){
+ new DrtShiftsWriter(shifts.get()).writeFile(this.controlerIO.getIterationFilename(iteration, "output_shifts.xml.gz"));
+ }
+ } catch ( Exception ee ) {
+ log.error("Exception writing shifts.", ee);
+ }
+ }
+
+
+ @Override
+ public void notifyIterationEnds(IterationEndsEvent event) {
+ dumpShiftPans(event.getIteration());
+ }
+}
diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/analysis/ShiftDurationXY.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/analysis/ShiftDurationXY.java
index 809e4385323..43af5244e69 100644
--- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/analysis/ShiftDurationXY.java
+++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/analysis/ShiftDurationXY.java
@@ -58,22 +58,28 @@ public void handleEvent(DrtShiftBreakStartedEvent event) {
@Override
public void handleEvent(final DrtShiftEndedEvent event) {
if (event.getMode().equals(mode)) {
- final Double start = shift2StartTime.get(event.getShiftId());
- double duration = event.getTime() - start;
- final DrtShiftSpecification drtShift = shifts.get().getShiftSpecifications().get(event.getShiftId());
- double plannedDuration = drtShift.getEndTime() - drtShift.getStartTime();
- shift2plannedVsActualDuration.put(event.getShiftId(), new Tuple<>(plannedDuration, duration));
+ Map, DrtShiftSpecification> shiftSpecifications = shifts.get().getShiftSpecifications();
+ if(shiftSpecifications.containsKey(event.getShiftId())) {
+ final DrtShiftSpecification drtShift = shiftSpecifications.get(event.getShiftId());
+ final Double start = shift2StartTime.get(event.getShiftId());
+ double duration = event.getTime() - start;
+ double plannedDuration = drtShift.getEndTime() - drtShift.getStartTime();
+ shift2plannedVsActualDuration.put(event.getShiftId(), new Tuple<>(plannedDuration, duration));
+ }
}
}
@Override
public void handleEvent(DrtShiftBreakEndedEvent event) {
if (event.getMode().equals(mode)) {
- final Double start = shift2BreakStartTime.get(event.getShiftId());
- double duration = event.getTime() - start;
- final DrtShiftBreakSpecification drtShift = shifts.get().getShiftSpecifications().get(event.getShiftId()).getBreak().orElseThrow();
- double plannedDuration = drtShift.getDuration();
- shift2plannedVsActualBreakDuration.put(event.getShiftId(), new Tuple<>(plannedDuration, duration));
+ Map, DrtShiftSpecification> shiftSpecifications = shifts.get().getShiftSpecifications();
+ if(shiftSpecifications.containsKey(event.getShiftId())) {
+ final Double start = shift2BreakStartTime.get(event.getShiftId());
+ double duration = event.getTime() - start;
+ final DrtShiftBreakSpecification drtShift = shifts.get().getShiftSpecifications().get(event.getShiftId()).getBreak().orElseThrow();
+ double plannedDuration = drtShift.getDuration();
+ shift2plannedVsActualBreakDuration.put(event.getShiftId(), new Tuple<>(plannedDuration, duration));
+ }
}
}
diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/analysis/ShiftHistogram.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/analysis/ShiftHistogram.java
index 00dc4e85a02..b2539c40ba7 100644
--- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/analysis/ShiftHistogram.java
+++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/analysis/ShiftHistogram.java
@@ -1,9 +1,6 @@
package org.matsim.contrib.drt.extension.operations.shifts.analysis;
-import org.matsim.api.core.v01.Id;
-import org.matsim.api.core.v01.population.Population;
import org.matsim.contrib.drt.extension.operations.shifts.events.*;
-import org.matsim.contrib.drt.extension.operations.shifts.shift.DrtShift;
import org.matsim.core.config.Config;
import org.matsim.core.utils.io.IOUtils;
import org.matsim.core.utils.misc.Time;
@@ -12,35 +9,30 @@
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.UncheckedIOException;
-import java.util.Set;
/**
* @author nkuehnel / MOIA
*/
public class ShiftHistogram implements DrtShiftStartedEventHandler, DrtShiftEndedEventHandler,
- DrtShiftBreakStartedEventHandler, DrtShiftBreakEndedEventHandler {
+ DrtShiftBreakStartedEventHandler, DrtShiftBreakEndedEventHandler {
private final String mode;
- public static final int DEFAULT_END_TIME = 30 * 3600;
- public static final int DEFAULT_BIN_SIZE = 300;
+ public static final int DEFAULT_END_TIME = 30 * 3600;
+ public static final int DEFAULT_BIN_SIZE = 300;
- private Set> shiftIds;
private int iteration = 0;
private final int binSize;
private final int nofBins;
private DataFrame data = null;
- public ShiftHistogram(Population population, String mode, Config config) {
- super();
+ public ShiftHistogram(String mode, Config config) {
+ super();
this.mode = mode;
this.binSize = DEFAULT_BIN_SIZE;
- this.nofBins = ((int) config.qsim().getEndTime().orElse(DEFAULT_END_TIME) ) / this.binSize + 1;
- reset(0);
- if (population == null) {
- this.shiftIds = null;
- }
+ this.nofBins = ((int) config.qsim().getEndTime().orElse(DEFAULT_END_TIME)) / this.binSize + 1;
+ reset(0);
}
/**
@@ -63,10 +55,9 @@ public ShiftHistogram(String mode, final int binSize, final int nofBins) {
public void handleEvent(final DrtShiftStartedEvent event) {
if (event.getMode().equals(mode)) {
int index = getBinIndex(event.getTime());
- if ((this.shiftIds == null || this.shiftIds.contains(event.getShiftId()))) {
- DataFrame dataFrame = getData();
- dataFrame.countsStart[index]++;
- }
+ DataFrame dataFrame = getData();
+ dataFrame.countsStart[index]++;
+
}
}
@@ -74,10 +65,9 @@ public void handleEvent(final DrtShiftStartedEvent event) {
public void handleEvent(final DrtShiftEndedEvent event) {
if (event.getMode().equals(mode)) {
int index = getBinIndex(event.getTime());
- if ((this.shiftIds == null || this.shiftIds.contains(event.getShiftId()))) {
- DataFrame dataFrame = getData();
- dataFrame.countsEnd[index]++;
- }
+ DataFrame dataFrame = getData();
+ dataFrame.countsEnd[index]++;
+
}
}
diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/config/ShiftsParams.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/config/ShiftsParams.java
index e61e5541896..3409d13b051 100644
--- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/config/ShiftsParams.java
+++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/config/ShiftsParams.java
@@ -8,8 +8,10 @@
*/
package org.matsim.contrib.drt.extension.operations.shifts.config;
+import com.google.common.base.Verify;
import org.matsim.contrib.common.util.ReflectiveConfigGroupWithConfigurableParameterSets;
import org.matsim.contrib.ev.infrastructure.ChargerSpecification;
+import org.matsim.core.config.Config;
import org.matsim.core.config.ConfigGroup;
import java.net.URL;
@@ -60,7 +62,7 @@ public class ShiftsParams extends ReflectiveConfigGroupWithConfigurableParameter
@Parameter
@Comment("defines the battery state of charge threshold at which vehicles will start charging" +
" at hubs when not in an active shift. values between [0,1)")
- public double chargeAtHubThreshold = 0.5;
+ public double chargeAtHubThreshold = 0.6;
@Parameter
@Comment("defines the battery state of charge threshold at which vehicles will start charging" +
@@ -97,11 +99,19 @@ public class ShiftsParams extends ReflectiveConfigGroupWithConfigurableParameter
"In this case, make sure that 'shiftScheduleLookAhead' is larger than the prebboking slack.")
public boolean considerUpcomingShiftsForInsertion = false;
- public ShiftsParams() {
+ public ShiftsParams() {
super(SET_NAME);
}
public URL getShiftInputUrl(URL context) {
return shiftInputFile == null ? null : ConfigGroup.getInputFileURL(context, shiftInputFile);
}
+
+ @Override
+ protected void checkConsistency(Config config) {
+ super.checkConsistency(config);
+ Verify.verify(chargeAtHubThreshold >= shiftAssignmentBatteryThreshold,
+ "chargeAtHubThreshold must be higher than shiftAssignmentBatteryThreshold to " +
+ "avoid deadlocks with undercharged vehicles in hubs.");
+ }
}
diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/dispatcher/DefaultShiftScheduler.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/dispatcher/DefaultShiftScheduler.java
new file mode 100644
index 00000000000..e51d7e01ec3
--- /dev/null
+++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/dispatcher/DefaultShiftScheduler.java
@@ -0,0 +1,52 @@
+package org.matsim.contrib.drt.extension.operations.shifts.dispatcher;
+
+import com.google.common.collect.ImmutableMap;
+import org.matsim.api.core.v01.Id;
+import org.matsim.contrib.drt.extension.operations.shifts.shift.*;
+import org.matsim.contrib.dvrp.fleet.Fleet;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Function;
+
+/**
+ * @author nkuehnel / MOIA
+ */
+public final class DefaultShiftScheduler implements ShiftScheduler {
+
+ private final DrtShiftsSpecification shiftsSpecification;
+ public static Function createShiftFromSpec = spec -> {
+ DefaultShiftBreakImpl shiftBreak = null;
+ DrtShiftBreakSpecification breakSpec = spec.getBreak().orElse(null);
+ if (breakSpec != null) {
+ shiftBreak = new DefaultShiftBreakImpl(
+ breakSpec.getEarliestBreakStartTime(),
+ breakSpec.getLatestBreakEndTime(),
+ breakSpec.getDuration());
+ }
+ return (DrtShift) new DrtShiftImpl(spec.getId(), spec.getStartTime(), spec.getEndTime(),
+ spec.getOperationFacilityId().orElse(null), spec.getDesignatedVehicleId().orElse(null),
+ shiftBreak);
+ };
+
+ public DefaultShiftScheduler(DrtShiftsSpecification shiftsSpecification) {
+ this.shiftsSpecification = shiftsSpecification;
+ }
+ @Override
+ public List schedule(double time, Fleet fleet) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public ImmutableMap, DrtShift> initialSchedule() {
+ return shiftsSpecification.getShiftSpecifications().values()
+ .stream()
+ .map(createShiftFromSpec)
+ .collect(ImmutableMap.toImmutableMap(DrtShift::getId, s -> s));
+ }
+
+ @Override
+ public DrtShiftsSpecification get() {
+ return shiftsSpecification;
+ }
+}
diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/dispatcher/DrtShiftDispatcherImpl.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/dispatcher/DrtShiftDispatcherImpl.java
index 6e082f6f7d5..198401f4526 100644
--- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/dispatcher/DrtShiftDispatcherImpl.java
+++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/dispatcher/DrtShiftDispatcherImpl.java
@@ -20,7 +20,6 @@
import org.matsim.contrib.drt.extension.operations.shifts.schedule.ShiftSchedules;
import org.matsim.contrib.drt.extension.operations.shifts.scheduler.ShiftTaskScheduler;
import org.matsim.contrib.drt.extension.operations.shifts.shift.DrtShift;
-import org.matsim.contrib.drt.extension.operations.shifts.shift.DrtShifts;
import org.matsim.contrib.drt.schedule.DrtDriveTask;
import org.matsim.contrib.drt.schedule.DrtStayTask;
import org.matsim.contrib.drt.schedule.DrtStopTask;
@@ -51,7 +50,7 @@ public class DrtShiftDispatcherImpl implements DrtShiftDispatcher {
private final String mode;
- private SortedSet unscheduledShifts;
+ private SortedSet unAssignedShifts;
private SortedSet assignedShifts;
private SortedSet activeShifts;
private SortedSet endingShifts;
@@ -59,7 +58,6 @@ public class DrtShiftDispatcherImpl implements DrtShiftDispatcher {
private Map, Queue> idleVehiclesQueues;
private final Fleet fleet;
- private final DrtShifts shifts;
private final MobsimTimer timer;
@@ -76,12 +74,14 @@ public class DrtShiftDispatcherImpl implements DrtShiftDispatcher {
private final ShiftStartLogic shiftStartLogic;
private final AssignShiftToVehicleLogic assignShiftToVehicleLogic;
- public DrtShiftDispatcherImpl(String mode, DrtShifts shifts, Fleet fleet, MobsimTimer timer, OperationFacilities operationFacilities,
+ private final ShiftScheduler shiftScheduler;
+
+ public DrtShiftDispatcherImpl(String mode, Fleet fleet, MobsimTimer timer, OperationFacilities operationFacilities,
OperationFacilityFinder breakFacilityFinder, ShiftTaskScheduler shiftTaskScheduler,
Network network, EventsManager eventsManager, ShiftsParams drtShiftParams,
- ShiftStartLogic shiftStartLogic, AssignShiftToVehicleLogic assignShiftToVehicleLogic) {
+ ShiftStartLogic shiftStartLogic, AssignShiftToVehicleLogic assignShiftToVehicleLogic,
+ ShiftScheduler shiftScheduler) {
this.mode = mode;
- this.shifts = shifts;
this.fleet = fleet;
this.timer = timer;
this.operationFacilities = operationFacilities;
@@ -92,15 +92,25 @@ public DrtShiftDispatcherImpl(String mode, DrtShifts shifts, Fleet fleet, Mobsim
this.drtShiftParams = drtShiftParams;
this.shiftStartLogic = shiftStartLogic;
this.assignShiftToVehicleLogic = assignShiftToVehicleLogic;
+ this.shiftScheduler = shiftScheduler;
}
@Override
public void initialize() {
- unscheduledShifts = new TreeSet<>(Comparator.comparingDouble(DrtShift::getStartTime));
- unscheduledShifts.addAll(shifts.getShifts().values());
+ unAssignedShifts = new TreeSet<>(Comparator.comparingDouble(DrtShift::getStartTime).thenComparing(Comparator.naturalOrder()));
+ unAssignedShifts.addAll(shiftScheduler.initialSchedule().values());
+
+ assignedShifts = new TreeSet<>(Comparator
+ .comparingDouble((ShiftEntry entry) -> entry.shift().getStartTime())
+ .thenComparing(ShiftEntry::shift));
- assignedShifts = new TreeSet<>(Comparator.comparingDouble(v -> v.shift().getStartTime()));
+ activeShifts = new TreeSet<>(Comparator
+ .comparingDouble((ShiftEntry entry) -> entry.shift().getEndTime())
+ .thenComparing(ShiftEntry::shift));
+ endingShifts = new TreeSet<>(Comparator
+ .comparingDouble((ShiftEntry entry) -> entry.shift().getEndTime())
+ .thenComparing(ShiftEntry::shift));
idleVehiclesQueues = new LinkedHashMap<>();
for(OperationFacility facility: operationFacilities.getDrtOperationFacilities().values()) {
@@ -114,15 +124,13 @@ public void initialize() {
queue
);
}
- activeShifts = new TreeSet<>(Comparator.comparingDouble(v -> v.shift().getEndTime()));
- endingShifts = new TreeSet<>(Comparator.comparingDouble(v -> v.shift().getEndTime()));
}
@Override
public void dispatch(double timeStep) {
if(timeStep % drtShiftParams.loggingInterval == 0) {
logger.info(String.format("Active shifts: %s | Assigned shifts: %s | Unscheduled shifts: %s",
- activeShifts.size(), assignedShifts.size(), unscheduledShifts.size()));
+ activeShifts.size(), assignedShifts.size(), unAssignedShifts.size()));
StringJoiner print = new StringJoiner(" | ");
for (Map.Entry, Queue> queueEntry : idleVehiclesQueues.entrySet()) {
print.add(String.format("Idle vehicles at facility %s: %d", queueEntry.getKey().toString(), queueEntry.getValue().size()));
@@ -133,6 +141,7 @@ public void dispatch(double timeStep) {
if (timeStep % (drtShiftParams.updateShiftEndInterval) == 0) {
updateShiftEnds(timeStep);
}
+ scheduleShifts(timeStep, this.fleet);
assignShifts(timeStep);
startShifts(timeStep);
checkBreaks();
@@ -162,6 +171,12 @@ private void checkBreaks() {
}
}
+
+ private void scheduleShifts(double timeStep, Fleet fleet) {
+ List scheduled = shiftScheduler.schedule(timeStep, fleet);
+ unAssignedShifts.addAll(scheduled);
+ }
+
private void startShifts(double timeStep) {
final Iterator iterator = this.assignedShifts.iterator();
while (iterator.hasNext()) {
@@ -194,7 +209,7 @@ private void startShifts(double timeStep) {
private void assignShifts(double timeStep) {
// Remove elapsed shifts
- unscheduledShifts.removeIf(shift -> {
+ unAssignedShifts.removeIf(shift -> {
if (shift.getStartTime() + drtShiftParams.maxUnscheduledShiftDelay < timeStep ) {
logger.warn("Shift with ID " + shift.getId() + " could not be assigned and is being removed as start time is longer in the past than defined by maxUnscheduledShiftDelay.");
return true;
@@ -204,7 +219,7 @@ private void assignShifts(double timeStep) {
// Assign shifts
Set assignableShifts = new LinkedHashSet<>();
- Iterator unscheduledShiftsIterator = unscheduledShifts.iterator();
+ Iterator unscheduledShiftsIterator = unAssignedShifts.iterator();
while(unscheduledShiftsIterator.hasNext()) {
DrtShift unscheduledShift = unscheduledShiftsIterator.next();
if(isSchedulable(unscheduledShift, timeStep)) {
@@ -218,31 +233,46 @@ private void assignShifts(double timeStep) {
for (DrtShift shift : assignableShifts) {
ShiftDvrpVehicle vehicle = null;
- for (ShiftEntry active : activeShifts) {
- if (active.shift().getEndTime() > shift.getStartTime()) {
- break;
+ if(shift.getDesignatedVehicleId().isPresent()) {
+ DvrpVehicle designatedVehicle = fleet.getVehicles().get(shift.getDesignatedVehicleId().get());
+ Verify.verify(designatedVehicle.getSchedule().getStatus() == Schedule.ScheduleStatus.STARTED);
+ Verify.verify(designatedVehicle instanceof ShiftDvrpVehicle);
+ if(!((ShiftDvrpVehicle) designatedVehicle).getShifts().isEmpty()) {
+ continue;
}
if(shift.getOperationFacilityId().isPresent()) {
- //we have to check that the vehicle ends the previous shift at the same facility where
- //the new shift is to start.
- if(active.shift().getOperationFacilityId().isPresent()) {
- if(!active.shift().getOperationFacilityId().get().equals(shift.getOperationFacilityId().get())) {
- continue;
- }
- } else {
- Optional nextShiftChangeover = ShiftSchedules.getNextShiftChangeover(active.vehicle().getSchedule());
- if(nextShiftChangeover.isPresent()) {
- Verify.verify(nextShiftChangeover.get().getShift().equals(active.shift()));
- if(!nextShiftChangeover.get().getFacility().getId().equals(shift.getOperationFacilityId().get())) {
- // there is already a shift changeover scheduled elsewhere
+ Verify.verify(idleVehiclesQueues.get(shift.getOperationFacilityId().get()).contains(designatedVehicle));
+ }
+ vehicle = (ShiftDvrpVehicle) designatedVehicle;
+ }
+
+ if(vehicle == null) {
+ for (ShiftEntry active : activeShifts) {
+ if (active.shift().getEndTime() > shift.getStartTime()) {
+ break;
+ }
+ if (shift.getOperationFacilityId().isPresent()) {
+ //we have to check that the vehicle ends the previous shift at the same facility where
+ //the new shift is to start.
+ if (active.shift().getOperationFacilityId().isPresent()) {
+ if (!active.shift().getOperationFacilityId().get().equals(shift.getOperationFacilityId().get())) {
continue;
}
+ } else {
+ Optional nextShiftChangeover = ShiftSchedules.getNextShiftChangeover(active.vehicle().getSchedule());
+ if (nextShiftChangeover.isPresent()) {
+ Verify.verify(nextShiftChangeover.get().getShift().equals(active.shift()));
+ if (!nextShiftChangeover.get().getFacility().getId().equals(shift.getOperationFacilityId().get())) {
+ // there is already a shift changeover scheduled elsewhere
+ continue;
+ }
+ }
}
}
- }
- if (assignShiftToVehicleLogic.canAssignVehicleToShift(active.vehicle(), shift)) {
- vehicle = active.vehicle();
- break;
+ if (assignShiftToVehicleLogic.canAssignVehicleToShift(active.vehicle(), shift)) {
+ vehicle = active.vehicle();
+ break;
+ }
}
}
@@ -277,7 +307,7 @@ private void assignShifts(double timeStep) {
} else {
// logger.warn("Could not assign shift " + shift.getId().toString() + " to a
// vehicle. Will retry next time step.");
- this.unscheduledShifts.add(shift);
+ this.unAssignedShifts.add(shift);
}
}
}
diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/dispatcher/ShiftScheduler.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/dispatcher/ShiftScheduler.java
new file mode 100644
index 00000000000..e5f74f8b75e
--- /dev/null
+++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/dispatcher/ShiftScheduler.java
@@ -0,0 +1,21 @@
+package org.matsim.contrib.drt.extension.operations.shifts.dispatcher;
+
+import com.google.common.collect.ImmutableMap;
+import org.matsim.api.core.v01.Id;
+import org.matsim.contrib.drt.extension.operations.shifts.shift.DrtShift;
+import org.matsim.contrib.drt.extension.operations.shifts.shift.DrtShiftsSpecification;
+
+import jakarta.inject.Provider;
+import org.matsim.contrib.dvrp.fleet.Fleet;
+
+import java.util.List;
+
+/**
+ * @author nkuehnel / MOIA
+ */
+public interface ShiftScheduler extends Provider {
+
+ List schedule(double time, Fleet fleet);
+ ImmutableMap, DrtShift> initialSchedule();
+
+}
diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/io/DrtShiftsReader.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/io/DrtShiftsReader.java
index f707a8c8108..928fd2360cd 100644
--- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/io/DrtShiftsReader.java
+++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/io/DrtShiftsReader.java
@@ -8,6 +8,7 @@
import org.matsim.contrib.drt.extension.operations.shifts.shift.DrtShiftBreakSpecificationImpl;
import org.matsim.contrib.drt.extension.operations.shifts.shift.DrtShiftSpecificationImpl;
import org.matsim.contrib.drt.extension.operations.shifts.shift.DrtShiftsSpecification;
+import org.matsim.contrib.dvrp.fleet.DvrpVehicle;
import org.matsim.core.utils.io.MatsimXmlParser;
import org.xml.sax.Attributes;
@@ -27,6 +28,7 @@ public class DrtShiftsReader extends MatsimXmlParser {
public static final String START_TIME = "start";
public static final String END_TIME = "end";
public static final String OPERATION_FACILITY_ID = "operationFacilityId";
+ public static final String DESIGNATED_VEHICLE_ID = "designatedVehicleId";
public static final String EARLIEST_BREAK_START_TIME = "earliestStart";
public static final String LATEST_BREAK_END_TIME = "latestEnd";
@@ -55,8 +57,12 @@ public void startTag(final String name, final Attributes atts, final Stack, DrtShiftSpecification> shifts) throws
atts.add(createTuple(END_TIME, shift.getEndTime()));
shift.getOperationFacilityId().ifPresent(operationFacilityId ->
atts.add(createTuple(OPERATION_FACILITY_ID, operationFacilityId.toString())));
+ shift.getDesignatedVehicleId().ifPresent(designatedVehicleId ->
+ atts.add(createTuple(DESIGNATED_VEHICLE_ID, designatedVehicleId.toString())));
this.writeStartTag(SHIFT_NAME, atts);
//Write break, if present
diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/run/ShiftDrtModeModule.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/run/ShiftDrtModeModule.java
index 8b52ca88951..fd4756bb2ab 100644
--- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/run/ShiftDrtModeModule.java
+++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/run/ShiftDrtModeModule.java
@@ -5,12 +5,14 @@
import com.google.inject.Provider;
import com.google.inject.Singleton;
import com.google.inject.TypeLiteral;
-import org.matsim.api.core.v01.population.Population;
+import org.matsim.contrib.common.timeprofile.ProfileWriter;
import org.matsim.contrib.drt.extension.DrtWithExtensionsConfigGroup;
import org.matsim.contrib.drt.extension.operations.DrtOperationsParams;
import org.matsim.contrib.drt.extension.operations.operationFacilities.OperationFacilitiesSpecification;
import org.matsim.contrib.drt.extension.operations.shifts.analysis.*;
import org.matsim.contrib.drt.extension.operations.shifts.config.ShiftsParams;
+import org.matsim.contrib.drt.extension.operations.shifts.dispatcher.ShiftScheduler;
+import org.matsim.contrib.drt.extension.operations.shifts.dispatcher.DefaultShiftScheduler;
import org.matsim.contrib.drt.extension.operations.shifts.io.DrtShiftsReader;
import org.matsim.contrib.drt.extension.operations.shifts.schedule.ShiftBreakTaskImpl;
import org.matsim.contrib.drt.extension.operations.shifts.schedule.ShiftChangeoverTaskImpl;
@@ -24,14 +26,13 @@
import org.matsim.contrib.drt.schedule.DrtStayTask;
import org.matsim.contrib.drt.schedule.DrtTaskBaseType;
import org.matsim.contrib.drt.scheduler.EmptyVehicleRelocator;
-import org.matsim.contrib.dvrp.fleet.FleetSpecification;
-import org.matsim.contrib.dvrp.run.AbstractDvrpModeModule;
-import org.matsim.contrib.dvrp.schedule.Task;
-import org.matsim.contrib.common.timeprofile.ProfileWriter;
import org.matsim.contrib.dvrp.analysis.VehicleOccupancyProfileCalculator;
import org.matsim.contrib.dvrp.analysis.VehicleOccupancyProfileView;
import org.matsim.contrib.dvrp.analysis.VehicleTaskProfileCalculator;
import org.matsim.contrib.dvrp.analysis.VehicleTaskProfileView;
+import org.matsim.contrib.dvrp.fleet.FleetSpecification;
+import org.matsim.contrib.dvrp.run.AbstractDvrpModeModule;
+import org.matsim.contrib.dvrp.schedule.Task;
import org.matsim.core.config.Config;
import org.matsim.core.config.groups.QSimConfigGroup;
import org.matsim.core.controler.MatsimServices;
@@ -82,14 +83,15 @@ public ShiftDrtModeModule(DrtConfigGroup drtCfg) {
@Override
public void install() {
ShiftsParams shiftsParams = drtOperationsParams.getShiftsParams().orElseThrow();
+
+ DrtShiftsSpecification drtShiftsSpecification = new DrtShiftsSpecificationImpl();
if (shiftsParams.shiftInputFile != null) {
- bindModal(DrtShiftsSpecification.class).toProvider(() -> {
- DrtShiftsSpecification drtShiftsSpecification = new DrtShiftsSpecificationImpl();
- new DrtShiftsReader(drtShiftsSpecification).readURL(shiftsParams.getShiftInputUrl(getConfig().getContext()));
- return drtShiftsSpecification;
- }).asEagerSingleton();
+ new DrtShiftsReader(drtShiftsSpecification).readURL(shiftsParams.getShiftInputUrl(getConfig().getContext()));
}
+ bindModal(ShiftScheduler.class).toProvider(modalProvider(getter -> new DefaultShiftScheduler(drtShiftsSpecification)));
+ bindModal(DrtShiftsSpecification.class).toProvider(modalKey(ShiftScheduler.class));
+
bindModal(ShiftDurationXY.class).toProvider(modalProvider(
getter -> new ShiftDurationXY(getter.getModal(new TypeLiteral>(){}), getMode())
)).asEagerSingleton();
@@ -99,7 +101,7 @@ public void install() {
)).asEagerSingleton();
bindModal(ShiftHistogram.class).toProvider(modalProvider(
- getter -> new ShiftHistogram(getter.get(Population.class), getMode(), getter.get(Config.class)))).asEagerSingleton();
+ getter -> new ShiftHistogram(getMode(), getter.get(Config.class)))).asEagerSingleton();
addEventHandlerBinding().to(modalKey(ShiftDurationXY.class));
addEventHandlerBinding().to(modalKey(BreakCorridorXY.class));
@@ -115,7 +117,7 @@ public void install() {
bindModal(DumpShiftDataAtEndImpl.class).toProvider(modalProvider(
getter -> new DumpShiftDataAtEndImpl(
- getter.getModal(new TypeLiteral>(){}),
+ getter.getModal(DrtShiftsSpecification.class),
getter.getModal(OperationFacilitiesSpecification.class),
getter.get(OutputDirectoryHierarchy.class)
))
@@ -137,5 +139,16 @@ public void install() {
addControlerListenerBinding().toProvider(modalProvider(getter -> new ProfileWriter(getter.get(MatsimServices.class), drtConfigGroup.getMode(),
new VehicleTaskProfileView(getter.getModal(VehicleTaskProfileCalculator.class), taskTypeComparator, taskTypePaints),
"shift_task_time_profiles"))).in(Singleton.class);
+
+ bindModal(RegularShiftDump.class).toProvider(modalProvider(
+ getter -> new RegularShiftDump(
+ getter.getModal(new TypeLiteral>(){}),
+ getter.get(OutputDirectoryHierarchy.class)
+ ))
+ ).asEagerSingleton();
+
+ addControlerListenerBinding().toProvider(modalProvider(
+ getter -> getter.getModal(RegularShiftDump.class)
+ ));
}
}
diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/run/ShiftDrtModeOptimizerQSimModule.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/run/ShiftDrtModeOptimizerQSimModule.java
index a65de06b2c4..70423f2e59e 100644
--- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/run/ShiftDrtModeOptimizerQSimModule.java
+++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/run/ShiftDrtModeOptimizerQSimModule.java
@@ -1,18 +1,13 @@
package org.matsim.contrib.drt.extension.operations.shifts.run;
-import com.google.common.collect.ImmutableMap;
import com.google.inject.Singleton;
-import org.matsim.api.core.v01.Id;
import org.matsim.api.core.v01.network.Network;
import org.matsim.contrib.drt.extension.DrtWithExtensionsConfigGroup;
import org.matsim.contrib.drt.extension.operations.DrtOperationsParams;
import org.matsim.contrib.drt.extension.operations.operationFacilities.OperationFacilities;
import org.matsim.contrib.drt.extension.operations.operationFacilities.OperationFacilityFinder;
import org.matsim.contrib.drt.extension.operations.shifts.config.ShiftsParams;
-import org.matsim.contrib.drt.extension.operations.shifts.dispatcher.DefaultAssignShiftToVehicleLogic;
-import org.matsim.contrib.drt.extension.operations.shifts.dispatcher.DefaultShiftStartLogic;
-import org.matsim.contrib.drt.extension.operations.shifts.dispatcher.DrtShiftDispatcher;
-import org.matsim.contrib.drt.extension.operations.shifts.dispatcher.DrtShiftDispatcherImpl;
+import org.matsim.contrib.drt.extension.operations.shifts.dispatcher.*;
import org.matsim.contrib.drt.extension.operations.shifts.fleet.DefaultShiftDvrpVehicle;
import org.matsim.contrib.drt.extension.operations.shifts.optimizer.ShiftDrtOptimizer;
import org.matsim.contrib.drt.extension.operations.shifts.optimizer.ShiftVehicleDataEntryFactory;
@@ -24,7 +19,6 @@
import org.matsim.contrib.drt.extension.operations.shifts.scheduler.ShiftDrtScheduleInquiry;
import org.matsim.contrib.drt.extension.operations.shifts.scheduler.ShiftTaskScheduler;
import org.matsim.contrib.drt.extension.operations.shifts.scheduler.ShiftTaskSchedulerImpl;
-import org.matsim.contrib.drt.extension.operations.shifts.shift.*;
import org.matsim.contrib.drt.optimizer.*;
import org.matsim.contrib.drt.optimizer.depot.DepotFinder;
import org.matsim.contrib.drt.optimizer.insertion.CostCalculationStrategy;
@@ -77,27 +71,6 @@ public ShiftDrtModeOptimizerQSimModule(DrtConfigGroup drtCfg) {
protected void configureQSim() {
ShiftsParams shiftsParams = drtOperationsParams.getShiftsParams().orElseThrow();
- bindModal(DrtShifts.class).toProvider(new ModalProviders.AbstractProvider<>(getMode(), DvrpModes::mode) {
- @Override
- public DrtShifts get() {
- DrtShiftsSpecification shiftsSpecification = getModalInstance(DrtShiftsSpecification.class);
- ImmutableMap, DrtShiftImpl> shifts = shiftsSpecification.getShiftSpecifications().values()
- .stream()
- .map(spec -> {
- DefaultShiftBreakImpl shiftBreak = null;
- DrtShiftBreakSpecification breakSpec = spec.getBreak().orElse(null);
- if(breakSpec != null) {
- shiftBreak = new DefaultShiftBreakImpl(
- breakSpec.getEarliestBreakStartTime(),
- breakSpec.getLatestBreakEndTime(),
- breakSpec.getDuration());
- }
- return new DrtShiftImpl(spec.getId(), spec.getStartTime(), spec.getEndTime(), spec.getOperationFacilityId().orElse(null), shiftBreak);
- })
- .collect(ImmutableMap.toImmutableMap(DrtShift::getId, s -> s));
- return () -> shifts;
- }
- }).asEagerSingleton();
addModalComponent(DrtOptimizer.class, modalProvider(
getter -> {
@@ -112,11 +85,12 @@ public DrtShifts get() {
getter.getModal(ScheduleTimingUpdater.class));
}));
- bindModal(DrtShiftDispatcher.class).toProvider(modalProvider(
- getter -> new DrtShiftDispatcherImpl(getMode(), getter.getModal(DrtShifts.class), getter.getModal(Fleet.class),
- getter.get(MobsimTimer.class), getter.getModal(OperationFacilities.class), getter.getModal(OperationFacilityFinder.class),
+ bindModal(DrtShiftDispatcher.class).toProvider(modalProvider(
+ getter -> new DrtShiftDispatcherImpl(getMode(), getter.getModal(Fleet.class), getter.get(MobsimTimer.class),
+ getter.getModal(OperationFacilities.class), getter.getModal(OperationFacilityFinder.class),
getter.getModal(ShiftTaskScheduler.class), getter.getModal(Network.class), getter.get(EventsManager.class),
- shiftsParams, new DefaultShiftStartLogic(), new DefaultAssignShiftToVehicleLogic(shiftsParams)))
+ shiftsParams, new DefaultShiftStartLogic(), new DefaultAssignShiftToVehicleLogic(shiftsParams),
+ getter.getModal(ShiftScheduler.class)))
).asEagerSingleton();
bindModal(InsertionCostCalculator.class).toProvider(modalProvider(
diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/scheduler/ShiftTaskSchedulerImpl.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/scheduler/ShiftTaskSchedulerImpl.java
index 94b5c3d0fed..c2fcc1ac4ee 100644
--- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/scheduler/ShiftTaskSchedulerImpl.java
+++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/scheduler/ShiftTaskSchedulerImpl.java
@@ -269,6 +269,8 @@ public void startShift(ShiftDvrpVehicle vehicle, double now, DrtShift shift) {
if(Schedules.getLastTask(schedule).equals(stayTask)) {
//nothing planned yet.
schedule.addTask(taskFactory.createStayTask(vehicle, now, shift.getEndTime(), stayTask.getLink()));
+ } else {
+ Schedules.getNextTask(schedule).setBeginTime(now);
}
} else {
throw new IllegalStateException("Vehicle cannot start shift during task:" + stayTask.getTaskType().name());
@@ -296,7 +298,8 @@ public void planAssignedShift(ShiftDvrpVehicle vehicle, double timeStep, DrtShif
Schedule schedule = vehicle.getSchedule();
StayTask stayTask = (StayTask) schedule.getCurrentTask();
if (stayTask instanceof WaitForShiftTask) {
- stayTask.setEndTime(Math.max(timeStep, shift.getStartTime()));
+ // set +1 to ensure this update happens after next shift start check
+ stayTask.setEndTime(Math.max(timeStep + 1, shift.getStartTime()));
}
}
diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/shift/DrtShift.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/shift/DrtShift.java
index d641677cd38..5682dbeaf55 100644
--- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/shift/DrtShift.java
+++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/shift/DrtShift.java
@@ -3,20 +3,19 @@
import org.matsim.api.core.v01.Id;
import org.matsim.api.core.v01.Identifiable;
import org.matsim.contrib.drt.extension.operations.operationFacilities.OperationFacility;
+import org.matsim.contrib.dvrp.fleet.DvrpVehicle;
import java.util.Optional;
/**
* @author nkuehnel, fzwick / MOIA
*/
-public interface DrtShift extends Identifiable {
+public interface DrtShift extends Identifiable, Comparable {
double getStartTime();
double getEndTime();
- Optional getBreak();
-
boolean isStarted();
boolean isEnded();
@@ -26,4 +25,8 @@ public interface DrtShift extends Identifiable {
void end();
Optional> getOperationFacilityId();
+
+ Optional getBreak();
+
+ Optional> getDesignatedVehicleId();
}
diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/shift/DrtShiftImpl.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/shift/DrtShiftImpl.java
index 79373816104..676e0fc6cc3 100644
--- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/shift/DrtShiftImpl.java
+++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/shift/DrtShiftImpl.java
@@ -2,6 +2,7 @@
import org.matsim.api.core.v01.Id;
import org.matsim.contrib.drt.extension.operations.operationFacilities.OperationFacility;
+import org.matsim.contrib.dvrp.fleet.DvrpVehicle;
import java.util.Optional;
@@ -15,6 +16,7 @@ public class DrtShiftImpl implements DrtShift {
private final double start;
private final double end;
private final Id operationFacilityId;
+ private final Id designatedVehicleId;
private final DrtShiftBreak shiftBreak;
@@ -22,12 +24,13 @@ public class DrtShiftImpl implements DrtShift {
private boolean ended = false;
public DrtShiftImpl(Id id, double start, double end, Id operationFacilityId,
- DrtShiftBreak shiftBreak) {
+ Id designatedVehicleId, DrtShiftBreak shiftBreak) {
this.id = id;
this.start = start;
this.end = end;
this.operationFacilityId = operationFacilityId;
- this.shiftBreak = shiftBreak;
+ this.designatedVehicleId = designatedVehicleId;
+ this.shiftBreak = shiftBreak;
}
@Override
@@ -45,6 +48,11 @@ public Optional getBreak() {
return Optional.ofNullable(shiftBreak);
}
+ @Override
+ public Optional> getDesignatedVehicleId() {
+ return Optional.ofNullable(designatedVehicleId);
+ }
+
@Override
public boolean isStarted() {
return started;
@@ -87,4 +95,9 @@ public Id getId() {
public String toString() {
return "Shift " + id.toString() + " ["+start+"-"+end+"]";
}
+
+ @Override
+ public int compareTo(DrtShift shift) {
+ return this.id.compareTo(shift.getId());
+ }
}
diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/shift/DrtShiftSpecification.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/shift/DrtShiftSpecification.java
index 18f877c45e3..e32ad8a8416 100644
--- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/shift/DrtShiftSpecification.java
+++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/shift/DrtShiftSpecification.java
@@ -3,6 +3,7 @@
import org.matsim.api.core.v01.Id;
import org.matsim.api.core.v01.Identifiable;
import org.matsim.contrib.drt.extension.operations.operationFacilities.OperationFacility;
+import org.matsim.contrib.dvrp.fleet.DvrpVehicle;
import java.util.Optional;
@@ -18,4 +19,6 @@ public interface DrtShiftSpecification extends Identifiable {
Optional getBreak();
Optional> getOperationFacilityId();
+
+ Optional> getDesignatedVehicleId();
}
diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/shift/DrtShiftSpecificationImpl.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/shift/DrtShiftSpecificationImpl.java
index fd5a36f2501..6e0bc88b0dc 100644
--- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/shift/DrtShiftSpecificationImpl.java
+++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/shift/DrtShiftSpecificationImpl.java
@@ -2,6 +2,7 @@
import org.matsim.api.core.v01.Id;
import org.matsim.contrib.drt.extension.operations.operationFacilities.OperationFacility;
+import org.matsim.contrib.dvrp.fleet.DvrpVehicle;
import java.util.Optional;
@@ -15,6 +16,7 @@ public class DrtShiftSpecificationImpl implements DrtShiftSpecification {
private final double end;
private final DrtShiftBreakSpecification shiftBreak;
private final Id operationFacilityId;
+ private final Id designatedVehicleId;
private DrtShiftSpecificationImpl(Builder builder) {
this.id = builder.id;
@@ -22,6 +24,7 @@ private DrtShiftSpecificationImpl(Builder builder) {
this.end = builder.end;
this.shiftBreak = builder.shiftBreak;
this.operationFacilityId = builder.operationFacilityId;
+ this.designatedVehicleId = builder.designatedVehicleId;
}
@Override
@@ -44,6 +47,11 @@ public Optional> getOperationFacilityId() {
return Optional.ofNullable(operationFacilityId);
}
+ @Override
+ public Optional> getDesignatedVehicleId() {
+ return Optional.ofNullable(designatedVehicleId);
+ }
+
@Override
public Id getId() {
return id;
@@ -69,6 +77,7 @@ public static final class Builder {
private double end;
private DrtShiftBreakSpecification shiftBreak;
private Id operationFacilityId;
+ public Id designatedVehicleId;
private Builder() {
}
@@ -97,6 +106,10 @@ public Builder operationFacility(Id operationFacilityId) {
this.operationFacilityId = operationFacilityId;
return this;
}
+ public Builder designatedVehicle(Id designatedVehicleId) {
+ this.designatedVehicleId = designatedVehicleId;
+ return this;
+ }
public DrtShiftSpecificationImpl build() {
return new DrtShiftSpecificationImpl(this);
diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/edrt/run/RunEDrtScenarioIT.java b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/edrt/run/RunEDrtScenarioIT.java
index 1d23eb2a1c4..8aaa6a7af7f 100644
--- a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/edrt/run/RunEDrtScenarioIT.java
+++ b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/edrt/run/RunEDrtScenarioIT.java
@@ -103,7 +103,9 @@ void testWithPrebooking() {
new OTFVisConfigGroup(), new EvConfigGroup());
DrtConfigGroup drtConfig = DrtConfigGroup.getSingleModeDrtConfig(config);
- drtConfig.addParameterSet(new PrebookingParams());
+ PrebookingParams prebookingParams = new PrebookingParams();
+ prebookingParams.abortRejectedPrebookings = false;
+ drtConfig.addParameterSet(prebookingParams);
Controler controller = RunEDrtScenario.createControler(config, false);
ProbabilityBasedPrebookingLogic.install(controller, drtConfig, 0.5, 4.0 * 3600.0);
diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/estimator/MultiModalDrtLegEstimatorTest.java b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/estimator/MultiModalDrtLegEstimatorTest.java
index f925ed604dd..d5e606ed980 100644
--- a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/estimator/MultiModalDrtLegEstimatorTest.java
+++ b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/estimator/MultiModalDrtLegEstimatorTest.java
@@ -5,7 +5,7 @@
import org.junit.jupiter.api.extension.RegisterExtension;
import org.matsim.application.MATSimApplication;
import org.matsim.contrib.drt.estimator.DrtEstimatorModule;
-import org.matsim.contrib.drt.estimator.impl.ConstantDrtEstimator;
+import org.matsim.contrib.drt.estimator.impl.ExampleDrtEstimator;
import org.matsim.contrib.drt.extension.DrtTestScenario;
import org.matsim.contrib.drt.extension.modechoice.MultiModalDrtLegEstimator;
import org.matsim.contrib.drt.run.DrtConfigGroup;
@@ -51,7 +51,7 @@ public void install() {
for (DrtConfigGroup el : drtConfig.getModalElements()) {
install(new DrtEstimatorModule(el.mode, el, el.getDrtEstimatorParams().get()));
- DrtEstimatorModule.bindEstimator(binder(), el.mode).toInstance(new ConstantDrtEstimator(1.05, 300));
+ DrtEstimatorModule.bindEstimator(binder(), el.mode).toInstance(new ExampleDrtEstimator(1.05, 300));
}
}
});
diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/operations/shifts/ShiftsIOTest.java b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/operations/shifts/ShiftsIOTest.java
index ff5eb57ecdc..ae00d55bd16 100644
--- a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/operations/shifts/ShiftsIOTest.java
+++ b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/operations/shifts/ShiftsIOTest.java
@@ -15,6 +15,7 @@
import org.matsim.contrib.drt.extension.operations.shifts.shift.DrtShiftSpecification;
import org.matsim.contrib.drt.extension.operations.shifts.shift.DrtShiftsSpecification;
import org.matsim.contrib.drt.extension.operations.shifts.shift.DrtShiftsSpecificationImpl;
+import org.matsim.contrib.dvrp.fleet.DvrpVehicle;
import org.matsim.testcases.MatsimTestUtils;
/**
@@ -35,6 +36,9 @@ public class ShiftsIOTest {
private final Id oid1 = Id.create("op1", OperationFacility.class);
private final Id oid2 = Id.create("op2", OperationFacility.class);
+ private final Id vehId1 = Id.create("drt1", DvrpVehicle.class);
+ private final Id vehId2 = Id.create("drt2", DvrpVehicle.class);
+
@Test
void testBasicReaderWriter() {
@@ -69,6 +73,7 @@ private void checkContent(DrtShiftsSpecification shiftsSpecification) {
assertEquals(45000., shiftSpecification1.getEndTime(), 0);
assertTrue(shiftSpecification1.getOperationFacilityId().isPresent());
assertEquals(oid1, shiftSpecification1.getOperationFacilityId().get());
+ assertEquals(vehId1, shiftSpecification1.getDesignatedVehicleId().get());
assertEquals(1800., shiftSpecification1.getBreak().orElseThrow().getDuration(), 0);
assertEquals(28800., shiftSpecification1.getBreak().orElseThrow().getEarliestBreakStartTime(), 0);
assertEquals(32400., shiftSpecification1.getBreak().orElseThrow().getLatestBreakEndTime(), 0);
@@ -80,6 +85,7 @@ private void checkContent(DrtShiftsSpecification shiftsSpecification) {
assertEquals(49000., shiftSpecification2.getEndTime(), 0);
assertTrue(shiftSpecification2.getOperationFacilityId().isPresent());
assertEquals(oid2, shiftSpecification2.getOperationFacilityId().get());
+ assertEquals(vehId2, shiftSpecification2.getDesignatedVehicleId().get());
assertEquals(3600., shiftSpecification2.getBreak().orElseThrow().getDuration(), 0);
assertEquals(29200., shiftSpecification2.getBreak().orElseThrow().getEarliestBreakStartTime(), 0);
assertEquals(32800., shiftSpecification2.getBreak().orElseThrow().getLatestBreakEndTime(), 0);
@@ -91,6 +97,7 @@ private void checkContent(DrtShiftsSpecification shiftsSpecification) {
assertEquals(53000., shiftSpecification3.getEndTime(), 0);
assertFalse(shiftSpecification3.getOperationFacilityId().isPresent());
assertEquals(Optional.empty(), shiftSpecification3.getOperationFacilityId());
+ assertEquals(Optional.empty(), shiftSpecification3.getDesignatedVehicleId());
assertTrue(shiftSpecification3.getBreak().isEmpty());
}
}
diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/operations/shifts/run/RunOnTheFlyShiftDrtScenarioIT.java b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/operations/shifts/run/RunOnTheFlyShiftDrtScenarioIT.java
new file mode 100644
index 00000000000..07c9a0b793b
--- /dev/null
+++ b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/operations/shifts/run/RunOnTheFlyShiftDrtScenarioIT.java
@@ -0,0 +1,211 @@
+package org.matsim.contrib.drt.extension.operations.shifts.run;
+
+import com.google.common.collect.ImmutableMap;
+import org.junit.jupiter.api.Test;
+import org.matsim.api.core.v01.Id;
+import org.matsim.api.core.v01.TransportMode;
+import org.matsim.contrib.common.zones.systems.grid.square.SquareGridZoneSystemParams;
+import org.matsim.contrib.drt.analysis.zonal.DrtZoneSystemParams;
+import org.matsim.contrib.drt.extension.DrtWithExtensionsConfigGroup;
+import org.matsim.contrib.drt.extension.operations.DrtOperationsControlerCreator;
+import org.matsim.contrib.drt.extension.operations.DrtOperationsParams;
+import org.matsim.contrib.drt.extension.operations.operationFacilities.OperationFacilitiesParams;
+import org.matsim.contrib.drt.extension.operations.shifts.config.ShiftsParams;
+import org.matsim.contrib.drt.extension.operations.shifts.dispatcher.DefaultShiftScheduler;
+import org.matsim.contrib.drt.extension.operations.shifts.dispatcher.ShiftScheduler;
+import org.matsim.contrib.drt.extension.operations.shifts.shift.*;
+import org.matsim.contrib.drt.fare.DrtFareParams;
+import org.matsim.contrib.drt.optimizer.constraints.DefaultDrtOptimizationConstraintsSet;
+import org.matsim.contrib.drt.optimizer.insertion.extensive.ExtensiveInsertionSearchParams;
+import org.matsim.contrib.drt.optimizer.rebalancing.RebalancingParams;
+import org.matsim.contrib.drt.optimizer.rebalancing.mincostflow.MinCostFlowRebalancingStrategyParams;
+import org.matsim.contrib.drt.run.DrtConfigGroup;
+import org.matsim.contrib.drt.run.MultiModeDrtConfigGroup;
+import org.matsim.contrib.dvrp.fleet.Fleet;
+import org.matsim.contrib.dvrp.run.AbstractDvrpModeModule;
+import org.matsim.contrib.dvrp.run.DvrpConfigGroup;
+import org.matsim.contrib.zone.skims.DvrpTravelTimeMatrixParams;
+import org.matsim.core.config.Config;
+import org.matsim.core.config.ConfigGroup;
+import org.matsim.core.config.ConfigUtils;
+import org.matsim.core.config.groups.QSimConfigGroup;
+import org.matsim.core.config.groups.ReplanningConfigGroup;
+import org.matsim.core.config.groups.ScoringConfigGroup;
+import org.matsim.core.controler.Controler;
+import org.matsim.core.controler.OutputDirectoryHierarchy;
+import org.matsim.core.controler.events.IterationStartsEvent;
+import org.matsim.core.controler.listener.IterationStartsListener;
+import org.matsim.examples.ExamplesUtils;
+
+import java.util.*;
+
+public class RunOnTheFlyShiftDrtScenarioIT {
+
+ @Test
+ void test() {
+
+ MultiModeDrtConfigGroup multiModeDrtConfigGroup = new MultiModeDrtConfigGroup(DrtWithExtensionsConfigGroup::new);
+
+ String fleetFile = "holzkirchenFleet.xml";
+ String plansFile = "holzkirchenPlans.xml.gz";
+ String networkFile = "holzkirchenNetwork.xml.gz";
+ String opFacilitiesFile = "holzkirchenOperationFacilities.xml";
+
+ DrtWithExtensionsConfigGroup drtWithShiftsConfigGroup = (DrtWithExtensionsConfigGroup) multiModeDrtConfigGroup.createParameterSet("drt");
+
+ drtWithShiftsConfigGroup.mode = TransportMode.drt;
+ DefaultDrtOptimizationConstraintsSet defaultConstraintsSet =
+ (DefaultDrtOptimizationConstraintsSet) drtWithShiftsConfigGroup.addOrGetDrtOptimizationConstraintsParams()
+ .addOrGetDefaultDrtOptimizationConstraintsSet();
+ drtWithShiftsConfigGroup.stopDuration = 30.;
+ defaultConstraintsSet.maxTravelTimeAlpha = 1.5;
+ defaultConstraintsSet.maxTravelTimeBeta = 10. * 60.;
+ defaultConstraintsSet.maxWaitTime = 600.;
+ defaultConstraintsSet.rejectRequestIfMaxWaitOrTravelTimeViolated = true;
+ defaultConstraintsSet.maxWalkDistance = 1000.;
+ drtWithShiftsConfigGroup.useModeFilteredSubnetwork = false;
+ drtWithShiftsConfigGroup.vehiclesFile = fleetFile;
+ drtWithShiftsConfigGroup.operationalScheme = DrtConfigGroup.OperationalScheme.door2door;
+ drtWithShiftsConfigGroup.plotDetailedCustomerStats = true;
+ drtWithShiftsConfigGroup.idleVehiclesReturnToDepots = false;
+
+ drtWithShiftsConfigGroup.addParameterSet(new ExtensiveInsertionSearchParams());
+
+ ConfigGroup rebalancing = drtWithShiftsConfigGroup.createParameterSet("rebalancing");
+ drtWithShiftsConfigGroup.addParameterSet(rebalancing);
+ ((RebalancingParams) rebalancing).interval = 600;
+
+ MinCostFlowRebalancingStrategyParams strategyParams = new MinCostFlowRebalancingStrategyParams();
+ strategyParams.targetAlpha = 0.3;
+ strategyParams.targetBeta = 0.3;
+
+ drtWithShiftsConfigGroup.getRebalancingParams().get().addParameterSet(strategyParams);
+
+ DrtZoneSystemParams drtZoneSystemParams = new DrtZoneSystemParams();
+ SquareGridZoneSystemParams zoneParams = (SquareGridZoneSystemParams) drtZoneSystemParams.createParameterSet(SquareGridZoneSystemParams.SET_NAME);
+ zoneParams.cellSize = 500.;
+ drtZoneSystemParams.addParameterSet(zoneParams);
+ drtZoneSystemParams.targetLinkSelection = DrtZoneSystemParams.TargetLinkSelection.mostCentral;
+ drtWithShiftsConfigGroup.addParameterSet(drtZoneSystemParams);
+
+ multiModeDrtConfigGroup.addParameterSet(drtWithShiftsConfigGroup);
+
+ DvrpConfigGroup dvrpConfigGroup = new DvrpConfigGroup();
+ DvrpTravelTimeMatrixParams matrixParams = dvrpConfigGroup.getTravelTimeMatrixParams();
+ matrixParams.addParameterSet(matrixParams.createParameterSet(SquareGridZoneSystemParams.SET_NAME));
+
+ final Config config = ConfigUtils.createConfig(multiModeDrtConfigGroup,
+ dvrpConfigGroup);
+ config.setContext(ExamplesUtils.getTestScenarioURL("holzkirchen"));
+
+ Set modes = new HashSet<>();
+ modes.add("drt");
+ config.travelTimeCalculator().setAnalyzedModes(modes);
+
+ ScoringConfigGroup.ModeParams scoreParams = new ScoringConfigGroup.ModeParams("drt");
+ config.scoring().addModeParams(scoreParams);
+ ScoringConfigGroup.ModeParams scoreParams2 = new ScoringConfigGroup.ModeParams("walk");
+ config.scoring().addModeParams(scoreParams2);
+
+ config.plans().setInputFile(plansFile);
+ config.network().setInputFile(networkFile);
+
+ config.qsim().setSimStarttimeInterpretation(QSimConfigGroup.StarttimeInterpretation.onlyUseStarttime);
+ config.qsim().setSimEndtimeInterpretation(QSimConfigGroup.EndtimeInterpretation.minOfEndtimeAndMobsimFinished);
+
+ final ScoringConfigGroup.ActivityParams home = new ScoringConfigGroup.ActivityParams("home");
+ home.setTypicalDuration(8 * 3600);
+ final ScoringConfigGroup.ActivityParams other = new ScoringConfigGroup.ActivityParams("other");
+ other.setTypicalDuration(4 * 3600);
+ final ScoringConfigGroup.ActivityParams education = new ScoringConfigGroup.ActivityParams("education");
+ education.setTypicalDuration(6 * 3600);
+ final ScoringConfigGroup.ActivityParams shopping = new ScoringConfigGroup.ActivityParams("shopping");
+ shopping.setTypicalDuration(2 * 3600);
+ final ScoringConfigGroup.ActivityParams work = new ScoringConfigGroup.ActivityParams("work");
+ work.setTypicalDuration(2 * 3600);
+
+ config.scoring().addActivityParams(home);
+ config.scoring().addActivityParams(other);
+ config.scoring().addActivityParams(education);
+ config.scoring().addActivityParams(shopping);
+ config.scoring().addActivityParams(work);
+
+ final ReplanningConfigGroup.StrategySettings stratSets = new ReplanningConfigGroup.StrategySettings();
+ stratSets.setWeight(1);
+ stratSets.setStrategyName("ChangeExpBeta");
+ config.replanning().addStrategySettings(stratSets);
+
+ config.controller().setLastIteration(1);
+ config.controller().setWriteEventsInterval(1);
+
+ config.controller().setOverwriteFileSetting(OutputDirectoryHierarchy.OverwriteFileSetting.deleteDirectoryIfExists);
+ config.controller().setOutputDirectory("test/output/holzkirchen_shifts");
+
+ DrtOperationsParams operationsParams = (DrtOperationsParams) drtWithShiftsConfigGroup.createParameterSet(DrtOperationsParams.SET_NAME);
+ ShiftsParams shiftsParams = (ShiftsParams) operationsParams.createParameterSet(ShiftsParams.SET_NAME);
+ OperationFacilitiesParams operationFacilitiesParams = (OperationFacilitiesParams) operationsParams.createParameterSet(OperationFacilitiesParams.SET_NAME);
+ operationsParams.addParameterSet(shiftsParams);
+ operationsParams.addParameterSet(operationFacilitiesParams);
+
+ operationFacilitiesParams.operationFacilityInputFile = opFacilitiesFile;
+ shiftsParams.allowInFieldChangeover = true;
+ drtWithShiftsConfigGroup.addParameterSet(operationsParams);
+
+ DrtFareParams drtFareParams = new DrtFareParams();
+ drtFareParams.baseFare = 1.;
+ drtFareParams.distanceFare_m = 1. / 1000;
+ drtWithShiftsConfigGroup.addParameterSet(drtFareParams);
+
+ final Controler run = DrtOperationsControlerCreator.createControler(config, false);
+
+ run.addOverridingModule(new AbstractDvrpModeModule(drtWithShiftsConfigGroup.getMode()) {
+ @Override
+ public void install() {
+ this.bindModal(OnTheFlyScheduler.class).toProvider(modalProvider(getter ->
+ new OnTheFlyScheduler())).asEagerSingleton();
+ this.bindModal(ShiftScheduler.class).toProvider(modalProvider( getter -> getter.getModal(OnTheFlyScheduler.class)));
+ this.addControlerListenerBinding().toProvider(modalProvider( getter -> getter.getModal(OnTheFlyScheduler.class)));
+ }
+ });
+
+ run.run();
+ }
+
+ private static class OnTheFlyScheduler implements ShiftScheduler, IterationStartsListener {
+
+
+ private DefaultShiftScheduler delegate = new DefaultShiftScheduler(new DrtShiftsSpecificationImpl());
+ private int iteration;
+
+ @Override
+ public DrtShiftsSpecification get() {
+ return delegate.get();
+ }
+
+ @Override
+ public List schedule(double time, Fleet fleet) {
+ List shifts = new ArrayList<>();
+ if (time > 4 * 3600 && time < 15 * 3600 && time % 3600 == 0) {
+ for (int i = 0; i < iteration + 1 ; i++) {
+ DrtShiftSpecificationImpl shift = DrtShiftSpecificationImpl.newBuilder()
+ .id(Id.create(time + "_" + i, DrtShift.class))
+ .start(time + 3600).end(time + 9 * 3600).build();
+ shifts.add(shift);
+ delegate.get().addShiftSpecification(shift);
+ }
+ }
+ return shifts.stream().map(DefaultShiftScheduler.createShiftFromSpec).toList();
+ }
+
+ @Override
+ public ImmutableMap, DrtShift> initialSchedule() {
+ delegate = new DefaultShiftScheduler(new DrtShiftsSpecificationImpl());
+ return delegate.initialSchedule();
+ }
+
+ @Override
+ public void notifyIterationStarts(IterationStartsEvent event) {
+ iteration = event.getIteration();
+ }
+ }
+}
diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/operations/shifts/run/RunPrebookingShiftDrtScenarioIT.java b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/operations/shifts/run/RunPrebookingShiftDrtScenarioIT.java
index 5babef611b3..01f5e27b837 100644
--- a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/operations/shifts/run/RunPrebookingShiftDrtScenarioIT.java
+++ b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/operations/shifts/run/RunPrebookingShiftDrtScenarioIT.java
@@ -1,5 +1,8 @@
package org.matsim.contrib.drt.extension.operations.shifts.run;
+import com.google.common.collect.HashMultiset;
+import com.google.common.collect.Multiset;
+import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.matsim.api.core.v01.Coord;
@@ -16,6 +19,8 @@
import org.matsim.contrib.drt.extension.operations.DrtOperationsParams;
import org.matsim.contrib.drt.extension.operations.operationFacilities.*;
import org.matsim.contrib.drt.extension.operations.shifts.config.ShiftsParams;
+import org.matsim.contrib.drt.extension.operations.shifts.dispatcher.DefaultShiftScheduler;
+import org.matsim.contrib.drt.extension.operations.shifts.dispatcher.ShiftScheduler;
import org.matsim.contrib.drt.extension.operations.shifts.shift.*;
import org.matsim.contrib.drt.optimizer.constraints.DefaultDrtOptimizationConstraintsSet;
import org.matsim.contrib.drt.optimizer.insertion.extensive.ExtensiveInsertionSearchParams;
@@ -32,6 +37,8 @@
import org.matsim.contrib.dvrp.fleet.FleetSpecificationImpl;
import org.matsim.contrib.dvrp.fleet.ImmutableDvrpVehicleSpecification;
import org.matsim.contrib.dvrp.passenger.PassengerRequestRejectedEventHandler;
+import org.matsim.contrib.dvrp.passenger.PassengerRequestScheduledEventHandler;
+import org.matsim.contrib.dvrp.passenger.PassengerRequestSubmittedEventHandler;
import org.matsim.contrib.dvrp.run.AbstractDvrpModeModule;
import org.matsim.contrib.dvrp.run.DvrpConfigGroup;
import org.matsim.contrib.zone.skims.DvrpTravelTimeMatrixParams;
@@ -60,11 +67,115 @@ public class RunPrebookingShiftDrtScenarioIT {
@Test
- void test() {
+ void testWithReattempts() {
MultiModeDrtConfigGroup multiModeDrtConfigGroup = new MultiModeDrtConfigGroup(DrtWithExtensionsConfigGroup::new);
+ DrtWithExtensionsConfigGroup drtWithShiftsConfigGroup = (DrtWithExtensionsConfigGroup) multiModeDrtConfigGroup.createParameterSet("drt");
+ final Controler run = prepare(drtWithShiftsConfigGroup, multiModeDrtConfigGroup);
+
+ Multiset> submittedPersons = HashMultiset.create();
+ Multiset> scheduledPersons = HashMultiset.create();
+ Multiset> rejectedPersons = HashMultiset.create();
+
+ run.addOverridingModule(new AbstractModule() {
+ @Override
+ public void install() {
+ addEventHandlerBinding().toInstance((PassengerRequestSubmittedEventHandler) event -> submittedPersons.addAll(event.getPersonIds()));
+ addEventHandlerBinding().toInstance((PassengerRequestScheduledEventHandler) event -> scheduledPersons.addAll(event.getPersonIds()));
+ addEventHandlerBinding().toInstance((PassengerRequestRejectedEventHandler) event -> rejectedPersons.addAll(event.getPersonIds()));
+ }
+ });
+
+ PrebookingParams prebookingParams = new PrebookingParams();
+ prebookingParams.maximumPassengerDelay = 600;
+ prebookingParams.unschedulingMode = PrebookingParams.UnschedulingMode.Routing;
+ prebookingParams.scheduleWaitBeforeDrive = true;
+ prebookingParams.abortRejectedPrebookings = false;
+ drtWithShiftsConfigGroup.addParameterSet(prebookingParams);
+
+ run.addOverridingQSimModule(new PrebookingModeQSimModule(drtWithShiftsConfigGroup.getMode(),
+ prebookingParams));
+
+ run.run();
+
+ Assertions.assertEquals(1, submittedPersons.count(Id.createPersonId(1)));
+ Assertions.assertEquals(2, submittedPersons.count(Id.createPersonId(2)));
+ Assertions.assertEquals(1, submittedPersons.count(Id.createPersonId(3)));
+ Assertions.assertEquals(2, submittedPersons.count(Id.createPersonId(4)));
+ Assertions.assertEquals(1, submittedPersons.count(Id.createPersonId(5)));
+ Assertions.assertEquals(2, submittedPersons.count(Id.createPersonId(6)));
+
+ Assertions.assertEquals(1, scheduledPersons.count(Id.createPersonId(1)));
+ Assertions.assertEquals(1, scheduledPersons.count(Id.createPersonId(2)));
+ Assertions.assertEquals(1, scheduledPersons.count(Id.createPersonId(3)));
+ Assertions.assertEquals(1, scheduledPersons.count(Id.createPersonId(4)));
+ Assertions.assertEquals(1, scheduledPersons.count(Id.createPersonId(5)));
+ Assertions.assertEquals(0, scheduledPersons.count(Id.createPersonId(6)));
+
+ Assertions.assertEquals(0, rejectedPersons.count(Id.createPersonId(1)));
+ Assertions.assertEquals(1, rejectedPersons.count(Id.createPersonId(2)));
+ Assertions.assertEquals(0, rejectedPersons.count(Id.createPersonId(3)));
+ Assertions.assertEquals(1, rejectedPersons.count(Id.createPersonId(4)));
+ Assertions.assertEquals(0, rejectedPersons.count(Id.createPersonId(5)));
+ Assertions.assertEquals(2, rejectedPersons.count(Id.createPersonId(6)));
+ }
+ @Test
+ void testWithoutReattempts() {
+
+ MultiModeDrtConfigGroup multiModeDrtConfigGroup = new MultiModeDrtConfigGroup(DrtWithExtensionsConfigGroup::new);
DrtWithExtensionsConfigGroup drtWithShiftsConfigGroup = (DrtWithExtensionsConfigGroup) multiModeDrtConfigGroup.createParameterSet("drt");
+ final Controler run = prepare(drtWithShiftsConfigGroup, multiModeDrtConfigGroup);
+
+ Multiset> submittedPersons = HashMultiset.create();
+ Multiset> scheduledPersons = HashMultiset.create();
+ Multiset> rejectedPersons = HashMultiset.create();
+
+ run.addOverridingModule(new AbstractModule() {
+ @Override
+ public void install() {
+ addEventHandlerBinding().toInstance((PassengerRequestSubmittedEventHandler) event -> submittedPersons.addAll(event.getPersonIds()));
+ addEventHandlerBinding().toInstance((PassengerRequestScheduledEventHandler) event -> scheduledPersons.addAll(event.getPersonIds()));
+ addEventHandlerBinding().toInstance((PassengerRequestRejectedEventHandler) event -> rejectedPersons.addAll(event.getPersonIds()));
+ }
+ });
+
+ PrebookingParams prebookingParams = new PrebookingParams();
+ prebookingParams.maximumPassengerDelay = 600;
+ prebookingParams.unschedulingMode = PrebookingParams.UnschedulingMode.Routing;
+ prebookingParams.scheduleWaitBeforeDrive = true;
+ prebookingParams.abortRejectedPrebookings = true;
+ drtWithShiftsConfigGroup.addParameterSet(prebookingParams);
+
+ run.addOverridingQSimModule(new PrebookingModeQSimModule(drtWithShiftsConfigGroup.getMode(),
+ prebookingParams));
+
+ run.run();
+
+ Assertions.assertEquals(1, submittedPersons.count(Id.createPersonId(1)));
+ Assertions.assertEquals(1, submittedPersons.count(Id.createPersonId(2)));
+ Assertions.assertEquals(1, submittedPersons.count(Id.createPersonId(3)));
+ Assertions.assertEquals(1, submittedPersons.count(Id.createPersonId(4)));
+ Assertions.assertEquals(1, submittedPersons.count(Id.createPersonId(5)));
+ Assertions.assertEquals(1, submittedPersons.count(Id.createPersonId(6)));
+
+ Assertions.assertEquals(1, scheduledPersons.count(Id.createPersonId(1)));
+ Assertions.assertEquals(0, scheduledPersons.count(Id.createPersonId(2)));
+ Assertions.assertEquals(1, scheduledPersons.count(Id.createPersonId(3)));
+ Assertions.assertEquals(0, scheduledPersons.count(Id.createPersonId(4)));
+ Assertions.assertEquals(1, scheduledPersons.count(Id.createPersonId(5)));
+ Assertions.assertEquals(0, scheduledPersons.count(Id.createPersonId(6)));
+
+ Assertions.assertEquals(0, rejectedPersons.count(Id.createPersonId(1)));
+ Assertions.assertEquals(1, rejectedPersons.count(Id.createPersonId(2)));
+ Assertions.assertEquals(0, rejectedPersons.count(Id.createPersonId(3)));
+ Assertions.assertEquals(1, rejectedPersons.count(Id.createPersonId(4)));
+ Assertions.assertEquals(0, rejectedPersons.count(Id.createPersonId(5)));
+ Assertions.assertEquals(1, rejectedPersons.count(Id.createPersonId(6)));
+ }
+
+ @NotNull
+ private Controler prepare(DrtWithExtensionsConfigGroup drtWithShiftsConfigGroup, MultiModeDrtConfigGroup multiModeDrtConfigGroup) {
drtWithShiftsConfigGroup.mode = TransportMode.drt;
DefaultDrtOptimizationConstraintsSet defaultConstraintsSet =
(DefaultDrtOptimizationConstraintsSet) drtWithShiftsConfigGroup.addOrGetDrtOptimizationConstraintsParams()
@@ -146,11 +257,6 @@ void test() {
shiftsParams.shiftEndLookAhead = 900.;
drtWithShiftsConfigGroup.addParameterSet(operationsParams);
- PrebookingParams prebookingParams = new PrebookingParams();
- prebookingParams.maximumPassengerDelay = 600;
- prebookingParams.unschedulingMode = PrebookingParams.UnschedulingMode.Routing;
- prebookingParams.scheduleWaitBeforeDrive = true;
- drtWithShiftsConfigGroup.addParameterSet(prebookingParams);
Scenario scenario = DrtControlerCreator.createScenarioWithDrtRouteFactory(config);
prepareNetwork(scenario);
@@ -159,27 +265,9 @@ void test() {
final Controler run = DrtOperationsControlerCreator.createControler(config, scenario, false);
prepareOperations(run, drtWithShiftsConfigGroup);
- run.addOverridingQSimModule(new PrebookingModeQSimModule(drtWithShiftsConfigGroup.getMode(),
- prebookingParams));
- AttributeBasedPrebookingLogic.install(run, drtWithShiftsConfigGroup);
-
- Set> rejectedPersons = new HashSet<>();
- run.addOverridingModule(new AbstractModule() {
- @Override
- public void install() {
- addEventHandlerBinding().toInstance((PassengerRequestRejectedEventHandler) event -> rejectedPersons.addAll(event.getPersonIds()));
- }
- });
-
- run.run();
-
- Assertions.assertFalse(rejectedPersons.contains(Id.createPersonId(1)));
- Assertions.assertTrue(rejectedPersons.contains(Id.createPersonId(2)));
- Assertions.assertFalse(rejectedPersons.contains(Id.createPersonId(3)));
- Assertions.assertTrue(rejectedPersons.contains(Id.createPersonId(4)));
- Assertions.assertFalse(rejectedPersons.contains(Id.createPersonId(5)));
- Assertions.assertTrue(rejectedPersons.contains(Id.createPersonId(6)));
+ AttributeBasedPrebookingLogic.install(run, drtWithShiftsConfigGroup);
+ return run;
}
private void preparePopulation(Scenario scenario) {
@@ -208,7 +296,7 @@ private void preparePopulation(Scenario scenario) {
Activity start = factory.createActivityFromLinkId("start", Id.createLinkId(1));
start.setEndTime(5000);
start.getAttributes().putAttribute("prebooking:submissionTime" + "drt", 900.);
- start.getAttributes().putAttribute("prebooking:plannedDepartureTime" + "drt", 5000.);
+ start.getAttributes().putAttribute("prebooking:plannedDepartureTime" + "drt", 5005.);
plan.addActivity(start);
plan.addLeg(factory.createLeg("drt"));
plan.addActivity(factory.createActivityFromLinkId("end", Id.createLinkId(2)));
@@ -311,7 +399,7 @@ private static void prepareOperations(Controler run, DrtWithExtensionsConfigGrou
public void install() {
bindModal(FleetSpecification.class).toInstance(fleetSpecification);
bindModal(OperationFacilitiesSpecification.class).toInstance(opFasSpecification);
- bindModal(DrtShiftsSpecification.class).toInstance(shiftsSpecification);
+ bindModal(ShiftScheduler.class).toProvider(modalProvider(getter -> new DefaultShiftScheduler(shiftsSpecification)));
}
});
diff --git a/contribs/drt-extensions/test/input/org/matsim/contrib/drt/extension/operations/shifts/testShifts.xml b/contribs/drt-extensions/test/input/org/matsim/contrib/drt/extension/operations/shifts/testShifts.xml
index 2cb87bd3c9f..972a28788af 100644
--- a/contribs/drt-extensions/test/input/org/matsim/contrib/drt/extension/operations/shifts/testShifts.xml
+++ b/contribs/drt-extensions/test/input/org/matsim/contrib/drt/extension/operations/shifts/testShifts.xml
@@ -1,8 +1,8 @@
-
+
-
+
diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/DrtEventSequenceCollector.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/DrtEventSequenceCollector.java
index b8b095cd1dc..90836e785cc 100644
--- a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/DrtEventSequenceCollector.java
+++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/DrtEventSequenceCollector.java
@@ -159,7 +159,7 @@ public List getDrtFares() {
}
public boolean isCompleted() {
- return personEvents.values().stream().allMatch(pe -> pe.droppedOff != null);
+ return submitted.getPersonIds().stream().allMatch(personId -> personEvents.get(personId).droppedOff != null);
}
}
diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/DetourBasedDrtEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/DetourBasedDrtEstimator.java
deleted file mode 100644
index e85e5595930..00000000000
--- a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/DetourBasedDrtEstimator.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package org.matsim.contrib.drt.estimator.impl;
-
-import org.matsim.contrib.drt.estimator.DrtEstimator;
-import org.matsim.contrib.drt.routing.DrtRoute;
-import org.matsim.core.utils.misc.OptionalTime;
-
-import java.util.Random;
-
-/**
- * A simple DRT estimator that uses normal distributions to estimate the ride time, wait time, ride distance and acceptance.
- */
-public final class DetourBasedDrtEstimator implements DrtEstimator {
-
- private final NormalDistributionGenerator distributionGenerator;
-
- private DetourBasedDrtEstimator(double estRideTimeAlpha, double estRideTimeBeta, double rideTimeStd, double estMeanWaitTime,
- double waitTimeStd) {
- this.distributionGenerator = new NormalDistributionGenerator(estRideTimeAlpha, estRideTimeBeta, rideTimeStd, estMeanWaitTime, waitTimeStd);
- }
-
- public static DetourBasedDrtEstimator normalDistributed(double estRideTimeAlpha, double estRideTimeBeta, double rideTimeStd, double estMeanWaitTime,
- double waitTimeStd) {
- return new DetourBasedDrtEstimator(estRideTimeAlpha, estRideTimeBeta, rideTimeStd, estMeanWaitTime, waitTimeStd);
- }
-
- @Override
- public Estimate estimate(DrtRoute route, OptionalTime departureTime) {
- double directRideTIme = route.getDirectRideTime();
- double directDistance = route.getDistance();
- double waitTime = distributionGenerator.generateWaitTime();
- double rideTime = distributionGenerator.generateRideTime(directRideTIme);
- double rideDistance = distributionGenerator.generateRideDistance(rideTime, directRideTIme, directDistance);
- double acceptanceRate = distributionGenerator.generateAcceptanceRate();
-
- return new Estimate(rideDistance, waitTime + rideTime, waitTime, acceptanceRate);
- }
-
- private static class NormalDistributionGenerator {
- private final Random random = new Random(4711);
- private final double estRideTimeAlpha;
- private final double estRideTimeBeta;
- private final double rideTimeStd;
- private final double estMeanWaitTime;
- private final double waitTimeStd;
-
- public NormalDistributionGenerator(double estRideTimeAlpha, double estRideTimeBeta, double rideTimeStd, double estMeanWaitTime,
- double waitTimeStd) {
- this.estRideTimeAlpha = estRideTimeAlpha;
- this.estRideTimeBeta = estRideTimeBeta;
- this.rideTimeStd = rideTimeStd;
- this.estMeanWaitTime = estMeanWaitTime;
- this.waitTimeStd = waitTimeStd;
- }
-
- public double generateRideTime(double directRideTime) {
- // TODO improve this distribution
- double estMeanRideTime = estRideTimeAlpha * directRideTime + estRideTimeBeta;
- return Math.max(directRideTime, estMeanRideTime * (1 + random.nextGaussian() * rideTimeStd));
- }
-
- public double generateRideDistance(double estRideTime, double directRideTime, double directRideDistance) {
- // TODO Currently, same ratio is used as in the ride time estimation; improve this distribution
- double ratio = estRideTime / directRideTime;
- return ratio * directRideDistance;
- }
-
- public double generateWaitTime() {
- // TODO improve this distribution
- return Math.max(estMeanWaitTime * (1 + random.nextGaussian() * waitTimeStd), 0);
- }
-
- public double generateAcceptanceRate() {
- return 1;
- }
- }
-}
diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/DirectTripBasedDrtEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/DirectTripBasedDrtEstimator.java
new file mode 100644
index 00000000000..08ae52d5a0a
--- /dev/null
+++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/DirectTripBasedDrtEstimator.java
@@ -0,0 +1,130 @@
+package org.matsim.contrib.drt.estimator.impl;
+
+import org.checkerframework.checker.units.qual.C;
+import org.matsim.api.core.v01.Id;
+import org.matsim.api.core.v01.network.Link;
+import org.matsim.contrib.drt.estimator.DrtEstimator;
+import org.matsim.contrib.drt.estimator.impl.distribution.DistributionGenerator;
+import org.matsim.contrib.drt.estimator.impl.distribution.LogNormalDistributionGenerator;
+import org.matsim.contrib.drt.estimator.impl.distribution.NoDistribution;
+import org.matsim.contrib.drt.estimator.impl.distribution.NormalDistributionGenerator;
+import org.matsim.contrib.drt.estimator.impl.trip_estimation.ConstantRideDurationEstimator;
+import org.matsim.contrib.drt.estimator.impl.trip_estimation.RideDurationEstimator;
+import org.matsim.contrib.drt.estimator.impl.waiting_time_estimation.ConstantWaitingTimeEstimator;
+import org.matsim.contrib.drt.estimator.impl.waiting_time_estimation.WaitingTimeEstimator;
+import org.matsim.contrib.drt.routing.DrtRoute;
+import org.matsim.core.utils.misc.OptionalTime;
+
+/**
+ * DRT estimator that uses available data (e.g., real-world operational data, simulation-based data) to provide estimated data for DRT trips.
+ */
+public final class DirectTripBasedDrtEstimator implements DrtEstimator {
+ private final RideDurationEstimator rideDurationEstimator;
+ private final WaitingTimeEstimator waitingTimeEstimator;
+ private final DistributionGenerator waitingTimeDistributionGenerator;
+ private final DistributionGenerator rideTimeDistributionGenerator;
+
+ public static class Builder {
+ // Initialize with default estimation
+ private RideDurationEstimator rideDurationEstimator = new ConstantRideDurationEstimator(1.25, 300);
+ private WaitingTimeEstimator waitingTimeEstimator = new ConstantWaitingTimeEstimator(300);
+ private DistributionGenerator waitingTimeDistributionGenerator = new NoDistribution();
+ private DistributionGenerator rideTimeDistributionGenerator = new NoDistribution();
+
+ public Builder setRideDurationEstimator(RideDurationEstimator rideDurationEstimator) {
+ this.rideDurationEstimator = rideDurationEstimator;
+ return this;
+ }
+
+ public Builder setWaitingTimeEstimator(WaitingTimeEstimator waitingTimeEstimator) {
+ this.waitingTimeEstimator = waitingTimeEstimator;
+ return this;
+ }
+
+ public Builder setRideDurationDistributionGenerator(DistributionGenerator rideTimeDistributionGenerator) {
+ this.rideTimeDistributionGenerator = rideTimeDistributionGenerator;
+ return this;
+ }
+
+ public Builder setWaitingTimeDistributionGenerator(DistributionGenerator waitingTimeDistributionGenerator) {
+ this.waitingTimeDistributionGenerator = waitingTimeDistributionGenerator;
+ return this;
+ }
+
+ public DirectTripBasedDrtEstimator build() {
+ return new DirectTripBasedDrtEstimator(rideDurationEstimator, waitingTimeEstimator, rideTimeDistributionGenerator, waitingTimeDistributionGenerator);
+ }
+
+ }
+
+ public DirectTripBasedDrtEstimator(RideDurationEstimator rideDurationEstimator, WaitingTimeEstimator waitingTimeEstimator,
+ DistributionGenerator rideTimeDistribution, DistributionGenerator waitTimeDistribution) {
+ this.rideDurationEstimator = rideDurationEstimator;
+ this.waitingTimeEstimator = waitingTimeEstimator;
+ this.rideTimeDistributionGenerator = rideTimeDistribution;
+ this.waitingTimeDistributionGenerator = waitTimeDistribution;
+ }
+
+ /**
+ * Example DRT estimator based on the normal distributed ride time and waiting time
+ * @param estRideTimeAlpha typical ride duration = alpha * direct ride time + beta, alpha is specified here
+ * @param estRideTimeBeta typical ride duration = alpha * direct ride time + beta, beta is specified here
+ * @param rideTimeStd standard deviation of ride duration (normalized to 1)
+ * @param estMeanWaitTime estimated waiting time (i.e., mean wait time)
+ * @param waitTimeStd standard deviation of waiting time (normalized to 1)
+ * @return NetworkBasedDrtEstimator
+ */
+ public static DirectTripBasedDrtEstimator normalDistributedNetworkBasedDrtEstimator(double estRideTimeAlpha, double estRideTimeBeta,
+ double rideTimeStd, double estMeanWaitTime,
+ double waitTimeStd) {
+ return new Builder()
+ .setWaitingTimeEstimator(new ConstantWaitingTimeEstimator(estMeanWaitTime))
+ .setRideDurationEstimator(new ConstantRideDurationEstimator(estRideTimeAlpha, estRideTimeBeta))
+ .setWaitingTimeDistributionGenerator(new NormalDistributionGenerator(1, waitTimeStd))
+ .setRideDurationDistributionGenerator(new NormalDistributionGenerator(2, rideTimeStd))
+ .build();
+ }
+
+ /**
+ * Example DRT estimator based on the log-normal distributed ride time and normal distributed waiting time
+ * @param estRideTimeAlpha typical ride duration = alpha * direct ride time + beta, alpha is specified here
+ * @param estRideTimeBeta typical ride duration = alpha * direct ride time + beta, beta is specified here
+ * @param mu log-normal distribution parameter for ride duration (normalized to typical ride duration)
+ * @param sigma log-normal distribution parameter for ride duration (normalized to typical ride duration)
+ * @param estMeanWaitTime estimated waiting time (i.e., mean wait time)
+ * @param waitTimeStd standard deviation of waiting time (normalized to 1)
+ * @return NetworkBasedDrtEstimator
+ */
+ public static DirectTripBasedDrtEstimator mixDistributedNetworkBasedDrtEstimator(double estRideTimeAlpha, double estRideTimeBeta,
+ double mu, double sigma, double estMeanWaitTime,
+ double waitTimeStd) {
+ return new Builder()
+ .setWaitingTimeEstimator(new ConstantWaitingTimeEstimator(estMeanWaitTime))
+ .setRideDurationEstimator(new ConstantRideDurationEstimator(estRideTimeAlpha, estRideTimeBeta))
+ .setWaitingTimeDistributionGenerator(new NormalDistributionGenerator(1, waitTimeStd))
+ .setRideDurationDistributionGenerator(new LogNormalDistributionGenerator(2, mu, sigma))
+ .build();
+ }
+
+ @Override
+ public Estimate estimate(DrtRoute route, OptionalTime departureTime) {
+ double directRideTIme = route.getDirectRideTime();
+ double directDistance = route.getDistance();
+ Id fromLinkId = route.getStartLinkId();
+ Id toLinkId = route.getEndLinkId();
+ double typicalRideDuration = rideDurationEstimator.getEstimatedRideDuration(fromLinkId, toLinkId, departureTime, directRideTIme);
+ double typicalRideDistance = (typicalRideDuration / directRideTIme) * directDistance;
+ double typicalWaitingTime = waitingTimeEstimator.estimateWaitTime(fromLinkId, toLinkId, departureTime);
+
+ double estimatedWaitingTime = typicalWaitingTime * waitingTimeDistributionGenerator.generateRandomValue();
+
+ double detourRandomFactor = rideTimeDistributionGenerator.generateRandomValue();
+ double estimatedRideDuration = detourRandomFactor * typicalRideDuration;
+ double estimatedRideDistance = detourRandomFactor * typicalRideDistance;
+
+ double acceptanceRate = 1.0;
+
+ return new Estimate(estimatedRideDistance, estimatedRideDuration, estimatedWaitingTime, acceptanceRate);
+ }
+
+}
diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/EuclideanDistanceBasedDrtEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/EuclideanDistanceBasedDrtEstimator.java
index dd3a2492ce9..8b617888084 100644
--- a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/EuclideanDistanceBasedDrtEstimator.java
+++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/EuclideanDistanceBasedDrtEstimator.java
@@ -3,12 +3,18 @@
import org.matsim.api.core.v01.Coord;
import org.matsim.api.core.v01.network.Network;
import org.matsim.contrib.drt.estimator.DrtEstimator;
+import org.matsim.contrib.drt.estimator.impl.distribution.DistributionGenerator;
+import org.matsim.contrib.drt.estimator.impl.distribution.LogNormalDistributionGenerator;
+import org.matsim.contrib.drt.estimator.impl.distribution.NormalDistributionGenerator;
+import org.matsim.contrib.drt.estimator.impl.trip_estimation.ConstantRideDurationEstimator;
+import org.matsim.contrib.drt.estimator.impl.trip_estimation.RideDurationEstimator;
+import org.matsim.contrib.drt.estimator.impl.waiting_time_estimation.ConstantWaitingTimeEstimator;
+import org.matsim.contrib.drt.estimator.impl.waiting_time_estimation.WaitingTimeEstimator;
import org.matsim.contrib.drt.routing.DrtRoute;
+import org.matsim.core.utils.collections.Tuple;
import org.matsim.core.utils.geometry.CoordUtils;
import org.matsim.core.utils.misc.OptionalTime;
-import java.util.Random;
-
public class EuclideanDistanceBasedDrtEstimator implements DrtEstimator {
private final Network network;
/**
@@ -16,26 +22,16 @@ public class EuclideanDistanceBasedDrtEstimator implements DrtEstimator {
* Estimated network distance = Euclidean distance * network distance factor
*/
private final double networkDistanceFactor;
- /**
- * Slope of the linear regression
- */
- private final double slope;
- /**
- * Intercept of the linear regression
- */
- private final double intercept;
-
- private final double estimatedMeanWaitTime;
-
- private final double waitTimeStd;
+ private final RideDurationEstimator rideDurationEstimator;
+ private final WaitingTimeEstimator waitingTimeEstimator;
+ private final DistributionGenerator rideDurationDistributionGenerator;
+ private final DistributionGenerator waitingTimeDistributionGenerator;
- private final double mu;
- private final double sigma;
- private final Random random = new Random(1234);
/**
* We use log normal distribution to estimate the ride duration of each individual trip. The distribution
* is based on the linear regression.
+ *
* @params networkDistanceFactor: Estimated network distance = Euclidean distance * network distance factor
* @params slope: slope for the linear regression
* @params intercept: intercept for linear regression
@@ -47,12 +43,21 @@ public EuclideanDistanceBasedDrtEstimator(Network network, double networkDistanc
double mu, double sigma) {
this.network = network;
this.networkDistanceFactor = networkDistanceFactor;
- this.slope = slope;
- this.intercept = intercept;
- this.estimatedMeanWaitTime = estimatedMeanWaitTime;
- this.waitTimeStd = waitTimeStd;
- this.mu = mu;
- this.sigma = sigma;
+ this.rideDurationEstimator = new ConstantRideDurationEstimator(slope, intercept);
+ this.waitingTimeEstimator = new ConstantWaitingTimeEstimator(estimatedMeanWaitTime);
+ this.rideDurationDistributionGenerator = new LogNormalDistributionGenerator(1, mu, sigma);
+ this.waitingTimeDistributionGenerator = new NormalDistributionGenerator(2, waitTimeStd);
+ }
+
+ public EuclideanDistanceBasedDrtEstimator(Network network, double networkDistanceFactor, RideDurationEstimator rideDurationEstimator,
+ WaitingTimeEstimator waitingTimeEstimator, DistributionGenerator rideDurationDistributionGenerator,
+ DistributionGenerator waitingTimeDistributionGenerator) {
+ this.network = network;
+ this.networkDistanceFactor = networkDistanceFactor;
+ this.rideDurationEstimator = rideDurationEstimator;
+ this.waitingTimeEstimator = waitingTimeEstimator;
+ this.rideDurationDistributionGenerator = rideDurationDistributionGenerator;
+ this.waitingTimeDistributionGenerator = waitingTimeDistributionGenerator;
}
@Override
@@ -60,19 +65,15 @@ public Estimate estimate(DrtRoute route, OptionalTime departureTime) {
Coord fromCoord = network.getLinks().get(route.getStartLinkId()).getToNode().getCoord();
Coord toCoord = network.getLinks().get(route.getEndLinkId()).getToNode().getCoord();
double euclideanDistance = CoordUtils.calcEuclideanDistance(fromCoord, toCoord);
- double typicalRideDuration = euclideanDistance * slope + intercept;
+
+ double typicalRideDuration = rideDurationEstimator.getEstimatedRideDuration(route.getStartLinkId(), route.getEndLinkId(), departureTime, euclideanDistance);
double typicalRideDistance = networkDistanceFactor * euclideanDistance;
- double randomFactor = nextLogNormal(mu, sigma);
- double waitTime = Math.max(estimatedMeanWaitTime * (1 + random.nextGaussian() * waitTimeStd), 0);
+ double typicalWaitingTime = waitingTimeEstimator.estimateWaitTime(route.getStartLinkId(), route.getEndLinkId(), departureTime);
+ double randomFactor = rideDurationDistributionGenerator.generateRandomValue();
+ double waitTime = Math.max(typicalWaitingTime * waitingTimeDistributionGenerator.generateRandomValue(), 0);
return new Estimate(typicalRideDistance * randomFactor, typicalRideDuration * randomFactor,
waitTime, 0);
}
- public double nextLogNormal(double mu, double sigma) {
- if (sigma == 0)
- return Math.exp(mu);
-
- return Math.exp(sigma * random.nextGaussian() + mu);
- }
}
diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/ConstantDrtEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/ExampleDrtEstimator.java
similarity index 82%
rename from contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/ConstantDrtEstimator.java
rename to contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/ExampleDrtEstimator.java
index 20ea18ee120..b49b3b988f0 100644
--- a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/ConstantDrtEstimator.java
+++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/ExampleDrtEstimator.java
@@ -2,13 +2,13 @@
import org.matsim.contrib.drt.estimator.DrtEstimator;
import org.matsim.contrib.drt.routing.DrtRoute;
-import org.matsim.contrib.drt.run.DrtConfigGroup;
import org.matsim.core.utils.misc.OptionalTime;
/**
* Estimates using a constant detour factor and waiting time.
*/
-public class ConstantDrtEstimator implements DrtEstimator {
+@Deprecated
+public class ExampleDrtEstimator implements DrtEstimator {
/**
* Detour factor for the estimate. 1.0 means no detour, 2.0 means twice the distance.
@@ -20,7 +20,7 @@ public class ConstantDrtEstimator implements DrtEstimator {
*/
private final double waitingTime;
- public ConstantDrtEstimator(double detourFactor, double waitingTime) {
+ public ExampleDrtEstimator(double detourFactor, double waitingTime) {
this.detourFactor = detourFactor;
this.waitingTime = waitingTime;
}
diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/BasicDrtEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/OnlineSimulationBasedDrtEstimator.java
similarity index 90%
rename from contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/BasicDrtEstimator.java
rename to contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/OnlineSimulationBasedDrtEstimator.java
index f02c4ee59b2..db1f3e83ccd 100644
--- a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/BasicDrtEstimator.java
+++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/OnlineSimulationBasedDrtEstimator.java
@@ -1,7 +1,6 @@
package org.matsim.contrib.drt.estimator.impl;
import org.apache.commons.math3.stat.descriptive.SummaryStatistics;
-import org.apache.commons.math3.stat.regression.RegressionResults;
import org.apache.commons.math3.stat.regression.SimpleRegression;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -23,12 +22,14 @@
import java.util.SplittableRandom;
/**
+ * When this estimator is used, explicit simulations of DRT will be carried out intermittently. During the iterations where no
+ * DRT is simulated, estimated DRT will be used. This estimator will replace the original DRT speed-up module
* Estimates drt trips based only daily averages. No spatial or temporal differentiation is taken into account for the estimate.
* This estimator is suited for small scenarios with few vehicles and trips and consequently few data points.
*/
-public class BasicDrtEstimator implements DrtOnlineEstimator, IterationEndsListener {
+public class OnlineSimulationBasedDrtEstimator implements DrtOnlineEstimator, IterationEndsListener {
- private static final Logger log = LogManager.getLogger(BasicDrtEstimator.class);
+ private static final Logger log = LogManager.getLogger(OnlineSimulationBasedDrtEstimator.class);
private final DrtEventSequenceCollector collector;
private final DrtEstimatorParams config;
@@ -41,8 +42,8 @@ public class BasicDrtEstimator implements DrtOnlineEstimator, IterationEndsListe
*/
private GlobalEstimate currentEst;
- public BasicDrtEstimator(DrtEventSequenceCollector collector, DrtEstimator initial,
- DrtEstimatorParams config, DrtConfigGroup drtConfig) {
+ public OnlineSimulationBasedDrtEstimator(DrtEventSequenceCollector collector, DrtEstimator initial,
+ DrtEstimatorParams config, DrtConfigGroup drtConfig) {
//zones = injector.getModal(DrtZonalSystem.class);
this.collector = collector;
this.initial = initial;
diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/distribution/DistributionGenerator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/distribution/DistributionGenerator.java
new file mode 100644
index 00000000000..d5e6e890729
--- /dev/null
+++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/distribution/DistributionGenerator.java
@@ -0,0 +1,10 @@
+package org.matsim.contrib.drt.estimator.impl.distribution;
+
+public interface DistributionGenerator {
+ /**
+ * @return relative value to the typical ride duration (i.e., generate a distribution around 1.0)
+ */
+ double generateRandomValue();
+
+ enum DistributionType {NO_DISTRIBUTION, NORMAL, LOG_NORMAL, CUSTOM}
+}
diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/distribution/LogNormalDistributionGenerator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/distribution/LogNormalDistributionGenerator.java
new file mode 100644
index 00000000000..1be1250a870
--- /dev/null
+++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/distribution/LogNormalDistributionGenerator.java
@@ -0,0 +1,35 @@
+package org.matsim.contrib.drt.estimator.impl.distribution;
+
+import java.util.Random;
+
+public class LogNormalDistributionGenerator implements DistributionGenerator {
+ private final Random random;
+ private final double mu;
+ private final double sigma;
+ private final double minValue;
+
+ private final double maxValue;
+
+ public LogNormalDistributionGenerator(long seed, double mu, double sigma) {
+ this.random = new Random(seed);
+ this.mu = mu;
+ this.sigma = sigma;
+ this.minValue = 0.5;
+ this.maxValue = 3;
+ }
+
+ public LogNormalDistributionGenerator(long seed, double mu, double sigma, double minValue, double maxValue) {
+ this.random = new Random(seed);
+ this.mu = mu;
+ this.sigma = sigma;
+ this.minValue = minValue;
+ this.maxValue = maxValue;
+ }
+
+ @Override
+ public double generateRandomValue() {
+ if (sigma == 0)
+ return Math.exp(mu);
+ return Math.max(Math.min(Math.exp(sigma * random.nextGaussian() + mu), maxValue), minValue);
+ }
+}
diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/distribution/NoDistribution.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/distribution/NoDistribution.java
new file mode 100644
index 00000000000..0643c45ba53
--- /dev/null
+++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/distribution/NoDistribution.java
@@ -0,0 +1,8 @@
+package org.matsim.contrib.drt.estimator.impl.distribution;
+
+public class NoDistribution implements DistributionGenerator{
+ @Override
+ public double generateRandomValue() {
+ return 1.0;
+ }
+}
diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/distribution/NormalDistributionGenerator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/distribution/NormalDistributionGenerator.java
new file mode 100644
index 00000000000..5b6a23fc31a
--- /dev/null
+++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/distribution/NormalDistributionGenerator.java
@@ -0,0 +1,34 @@
+package org.matsim.contrib.drt.estimator.impl.distribution;
+
+import java.util.Random;
+
+public class NormalDistributionGenerator implements DistributionGenerator{
+ private final Random random;
+ private final double std;
+
+ private final double minValue;
+
+ private final double maxValue;
+
+ public NormalDistributionGenerator(long seed, double std) {
+ this.random = new Random(seed);
+ this.std = std;
+ this.minValue = 0.5;
+ this.maxValue = 3.0;
+ }
+
+ public NormalDistributionGenerator(long seed, double std, double minValue, double maxValue) {
+ this.random = new Random(seed);
+ this.std = std;
+ this.minValue = minValue;
+ this.maxValue = maxValue;
+ }
+
+ @Override
+ public double generateRandomValue() {
+ double randomValue = 1 + random.nextGaussian() * std;
+ randomValue = Math.min(maxValue, randomValue);
+ randomValue = Math.max(minValue, randomValue);
+ return randomValue;
+ }
+}
diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/trip_estimation/ConstantRideDurationEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/trip_estimation/ConstantRideDurationEstimator.java
new file mode 100644
index 00000000000..7c431fb39ba
--- /dev/null
+++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/trip_estimation/ConstantRideDurationEstimator.java
@@ -0,0 +1,20 @@
+package org.matsim.contrib.drt.estimator.impl.trip_estimation;
+
+import org.matsim.api.core.v01.Id;
+import org.matsim.api.core.v01.network.Link;
+import org.matsim.core.utils.misc.OptionalTime;
+
+public class ConstantRideDurationEstimator implements RideDurationEstimator {
+ private final double alpha;
+ private final double beta;
+
+ public ConstantRideDurationEstimator(double alpha, double beta) {
+ this.alpha = alpha;
+ this.beta = beta;
+ }
+
+ @Override
+ public double getEstimatedRideDuration(Id fromLinkId, Id toLinkId, OptionalTime departureTime, double directRideDuration) {
+ return alpha * directRideDuration + beta;
+ }
+}
diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/trip_estimation/RideDurationEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/trip_estimation/RideDurationEstimator.java
new file mode 100644
index 00000000000..d19a4e9fa6c
--- /dev/null
+++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/trip_estimation/RideDurationEstimator.java
@@ -0,0 +1,11 @@
+package org.matsim.contrib.drt.estimator.impl.trip_estimation;
+
+import org.matsim.api.core.v01.Id;
+import org.matsim.api.core.v01.network.Link;
+import org.matsim.core.utils.collections.Tuple;
+import org.matsim.core.utils.misc.OptionalTime;
+
+public interface RideDurationEstimator {
+ double getEstimatedRideDuration(Id fromLinkId, Id toLinkId, OptionalTime departureTime, double directTripDuration);
+
+}
diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/waiting_time_estimation/ConstantWaitingTimeEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/waiting_time_estimation/ConstantWaitingTimeEstimator.java
new file mode 100644
index 00000000000..1b2d18288d5
--- /dev/null
+++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/waiting_time_estimation/ConstantWaitingTimeEstimator.java
@@ -0,0 +1,18 @@
+package org.matsim.contrib.drt.estimator.impl.waiting_time_estimation;
+
+import org.matsim.api.core.v01.Id;
+import org.matsim.api.core.v01.network.Link;
+import org.matsim.core.utils.misc.OptionalTime;
+
+public class ConstantWaitingTimeEstimator implements WaitingTimeEstimator {
+ private final double typicalWaitingTime;
+
+ public ConstantWaitingTimeEstimator(double typicalWaitingTime) {
+ this.typicalWaitingTime = typicalWaitingTime;
+ }
+
+ @Override
+ public double estimateWaitTime(Id fromLinkId, Id toLinkId, OptionalTime departureTime) {
+ return typicalWaitingTime;
+ }
+}
diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/waiting_time_estimation/ShapeFileBasedWaitingTimeEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/waiting_time_estimation/ShapeFileBasedWaitingTimeEstimator.java
new file mode 100644
index 00000000000..32bcb03c8cd
--- /dev/null
+++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/waiting_time_estimation/ShapeFileBasedWaitingTimeEstimator.java
@@ -0,0 +1,63 @@
+package org.matsim.contrib.drt.estimator.impl.waiting_time_estimation;
+
+import org.geotools.api.feature.simple.SimpleFeature;
+import org.locationtech.jts.geom.Geometry;
+import org.matsim.api.core.v01.Id;
+import org.matsim.api.core.v01.TransportMode;
+import org.matsim.api.core.v01.network.Link;
+import org.matsim.api.core.v01.network.Network;
+import org.matsim.core.utils.geometry.geotools.MGC;
+import org.matsim.core.utils.misc.OptionalTime;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class ShapeFileBasedWaitingTimeEstimator implements WaitingTimeEstimator {
+ /**
+ * Typical waiting time. Due to the length limit of the attribute name, we have to use some abbreviate
+ */
+ private final static String TYPICAL_WAITING_TIME_NAME = "typ_wt";
+ private final Map, Double> typicalWaitingTimeForEachLink = new HashMap<>();
+ /**
+ * The default typical waiting time. This value will be used for links that are not covered by any
+ * waiting time zone. The baseTypicalWaitingTime is usually larger than the typical waiting time
+ * in any waiting time zone.
+ */
+ private final double baseTypicalWaitingTime;
+
+ public ShapeFileBasedWaitingTimeEstimator(Network network, List features) {
+ baseTypicalWaitingTime = 1800;
+ initializeWaitingTimeMap(network, features);
+ }
+
+ public ShapeFileBasedWaitingTimeEstimator(Network network, List features, double baseTypicalWaitingTime) {
+ this.baseTypicalWaitingTime = baseTypicalWaitingTime;
+ initializeWaitingTimeMap(network, features);
+ }
+
+ private void initializeWaitingTimeMap(Network network, List features) {
+ for (Link link : network.getLinks().values()) {
+ if (!link.getAllowedModes().contains(TransportMode.car) && !link.getAllowedModes().contains(TransportMode.drt)) {
+ continue;
+ }
+ double minTypicalWaitingTime = baseTypicalWaitingTime;
+ for (SimpleFeature feature : features) {
+ Geometry geometry = (Geometry) feature.getDefaultGeometry();
+ if (geometry.contains(MGC.coord2Point(link.getToNode().getCoord()))) {
+ // The link is located within the zone -> reduce typical waiting time if necessary
+ double typicalWaitingTimeForCurrentZone = (long) feature.getAttribute(TYPICAL_WAITING_TIME_NAME);
+ if (typicalWaitingTimeForCurrentZone < minTypicalWaitingTime) {
+ minTypicalWaitingTime = typicalWaitingTimeForCurrentZone;
+ }
+ }
+ }
+ typicalWaitingTimeForEachLink.put(link.getId(), minTypicalWaitingTime);
+ }
+ }
+
+ @Override
+ public double estimateWaitTime(Id fromLinkId, Id toLinkId, OptionalTime departureTime) {
+ return typicalWaitingTimeForEachLink.get(fromLinkId);
+ }
+}
diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/waiting_time_estimation/WaitingTimeEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/waiting_time_estimation/WaitingTimeEstimator.java
new file mode 100644
index 00000000000..8649cd88a2c
--- /dev/null
+++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/waiting_time_estimation/WaitingTimeEstimator.java
@@ -0,0 +1,9 @@
+package org.matsim.contrib.drt.estimator.impl.waiting_time_estimation;
+
+import org.matsim.api.core.v01.Id;
+import org.matsim.api.core.v01.network.Link;
+import org.matsim.core.utils.misc.OptionalTime;
+
+public interface WaitingTimeEstimator {
+ double estimateWaitTime(Id fromLinkId, Id toLinkId, OptionalTime departureTime);
+}
diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultUnplannedRequestInserter.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultUnplannedRequestInserter.java
index 0f8443f0141..1854e93ffd1 100644
--- a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultUnplannedRequestInserter.java
+++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultUnplannedRequestInserter.java
@@ -54,6 +54,7 @@
public class DefaultUnplannedRequestInserter implements UnplannedRequestInserter {
private static final Logger log = LogManager.getLogger(DefaultUnplannedRequestInserter.class);
public static final String NO_INSERTION_FOUND_CAUSE = "no_insertion_found";
+ public static final String OFFER_REJECTED_CAUSE = "offer_rejected";
private final String mode;
private final Fleet fleet;
@@ -125,17 +126,7 @@ private void scheduleUnplannedRequest(DrtRequest req, Map, Vehic
Optional best = insertionSearch.findBestInsertion(req,
Collections.unmodifiableCollection(vehicleEntries.values()));
if (best.isEmpty()) {
- if (!insertionRetryQueue.tryAddFailedRequest(req, now)) {
- eventsManager.processEvent(
- new PassengerRequestRejectedEvent(now, mode, req.getId(), req.getPassengerIds(),
- NO_INSERTION_FOUND_CAUSE));
- log.debug("No insertion found for drt request "
- + req
- + " with passenger ids="
- + req.getPassengerIds().stream().map(Object::toString).collect(Collectors.joining(","))
- + " fromLinkId="
- + req.getFromLink().getId());
- }
+ retryOrReject(req, now, NO_INSERTION_FOUND_CAUSE);
} else {
InsertionWithDetourData insertion = best.get();
@@ -144,26 +135,44 @@ private void scheduleUnplannedRequest(DrtRequest req, Map, Vehic
insertion.detourTimeInfo.pickupDetourInfo.departureTime,
insertion.detourTimeInfo.dropoffDetourInfo.arrivalTime);
- var vehicle = insertion.insertion.vehicleEntry.vehicle;
- var pickupDropoffTaskPair = insertionScheduler.scheduleRequest(acceptedRequest.get(), insertion);
+ if(acceptedRequest.isPresent()) {
+ var vehicle = insertion.insertion.vehicleEntry.vehicle;
+ var pickupDropoffTaskPair = insertionScheduler.scheduleRequest(acceptedRequest.get(), insertion);
- VehicleEntry newVehicleEntry = vehicleEntryFactory.create(vehicle, now);
- if (newVehicleEntry != null) {
- vehicleEntries.put(vehicle.getId(), newVehicleEntry);
- } else {
- vehicleEntries.remove(vehicle.getId());
- }
+ VehicleEntry newVehicleEntry = vehicleEntryFactory.create(vehicle, now);
+ if (newVehicleEntry != null) {
+ vehicleEntries.put(vehicle.getId(), newVehicleEntry);
+ } else {
+ vehicleEntries.remove(vehicle.getId());
+ }
+
+ double expectedPickupTime = pickupDropoffTaskPair.pickupTask.getBeginTime();
+ expectedPickupTime = Math.max(expectedPickupTime, acceptedRequest.get().getEarliestStartTime());
+ expectedPickupTime += stopDurationProvider.calcPickupDuration(vehicle, req);
- double expectedPickupTime = pickupDropoffTaskPair.pickupTask.getBeginTime();
- expectedPickupTime = Math.max(expectedPickupTime, acceptedRequest.get().getEarliestStartTime());
- expectedPickupTime += stopDurationProvider.calcPickupDuration(vehicle, req);
+ double expectedDropoffTime = pickupDropoffTaskPair.dropoffTask.getBeginTime();
+ expectedDropoffTime += stopDurationProvider.calcDropoffDuration(vehicle, req);
- double expectedDropoffTime = pickupDropoffTaskPair.dropoffTask.getBeginTime();
- expectedDropoffTime += stopDurationProvider.calcDropoffDuration(vehicle, req);
+ eventsManager.processEvent(
+ new PassengerRequestScheduledEvent(now, mode, req.getId(), req.getPassengerIds(), vehicle.getId(),
+ expectedPickupTime, expectedDropoffTime));
+ } else {
+ retryOrReject(req, now, OFFER_REJECTED_CAUSE);
+ }
+ }
+ }
+ private void retryOrReject(DrtRequest req, double now, String cause) {
+ if (!insertionRetryQueue.tryAddFailedRequest(req, now)) {
eventsManager.processEvent(
- new PassengerRequestScheduledEvent(now, mode, req.getId(), req.getPassengerIds(), vehicle.getId(),
- expectedPickupTime, expectedDropoffTime));
+ new PassengerRequestRejectedEvent(now, mode, req.getId(), req.getPassengerIds(),
+ cause));
+ log.debug("No insertion found for drt request "
+ + req
+ + " with passenger ids="
+ + req.getPassengerIds().stream().map(Object::toString).collect(Collectors.joining(","))
+ + " fromLinkId="
+ + req.getFromLink().getId());
}
}
}
diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/prebooking/PrebookingManager.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/prebooking/PrebookingManager.java
index ed79cd0bf9f..04d8df45161 100644
--- a/contribs/drt/src/main/java/org/matsim/contrib/drt/prebooking/PrebookingManager.java
+++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/prebooking/PrebookingManager.java
@@ -9,9 +9,7 @@
import org.matsim.api.core.v01.events.handler.PersonStuckEventHandler;
import org.matsim.api.core.v01.network.Link;
import org.matsim.api.core.v01.network.Network;
-import org.matsim.api.core.v01.population.Leg;
-import org.matsim.api.core.v01.population.Person;
-import org.matsim.api.core.v01.population.Plan;
+import org.matsim.api.core.v01.population.*;
import org.matsim.contrib.drt.passenger.AcceptedDrtRequest;
import org.matsim.contrib.drt.prebooking.unscheduler.RequestUnscheduler;
import org.matsim.contrib.dvrp.fleet.DvrpVehicle;
@@ -21,10 +19,12 @@
import org.matsim.core.api.experimental.events.EventsManager;
import org.matsim.core.mobsim.framework.MobsimAgent;
import org.matsim.core.mobsim.framework.MobsimAgent.State;
+import org.matsim.core.mobsim.framework.MobsimPassengerAgent;
import org.matsim.core.mobsim.framework.MobsimTimer;
import org.matsim.core.mobsim.framework.events.MobsimAfterSimStepEvent;
import org.matsim.core.mobsim.framework.listeners.MobsimAfterSimStepListener;
import org.matsim.core.mobsim.qsim.InternalInterface;
+import org.matsim.core.mobsim.qsim.agents.HasModifiablePlan;
import org.matsim.core.mobsim.qsim.agents.WithinDayAgentUtils;
import org.matsim.core.mobsim.qsim.interfaces.MobsimEngine;
@@ -59,12 +59,16 @@ public class PrebookingManager implements MobsimEngine, MobsimAfterSimStepListen
private final VrpOptimizer optimizer;
private final RequestUnscheduler unscheduler;
+ private final boolean abortRejectedPrebookings;
private final MobsimTimer mobsimTimer;
+ private InternalInterface internalInterface;
+
+
public PrebookingManager(String mode, Network network, PassengerRequestCreator requestCreator,
- VrpOptimizer optimizer, MobsimTimer mobsimTimer, PassengerRequestValidator requestValidator,
- EventsManager eventsManager, RequestUnscheduler unscheduler) {
+ VrpOptimizer optimizer, MobsimTimer mobsimTimer, PassengerRequestValidator requestValidator,
+ EventsManager eventsManager, RequestUnscheduler unscheduler, boolean abortRejectedPrebookings) {
this.network = network;
this.mode = mode;
this.requestCreator = requestCreator;
@@ -74,6 +78,7 @@ public PrebookingManager(String mode, Network network, PassengerRequestCreator r
this.mobsimTimer = mobsimTimer;
this.eventsManager = eventsManager;
this.unscheduler = unscheduler;
+ this.abortRejectedPrebookings = abortRejectedPrebookings;
}
// Functionality for ID management
@@ -386,6 +391,22 @@ private void processRejections(double now) {
} else {
unscheduleUponVehicleAssignment.add(requestId);
}
+
+ if(abortRejectedPrebookings) {
+ for (Id passengerId : item.request.getPassengerIds()) {
+ MobsimAgent agent = internalInterface.getMobsim().getAgents().get(passengerId);
+ PlanElement planElement = WithinDayAgentUtils.getCurrentPlanElement(agent);
+ if(planElement instanceof Activity activity) {
+ activity.setEndTime(Double.POSITIVE_INFINITY);
+ activity.setMaximumDurationUndefined();
+ ((HasModifiablePlan) agent).resetCaches();
+ internalInterface.getMobsim().rescheduleActivityEnd(agent);
+ }
+ eventsManager.processEvent(new PersonStuckEvent(now, agent.getId(), agent.getCurrentLinkId(),
+ this.mode));
+ internalInterface.getMobsim().getAgentCounter().incLost();
+ }
+ }
}
}
@@ -454,5 +475,6 @@ public void afterSim() {
@Override
public void setInternalInterface(InternalInterface internalInterface) {
+ this.internalInterface = internalInterface;
}
}
diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/prebooking/PrebookingModeQSimModule.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/prebooking/PrebookingModeQSimModule.java
index 19274c3fd8b..4ae7e1201a3 100644
--- a/contribs/drt/src/main/java/org/matsim/contrib/drt/prebooking/PrebookingModeQSimModule.java
+++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/prebooking/PrebookingModeQSimModule.java
@@ -59,7 +59,7 @@ protected void configureQSim() {
MobsimTimer mobsimTimer = getter.get(MobsimTimer.class);
return new PrebookingManager(getMode(), network, requestCreator, optimizer, mobsimTimer, requestValidator,
- eventsManager, requestUnscheduler);
+ eventsManager, requestUnscheduler, prebookingParams.abortRejectedPrebookings);
})).in(Singleton.class);
addModalQSimComponentBinding().to(modalKey(PrebookingManager.class));
diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/prebooking/PrebookingParams.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/prebooking/PrebookingParams.java
index fdf678bb272..4f1cdcb58e2 100644
--- a/contribs/drt/src/main/java/org/matsim/contrib/drt/prebooking/PrebookingParams.java
+++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/prebooking/PrebookingParams.java
@@ -38,4 +38,10 @@ public enum UnschedulingMode {
@NotNull
public UnschedulingMode unschedulingMode = UnschedulingMode.StopBased;
+ @Parameter
+ @Comment("Defines whether agents are set to stuck and abort when a prebooked request is rejected." +
+ "If false, prebooked agents will re-attempt to ride at their initially planned departure time." +
+ "Note that additional passenger events for submission, scheduling etc. will occur for re-attempts.")
+ public boolean abortRejectedPrebookings = true;
+
}
\ No newline at end of file
diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/prebooking/PrebookingStopActivity.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/prebooking/PrebookingStopActivity.java
index fd81c1745f3..e55af9e76a5 100644
--- a/contribs/drt/src/main/java/org/matsim/contrib/drt/prebooking/PrebookingStopActivity.java
+++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/prebooking/PrebookingStopActivity.java
@@ -1,15 +1,15 @@
package org.matsim.contrib.drt.prebooking;
-import java.util.HashSet;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Queue;
-import java.util.Set;
import java.util.function.Supplier;
import org.matsim.api.core.v01.Id;
import org.matsim.api.core.v01.IdMap;
+import org.matsim.api.core.v01.IdSet;
import org.matsim.api.core.v01.Identifiable;
import org.matsim.api.core.v01.population.Person;
import org.matsim.contrib.drt.passenger.AcceptedDrtRequest;
@@ -39,9 +39,13 @@ public class PrebookingStopActivity extends FirstLastSimStepDynActivity implemen
private final Map, ? extends AcceptedDrtRequest> pickupRequests;
private final Map, ? extends AcceptedDrtRequest> dropoffRequests;
- private final IdMap enterTimes = new IdMap<>(Request.class);
+ private final Queue enterTimes = new PriorityQueue<>();
private final Queue leaveTimes = new PriorityQueue<>();
- private final Set> enteredRequests = new HashSet<>();
+
+ private final IdSet enteredRequests = new IdSet<>(Request.class);
+
+ private final IdSet registeredPickups = new IdSet<>(Request.class);
+ private final IdMap expectedPickups = new IdMap<>(Request.class);
private final PrebookingManager prebookingManager;
private final PassengerHandler passengerHandler;
@@ -93,7 +97,6 @@ private void initDropoffRequests(double now) {
}
private boolean updateDropoffRequests(double now) {
-
while (!leaveTimes.isEmpty() && leaveTimes.peek().time <= now) {
Id requestId = leaveTimes.poll().id;
passengerHandler.dropOffPassengers(driver, requestId, now);
@@ -105,60 +108,94 @@ private boolean updateDropoffRequests(double now) {
}
private record QueuedRequest(Id id, double time) implements Comparable {
-
@Override
public int compareTo(QueuedRequest o) {
return Double.compare(this.time, o.time);
}
}
+ private int cachedPickupRequestsHash = -1;
+
private boolean updatePickupRequests(double now, boolean isFirstStep) {
- var pickupIterator = pickupRequests.values().iterator();
-
- while (pickupIterator.hasNext()) {
- var request = pickupIterator.next();
-
- if (!enteredRequests.contains(request.getId()) && !enterTimes.containsKey(request.getId())) {
- // this is a new request that has been added after the activity has been created
- // or that had not arrived yet
-
- if (passengerHandler.notifyWaitForPassengers(this, this.driver, request.getId())) {
- // agent starts to enter
- queuePickup(request, now);
- } else if (now > request.getEarliestStartTime() && !isFirstStep) {
- if (abandonVoter.abandonRequest(now, vehicle, request)) {
- prebookingManager.abandon(request.getId());
- }
+ int pickupRequestsHash = pickupRequests.hashCode();
+
+ // part 1: check if the pickup list has been updated dynamically
+
+ if (isFirstStep || pickupRequestsHash != cachedPickupRequestsHash) {
+ cachedPickupRequestsHash = pickupRequestsHash;
+
+ // added requests
+ for (AcceptedDrtRequest request : pickupRequests.values()) {
+ if (!registeredPickups.contains(request.getId())) {
+ // in the first step, this is a standard pickup request, later this is a request that has been added after the activity has been created
+ expectedPickups.put(request.getId(), request);
+ registeredPickups.add(request.getId());
+ }
+ }
+
+ // removed requests (for instance via cancellation)
+ var expectedIterator = expectedPickups.iterator();
+ while (expectedIterator.hasNext()) {
+ if (!pickupRequests.containsKey(expectedIterator.next().getId())) {
+ // a request has been removed from the list of expected pickups
+ expectedIterator.remove();
}
}
}
+
+ // part 2: handle the requests that we expect but which have not arrived yet
+
+ var expectedIterator = expectedPickups.values().iterator();
+ while (expectedIterator.hasNext()) {
+ AcceptedDrtRequest request = expectedIterator.next();
+
+ if (passengerHandler.notifyWaitForPassengers(this, this.driver, request.getId())) {
+ // agent starts to enter
+ queuePickup(request, now);
+ expectedIterator.remove();
+ } else if (now > request.getEarliestStartTime() && !isFirstStep) {
+ if (abandonVoter.abandonRequest(now, vehicle, request)) {
+ // abandon the request, but not in the first time step for the sake of event timing
+ prebookingManager.abandon(request.getId());
+ expectedIterator.remove();
+ }
+ }
+ }
+
+ // part 3: handle the requests that are currently entering the vehicle
- var enterIterator = enterTimes.entrySet().iterator();
+ var enterIterator = enterTimes.iterator();
+
+ // logic is as follows:
+ // - let people enter in the order at which they arrived + their interaction time
+ // - but in case there is no capacity (others still disembarking) they need to wait
while (enterIterator.hasNext()) {
var entry = enterIterator.next();
int availableCapacity = vehicle.getCapacity() - onboard;
- if (entry.getValue() <= now) {
- int requiredCapacity = pickupRequests.get(entry.getKey()).getPassengerCount();
+ if (entry.time <= now) {
+ int requiredCapacity = pickupRequests.get(entry.id).getPassengerCount();
if (requiredCapacity <= availableCapacity) {
// let agent enter now
- Verify.verify(passengerHandler.tryPickUpPassengers(this, driver, entry.getKey(), now));
- enteredRequests.add(entry.getKey());
+ Verify.verify(passengerHandler.tryPickUpPassengers(this, driver, entry.id, now));
+ enteredRequests.add(entry.id);
onboard += requiredCapacity;
enterIterator.remove();
}
+ } else {
+ break;
}
}
- return enterTimes.size() == 0 && pickupRequests.size() == enteredRequests.size();
+ return expectedPickups.size() == 0 && pickupRequests.size() == enteredRequests.size();
}
private void queuePickup(AcceptedDrtRequest request, double now) {
prebookingManager.notifyPickup(now, request);
double enterTime = now + stopDurationProvider.calcPickupDuration(vehicle, request.getRequest());
- enterTimes.put(request.getId(), enterTime);
+ enterTimes.add(new QueuedRequest(request.getId(), enterTime));
}
@Override
@@ -169,7 +206,10 @@ protected void simStep(double now) {
@Override
public void notifyPassengersAreReadyForDeparture(List passengers, double now) {
var request = getRequestForPassengers(passengers.stream().map(Identifiable::getId).toList());
- queuePickup(request, now);
+ if(expectedPickups.containsKey(request.getId())) {
+ queuePickup(request, now);
+ expectedPickups.remove(request.getId());
+ }
}
private AcceptedDrtRequest getRequestForPassengers(List> passengerIds) {
diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/scheduler/DefaultRequestInsertionScheduler.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/scheduler/DefaultRequestInsertionScheduler.java
index 8b3755ba082..5ef8ea8f31a 100644
--- a/contribs/drt/src/main/java/org/matsim/contrib/drt/scheduler/DefaultRequestInsertionScheduler.java
+++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/scheduler/DefaultRequestInsertionScheduler.java
@@ -24,6 +24,7 @@
import java.util.List;
+import org.matsim.api.core.v01.Id;
import org.matsim.api.core.v01.network.Link;
import org.matsim.contrib.drt.optimizer.VehicleEntry;
import org.matsim.contrib.drt.optimizer.Waypoint;
@@ -37,6 +38,7 @@
import org.matsim.contrib.drt.stops.StopTimeCalculator;
import org.matsim.contrib.dvrp.fleet.DvrpVehicle;
import org.matsim.contrib.dvrp.fleet.Fleet;
+import org.matsim.contrib.dvrp.path.DivertedVrpPath;
import org.matsim.contrib.dvrp.path.VrpPathWithTravelData;
import org.matsim.contrib.dvrp.path.VrpPaths;
import org.matsim.contrib.dvrp.schedule.DriveTask;
@@ -65,9 +67,9 @@ public class DefaultRequestInsertionScheduler implements RequestInsertionSchedul
private final StopTimeCalculator stopTimeCalculator;
private final boolean scheduleWaitBeforeDrive;
- public DefaultRequestInsertionScheduler(Fleet fleet, MobsimTimer timer,
- TravelTime travelTime, ScheduleTimingUpdater scheduleTimingUpdater, DrtTaskFactory taskFactory,
- StopTimeCalculator stopTimeCalculator, boolean scheduleWaitBeforeDrive) {
+ public DefaultRequestInsertionScheduler(Fleet fleet, MobsimTimer timer, TravelTime travelTime,
+ ScheduleTimingUpdater scheduleTimingUpdater, DrtTaskFactory taskFactory,
+ StopTimeCalculator stopTimeCalculator, boolean scheduleWaitBeforeDrive) {
this.timer = timer;
this.travelTime = travelTime;
this.scheduleTimingUpdater = scheduleTimingUpdater;
@@ -128,8 +130,7 @@ private void verifyConstraints(InsertionWithDetourData insertion) {
Schedule schedule = insertion.insertion.vehicleEntry.vehicle.getSchedule();
for (Task task : schedule.getTasks()) {
- if (task instanceof DrtStopTask) {
- DrtStopTask stopTask = (DrtStopTask) task;
+ if (task instanceof DrtStopTask stopTask) {
for (AcceptedDrtRequest request : stopTask.getPickupRequests().values()) {
Verify.verify(stopTask.getEndTime() <= request.getLatestStartTime());
@@ -144,7 +145,7 @@ private void verifyConstraints(InsertionWithDetourData insertion) {
}
private void verifyStructure(Schedule schedule) {
- boolean previousDrive = false;
+ DriveTask previousDrive = null;
int startIndex = schedule.getStatus().equals(ScheduleStatus.STARTED) ? schedule.getCurrentTask().getTaskIdx()
: 0;
@@ -152,11 +153,18 @@ private void verifyStructure(Schedule schedule) {
for (int index = startIndex; index < schedule.getTaskCount(); index++) {
Task task = schedule.getTasks().get(index);
- if (task instanceof DriveTask) {
- Verify.verify(!previousDrive);
- previousDrive = true;
+ if (task instanceof DriveTask driveTask) {
+ if(previousDrive != null) {
+ Verify.verify(previousDrive.getPath() instanceof DivertedVrpPath,
+ "The first of two subsequent drive tasks has to be a diverted path.");
+ Id firstEnd = previousDrive.getPath().getToLink().getId();
+ Id secondStart = driveTask.getPath().getFromLink().getId();
+ Verify.verify(firstEnd.equals(secondStart),
+ String.format("Subsequent drive tasks are not connected link %s !=> %s", firstEnd.toString(), secondStart.toString()));
+ }
+ previousDrive = driveTask;
} else {
- previousDrive = false;
+ previousDrive = null;
}
}
}
@@ -211,12 +219,16 @@ private DrtStopTask insertPickup(AcceptedDrtRequest request, InsertionWithDetour
beforePickupTask = insertWait(vehicleEntry.vehicle, currentTask, dropoffIdx);
}
}
+ if(!stops.isEmpty() && stops.size() + 1 > pickupIdx) {
+ //there is an existing stop which was scheduled earlier and was not the destination of the already diverted drive task
+ removeBetween(schedule, beforePickupTask, stops.get(pickupIdx).task);
+ }
} else { // insert pickup after an existing stop/stay task
StayTask stayTask = null;
DrtStopTask stopTask = null;
if (pickupIdx == 0) {
if (scheduleStatus == ScheduleStatus.PLANNED) {// PLANNED schedule
- stayTask = (StayTask)schedule.getTasks().get(0);
+ stayTask = (StayTask)schedule.getTasks().getFirst();
stayTask.setEndTime(stayTask.getBeginTime());// could get later removed with ScheduleTimingUpdater
} else if (STAY.isBaseTypeOf(currentTask)) {
stayTask = (StayTask)currentTask; // ongoing stay task
@@ -307,7 +319,11 @@ private DrtStopTask insertPickup(AcceptedDrtRequest request, InsertionWithDetour
double nextBeginTime = pickupIdx == dropoffIdx ? //
pickupStopTask.getEndTime() : // asap
- stops.get(pickupIdx).task.getBeginTime(); // as planned
+ stops.get(pickupIdx).task.getPickupRequests().values()
+ .stream()
+ .mapToDouble(AcceptedDrtRequest::getEarliestStartTime)
+ .min()
+ .orElse(pickupStopTask.getEndTime());
if (request.getFromLink() == toLink) {
// prebooking case when we are already at the stop location, but next stop task happens in the future
@@ -340,7 +356,7 @@ private DrtStopTask insertPickup(AcceptedDrtRequest request, InsertionWithDetour
}
private DrtStopTask insertDropoff(AcceptedDrtRequest request, InsertionWithDetourData insertionWithDetourData,
- DrtStopTask pickupTask) {
+ DrtStopTask pickupTask) {
final double now = timer.getTimeOfDay();
var insertion = insertionWithDetourData.insertion;
VehicleEntry vehicleEntry = insertion.vehicleEntry;
@@ -422,8 +438,13 @@ private DrtStopTask insertDropoff(AcceptedDrtRequest request, InsertionWithDetou
afterDropoffTask.getTaskIdx() + 1, afterDropoffTask.getEndTime());
} else {
// may want to wait here or after driving before starting next stop
+ double earliestArrivalTime = stops.get(dropoffIdx).task.getPickupRequests().values()
+ .stream()
+ .mapToDouble(AcceptedDrtRequest::getEarliestStartTime)
+ .min()
+ .orElse(dropoffStopTask.getEndTime());
Task afterDropoffTask = insertDriveWithWait(vehicleEntry.vehicle, dropoffStopTask, vrpPath,
- stops.get(dropoffIdx).task.getBeginTime());
+ earliestArrivalTime);
scheduleTimingUpdater.updateTimingsStartingFromTaskIdx(vehicleEntry.vehicle,
afterDropoffTask.getTaskIdx() + 1, afterDropoffTask.getEndTime());
@@ -506,7 +527,7 @@ private Task insertDriveWithWait(DvrpVehicle vehicle, Task departureTask, VrpPat
Task driveTask = taskFactory.createDriveTask(vehicle, path, DrtDriveTask.TYPE);
schedule.addTask(leadingTask.getTaskIdx() + 1, driveTask);
- if (driveTask.getEndTime() < latestArrivalTime) {
+ if (driveTask.getEndTime() < latestArrivalTime && !scheduleWaitBeforeDrive) {
DrtStayTask waitTask = taskFactory.createStayTask(vehicle, driveTask.getEndTime(), latestArrivalTime,
path.getToLink());
schedule.addTask(driveTask.getTaskIdx() + 1, waitTask);
diff --git a/contribs/drt/src/test/java/org/matsim/contrib/drt/estimator/DrtEstimateAndTeleportTest.java b/contribs/drt/src/test/java/org/matsim/contrib/drt/estimator/DrtEstimateAndTeleportTest.java
new file mode 100644
index 00000000000..cafd39170b3
--- /dev/null
+++ b/contribs/drt/src/test/java/org/matsim/contrib/drt/estimator/DrtEstimateAndTeleportTest.java
@@ -0,0 +1,59 @@
+package org.matsim.contrib.drt.estimator;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.matsim.contrib.common.zones.systems.grid.square.SquareGridZoneSystemParams;
+import org.matsim.contrib.drt.estimator.impl.DirectTripBasedDrtEstimator;
+import org.matsim.contrib.drt.estimator.impl.distribution.NormalDistributionGenerator;
+import org.matsim.contrib.drt.estimator.impl.trip_estimation.ConstantRideDurationEstimator;
+import org.matsim.contrib.drt.estimator.impl.waiting_time_estimation.ConstantWaitingTimeEstimator;
+import org.matsim.contrib.drt.run.DrtConfigGroup;
+import org.matsim.contrib.drt.run.DrtControlerCreator;
+import org.matsim.contrib.drt.run.MultiModeDrtConfigGroup;
+import org.matsim.contrib.dvrp.run.DvrpConfigGroup;
+import org.matsim.contrib.zone.skims.DvrpTravelTimeMatrixParams;
+import org.matsim.core.config.Config;
+import org.matsim.core.config.ConfigUtils;
+import org.matsim.core.controler.AbstractModule;
+import org.matsim.core.controler.Controler;
+import org.matsim.core.utils.io.IOUtils;
+import org.matsim.examples.ExamplesUtils;
+import org.matsim.testcases.MatsimTestUtils;
+import org.matsim.vis.otfvis.OTFVisConfigGroup;
+
+import java.net.URL;
+
+public class DrtEstimateAndTeleportTest {
+ @RegisterExtension
+ public MatsimTestUtils utils = new MatsimTestUtils();
+
+ @Test
+ public void testDrtEstimateAndTeleport() {
+ URL configUrl = IOUtils.extendUrl(ExamplesUtils.getTestScenarioURL("mielec"), "mielec_drt_config.xml");
+
+ DvrpConfigGroup dvrpConfig = new DvrpConfigGroup();
+ DvrpTravelTimeMatrixParams matrixParams = dvrpConfig.getTravelTimeMatrixParams();
+ matrixParams.addParameterSet(matrixParams.createParameterSet(SquareGridZoneSystemParams.SET_NAME));
+
+ Config config = ConfigUtils.loadConfig(configUrl, new MultiModeDrtConfigGroup(), dvrpConfig,
+ new OTFVisConfigGroup());
+ DrtConfigGroup drtConfigGroup = DrtConfigGroup.getSingleModeDrtConfig(config);
+ drtConfigGroup.simulationType = DrtConfigGroup.SimulationType.estimateAndTeleport;
+
+ Controler controler = DrtControlerCreator.createControler(config, false);
+ controler.addOverridingModule(new AbstractModule() {
+ @Override
+ public void install() {
+ DrtEstimatorModule.bindEstimator(binder(), drtConfigGroup.mode).toInstance(
+ new DirectTripBasedDrtEstimator.Builder()
+ .setWaitingTimeEstimator(new ConstantWaitingTimeEstimator(300))
+ .setWaitingTimeDistributionGenerator(new NormalDistributionGenerator(1, 0.4))
+ .setRideDurationEstimator(new ConstantRideDurationEstimator(1.25, 300))
+ .setRideDurationDistributionGenerator(new NormalDistributionGenerator(2, 0.3))
+ .build()
+ );
+ }
+ });
+ controler.run();
+ }
+}
diff --git a/contribs/drt/src/test/java/org/matsim/contrib/drt/run/examples/RunDrtExampleIT.java b/contribs/drt/src/test/java/org/matsim/contrib/drt/run/examples/RunDrtExampleIT.java
index 0b2adb16db2..0291899bc1d 100644
--- a/contribs/drt/src/test/java/org/matsim/contrib/drt/run/examples/RunDrtExampleIT.java
+++ b/contribs/drt/src/test/java/org/matsim/contrib/drt/run/examples/RunDrtExampleIT.java
@@ -26,9 +26,7 @@
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
import java.util.stream.Collectors;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
@@ -37,6 +35,10 @@
import org.matsim.contrib.drt.optimizer.DrtRequestInsertionRetryParams;
import org.matsim.contrib.drt.optimizer.insertion.repeatedselective.RepeatedSelectiveInsertionSearchParams;
import org.matsim.contrib.drt.optimizer.insertion.selective.SelectiveInsertionSearchParams;
+import org.matsim.contrib.drt.passenger.AcceptedDrtRequest;
+import org.matsim.contrib.drt.passenger.DefaultOfferAcceptor;
+import org.matsim.contrib.drt.passenger.DrtOfferAcceptor;
+import org.matsim.contrib.drt.passenger.DrtRequest;
import org.matsim.contrib.drt.prebooking.PrebookingParams;
import org.matsim.contrib.drt.prebooking.logic.ProbabilityBasedPrebookingLogic;
import org.matsim.contrib.drt.run.DrtConfigGroup;
@@ -53,6 +55,7 @@
import org.matsim.contrib.dvrp.passenger.PassengerRequestScheduledEvent;
import org.matsim.contrib.dvrp.passenger.PassengerRequestScheduledEventHandler;
import org.matsim.contrib.dvrp.run.AbstractDvrpModeModule;
+import org.matsim.contrib.dvrp.run.AbstractDvrpModeQSimModule;
import org.matsim.contrib.dvrp.run.DvrpConfigGroup;
import org.matsim.contrib.zone.skims.DvrpTravelTimeMatrixParams;
import org.matsim.core.config.Config;
@@ -60,6 +63,7 @@
import org.matsim.core.controler.AbstractModule;
import org.matsim.core.controler.Controler;
import org.matsim.core.controler.OutputDirectoryHierarchy.OverwriteFileSetting;
+import org.matsim.core.gbl.MatsimRandom;
import org.matsim.core.utils.io.IOUtils;
import org.matsim.examples.ExamplesUtils;
import org.matsim.testcases.MatsimTestUtils;
@@ -366,7 +370,9 @@ void testRunDrtWithPrebooking() {
config.controller().setOutputDirectory(utils.getOutputDirectory());
DrtConfigGroup drtConfig = DrtConfigGroup.getSingleModeDrtConfig(config);
- drtConfig.addParameterSet(new PrebookingParams());
+ PrebookingParams prebookingParams = new PrebookingParams();
+ prebookingParams.abortRejectedPrebookings = false;
+ drtConfig.addParameterSet(prebookingParams);
Controler controller = DrtControlerCreator.createControler(config, false);
ProbabilityBasedPrebookingLogic.install(controller, drtConfig, 0.5, 4.0 * 3600.0);
@@ -384,7 +390,7 @@ void testRunDrtWithPrebooking() {
var expectedStats = Stats.newBuilder()
.rejectionRate(0.04)
.rejections(14)
- .waitAverage(232.47)
+ .waitAverage(232.48)
.inVehicleTravelTimeMean(389.16)
.totalTravelTimeMean(621.63)
.build();
@@ -392,6 +398,39 @@ void testRunDrtWithPrebooking() {
verifyDrtCustomerStatsCloseToExpectedStats(utils.getOutputDirectory(), expectedStats);
}
+
+ @Test
+ void testRunDrtOfferRejectionExample() {
+ Id.resetCaches();
+ URL configUrl = IOUtils.extendUrl(ExamplesUtils.getTestScenarioURL("mielec"),
+ "mielec_stop_based_drt_config.xml");
+ Config config = ConfigUtils.loadConfig(configUrl, new MultiModeDrtConfigGroup(), new DvrpConfigGroup(),
+ new OTFVisConfigGroup());
+
+ config.controller().setOverwriteFileSetting(OverwriteFileSetting.deleteDirectoryIfExists);
+ config.controller().setOutputDirectory(utils.getOutputDirectory());
+
+ Controler controller = DrtControlerCreator.createControler(config, false);
+ controller.addOverridingQSimModule(new AbstractDvrpModeQSimModule("drt") {
+ @Override
+ protected void configureQSim() {
+ bindModal(DrtOfferAcceptor.class).toProvider(modalProvider(getter -> new ProbabilisticOfferAcceptor()));
+ }
+ });
+ controller.run();
+
+
+ var expectedStats = Stats.newBuilder()
+ .rejectionRate(0.46)
+ .rejections(174.0)
+ .waitAverage(222.66)
+ .inVehicleTravelTimeMean(369.74)
+ .totalTravelTimeMean(592.4)
+ .build();
+
+ verifyDrtCustomerStatsCloseToExpectedStats(utils.getOutputDirectory(), expectedStats);
+ }
+
/**
* Early warning system: if customer stats vary more than the defined percentage above or below the expected values
* then the following unit tests will fail. This is meant to serve as a red flag.
@@ -536,4 +575,20 @@ public void install() {
});
}
}
+
+ private static class ProbabilisticOfferAcceptor implements DrtOfferAcceptor {
+
+ private final DefaultOfferAcceptor delegate = new DefaultOfferAcceptor();
+
+ private final Random random = new Random(123);
+
+ @Override
+ public Optional acceptDrtOffer(DrtRequest request, double departureTime, double arrivalTime) {
+ if (random.nextBoolean()) {
+ return Optional.empty();
+ } else {
+ return delegate.acceptDrtOffer(request, departureTime, arrivalTime);
+ }
+ }
+ }
}
diff --git a/contribs/drt/src/test/java/org/matsim/contrib/drt/scheduler/DefaultRequestInsertionSchedulerTest.java b/contribs/drt/src/test/java/org/matsim/contrib/drt/scheduler/DefaultRequestInsertionSchedulerTest.java
new file mode 100644
index 00000000000..b1924ad36b4
--- /dev/null
+++ b/contribs/drt/src/test/java/org/matsim/contrib/drt/scheduler/DefaultRequestInsertionSchedulerTest.java
@@ -0,0 +1,288 @@
+package org.matsim.contrib.drt.scheduler;
+
+import com.google.common.base.Verify;
+import com.google.common.collect.ImmutableList;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.matsim.api.core.v01.Id;
+import org.matsim.api.core.v01.network.Link;
+import org.matsim.contrib.drt.optimizer.VehicleEntry;
+import org.matsim.contrib.drt.optimizer.Waypoint;
+import org.matsim.contrib.drt.optimizer.insertion.InsertionDetourTimeCalculator;
+import org.matsim.contrib.drt.optimizer.insertion.InsertionGenerator;
+import org.matsim.contrib.drt.optimizer.insertion.InsertionWithDetourData;
+import org.matsim.contrib.drt.passenger.AcceptedDrtRequest;
+import org.matsim.contrib.drt.passenger.DrtRequest;
+import org.matsim.contrib.drt.run.examples.RunDrtExampleIT;
+import org.matsim.contrib.drt.schedule.*;
+import org.matsim.contrib.drt.stops.MinimumStopDurationAdapter;
+import org.matsim.contrib.drt.stops.PrebookingStopTimeCalculator;
+import org.matsim.contrib.drt.stops.StaticPassengerStopDurationProvider;
+import org.matsim.contrib.dvrp.fleet.*;
+import org.matsim.contrib.dvrp.optimizer.Request;
+import org.matsim.contrib.dvrp.path.OneToManyPathSearch;
+import org.matsim.contrib.dvrp.path.VrpPathWithTravelData;
+import org.matsim.contrib.dvrp.path.VrpPaths;
+import org.matsim.contrib.dvrp.schedule.*;
+import org.matsim.core.mobsim.framework.MobsimTimer;
+import org.matsim.core.router.util.LeastCostPathCalculator;
+import org.matsim.core.router.util.TravelTime;
+import org.matsim.testcases.MatsimTestUtils;
+import org.matsim.testcases.fakes.FakeLink;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.matsim.contrib.dvrp.path.VrpPaths.NODE_TRANSITION_TIME;
+
+/**
+ * @author nkuehnel / MOIA
+ */
+public class DefaultRequestInsertionSchedulerTest {
+
+ @RegisterExtension
+ public MatsimTestUtils utils = new MatsimTestUtils();
+
+ public static final TravelTime TRAVEL_TIME = (link, time, person, vehicle) -> 10 - NODE_TRANSITION_TIME;
+ public static final double STOP_DURATION = 60.;
+
+ private final static double DRIVE_TIME = 10.;
+
+ public static final double CURRENT_TIME = 10;
+ public static final double R1_PU_TIME = CURRENT_TIME + DRIVE_TIME + STOP_DURATION;
+ public static final double R1_DO_TIME = R1_PU_TIME + DRIVE_TIME;
+
+ //existing on-board request
+ public static final double R2_PU_TIME = 0.;
+ public static final double R2_DO_TIME = R1_DO_TIME + STOP_DURATION + DRIVE_TIME ;
+
+ public static final int R3_PU_TIME = 20;
+ public static final int R3_DO_TIME = 30;
+
+ public static final double ALLOWED_DETOUR = STOP_DURATION + 2 * DRIVE_TIME;
+
+ public static final Id V_1_ID = Id.create("v1", DvrpVehicle.class);
+
+ private final Link from1 = link("from1");
+ private final Link to1 = link("to1");
+
+ private final Link from2 = link("from2");
+ private final Link to2 = link("to2");
+ private final Link from3 = from1;
+ private final Link to3 = link("to3");
+ private final DrtRequest existingRequest1 = request("r1", from1, to1, 0., R1_DO_TIME + ALLOWED_DETOUR, R1_PU_TIME, R1_PU_TIME);
+ private final DrtRequest existingRequest2 = request("r2", from2, to2, 0., R2_DO_TIME + ALLOWED_DETOUR, R2_PU_TIME, R2_PU_TIME);
+ private final DrtRequest newRequest = request("r3", from3, to3, CURRENT_TIME, R3_DO_TIME + ALLOWED_DETOUR, R3_PU_TIME, R3_PU_TIME);
+
+ private static final String mode = "DRT_MODE";
+
+
+ @Test
+ public void testInsertion() {
+ Link startLink = link("start");
+ FleetSpecificationImpl fleetSpecification = new FleetSpecificationImpl();
+ fleetSpecification.addVehicleSpecification(ImmutableDvrpVehicleSpecification.newBuilder()
+ .id(V_1_ID)
+ .startLinkId(startLink.getId())
+ .capacity(6)
+ .serviceBeginTime(0)
+ .serviceEndTime(1000)
+ .build()
+ );
+
+ Fleet fleet = Fleets.createDefaultFleet(fleetSpecification, dvrpVehicleSpecification -> startLink);
+ MobsimTimer timer = new MobsimTimer(1);
+ timer.setTime(CURRENT_TIME);
+ DefaultRequestInsertionScheduler insertionScheduler = getDefaultRequestInsertionScheduler(fleet, timer);
+
+
+ DvrpVehicle vehicle = fleet.getVehicles().get(V_1_ID);
+
+ // vehicle schedule
+ Task task = vehicle.getSchedule().nextTask();
+
+ vehicle.getSchedule().getCurrentTask().setEndTime(CURRENT_TIME);
+ LeastCostPathCalculator.Path path = new LeastCostPathCalculator.Path(null, List.of(), 0., 0);
+ VrpPathWithTravelData vrpPath = VrpPaths.createPath(startLink, existingRequest1.getFromLink(), CURRENT_TIME, path, TRAVEL_TIME);
+ vehicle.getSchedule().addTask(new DrtDriveTask(vrpPath, DrtDriveTask.TYPE));
+
+ DefaultDrtStopTask stopTask0 = new DefaultDrtStopTask(R1_PU_TIME - STOP_DURATION, R1_PU_TIME, from1);
+ AcceptedDrtRequest acceptedExistingRequest = AcceptedDrtRequest.createFromOriginalRequest(existingRequest1);
+ stopTask0.addPickupRequest(acceptedExistingRequest);
+ vehicle.getSchedule().addTask(stopTask0);
+
+ VrpPathWithTravelData vrpPath2 = VrpPaths.createPath(existingRequest1.getFromLink(), existingRequest1.getToLink(), stopTask0.getEndTime(), path, TRAVEL_TIME);
+ vehicle.getSchedule().addTask(new DrtDriveTask(vrpPath2, DrtDriveTask.TYPE));
+
+ DefaultDrtStopTask stopTask1 = new DefaultDrtStopTask(R1_DO_TIME, R1_DO_TIME + STOP_DURATION, to1);
+ stopTask1.addDropoffRequest(acceptedExistingRequest);
+ vehicle.getSchedule().addTask(stopTask1);
+
+ LeastCostPathCalculator.Path longPath = new LeastCostPathCalculator.Path(null, List.of(), 200, 0);
+ VrpPathWithTravelData vrpPath3 = VrpPaths.createPath(existingRequest1.getToLink(), existingRequest2.getToLink(), stopTask1.getEndTime(), longPath, TRAVEL_TIME);
+ vehicle.getSchedule().addTask(new DrtDriveTask(vrpPath3, DrtDriveTask.TYPE));
+
+ DefaultDrtStopTask stopTask2 = new DefaultDrtStopTask(stopTask1.getEndTime() + longPath.travelTime + 10., stopTask1.getEndTime() + longPath.travelTime + STOP_DURATION, to2);
+ AcceptedDrtRequest acceptedExistingRequest2 = AcceptedDrtRequest.createFromOriginalRequest(existingRequest2);
+ stopTask2.addDropoffRequest(acceptedExistingRequest2);
+ vehicle.getSchedule().addTask(stopTask2);
+
+
+ // vehicle entry
+ Waypoint.Start start = start(null, CURRENT_TIME, startLink, 1);//not a STOP -> pickup cannot be appended
+ Waypoint.Stop stop0 = stop(stopTask0, 2);
+ Waypoint.Stop stop1 = stop(stopTask1, 1);
+ Waypoint.Stop stop2 = stop(stopTask2, 0);
+ var vehicleEntry = entry(vehicle, start, stop0, stop1, stop2);
+
+ InsertionWithDetourData.InsertionDetourData detour = detourData(0, 10, 10, 10.);
+ InsertionDetourTimeCalculator.DetourTimeInfo detourTimeInfo = detourTimeInfo();
+ InsertionWithDetourData insertion = insertion(vehicleEntry, 1, 2, detour, newRequest,
+ detourTimeInfo);
+
+ RequestInsertionScheduler.PickupDropoffTaskPair pickupDropoffTaskPair =
+ insertionScheduler.scheduleRequest(AcceptedDrtRequest.createFromOriginalRequest(newRequest), insertion);
+
+ ScheduleInfo actualScheduleInfo = getScheduleInfo(vehicle.getSchedule());
+ ScheduleInfo expectedScheduleInfo = ScheduleInfo.newBuilder()
+ .addTask(new ScheduleBuilder.TaskInfo(0, 0, 10, Task.TaskStatus.STARTED,
+ DrtStayTask.TYPE, Set.of(), Set.of()))
+ .addTask(new ScheduleBuilder.TaskInfo(1, 10, 20, Task.TaskStatus.PLANNED,
+ DrtDriveTask.TYPE, Set.of(), Set.of()))
+ .addTask(new ScheduleBuilder.TaskInfo(2, 20, 80, Task.TaskStatus.PLANNED,
+ DefaultDrtStopTask.TYPE, Set.of(existingRequest1.getId(), newRequest.getId()), Set.of()))
+ .addTask(new ScheduleBuilder.TaskInfo(3, 80, 90, Task.TaskStatus.PLANNED,
+ DrtDriveTask.TYPE, Set.of(), Set.of()))
+ .addTask(new ScheduleBuilder.TaskInfo(4, 90, 150, Task.TaskStatus.PLANNED,
+ DefaultDrtStopTask.TYPE, Set.of(), Set.of(existingRequest1.getId())))
+ .addTask(new ScheduleBuilder.TaskInfo(5, 150, 170, Task.TaskStatus.PLANNED,
+ DrtDriveTask.TYPE, Set.of(), Set.of()))
+ .addTask(new ScheduleBuilder.TaskInfo(6, 170, 230, Task.TaskStatus.PLANNED,
+ DefaultDrtStopTask.TYPE, Set.of(), Set.of(newRequest.getId())))
+ .addTask(new ScheduleBuilder.TaskInfo(7, 230, 250, Task.TaskStatus.PLANNED,
+ DrtDriveTask.TYPE, Set.of(), Set.of()))
+ .addTask(new ScheduleBuilder.TaskInfo(8, 250, 310, Task.TaskStatus.PLANNED,
+ DefaultDrtStopTask.TYPE, Set.of(), Set.of(existingRequest2.getId())))
+ .build();
+
+ compareTwoSchedules(actualScheduleInfo, expectedScheduleInfo);
+
+
+ }
+
+ private InsertionDetourTimeCalculator.DetourTimeInfo detourTimeInfo() {
+ return new InsertionDetourTimeCalculator.DetourTimeInfo(
+ new InsertionDetourTimeCalculator.PickupDetourInfo(R1_PU_TIME + STOP_DURATION, 0.),
+ new InsertionDetourTimeCalculator.DropoffDetourInfo(R1_PU_TIME + STOP_DURATION + DRIVE_TIME, 20.)
+ );
+ }
+
+ private static DefaultRequestInsertionScheduler getDefaultRequestInsertionScheduler(Fleet fleet, MobsimTimer timer) {
+ MinimumStopDurationAdapter stopDuration = new MinimumStopDurationAdapter(new PrebookingStopTimeCalculator(StaticPassengerStopDurationProvider.of(STOP_DURATION, 0.0)), 60.);
+ ScheduleTimingUpdater scheduleTimingUpdater = new ScheduleTimingUpdater(timer, new DrtStayTaskEndTimeCalculator(stopDuration));
+ DefaultRequestInsertionScheduler insertionScheduler = new DefaultRequestInsertionScheduler(fleet, timer, TRAVEL_TIME, scheduleTimingUpdater,
+ new DrtTaskFactoryImpl(), stopDuration, true);
+ return insertionScheduler;
+ }
+
+ private InsertionWithDetourData.InsertionDetourData detourData(double toPickupTT, double fromPickupTT, double toDropoffTT,
+ double fromDropoffTT) {
+ var toPickupDetour = new OneToManyPathSearch.PathData(new LeastCostPathCalculator.Path(null, List.of(), toPickupTT, 0), 0);
+ var fromPickupDetour = new OneToManyPathSearch.PathData(new LeastCostPathCalculator.Path(null, List.of(), fromPickupTT, 0), 0);
+ var toDropoffDetour = new OneToManyPathSearch.PathData(new LeastCostPathCalculator.Path(null, List.of(), toDropoffTT, 0), 0);
+ var fromDropoffDetour = new OneToManyPathSearch.PathData(new LeastCostPathCalculator.Path(null, List.of(), fromDropoffTT, 0), 0);
+ return new InsertionWithDetourData.InsertionDetourData(toPickupDetour, fromPickupDetour, toDropoffDetour, fromDropoffDetour);
+ }
+
+ private InsertionWithDetourData insertion(VehicleEntry entry, int pickupIdx, int dropoffIdx,
+ InsertionWithDetourData.InsertionDetourData detour,
+ DrtRequest drtRequest, InsertionDetourTimeCalculator.DetourTimeInfo detourTimeInfo) {
+ return new InsertionWithDetourData(
+ new InsertionGenerator.Insertion(drtRequest, entry, pickupIdx, dropoffIdx),
+ detour,
+ detourTimeInfo
+ );
+ }
+
+
+ private VehicleEntry entry(DvrpVehicle vehicle, Waypoint.Start start, Waypoint.Stop... stops) {
+ List precedingStayTimes = Collections.nCopies(stops.length, 0.0);
+ return new VehicleEntry(vehicle, start, ImmutableList.copyOf(stops), null, precedingStayTimes, 0);
+ }
+
+ private Waypoint.Start start(Task task, double time, Link link, int occupancy) {
+ return new Waypoint.Start(task, link, time, occupancy);
+ }
+
+ private Waypoint.Stop stop(DefaultDrtStopTask stopTask, int outgoingOccupancy) {
+ return new Waypoint.Stop(stopTask, outgoingOccupancy);
+ }
+
+
+ private DrtRequest request(String id, Link fromLink, Link toLink, double submissionTime,
+ double latestArrivalTime, double earliestStartTime, double latestStartTime) {
+ return DrtRequest.newBuilder()
+ .id(Id.create(id, Request.class))
+ .passengerIds(List.of(Id.createPersonId(id)))
+ .submissionTime(submissionTime)
+ .latestArrivalTime(latestArrivalTime)
+ .latestStartTime(latestStartTime)
+ .earliestStartTime(earliestStartTime)
+ .fromLink(fromLink)
+ .toLink(toLink)
+ .mode(mode)
+ .build();
+ }
+
+ private Link link(String id) {
+ return new FakeLink(Id.createLinkId(id));
+ }
+
+
+
+ private record ScheduleInfo(List taskInfos) {
+ public static ScheduleBuilder newBuilder() {
+ return new ScheduleBuilder();
+ }
+ }
+
+ private static ScheduleInfo getScheduleInfo(Schedule schedule) {
+ ScheduleBuilder scheduleBuilder = ScheduleInfo.newBuilder();
+ for (Task task : schedule.getTasks()) {
+ scheduleBuilder.addTask(new ScheduleBuilder.TaskInfo(task.getTaskIdx(), task.getBeginTime(),
+ task.getEndTime(), task.getStatus(), task.getTaskType(),
+ task instanceof DrtStopTask ? ((DrtStopTask) task).getPickupRequests().keySet(): Set.of(),
+ task instanceof DrtStopTask ? ((DrtStopTask) task).getDropoffRequests().keySet(): Set.of()
+ ));
+ }
+ return scheduleBuilder.build();
+ }
+
+
+ private static class ScheduleBuilder {
+
+ private record TaskInfo(int taskIdx, double beginTime, double endTime, Task.TaskStatus status,
+ Task.TaskType taskType, Set> puRequests, Set> doRequests) {}
+
+ private ScheduleBuilder(){}
+
+
+ private final List taskInfos = new ArrayList<>();
+
+ public ScheduleBuilder addTask(TaskInfo taskInfo) {
+ taskInfos.add(taskInfo.taskIdx, taskInfo);
+ return this;
+ }
+
+ public ScheduleInfo build() {
+ return new ScheduleInfo(taskInfos);
+ }
+ }
+
+ private static void compareTwoSchedules(ScheduleInfo actualScheduleInfo, ScheduleInfo expectedScheduleInfo) {
+ assertThat(actualScheduleInfo).usingRecursiveComparison().isEqualTo(expectedScheduleInfo);
+ }
+}
\ No newline at end of file
diff --git a/contribs/drt/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationWithModeChoiceTest.java b/contribs/drt/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationWithModeChoiceTest.java
index effd09b64ac..0e035acb518 100644
--- a/contribs/drt/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationWithModeChoiceTest.java
+++ b/contribs/drt/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationWithModeChoiceTest.java
@@ -6,7 +6,6 @@
import org.matsim.api.core.v01.TransportMode;
import org.matsim.api.core.v01.network.Network;
import org.matsim.contrib.drt.estimator.DrtEstimator;
-import org.matsim.contrib.drt.estimator.impl.DetourBasedDrtEstimator;
import org.matsim.contrib.drt.estimator.impl.EuclideanDistanceBasedDrtEstimator;
import org.matsim.contrib.drt.run.DrtConfigGroup;
import org.matsim.contrib.drt.run.DrtControlerCreator;
@@ -72,8 +71,6 @@ void testModeChoice() {
controler.addOverridingModule(new AbstractDvrpModeModule(drtConfigGroup.mode) {
@Override
public void install() {
-// bindModal(DrtEstimator.class).toInstance(DetourBasedDrtEstimator.normalDistributed(1.2, 32,
-// 0.3, 300, 0.4));
bindModal(DrtEstimator.class).toProvider(modalProvider(getter -> new
EuclideanDistanceBasedDrtEstimator(getter.getModal(Network.class), 2.0, 0.1577493,
103.0972273, 120, 0.3, -0.1, 0.28)));
diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/DefaultPassengerEngine.java b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/DefaultPassengerEngine.java
index 7406ceaa359..96571f584da 100644
--- a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/DefaultPassengerEngine.java
+++ b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/DefaultPassengerEngine.java
@@ -153,7 +153,7 @@ private void handleGroupDepartures(double now) {
private void handleDepartureImpl(double now, List group) {
List> groupIds = group.stream().map(Identifiable::getId).toList();
- MobsimPassengerAgent representative = group.get(0);
+ MobsimPassengerAgent representative = group.getFirst();
Id fromLinkId = representative.getCurrentLinkId();
Id toLinkId = representative.getDestinationLinkId();
diff --git a/contribs/dvrp/src/test/java/org/matsim/contrib/dvrp/router/DiversionTest.java b/contribs/dvrp/src/test/java/org/matsim/contrib/dvrp/router/DiversionTest.java
index ed2c0c27587..16e1f5be09f 100644
--- a/contribs/dvrp/src/test/java/org/matsim/contrib/dvrp/router/DiversionTest.java
+++ b/contribs/dvrp/src/test/java/org/matsim/contrib/dvrp/router/DiversionTest.java
@@ -51,6 +51,7 @@
import org.matsim.core.config.ConfigUtils;
import org.matsim.core.config.groups.QSimConfigGroup;
import org.matsim.core.config.groups.QSimConfigGroup.StarttimeInterpretation;
+import org.matsim.core.config.groups.RoutingConfigGroup;
import org.matsim.core.controler.Controler;
import org.matsim.core.controler.OutputDirectoryHierarchy.OverwriteFileSetting;
import org.matsim.core.mobsim.framework.MobsimTimer;
@@ -124,7 +125,7 @@ void testRepeatedSameDestinationDiversions() {
{
/* Create some necessary configuration for the test */
-
+ config.routing().setNetworkRouteConsistencyCheck(RoutingConfigGroup.NetworkRouteConsistencyCheck.disable);
config.controller().setOverwriteFileSetting(OverwriteFileSetting.deleteDirectoryIfExists);
config.controller().setLastIteration(0);
@@ -454,6 +455,7 @@ void testRepeatedDiversionToDifferentDestinationRightBeforeLastLink() {
config.controller().setOverwriteFileSetting(OverwriteFileSetting.deleteDirectoryIfExists);
config.controller().setLastIteration(0);
+ config.routing().setNetworkRouteConsistencyCheck(RoutingConfigGroup.NetworkRouteConsistencyCheck.disable);
config.qsim().setStartTime(0.0);
config.qsim().setSimStarttimeInterpretation(StarttimeInterpretation.onlyUseStarttime);
diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestPositionEmissionModule.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestPositionEmissionModule.java
index f1824def7cd..a3059795499 100644
--- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestPositionEmissionModule.java
+++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestPositionEmissionModule.java
@@ -18,11 +18,7 @@
import org.matsim.contrib.emissions.utils.EmissionsConfigGroup;
import org.matsim.core.api.experimental.events.EventsManager;
import org.matsim.core.config.ConfigUtils;
-import org.matsim.core.config.groups.ControllerConfigGroup;
-import org.matsim.core.config.groups.NetworkConfigGroup;
-import org.matsim.core.config.groups.ReplanningConfigGroup;
-import org.matsim.core.config.groups.ScoringConfigGroup;
-import org.matsim.core.config.groups.QSimConfigGroup;
+import org.matsim.core.config.groups.*;
import org.matsim.core.controler.AbstractModule;
import org.matsim.core.controler.Controler;
import org.matsim.core.controler.OutputDirectoryHierarchy;
@@ -91,6 +87,7 @@ void compareToOtherModule_singleVehicleSingleLink() {
var config = ConfigUtils.loadConfig(configFile, emissionConfig);
config.controller().setOverwriteFileSetting(OutputDirectoryHierarchy.OverwriteFileSetting.deleteDirectoryIfExists);
config.controller().setOutputDirectory(testUtils.getOutputDirectory());
+ config.routing().setNetworkRouteConsistencyCheck(RoutingConfigGroup.NetworkRouteConsistencyCheck.disable);
emissionConfig.setAverageColdEmissionFactorsFile("../sample_41_EFA_ColdStart_vehcat_2020average.csv");
emissionConfig.setAverageWarmEmissionFactorsFile( "../sample_41_EFA_HOT_vehcat_2020average.csv" );
diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierDriverAgent.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierDriverAgent.java
index 00233bbbf18..c7f030f3457 100644
--- a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierDriverAgent.java
+++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierDriverAgent.java
@@ -97,6 +97,10 @@ void handleAnEvent(Event event){
case LinkEnterEvent linkEnterEvent -> handleEvent(linkEnterEvent);
case ActivityEndEvent activityEndEvent -> handleEvent(activityEndEvent);
case ActivityStartEvent activityStartEvent -> handleEvent(activityStartEvent);
+ case VehicleEntersTrafficEvent vehicleEntersTrafficEvent -> handleEvent(vehicleEntersTrafficEvent);
+ case VehicleLeavesTrafficEvent vehicleLeavesTrafficEvent -> handleEvent(vehicleLeavesTrafficEvent);
+ case PersonMoneyEvent personMoneyEvent -> handleEvent( personMoneyEvent );
+ case PersonScoreEvent personScoreEvent -> handleEvent( personScoreEvent );
case null, default -> createAdditionalEvents(event, null, scheduledTour, driverId, planElementCounter);
}
}
@@ -145,6 +149,33 @@ private void handleEvent( LinkEnterEvent event ){
createAdditionalEvents( event, null, scheduledTour, driverId, planElementCounter );
}
+ private void handleEvent( PersonScoreEvent event ){
+ if( scoringFunction != null ){
+ scoringFunction.handleEvent( event );
+ }
+ }
+
+ private void handleEvent( PersonMoneyEvent event ){
+ if( scoringFunction != null ){
+ scoringFunction.handleEvent( event );
+ }
+ }
+
+ private void handleEvent( VehicleEntersTrafficEvent event ){
+ if( scoringFunction != null ){
+ scoringFunction.handleEvent( event );
+ }
+ if ((Event) event instanceof VehicleEntersTrafficEvent vehicleEntersTrafficEvent) {
+ driver2EventHandler.handleEvent(vehicleEntersTrafficEvent);
+ }
+ }
+
+ private void handleEvent( VehicleLeavesTrafficEvent event ){
+ if( scoringFunction != null ){
+ scoringFunction.handleEvent( event );
+ }
+ }
+
private void handleEvent( ActivityEndEvent event ){
if( currentActivity == null ){
Activity firstActivity = PopulationUtils.createActivityFromLinkId( event.getActType(), event.getLinkId() );
@@ -196,7 +227,6 @@ private void createAdditionalEvents( Event event, Activity activity, ScheduledTo
// if( scoringFunction == null ){
// (means "called from LSP". kai, jul'22)
- driver2EventHandler.handleAnEvent(event);
Id vehicleId = driver2EventHandler.getVehicleOfDriver(driverId);
// Reason why this here is needed is that the more informative objects such as ScheduledTour cannot be
@@ -271,15 +301,6 @@ public Id getVehicleOfDriver(Id personId){
return driversVehicles.get(personId);
}
- public void handleAnEvent(Event event){
- if (event instanceof VehicleEntersTrafficEvent vehicleEntersTrafficEvent) {
- driver2EventHandler.handleEvent(vehicleEntersTrafficEvent);
- }
- if (event instanceof VehicleEntersTrafficEvent vehicleEntersTrafficEvent) {
- driver2EventHandler.handleEvent(vehicleEntersTrafficEvent);
- }
- }
-
}
}
diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierVehicleReRouter.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierVehicleReRouter.java
index 4a75e5c607d..cd03cb5fd94 100644
--- a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierVehicleReRouter.java
+++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierVehicleReRouter.java
@@ -36,6 +36,7 @@
import com.graphhopper.jsprit.io.algorithm.AlgorithmConfigXmlReader;
import com.graphhopper.jsprit.io.algorithm.VehicleRoutingAlgorithms;
import org.matsim.api.core.v01.network.Network;
+import org.matsim.contrib.roadpricing.RoadPricingScheme;
import org.matsim.core.replanning.ReplanningContext;
import org.matsim.core.replanning.modules.GenericPlanStrategyModule;
import org.matsim.core.router.util.TravelTime;
@@ -58,7 +59,7 @@ class CarrierVehicleReRouter implements GenericPlanStrategyModule{
private final VehicleRoutingActivityCosts vehicleRoutingActivityCosts;
- public CarrierVehicleReRouter( Network network, CarrierVehicleTypes vehicleTypes, TravelTime travelTimes, String vrpAlgoConfigFile, VehicleTypeDependentRoadPricingCalculator roadPricing ) {
+ public CarrierVehicleReRouter( Network network, CarrierVehicleTypes vehicleTypes, TravelTime travelTimes, String vrpAlgoConfigFile, RoadPricingScheme roadPricing ) {
this.network = network;
vehicleRoutingTransportCosts = getNetworkBasedTransportCosts(network,vehicleTypes,travelTimes,roadPricing);
vehicleRoutingActivityCosts = new VehicleRoutingActivityCosts() {
@@ -146,7 +147,7 @@ public void handlePlan(CarrierPlan carrierPlan) {
}
- private NetworkBasedTransportCosts getNetworkBasedTransportCosts(Network network, CarrierVehicleTypes vehicleTypes, TravelTime travelTimes, VehicleTypeDependentRoadPricingCalculator roadPricing) {
+ private NetworkBasedTransportCosts getNetworkBasedTransportCosts(Network network, CarrierVehicleTypes vehicleTypes, TravelTime travelTimes, RoadPricingScheme roadPricing ) {
//******
//Define transport-costs
//******
@@ -157,7 +158,7 @@ private NetworkBasedTransportCosts getNetworkBasedTransportCosts(Network network
//sets time-dependent travelTimes
tpcostsBuilder.setTravelTime(travelTimes);
- if(roadPricing != null) tpcostsBuilder.setRoadPricingCalculator(roadPricing);
+ if(roadPricing != null) tpcostsBuilder.setRoadPricingScheme(roadPricing );
//sets time-slice to build time-dependent tpcosts and travelTime matrices
tpcostsBuilder.setTimeSliceWidth(900);
diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCosts.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCosts.java
index f332b84cb0b..e6d8e1a0e45 100644
--- a/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCosts.java
+++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCosts.java
@@ -30,6 +30,8 @@
import org.matsim.api.core.v01.network.Link;
import org.matsim.api.core.v01.network.Network;
import org.matsim.api.core.v01.population.Person;
+import org.matsim.contrib.roadpricing.RoadPricingScheme;
+import org.matsim.contrib.roadpricing.RoadPricingSchemeImpl;
import org.matsim.core.router.speedy.SpeedyALTFactory;
import org.matsim.core.router.util.LeastCostPathCalculator;
import org.matsim.core.router.util.LeastCostPathCalculator.Path;
@@ -83,6 +85,8 @@
*/
public class NetworkBasedTransportCosts implements VRPTransportCosts {
+ private final RoadPricingScheme roadPricingScheme;
+
public interface InternalLeastCostPathCalculatorListener {
void startCalculation(long routerId);
@@ -316,27 +320,34 @@ private static class VehicleTypeVarCosts {
*/
static class VehicleTransportCostsIncludingToll implements TravelDisutility {
-// private static Logger logger = LogManager.getLogger(VehicleTransportCostsIncludingToll.class);
private final TravelDisutility baseTransportDisutility;
- private final VehicleTypeDependentRoadPricingCalculator vehicleTypeDependentPricingCalculator;
+ private final RoadPricingScheme roadPricingScheme;
- public VehicleTransportCostsIncludingToll(TravelDisutility baseTransportDisutility,
- VehicleTypeDependentRoadPricingCalculator vehicleTypeDependentPricingCalculator) {
+ public VehicleTransportCostsIncludingToll( TravelDisutility baseTransportDisutility,
+ RoadPricingScheme roadPricingScheme ) {
super();
this.baseTransportDisutility = baseTransportDisutility;
- this.vehicleTypeDependentPricingCalculator = vehicleTypeDependentPricingCalculator;
-// System.out.println("huuuuuuuuuuuuuuuuuuuu - initialize transport costs with toll");
+ this.roadPricingScheme = roadPricingScheme;
}
@Override
public double getLinkTravelDisutility(Link link, double time, Person person,
org.matsim.vehicles.Vehicle vehicle) {
double costs = baseTransportDisutility.getLinkTravelDisutility(link, time, person, vehicle);
- Id typeId = vehicle.getType().getId();
- double toll = vehicleTypeDependentPricingCalculator.getTollAmount(typeId, link, time);
-// System.out.println("huuuuuuuuuuuuuuuuuuuu - paid toll");
+
+ RoadPricingSchemeImpl.Cost costInfo;
+ if (person == null) {
+ costInfo = roadPricingScheme.getLinkCostInfo( link.getId(), time, null, vehicle.getId() );
+ } else {
+ costInfo = roadPricingScheme.getLinkCostInfo( link.getId(), time, person.getId(), vehicle.getId() );
+ }
+
+ double toll = 0.;
+ if ( costInfo != null ){
+ toll = costInfo.amount;
+ }
return costs + toll;
}
@@ -377,7 +388,8 @@ public static Builder newInstance(Network network) {
private LeastCostPathCalculatorFactory leastCostPathCalculatorFactory = (network, travelCosts, travelTimes) -> new SpeedyALTFactory().createPathCalculator(network, travelCosts, travelTime);
- private VehicleTypeDependentRoadPricingCalculator roadPricingCalculator = new VehicleTypeDependentRoadPricingCalculator();
+// private VehicleTypeDependentRoadPricingCalculator roadPricingScheme = new VehicleTypeDependentRoadPricingCalculator();
+ private RoadPricingScheme roadPricingScheme;
private boolean withToll = false;
@@ -393,7 +405,7 @@ public static Builder newInstance(Network network) {
* Creates the builder requiring {@link Network} and a collection of
* {@link VehicleType}.
*
- * @param network
+ * @param network the MATSim network
* @param vehicleTypes must be all vehicleTypes and their assigned
* costInformation in the system.
*/
@@ -414,7 +426,7 @@ private void retrieveTypeSpecificCosts(Collection vehicleTypes) {
* Sets the travelTime. By default, travelTime is based on
* link.getFreespeed();.
*
- * @param travelTime
+ * @param travelTime the travelTime to set
* @return this builder
*/
public Builder setTravelTime(TravelTime travelTime) {
@@ -463,7 +475,7 @@ public Builder setFIFO(boolean isFIFO) {
*
* By default, it use {@link SpeedyALTFactory}
*
- * @param {@link {@link LeastCostPathCalculatorFactory}
+ * @param leastCostPathCalcFactory {@link LeastCostPathCalculatorFactory}
* @return this builder
*/
public Builder setThreadSafeLeastCostPathCalculatorFactory(
@@ -472,9 +484,9 @@ public Builder setThreadSafeLeastCostPathCalculatorFactory(
return this;
}
- public Builder setRoadPricingCalculator(VehicleTypeDependentRoadPricingCalculator calculator) {
+ public Builder setRoadPricingScheme( RoadPricingScheme roadPricingScheme) {
withToll = true;
- this.roadPricingCalculator = calculator;
+ this.roadPricingScheme = roadPricingScheme;
return this;
}
@@ -501,7 +513,7 @@ public NetworkBasedTransportCosts build() {
baseDisutility = new BaseVehicleTransportCosts(typeSpecificCosts, travelTime);
}
if (withToll) {
- finalDisutility = new VehicleTransportCostsIncludingToll(baseDisutility, roadPricingCalculator);
+ finalDisutility = new VehicleTransportCostsIncludingToll(baseDisutility, roadPricingScheme );
} else
finalDisutility = baseDisutility;
return new NetworkBasedTransportCosts(this);
@@ -511,10 +523,10 @@ public NetworkBasedTransportCosts build() {
* Adds type-specific costs. If typeId already exists, existing entry is
* overwritten.
*
- * @param typeId
- * @param fix
- * @param perSecond
- * @param perMeter
+ * @param typeId the vehicleType-id as String
+ * @param fix fix costs for the vehicle
+ * @param perSecond variable costs per second
+ * @param perMeter variable costs per meter
*/
public void addVehicleTypeSpecificCosts(String typeId, double fix, double perSecond, double perMeter) {
typeSpecificCosts.put(typeId, new VehicleTypeVarCosts(perMeter, perSecond));
@@ -551,8 +563,6 @@ public void addVehicleTypeSpecificCosts(String typeId, double fix, double perSec
private final Map matsimVehicles = new HashMap<>();
- private final VehicleTypeDependentRoadPricingCalculator roadPricingCalc;
-
/**
* by default sets the {@link SpeedyALTFactory}
*/
@@ -568,7 +578,7 @@ private NetworkBasedTransportCosts(Builder builder) {
this.travelTime = builder.travelTime;
this.network = builder.network;
this.leastCostPathCalculatorFactory = builder.leastCostPathCalculatorFactory;
- this.roadPricingCalc = builder.roadPricingCalculator;
+ this.roadPricingScheme = builder.roadPricingScheme;
this.timeSliceWidth = builder.timeSliceWidth;
this.defaultTypeId = builder.defaultTypeId;
this.ttMemorizedCounter = new Counter("#TransportCostValues cached ");
@@ -585,7 +595,7 @@ private NetworkBasedTransportCosts(Builder builder) {
* cached travel-time. If not, it computes and caches new values with the
* leastCostPathCalc defined in here.
*
- * @Throws {@link IllegalStateException} if vehicle is null
+ * @exception IllegalStateException if vehicle is null
*/
@Override
public double getTransportTime(Location fromId, Location toId, double departureTime, Driver driver,
@@ -666,7 +676,7 @@ private void informStartCalc() {
* cached travel-cost value. If not, it computes and caches new values with the
* leastCostPathCalc defined in here.
*
- * @Throws {@link IllegalStateException} if vehicle is null
+ * @exception IllegalStateException if vehicle is null
*/
@Override
public double getTransportCost(Location fromId, Location toId, double departureTime, Driver driver,
@@ -734,7 +744,7 @@ public double getTransportCost(Location fromId, Location toId, double departureT
* cached distance. If not, it computes and caches new values with the
* leastCostPathCalc defined in here.
*
- * @Throws {@link IllegalStateException} if vehicle is null
+ * @exception IllegalStateException if vehicle is null
*/
@Override
public double getDistance(Location fromId, Location toId, double departureTime, Vehicle vehicle) {
@@ -799,7 +809,7 @@ public Collection getInternalListeners(
* This is a rather bad approximation. If you require this, you should implement
* another {@link VehicleRoutingTransportCosts}
*
- * @Throws {@link IllegalStateException} if vehicle is null
+ * @exception IllegalStateException if vehicle is null
*/
@Override
public double getBackwardTransportCost(Location fromId, Location toId, double arrivalTime, Driver driver,
@@ -815,7 +825,7 @@ public double getBackwardTransportCost(Location fromId, Location toId, double ar
* This is a rather bad approximation. If you require this, you should implement
* another {@link VehicleRoutingTransportCosts}.
*
- * @Throws {@link IllegalStateException} if vehicle is null
+ * @exception IllegalStateException if vehicle is null
*/
@Override
public double getBackwardTransportTime(Location fromId, Location toId, double arrivalTime, Driver driver,
@@ -862,7 +872,7 @@ private int getTimeSlice(double time) {
/**
* Gets the network the calculation is based on.
*
- * @return
+ * @return the network
*/
public Network getNetwork() {
return network;
@@ -877,13 +887,4 @@ public TravelTime getTravelTime() {
return travelTime;
}
- /**
- * Gets the {@link VehicleTypeDependentRoadPricingCalculator}
- *
- * @return {@link VehicleTypeDependentRoadPricingCalculator}
- */
- public VehicleTypeDependentRoadPricingCalculator getRoadPricingCalculator() {
- return roadPricingCalc;
- }
-
}
diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/VehicleTypeDependentRoadPricingCalculator.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/VehicleTypeDependentRoadPricingCalculator.java
index ed5d3694720..6175780ab9a 100644
--- a/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/VehicleTypeDependentRoadPricingCalculator.java
+++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/VehicleTypeDependentRoadPricingCalculator.java
@@ -35,6 +35,7 @@
* @author stefan schröder
*
*/
+@Deprecated // use RoadPricingScheme
public class VehicleTypeDependentRoadPricingCalculator {
interface TollCalculator {
diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierModuleTest.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierModuleTest.java
index b0d4922fcf9..49dc173dd05 100644
--- a/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierModuleTest.java
+++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierModuleTest.java
@@ -27,6 +27,7 @@
import org.matsim.api.core.v01.Scenario;
import org.matsim.core.config.Config;
import org.matsim.core.config.ConfigUtils;
+import org.matsim.core.config.groups.RoutingConfigGroup;
import org.matsim.core.config.groups.ScoringConfigGroup;
import org.matsim.core.controler.AbstractModule;
import org.matsim.core.controler.Controler;
@@ -53,6 +54,7 @@ public class CarrierModuleTest {
@BeforeEach
public void setUp(){
Config config = ConfigUtils.createConfig() ;
+ config.routing().setNetworkRouteConsistencyCheck(RoutingConfigGroup.NetworkRouteConsistencyCheck.disable);
ScoringConfigGroup.ActivityParams workParams = new ScoringConfigGroup.ActivityParams("w");
workParams.setTypicalDuration(60 * 60 * 8);
config.scoring().addActivityParams(workParams);
diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/controler/EquilWithCarrierWithPersonsIT.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/controler/EquilWithCarrierWithPersonsIT.java
index acfb8eab226..75800bfd34d 100644
--- a/contribs/freight/src/test/java/org/matsim/freight/carriers/controler/EquilWithCarrierWithPersonsIT.java
+++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/controler/EquilWithCarrierWithPersonsIT.java
@@ -30,6 +30,7 @@
import org.matsim.core.config.Config;
import org.matsim.core.config.ConfigUtils;
import org.matsim.core.config.groups.ReplanningConfigGroup.StrategySettings;
+import org.matsim.core.config.groups.RoutingConfigGroup;
import org.matsim.core.config.groups.ScoringConfigGroup.ActivityParams;
import org.matsim.core.controler.AbstractModule;
import org.matsim.core.controler.Controler;
@@ -57,6 +58,8 @@ static Config commonConfig( MatsimTestUtils testUtils ) {
config.controller().setOutputDirectory(testUtils.getOutputDirectory());
config.network().setInputFile( testUtils.getClassInputDirectory() + "network.xml" );
+ config.routing().setNetworkRouteConsistencyCheck(RoutingConfigGroup.NetworkRouteConsistencyCheck.disable);
+
return config;
}
diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/controler/EquilWithCarrierWithoutPersonsIT.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/controler/EquilWithCarrierWithoutPersonsIT.java
index 83f1dd9e021..70b01111b10 100644
--- a/contribs/freight/src/test/java/org/matsim/freight/carriers/controler/EquilWithCarrierWithoutPersonsIT.java
+++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/controler/EquilWithCarrierWithoutPersonsIT.java
@@ -30,6 +30,7 @@
import org.matsim.api.core.v01.Scenario;
import org.matsim.core.config.Config;
import org.matsim.core.config.ConfigUtils;
+import org.matsim.core.config.groups.RoutingConfigGroup;
import org.matsim.core.controler.AbstractModule;
import org.matsim.core.controler.Controler;
import org.matsim.freight.carriers.FreightCarriersConfigGroup;
@@ -50,6 +51,7 @@ public class EquilWithCarrierWithoutPersonsIT {
public void setUp() {
Config config = EquilWithCarrierWithPersonsIT.commonConfig( testUtils );
+ config.routing().setNetworkRouteConsistencyCheck(RoutingConfigGroup.NetworkRouteConsistencyCheck.disable);
Scenario scenario = EquilWithCarrierWithPersonsIT.commonScenario( config, testUtils );
controler = new Controler(scenario);
}
diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java
index ccdb7095162..64e7eeba641 100644
--- a/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java
+++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java
@@ -27,16 +27,21 @@
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
+import org.matsim.api.core.v01.Coord;
import org.matsim.api.core.v01.Id;
import org.matsim.api.core.v01.Scenario;
import org.matsim.api.core.v01.network.Network;
+import org.matsim.contrib.roadpricing.*;
import org.matsim.core.config.Config;
import org.matsim.core.network.io.MatsimNetworkReader;
import org.matsim.core.scenario.ScenarioUtils;
+import org.matsim.core.utils.misc.Time;
+import org.matsim.freight.carriers.CarrierVehicle;
import org.matsim.testcases.MatsimTestUtils;
import org.matsim.vehicles.CostInformation;
import org.matsim.vehicles.VehicleType;
import org.matsim.vehicles.VehicleUtils;
+import org.matsim.vehicles.VehiclesFactory;
import java.util.Arrays;
@@ -47,6 +52,8 @@
public class NetworkBasedTransportCostsTest {
+ private static final String TYPE_1 = "type1";
+ private static final String TYPE_2 = "type2";
@RegisterExtension
public final MatsimTestUtils utils = new MatsimTestUtils();
@@ -60,21 +67,21 @@ void test_whenAddingTwoDifferentVehicleTypes_itMustAccountForThem(){
Network network = scenario.getNetwork();
NetworkBasedTransportCosts.Builder builder = NetworkBasedTransportCosts.Builder.newInstance(network);
- builder.addVehicleTypeSpecificCosts("type1", 10.0, 0.0, 2.0);
- builder.addVehicleTypeSpecificCosts("type2", 20.0, 0.0, 4.0);
+ builder.addVehicleTypeSpecificCosts(TYPE_1, 10.0, 0.0, 2.0);
+ builder.addVehicleTypeSpecificCosts(TYPE_2, 20.0, 0.0, 4.0);
NetworkBasedTransportCosts c = builder.build();
Vehicle vehicle1 = mock(Vehicle.class);
com.graphhopper.jsprit.core.problem.vehicle.VehicleType type1 = mock( com.graphhopper.jsprit.core.problem.vehicle.VehicleType.class );
when(type1.getMaxVelocity()).thenReturn(5.0);
- when(type1.getTypeId()).thenReturn("type1");
+ when(type1.getTypeId()).thenReturn(TYPE_1);
when(vehicle1.getType()).thenReturn(type1);
when(vehicle1.getId()).thenReturn("vehicle1");
Vehicle vehicle2 = mock(Vehicle.class);
com.graphhopper.jsprit.core.problem.vehicle.VehicleType type2 = mock( com.graphhopper.jsprit.core.problem.vehicle.VehicleType.class );
when(type2.getMaxVelocity()).thenReturn(5.0);
- when(type2.getTypeId()).thenReturn("type2");
+ when(type2.getTypeId()).thenReturn(TYPE_2);
when(vehicle2.getType()).thenReturn(type2);
when(vehicle2.getId()).thenReturn("vehicle2");
@@ -94,8 +101,8 @@ void test_whenVehicleTypeNotKnow_throwException(){
Network network = scenario.getNetwork();
NetworkBasedTransportCosts.Builder builder = NetworkBasedTransportCosts.Builder.newInstance(network);
- builder.addVehicleTypeSpecificCosts("type1", 10.0, 0.0, 2.0);
- builder.addVehicleTypeSpecificCosts("type2", 20.0, 0.0, 4.0);
+ builder.addVehicleTypeSpecificCosts(TYPE_1, 10.0, 0.0, 2.0);
+ builder.addVehicleTypeSpecificCosts(TYPE_2, 20.0, 0.0, 4.0);
NetworkBasedTransportCosts c = builder.build();
Vehicle vehicle2 = mock(Vehicle.class);
@@ -120,14 +127,14 @@ void test_whenAddingTwoVehicleTypesViaConstructor_itMustAccountForThat(){
String NETWORK_FILENAME = utils.getClassInputDirectory() + "network.xml";
new MatsimNetworkReader(scenario.getNetwork()).readFile(NETWORK_FILENAME);
- VehicleType vehType1 = VehicleUtils.getFactory().createVehicleType(Id.create( "type1", VehicleType.class ));
+ VehicleType vehType1 = VehicleUtils.getFactory().createVehicleType(Id.create(TYPE_1, VehicleType.class ));
CostInformation costInformation1 = vehType1.getCostInformation() ;
costInformation1.setFixedCost( 0.0 );
costInformation1.setCostsPerMeter( 2.0 );
costInformation1.setCostsPerSecond( 0.0 );
- VehicleType vehType2 = VehicleUtils.getFactory().createVehicleType(Id.create( "type2", VehicleType.class ));
+ VehicleType vehType2 = VehicleUtils.getFactory().createVehicleType(Id.create(TYPE_2, VehicleType.class ));
CostInformation costInformation = vehType2.getCostInformation() ;
costInformation.setFixedCost( 0.0 );
@@ -136,20 +143,20 @@ void test_whenAddingTwoVehicleTypesViaConstructor_itMustAccountForThat(){
Network network = scenario.getNetwork();
NetworkBasedTransportCosts.Builder builder =
- NetworkBasedTransportCosts.Builder.newInstance(network,Arrays.asList(vehType1,vehType2));
+ NetworkBasedTransportCosts.Builder.newInstance(network,Arrays.asList(vehType1,vehType2));
NetworkBasedTransportCosts networkBasedTransportCosts = builder.build();
Vehicle vehicle1 = mock(Vehicle.class);
com.graphhopper.jsprit.core.problem.vehicle.VehicleType type1 = mock( com.graphhopper.jsprit.core.problem.vehicle.VehicleType.class );
when(type1.getMaxVelocity()).thenReturn(5.0);
- when(type1.getTypeId()).thenReturn("type1");
+ when(type1.getTypeId()).thenReturn(TYPE_1);
when(vehicle1.getType()).thenReturn(type1);
when(vehicle1.getId()).thenReturn("vehicle1");
Vehicle vehicle2 = mock(Vehicle.class);
com.graphhopper.jsprit.core.problem.vehicle.VehicleType type2 = mock( com.graphhopper.jsprit.core.problem.vehicle.VehicleType.class );
when(type2.getMaxVelocity()).thenReturn(5.0);
- when(type2.getTypeId()).thenReturn("type2");
+ when(type2.getTypeId()).thenReturn(TYPE_2);
when(vehicle2.getType()).thenReturn(type2);
when(vehicle2.getId()).thenReturn("vehicle2");
@@ -159,4 +166,211 @@ void test_whenAddingTwoVehicleTypesViaConstructor_itMustAccountForThat(){
Assertions.assertEquals(20000.0, networkBasedTransportCosts.getDistance(Location.newInstance("6"), Location.newInstance("21"), 0.0, vehicle2), 0.01);
}
+
+ /**
+ * This test is a modified version of {@link #test_whenAddingTwoDifferentVehicleTypes_itMustAccountForThem}
+ * In addition, there is added a road pricing scheme to toll all vehicles
+ */
+ @Test
+ void test_whenAddingTwoDifferentVehicleTypes_tollAllTypes(){
+ Config config = new Config();
+ config.addCoreModules();
+ Scenario scenario = ScenarioUtils.createScenario(config);
+ new MatsimNetworkReader(scenario.getNetwork()).readFile(utils.getClassInputDirectory() + "network.xml");
+
+ //Create Rp Scheme from code.
+ RoadPricingSchemeImpl scheme = RoadPricingUtils.addOrGetMutableRoadPricingScheme(scenario );
+ /* Configure roadpricing scheme. */
+ RoadPricingUtils.setName(scheme, "DemoToll4Test");
+ RoadPricingUtils.setType(scheme, RoadPricingScheme.TOLL_TYPE_LINK);
+ RoadPricingUtils.setDescription(scheme, "Tolling scheme for test.");
+
+ /* Add general link based toll for one link */
+ RoadPricingUtils.addLink(scheme, Id.createLinkId("21"));
+ RoadPricingUtils.createAndAddGeneralCost(scheme, Time.parseTime("00:00:00"), Time.parseTime("72:00:00"), 99.99);
+
+ NetworkBasedTransportCosts.Builder builder = NetworkBasedTransportCosts.Builder.newInstance(scenario.getNetwork());
+ builder.addVehicleTypeSpecificCosts(TYPE_1, 10.0, 0.0, 2.0);
+ builder.addVehicleTypeSpecificCosts(TYPE_2, 20.0, 0.0, 4.0);
+ builder.setRoadPricingScheme(scheme);
+ NetworkBasedTransportCosts c = builder.build();
+
+ Vehicle vehicle1 = mock(Vehicle.class);
+ com.graphhopper.jsprit.core.problem.vehicle.VehicleType type1 = mock( com.graphhopper.jsprit.core.problem.vehicle.VehicleType.class );
+ when(type1.getMaxVelocity()).thenReturn(5.0);
+ when(type1.getTypeId()).thenReturn(TYPE_1);
+ when(vehicle1.getType()).thenReturn(type1);
+ when(vehicle1.getId()).thenReturn("vehicle1");
+
+ Vehicle vehicle2 = mock(Vehicle.class);
+ com.graphhopper.jsprit.core.problem.vehicle.VehicleType type2 = mock( com.graphhopper.jsprit.core.problem.vehicle.VehicleType.class );
+ when(type2.getMaxVelocity()).thenReturn(5.0);
+ when(type2.getTypeId()).thenReturn(TYPE_2);
+ when(vehicle2.getType()).thenReturn(type2);
+ when(vehicle2.getId()).thenReturn("vehicle2");
+
+ //vehicle1: includes toll
+ Assertions.assertEquals(20099.99, c.getTransportCost(Location.newInstance("20"), Location.newInstance("21"), 0.0, mock(Driver.class), vehicle1), 0.01);
+ Assertions.assertEquals(20000.0, c.getDistance(Location.newInstance("6"), Location.newInstance("21"), 0.0, vehicle1), 0.01);
+
+ //vehicle 2: no toll
+ Assertions.assertEquals(40099.99, c.getTransportCost(Location.newInstance("20"), Location.newInstance("21"), 0.0, mock(Driver.class), vehicle2), 0.01);
+ Assertions.assertEquals(20000.0, c.getDistance(Location.newInstance("6"), Location.newInstance("21"), 0.0, vehicle2), 0.01);
+ }
+
+ /**
+ * This test is a modified version of {@link #test_whenAddingTwoDifferentVehicleTypes_itMustAccountForThem}
+ * In addition, there is added a road pricing scheme.
+ * The scheme is only set for one vehicle type: type1.
+ * So, only the vehicle using that type (vehicle1) should be tolled, the other (vehicle2) not.
+ * This test is build, in a way, that it uses the MATSim infrastructure for filtering the vehicles in the toll factor.
+ * To see it just on jsprit setting, please refer to {@link #test_whenAddingTwoDifferentVehicleTypes_tollBasedOnVehicleId}
+ */
+ @Test
+ void test_whenAddingTwoDifferentVehicleTypes_tollOneTypeTollFactor(){
+ Config config = new Config();
+ config.addCoreModules();
+ Scenario scenario = ScenarioUtils.createScenario(config);
+ new MatsimNetworkReader(scenario.getNetwork()).readFile(utils.getClassInputDirectory() + "network.xml");
+
+ //Create RoadPricing Scheme from code.
+ RoadPricingSchemeImpl scheme = RoadPricingUtils.addOrGetMutableRoadPricingScheme(scenario );
+ /* Configure roadpricing scheme. */
+ RoadPricingUtils.setName(scheme, "DemoToll4Test");
+ RoadPricingUtils.setType(scheme, RoadPricingScheme.TOLL_TYPE_LINK);
+ RoadPricingUtils.setDescription(scheme, "Tolling scheme for test.");
+
+ /* Add general link based toll for one link */
+ RoadPricingUtils.addLink(scheme, Id.createLinkId("21"));
+ RoadPricingUtils.createAndAddGeneralCost(scheme, Time.parseTime("00:00:00"), Time.parseTime("72:00:00"), 99.99);
+
+ //Use toll factor to only toll vehicles of type1.
+ TollFactor tollFactor = (personId, vehicleId, linkId, time) -> {
+ double tollFactor1 = 0.;
+ var vehTypeIdString = VehicleUtils.findVehicle(vehicleId, scenario).getType().getId().toString(); //This needs, the vehicles registered in the scenario.
+ if (TYPE_1.equals(vehTypeIdString)) {
+ tollFactor1 = 1.;
+ }
+ return tollFactor1;
+ };
+ RoadPricingScheme rpSchemeWTollFactor = new RoadPricingSchemeUsingTollFactor( scheme , tollFactor );
+
+ /// End creating roadPricing scheme from Code
+
+ //Build MATSim vehicles and convert them to jsprit Vehicles ... just to see, that this works across the whole chain and
+ //that we can filter/search by (MATSim) vehicle types in TollFactor usage
+ VehiclesFactory vf = scenario.getVehicles().getFactory();
+ final Vehicle vehicle1;
+ {
+ VehicleType vehType1 = vf.createVehicleType( Id.create( TYPE_1, VehicleType.class ) );
+ vehType1.getCostInformation().setFixedCost(10.0);
+ vehType1.getCostInformation().setCostsPerSecond(0.0);
+ vehType1.getCostInformation().setCostsPerMeter(2.0);
+ scenario.getVehicles().addVehicleType( vehType1 );
+ CarrierVehicle matsimVehicle1 = CarrierVehicle.newInstance( Id.createVehicleId( "vehicle1" ), Id.createLinkId("20"), vehType1 );
+ scenario.getVehicles().addVehicle( matsimVehicle1 );
+ vehicle1 = MatsimJspritFactory.createJspritVehicle( matsimVehicle1, new Coord() );
+ }
+
+ final Vehicle vehicle2;
+ {
+ VehicleType vehType2 = vf.createVehicleType(Id.create(TYPE_2, VehicleType.class));
+ vehType2.getCostInformation().setFixedCost(20.0);
+ vehType2.getCostInformation().setCostsPerSecond(0.0);
+ vehType2.getCostInformation().setCostsPerMeter(4.0);
+ scenario.getVehicles().addVehicleType(vehType2);
+
+ CarrierVehicle matsimVehicle2 = CarrierVehicle.newInstance(Id.createVehicleId("vehicle2"), Id.createLinkId("20"), vehType2);
+ scenario.getVehicles().addVehicle(matsimVehicle2);
+ vehicle2 = MatsimJspritFactory.createJspritVehicle(matsimVehicle2, new Coord());
+ }
+
+ //Build the NetbasedTransportCosts object with the roadpricing scheme.
+ NetworkBasedTransportCosts c = NetworkBasedTransportCosts.Builder.newInstance(
+ scenario.getNetwork(),
+ scenario.getVehicles().getVehicleTypes().values() )
+ .setRoadPricingScheme(rpSchemeWTollFactor)
+ .build() ;
+
+ //vehicle1: includes toll
+ Assertions.assertEquals(20099.99, c.getTransportCost(Location.newInstance("20"), Location.newInstance("21"), 0.0, mock(Driver.class), vehicle1), 0.01);
+ Assertions.assertEquals(20000.0, c.getDistance(Location.newInstance("6"), Location.newInstance("21"), 0.0, vehicle1), 0.01);
+
+ //vehicle 2: no toll
+ Assertions.assertEquals(40000.0, c.getTransportCost(Location.newInstance("20"), Location.newInstance("21"), 0.0, mock(Driver.class), vehicle2), 0.01);
+ Assertions.assertEquals(20000.0, c.getDistance(Location.newInstance("6"), Location.newInstance("21"), 0.0, vehicle2), 0.01);
+ }
+
+
+ /**
+ * This test is a modified version of {@link #test_whenAddingTwoDifferentVehicleTypes_itMustAccountForThem}
+ * In addition, there is added a road pricing scheme.
+ * With using a toll factor, the tolling can be set differently for the two vehicles.
+ * This test is build, in a way, that it uses the JSPRIT vehicle directly.
+ * To see it with the MATSim settings, please refer to {@link #test_whenAddingTwoDifferentVehicleTypes_tollOneTypeTollFactor()}
+ */
+ @Test
+ void test_whenAddingTwoDifferentVehicleTypes_tollBasedOnVehicleId(){
+ Config config = new Config();
+ config.addCoreModules();
+ Scenario scenario = ScenarioUtils.createScenario(config);
+ new MatsimNetworkReader(scenario.getNetwork()).readFile(utils.getClassInputDirectory() + "network.xml");
+
+ //Create Rp Scheme from code.
+ RoadPricingSchemeImpl scheme = RoadPricingUtils.addOrGetMutableRoadPricingScheme(scenario );
+ /* Configure roadpricing scheme. */
+ RoadPricingUtils.setName(scheme, "DemoToll4TestType1");
+ RoadPricingUtils.setType(scheme, RoadPricingScheme.TOLL_TYPE_LINK);
+ RoadPricingUtils.setDescription(scheme, "Tolling scheme for test.");
+
+ /* Add general link based toll for one link */
+ RoadPricingUtils.addLink(scheme, Id.createLinkId("21"));
+ RoadPricingUtils.createAndAddGeneralCost(scheme, Time.parseTime("00:00:00"), Time.parseTime("72:00:00"), 99.99);
+
+ //Use a factor to take into account the different types. type2 gehts tolled with 50% of the toll of type1
+ TollFactor tollFactor = (personId, vehicleId, linkId, time) -> {
+ //No information about the vehicleType available anywhere, because it is not registered centrally.
+ // -> Use the vehicleId to distinguish the types.
+ var vehTypeIdString = vehicleId.toString();
+ if (vehTypeIdString.equals("vehicle1")) {
+ return 1;
+ } else if (vehTypeIdString.equals("vehicle2")) {
+ return 0.5;
+ } else {
+ return 0;
+ }
+ };
+ RoadPricingSchemeUsingTollFactor rpSchemeWTollFactor = new RoadPricingSchemeUsingTollFactor( scheme , tollFactor );
+
+ ///___ End creating toll scheme from code
+
+ NetworkBasedTransportCosts.Builder builder = NetworkBasedTransportCosts.Builder.newInstance(scenario.getNetwork());
+ builder.addVehicleTypeSpecificCosts(TYPE_1, 10.0, 0.0, 2.0);
+ builder.addVehicleTypeSpecificCosts(TYPE_2, 20.0, 0.0, 4.0);
+ builder.setRoadPricingScheme(rpSchemeWTollFactor); //add the rpCalculator to activate the tolling.
+ NetworkBasedTransportCosts c = builder.build();
+
+ Vehicle vehicle1 = mock(Vehicle.class);
+ com.graphhopper.jsprit.core.problem.vehicle.VehicleType type1 = mock( com.graphhopper.jsprit.core.problem.vehicle.VehicleType.class );
+ when(type1.getMaxVelocity()).thenReturn(5.0);
+ when(type1.getTypeId()).thenReturn(TYPE_1);
+ when(vehicle1.getType()).thenReturn(type1);
+ when(vehicle1.getId()).thenReturn("vehicle1");
+
+ Vehicle vehicle2 = mock(Vehicle.class);
+ com.graphhopper.jsprit.core.problem.vehicle.VehicleType type2 = mock( com.graphhopper.jsprit.core.problem.vehicle.VehicleType.class );
+ when(type2.getMaxVelocity()).thenReturn(5.0);
+ when(type2.getTypeId()).thenReturn(TYPE_2);
+ when(vehicle2.getType()).thenReturn(type2);
+ when(vehicle2.getId()).thenReturn("vehicle2");
+
+ //vehicle1: includes toll of 99.99 for entering the final link
+ Assertions.assertEquals(20099.99, c.getTransportCost(Location.newInstance("20"), Location.newInstance("21"), 0.0, mock(Driver.class), vehicle1), 0.01);
+ Assertions.assertEquals(20000.0, c.getDistance(Location.newInstance("6"), Location.newInstance("21"), 0.0, vehicle1), 0.01);
+
+ //vehicle 2: includes toll of 49.995 (50% of 99.99) for entering the final link
+ Assertions.assertEquals(40049.995, c.getTransportCost(Location.newInstance("20"), Location.newInstance("21"), 0.0, mock(Driver.class), vehicle2), 0.01);
+ Assertions.assertEquals(20000.0, c.getDistance(Location.newInstance("6"), Location.newInstance("21"), 0.0, vehicle2), 0.01);
+ }
+
}
diff --git a/contribs/hybridsim/pom.xml b/contribs/hybridsim/pom.xml
index 5917f032e3e..b480aa197dd 100644
--- a/contribs/hybridsim/pom.xml
+++ b/contribs/hybridsim/pom.xml
@@ -10,8 +10,8 @@
hybridsim
- 4.27.2
- 1.65.0
+ 4.28.0
+ 1.65.1
diff --git a/contribs/locationchoice/src/test/java/org/matsim/contrib/locationchoice/LocationChoiceIT.java b/contribs/locationchoice/src/test/java/org/matsim/contrib/locationchoice/LocationChoiceIT.java
index 4f39e4a0b72..1a045c7c8f6 100644
--- a/contribs/locationchoice/src/test/java/org/matsim/contrib/locationchoice/LocationChoiceIT.java
+++ b/contribs/locationchoice/src/test/java/org/matsim/contrib/locationchoice/LocationChoiceIT.java
@@ -84,6 +84,7 @@ public class LocationChoiceIT {
void testLocationChoice() {
final Config config = localCreateConfig( utils.getPackageInputDirectory() + "config2.xml");
+ config.routing().setNetworkRouteConsistencyCheck(RoutingConfigGroup.NetworkRouteConsistencyCheck.disable);
final MutableScenario scenario = (MutableScenario) ScenarioUtils.createScenario(config);
diff --git a/contribs/multimodal/src/test/java/org/matsim/contrib/multimodal/MultiModalControlerListenerTest.java b/contribs/multimodal/src/test/java/org/matsim/contrib/multimodal/MultiModalControlerListenerTest.java
index cb24c3d8849..fa7c3b2f767 100644
--- a/contribs/multimodal/src/test/java/org/matsim/contrib/multimodal/MultiModalControlerListenerTest.java
+++ b/contribs/multimodal/src/test/java/org/matsim/contrib/multimodal/MultiModalControlerListenerTest.java
@@ -89,7 +89,7 @@ void testSimpleScenario() {
static void runSimpleScenario(int numberOfThreads) {
Config config = ConfigUtils.createConfig();
-
+ config.routing().setNetworkRouteConsistencyCheck(RoutingConfigGroup.NetworkRouteConsistencyCheck.disable);
config.qsim().setEndTime(24 * 3600);
config.controller().setLastIteration(0);
diff --git a/contribs/multimodal/src/test/java/org/matsim/contrib/multimodal/MultiModalTripRouterTest.java b/contribs/multimodal/src/test/java/org/matsim/contrib/multimodal/MultiModalTripRouterTest.java
index a939cb76327..ea6ba8549c3 100644
--- a/contribs/multimodal/src/test/java/org/matsim/contrib/multimodal/MultiModalTripRouterTest.java
+++ b/contribs/multimodal/src/test/java/org/matsim/contrib/multimodal/MultiModalTripRouterTest.java
@@ -39,6 +39,7 @@
import org.matsim.core.api.experimental.events.EventsManager;
import org.matsim.core.config.Config;
import org.matsim.core.config.ConfigUtils;
+import org.matsim.core.config.groups.RoutingConfigGroup;
import org.matsim.core.config.groups.ScoringConfigGroup;
import org.matsim.core.controler.AbstractModule;
import org.matsim.core.controler.Injector;
@@ -73,6 +74,7 @@ void testRouteLeg() {
config.routing().addParam("teleportedModeSpeed_ride", "15.0");
config.routing().addParam("teleportedModeSpeed_undefined", "13.88888888888889");
config.routing().addParam("teleportedModeSpeed_walk", "1.34");
+ config.routing().setNetworkRouteConsistencyCheck(RoutingConfigGroup.NetworkRouteConsistencyCheck.disable);
config.scoring().addModeParams( new ScoringConfigGroup.ModeParams( TransportMode.ride ) );
final Scenario scenario = ScenarioUtils.createScenario(config);
diff --git a/contribs/multimodal/src/test/java/org/matsim/contrib/multimodal/RunMultimodalExampleTest.java b/contribs/multimodal/src/test/java/org/matsim/contrib/multimodal/RunMultimodalExampleTest.java
index 3a3c2101c9a..4cad691e8b5 100644
--- a/contribs/multimodal/src/test/java/org/matsim/contrib/multimodal/RunMultimodalExampleTest.java
+++ b/contribs/multimodal/src/test/java/org/matsim/contrib/multimodal/RunMultimodalExampleTest.java
@@ -20,8 +20,9 @@ void main(){
URL url = IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "berlin" ), "config_multimodal.xml" );;
String [] args = { url.toString(),
- "--config:controler.outputDirectory" , utils.getOutputDirectory()
- } ;
+ "--config:controler.outputDirectory" , utils.getOutputDirectory(),
+ "--config:routing.networkRouteConsistencyCheck", "disable"
+ } ;;
try{
RunMultimodalExample.main( args );
diff --git a/contribs/multimodal/src/test/java/org/matsim/contrib/multimodal/pt/MultiModalPTCombinationTest.java b/contribs/multimodal/src/test/java/org/matsim/contrib/multimodal/pt/MultiModalPTCombinationTest.java
index ca3a78fce35..78231bd1790 100644
--- a/contribs/multimodal/src/test/java/org/matsim/contrib/multimodal/pt/MultiModalPTCombinationTest.java
+++ b/contribs/multimodal/src/test/java/org/matsim/contrib/multimodal/pt/MultiModalPTCombinationTest.java
@@ -85,6 +85,7 @@ void testMultiModalPtCombination() {
Scenario scenario = f.scenario;
Config config = scenario.getConfig();
config.controller().setOutputDirectory(utils.getOutputDirectory());
+ config.routing().setNetworkRouteConsistencyCheck(RoutingConfigGroup.NetworkRouteConsistencyCheck.disable);
MultiModalConfigGroup mmcg = new MultiModalConfigGroup();
mmcg.setMultiModalSimulationEnabled(true);
diff --git a/contribs/multimodal/src/test/java/org/matsim/contrib/multimodal/simengine/StuckAgentTest.java b/contribs/multimodal/src/test/java/org/matsim/contrib/multimodal/simengine/StuckAgentTest.java
index 790922dd590..d0776605026 100644
--- a/contribs/multimodal/src/test/java/org/matsim/contrib/multimodal/simengine/StuckAgentTest.java
+++ b/contribs/multimodal/src/test/java/org/matsim/contrib/multimodal/simengine/StuckAgentTest.java
@@ -46,6 +46,7 @@
import org.matsim.contrib.multimodal.config.MultiModalConfigGroup;
import org.matsim.core.config.Config;
import org.matsim.core.config.ConfigUtils;
+import org.matsim.core.config.groups.RoutingConfigGroup;
import org.matsim.core.config.groups.ScoringConfigGroup.ActivityParams;
import org.matsim.core.controler.Controler;
import org.matsim.core.events.handler.BasicEventHandler;
@@ -69,7 +70,7 @@ public class StuckAgentTest {
void testStuckEvents() {
Config config = ConfigUtils.createConfig();
config.controller().setOutputDirectory(utils.getOutputDirectory());
-
+ config.routing().setNetworkRouteConsistencyCheck(RoutingConfigGroup.NetworkRouteConsistencyCheck.disable);
config.qsim().setEndTime(24*3600);
config.controller().setLastIteration(0);
diff --git a/contribs/noise/src/main/java/org/matsim/contrib/noise/MergeNoiseCSVFile.java b/contribs/noise/src/main/java/org/matsim/contrib/noise/MergeNoiseCSVFile.java
index d052f341cfe..7abae434d94 100644
--- a/contribs/noise/src/main/java/org/matsim/contrib/noise/MergeNoiseCSVFile.java
+++ b/contribs/noise/src/main/java/org/matsim/contrib/noise/MergeNoiseCSVFile.java
@@ -392,6 +392,7 @@ private void readReceiverPoints() {
}
}
+ //TODO this should be updated to use CSVReader or something as robust
private void readValues() {
for (int ll = 0; ll < this.labels.length; ll++) {
diff --git a/contribs/noise/src/main/java/org/matsim/contrib/noise/NoiseConfigGroup.java b/contribs/noise/src/main/java/org/matsim/contrib/noise/NoiseConfigGroup.java
index cd7b2a500ab..06e793c85d9 100644
--- a/contribs/noise/src/main/java/org/matsim/contrib/noise/NoiseConfigGroup.java
+++ b/contribs/noise/src/main/java/org/matsim/contrib/noise/NoiseConfigGroup.java
@@ -95,8 +95,8 @@ public NoiseConfigGroup() {
private double receiverPointGap = 250.;
- private String[] consideredActivitiesForReceiverPointGrid = {"home", "work"};
- private String[] consideredActivitiesForDamageCalculation = {"home", "work"};
+ private String[] consideredActivitiesForReceiverPointGrid = {"home*", "work*"};
+ private String[] consideredActivitiesForDamageCalculation = {"home*", "work*"};
private double receiverPointsGridMinX = 0.;
private double receiverPointsGridMinY = 0.;
diff --git a/contribs/noise/src/main/java/org/matsim/contrib/noise/NoiseWriter.java b/contribs/noise/src/main/java/org/matsim/contrib/noise/NoiseWriter.java
index de465940c1a..6187e0b2f06 100644
--- a/contribs/noise/src/main/java/org/matsim/contrib/noise/NoiseWriter.java
+++ b/contribs/noise/src/main/java/org/matsim/contrib/noise/NoiseWriter.java
@@ -78,17 +78,17 @@ public static void writeReceiverPoints(NoiseContext noiseContext, String outputP
// .addAttribute("Id", String.class)
// .create();
// Collection features = new ArrayList();
-//
+//
// for (ReceiverPoint rp : noiseContext.getReceiverPoints().values()) {
-//
+//
// SimpleFeature feature = factory.createPoint(MGC.coord2Coordinate(rp.getCoord()), new Object[] {rp.getId().toString()}, null);
// features.add(feature);
// }
-//
+//
// String filePath = outputPath;
// File file = new File(filePath);
// file.mkdirs();
-//
+//
// log.info("Writing receiver points to shapefile... ");
// ShapeFileWriter.writeGeometries(features, filePath + "receiverPoints.shp");
// log.info("Writing receiver points to shapefile... Done. ");
@@ -318,13 +318,11 @@ public static void writeDamageInfoPerHour(NoiseContext noiseContext, String outp
try {
BufferedWriter bw = new BufferedWriter(new FileWriter(file));
-
- bw.write("Receiver Point Id;Damages " + Time.writeTime(timeInterval, Time.TIMEFORMAT_HHMMSS));
+ bw.write("Receiver Point Id;Damages " + Time.writeTime(timeInterval, Time.TIMEFORMAT_HHMMSS) + ";x;y;t");
bw.newLine();
for (NoiseReceiverPoint rp : noiseContext.getReceiverPoints().values()) {
-
- bw.write(rp.getId() + ";" + rp.getDamageCosts());
+ bw.write(rp.getId() + ";" + rp.getDamageCosts() + ";" + rp.getCoord().getX() + ";" + rp.getCoord().getY() + ";" + timeInterval );
bw.newLine();
}
diff --git a/contribs/noise/src/test/java/org/matsim/contrib/noise/NoiseConfigGroupIT.java b/contribs/noise/src/test/java/org/matsim/contrib/noise/NoiseConfigGroupIT.java
index d5b61b0b590..1b5e2db9ccd 100644
--- a/contribs/noise/src/test/java/org/matsim/contrib/noise/NoiseConfigGroupIT.java
+++ b/contribs/noise/src/test/java/org/matsim/contrib/noise/NoiseConfigGroupIT.java
@@ -22,17 +22,18 @@
*/
package org.matsim.contrib.noise;
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.matsim.api.core.v01.Scenario;
import org.matsim.core.config.Config;
import org.matsim.core.config.ConfigUtils;
+import org.matsim.core.config.groups.RoutingConfigGroup;
import org.matsim.core.controler.Controler;
import org.matsim.core.controler.OutputDirectoryHierarchy;
import org.matsim.core.scenario.ScenarioUtils;
-import org.matsim.testcases.MatsimTestUtils;
-
+import org.matsim.testcases.MatsimTestUtils;
+
/**
* @author ikaddoura
*
@@ -41,9 +42,9 @@
public class NoiseConfigGroupIT {
@RegisterExtension
- private MatsimTestUtils testUtils = new MatsimTestUtils();
-
- @Test
+ private MatsimTestUtils testUtils = new MatsimTestUtils();
+
+ @Test
final void test0(){
String configFile = testUtils.getPackageInputDirectory() + "NoiseConfigGroupTest/config0.xml";
@@ -69,14 +70,15 @@ final void test0(){
String tunnelLinkIds = noiseParameters.getTunnelLinkIDsSet().toArray()[0] + "," + noiseParameters.getTunnelLinkIDsSet().toArray()[1];
Assertions.assertEquals("link1,link2", tunnelLinkIds, "wrong config parameter");
- }
-
- @Test
+ }
+
+ @Test
final void test1(){
String configFile = testUtils.getPackageInputDirectory() + "NoiseConfigGroupTest/config1.xml";
Config config = ConfigUtils.loadConfig(configFile, new NoiseConfigGroup());
config.controller().setOutputDirectory(testUtils.getOutputDirectory());
+ config.routing().setNetworkRouteConsistencyCheck(RoutingConfigGroup.NetworkRouteConsistencyCheck.disable);
NoiseConfigGroup noiseParameters = (NoiseConfigGroup) config.getModule("noise");
diff --git a/contribs/noise/src/test/java/org/matsim/contrib/noise/NoiseIT.java b/contribs/noise/src/test/java/org/matsim/contrib/noise/NoiseIT.java
index e8aa97a3ab3..542580dcb44 100644
--- a/contribs/noise/src/test/java/org/matsim/contrib/noise/NoiseIT.java
+++ b/contribs/noise/src/test/java/org/matsim/contrib/noise/NoiseIT.java
@@ -93,6 +93,7 @@ final void test1(){
String[] consideredActivities = {"home", "work"};
noiseParameters.setConsideredActivitiesForDamageCalculationArray(consideredActivities);
+ noiseParameters.setConsideredActivitiesForReceiverPointGridArray(consideredActivities);
com.google.inject.Injector injector = Injector.createInjector( scenario.getConfig() , new AbstractModule(){
@Override public void install(){
@@ -197,6 +198,7 @@ private static void runTest2a( Config runConfig ) {
String[] consideredActivities = {"home", "work"};
noiseParameters.setConsideredActivitiesForDamageCalculationArray(consideredActivities);
+ noiseParameters.setConsideredActivitiesForReceiverPointGridArray(consideredActivities);
noiseParameters.setScaleFactor(1.);
noiseParameters.setUseActualSpeedLevel(false);
@@ -984,6 +986,7 @@ final void test2b(){
String[] consideredActivities = {"home", "work"};
noiseParameters.setConsideredActivitiesForDamageCalculationArray(consideredActivities);
+ noiseParameters.setConsideredActivitiesForReceiverPointGridArray(consideredActivities);
noiseParameters.setScaleFactor(1.);
noiseParameters.setNoiseAllocationApproach(NoiseConfigGroup.NoiseAllocationApproach.MarginalCost);
@@ -1073,6 +1076,7 @@ final void test2c(){
String[] consideredActivities = {"home", "work"};
noiseParameters.setConsideredActivitiesForDamageCalculationArray(consideredActivities);
+ noiseParameters.setConsideredActivitiesForReceiverPointGridArray(consideredActivities);
noiseParameters.setScaleFactor(1.);
noiseParameters.setUseActualSpeedLevel(true);
diff --git a/contribs/noise/test/input/org/matsim/contrib/noise/NoiseConfigGroupTest/config1.xml b/contribs/noise/test/input/org/matsim/contrib/noise/NoiseConfigGroupTest/config1.xml
index e2d42df47cf..f4830014284 100644
--- a/contribs/noise/test/input/org/matsim/contrib/noise/NoiseConfigGroupTest/config1.xml
+++ b/contribs/noise/test/input/org/matsim/contrib/noise/NoiseConfigGroupTest/config1.xml
@@ -1,24 +1,25 @@
-
+
-
+
+
-
+
-
+
-
+
@@ -34,20 +35,20 @@
-
-
+
+
-
+
-
+
-
+
-
+
@@ -66,26 +67,26 @@
-
+
-
+
-
+
-
+
-
+
-
+
@@ -171,20 +172,20 @@
-
+
-
+
-
+
-
+
-
+
@@ -199,5 +200,5 @@
-
+
diff --git a/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingproxy/CarEgressWalkChanger.java b/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingproxy/CarEgressWalkChanger.java
index ee231f716ed..20c0b113bed 100644
--- a/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingproxy/CarEgressWalkChanger.java
+++ b/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingproxy/CarEgressWalkChanger.java
@@ -33,7 +33,7 @@
*
* This class allows to implicitly apply penalties to plans by changing the duration of the egress walk after car interactions.
* By construction this only works for plans involving car trips and can not be used if you want to penalize all plans that
- * fulfill a certain condition.
+ * fulfill a certain condition. Note that if you bind this, you should also bind the return value of {@link #getBackChanger()}!
*