From 43b3bcb411c9fddc0bfb9a3fee9480a63c930804 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 6 Aug 2024 14:33:54 +0000 Subject: [PATCH 01/15] Bump it.unimi.dsi:fastutil-core from 8.5.13 to 8.5.14 Bumps [it.unimi.dsi:fastutil-core](https://github.com/vigna/fastutil) from 8.5.13 to 8.5.14. - [Changelog](https://github.com/vigna/fastutil/blob/master/CHANGES) - [Commits](https://github.com/vigna/fastutil/commits/8.5.14) --- updated-dependencies: - dependency-name: it.unimi.dsi:fastutil-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- matsim/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matsim/pom.xml b/matsim/pom.xml index 3f2321ada6d..7f768fffe76 100644 --- a/matsim/pom.xml +++ b/matsim/pom.xml @@ -127,7 +127,7 @@ it.unimi.dsi fastutil-core - 8.5.13 + 8.5.14 org.geotools From 5bf784e34d408d34d607c9acd4e85d305e53d348 Mon Sep 17 00:00:00 2001 From: rakow Date: Tue, 6 Aug 2024 17:16:37 +0200 Subject: [PATCH 02/15] Preserve the working directory when gui is run from cli (#3391) --- .../org/matsim/application/MATSimApplication.java | 2 ++ .../main/java/org/matsim/application/ShowGUI.java | 7 +++++++ matsim/src/main/java/org/matsim/run/gui/Gui.java | 14 ++++++++++++-- 3 files changed, 21 insertions(+), 2 deletions(-) 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 4e4c6860d63..2425a0f1491 100644 --- a/contribs/application/src/main/java/org/matsim/application/MATSimApplication.java +++ b/contribs/application/src/main/java/org/matsim/application/MATSimApplication.java @@ -413,6 +413,8 @@ public static void runWithDefaults(Class 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/matsim/src/main/java/org/matsim/run/gui/Gui.java b/matsim/src/main/java/org/matsim/run/gui/Gui.java index 4b826b14842..1ca4a9afc8d 100644 --- a/matsim/src/main/java/org/matsim/run/gui/Gui.java +++ b/matsim/src/main/java/org/matsim/run/gui/Gui.java @@ -91,6 +91,11 @@ public class Gui extends JFrame { private File configFile; private File lastUsedDirectory; + + /** + * This is the working directory for the simulation. If it is null, the working directory is the directory of the config file. + */ + private File workingDirectory = null; private ConfigEditor editor = null; private ScheduleValidatorWindow transitValidator = null; @@ -439,6 +444,8 @@ private void startMATSim() { textStdOut.setText(""); textErrOut.setText(""); + String cwd = workingDirectory == null ? new File(txtConfigfilename.getText()).getParent() : workingDirectory.getAbsolutePath(); + new Thread(() -> { String classpath = System.getProperty("java.class.path"); String[] cpParts = classpath.split(File.pathSeparator); @@ -457,8 +464,7 @@ private void startMATSim() { "--add-exports", "java.desktop/sun.java2d=ALL-UNNAMED", mainClass, txtConfigfilename.getText() }; // see https://jogamp.org/bugzilla/show_bug.cgi?id=1317#c21 and/or https://github.com/matsim-org/matsim-libs/pull/2940 - exeRunner = ExeRunner.run(cmdArgs, textStdOut, textErrOut, - new File(txtConfigfilename.getText()).getParent()); + exeRunner = ExeRunner.run(cmdArgs, textStdOut, textErrOut, cwd); int exitcode = exeRunner.waitForFinish(); exeRunner = null; @@ -575,6 +581,10 @@ public static void main(String[] args) { Gui.show("MATSim", RunMatsim.class, args.length == 1 ? new File(args[0]) : null); } + public void setWorkingDirectory(File cwd) { + this.workingDirectory = cwd; + } + // Is it a problem to make the following available to the outside? If so, why? Would it // be better to rather copy/paste the above code and start from there? kai, jun/aug'18 From 4e4afdcb6822f294685f67ccc8b039b15744f176 Mon Sep 17 00:00:00 2001 From: schlenther Date: Wed, 7 Aug 2024 16:36:03 +0200 Subject: [PATCH 03/15] use asterisk for act type default --- .../org/matsim/application/analysis/noise/NoiseAnalysis.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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..7cd5fea5502 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 @@ -46,7 +46,8 @@ 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.Option(names = "--consider-activities", split = ",", description = "Considered activities for noise calculation." + + " Use asterisk ('*') for acttype prefixes, if all such acts shall be considered.", defaultValue = "h,w,home*,work*") private Set considerActivities; @CommandLine.Option(names = "--noise-barrier", description = "Path to the noise barrier File", defaultValue = "") From 6a30c28d370e72729199eee0d9a48741f9cc98d8 Mon Sep 17 00:00:00 2001 From: schlenther Date: Wed, 7 Aug 2024 17:24:55 +0200 Subject: [PATCH 04/15] NoiseAnalysis: set the scale factor for according to sample size --- .../analysis/noise/NoiseAnalysis.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) 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 7cd5fea5502..6730cae8996 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,7 @@ package org.matsim.application.analysis.noise; +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 +10,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; @@ -38,6 +41,8 @@ ) 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,6 +51,9 @@ public class NoiseAnalysis implements MATSimAppCommand { @CommandLine.Mixin private final ShpOptions shp = new ShpOptions(); + @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 = "h,w,home*,work*") private Set considerActivities; @@ -89,6 +97,16 @@ public Integer call() throws Exception { noiseParameters.setNoiseBarriersFilePath(noiseBarrierFile); } + 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(); @@ -120,6 +138,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; From ea1f72cef8315e9d253fde79198ffaa471c96ceb Mon Sep 17 00:00:00 2001 From: simei94 <67737999+simei94@users.noreply.github.com> Date: Thu, 8 Aug 2024 14:09:32 +0200 Subject: [PATCH 05/15] add fare zone based pt pricing (#3382) * first try to implement fare zone based pt pricing, deutschlandtarif numbers still missing * put deutschlandtarif price linear functions into code * unit test for FareZoneBasedPtFareHandler --- .../pt/fare/DistanceBasedPtFareParams.java | 13 ++ .../pt/fare/FareZoneBasedPtFareHandler.java | 163 ++++++++++++++++++ .../vsp/pt/fare/PtFareConfigGroup.java | 2 +- .../playground/vsp/pt/fare/PtFareModule.java | 11 +- .../fare/FareZoneBasedPtFareHandlerTest.java | 124 +++++++++++++ .../scenarios/kelheim/ptTestArea/pt-area.cpg | 1 + .../scenarios/kelheim/ptTestArea/pt-area.dbf | Bin 0 -> 330 bytes .../scenarios/kelheim/ptTestArea/pt-area.prj | 1 + .../scenarios/kelheim/ptTestArea/pt-area.shp | Bin 0 -> 348 bytes .../scenarios/kelheim/ptTestArea/pt-area.shx | Bin 0 -> 108 bytes 10 files changed, 310 insertions(+), 5 deletions(-) create mode 100644 contribs/vsp/src/main/java/playground/vsp/pt/fare/FareZoneBasedPtFareHandler.java create mode 100644 contribs/vsp/src/test/java/playground/vsp/pt/fare/FareZoneBasedPtFareHandlerTest.java create mode 100644 examples/scenarios/kelheim/ptTestArea/pt-area.cpg create mode 100644 examples/scenarios/kelheim/ptTestArea/pt-area.dbf create mode 100644 examples/scenarios/kelheim/ptTestArea/pt-area.prj create mode 100644 examples/scenarios/kelheim/ptTestArea/pt-area.shp create mode 100644 examples/scenarios/kelheim/ptTestArea/pt-area.shx diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/DistanceBasedPtFareParams.java b/contribs/vsp/src/main/java/playground/vsp/pt/fare/DistanceBasedPtFareParams.java index a86cd173c14..442d956bf3c 100644 --- a/contribs/vsp/src/main/java/playground/vsp/pt/fare/DistanceBasedPtFareParams.java +++ b/contribs/vsp/src/main/java/playground/vsp/pt/fare/DistanceBasedPtFareParams.java @@ -22,6 +22,7 @@ public class DistanceBasedPtFareParams extends ReflectiveConfigGroup { public static final String LONG_DISTANCE_TRIP_THRESHOLD = "longDistanceTripThreshold"; public static final String LONG_DISTANCE_TRIP_SLOPE = "longDistanceTripSlope"; public static final String LONG_DISTANCE_TRIP_INTERCEPT = "longDistanceTripIntercept"; + public static final String FARE_ZONE_SHP = "fareZoneShp"; @PositiveOrZero private double minFare = 2.0; @@ -35,6 +36,7 @@ public class DistanceBasedPtFareParams extends ReflectiveConfigGroup { private double longDistanceTripIntercept = 30.0; @PositiveOrZero private double longDistanceTripSlope = 0.00025; + private String fareZoneShp; public DistanceBasedPtFareParams() { super(SET_NAME); @@ -52,6 +54,7 @@ public Map getComments() { map.put(LONG_DISTANCE_TRIP_THRESHOLD, "Threshold of the long trips in meters. Below this value, " + "the trips are considered as normal trips. Above this value, the trips are considered as " + "inter-city trips"); + map.put(FARE_ZONE_SHP, "Shp file with fare zone(s). This parameter is only used for PtFareCalculationModel 'fareZoneBased'."); return map; } @@ -114,4 +117,14 @@ public double getLongDistanceTripThreshold() { public void setLongDistanceTripThreshold(double longDistanceTripThreshold) { this.longDistanceTripThreshold = longDistanceTripThreshold; } + + @StringGetter(FARE_ZONE_SHP) + public String getFareZoneShp() { + return fareZoneShp; + } + + @StringSetter(FARE_ZONE_SHP) + public void setFareZoneShp(String fareZoneShp) { + this.fareZoneShp = fareZoneShp; + } } diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/FareZoneBasedPtFareHandler.java b/contribs/vsp/src/main/java/playground/vsp/pt/fare/FareZoneBasedPtFareHandler.java new file mode 100644 index 00000000000..962a18fac57 --- /dev/null +++ b/contribs/vsp/src/main/java/playground/vsp/pt/fare/FareZoneBasedPtFareHandler.java @@ -0,0 +1,163 @@ +package playground.vsp.pt.fare; + +import com.google.inject.Inject; +import org.apache.commons.math.stat.regression.SimpleRegression; +import org.geotools.api.feature.simple.SimpleFeature; +import org.locationtech.jts.geom.Geometry; +import org.matsim.api.core.v01.Coord; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.events.ActivityStartEvent; +import org.matsim.api.core.v01.events.PersonMoneyEvent; +import org.matsim.api.core.v01.events.handler.ActivityStartEventHandler; +import org.matsim.api.core.v01.population.Person; +import org.matsim.application.options.ShpOptions; +import org.matsim.core.api.experimental.events.EventsManager; +import org.matsim.core.router.StageActivityTypeIdentifier; +import org.matsim.core.utils.geometry.CoordUtils; +import org.matsim.core.utils.geometry.geotools.MGC; +import org.matsim.pt.PtConstants; + +import java.util.AbstractMap; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class FareZoneBasedPtFareHandler implements ActivityStartEventHandler { + @Inject + private EventsManager events; + + public static final String FARE = "fare"; + public static final String PT_FARE_ZONE_BASED = "fare zone based pt fare"; + public static final String PT_GERMANWIDE_FARE_BASED = "german-wide fare based pt fare"; + + private final ShpOptions shp; + + private final Map, Coord> personDepartureCoordMap = new HashMap<>(); + private final Map, Coord> personArrivalCoordMap = new HashMap<>(); + + public FareZoneBasedPtFareHandler(DistanceBasedPtFareParams params) { + this.shp = new ShpOptions(params.getFareZoneShp(), null, null); + } + + @Override + public void handleEvent(ActivityStartEvent event) { + + if (event.getActType().equals(PtConstants.TRANSIT_ACTIVITY_TYPE)) { + personDepartureCoordMap.computeIfAbsent(event.getPersonId(), c -> event.getCoord()); // The departure place is fixed to the place of first pt interaction an agent has in the whole leg + personArrivalCoordMap.put(event.getPersonId(), event.getCoord()); // The arrival stop will keep updating until the agent start a real activity (i.e. finish the leg) + } + + if (!StageActivityTypeIdentifier.isStageActivity(event.getActType())) { + Id personId = event.getPersonId(); + if (personDepartureCoordMap.containsKey(personId)) { + double distance = CoordUtils.calcEuclideanDistance + (personDepartureCoordMap.get(personId), personArrivalCoordMap.get(personId)); + + SimpleFeature departureZone = determineFareZone(personDepartureCoordMap.get(personId), shp.readFeatures()); + SimpleFeature arrivalZone = determineFareZone(personArrivalCoordMap.get(personId), shp.readFeatures()); + + Map.Entry fareEntry = computeFare(distance, departureZone, arrivalZone); + // charge fare to the person + events.processEvent( + new PersonMoneyEvent(event.getTime(), event.getPersonId(), -fareEntry.getValue(), + PtFareConfigGroup.PT_FARE, fareEntry.getKey(), event.getPersonId().toString())); + + personDepartureCoordMap.remove(personId); + personArrivalCoordMap.remove(personId); + } + } + } + + public static Map.Entry computeFare(double distance, SimpleFeature departureZone, SimpleFeature arrivalZone) { + + if (departureZone != null && arrivalZone != null) { +// if both zones are not null -> departure and arrival point are inside of one of the tarifzonen + if (departureZone.getID().equals(arrivalZone.getID())) { + return new AbstractMap.SimpleEntry<>(PT_FARE_ZONE_BASED ,(double) departureZone.getAttribute(FARE)); + } + } +// in every other case return german wide fare / Deutschlandtarif + return getGermanWideFare(distance); + } + + private static Map.Entry getGermanWideFare(double distance) { + + SimpleRegression regression = new SimpleRegression(); + +// in Deutschlandtarif, the linear function for the prices above 100km seem to have a different steepness +// hence the following difference in data points +// prices taken from https://deutschlandtarifverbund.de/wp-content/uploads/2024/07/20231201_TBDT_J_10_Preisliste_V07.pdf + if (distance / 1000 <= 100.) { + regression.addData(1, 1.70); + regression.addData(2,1.90); + regression.addData(3,2.00); + regression.addData(4,2.10); + regression.addData(5,2.20); + regression.addData(6,3.20); + regression.addData(7,3.70); + regression.addData(8,3.80); + regression.addData(9,3.90); + regression.addData(10,4.10); + regression.addData(11,5.00); + regression.addData(12,5.40); + regression.addData(13,5.60); + regression.addData(14,5.80); + regression.addData(15,5.90); + regression.addData(16,6.40); + regression.addData(17,6.50); + regression.addData(18,6.60); + regression.addData(19,6.70); + regression.addData(20,6.90); + regression.addData(30,9.90); + regression.addData(40,13.70); + regression.addData(50,16.30); + regression.addData(60,18.10); + regression.addData(70,20.10); + regression.addData(80,23.20); + regression.addData(90,26.20); + regression.addData(100,28.10); + } else { + regression.addData(100,28.10); + regression.addData(200,47.20); + regression.addData(300,59.70); + regression.addData(400,71.70); + regression.addData(500,83.00); + regression.addData(600,94.60); + regression.addData(700,106.30); + regression.addData(800,118.20); + regression.addData(900,130.10); + regression.addData(1000,141.00); + regression.addData(1100,148.60); + regression.addData(1200,158.10); + regression.addData(1300,169.20); + regression.addData(1400,179.80); + regression.addData(1500,190.10); + regression.addData(1600,201.50); + regression.addData(1700,212.80); + regression.addData(1800,223.30); + regression.addData(1900,233.90); + regression.addData(2000,244.00); + } + return new AbstractMap.SimpleEntry<>(PT_GERMANWIDE_FARE_BASED, regression.getSlope() * distance / 1000 + regression.getIntercept()); + } + + static SimpleFeature determineFareZone(Coord coord, List features) { + SimpleFeature zone = null; + + for (SimpleFeature ft : features) { + Geometry geom = (Geometry) ft.getDefaultGeometry(); + + if (MGC.coord2Point(coord).within(geom)) { + zone = ft; + break; + } + } + return zone; + } + + @Override + public void reset(int iteration) { + personArrivalCoordMap.clear(); + personDepartureCoordMap.clear(); + } +} diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareConfigGroup.java b/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareConfigGroup.java index 20c9291dc1b..8abf76dcb37 100644 --- a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareConfigGroup.java +++ b/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareConfigGroup.java @@ -13,7 +13,7 @@ public class PtFareConfigGroup extends ReflectiveConfigGroup { public static final String APPLY_UPPER_BOUND = "applyUpperBound"; public static final String UPPER_BOUND_FACTOR = "upperBoundFactor"; - public enum PtFareCalculationModels {distanceBased} // More to come (e.g. zone based, hybrid...) + public enum PtFareCalculationModels {distanceBased, fareZoneBased} // More to come (e.g. zone based, hybrid...) private static final String PT_FARE_CALCULATION_CMT = "PT fare calculation scheme. Current implementation: distanceBased (more to come...)"; public static final String UPPER_BOUND_FACTOR_CMT = "When upper bound is applied, upperBound = upperBoundFactor * max Fare of the day. " + diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareModule.java b/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareModule.java index 9bd25cc81f4..4da41c16612 100644 --- a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareModule.java +++ b/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareModule.java @@ -11,12 +11,15 @@ public void install() { getConfig().scoring().getModes().get(TransportMode.pt).setDailyMonetaryConstant(0); getConfig().scoring().getModes().get(TransportMode.pt).setMarginalUtilityOfDistance(0); PtFareConfigGroup ptFareConfigGroup = ConfigUtils.addOrGetModule(this.getConfig(), PtFareConfigGroup.class); + DistanceBasedPtFareParams distanceBasedPtFareParams = ConfigUtils.addOrGetModule(this.getConfig(), DistanceBasedPtFareParams.class); + if (ptFareConfigGroup.getPtFareCalculation() == PtFareConfigGroup.PtFareCalculationModels.distanceBased) { - DistanceBasedPtFareParams distanceBasedPtFareParams = ConfigUtils.addOrGetModule(this.getConfig(), DistanceBasedPtFareParams.class); - addEventHandlerBinding().toInstance(new DistanceBasedPtFareHandler(distanceBasedPtFareParams)); - } else { + addEventHandlerBinding().toInstance(new DistanceBasedPtFareHandler(distanceBasedPtFareParams)); + } else if (ptFareConfigGroup.getPtFareCalculation() == PtFareConfigGroup.PtFareCalculationModels.fareZoneBased) { + addEventHandlerBinding().toInstance(new FareZoneBasedPtFareHandler(distanceBasedPtFareParams)); + } else { throw new RuntimeException("Please choose from the following fare Calculation method: [" + - PtFareConfigGroup.PtFareCalculationModels.distanceBased + "]"); + PtFareConfigGroup.PtFareCalculationModels.distanceBased + ", " + PtFareConfigGroup.PtFareCalculationModels.fareZoneBased + "]"); } if (ptFareConfigGroup.getApplyUpperBound()) { diff --git a/contribs/vsp/src/test/java/playground/vsp/pt/fare/FareZoneBasedPtFareHandlerTest.java b/contribs/vsp/src/test/java/playground/vsp/pt/fare/FareZoneBasedPtFareHandlerTest.java new file mode 100644 index 00000000000..ec486ec2cee --- /dev/null +++ b/contribs/vsp/src/test/java/playground/vsp/pt/fare/FareZoneBasedPtFareHandlerTest.java @@ -0,0 +1,124 @@ +package playground.vsp.pt.fare; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.matsim.analysis.personMoney.PersonMoneyEventsAnalysisModule; +import org.matsim.api.core.v01.Coord; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.population.*; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.ScoringConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy; +import org.matsim.core.scenario.MutableScenario; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.testcases.MatsimTestUtils; + +import java.io.BufferedReader; +import java.io.IOException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +import static org.matsim.application.ApplicationUtils.globFile; + +public class FareZoneBasedPtFareHandlerTest { + + @RegisterExtension + private MatsimTestUtils utils = new MatsimTestUtils(); + + @Test + void testFareZoneBasedPtFareHandler() { + + URL context = ExamplesUtils.getTestScenarioURL("kelheim"); + Config config = ConfigUtils.loadConfig(IOUtils.extendUrl(context, "config.xml")); + config.controller().setOverwriteFileSetting(OutputDirectoryHierarchy.OverwriteFileSetting.deleteDirectoryIfExists); + config.controller().setOutputDirectory(utils.getOutputDirectory()); + config.controller().setLastIteration(0); + + PtFareConfigGroup ptFareConfigGroup = ConfigUtils.addOrGetModule(config, PtFareConfigGroup.class); + ptFareConfigGroup.setPtFareCalculationModel(PtFareConfigGroup.PtFareCalculationModels.fareZoneBased); + + DistanceBasedPtFareParams fareParams = ConfigUtils.addOrGetModule(config, DistanceBasedPtFareParams.class); + fareParams.setFareZoneShp(IOUtils.extendUrl(context, "ptTestArea/pt-area.shp").toString()); + + + ScoringConfigGroup scoring = ConfigUtils.addOrGetModule(config, ScoringConfigGroup.class); + + ScoringConfigGroup.ActivityParams homeParams = new ScoringConfigGroup.ActivityParams("home"); + ScoringConfigGroup.ActivityParams workParams = new ScoringConfigGroup.ActivityParams("work"); + homeParams.setTypicalDuration(8 * 3600.); + workParams.setTypicalDuration(8 * 3600.); + scoring.addActivityParams(homeParams); + scoring.addActivityParams(workParams); + + + MutableScenario scenario = (MutableScenario) ScenarioUtils.loadScenario(config); + + Population population = ScenarioUtils.createScenario(ConfigUtils.createConfig()).getPopulation(); + PopulationFactory fac = population.getFactory(); + + Person person = fac.createPerson(Id.createPersonId("fareTestPerson")); + Plan plan = fac.createPlan(); + + Activity home = fac.createActivityFromCoord("home", new Coord(710300.624,5422165.737)); +// bus to Saal (Donau) work location departs at 09:14 + home.setEndTime(9 * 3600.); + Activity work = fac.createActivityFromCoord("work", new Coord(714940.65,5420707.78)); +// rb17 to regensburg 2nd home location departs at 13:59 + work.setEndTime(13 * 3600. + 45 * 60); + Activity home2 = fac.createActivityFromCoord("home", new Coord(726634.40,5433508.07)); + + Leg leg = fac.createLeg(TransportMode.pt); + + plan.addActivity(home); + plan.addLeg(leg); + plan.addActivity(work); + plan.addLeg(leg); + plan.addActivity(home2); + + person.addPlan(plan); + population.addPerson(person); + scenario.setPopulation(population); + + Controler controler = new Controler(scenario); + controler.addOverridingModule(new AbstractModule() { + @Override + public void install() { + install(new PtFareModule()); + install(new PersonMoneyEventsAnalysisModule()); + } + }); + controler.run(); + + Assertions.assertTrue(Files.exists(Path.of(utils.getOutputDirectory()))); + +// read personMoneyEvents.tsv and check if both fare entries do have the correct fare type + String filePath = globFile(Path.of(utils.getOutputDirectory()), "*output_personMoneyEvents.tsv*").toString(); + String line; + List events = new ArrayList<>(); + + try (BufferedReader br = IOUtils.getBufferedReader(filePath)) { +// skip header + br.readLine(); + + while ((line = br.readLine()) != null) { + events.add(line.split(";")); + } + } catch (IOException e) { + e.printStackTrace(); + } + + Assertions.assertEquals(2, events.size()); + Assertions.assertEquals(FareZoneBasedPtFareHandler.PT_FARE_ZONE_BASED, events.get(0)[4]); + Assertions.assertEquals(FareZoneBasedPtFareHandler.PT_GERMANWIDE_FARE_BASED, events.get(1)[4]); + } +} diff --git a/examples/scenarios/kelheim/ptTestArea/pt-area.cpg b/examples/scenarios/kelheim/ptTestArea/pt-area.cpg new file mode 100644 index 00000000000..3ad133c048f --- /dev/null +++ b/examples/scenarios/kelheim/ptTestArea/pt-area.cpg @@ -0,0 +1 @@ +UTF-8 \ No newline at end of file diff --git a/examples/scenarios/kelheim/ptTestArea/pt-area.dbf b/examples/scenarios/kelheim/ptTestArea/pt-area.dbf new file mode 100644 index 0000000000000000000000000000000000000000..e17541dab999012ee260f988c47319e51b56771b GIT binary patch literal 330 zcmZRs;b3KCU|=}N&;cYdL1qeE%n!ukf^#7ZKSy6zsE{*=4uEoClw**qBa{u+FToF! zfzY}6DXCBquzqy&(-Mnd@?ibk%&7W#72v?oB`8GKzaX_Ju_QA;PuH<1H4!dH7DEdM QNGU2oG0#xX)WARr09(r;z5oCK literal 0 HcmV?d00001 diff --git a/examples/scenarios/kelheim/ptTestArea/pt-area.prj b/examples/scenarios/kelheim/ptTestArea/pt-area.prj new file mode 100644 index 00000000000..bd846aeb220 --- /dev/null +++ b/examples/scenarios/kelheim/ptTestArea/pt-area.prj @@ -0,0 +1 @@ +PROJCS["ETRS_1989_UTM_Zone_32N",GEOGCS["GCS_ETRS_1989",DATUM["D_ETRS_1989",SPHEROID["GRS_1980",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",500000.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",9.0],PARAMETER["Scale_Factor",0.9996],PARAMETER["Latitude_Of_Origin",0.0],UNIT["Meter",1.0]] \ No newline at end of file diff --git a/examples/scenarios/kelheim/ptTestArea/pt-area.shp b/examples/scenarios/kelheim/ptTestArea/pt-area.shp new file mode 100644 index 0000000000000000000000000000000000000000..a798ec1b8bf6937c07c6ae55c679a3412e7ed06c GIT binary patch literal 348 zcmZQzQ0HR64%WS3W?*0i$~B%pRI_f5s-x}KoKT)MA&w%6yXAh}RdtN$O*Qq|6yk_o zJBlbHkXJ#BSs;ZxP_0`Ue5%7&A?(@l?+fR%4XTbAo*xc~1MPM7dbfGwSye}!_#c^8 z8$ulKPBn4ceM8kzTFdgwi**QhZY(?{Vzf5IanJUzBC~I*Iwo!6?6wB_c)s#!Nj)zS8APAJcs5J!>3-EzO~syasWrkeU}3US1) L9Yxd#$g2PVpUn^* literal 0 HcmV?d00001 From e981bde003b91aa599b51cac12c43d36ea35ed6a Mon Sep 17 00:00:00 2001 From: schlenther Date: Thu, 8 Aug 2024 16:34:20 +0200 Subject: [PATCH 06/15] better defaults for NoiseDashboard --- .../org/matsim/simwrapper/dashboard/NoiseDashboard.java | 8 ++++---- .../main/java/org/matsim/simwrapper/viz/ColorScheme.java | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/NoiseDashboard.java b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/NoiseDashboard.java index dc934e6c2e2..b502f3fbf57 100644 --- a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/NoiseDashboard.java +++ b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/NoiseDashboard.java @@ -42,7 +42,7 @@ public void configure(Header header, Layout layout) { viz.maxHeight = 20; viz.center = data.context().getCenter(); viz.zoom = data.context().mapZoomLevel; - viz.setColorRamp(new double[]{40, 50, 60}, new String[]{"#1175b3", "#95c7df", "#f4a986", "#cc0c27"}); + viz.setColorRamp(new double[]{30, 40, 50, 60, 70}, new String[]{"#1175b3", "#95c7df", "#dfdb95", "#dfb095", "#f4a986", "#cc0c27"}); viz.file = data.computeWithPlaceholder(NoiseAnalysis.class, "immission_per_day.%s", "avro"); }) .el(MapPlot.class, (viz, data) -> { @@ -58,8 +58,8 @@ public void configure(Header header, Layout layout) { viz.display.lineColor.dataset = "noise"; viz.display.lineColor.columnName = "value"; viz.display.lineColor.join = "Link Id"; - viz.display.lineColor.fixedColors = new String[]{"#1175b3", "#95c7df", "#f4a986", "#cc0c27"}; - viz.display.lineColor.setColorRamp(ColorScheme.RdYlBu, 4, true, "45, 55, 65"); + //viz.display.lineColor.fixedColors = new String[]{"#1175b3", "#95c7df", "#f4a986", "#cc0c27"}; + viz.display.lineColor.setColorRamp(ColorScheme.Oranges, 8, false, "35, 45, 55, 65, 75, 85, 95"); viz.display.lineWidth.dataset = "noise"; viz.display.lineWidth.columnName = "value"; viz.display.lineWidth.scaleFactor = 8d; @@ -75,7 +75,7 @@ public void configure(Header header, Layout layout) { viz.maxHeight = 20; viz.center = data.context().getCenter(); viz.zoom = data.context().mapZoomLevel; - viz.setColorRamp(new double[]{40, 50, 60}, new String[]{"#1175b3", "#95c7df", "#f4a986", "#cc0c27"}); + viz.setColorRamp(new double[]{30, 40, 50, 60, 70}, new String[]{"#1175b3", "#95c7df", "#dfdb95", "#dfb095", "#f4a986", "#cc0c27"}); viz.file = data.computeWithPlaceholder(NoiseAnalysis.class, "immission_per_hour.%s", "avro"); }); } diff --git a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/viz/ColorScheme.java b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/viz/ColorScheme.java index 37e31cc97ca..df8f6410679 100644 --- a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/viz/ColorScheme.java +++ b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/viz/ColorScheme.java @@ -27,6 +27,7 @@ public final class ColorScheme { public static final String Inferne = "Inferne"; public static final String Cividis = "Cividis"; public static final String Rainbow = "Rainbow"; + public static final String Oranges = "Oranges"; private ColorScheme() { From cdfe0bc6de01513c198ed851e089a212e2da2b11 Mon Sep 17 00:00:00 2001 From: Ricardo Ewert Date: Thu, 8 Aug 2024 17:02:45 +0200 Subject: [PATCH 07/15] remove the static --- .../prepare/CreateDataDistributionOfStructureData.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/prepare/CreateDataDistributionOfStructureData.java b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/prepare/CreateDataDistributionOfStructureData.java index 477231505c1..dcd4c3732d9 100644 --- a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/prepare/CreateDataDistributionOfStructureData.java +++ b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/prepare/CreateDataDistributionOfStructureData.java @@ -29,7 +29,7 @@ public class CreateDataDistributionOfStructureData implements MATSimAppCommand { private static final Logger log = LogManager.getLogger(CreateDataDistributionOfStructureData.class); - private static LanduseDataConnectionCreator landuseDataConnectionCreator; + private final LanduseDataConnectionCreator landuseDataConnectionCreator; private enum LanduseConfiguration { useOnlyOSMLanduse, useOSMBuildingsAndLanduse @@ -78,16 +78,16 @@ private enum LanduseConfiguration { private final Map>> buildingsPerZone = new HashMap<>(); public CreateDataDistributionOfStructureData(LanduseDataConnectionCreator landuseDataConnectionCreator) { - CreateDataDistributionOfStructureData.landuseDataConnectionCreator = landuseDataConnectionCreator; + this.landuseDataConnectionCreator = landuseDataConnectionCreator; log.info("Using LanduseDataConnectionCreator {} to connect the types of the landuse data to the categories of the small scale commercial traffic generation", landuseDataConnectionCreator.getClass().getSimpleName()); } public CreateDataDistributionOfStructureData() { - landuseDataConnectionCreator = new LanduseDataConnectionCreatorForOSM_Data(); + this.landuseDataConnectionCreator = new LanduseDataConnectionCreatorForOSM_Data(); log.info("Using default LanduseDataConnectionCreatorForOSM_Data to connect the types of the landuse data to the categories of the small scale commercial traffic generation"); } public static void main(String[] args) { - System.exit(new CommandLine(new CreateDataDistributionOfStructureData(landuseDataConnectionCreator)).execute(args)); + System.exit(new CommandLine(new CreateDataDistributionOfStructureData()).execute(args)); } @Override From 624ca13d060c4313c753868fc14f5c947da6d845 Mon Sep 17 00:00:00 2001 From: schlenther Date: Thu, 8 Aug 2024 18:05:56 +0200 Subject: [PATCH 08/15] NoiseAnalysis: more explicit parameter settings + bug fix in MergeNoiseOutput --- .../analysis/noise/MergeNoiseOutput.java | 14 ++-- .../analysis/noise/NoiseAnalysis.java | 67 +++++++++++++------ .../contrib/noise/NoiseConfigGroup.java | 4 +- .../simwrapper/dashboard/NoiseDashboard.java | 4 +- 4 files changed, 60 insertions(+), 29 deletions(-) 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..88f8f9354e5 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 @@ -118,6 +118,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)); @@ -143,9 +144,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); } @@ -188,7 +188,10 @@ private void mergeImissions(String pathParameter, String label) { // 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)) + .columnTypesPartial(Map.of("x", ColumnType.FLOAT, + "y", ColumnType.FLOAT, + "Receiver Point Id", ColumnType.INTEGER, + "t", ColumnType.DOUBLE)) .sample(false) .separator(';').build()); @@ -278,7 +281,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()); 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 6730cae8996..02d6337de15 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 @@ -55,7 +55,7 @@ public class NoiseAnalysis implements MATSimAppCommand { 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 = "h,w,home*,work*") + " 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 = "") @@ -71,32 +71,55 @@ 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 som estandards. 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.setReceiverPointsGridMinX(minCoord.getX()); + noiseParameters.setReceiverPointsGridMinY(minCoord.getY()); + noiseParameters.setReceiverPointsGridMaxX(maxCoord.getX()); + noiseParameters.setReceiverPointsGridMaxY(maxCoord.getY()); + } - noiseParameters.setNoiseComputationMethod(NoiseConfigGroup.NoiseComputationMethod.RLS19); + noiseParameters.setNoiseComputationMethod(NoiseConfigGroup.NoiseComputationMethod.RLS19); - if (!Objects.equals(noiseBarrierFile, "")) { - noiseParameters.setNoiseBarriersSourceCRS(config.global().getCoordinateSystem()); - noiseParameters.setConsiderNoiseBarriers(true); - noiseParameters.setNoiseBarriersFilePath(noiseBarrierFile); + 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){ @@ -111,6 +134,9 @@ public Integer call() throws Exception { 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(); @@ -122,12 +148,11 @@ public Integer call() throws Exception { MergeNoiseOutput mergeNoiseOutput = new MergeNoiseOutput(paths, Path.of(outputFilePath), config.global().getCoordinateSystem()); mergeNoiseOutput.run(); - 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()); 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/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/NoiseDashboard.java b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/NoiseDashboard.java index b502f3fbf57..036b3c5a718 100644 --- a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/NoiseDashboard.java +++ b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/NoiseDashboard.java @@ -35,7 +35,7 @@ public void configure(Header header, Layout layout) { layout.row("aggregate noise") .el(GridMap.class, (viz, data) -> { viz.title = "Noise Immissions (Grid)"; - viz.description = "Aggregate Noise Immissions per day"; + viz.description = "Total Noise Immissions per day"; viz.height = 12.0; viz.cellSize = 250; viz.opacity = 0.2; @@ -47,7 +47,7 @@ public void configure(Header header, Layout layout) { }) .el(MapPlot.class, (viz, data) -> { viz.title = "Noise Emissions (Link)"; - viz.description = "Aggregate Noise Emissions per day"; + viz.description = "Maximum Noise Level per day [dB]"; viz.height = 12.0; viz.center = data.context().getCenter(); viz.zoom = data.context().mapZoomLevel; From a455df3d4280aeced29d55a5044014b8e61eb995 Mon Sep 17 00:00:00 2001 From: Chengqi Lu <43133404+luchengqi7@users.noreply.github.com> Date: Fri, 9 Aug 2024 10:26:20 +0200 Subject: [PATCH 09/15] Update DRT estimate and teleport module (#3333) Re-organizing the DRT estimation scripts. For more details, please see detailed description above. --- .../MultiModalDrtLegEstimatorTest.java | 4 +- .../impl/DetourBasedDrtEstimator.java | 76 ---------- .../impl/DirectTripBasedDrtEstimator.java | 130 ++++++++++++++++++ .../EuclideanDistanceBasedDrtEstimator.java | 65 ++++----- ...stimator.java => ExampleDrtEstimator.java} | 6 +- ...=> OnlineSimulationBasedDrtEstimator.java} | 11 +- .../distribution/DistributionGenerator.java | 10 ++ .../LogNormalDistributionGenerator.java | 35 +++++ .../impl/distribution/NoDistribution.java | 8 ++ .../NormalDistributionGenerator.java | 34 +++++ .../ConstantRideDurationEstimator.java | 20 +++ .../RideDurationEstimator.java | 11 ++ .../ConstantWaitingTimeEstimator.java | 18 +++ .../ShapeFileBasedWaitingTimeEstimator.java | 63 +++++++++ .../WaitingTimeEstimator.java | 9 ++ .../estimator/DrtEstimateAndTeleportTest.java | 59 ++++++++ .../DrtTeleportationWithModeChoiceTest.java | 3 - 17 files changed, 441 insertions(+), 121 deletions(-) delete mode 100644 contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/DetourBasedDrtEstimator.java create mode 100644 contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/DirectTripBasedDrtEstimator.java rename contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/{ConstantDrtEstimator.java => ExampleDrtEstimator.java} (82%) rename contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/{BasicDrtEstimator.java => OnlineSimulationBasedDrtEstimator.java} (90%) create mode 100644 contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/distribution/DistributionGenerator.java create mode 100644 contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/distribution/LogNormalDistributionGenerator.java create mode 100644 contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/distribution/NoDistribution.java create mode 100644 contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/distribution/NormalDistributionGenerator.java create mode 100644 contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/trip_estimation/ConstantRideDurationEstimator.java create mode 100644 contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/trip_estimation/RideDurationEstimator.java create mode 100644 contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/waiting_time_estimation/ConstantWaitingTimeEstimator.java create mode 100644 contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/waiting_time_estimation/ShapeFileBasedWaitingTimeEstimator.java create mode 100644 contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/waiting_time_estimation/WaitingTimeEstimator.java create mode 100644 contribs/drt/src/test/java/org/matsim/contrib/drt/estimator/DrtEstimateAndTeleportTest.java 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/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/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/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))); From 1730ac8213fb52066926563386badd19b3e9e71f Mon Sep 17 00:00:00 2001 From: schlenther Date: Fri, 9 Aug 2024 11:01:06 +0200 Subject: [PATCH 10/15] NoiseAnalysis: merge damages files --- .../analysis/noise/MergeNoiseOutput.java | 76 +++++++++---------- .../analysis/noise/NoiseAnalysis.java | 3 +- .../contrib/noise/MergeNoiseCSVFile.java | 1 + .../org/matsim/contrib/noise/NoiseWriter.java | 14 ++-- 4 files changed, 42 insertions(+), 52 deletions(-) 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 88f8f9354e5..e59c4aee75c 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,14 @@ 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; + MergeNoiseOutput(Path path, String coordinateSystem ) { + this.outputDirectory = path; + this.crs = coordinateSystem; } /** @@ -90,25 +91,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"); } /** @@ -129,7 +114,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")); @@ -165,41 +150,48 @@ 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 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)) + //we need "damages_receiverPoint" -> "Damages 01:00:00" and "immission" -> "Immision 01:00:00" + String 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)) + "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); } @@ -235,7 +227,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(); @@ -257,7 +249,7 @@ 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(); 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 02d6337de15..deceb84624e 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 @@ -144,8 +144,7 @@ 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(); return 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/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(); } From 6ba2578003eaed40f431e3401b88c3a98035aefc Mon Sep 17 00:00:00 2001 From: schlenther Date: Fri, 9 Aug 2024 13:11:10 +0200 Subject: [PATCH 11/15] NoiseDashboard: include stats and damage plots --- .../analysis/noise/MergeNoiseOutput.java | 11 +++- .../analysis/noise/NoiseAnalysis.java | 26 +++++++- .../simwrapper/dashboard/NoiseDashboard.java | 65 ++++++++++++++----- .../dashboard/NoiseDashboardTests.java | 7 +- 4 files changed, 89 insertions(+), 20 deletions(-) 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 e59c4aee75c..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 @@ -53,6 +53,8 @@ final class MergeNoiseOutput { private final int minTime = 3600; private int maxTime = 24 * 3600; + private final Map totalReceiverPointValues = new HashMap<>(); + MergeNoiseOutput(Path path, String coordinateSystem ) { this.outputDirectory = path; this.crs = coordinateSystem; @@ -162,6 +164,7 @@ private void mergeReceiverPointData(String outputDir, String label) { // 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 timeDataFile = outputDir + label + "_" + round(time, 1) + ".csv"; @@ -174,7 +177,7 @@ private void mergeReceiverPointData(String outputDir, String label) { } //we need "damages_receiverPoint" -> "Damages 01:00:00" and "immission" -> "Immision 01:00:00" - String substrToCapitalize = label.contains("_") ? label.substring(0, label.lastIndexOf("_")) : label; + substrToCapitalize = label.contains("_") ? label.substring(0, label.lastIndexOf("_")) : label; String valueHeader = StringUtils.capitalize(substrToCapitalize) + " " + Time.writeTime(time, Time.TIMEFORMAT_HHMMSS); // Read the data file @@ -255,9 +258,12 @@ private void mergeReceiverPointData(String outputDir, String label) { 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); @@ -317,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 deceb84624e..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,7 @@ 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; @@ -19,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; @@ -36,7 +44,10 @@ 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 { @@ -77,7 +88,7 @@ public Integer call() throws Exception { NoiseConfigGroup noiseParameters = ConfigUtils.addOrGetModule(config, NoiseConfigGroup.class); if(overrideParameters){ - log.warn("no NoiseConfigGroup was configured before. Will set som estandards. You should check the next lines in the log file!"); + 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)); @@ -147,6 +158,17 @@ public Integer call() throws Exception { 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; } diff --git a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/NoiseDashboard.java b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/NoiseDashboard.java index 036b3c5a718..48f173a8adb 100644 --- a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/NoiseDashboard.java +++ b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/NoiseDashboard.java @@ -1,6 +1,7 @@ package org.matsim.simwrapper.dashboard; import org.matsim.application.analysis.noise.NoiseAnalysis; +import org.matsim.application.analysis.population.StuckAgentAnalysis; import org.matsim.application.prepare.network.CreateAvroNetwork; import org.matsim.simwrapper.Dashboard; import org.matsim.simwrapper.Header; @@ -8,6 +9,7 @@ import org.matsim.simwrapper.viz.ColorScheme; import org.matsim.simwrapper.viz.GridMap; import org.matsim.simwrapper.viz.MapPlot; +import org.matsim.simwrapper.viz.Tile; /** * Shows emission in the scenario. @@ -32,19 +34,12 @@ public void configure(Header header, Layout layout) { header.title = "Noise"; header.description = "Shows the noise footprint and spatial distribution."; - layout.row("aggregate noise") - .el(GridMap.class, (viz, data) -> { - viz.title = "Noise Immissions (Grid)"; - viz.description = "Total Noise Immissions per day"; - viz.height = 12.0; - viz.cellSize = 250; - viz.opacity = 0.2; - viz.maxHeight = 20; - viz.center = data.context().getCenter(); - viz.zoom = data.context().mapZoomLevel; - viz.setColorRamp(new double[]{30, 40, 50, 60, 70}, new String[]{"#1175b3", "#95c7df", "#dfdb95", "#dfb095", "#f4a986", "#cc0c27"}); - viz.file = data.computeWithPlaceholder(NoiseAnalysis.class, "immission_per_day.%s", "avro"); - }) + layout.row("stats") + .el(Tile.class, (viz, data) -> { + viz.dataset = data.compute(NoiseAnalysis.class, "noise_stats.csv"); + viz.height = 0.1; + }); + layout.row("emissions") .el(MapPlot.class, (viz, data) -> { viz.title = "Noise Emissions (Link)"; viz.description = "Maximum Noise Level per day [dB]"; @@ -65,18 +60,56 @@ public void configure(Header header, Layout layout) { viz.display.lineWidth.scaleFactor = 8d; viz.display.lineWidth.join = "Link Id"; }); - layout.row("hourly noise") + layout.row("imissions") + .el(GridMap.class, (viz, data) -> { + viz.title = "Noise Immissions (Grid)"; + viz.description = "Total Noise Immissions per day"; + viz.height = 12.0; + viz.cellSize = 250; + viz.opacity = 0.1; + viz.maxHeight = 40; + viz.center = data.context().getCenter(); + viz.zoom = data.context().mapZoomLevel; + viz.setColorRamp(new double[]{30, 40, 50, 60, 70}, new String[]{"#1175b3", "#95c7df", "#dfdb95", "#dfb095", "#f4a986", "#cc0c27"}); + viz.file = data.computeWithPlaceholder(NoiseAnalysis.class, "immission_per_day.%s", "avro"); + }) .el(GridMap.class, (viz, data) -> { viz.title = "Hourly Noise Immissions (Grid)"; viz.description = "Noise Immissions per hour"; viz.height = 12.0; viz.cellSize = 250; - viz.opacity = 0.2; - viz.maxHeight = 20; + viz.opacity = 0.1; + viz.maxHeight = 40; viz.center = data.context().getCenter(); viz.zoom = data.context().mapZoomLevel; viz.setColorRamp(new double[]{30, 40, 50, 60, 70}, new String[]{"#1175b3", "#95c7df", "#dfdb95", "#dfb095", "#f4a986", "#cc0c27"}); viz.file = data.computeWithPlaceholder(NoiseAnalysis.class, "immission_per_hour.%s", "avro"); }); + layout.row("damages") + .el(GridMap.class, (viz, data) -> { + viz.title = "Daily Noise Damages (Grid)"; + viz.description = "Total Noise Damages per day [€]"; + viz.height = 12.0; + viz.cellSize = 250; + viz.opacity = 0.1; + viz.maxHeight = 40; + viz.center = data.context().getCenter(); + viz.zoom = data.context().mapZoomLevel; + viz.setColorRamp(ColorScheme.Oranges); + viz.file = data.computeWithPlaceholder(NoiseAnalysis.class, "damages_receiverPoint_per_day.%s", "avro"); + }) + .el(GridMap.class, (viz, data) -> { + viz.title = "Hourly Noise Damages (Grid)"; + viz.description = "Noise Damages per hour [€]"; + viz.height = 12.0; + viz.cellSize = 250; + viz.opacity = 0.2; + viz.maxHeight = 40; + viz.center = data.context().getCenter(); + viz.zoom = data.context().mapZoomLevel; +// viz.setColorRamp(new double[]{30, 40, 50, 60, 70}, new String[]{"#1175b3", "#95c7df", "#dfdb95", "#dfb095", "#f4a986", "#cc0c27"}); + viz.setColorRamp(ColorScheme.Oranges); + viz.file = data.computeWithPlaceholder(NoiseAnalysis.class, "damages_receiverPoint_per_hour.%s", "avro"); + }); } } diff --git a/contribs/simwrapper/src/test/java/org/matsim/simwrapper/dashboard/NoiseDashboardTests.java b/contribs/simwrapper/src/test/java/org/matsim/simwrapper/dashboard/NoiseDashboardTests.java index 6ca2a08cee3..fdc846cdff5 100644 --- a/contribs/simwrapper/src/test/java/org/matsim/simwrapper/dashboard/NoiseDashboardTests.java +++ b/contribs/simwrapper/src/test/java/org/matsim/simwrapper/dashboard/NoiseDashboardTests.java @@ -46,6 +46,11 @@ void generate() { Assertions.assertThat(out) .isDirectoryContaining("glob:**emission_per_day.csv") .isDirectoryContaining("glob:**immission_per_day.avro") - .isDirectoryContaining("glob:**immission_per_hour.avro"); + .isDirectoryContaining("glob:**immission_per_hour.avro") + .isDirectoryContaining("glob:**damages_receiverPoint_per_hour.avro") + .isDirectoryContaining("glob:**damages_receiverPoint_per_day.avro") + .isDirectoryContaining("glob:**noise_stats.csv"); + + //TODO check content / values of the files } } From cda5767f20627d1e8f8283cb1cb542c6be8c36d8 Mon Sep 17 00:00:00 2001 From: Paul Heinrich Date: Fri, 9 Aug 2024 13:34:12 +0200 Subject: [PATCH 12/15] only perform net consistency check once --- .../org/matsim/core/router/NetworkRoutingProvider.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/matsim/src/main/java/org/matsim/core/router/NetworkRoutingProvider.java b/matsim/src/main/java/org/matsim/core/router/NetworkRoutingProvider.java index a6c00d06942..7b874593fa1 100644 --- a/matsim/src/main/java/org/matsim/core/router/NetworkRoutingProvider.java +++ b/matsim/src/main/java/org/matsim/core/router/NetworkRoutingProvider.java @@ -46,6 +46,7 @@ public class NetworkRoutingProvider implements Provider{ private static final Logger log = LogManager.getLogger( NetworkRoutingProvider.class ) ; private final String routingMode; + private boolean alreadyCheckedConsistency = false; @Inject Map travelTimes; @Inject Map travelDisutilityFactories; @@ -142,6 +143,12 @@ private void checkNetwork(Network filteredNetwork) { return; } + if(alreadyCheckedConsistency){ + return; + } + + log.info("Checking network for mode '{}' for consistency...", mode); + int nLinks = filteredNetwork.getLinks().size(); int nNodes = filteredNetwork.getNodes().size(); new NetworkCleaner().run(filteredNetwork); @@ -153,5 +160,7 @@ private void checkNetwork(Network filteredNetwork) { "\n If this network topology is intended, set the routing config parameter 'networkRouteConsistencyCheck' to 'disable'."); throw new RuntimeException(errorMessage); } + + alreadyCheckedConsistency = true; } } From e2f7c360eda279ed4a0b07ec3298b5bb910413af Mon Sep 17 00:00:00 2001 From: schlenther Date: Fri, 9 Aug 2024 14:18:15 +0200 Subject: [PATCH 13/15] CreateSingleSimWrapperDashboard --- .../CreateSingleSimWrapperDashboard.java | 148 ++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 contribs/simwrapper/src/main/java/org/matsim/simwrapper/CreateSingleSimWrapperDashboard.java diff --git a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/CreateSingleSimWrapperDashboard.java b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/CreateSingleSimWrapperDashboard.java new file mode 100644 index 00000000000..fce848736a6 --- /dev/null +++ b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/CreateSingleSimWrapperDashboard.java @@ -0,0 +1,148 @@ +/* *********************************************************************** * + * project: org.matsim.* + * Controler.java + * * + * *********************************************************************** * + * * + * copyright : (C) 2007 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** */ + +package org.matsim.simwrapper; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.matsim.application.ApplicationUtils; +import org.matsim.application.MATSimAppCommand; +import org.matsim.application.options.ShpOptions; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.simwrapper.dashboard.*; +import picocli.CommandLine; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.List; + +@CommandLine.Command( + name = "dashboard", + description = "Run analysis and create SimWrapper dashboard for existing run output." +) + +/** + * This class creates single SimWrapper dashboards for multiple output directories. It is meant to be run as a post-process, + * e.g. when a specific dashboard was missing after the initial run (for whatever reason). + * It will create the dashboard with all standard settings. + * Depending on the dashboard type, it might be required to provide ShpOptions for data filtering. + * TODO: test whether this works for the non-noise DashboardTypes. + */ +final class CreateSingleSimWrapperDashboard implements MATSimAppCommand { + + private static final Logger log = LogManager.getLogger(CreateSingleSimWrapperDashboard.class); + + @CommandLine.Option(names = "--type", required = true, description = "Provide the dashboard type to be generated. See DashboardType enum within this class.") + private DashboardType dashboardType; + + @CommandLine.Parameters(arity = "1..*", description = "Path to run output directories for which the dashboards is to be generated.") + private List inputPaths; + + @CommandLine.Mixin + private final ShpOptions shp = new ShpOptions(); + + enum DashboardType{ + noise, + emissions, + traffic, + overview, + stuckAgent, + populationAttribute, + ODTrip, + trip, + publicTransit + } + + private CreateSingleSimWrapperDashboard(){ + } + + @Override + public Integer call() throws Exception { + + for (Path runDirectory : inputPaths) { + log.info("Creating " + dashboardType + " for {}", runDirectory); + + Path configPath = ApplicationUtils.matchInput("config.xml", runDirectory); + Config config = ConfigUtils.loadConfig(configPath.toString()); + SimWrapper sw = SimWrapper.create(config); + + SimWrapperConfigGroup simwrapperCfg = ConfigUtils.addOrGetModule(config, SimWrapperConfigGroup.class); + + if (shp.isDefined()){ + //not sure if this is the best way to go, might be that the shape file would be automatically read by providing the --shp command line option + simwrapperCfg.defaultParams().shp = shp.getShapeFile().toString(); + } + + //skip default dashboards + simwrapperCfg.defaultDashboards = SimWrapperConfigGroup.Mode.disabled; + + //add dashboard + switch (dashboardType) { + case noise -> { + sw.addDashboard(new NoiseDashboard()); + } + case emissions -> { + sw.addDashboard(new EmissionsDashboard()); + } + case traffic -> { + sw.addDashboard(new TrafficDashboard()); + } + case overview -> { + sw.addDashboard(new OverviewDashboard()); + } + case stuckAgent -> { + sw.addDashboard(new StuckAgentDashboard()); + } + case populationAttribute -> { + sw.addDashboard(new PopulationAttributeDashboard()); + } + case ODTrip -> { + throw new RuntimeException("ODTripDashboard needs additional information. Single creation is currently not implemented"); +// sw.addDashboard(new ODTripDashboard()); + } + case trip -> { + sw.addDashboard(new TripDashboard()); + } + case publicTransit -> { + sw.addDashboard(new PublicTransitDashboard()); + } + default -> throw new IllegalArgumentException("unkown dashboard type: " + dashboardType); + } + + try { + //append dashboard to existing ones + boolean append = true; + sw.generate(runDirectory, append); + sw.run(runDirectory); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + return 0; + } + + public static void main(String[] args) { + new CreateSingleSimWrapperDashboard().execute(args); + } + +} + From 9175ec805299815d0d8797c57de367e908aa31eb Mon Sep 17 00:00:00 2001 From: schlenther Date: Fri, 9 Aug 2024 14:40:02 +0200 Subject: [PATCH 14/15] fix noise tests: explicitly set activity types for rp grid, when setting act type for damage calculation --- .../org/matsim/contrib/noise/NoiseIT.java | 4 ++ .../noise/NoiseConfigGroupTest/config1.xml | 47 ++++++++++--------- 2 files changed, 28 insertions(+), 23 deletions(-) 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 @@ - + From c316aa5af2af5dd7eadd77ab3d5e320e8b059eec Mon Sep 17 00:00:00 2001 From: nkuehnel Date: Sun, 11 Aug 2024 22:17:07 +0200 Subject: [PATCH 15/15] fix nasty insertion scheduler bug --- .../drt/scheduler/DefaultRequestInsertionScheduler.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) 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..72082906255 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 @@ -128,8 +128,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()); @@ -211,12 +210,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