From 0c13c74065461fe1c4415d8afe1f8dd665037086 Mon Sep 17 00:00:00 2001 From: Paul Heinrich Date: Mon, 9 Sep 2024 14:28:33 +0200 Subject: [PATCH 01/53] add turn restriction test case --- ...athCalculatorTestWithTurnRestrictions.java | 94 +++++++++++-------- 1 file changed, 53 insertions(+), 41 deletions(-) diff --git a/matsim/src/test/java/org/matsim/core/router/AbstractLeastCostPathCalculatorTestWithTurnRestrictions.java b/matsim/src/test/java/org/matsim/core/router/AbstractLeastCostPathCalculatorTestWithTurnRestrictions.java index 11e4ddfc1ce..1ed05a2401e 100644 --- a/matsim/src/test/java/org/matsim/core/router/AbstractLeastCostPathCalculatorTestWithTurnRestrictions.java +++ b/matsim/src/test/java/org/matsim/core/router/AbstractLeastCostPathCalculatorTestWithTurnRestrictions.java @@ -1,12 +1,6 @@ package org.matsim.core.router; -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.io.IOException; -import java.util.Arrays; - -import javax.xml.parsers.ParserConfigurationException; - +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.matsim.api.core.v01.Coord; import org.matsim.api.core.v01.Id; @@ -17,23 +11,27 @@ import org.matsim.api.core.v01.network.Node; import org.matsim.core.config.Config; import org.matsim.core.network.NetworkUtils; -import org.matsim.core.network.io.MatsimNetworkReader; import org.matsim.core.router.util.LeastCostPathCalculator; import org.matsim.core.router.util.LeastCostPathCalculator.Path; import org.matsim.core.scenario.ScenarioUtils; -import org.matsim.testcases.MatsimTestUtils; import org.xml.sax.SAXException; +import javax.xml.parsers.ParserConfigurationException; +import java.io.IOException; +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.assertEquals; + public abstract class AbstractLeastCostPathCalculatorTestWithTurnRestrictions extends AbstractLeastCostPathCalculatorTest { @Test void testCalcLeastCostPath_TurnRestrictions() throws SAXException, ParserConfigurationException, IOException { Network network = createTurnRestrictionsTestNetwork(); - + Node nodeS = network.getNodes().get(Id.create("S", Node.class)); Node nodeT = network.getNodes().get(Id.create("T", Node.class)); LeastCostPathCalculator routerAlgo = getLeastCostPathCalculator(network); - Path path = routerAlgo.calcLeastCostPath(nodeS, nodeT, 8.0*3600, null, null); + Path path = routerAlgo.calcLeastCostPath(nodeS, nodeT, 8.0 * 3600, null, null); assertEquals(7, path.nodes.size(), "number of nodes wrong."); assertEquals(6, path.links.size(), "number of links wrong."); @@ -45,7 +43,7 @@ void testCalcLeastCostPath_TurnRestrictions() throws SAXException, ParserConfigu assertEquals(network.getNodes().get(Id.create("4", Node.class)), path.nodes.get(4)); assertEquals(network.getNodes().get(Id.create("5", Node.class)), path.nodes.get(5)); assertEquals(network.getNodes().get(Id.create("T", Node.class)), path.nodes.get(6)); - + assertEquals(network.getLinks().get(Id.create("S1", Link.class)), path.links.get(0)); assertEquals(network.getLinks().get(Id.create("12", Link.class)), path.links.get(1)); assertEquals(network.getLinks().get(Id.create("23", Link.class)), path.links.get(2)); @@ -54,9 +52,22 @@ void testCalcLeastCostPath_TurnRestrictions() throws SAXException, ParserConfigu assertEquals(network.getLinks().get(Id.create("5T", Link.class)), path.links.get(5)); } + @Test + void testCalcLeastCostPath_TurnRestrictions_IntermediateNode() { + Network network = createTurnRestrictionsTestNetwork(); + + Node nodeS = network.getNodes().get(Id.create("S", Node.class)); + Node node3 = network.getNodes().get(Id.create("3", Node.class)); + + LeastCostPathCalculator routerAlgo = getLeastCostPathCalculator(network); + Path path = routerAlgo.calcLeastCostPath(nodeS, node3, 8.0 * 3600, null, null); + Assertions.assertNotNull(path); + } + + //@formatter:off /** * Creates a test network where the shortest path is impossible due to turn restrictions - * + * * S * | * \/ @@ -64,36 +75,37 @@ void testCalcLeastCostPath_TurnRestrictions() throws SAXException, ParserConfigu * | / /\ * \/ / | * 3--->4--->5 - * + * * Where S1 -> 1T and 23 -> 34 -> 4T are forbidden. - * + * * @return */ - private Network createTurnRestrictionsTestNetwork() { - Config config = utils.loadConfig((String)null); + //@formatter:on + private Network createTurnRestrictionsTestNetwork() { + Config config = utils.loadConfig((String) null); Scenario scenario = ScenarioUtils.createScenario(config); - final Network network = scenario.getNetwork(); - - final Node nodeS = NetworkUtils.createAndAddNode(network, Id.createNodeId("S"), new Coord(1,2)); - final Node node1 = NetworkUtils.createAndAddNode(network, Id.createNodeId("1"), new Coord(1,1)); - final Node node2 = NetworkUtils.createAndAddNode(network, Id.createNodeId("2"), new Coord(0,1)); - final Node node3 = NetworkUtils.createAndAddNode(network, Id.createNodeId("3"), new Coord(0,0)); - final Node node4 = NetworkUtils.createAndAddNode(network, Id.createNodeId("4"), new Coord(1,0)); - final Node node5 = NetworkUtils.createAndAddNode(network, Id.createNodeId("5"), new Coord(2,0)); - final Node nodeT = NetworkUtils.createAndAddNode(network, Id.createNodeId("T"), new Coord(2,0)); - - final Link linkS1 = NetworkUtils.createAndAddLink(network, Id.createLinkId("S1"), nodeS, node1, 1, 1,1, 1); - NetworkUtils.createAndAddLink(network, Id.createLinkId("12"), node1, node2, 1, 1,1, 1); - NetworkUtils.createAndAddLink(network, Id.createLinkId("1T"), node1, nodeT, 1, 1,1, 1); - final Link link23 = NetworkUtils.createAndAddLink(network, Id.createLinkId("23"), node2, node3, 1, 1,1, 1); - NetworkUtils.createAndAddLink(network, Id.createLinkId("34"), node3, node4, 1, 1,1, 1); - NetworkUtils.createAndAddLink(network, Id.createLinkId("4T"), node4, nodeT, 1, 1,1, 1); - NetworkUtils.createAndAddLink(network, Id.createLinkId("45"), node4, node5, 1, 1,1, 1); - NetworkUtils.createAndAddLink(network, Id.createLinkId("5T"), node5, nodeT, 1, 1,1, 1); - - NetworkUtils.addDisallowedNextLinks(linkS1, TransportMode.car, Arrays.asList(Id.createLinkId("1T"))); - NetworkUtils.addDisallowedNextLinks(link23, TransportMode.car, Arrays.asList(Id.createLinkId("34"), Id.createLinkId("4T"))); - - return network; - } + final Network network = scenario.getNetwork(); + + final Node nodeS = NetworkUtils.createAndAddNode(network, Id.createNodeId("S"), new Coord(1, 2)); + final Node node1 = NetworkUtils.createAndAddNode(network, Id.createNodeId("1"), new Coord(1, 1)); + final Node node2 = NetworkUtils.createAndAddNode(network, Id.createNodeId("2"), new Coord(0, 1)); + final Node node3 = NetworkUtils.createAndAddNode(network, Id.createNodeId("3"), new Coord(0, 0)); + final Node node4 = NetworkUtils.createAndAddNode(network, Id.createNodeId("4"), new Coord(1, 0)); + final Node node5 = NetworkUtils.createAndAddNode(network, Id.createNodeId("5"), new Coord(2, 0)); + final Node nodeT = NetworkUtils.createAndAddNode(network, Id.createNodeId("T"), new Coord(2, 0)); + + final Link linkS1 = NetworkUtils.createAndAddLink(network, Id.createLinkId("S1"), nodeS, node1, 1, 1, 1, 1); + NetworkUtils.createAndAddLink(network, Id.createLinkId("12"), node1, node2, 1, 1, 1, 1); + NetworkUtils.createAndAddLink(network, Id.createLinkId("1T"), node1, nodeT, 1, 1, 1, 1); + final Link link23 = NetworkUtils.createAndAddLink(network, Id.createLinkId("23"), node2, node3, 1, 1, 1, 1); + NetworkUtils.createAndAddLink(network, Id.createLinkId("34"), node3, node4, 1, 1, 1, 1); + NetworkUtils.createAndAddLink(network, Id.createLinkId("4T"), node4, nodeT, 1, 1, 1, 1); + NetworkUtils.createAndAddLink(network, Id.createLinkId("45"), node4, node5, 1, 1, 1, 1); + NetworkUtils.createAndAddLink(network, Id.createLinkId("5T"), node5, nodeT, 1, 1, 1, 1); + + NetworkUtils.addDisallowedNextLinks(linkS1, TransportMode.car, Arrays.asList(Id.createLinkId("1T"))); + NetworkUtils.addDisallowedNextLinks(link23, TransportMode.car, Arrays.asList(Id.createLinkId("34"), Id.createLinkId("4T"))); + + return network; + } } From 473aeb7951ed8d0fb406187c0c7b17e8dabf5fd5 Mon Sep 17 00:00:00 2001 From: Paul Heinrich Date: Tue, 24 Sep 2024 15:29:44 +0200 Subject: [PATCH 02/53] add simpler turn restriction test case --- ...athCalculatorTestWithTurnRestrictions.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/matsim/src/test/java/org/matsim/core/router/AbstractLeastCostPathCalculatorTestWithTurnRestrictions.java b/matsim/src/test/java/org/matsim/core/router/AbstractLeastCostPathCalculatorTestWithTurnRestrictions.java index 1ed05a2401e..3d96cd73091 100644 --- a/matsim/src/test/java/org/matsim/core/router/AbstractLeastCostPathCalculatorTestWithTurnRestrictions.java +++ b/matsim/src/test/java/org/matsim/core/router/AbstractLeastCostPathCalculatorTestWithTurnRestrictions.java @@ -64,6 +64,30 @@ void testCalcLeastCostPath_TurnRestrictions_IntermediateNode() { Assertions.assertNotNull(path); } + @Test + void testCalcLeastCostPath_TurnRestrictions_simple() { + Network network = createTurnRestrictionsTestNetwork(); + + Node nodeS = network.getNodes().get(Id.create("S", Node.class)); + Node node1 = network.getNodes().get(Id.create("1", Node.class)); + + LeastCostPathCalculator routerAlgo = getLeastCostPathCalculator(network); + Path path = routerAlgo.calcLeastCostPath(nodeS, node1, 8.0 * 3600, null, null); + Assertions.assertNotNull(path); + } + + @Test + void testCalcLeastCostPath_noTurnRestrictions_simple() { + Network network = createTurnRestrictionsTestNetwork(); + + Node nodeS = network.getNodes().get(Id.create("5", Node.class)); + Node node1 = network.getNodes().get(Id.create("T", Node.class)); + + LeastCostPathCalculator routerAlgo = getLeastCostPathCalculator(network); + Path path = routerAlgo.calcLeastCostPath(nodeS, node1, 8.0 * 3600, null, null); + Assertions.assertNotNull(path); + } + //@formatter:off /** * Creates a test network where the shortest path is impossible due to turn restrictions From c7938c7da2b30c3aa1179f3b630a9bcb0957a258 Mon Sep 17 00:00:00 2001 From: marecabo <23156476+marecabo@users.noreply.github.com> Date: Fri, 18 Oct 2024 16:37:34 +0200 Subject: [PATCH 03/53] Add matsim.tempDir property for specifying ImageIO cache directory --- .../core/controler/ControlerDefaultsModule.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/matsim/src/main/java/org/matsim/core/controler/ControlerDefaultsModule.java b/matsim/src/main/java/org/matsim/core/controler/ControlerDefaultsModule.java index 293ac9ed415..55dfbd40bd9 100755 --- a/matsim/src/main/java/org/matsim/core/controler/ControlerDefaultsModule.java +++ b/matsim/src/main/java/org/matsim/core/controler/ControlerDefaultsModule.java @@ -51,6 +51,9 @@ import java.io.File; public final class ControlerDefaultsModule extends AbstractModule { + + public static final String MATSIM_TEMP_DIR_PROPERTY = "matsim.tempDir"; + @Override public void install() { install(new EventsManagerModule()); @@ -85,9 +88,16 @@ public void install() { // Maybe not the best place to but this but since ChartUtils is used by many modules, including default ones, // the cache needs to be always set correctly. addControlerListenerBinding().toInstance(new StartupListener() { - @Inject private OutputDirectoryHierarchy outputDirectoryHierarchy; - @Override public void notifyStartup(StartupEvent event) { - ImageIO.setCacheDirectory(new File(outputDirectoryHierarchy.getTempPath())); + @Inject + private OutputDirectoryHierarchy outputDirectoryHierarchy; + + @Override + public void notifyStartup(StartupEvent event) { + String matsimTempDir = System.getProperty(MATSIM_TEMP_DIR_PROPERTY); + if (matsimTempDir == null) { + matsimTempDir = outputDirectoryHierarchy.getTempPath(); + } + ImageIO.setCacheDirectory(new File(matsimTempDir)); } }); From 5fc0d3f6c85612a3b73b334316ce35806d58c916 Mon Sep 17 00:00:00 2001 From: marecabo <23156476+marecabo@users.noreply.github.com> Date: Fri, 18 Oct 2024 17:15:54 +0200 Subject: [PATCH 04/53] Move specification of MATSim temp dir to OutputDirectoryHierarchy --- .../matsim/core/controler/ControlerDefaultsModule.java | 10 +--------- .../core/controler/OutputDirectoryHierarchy.java | 8 +++++++- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/matsim/src/main/java/org/matsim/core/controler/ControlerDefaultsModule.java b/matsim/src/main/java/org/matsim/core/controler/ControlerDefaultsModule.java index 55dfbd40bd9..0de32d9c47b 100755 --- a/matsim/src/main/java/org/matsim/core/controler/ControlerDefaultsModule.java +++ b/matsim/src/main/java/org/matsim/core/controler/ControlerDefaultsModule.java @@ -52,8 +52,6 @@ public final class ControlerDefaultsModule extends AbstractModule { - public static final String MATSIM_TEMP_DIR_PROPERTY = "matsim.tempDir"; - @Override public void install() { install(new EventsManagerModule()); @@ -88,16 +86,10 @@ public void install() { // Maybe not the best place to but this but since ChartUtils is used by many modules, including default ones, // the cache needs to be always set correctly. addControlerListenerBinding().toInstance(new StartupListener() { - @Inject - private OutputDirectoryHierarchy outputDirectoryHierarchy; @Override public void notifyStartup(StartupEvent event) { - String matsimTempDir = System.getProperty(MATSIM_TEMP_DIR_PROPERTY); - if (matsimTempDir == null) { - matsimTempDir = outputDirectoryHierarchy.getTempPath(); - } - ImageIO.setCacheDirectory(new File(matsimTempDir)); + ImageIO.setCacheDirectory(new File(event.getServices().getControlerIO().getTempPath())); } }); diff --git a/matsim/src/main/java/org/matsim/core/controler/OutputDirectoryHierarchy.java b/matsim/src/main/java/org/matsim/core/controler/OutputDirectoryHierarchy.java index 86272160a77..9decfe75a1a 100644 --- a/matsim/src/main/java/org/matsim/core/controler/OutputDirectoryHierarchy.java +++ b/matsim/src/main/java/org/matsim/core/controler/OutputDirectoryHierarchy.java @@ -47,6 +47,8 @@ public enum OverwriteFileSetting {failIfDirectoryExists, overwriteExistingFiles, private static final String DIRECTORY_ITERS = "ITERS"; + public static final String MATSIM_TEMP_DIR_PROPERTY = "matsim.tempDir"; + private static final Logger log = LogManager.getLogger(OutputDirectoryHierarchy.class); private String runId = null; @@ -108,7 +110,11 @@ public OutputDirectoryHierarchy(String outputPath, String runId, OverwriteFileSe * @return path to a temp-directory. */ public final String getTempPath() { - return outputPath + "/tmp"; + String matsimTempDir = System.getProperty(MATSIM_TEMP_DIR_PROPERTY); + if (matsimTempDir == null) { + matsimTempDir = outputPath + "/tmp"; + } + return matsimTempDir; } /** From f3f6f572c9c4744455662090f3cffc1dc1d1281f Mon Sep 17 00:00:00 2001 From: marecabo <23156476+marecabo@users.noreply.github.com> Date: Fri, 18 Oct 2024 17:16:03 +0200 Subject: [PATCH 05/53] Add test case --- .../OutputDirectoryHierarchyTest.java | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/matsim/src/test/java/org/matsim/core/controler/OutputDirectoryHierarchyTest.java b/matsim/src/test/java/org/matsim/core/controler/OutputDirectoryHierarchyTest.java index 5fa3ccb628a..5fc8c4f54b4 100644 --- a/matsim/src/test/java/org/matsim/core/controler/OutputDirectoryHierarchyTest.java +++ b/matsim/src/test/java/org/matsim/core/controler/OutputDirectoryHierarchyTest.java @@ -21,14 +21,26 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.population.Activity; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; import org.matsim.core.config.groups.ControllerConfigGroup; +import org.matsim.core.controler.OutputDirectoryHierarchy.OverwriteFileSetting; +import org.matsim.core.scenario.ScenarioUtils; import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; import org.matsim.testcases.MatsimTestUtils; +import static org.junit.jupiter.api.Assertions.assertTrue; + import java.io.BufferedWriter; import java.io.File; import java.io.IOException; import java.io.UncheckedIOException; +import java.net.URL; +import java.util.Set; +import java.util.stream.Collectors; /** * @author thibautd @@ -146,4 +158,27 @@ void testDeleteIfDirectoryExists() { "Directory was not cleared" ); } + + @Test + void testTmpDir() { + + String javaTempDir = System.getProperty("java.io.tmpdir"); + System.setProperty(OutputDirectoryHierarchy.MATSIM_TEMP_DIR_PROPERTY, javaTempDir); + System.setProperty("matsim.preferLocalDtds", "true"); + + URL scenarioURL = ExamplesUtils.getTestScenarioURL("siouxfalls-2014"); + + Config config = ConfigUtils.loadConfig(IOUtils.extendUrl(scenarioURL, "config_default.xml")); + config.controller().setOverwriteFileSetting(OverwriteFileSetting.deleteDirectoryIfExists); + config.controller().setLastIteration(1); + + Scenario scenario = ScenarioUtils.loadScenario(config); + + Controler controller = new Controler(scenario); + controller.run(); + + String matsimTempDir = controller.getControlerIO().getTempPath(); + Assertions.assertEquals(javaTempDir, matsimTempDir); + } + } From 1ea30fe72963e60a9442b7629d7dedd78d554ed3 Mon Sep 17 00:00:00 2001 From: marecabo <23156476+marecabo@users.noreply.github.com> Date: Fri, 18 Oct 2024 18:01:10 +0200 Subject: [PATCH 06/53] Assert that matsimTempDir is not null --- .../org/matsim/core/controler/OutputDirectoryHierarchyTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/matsim/src/test/java/org/matsim/core/controler/OutputDirectoryHierarchyTest.java b/matsim/src/test/java/org/matsim/core/controler/OutputDirectoryHierarchyTest.java index 5fc8c4f54b4..8a1f9c7ce16 100644 --- a/matsim/src/test/java/org/matsim/core/controler/OutputDirectoryHierarchyTest.java +++ b/matsim/src/test/java/org/matsim/core/controler/OutputDirectoryHierarchyTest.java @@ -164,6 +164,8 @@ void testTmpDir() { String javaTempDir = System.getProperty("java.io.tmpdir"); System.setProperty(OutputDirectoryHierarchy.MATSIM_TEMP_DIR_PROPERTY, javaTempDir); + Assertions.assertNotNull(javaTempDir); + System.setProperty("matsim.preferLocalDtds", "true"); URL scenarioURL = ExamplesUtils.getTestScenarioURL("siouxfalls-2014"); From 7d9f7c720740c99728a3ea3ebc400404775864ce Mon Sep 17 00:00:00 2001 From: Ricardo Ewert Date: Mon, 21 Oct 2024 10:11:25 +0200 Subject: [PATCH 07/53] update test for both model types --- ...nerateSmallScaleCommercialTrafficTest.java | 2 +- ...cVolume_goodsTraffic_startPerZone_10pt.csv | 16 ++++++++++++++++ ...icVolume_goodsTraffic_stopPerZone_10pt.csv | 16 ++++++++++++++++ ...odMatrix_goodsTraffic_vehTyp1_purpose1.csv | 4 ++++ ...odMatrix_goodsTraffic_vehTyp1_purpose2.csv | 4 ++++ ...odMatrix_goodsTraffic_vehTyp1_purpose3.csv | 4 ++++ ...odMatrix_goodsTraffic_vehTyp1_purpose4.csv | 4 ++++ ...odMatrix_goodsTraffic_vehTyp1_purpose5.csv | 4 ++++ ...odMatrix_goodsTraffic_vehTyp1_purpose6.csv | 4 ++++ ...odMatrix_goodsTraffic_vehTyp2_purpose1.csv | 4 ++++ ...odMatrix_goodsTraffic_vehTyp2_purpose2.csv | 4 ++++ ...odMatrix_goodsTraffic_vehTyp2_purpose3.csv | 4 ++++ ...odMatrix_goodsTraffic_vehTyp2_purpose4.csv | 4 ++++ ...odMatrix_goodsTraffic_vehTyp2_purpose5.csv | 4 ++++ ...odMatrix_goodsTraffic_vehTyp2_purpose6.csv | 4 ++++ ...odMatrix_goodsTraffic_vehTyp3_purpose1.csv | 4 ++++ ...odMatrix_goodsTraffic_vehTyp3_purpose2.csv | 4 ++++ ...odMatrix_goodsTraffic_vehTyp3_purpose3.csv | 4 ++++ ...odMatrix_goodsTraffic_vehTyp3_purpose4.csv | 4 ++++ ...odMatrix_goodsTraffic_vehTyp3_purpose5.csv | 4 ++++ ...odMatrix_goodsTraffic_vehTyp3_purpose6.csv | 4 ++++ ...odMatrix_goodsTraffic_vehTyp4_purpose1.csv | 4 ++++ ...odMatrix_goodsTraffic_vehTyp4_purpose2.csv | 4 ++++ ...odMatrix_goodsTraffic_vehTyp4_purpose3.csv | 4 ++++ ...odMatrix_goodsTraffic_vehTyp4_purpose4.csv | 4 ++++ ...odMatrix_goodsTraffic_vehTyp4_purpose5.csv | 4 ++++ ...odMatrix_goodsTraffic_vehTyp4_purpose6.csv | 4 ++++ ...odMatrix_goodsTraffic_vehTyp5_purpose1.csv | 4 ++++ ...odMatrix_goodsTraffic_vehTyp5_purpose2.csv | 4 ++++ ...odMatrix_goodsTraffic_vehTyp5_purpose3.csv | 4 ++++ ...odMatrix_goodsTraffic_vehTyp5_purpose4.csv | 4 ++++ ...odMatrix_goodsTraffic_vehTyp5_purpose5.csv | 4 ++++ ...odMatrix_goodsTraffic_vehTyp5_purpose6.csv | 4 ++++ .../test.output_events.xml.gz | Bin 37243 -> 69240 bytes 34 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/TrafficVolume_goodsTraffic_startPerZone_10pt.csv create mode 100644 contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/TrafficVolume_goodsTraffic_stopPerZone_10pt.csv create mode 100644 contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp1_purpose1.csv create mode 100644 contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp1_purpose2.csv create mode 100644 contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp1_purpose3.csv create mode 100644 contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp1_purpose4.csv create mode 100644 contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp1_purpose5.csv create mode 100644 contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp1_purpose6.csv create mode 100644 contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp2_purpose1.csv create mode 100644 contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp2_purpose2.csv create mode 100644 contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp2_purpose3.csv create mode 100644 contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp2_purpose4.csv create mode 100644 contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp2_purpose5.csv create mode 100644 contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp2_purpose6.csv create mode 100644 contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp3_purpose1.csv create mode 100644 contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp3_purpose2.csv create mode 100644 contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp3_purpose3.csv create mode 100644 contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp3_purpose4.csv create mode 100644 contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp3_purpose5.csv create mode 100644 contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp3_purpose6.csv create mode 100644 contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp4_purpose1.csv create mode 100644 contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp4_purpose2.csv create mode 100644 contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp4_purpose3.csv create mode 100644 contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp4_purpose4.csv create mode 100644 contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp4_purpose5.csv create mode 100644 contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp4_purpose6.csv create mode 100644 contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp5_purpose1.csv create mode 100644 contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp5_purpose2.csv create mode 100644 contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp5_purpose3.csv create mode 100644 contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp5_purpose4.csv create mode 100644 contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp5_purpose5.csv create mode 100644 contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp5_purpose6.csv diff --git a/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/RunGenerateSmallScaleCommercialTrafficTest.java b/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/RunGenerateSmallScaleCommercialTrafficTest.java index 7aeefbf5925..999ea549ccf 100644 --- a/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/RunGenerateSmallScaleCommercialTrafficTest.java +++ b/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/RunGenerateSmallScaleCommercialTrafficTest.java @@ -73,7 +73,7 @@ void testMainRunAndResults() { String sample = "0.1"; String jspritIterations = "2"; String creationOption = "createNewCarrierFile"; - String smallScaleCommercialTrafficType = "commercialPersonTraffic"; + String smallScaleCommercialTrafficType = "completeSmallScaleCommercialTraffic"; String zoneShapeFileName = utils.getPackageInputDirectory() + "/shp/testZones.shp"; String zoneShapeFileNameColumn = "name"; String shapeCRS = "EPSG:4326"; diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/TrafficVolume_goodsTraffic_startPerZone_10pt.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/TrafficVolume_goodsTraffic_startPerZone_10pt.csv new file mode 100644 index 00000000000..bb4a958810a --- /dev/null +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/TrafficVolume_goodsTraffic_startPerZone_10pt.csv @@ -0,0 +1,16 @@ +zoneID mode/vehType 1 2 3 4 5 +area1 vehTyp3 0 1 4 4 3 +area2 vehTyp4 0 0 1 4 1 +area3 vehTyp5 0 0 1 3 1 +area1 vehTyp4 0 0 1 1 0 +area2 vehTyp5 0 0 3 21 9 +area1 vehTyp1 1 2 10 4 3 +area2 vehTyp2 0 0 2 3 7 +area3 vehTyp3 0 0 1 2 1 +area1 vehTyp2 0 0 2 1 2 +area2 vehTyp3 0 1 4 13 8 +area3 vehTyp4 0 0 0 1 0 +area3 vehTyp1 0 0 2 1 1 +area2 vehTyp1 1 2 11 10 9 +area3 vehTyp2 0 0 0 0 1 +area1 vehTyp5 0 0 3 7 3 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/TrafficVolume_goodsTraffic_stopPerZone_10pt.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/TrafficVolume_goodsTraffic_stopPerZone_10pt.csv new file mode 100644 index 00000000000..8eacf8fd4d5 --- /dev/null +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/TrafficVolume_goodsTraffic_stopPerZone_10pt.csv @@ -0,0 +1,16 @@ +zoneID mode/vehType 1 2 3 4 5 +area1 vehTyp3 0 1 3 7 1 +area2 vehTyp4 0 0 1 2 0 +area3 vehTyp5 0 0 0 3 0 +area1 vehTyp4 0 0 0 2 0 +area2 vehTyp5 0 1 3 12 1 +area1 vehTyp1 1 2 7 5 1 +area2 vehTyp2 0 0 1 2 1 +area3 vehTyp3 0 0 1 1 0 +area1 vehTyp2 0 0 1 2 1 +area2 vehTyp3 0 1 3 7 1 +area3 vehTyp4 0 0 0 0 0 +area3 vehTyp1 0 0 2 1 0 +area2 vehTyp1 1 2 9 5 1 +area3 vehTyp2 0 0 0 0 0 +area1 vehTyp5 0 1 2 13 1 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp1_purpose1.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp1_purpose1.csv new file mode 100644 index 00000000000..cc8a668c7b8 --- /dev/null +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp1_purpose1.csv @@ -0,0 +1,4 @@ +O/D area1 area2 area3 +area1 0 0 0 +area2 1 1 0 +area3 0 0 0 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp1_purpose2.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp1_purpose2.csv new file mode 100644 index 00000000000..de59ab8889f --- /dev/null +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp1_purpose2.csv @@ -0,0 +1,4 @@ +O/D area1 area2 area3 +area1 1 0 0 +area2 1 2 0 +area3 0 0 0 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp1_purpose3.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp1_purpose3.csv new file mode 100644 index 00000000000..26a96bff6fd --- /dev/null +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp1_purpose3.csv @@ -0,0 +1,4 @@ +O/D area1 area2 area3 +area1 3 3 0 +area2 4 5 1 +area3 0 1 1 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp1_purpose4.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp1_purpose4.csv new file mode 100644 index 00000000000..12ec403fccd --- /dev/null +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp1_purpose4.csv @@ -0,0 +1,4 @@ +O/D area1 area2 area3 +area1 2 1 0 +area2 3 4 0 +area3 0 0 1 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp1_purpose5.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp1_purpose5.csv new file mode 100644 index 00000000000..7e6891a86a5 --- /dev/null +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp1_purpose5.csv @@ -0,0 +1,4 @@ +O/D area1 area2 area3 +area1 1 0 0 +area2 0 1 0 +area3 0 0 0 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp1_purpose6.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp1_purpose6.csv new file mode 100644 index 00000000000..4f394b5d502 --- /dev/null +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp1_purpose6.csv @@ -0,0 +1,4 @@ +O/D area1 area2 area3 +area1 0 0 0 +area2 0 0 0 +area3 0 0 0 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp2_purpose1.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp2_purpose1.csv new file mode 100644 index 00000000000..4f394b5d502 --- /dev/null +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp2_purpose1.csv @@ -0,0 +1,4 @@ +O/D area1 area2 area3 +area1 0 0 0 +area2 0 0 0 +area3 0 0 0 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp2_purpose2.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp2_purpose2.csv new file mode 100644 index 00000000000..4f394b5d502 --- /dev/null +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp2_purpose2.csv @@ -0,0 +1,4 @@ +O/D area1 area2 area3 +area1 0 0 0 +area2 0 0 0 +area3 0 0 0 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp2_purpose3.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp2_purpose3.csv new file mode 100644 index 00000000000..2bf59089a18 --- /dev/null +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp2_purpose3.csv @@ -0,0 +1,4 @@ +O/D area1 area2 area3 +area1 1 1 0 +area2 0 0 0 +area3 0 0 0 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp2_purpose4.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp2_purpose4.csv new file mode 100644 index 00000000000..0ae1ae162f4 --- /dev/null +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp2_purpose4.csv @@ -0,0 +1,4 @@ +O/D area1 area2 area3 +area1 0 1 0 +area2 2 1 0 +area3 0 0 0 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp2_purpose5.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp2_purpose5.csv new file mode 100644 index 00000000000..c53d46eaaae --- /dev/null +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp2_purpose5.csv @@ -0,0 +1,4 @@ +O/D area1 area2 area3 +area1 0 0 0 +area2 0 0 0 +area3 1 1 0 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp2_purpose6.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp2_purpose6.csv new file mode 100644 index 00000000000..2bf59089a18 --- /dev/null +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp2_purpose6.csv @@ -0,0 +1,4 @@ +O/D area1 area2 area3 +area1 1 1 0 +area2 0 0 0 +area3 0 0 0 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp3_purpose1.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp3_purpose1.csv new file mode 100644 index 00000000000..4f394b5d502 --- /dev/null +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp3_purpose1.csv @@ -0,0 +1,4 @@ +O/D area1 area2 area3 +area1 0 0 0 +area2 0 0 0 +area3 0 0 0 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp3_purpose2.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp3_purpose2.csv new file mode 100644 index 00000000000..cc8a668c7b8 --- /dev/null +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp3_purpose2.csv @@ -0,0 +1,4 @@ +O/D area1 area2 area3 +area1 0 0 0 +area2 1 1 0 +area3 0 0 0 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp3_purpose3.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp3_purpose3.csv new file mode 100644 index 00000000000..72ffd6bb344 --- /dev/null +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp3_purpose3.csv @@ -0,0 +1,4 @@ +O/D area1 area2 area3 +area1 1 2 0 +area2 2 1 0 +area3 0 0 1 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp3_purpose4.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp3_purpose4.csv new file mode 100644 index 00000000000..4f435ce0431 --- /dev/null +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp3_purpose4.csv @@ -0,0 +1,4 @@ +O/D area1 area2 area3 +area1 1 1 0 +area2 5 5 1 +area3 1 1 0 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp3_purpose5.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp3_purpose5.csv new file mode 100644 index 00000000000..cc8a668c7b8 --- /dev/null +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp3_purpose5.csv @@ -0,0 +1,4 @@ +O/D area1 area2 area3 +area1 0 0 0 +area2 1 1 0 +area3 0 0 0 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp3_purpose6.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp3_purpose6.csv new file mode 100644 index 00000000000..8b670f48efc --- /dev/null +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp3_purpose6.csv @@ -0,0 +1,4 @@ +O/D area1 area2 area3 +area1 0 0 0 +area2 1 2 0 +area3 0 0 0 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp4_purpose1.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp4_purpose1.csv new file mode 100644 index 00000000000..4f394b5d502 --- /dev/null +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp4_purpose1.csv @@ -0,0 +1,4 @@ +O/D area1 area2 area3 +area1 0 0 0 +area2 0 0 0 +area3 0 0 0 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp4_purpose2.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp4_purpose2.csv new file mode 100644 index 00000000000..4f394b5d502 --- /dev/null +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp4_purpose2.csv @@ -0,0 +1,4 @@ +O/D area1 area2 area3 +area1 0 0 0 +area2 0 0 0 +area3 0 0 0 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp4_purpose3.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp4_purpose3.csv new file mode 100644 index 00000000000..89e40cb7518 --- /dev/null +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp4_purpose3.csv @@ -0,0 +1,4 @@ +O/D area1 area2 area3 +area1 0 1 0 +area2 0 0 0 +area3 0 0 0 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp4_purpose4.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp4_purpose4.csv new file mode 100644 index 00000000000..9a8d21f3eeb --- /dev/null +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp4_purpose4.csv @@ -0,0 +1,4 @@ +O/D area1 area2 area3 +area1 0 0 0 +area2 1 1 0 +area3 1 1 0 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp4_purpose5.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp4_purpose5.csv new file mode 100644 index 00000000000..4f394b5d502 --- /dev/null +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp4_purpose5.csv @@ -0,0 +1,4 @@ +O/D area1 area2 area3 +area1 0 0 0 +area2 0 0 0 +area3 0 0 0 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp4_purpose6.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp4_purpose6.csv new file mode 100644 index 00000000000..7e6891a86a5 --- /dev/null +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp4_purpose6.csv @@ -0,0 +1,4 @@ +O/D area1 area2 area3 +area1 1 0 0 +area2 0 1 0 +area3 0 0 0 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp5_purpose1.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp5_purpose1.csv new file mode 100644 index 00000000000..4f394b5d502 --- /dev/null +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp5_purpose1.csv @@ -0,0 +1,4 @@ +O/D area1 area2 area3 +area1 0 0 0 +area2 0 0 0 +area3 0 0 0 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp5_purpose2.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp5_purpose2.csv new file mode 100644 index 00000000000..7e6891a86a5 --- /dev/null +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp5_purpose2.csv @@ -0,0 +1,4 @@ +O/D area1 area2 area3 +area1 1 0 0 +area2 0 1 0 +area3 0 0 0 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp5_purpose3.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp5_purpose3.csv new file mode 100644 index 00000000000..dae6ecd671c --- /dev/null +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp5_purpose3.csv @@ -0,0 +1,4 @@ +O/D area1 area2 area3 +area1 0 2 0 +area2 2 1 0 +area3 0 0 0 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp5_purpose4.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp5_purpose4.csv new file mode 100644 index 00000000000..ab520bdffca --- /dev/null +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp5_purpose4.csv @@ -0,0 +1,4 @@ +O/D area1 area2 area3 +area1 3 3 1 +area2 9 8 2 +area3 1 1 0 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp5_purpose5.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp5_purpose5.csv new file mode 100644 index 00000000000..2bf59089a18 --- /dev/null +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp5_purpose5.csv @@ -0,0 +1,4 @@ +O/D area1 area2 area3 +area1 1 1 0 +area2 0 0 0 +area3 0 0 0 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp5_purpose6.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp5_purpose6.csv new file mode 100644 index 00000000000..4f394b5d502 --- /dev/null +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_goodsTraffic_vehTyp5_purpose6.csv @@ -0,0 +1,4 @@ +O/D area1 area2 area3 +area1 0 0 0 +area2 0 0 0 +area3 0 0 0 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/test.output_events.xml.gz b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/test.output_events.xml.gz index 4cac3132da0c11f74d82c2a80388c2ce0c30e3a4..23c2766f7c3d3b51432ff2bca512c0fb5805a36d 100644 GIT binary patch literal 69240 zcmYJab97_x_x_#QwmVbXwr$(CZFg$hb~|lqbIPf0+nu_{`dI0=+=p+l}gI^NBbEqF5ncHhJNJ))kZ3)gbFPQ_(AuOWjUF%%GdpS zGo&Z+?OIJsOARN@%pQxwrFF8(A2;VTCVGbM-PnHl>n8tmwDwVs!=kr*ms-_wzAetLH=E>vsDif}uCy<#yR%2kC3S_bs3P>x-k; z|6`fq`+dB!$D;ust-S&t`)>kYuZN?(-=DOdpT{Y1vz*`S`%xb7`S{T5_jNyG(EIND zI@9}c_c+SX`|kYudCagKU*7xmbiW<&dN^Ul`|)|0|3Xw-{&2|=@bB9NX{pq&o&Z?;ocYy&vzT6#Lsf@AF?D^9FfapU2k$ z<}hFDEK6UX`}GQ6Z(n{d$Mpf9Iyy_+4A+)-t(k>AU9VPWxlnIY^#TE3%iq7nWrkti z`9{G1<+1nc;l3BY=Y7WD^Xa4BAmHn6+yC|OynZ=#RPywzt-$a8T;cnQQ}?uArRSWV zzAuXb9}@z;6MQ$9EC(;?VetY65s$450UwWE*m_Wdf_yVW3;`gz2KjBu0d-~@Fh-kT z=;Sp-pMKu2k=>0;Zlo0IoGMoOkE3f5shR5ivTYS3fErfWs1!9`^d9ih>yb}gD>3<} zUcZ;me++&KPfsBn_!o-OSZdc_-f6R=DvvvwGXV$xuD_O?U>&vpA#CRd__YhUf_3TZ z^}N5oEeizf{xDGMPlwvF3b{P)k;d`uPkDcK4HB?ZI9pi{`8sUP?+wtBf4i&ke1CcC z4fr~)@BLg4c)6?J{(63}m=#N#XC13A`8rk*_&5wsE)>n{K}doBnDBk?JMFwwNa~~# z#n6?5Z^YF#f^Qa&@@ zZglc2g_EK*(x-as^V?0WqbdxY7hH$Gf3K829CQmoYH5+(gfI9eW;q-#$INhS=C3qI2>N z3Pu1pND!xH)ACH~?nPO;etBvY>qkyPLru8mLbU4?tVpJ?vXDEIma%n<~A6Ay$G>+G-p701HB%uRXo1HwihJr7jB?SctlI5jHB2edX{>Z3J;Hzr*TOT4cJK)kShEC z&kv*8PYR)a1aVxERyJ`y|EzmZLj4HScp_aDfjKrR_}A|is6B0;7;&U%GO^<0e)^y?iSeMMAl- zJ;Z_c&SU?ulPk@M8&mt0kDsdizPTv{46NwQSBuN>-PTiXqJ1FkE~Em*ip!xUDFc3N z0%FrukC8z4gMoxwPG$gfuay^RPcg@f5LqJAEZ{fK`0Le68UZ5oOxGY^K|Y3bfpxq~ zHp2xulvXu67l-C7Jyc-3Ufp%oERRXp`o^Oeg9x|XM5KdD`Z#fsojm~>JlSPxASDuM zSfn2sve|80!i@<9@j&BTr5h1{MLOC{^%`~}oP&v;m5()SfuWc+gpjlc}Dk*H%N2uYGs z0d!)2otFyOzf)YU9H9NtG@mY~iPStl6Uyi|Dqy>xQ*i2nO_e@Dpn!#v{Cvr2Iqrn92% zo|K_Cal}c*bFfao(HFC%qAiRo_xtu#1YHNL&b(_Xm@euxWuU6cF0l6SuK5NBt*0IuKR>ioxSv{U(d*+{@)?jjo6=1V=- z-k!Ug{X-(wOtlNi2pf)`I=2_8QG{g9qiKkstN!d-8Cq52>)^2YRqu39b#f~A0zXF7) zZZR4UgiUy3BPKs~`gCgk`TJWI)soGggWsgmL-t3?_y?Gt>22F5e)wsWoeqH)RX_L$ zIIBaW2M(NH@@si6Vi!^SZe7*!;%*)GFkHOOe3cSLD`I5;vQtt7#agDC|nm}8+#jzR7MxBLYd?kVy{Ncd- zm9eR765HeSh=EZ zjKO(rAY!Jf>Zp=Q7fT+&*feNao{_m_ll;@bc#PaIIAwS(Aub<#Ga z`%8XJ&`+(}qqRKMjsZ4%ZEo1`?Y%z~)KVk7x3))M=s5W(&pKw#mnuYD+(<2!tK02- z*0q~0{c{)%DFO3O=DBpiA9gM_bGBg^_Kw+AGA^TH#T&Z^rPy(}8~2g&6EW9LQYhI? z@IG~oEqZX0GYq=z#8emQFod=*3PqyOV^vMf?fXqOumkGaYxoTizqfYjY5-?b;#c`~ z@uIX56zBw*kh3n52TS3+!)8LXuDr_I{f)k40rS|=V_|a}7zR?I!u7@^qV%u_b9!9XbC39pjFdb5R8!@37^)l9DfySn&Vx1(nbU?gpzp7JIFxI+0+q2FM1oCQHR#W4Nw)8S|uz2Rml9tZ`Z;yRndNBV{N z_hYLu_Ih4(AoO$zkvXbh6BdfWtptoPh$#WDtj{^0RO*&_Py?eLZTn4cB$`4DoeJ1B zjxLy6ZVdySE^k{Q7$?O$zrkrP2006E%d#xP+z2=&L~7(=o@3PS)FUVCReaundO=+t z+k6On{^M6xir~#>Z(8dI4aWD1{sJmr47%O{t_szOTjdvd?k@C86@5zOlO(PR#YkZa z^L%zPFpI(WO;pW0b_d2{#%i*C7Vxf?p>6g5(%Y64ewO_Pjl4o5uM+~vh#?#KGmwvl z%tq~m0M5<3&7q}^{NQ`ed)cb^Fs;IU@M86)!I}Gc@9;g*-%c>3x9Yig8KsEdO3YIc zRXc8C*FmaP~qg3Yv~^usbZ6 z8^+YNhRk>zRU@to^dJ?|Z+_q_2PRx!p=v;&RcV!Ega>7??+E9BcqGGlh9djVCGdg) zEE<)}c9fO9!vTi}F0ARWfU9Mc7|v{I`_|Wn-z|ULNg7gF(?y}lkTEF^8%6bomCk3^6XNZ@%*#`)v{brmcsn7PY@6LiO}zMUF_q; zWu@$)KnyHH>vsd13G3miH(o(-T8_MsWS5RWP|j=b-5Q$AH2$@&_Gi`H6B3mlp3q^* zQIfC0FZh$@IDOs#tp8DcKEl0IS+Gu;?2h`b z#D6#Xc(;us5o|Q$=2A^4BxFCK+;mQq~^-+IB0W zZ310HZsd2J6Z~US5I9TXsw`HmhN>2jLqLy${tVV?;RP69ToEB{G&LmeOr99Bq2`!J z@YJq|1;PpZQgah+`I$}85oi7I2j*ECwzN4~m_>Ze2-h_nv?i&VE7Vp?k9wwK*wHOd zq>KP@>6saF|{X0mSOA8s8k-X?tORSBK)*(Y-b~zzl4kv0C zg?H}zhspF@RZZk*;2&m;UD9F-jNvhr+fbB~e zK8&W`aNWu?<{)5{zx=2@#J?m_NFMk--P{d4m(&z|cOE?~XtC&`3a+OI2X=LZ%vAM! z-j#uW(zDipERFv(ly3{Bd-tP&e#E>Aq|4AkbTEPtT-%`kc_|`&wKJyjju^)#Gkd*r z#nK$lX@~bb-9mTHft-e<(LEEnhAUPVqf*|!VD44|b#kfGh@ zp97)atp@!bAn*rpq#oI<{Vuwu$I&ruK+__EXai7sDD432Z=gYrBAHGG|rTc)b2(W)CcYLkzgJ0AGftMHtcl zkrTiDdv+S(Dz|m4v+%>0?#>=u&;Xm?N`qA0n(!Y)JU#44PjHyg(}maZkAe1|+tDc+-v3dwXs>>X>a|-cjVfWIACCe=7(P{lH|(lg&(< z^C5l6G7NyWvaLTx#rbsX1aoJ@!zwFmwX+Zhb07|W`CnJcG0(9+G3<6*%$>G^LU41bRO_Fup8l$dIQwwmU!~sN zV}1bbDY-XVAk^eBuE3H^EHM7QXnt)+@M)vL*tt3B7 zkOrr@9;g?XcxDlkN&9|V(X0i5qdTdhpM<`sGjI1!{v2<7#*fp|gA*5xc?=>>>_>J`HXY6BLg!XxnFwtrzD8 zUAK~_m|sOcOp1FB`h#DTrSlK;tEmizPJ85br)9}FQcowJ-9(7 zi75#DiYnjjNKjDORIZFrWcTVef})O%H`*nzhw=#sGT~u+xvDyUo4BNDJut-5p7%mn5%M$ft!-D1}*n!i#YCg&oDsCmj-|K9rzlFk9$YDF;@U98h)O`xM2xvg}$Sz}}=vU!8!}`QiL& zn)4_SBJ1gUphRf156zI^uHv`$1JupUskJrp&8n{j;P=o246QED(!*)?GvF`H^fbhV zq*+f#1YONHpKtHh3ISEDCgpzy&WDj(q#4|eQ>}&r(|=K&wHt?WH-vY{>|0rs3kl&VBUd$Sm?voatrnYoPh%?gh8CirEeN)VQ(GAEyas z(?HfRXKz9nzV_b&KHk3ZS?|~T>9D>VO_?`sMyrCS?9iV2c;o>e8btDBbnyQ^H8A^l1V0^Yd}$>u!A; zf>V??{aTloa&U5gd#*Me)Rn%G^-HnieW}LEd?^=w41f6RuUquz(>Eo2o)7p^V#+hn zFL{_UQ{S8_@;UU@_f+`m+0naBvTU*DO;l%h%*elE3YX*AUYpcT1NXQpyM~+;+zK=+ zDY6Btzaq&F%e15rreUW4*R)=aMyhpWPfL^Ag7H|Z&K^TC>*lJRXjfb`T#aJPS<9Bm zl+fsB4j=xI1eu}&DZx^#R_2m%Rp0Q!%oZj^gn~$U% zn|qqW2Z>V*x${s$WY(K-r0F@T{d-}a@T65w&KFS?llV*D+1FZ(o+H@#q<<~7Zb_y0 z$;q?P^Tzt*mld}Sl)GjQkxEZg&0QGA5%j>lV#LR+Zf*%rxE$@0sLUU@hn%}@GSOxh zRD2}6q@L|G0PT1DWuM@V79_AvTv%6>3s*!t32o?XBu;=CWZimrwo35z9`-3UJ6yFI zd)fpB3l{xErB)SiMjgO4m^G&Sh(v6?D1as1kIKcoR2`7o++?Nu-zH76FHmz@Q3rKC zr!~@!{qE%5OJ;j)so9qac_)HHi0`zR_I{Sy|FVg*ZS1<2(>Psl_MSJ`F4*#1$ZG66 z#Lp{ zxVIGt&h?Wpy!9vb$pB(5%{CC%{}- z*#4MjSBE}kD&1Utw#*UNafwp9fmcOaufB- zQsik9i0Fha%a@$w2Wt~4%0At1m=rJs0UK_vw1!lg&Pe7ta$%P`R09CGWzNjC&e}2O zA~2U?bfdm78QUmflKLQ{D#xSxp!S4;zge_EV>u0Jz)aZ4M!6TRR!vae#i?KxUi zVGyJ4^A^ISWnPe?h+{Rd>diFPfNX+`>Nu(?H=vn6M|)|etN6hL+gBCaDqPG=>{B4>@Y~L>{*&tZ?MiKX2>*%Ds6|UYUBwkln&FKmA5J^`}6jf{}!Tc zb55?}lza?7{P6nJx&MC4N1f_H9Ze9; zI;y&o1DrtK;Vo_P5f2p8ZUV1uvFIP!#xz@)v8^he!|Tl2>}*ihZX2LA%A)G0HJ57nUuUfipntWgbo@K{e=@BS23|{lU=&*2Dh=p-X1#J!a`=slDR?}}d5FAV9}5b&Ql_rG?795TnRz1&W)g*fTs1hVQ|3VM6+ zk&04x<{66!l^amI-oz{oTUg}ozonJ*rP36?{KRZFty*=PhUi<+7)OlAq|NR9ynggk zu~DTotkqQMGAs~+J(}~O@67p_qc)wcN=a05nS*oVKHqAU5;PO~y%6YThaN;c-etG` z!5aOS<8QSkI@6SnIKHG+cc=y|2@B9^*+E8Mz7#SXWPQm6ePpzP4B(k`oJADY?+3-2Sf157OMyv12TrF%K#dm7GwPZXCPJ!By&=ch-ce~ zsEsi;LDn!(ZM-e^he>qU$V#Gno%#t<>J;syVR6y%&fa=I4^eUCRB->4+lC$Q$y3D+;mle_u6Y z)A}JX4_)xd*YxKI^Gm74#*$i2vx3~tw{w=xS-sc2#kkQ+Y_|q*Ak5q-pjR6s?jc%d z!+l@&FC490gw{Wiu|%i!0Uew!Pr>{70sR7{ULzL}UfR;pv&oUphkMHBxaaFH+;k}HH6Y=LZTW<$c1V`m8(TXJFZUuTtoM^(W_{r-qjG_^>!H@q-2#z z+jh=ug_mJeT`qjeG?_RN=wr(>bfy?1p8^Z04n<+Qp%gy+0SXFvB7?z5e{LLF(*upqL! z`XsC-ulN6$O^bNLMaQ<4YjUe2!U0czfVtZN5)vj6(foVQN zs;_!a$^w6$*73mtS(ynkSQp-Vwr)ePY=cCoJEHi$x3ooX}jqlJnUpjuj zT$w{|3!6!5wkm|qi0qShWT%5g_!J-iTJqcq6e-yHF>K>uZxd2yZ|hV~yZi!a!* z7lnZ6b?1mb1J_IY#A~%Y4dd*$iB*nwJ+=Y87$VfuV=6IwG2O?^1@rucvwZ7hojTZC zEQpc{)+X<5{1`32PRH8PyKVICe-ZZXJ0ChWT=X0Yz>%&mR;|{(qm*`{&$V=IJh!}{ z?tCwDDAu6;`O~n^<`_$|GTw5%-&ABB(yj@s=!U6R|CmhoPfQAETSNxGjTkieZMt91 zZRCM$YZSFz!MWzX8d_`pf|W;gO|O;T5F`-(=zyJ3L$x%BxiK@#FsD8%Ve9x@K;ms| zzKkHYS?GTpWTTHUl!d;fQNdba*)_*}&zw4;!HWe0T)9Dyfj&{etzpf@;J@;mq~kK* zgPTlm<$u(=mm94KdtU^oNfHqVwZ%Ot$j&g%K(0n-4#sq}M@TzSk5n2l?^A0EImT{| zssqP!y$8`OO^L&93PbFKU*`ChS#GfB#z0}yU>LmR)9g0Q{`>IlG((Q1QNI>kg|L~R z4^-8P=^3yT%ZR|1Chj^k`g#gbO&7NfYuo-gXHPg9fU?KrGrEJY^wwEod5>8Z;h@pd z_SvR|C6QAW{o}km1l$7w^n^wxs0q+^1Cz$4p{&rXW@vU!lmgj+YoR@1@(frU9czXZDcY|kB7KS{C{?|DsQ~G{ zm)7#(Hs=6Ce#g&*MaiHutPsvNGDiyxBO=HG2IrZsE4yIze%_L@$La>a)FBpkk)sCI zx;FXT!cJ$B)UN)~pQ>ecRqGAI0PO!M#BkA2z2lDK9o8RB59&b{!@~zLkea9X?Z87k zr%^J3`6tY#+ua?anQZLAiO}y9%J&%`w-?U@g+k% zP}4Hc!#4sk(z%~u(M8iD?&zc~YI#TlsC29Jnh_hc&x4P?L2xYGAsR-RxX26azBbxr z;fcjHC~2u7BJV{t1pFo@<=7BJ!%c0A6_jSMttkB3E30km$$O7GVBQN+R3kI|<1Y@a zAmCVlOm@&cpY}ZyN(sYi<*J6cm2Bs5uED1cyYTQXfv}{;AVoeMB)6=&P!DLZ77wRF zxSaSj!V0VmT23FZTt}sCE<(0r2J;M! z=h4o`+vm;FdZ5NzI(N4^J7&F3pCt2`BK>eRV!^1p8NSPm0?s2|RiD2XOxdXqkp1+Y z^+j>amT;Q@!hKk+w-U6=)P$6IkEc;VnRPkg-=wlywP2q7;+*{i`iBb(Dl2Dp_SZBo zHr-;NbP?ur%KX^bL<*9}U(%FtknX${pw8#;)jh2`@!f+0F0=X;+4tX1tWAZf#eLj~ z8(~0ZaCOa>Fkj00ROEpfy+~6L_D8Z1n4x4=r1uI0gZ!ysLeM3AR*# z)-LvCJLy6`EXq1$bbuf#C__7qDW zYTcTIasfLygiQEywTB7Ox61E~4OfV{Zkl@cO=?-$nw`#KPnWayR*Tx_pqpf+>(4)p z8V4owf%^u7pS3e#(PN3~YEJ_MnhocKMl{v>oQ81I_7UImp}=-X&2GP1DN!!dS9)XM z{PjOa>5bdymT;fhe)!VnPwK0DIR1M)watv+(CdcqcN4#)y9U*?`xAz%y-KM6KU1J; zf)n6OJ+li!4{*U%Pk#>nC-)@%X>pN0wpG7YUbStd5|S~u#s@WUx0|-iQbe0yh(n?W zOUelVy-N)qEkdE1k?`dIjzj#Ky%F1}tmwMIMjg{YHF8^Jz#3vzO}th&Xz&!S#i^&gd+JeN_Ed=T*C%{aCZIQo42vRvTk}LWXPAN4C%W<=A!CorlibL_s;Gv(}m#SY0LUE;! z5^Q3f>MNZgz~^;b;42$&GR6ILx8e}s4^7Q+hJqZ5g8Yiy>4j5(H$?5ZwbnGV5)RK_XWI90g)A?Teh|e^57M^{zT9$1 zc9dCs`w?Jp%B`(eF#_duu%-fet^;UDc_+~uuf^5~+HVTTU^%efIu*mkLTuz0t;XUc z<%T#E8u+uS^fOy5g}aG)Q*6dmEhwK(2V{^5mnUBmNkwru`TPXXppd5tZnrC2%&VA8zizpyGpeG4F1On2|y*$CSB{?1F*dG!LC6TSSBUnhC zhqRV#h%O)!j13wlLL@UDeqYHwMkg(Z{2MQCfs{s$Ji|k|n_i>fy&XQrYBbt>bJ6yt z@7|kgiM*U&xfSYA+~Yki7=Dmfd!+(FUq#Hg2TCp@(`ma>YiX3i1Oco1wz{SE{+Wox zUSJ~HE-qvJX$ZKDEE>kpQja&hX8@Isp`~VyYgWcu#qLs2RCS&=J8~$?T-tBT`@SJF zupBzI{z#tXJoXh{06^xpq(A0fa5OJ08wy}31r}+}OMS{Fg^~Q6tp6QOQbja>DMh|f zCs%L#ao@q#$5yVs5K>L9`C+4p^7m!m87dfx);XVo2+f12v**N2vfM8diq_DyH0LK(nb=;E5-%5iR43j;3a%MFV{J; z$8)S!Hvqu~6Pz%0Uaj`16C6VTS2N7o7d%*s@f&HoB`P&u9qc~8SFY4S1&dMWW7bHa zx!-pO(T4*{rIey;J1(G=;OQjy70i7_XBlO^+GAr~N!zx#=!n(~mI#iT^hu_P+?Y!e zzd>DH)O7%ZHmebcSWDxc3MTqrl0sCmxspHqd)u`VD>NPoo3|>r&>w=D@n~;W+m>@{ zRsYW!bKV_FmU4G@k?{Y0EYhqREJA(emq(=PXeswgbpAdR^~@b@Hu$pJe%bJq z5D`%f^de;vA@xX0>F*RKTx$5dH+pfGCR?CwUT=gGEcriK(eW*9XUW*1ki1R;)2U11 z?G3~uf!s2$!KV6o?%H8F_qtlg;~xoSbLJ7}CG9xmj`O$chz7EXYH8Ioq!r#1iz4*I zxrfxo6B^oeMe+*zonFtstqg!D^S_qN<}&KWk`|qu_E|KlUSrhVN?iqu8FpjAe)XR_ z{i)e5Ed%c?9QPO6`F&75dHh~c+!AsTesn{=E(BCr{mFNuRi(V*0lqSzDg})sZqVio zW00S{JASxr$d;K%av8{4ev)f3>&z3q%)1F zUmsDUR_LqW;DG!2TQ4pQB9770^{hi(QULo7{T#~Y^j^$zzn=>q&`^@5&>w@h$;Cg0 z0ns3R7Sgp?LbM{i#2MFVQR{2BuS&+qqg7;~x&Mac=_eIsoo&!*zGjQO34wdF`JxyYI+;S)8}WX{(0W!1C~;*h0Cq#t zve;$B0e8MFI?7>!A3uM>HyuWiN@P>wCSHQsWk9#)0Q!^qDFv&*YH63mkHCw4TFLQ#Zw%^Y=-YRmwwBC9@rVD5y8{DlMjrs&RA!( zQGWa-mT+hIk1ES}=~8 zq{@N&5NeOYr!cdF%HyBl zFyf#1C)w@esm2FHVlERI3v>JoxY;-I!i0cDBcmBdeoV{Q!~e*R&{cDL8KL|afB4$E!oc#7zJV_zR*x83YfJu3NC_Vk zmNsN+zP<4L|I--{h4D%nst3Ge`FlBn_l!!JHM@nR3H2!|Sh12&v{1*@Lj1ZuD;Ylx zE^$0MHT1P}=yJ=bX`n(62Ap-$(tQYpSQcMPyL55?o;h1FY_1gguBF$D^%UvJ?#)MwTI=|Ee$~I-x%ltd zjnXQ4OKK#Ea^?k>wO|nUgM3RRNeUlpFpTfUq3hulPO)K3*4BawyuEevX0yk`2<&a* z;h0gLYY9++?rp@8O|=Au-bY~?afPQ#Js+pdNO-`OnHS|RiH_eCRWY*nCydXZ%CPDt zp}MmI)xUwMD#=WtTsZ}RmCepwQxw~Mtp%hiuxdwvnP_$;K8={auOCk- zZF;YdeBUDEuEE4FplmnkH~r=w3&B3&g;S_+sWMi7h)uzdq!=^*?v|!NZd{K`H z!2~|bX}Qj!i__Tu0i^Q-@tQAAIthpQHun;HthJi%55WWRhErTp)%SN@r>dp@z-fCq zo79kcLk{`NCvM$1$l7?{ki9o^AloPz|4uF>bl~*ld#E)B4b$c7V>=x**X$H%5eWl` z0TnABc4NneVp5L8DA8eYw}%R;tdL}F$K?Rk%8Q>g;^OQ$Yvlh-pg7jUx^2YJ9BMDm zz<=e0U$5VaNKeC7VSA*pjYUr1DVBb|we-P`=UKFs+WvAE;+o;|F9C`op3c33CRrxS zDylHhkQ`_OQ)EkZw z6mdFue(shOCFKS=U=s5}FiP6o+|4&)4u}WSn`k~i`PR^NO;9Z4B3cw0NM4aTTfo1{ zc7+tnOb?0ZG=cZ|s3TM_GnoCAS*mOW+5_VcZh%RM-|l*>2lC$v{#mx+Ul;C5nqS|5 zmW3MiTE+>rl+Y|Kpc>sGS!7JSL&-7516MIMZa&L+&b*;=+|Hkknl=Uo>Wyqg^T>it z*cBtoI``)h15di*ybt`Cp!2TT^AU6uN&tKkB41`jgaRYdiEc{-X}< z0l#>Jxf5XNn6f^y;Y{OW%|LwHjy&U9ki<4loZV}4r*=M``Ez}K7JObI*Eb0=)8>}RJ<`z&Z1=b)X&v)@k`e18-T4c#5=P%-bwHoK14dJ%vx*Y zoyGqiJoN24*gY1C#6KyeV0E%j@A&beQ0_+1$k^I_K?r#_yLIw@?4WX*edSP5P-V^Q zM=rFu?CCv*5bjnRdi^|(tDqD?VX%LC`|r$4w_yZzzlaLJ9NVl#wc&sOaH{2vx|E(G zrt9BYk?B4=sWw&qP+s?+0T1*bfPvHOVA@72mg=luvc7klrlF1bi zpk|&(vo`?V9AO}jN#Fe8`v+~j0q3XM9`~m+=yTP>`cq`4JL=HMc3>50Th==S%Sz}% z5o?FHjdXAGvXk5yK5}wI@xQ!tvY`H@4zF_xkop>-K5YgEzCu|cu#_A!;KzIVo9Cii z`SeY>86K0IZPt-eVH6#j8h%T6DxiyKyCPx;qrWLyMbBwG0%Fpu%>{5l|&N&pNu?p$q-vs%!tNTavS;zruNL zoc@grg4xO+b*Q1cSG8-jv{kPHXXSL#Dj^$JbJ2IO9!(<{$X1})m8M9c(pq!xy#~#- z`nbbR)$`_W8VEB-Atszsh-6a);#xNh0=!iE6xW7e8*nGgaGl6p9yYtz6io_nbxQA4 z|J!|9CV{8!2hvp!GWT$ncu(H*$st@d#fMX_uOM7*lgU2h*LLyXA+>J#*ybR;d_n^w zTF%%-lfmGO?a=9nGJ;n^O6GsM|K_LJNm~w|>#1ltPHf^TADIj_PD0_tMw{CI>JE=3YJTjTjTD5q}AYmfcG??7(xu z#D#PJ#^060d-q0Y?lVgzhSKTh=5MeaGLQT82F>%>R_LZb;w4h&Ra7jjqxV|b(-Z&W zS5--C+{ANA?o4Xy9Q5OH2&q;Oz}XkzEDB*D64nL|6Dx?>di%w57F9Z#K^k|byO6x^ zRLbw*%jAK$u+>`wB&sb1#}Bfx(aw@}$u5<^mN}lo(1~iBw>MMB5RWQcox}S||8Gdl z+*R~*w<=5ZB-h&~`ceM!w+f6G|B!PK)Ro&r?x6=^piRwB2Qp0BqINMHFSb@|YxV#B zA-`j-Ap~y%&9I4+ODZSN>qoxtyG9O;M)!Qmz4D~9coMWfN=E}m{=IOP>CE)}ZCUAz z3x%MiDpaA|XNGt6x4r3xze}x)8}QsxkBq`JdJqExO*<-FfM1MedeaD6*x-EKw4?PQ zL{E-LmK51~8G(Y*IVY{k2d|m)0Mk4tsiHuqnoCHU=&~00IwbtL@u~ZMj`f{?qXVl7 zyNuqOn`oeZC0h%QDm&ENyw5eLurv#dnewqO$OvX@T6&Ur=u4G57#EmEOpkFrS)w);%-<2jq4qI-fL@B56-at)b!Z%{+<6Z#uWL{ zwDvS=H$EwUjLQDQTu9m;^MUYSCaK{LLe0pGFv_!Ov+_!=tUY-Jw(LLN<_l;13J(Om zKh-}clKZ(5O`va`Z7ut@R!3q4a(nsfTxKOGv8vo33Nmu&aa;9)+BP%;YHbGx_1nmj zj-XhLD#y?)vylj+2>~GIJAVU}j7%;KJ0ki^niU2!-_q6Z<0qkJH$wXo6jT4+Y~#Kd zI`?cMv(+uzR=#45^-Xn&Oq2CZ@yO!ZZrx%LyXJo>He%+s;p(2n4Mmr_lD%P?ZGCOd zTeV}DXO`U|zli{8agmndO~Z-{IPA``Vbca2;IwtQf1ml;8)u{OrZhg8nsWbYetOC( z-g|XO1j>!*b5AW6Mzv1V?#84+@*rAxOFZ^BvzMQ#b0Z#fr&dWVvW^B|-h6IKEmMsW zDPe*$c>zbAutRxaiL(2 zbGg&UFr3JWYJ~q){Ox zXj3CB`d`cfSLOd=7MtmT7h^f+btb~-hIdr-r>|ByIV8aS6HUS114aY!2vhiXOPzvUA4_b4=hhuTPYn>rAO#O z%4Tn9Zvw~M;GLGs)E37p4sCZi+SQg9D#&QpIgtlIO(1Mr=GEZfWwPaEwJ_JtU?bWWNrrn>e|u7`P$Ba8eiW5s}#cVa@^N}Byzq3 zCMTAd@3G|`X}-gdAXTMjVa;^7Y*9XY`c*!Ev?R(7E|>nV2PN$fdk5@+AOB2S`2=Mg zZY5f*Kmm@ zZm%`0cHfW|wV&YQEtJX@pqW1>vm>lOY@Csi!rQQ*9{51C-vu-r0Dqa+oGuY73BI_V zoim`ZHdYpYR&QH%#9p{{6J)`M9?}d`Rm>mqp)4B}$S_1~rxF{T3RBqmFT>wy67<&3 zz}aOkjK%nQrJGIhOGU@goiPE@;PTCNl}^kpS@ir_4+udk9fOz}-D~?W>8)sYzMo2C zm1Hf!nm5GORpZnW3km8vb7e8Dc9=IKN`(57$%WFgZ4oxs!G!v_&_XLGVRVEw8x|@| zcuqkfr!BDfnU=5|$d&e3JJ1qUczu}p2b7~?Z~dsAMY9<)lM_Z>nnJ1`sms#-pTwxS zE1RguQaugM<;45Qiuq91t{nNZMP7=7yGlSNy)L7xkWxQWd+-)=D7x-EpvDW(R2C`S zw9;W(Tl>SheB0FBDC;9WgUNCx&0p#~hFs11VLTQW9tb1^x@t#01DoU_kh43N8Kw18 zL1PHIZDyL+HueAKDfh#tn%%JlQqQba7pdZ|1Y-xcXZY7|ts~HvlIt)ahf~^bL$2=% zBZj;BqsLDDdoKvi1!Kf0zU3(@f%So><@>!!1bHFtp&dWqyRakPraP4maubf@b69hh`TxiqI8C+43RH&Ex6s zg0PgQwD?x{T@W7Mm6jpu$!cW3i1^-i+YuvN6NnX}WWMi>yU!{H!tV#_QY<;?97we* z^p;(t2?2W(?|XCpROyPSH(3>=w%&9i0ESYN@Mko$c?*}Q=C!kVL8!8^{s;-ZOyLQ- z*Ce_0+qt4hmaeTiw#EHHOO4ElYVEiiu(=b>GGDM{tt*v1aJzGOI@0nbx=Xb`IYSu7 znyvNG%9f5sZaA=yH*a>$Xv*EvB-ADm+kH_h>zp&aXgcVdF-|ShgkK#Pu9aBP1*lQk z=fWpjLL4o+9FwQyK@$)9Yi&{R`dl>|Z&>1l<5dF;PX|&=a4hDo2;7UaxqfpHkuF8s ziYjwHVoJ_rG3(XGm6>2b*Uy2!td!;yK%CAn0)4`HP zj9nl880mjc)HpNP$-DZA3#_bjSLl4drtq^+lJ)iKOG2+PmUE}jRxv7fo%#G_Z>z>J z9WR2bxF?(4Y54m5Ya5EE7_Bn65-Xe9X5rzb5t~&xk!dYfK$2pu{AXwcsopZh3iJEi zIjaqu3@?`krxw71Twxrk0OW(|*9>EyHWpRKPe0&}BAL2qRpywy$)WFnub&6~5t>9D zhOo$0Z7h7$X8yer(j#J)2P6pavsa{$^J z?0t}?^{>Yovh^{FRs<|1HWimvX17r5uBHZ*m!-6NsM1~jV>1wW<9(+hh`j4uZ~ulf z0ahz8G$};QwY;=ijE~%~dK&%d&?ni_o_B$&T6k{w18)JCBgaf%#q?pD*e}De0U=>v+ZG4K^C-Xh4jH+qh1mV%VsbTKyQsk9uPv zx=ed2)*^7|q2=x57{JK9U7**~sV!$%`S;W~O)+k(%%v@x!?!OrCB-RL9kt*ReF*~= zKg1nec758^FnV-5>Bs0yBemc)(gqaF#$-A-BqR0UHTJ-nui~bc{S@<&B?SiG9sa_E zO)|b?lUE~y4aH!6log|7e10ONjv4tj0c%#TcD}UeUH2e>YQ79}aIm8P>$a^aC?!O&dTZ1|xB zGUw?JDhVZ>^bz($k5``lR#D#OIh|nU8zMx6R0~kB{?a|K6|JbHGaM=K%*eWtunOUF zZp&wP2KYm$he{9-`gh?W3F0-}wn>8q>l#}z*@ykHCeXg?YjoGX2;wcFo&1B(&dnR! zv4zs(rCRa2gDcfY0Gq9qlh8zvT?CMnhyJZOe_7rF1M}zWJreUe%mo^( zOA%t4fFyqQGO3j{-Hxt#?3=1i{-H!itSA#_OYRYJlylmdIVH?C?I`GrlnkJy(`;Ar zU|EP!dXtY_>_URnG06WE1QdUTn-9?3{C$b+otOjB6M6~Wb-eiu1VcKK?q1g8G)xe7 z(rF(T0@XI)@2U;Nh0@}lus!wE=iUSOimOJv{@(E+9VeP~01lj`%Ebpc=9(=;WoUKj zJKpPFH6#x-Z2;A0v0+15!oPIwF{){a`zQFq}A`%+E` zA)D~>EwwK>Nm6Js-rJWXR$F37&Yt0*bFY#?n&K~-mhv5Y%|3XQa~=HOK#$qDbiC`t zmb}w{(`The8uR6cJ2Tx#fOEFks0%tm<6mKcS2hgJLd%fvDaObgyFy)xGq>0gsdGJB zcP}MMLRCXZ)O$~qsHdXNh5n-X{jG%LHo*kN^M%hpZx-w=ycf^-tyKiw?>8sAbms!d z+@`(8HVZg=y{0z%|NE(Oy$PH-o~TbvjzBF>yiqdBWD1PdPD)h2MB1i>W59L*l#WcQ zZz29=*0jn!P-$|q$Um#ldDNhL)l3K+!PL~B-Gu2;)64*Q7OVGxStt-V6wmsf78*0G zur92>%5^Li4=->0!oqQ*hqvSp34VUJg0Gg53q_u9;n14RqLsQR7l6A`KO|ZRo=xIe zol$QMse(qemR=9B5)(0-#hdK$)lh|Vy$|ZG7?uR0Cwm!q;4bVq<@m6v5dDx`q4nSysf7yQUxEvM^wA zcMI@{nH?O^*!%#DQgbc2jKj|vpH+9MJWeUk)o-qomY z)GE-m+FO$5A;Uxl!L*ILOC4jz;n-#j(|O#2k->~(`^Y14=X68P)NxByElAt}^xFHc z>Vf3jv^EC4VYCD{WK%a%h614f4WqV>MDSX=J{p^{ZceA;x5MPb{yY|{9PsLCAwOmwU*0#3&RM3YL%39T9fla@ePp?5em#%DKa~m0oj2_4z zCN>3DTDCx0lX10`T+G_%W>~hPw8>wA`=$lvw73KaOK7B^1qUMTZq~kZn=G z?4_<%Zh~_*!yx>sJg#J78g!~Z!V2LboyEx2X(}W8;y<`wB-2uP8>Ei30c+Eo0e8GG zb41F%@=%v#%fI|9XAsb4-UzV2F8aS75I)31z(ttKNo=iQcneIq4V z=P3`~IzYSv**Dac!>Vqmko#9Qdkqu?*m9c3y=mH&fph2_{1%nP#ecUB?MFM7^FV2u z(-EZ#NunsFcHZX90-rsL^_teYW&%kN+(paHmq*zU$E{7v#W|gEn|4rq9gP$>2_5g6 z6qQ6Rq=|bso~z$U_6%X0hP)3Z&%|?e&^;X-gQ2FAA*@$cBH20G4WCZiW~ttS0+)Ho z{8gAjPspm`@9KIsvi^p2hd|sVB&@$Y{!`R}hpO>iO6c^FrM9Z(d9=JYm^XPR8K#4r zbG%cW3cP;OnF%`~GB1vX#SQXB0IizyO(xUtd>lL#6IDHEvZ|b7ew45&`VJBPkd{au zRDbG@J}wP+7u5XpKH8`X79G4R$3GY#S5nch-)QytLHmodW)s}qWb_LFu2+jv7@pq~ zexv5EAc#Rj%CE;j-u0iqdd{_Z?tgT-QW=_;QnWz&PgOvBPA}dZF93%45L%G0m*@Lp zTGOhS#uk{`Xen;6#FKd6nH?B{+C(#PT_wl3whkuFdh(WdE4tQ&=?IHk-hbAu88XQp z1eLB+=IMX+@bv)@`;@0eivutepH##BsbS%RyQD_#*t(T}l5fh8q9H}379<#BE zXBdbnohHu;P`whJ<%SP$Xu)n{I{0-TBqs+|<6%0)%^C^Voxj;TcXh(>^wzx=nynlq z3hxfh`+2u%g9o6<7oNwrlsx_>J6{C~%rqNL3W$Dzg6#K82ZxqQ?P;~rV$oqxBR7r<`!yWMGQ9gbl+ zWSlaxR&l<Kw8s$h1UoA3;d_^Q%I_| zrBheB|;F-CdtwEa81rqX7;By_7~; z8m*wpc0dS8MJy7%VR%{kgtqW7{zdvsjfgsEtT+;C zR;}OKR0;jQ74$(5Cz_svhiEE`((OWcAjwMYn;I9qb6BuGHL+7=aQF}-%|_3DS?f(j z4pHvFX!HH4n-=_I&?}cV=}aDMq{TgsgY_|25$FedG-q!8;;*|I!8%ATGTEDhwj;)D zi+_*G9?Cq>ngJ3!ca_FhNLPGljOJeriZbF!zgM2-qv?KZWq;NCsJ`^TnLU<*PYt%z z`Hy@%`~6E6Kf$>pl=ow$ZMZ}x5(jh!W_y&`u#Ad;=zhC(Xh25c?FzP4VDk zNF&>Bt)8l@zngnm_t~=;HQzPeDR!~FupJGSYfE(he=}*sGXn=w1>x-a|Iz5%TAe9n zc@WUX>&#?~4SGaBO$0SrO@!7OMmq>R5Sk%5Hvg3~&1#Aw-`qR@T0_@4$CjYAzjU~l z%$Nqx#EQO^@(XmlEBpO?C zjsop+h=4m|0A)H%Gb4d<_d6#+L>WI!EkryDH4D!Z(+B~#bUe!bWFJ8JHPl^_yNpT5E{Y-vZ5nINa!u#{oPkRRY z^Q?E@yuHfU1Mb$&GY+#J@iTiZD0N&<*rHO&%~oNemHgI^5S&|*pul#T)49_faO3)l zpN|+}@T9^Fh8orsE@|Zf1>K<8&8!bJyD9i5*9QwC6ld_1?;J7usjrkV{UjG?{NlUx zhxiZ@^i+5Y?mS#L5JZ7229_AiCE9IL&P6%FgiM4t@5*9Wuy#e+rua(-no6#fooipU zLM!LHHB&3xJ%FWz6ED9YJ%E86iJ0nE7-w}TB>q1sZP>g13xnTxE6Rkp>6M|!sD{CF zX_BB2!L`bCwcWNE!2HQmzUTy0GZrk`e(!X`1WuM9vQ*Hs%yuuh3K-7S8{_+ca-B{w zCor>8sui&RJxqOJmB{t30PJweSp<8I0L;->-S*?u6hON1&g}nDYc~<(YVy=pQHkgp zh$J0?1bgLkN~>fSxBL9XdtkXV;z;wiJaqw+fw|a9LJ{oSqOAHyK+NNc5 zC-g3*BigAAnB+!g3}Xj^VRWfZ>w}~9%CNA3yEc9VVQ0yjfyZTK1Pk$paNXde`i~0e zXMyHII1RZ2aM}vlSePFAO30HxRMC)`dbnQGCD@QwdcdG2x zcN@sp(m`Sp4Fpu~^6oliq;VvAlFw-m&BmXB!R_ZNY{x*+?5~_K9iI;%APe~!PnUdx zsn_`X&t2S8bwS=t8`|+H;ayx%6j6#v-F3||2P$Ba#%myI2_3$#|x z@jI9lbq=&0<2rjiibVpvN~l{W9$6F4s)5T`t75dp?QOecMv|(Q|m14zgw0<{sEC zge|aS>zBEPbk(Tx+!3&w=%B`t;{8Ocld=sVOHpbaF7B+|kXnJnx_H(0`+wF-kpUZn zy&K7%cH9AkTYnfv%bL>=$^hPzc@o^m)0*=0m&rWhQh~wmMCv~XB7bl8el94PAmwdU=aCpdW;f%%*K$UsQKIWb>iq_-p0(*zj?mo}h;o{8k}Tz9Eb5gJ4@K zAHxeuedE0DUAxWg0_R&5B?Z>*&7;?CrfEZ6biVzPhN&|9Fz*!{MO95fF~1@0(8|_g z7C9?D5f;K0@8lnqCOMyC=@-{OX0<29>L@J6E<=x58Xj4_mab~7%hI8%mCims)_2{W zaZe4~r;J!=L;|yW=O|jtw$A7P`%r!`IymN3=2&H8iBxu2{Xh9e@h|Ohd9DE6ViHve zGi<)17VrtNrPY{9C;NUi&B)#`+s;Nj>e!X~W>*vmWt4EP3ysmN-aP`B*B*%+)jecN z?=Ve+HnJ$>$`OJg)Dr*bq{@*uGXy&<;KpUG%m|_d*=o*}C}u$zZu1&Hs_!~jc(1)C z8+R!#NxdelSo5Qc(QRRU9+dtACpgHt(BUsv zBp3va9bt7QHp;-MNIJDCvl<2;Sme~m|NDr8LqUfIIgieLPW1|W7cnMv3eE!h*7xE5 zHyJX&9&=&(y7n-}+2sQ}rj9k@orRlyh5gC&T5TQ~?gB_eD|Y+eBp3$TXyDhe9IE96 z7PY8{jKU#w3MXv83*LicoK3gOKsb`y(gNqy0o~vsGI+$wWo$`dlNEZ^zobvonL%CT zT}9;@SHS2j%JhC&QluXy{E)2X_2A zNSJ5Y5Mt$%LjX%YiQ7OYOP9v{T}vLfuB!&oBg;YkT)1rOa_Y!%sRkcOL-_@4;Gh^H zO0kAnp^@MxpE;gR|Gz4_)PnQVXB8coOHud}F`i=9<**WN)fVxF>oS@1NRe47 zdjz$HA9L*@*181D&ORtkBoxvw_AR6(IE_2K&ME*HV{j5ki^*iGTTOXfzblv0U+VV}|)-KBQCBck%3 z8RDv+7ta10wukoBRelLUQgPlH%fY$|=xi$h8}x-^fa4S+W5c7C>i-_c&drj8#@02@ zvx9rHdUpm*$@va@x*X3Z_W&IQSq8Z4zYj+u{KbEZ7HgSW9B_`0Ld|z!w)+<@{LnB{QRj_+lXNK`HFy0|_*32MvEj4VMlHy{w*dJXZEq+Ku^5(CcA7F{ z5LMJU)T1n$wa7+faknnkgx|nnwsyV5D@Vadsg`N>?&80Da51boso3)OQ7As1s=hEN3R3p1i z<`?8$f|R>~4L>U(F%0J2KKmY2OxVn`F-@hp;yuBU4B~kv0Nz)E0UC&&cqc`huzPWQ z^j60LLricr>dZP5dKn0tBF=VmKUR>Uv=-Z!1S05$669N1N>PL($0KIjgK6l=%=L_( z7W&T~yu0+IlzTp6G=NA5I-N2k<8NQ3C*Vg4mWw3_=}n@MTxIS}*rl+GWhf?3=QS}p zufdGo0D$2=EDWJSER5anuKp?2Wm5IU#X#tHwi2Aiqe4R}M%38h__?rxqSBRKOS|9; zr{?`5InEw>p!82K?_~HT(zLpd$)2`_xv5Z#LRuJj;*6!aAuebwmzc7mta1*r1yC(f zMvcc(Gl!ivwz%!N0>~AWYG9WcDIV?bpV?&94`oZ^yBk8FD*N(z^G?0zKVxdNP4(6C zJvCgFFQGgSc|y&&Yf(^VKDSw6uli$CXwx=p>Iu@JtDwo`wa4U>2*O5ec-~8wi$J%6 zHg{ywjN{iws*f+*G%Gy?Ge`LT=FMNWX+3m<=yNnlbVW>Ir)8qNAnlXzed)(p{u{mj zC4kr0i3?WKFeuI%k3_etP@QFE<#B)dh0M00lJ*E2QoU%UglcS0N`ij9MG4V9sfnl6 z@IuPwJr7JhLlTtN z(iF5+$6&sBud%LFgnhAu6t+xq)u9a|3GzPqf!NM8wo=~kd$l29N`A{q(J5&&&m+ku z#~~r%d0Pliij$|1;qp2qu@-)wGA>b)gbKq`skNqmLF3TJG+^65oj*cY16%ywW0?Iu z-1R)>z1j>E6L-+nW2nzPzjhR^P}j+PC?BToZ|z1_FdwVT+R!^CXLA`>ujy;ian?`! zD9>9z5%3kQ{v&RE!)Ev=^aWtvn-PNHYFTQ_IE?ks3d$$wdtu%;1k?;2II8OQ`qp<@ zaTrq7s7_X11OJ7BTlzN-6c?QXDkRA5YC&j8dRG? z?0Qgg%|+)5B|Za|)-m;C?O9Uje(qYBBWfy)h5S46T3Ug?RS?odSapkdB*~%Szwq1& zsiGIsdl~z;{j;DdM)s@}qv8X-!{0UjkGR==II&&f>8kA2SU|-qUQig$R69AvI{ewE_#=V#pZ1uWLnFrv7J3OtK54xe-x z(;3ni$;|R8o73uCF|MyegUJk@R7TQwC|aY! z?xQe8?f+!p;96K5#vQ0oyt!o`iL?=boMkVDII`s(YcfvVMxOGIrq(9+^bw+&25_h! zCd3cv^c_=(8s&(4x;5Tef?x=i--OJZmKyV$u{%}2Q_1CI%@yuk*7#Q^(xXMT;Nvl8 z%tN@O?#0V%m4r=nG|_*?U)8@vy_5hI0$hwL0q;*hU(IK3zj3~ z2zoukeY;7nMT|Gm{vv++oi$Iz*InLnu_41lf;U@Xyf8u2rd^{^ea?bg)4rasoJh!W zZL-Z?x(PGIwce#6n&SHAQ(Anf(1lu#ulXbGRV*l{z>9W}yULK}TM_iEYgYTTruZs> zF#yU?KB6i_*I(2)vbYa%5!|?7iB6c{uSP+vZ?hZYDU!wjPSwg*a(|PfM2?JNzN)adRD5@u zPH{HXe9%Fy9PY9@%&)kJr%sm}U{cq))?kf^iBY9WulnZT z+TvU+fW`Oc7nRxuW%P+amhP2;hZvT&?)4A8A&xyzNKb>#spS}^hTu^)>x>XmzxB$0 zfdtmZ>6CiwD4@}yw@VLWLrII-RQx(>wudQmv5hAltgh1w{LdbWV9zqJ^GbGYjNZtlVQXHVANqYsJkZ((G#w|Nfu>^#=X6!RJrh}6Nl<`xLB3@Ow(B4v zSy8q|Z`1qfl~UtIrw2fjxgA5RuH4>f8vxm)zxugr0c?cUt6QX=u6FcSqINDwgmSEO z>t$+O>InIy63a>V3Ct|)d4f7(v`O5#WR9z>@#LMm*7dx4qh9)!%xt1~hv{UOK1rSe z<=4;ShzNM=?(bt}g#MM*T$h96M4tYO>-JsgS|)PUpEJtNj8}pMk@EGtXttpOKhxB+ z(zIX9{qK_VWiq@67eY|w3hw0ZD^!=$jfoyk9m`BB5X66f-VoKgNm#ap9uMN#7^{F77vSX4&gJuJ;ta zkGl|h2}hTUS5^tyxmj(pV?wU~iO;CZwK=twYmKH(pWky6ewVmi&%SX~=KGc7HEfn| z>R^FWyoB}rLM_l|T5hW33QfMqMT#t)B?IF)EU&Rb$A9G-8K*-AV6fzS(Ky@p_~&OW zQAqxY|1iF`F2jW(KYV3(_NV{vCFZ#`GwT3M>mVH4rm>6dWRBNvZ_~!ykNTz!|KQ!L zs=02+HYr+)wD6-{C&^|TI~zC+B$}r<#hIY#|B<#dVRqn66Oqh?NRgiGuGI^mxr$h% ziEFBBj6i3qW(QMuGD`x%kPMwaVMq+YVjF5jxJk~*qzYw5kHt$(G;4K+zs9(2ikfJ+ z_k9Jz?oz|5Sc<{M?&V<-m22J|<9_>8meuAygJcQOEQazb9-$&1tG;?L$JTG!@^M6qdz3*M_b&INO32+otaY^oE?9CB#dnb)IkY%Vl+*xp*;76+3d2#1mSbQ6xE1 z!k?I9e|1c%zYS-85&wCXiOKNFxLgDS<`5|lZ}x5X!&zr%zN}}LxUX+AEPZ4^)!2N` zwgz39xGk9aWF`Ce*#O2NlAJe8m2x97{>Tx24zU|lPakyCf=XOt{QfW9l388Y9yP~A z#%@si(reT zR8L~Hk9HD7%O%X&{xJxy)%f2h#N3}wvQJsUjT|F8$4qLhY^iPFYja>7_m(E6>?4TEsinA^h z|JK{4s>l#Nh}j73J&dnj)8n9(5FtZr=UR$vh#p^y>g_sLI|vPdoVJeHQ+Fr-ufEb8 zwk=uzwsthVY{NQRqj>NpF*f++t7k>%gdIFnDWLbjA<;?1x=_bBAqoO9NHqx?D{Gpk zhJqpx5$gkS(MEU~7NhjRZ;nvm))>7XcZ`h$cCsAaOQ5?HIc0Oht2*mQcw5-;iv%c! zy zhEef!oH-uRHfU%B7Wk?^! zpf6%E4!(2IEWP?uW5wD7i0rTxZ*p{-TP}y+rrjuRQXk0bk{hJm4T9CNw#yM#S3~?Kl(aTr)pT_NV_fN&;odv;9~#(%2|1`oEb=j$XBW&w z|MxjN1ubi?CU^e_ki0{^G;2ZWH(5fku*CdS=S^IV$uK~krlh&IWU`#Y=V1**LY zz-HZ7qSljAe(^5NQ2+iexs9AhZ4H6l2>rpw^u!NFoDOf#-Qy&4b_Hf<#s7YnLPKjI zX2%Llj$CN+_dXdXSsX1Ws#xjmI$@rpqI?)#bG)Ts|AL{E)b;?naaEu5Z_mwIc!A?} zDy|^#Fh>{l5N->lKR|c-7JC5QKazjnzXyA9gXxzENwMvUExqlCT$LJUd?mgguN&g6 zr56JA$0XEpBT)*VgB}+`PLa0=9kaAqBnYZ>(U$lV7Qw|1lVyqsMb`(hVROf*kJvQa zv!L?R70W<*n{%iu$5p9m46<9;E`IWRSY1#7HIrml?Z_mDZ8ZN>gwi^g77~OSizk|F zX)|8uF^3>I2|Z6#KgVfCHVRXk_Xqp0Bpuz7h3bkwNgO6EkKDcj@any=Pln1b}-Pr;2U56=$!s>k2| z2}&M>KPP>> z-lh;=IFDibD#W6 zfUCR)khEE0*U>8_cg7}ncmDWNB;uCsb!7E!KH9%cb*MH=V^OrbDY3`bMH>y2q2c!tlMUSkg*afGC zE|)o)Tog4X4414}G4X+b-zT{Tbe_uwf>Wiufe{Rp7V{yKym-Kc- zvAW{Qw&#DFO_hq=AXo>m+SO{Ex;PPu)m6^$ua~hd85|*MeB@;jcX}OmRN=h4I=z|b zuoU$3$_?AxUuG)tgSJ!X4Y1>McSYHxcd1wMwrT*eXjixpyPh2y*-85#3^l7ku=~3f zPeg|%QeuCayJd^It5s&P%DI>?0kEUzkV^a}*v@Gu)S zWPSgK^q6BZn~3P9$EAI505U861zb-_DD0aLd8GTGgfF#NY(_f2?f+S=rY1kWQUp?i z8=DD`1BPcL6)V61@^IBFeMIPSjVGyB0sC^A^5xe)H-LB&gclQlRuVEJl3o(B(GeN- zw92ud7H*ZapL*K;7yt0Y;;NF=A5LCg5se%L1$2Yy&KtNRd7x|B+Dn#ILv)II0-t_J zW`}jXh)mW7jhUX{p4FdOMJKVdlmXX2>fG%Z1w%)&Wqq%6JVBFN1D4?kccSZKR91|J zy@c8}5%>F5ZP3Sh{Sp3=^{UO!sY^RrEuHJda4W_3l& zNezN5pNzLp%V$d9BE+O_+EqZ$`pc^SZbodwd)#4fHYeSTXF8(=r{aFI@G$z)<8Z57 zKf2yf)+r3?9~~&=mOYAMHd9s>@f#UN1g|gexoenJx32Z4xCR{JnAV40Hb6l#@-AYj4n7!l66XH^5TATMulZU zzk9;IgAETkK9c05n`p3e$O0n`Ch#_vztJS%pHVI&R+4=2t`#Cd7L#_@` z7d3zy?FI8EawPApUDLzNItM>jJX&}JGtSnvvtrwH(zLU(rZF?hS+|c4AQl8pENTvM zoFL?H(*JXf8!W-g3Us3%C^B2y!*84Aj>?NIR0p96JUdMz^%Kg^B@R(&*Y{SP3!JcH zt{4OnIJwXGt5w)lJ7%9-Ebdzxg?DMycu!V~FOyiwvI?+`6`|FUU5E)rM>2DHYnCds zJ!iP>%6LY$!ed&;!iU(Q|0=0OX)Nqy%N-!!+p?Ly^WR)$Te~s&Mlj@NziHiZ z>0W_Ser2$};Rz^0vVvkVn?4eZ zEI=N!;9s{fd#+EUf9;VC6cG>7Tm;kY53`^+n)`cCzkh={tIU)UzBQTeaQu0z*|f z1^1TQiT(M^W;N4;MLw{090#+mmmFx0Ybe~qBd7*5RQVpUYsHDcyr^Nz|HIw3Ebv)) z0EZ(F7SJcvL4oK6wN;a@2vb=@+V};+iP=df1hx9vxu@go;&0@n4>7RiDoJ*B{`@EwkRl(JUjqW7c zq#LYjZ;jr=g-KUG5S$u)XWWa&$Ra@&pE-|LNtyM7Tsu!z(PIJsdQ&Dv#0D)`3F$gJ zc2hz1gRAIEG`>z{NSPdwq~1_k)ipLc0ZOejG?L+nDuCt3GC8h(Qq{w)ww3shayyC| z*OTFc6O&;!01(#IJe4934MM{BknUlA71Gk+?uScNBLS;uwU=OT(zoUQ6cKDlG>XQ1 zz?0@B;z|b6<|J+Q_;QstXR-;oljy$*nclf6KOAo!0#mEhJ@PkZ|4ki-R0+z9gtfxF z-_^2MIFG*^N48LTBSVv;1^nliI4x|>=|UC^bDZzQ{^$fhHC?pWzb#b0@W%ehqsaO) zi~;LHEEY2|2br#4;6(Jx>{$s{V#1B-T-3pfh|#1ueC_850hE5ySI1F;G7M}b4W{P< z=IdbS6!U=+xv1CT=h>6f{00JGNy7u#~yuy+HAJ2`hZv8JF+|{VY;>z zCFhT;K|<+unj>Lc@0Ww97VKd=N70Wp+rC|=L3HdXlD>F)rfL5Ko^-#WZNCDV7&t3d zbnRC_I{SW_7MAvfJM~uyThKLC(;gJ$j2Itpppg~4kyscEo1+6)k=iFu8kf+ItQBx6 z==ZHvE3y?o(9>MGi_%M1R=pQ@rmOJI+7mlF|0~G?h{tQDX*t|=* zGsEerWE=8Cy8%Gtvf~+*x0b6Ge69`Pi%Qhps*3$Cn*u@1%VSz{nj0j&wx(oQbpD*J zR%D|qQIW2Zes36bS_kT$wns!j4@}R9d1+>lRasPYkF_UZUF0>UV^X0i`3ww-{x=sI zxFD|WE(`Hq5$xX4S;1uMg z$2hB)Ujxo&X5-bF%F4Z5S{xB#NI!9|HP8(0b@9@u*NHsil-%_;9Q{ts z&tItG`{%-yIIujBqKL?|j!8~_SIT`6@mn26q7CGYEs{U{A)tvK@$qUy;{$ZD#yjHg zfCOzsYrDK;Hr5Tta5*@NNw(V^a2%~DCA&OFSw3lZZJB@=eNxZS{1Y&;b<0_yKG&Y% zo07)ZeR4xGye797_zdU{tJYf5JJ`iawF7u07Tkkd?elNJsWBC84S!%)JuNH)%AG#n ziE+X&I~|HJihsyI&Z&LDakOyR+TLun$pY)CMQjspp~gEe635*UuNIum0um<~lc-Ad zBe_LfJ5+S-@s68PK08EBcunUo&cfENmEPws4c0icvRt+UgV$8~U05>C$eeFrO$cBV zWdiibL>h_&TKJp&3`Py;Uq04p69Y($MyY6s@7$M&-H#@@tSrBM3 zut3wsc2^1jsE9Id%K1R&&Xh8@eF~l_B1|8&IlsREOG^lRA&rY48aNhP_$J0i% zgR7;i5x&9-H`jJos_0aX9QS!>uVQ~xn_>{U+9{M}DC+>>)!53JqP3(>Geg-YQtfXK zAGl%YpScs2C5=R6i4pN_jf^08(4lxYS7%fGS?X3fjlX$U^A~rIg_dj2zK=x3f@Gi03*yRF)9~bxSyGI*)x`@OX|2Rdcd&D50OA1 z=;Q_hK{lQ4ZiAt~?wjHbUdoD?HXbhm=-{3o$?)xx3VyXt4s_P6df0!}S;U8mJR!b1 zOtk)x*}uOOS{qrsc?H4Y=gMptAwau)SR{@W*FawWu7LgvAgGZyO3Uu$f#uVkbst&nGqMLBLAIHLuSvQF;8%y zU4N})uKi##WTqbk*?ThZ2V3qe-?v6PGqjjFGo&{Ne$gQ1G1|H?0|7j)@?Y;0d02Kk zhWTTU8u&M8YXhdAzBZ6n>#e$mnh&Vhy7nZCFNxfM z)_*FcFY`i~3mTNLQGtD2bq-&``@?~VyKhU(uvL5b_cFQg+UbZRs^4-ewSUX^yaqtk z96)PCSEld%o72}2(&W*rO8f4pDqX_<6)|v4CjwHNij*&L#t?1FG0%9w{9DqQLs<~vvj z^{HlhXfwIPG{!oW5fE@Ffi3HCXGO?nt?LM*sxh}&$W`?j z9qXV01>q^yPRUpn($spazopbPtkTWLfC4m1k;*QRZMkK!k~WdvSaxiVj0if)VRSnZ z7_5@neqYQSL^xOwF0zdM(LG;mW}}>!IQ5AEN*ZUkw3*@}NbvlrXIKM`1hx~Yu3J-x zL#BAS5%00RhjU~!$U$$Y?3}D#qCmsrR0@RjbfIvvd$A>K8Qom%D)(}VcWe46WvDk1 z=Pg7|(GBe59UQoAM44Ns>;kRxiqLH!C3^`Tq&-95VvMo~+QfI5BI7>nbCCzF%Oj_< zo?nCiskAw%u4E7(ta{ysT3=V1AxPI}mx3wpP0C2w_<#!nyPXsMKq6E;*LERK9b z!9t0@5@D^5_{z`})#<`LIb64Ny+#XS_g2R`z^jgGYE=yes`4iM+p9_NE5qC=04C47 zQiZL6e+_xaqgOgLy45?XGUSB){U4|0ke{Md0OtjTt~7@F<)Nm3o<`!W>2*=+1(fbE zdwGM+xJzb|x$IJia1~ZiEXbDxR0LGJ0yL~=)8Qf)$3lKr+(~c}4NT6&WsT`Hxzhb; z4I9gx{j7R{X*J!EjA=58tqm7fYk+}&cWwDvhO;L~@ouuBDqT9K2w?eg&DjUKnSn#;We z>^twV)00EHWtBSLG9kh0Cpp(s2U&w;r8cl@dD>Hmp;%oFEX3p{px>)!bcO%(>M;>O zpN^(P5dKu!H6>O{9V=VP#^x3|gI)x zO<)%SG&kBv$+9%enppE%I7c3Y!1`BviHgaNtN+pTjp1=VZ`&I+Ny9d_8r!xSwy|y7 zY;4=MZ8x@^#@wJuHcp=H@BhAEa_oKVm&rY|GpDY(46@o65%gM)#g2261k|H6^-+IVR3SSbjPEgj_1`nrYHYRjAp9PFa4+yLih2Vh zp$>(a#i4dH;B0KrqMPZpzIKQhY~*k2Mbt{?AS!G47-LpoF7kFR2@ym4SY78M)8({H z@Z_69XAWFSCT~*q)6u*8lnc05q3xw^V{muJPMxaGR=56ICvOn__7-m~#_r+UtZQmd z7b9bM4YDq4E*v`Wsn|2sqEwjNqzd~3{@bAf>wAq+&>wr3o)C@MhkC$Izpji;fQ%w!Hv zyE&K8mL_~GE?SW=s&vLOdwU8F#QDgm2M0Q=D08VRmWV)K_PIj?WYU!rm*Y%F*-0nLIM8+LFj@Zkpg% z2pba=Vc7qlr{s|=ESV8uue|p6@sjrL1B2w{2r?A)CTCrS_U^Jp3NI3I1LC~|`3;-x zB71WAj^vXWYIQ#);PY)>a&~C)zl(v?7{l(~+)*7LoRr`rz`+p@-MX*n3oOa&P6F_w z?S36A3iDlb8R8bi*X3aC$JBOFQ!Jqxag{cFDsf}8OoTOf8s0jdjD8H*5rgMeCSiD_$l5}mb4 zsVAeZ?i5VZk?Q@@CipP_$3BS(^LjFKp(>b2{{X2uNcE-9z225ij+e6--{e^mD?Se$ z>>ez~JqYad>s#q;-X{t*@K)>Z*E-p+pp8%B_$N4hYR>&|Jm%Q0E`3~Kye@UotKWN` zaK1@|+Y(S(_r$3f-gRfIAjJZhILTmqrqLk3n#b=YqED;!a71ewty+! zlug^3;}Lr}6Jns39;k)oA@)}RR_Q`FP3Gqn_=gKZxF`Etyw-2)tk3A5iFSNi6O5o= zOic3aLsQpdQ&U`PXHD?bDoGpOw z>pVGW!*|G{aax*-a;mwfKW=k4l~?dv{!+N3E8GfPu9l+Hy+7$dAZGrM6y0!?s0(y) zRKxyvTg!(0ReDXy2DrwWM#VpZWaHHI$L_KeAgpqu@ov;Qs15NGxP#V_1ldU6p-Rb8 z_~(jP+8c1#Z!Qr#NfRn$V>MAd^&A==kN4~O!Z3h>$n5@FLmFHReb>vTL&Na7J8YuP zOI-$ETZZJFZePARbBg>wnNk(-*(v zt+`->he;FPBCI54>~LPXHX7LO4qCAOomTES<);4#>;GtD0dJ;l+8!V037gB}_-68H zx(*8mjx(Q(5m?nSsw#+E+?hdZ9Mt{qqW>mjb&^89j}Kt?mMtxFOxX*A4?7Z_zM2$y z^5<2q+P(A3Oo*e&$=fR~c~#laufK`HO(;jJ_n*ZosUmvI*Uccp&`ew2|i2cf{0P_ ztw)7>Mn>CZ*jPEX3~|!O7rGLfJC~72H$-3l9uo8eyqm28Sqs+k>V(|}w;X@2QVnn7 zqPqrkg2fW?mn;sQV60$L}7!)czYg+6H zqldFW<}t#0aj^&b6 zs~3i&4u1Kw54LKAa1h>beG92oBg8x4_t9k^dW-j1`Ux%A6lM8nC6?W>d7WXK?- z%Y)60emD{2E52}t`E>{;`3pXe!fIRMNJh%kjhLg zr)^x7eGs6dE?bIikuYC1i*usx0^-I%rI%@sge)v4Fn{?LjPd|tr?9G>#e>)aLHsa4 z1717qYV%E_=l;di5S*CAsN84uITN{)$KTCj^3VM}%^UDs8ghV2Rf%)aWx9P(LxyXG zt5==LHf+cxqn=i|sC_1@p~iY`S#L2koRx@ksP*)Bmj%jT!sra|(U`n4Iu3kw7F~yO zSsh}ENQn>pziVgsbSZ3BQ=AYs6Cy$usearBxey3cr>|>sFMe&J9O86N7gV%`Z}*wA z>w&+zW=;bw+Z~n;ro-ZSpt^rp2!)mYg&RJ{Vcq@_WG22#`dWX20(@wXjAAB@i^mIU z?7R56^bqzJI}5SpNA`G6rnWWjuQb+0@lW4RUpoEr?%&>8{U)8IV6xTHjC5&Kl{J=K z8HtJTunm`3I=n}%pY2vt=NsfXZ$#NCUNSGLp6#N_n}huysj12l8ceJ~JNB(E#CpIb z7m3XcocHY%WauglqdkpF)hMlA_GQoS!0JAMc7cN@7ri&)ng)=JjO@C3+;Y`jCZ#?wFVYZIprOw3t^&_2ePD~G$$=ht7JVBZtUvsSrYUj-#rTUM$41q=13K8 z7LCMq9f37cA_Km?t8r_oY5vRATXhqs9FTSPMpka5v^IDXTQQ&f3l@LFhXL2Hwq5U} zA2>I%zYNYZ=sIy0Lg-H|Vr6nlM3KnIzFi3_S69P<#_X>)CZpKM!)UGTO~qxkaQ#)c z{>VgEC)j@*-azS2_Y}6oIDz?IW z)Sa&!t6zRao~-|3R6bnpA7;8evO~_Iym{c*zV6dUNJs<7X4u)ly2U{tZnrc*Wn{BN z?~EJ)=jd!#M`INLHSEl>CLfwwzkL~s7% z1*Mjh0IW>L<`ii=#YW3=V}+R6(gfoliaM|@%`O7deU#;v_Xh&{KxJsRhXD!p`C=`B zXfs)0fw$cUB)DyfyZ9Y`q(Vy}F!GkO3uPWFwF_s#@GD=-Ocdr;*b|CMHok>L?{6hF z5l9-=jS%LqZ+2am{^g|*F<7{Y9vr2N&=<+v`z_^OqOEqErPS3V-W`(zhY7Y@5WK&7 zCPaq%fh0eN1yCUV6yb_Zx}!WhF|X2-+Hy|vi(iDK%NR7VdL?R|xKHI4-x3B+-yUCn0{FA51z$nWB#3U99sPT3o`~VxU%nJL)G35{v}AFXm|Tbm zc-Ze@$D81SN*bg`K~HMo100A=?1%7<{%!N&ZrA=1_!PpmsV^`eA;+`^+Az0J7Bluz zBC=B`dC61+x`yPRdZMAQ;IS^nKW6MZy9eIz>Y=n^NcD$n@0EmkwaE-0cgV{D#jy63 z4`pE*(2k~XtNLf6U?GXOD#_dsY;uKEC6=rB>9~Etik>Fc&M>3AuNo>|;gjA6@e!kL zXu;au*xtAI;rofM!(wJAZIfI&dWR9;nfV4GEn9_e$sgE?(7?Y>QX0pc%SVyM87?_7 z0b0P;`q`q{pOsr{KnOsxjj$=PFRluv)Hls$W{be{DjHe$Mwxb95qE}S?c@1p#KOh5 zxE!@{6Jx0Cq9iL&en<671ju|9MMAf)2JfA9lf6etx52NMtb?Os1HtH`e+BHEM%2#f z=R#-ufF39;vajTKk%X|}HuKXXoY4cQT}QTA+&@$MgANU@fJtWl>&i}}eqSt+y{2u1 zQ(Y!jM}zhY4U?17H!s78JT<&hE+4PbU z;+S=Wa3_$$5O=U++h9JMGj#oOgwlAq$T8&7oOWi;RtxF^qiLLefAN4vnNt2 zIii5uIX zk&XplK_mdmip9`bX1`S5$kd)1p(TN^@Hz7_?O|10`FJP ztf+`ZD;JF6PB5XqBGxk&c4p81)|c^NscZMd^)~r=j*#h9@ZTs{_LyzX1SANn;WXC$ zk_%zpP0h`_DRW9DMGvB$qdkdY2BwA>NfKmhb+ZDSmVBghYgATiZ{kx23{T_@Kqi4$ zNH+lckf7!ut?3X3mHt`FLBDz}Z^h)>ujkQFt9D(xx5gDazJa|(WOQLSDa*yG z-~5VH))ya0c!d3^{7;0u1zDeUX#itB<+5C-tu#Kp`qJApBsM!W7{1)?o34;D)>^Qb zL5qAM#gd1`^ z@b~AFELO_Osgw$Rw|@h}$S-nCTWWi4_0xO~xvUS~LKdWXngu_})Hh-E#*3X}>bW4u zyaqo%T?`UxmKyH+LfV2Iv6ai3%gr{7ze{Hf-CwFZUQryKC?^;`3bDxw#rZ*^J_3bD z3&R5Nx@*Zw3gA*KIhN)j0yE1bj%vh)-J8y$Tr{R%H*uZ6WCz^{Nkp@MxiRv%JhX-gFq zzpoNy^(xWu)9!m#ezNY)4^UcT;BI|pnbH7^smP$-i!^3fF^$e8mbZUeIS=71R9QGv zNF9$^vmMKhUuf=VSWucdkK2CdFfhxSv{tp5S#!9K^isx~b;Q8_w=~W?cd$`GL@(}L zmCwLjA6rMU%!^uPx_hM?RG3^fs$UX!P%q!w$ZD>Dh&(%WqPX51u$S&j$UfI=fJ_%H zOu=AuAzm`q!-po+LRa03k9VwH%8?u=ty%J+DA?TA`FjCJ;M1=SpXncktk>bxx2#wq z;OQe=4|%sA=5NYe@qEaE@MaIpWfavKHf7J=v9T?UIH@uJ4IiDcd*L0vQQotlhBujB z&xZFS_s>_gvf+glX(cxai92RT$)a70PgNpTt8l3;ArMvTxR^$fhLZpG zpt`z?DBlk5uL>HjLe5AJZ=2-IP(idf#B^4joV%01CZaVE(KeX2datvE)Fxg_^#VpG z>p3=ZG7214$LWs`y&XPQdNWVzbL8|08G#+v9h$!1Y zgm*!)my;C=VN({6lx_Efi)_FAdRe8F)~boMikaVADE|z~b?!yC$#~iGy(-^@4zPPj zDe8a5K2&h#rm*n^h(!|fz@~UX+Jo_VRYlMupiVF(CKGeX?t=;|n%RKluDWW;b54}? zXy^`i&+$Ql+ZFld1Z{!+aqBC}GFMW3XR+w{&8NbsARwO|J%@h~AWV*Suh^V`(EftE>?3 z{}|mx^+{@j$y8iyp^Jd}VZGlY;S%ZhP*GOa^_gKqTBiNBX+26LIq?0o+KULHSQKp- zB;=b{ME81p)zMiE(RgUY^DIfM8@w#fdVQZFc)f)GoUQa*lEhMi_>7d@L7228ut22M z?6j#Pw+OWVoG}%@2-E;2WU%U=ravqW!OL*oT0%>GGqpK?D3| z8@g$?gm+qqlO!^^8eg^4>&wT^eXW95tyri=mNlu=5-L*^E`ygrOztBKL~vHZAKM2p z264q(0ezeW?|o)hrObv+4+~Tgi|w_f#|k{1BHXKP-!WdGRI6=ggROOnfN9Hw;$9#5 z^gDRBZ*r$Z#G$dy{ah9=@J#afr;dfd4UU0-CQ+L2FMzmQxrzt$0{ z%a7GFwwHwa`zzya7(=08^h%o)24t|#ABMxQI}}aeupwSeU*!LljCE$_;V;L#MW8z8 zERNbrHR?*nciB!|DO|dEhR)Xls86U|cE2DQffH(8un+(}digm-ZX`)WnF;vaV|)nh zM^ND~d90|>rUg^&r)2anAC^e|j9(s|I8w4ip2FTU%!j5=jYDA0qp#9x))#?aIrVXt zLvVAS^&{4q?&M^(a8ZJ#Tgpb~P_?Hzc7BAlg5~YkU62$AGt&N!6zWUd%CCIh5>crd z+GA6uq?TJ$O*|hCq6Pb-9`5W2U`?c;6P0|IH{GdY-qibE3disiiFwFV3s-YszF05T zOTM)DN=`P13;DOas!1;{BSauF&E<*+AZ&-g)opk+Li2eC0YVRWw!U`ifKJNHIC<`i z?KK?4onH*9xwRm<=~GeivI$+KYO*^?$Z=lo((LY3L-{3jy!_FM8;M1)lO-3xf> zjz03+4MvCl{%e?unVBcL5*oap$3%I-$1ZC0+-G#~_lY+($z^1-f`mf8;EKaGptB#) z2P?4otSW2YD%?cmY|Ulx{tKmb*vQV<1w8hOsW;zV1=fxC-}X*1hRV|sgf22$cVq>j z`RtTUJll%pV^wNRAXmKLlq4mL`Y9W(xdVtg3SPV6qsp_|Sh>=USi`1_ch=F|bh^?H zM5ChTB%WN0aPSZJ9)Xwjs01EZTFz?2QycXvC&O~sSG4=gy|7WkTfhqEfD%E$S`zVF zJhQw@M#yyl8Yhtb@zjSHAmJJHW}Bb=BQ80fzzAjII25ukiOBLyW??c~_&stoxK8Y=0&_T_D0i29q-Q7tWQV+iW)aLxWPOV#LZHw+Zm2 zU0LX$&f@(dKve;sH0^3H)v2>2Hd>8@BVud2}O#~L;ixP#vJxg2{}onl+Q6{?Y) zn%r@AFlZeK{i1E*$RzHgg#2lh3JhkVklYfRkK z^mVDJiNO%AN1Hx%>g7-DO-YbnrKf6lRj4akD~q32Stq@ASQkQhx*bZa(#WXaw748w znRX<3;$NT6efDzdLxOKcv-Am+qN87f@MbcUo`y=kNAj!iZ!US}??bL+alg&P zFlRgS*6wpJqkJIOHXBPvEl1*RA0>UC|{Lo*qhh1=1U1ti=IH8B^QZwE^OGGWo zJG=A>^=QTfGwxMbcXF-=0w8Wuxo=F&Bg5DS($NIkEl$H>1CAIVVAz?x9Yu3}ehwTW zBj@Vl{pw=mL;d$DOy`JUsA!OKP%j{VH}UVxM293D40DNlWz89@&CXDX6-#j^U|E7$ zs7fikthnoQ#{87#D^LVKD zTPlUtkm(ithm201*N>uYo-Kv2aSBiMfF_ebc{p`i3FB7mdhtnMfV`g*4Vng_+VIH) zoTqaPK}|~l6_eRJpa@?;2MMM)`ZIvrp=*77)E@O8_?1iy;xz7qjPF>bl>lv0d=9dK z54(>SK(Fv;`|KfiWL5w=12Y{#{Fb>}fOZ)DITK%L_ViQCbI$q6o zI-_){)1NE9_?qq54*pKm#MQnVrV3|I%GgmnliL2d*GW~6!tts3e76RT^|FNKnN&pg z^1aA(J6W@;(<{IFM2UsNmOL5lV%u7NsTK1nGA@OfY8=f4fwk7!| zLtCX?Q;CU9|ICygo(USEufnmKuMe$Y)&ezu96EBw0_bTMFZI13)eVZ?%CF#s0Ko4r zKiEv9;(c@{o(w>_?(~daox@|i=1`B84#lQ3@9<$11lB|`BMe&4=ZPB2{mXyy$AM-` z{mc5~-}LEo4yIQxQI34cKlwL5BY^2_M(9H}_VrSM<6eIYM_7%|S%s(`v0C-;0xVFy zZ0%y&7F;7H;|Tu2O^6_QyRxGa>rI7NASj218(cBaNZd;vd- zBW_1oy$I}i4-5BXoT~{aPlq{tSE2_Rz_wqzsjsTY#A3$tW>M5J3jEQQSD7L}9+xLr z!vfF4JD{8VTf9%@mPm&hk-B)k5A7<$F*|gL;fs=9hJ5S^Si}Q``To;HQyUJ$+QlA# zCn#5;ziBL)i?OhWR6^)OS~UZkOdTSRPa|Prh}{C$KU|%}3V21B*WNga4kj*PIf}f0 zo`1a^l#&q;7L|tEln;4K2U4wxyin`#4Yn|-YmOx#44P^UlGd*owwBfX2yjR{&u#v2 zfoP-4oXSaCmhe|KZ^W^8v-SxDvxK+}Yf$eNetg*lGI1wpjLAho4kPpxD}S%~v(l_2Cb_&P+sb3P%&Q&lSxcn3cb!&IvT*BXCJ_{e7!NPXCDu?BLyS5kXC-g#JLL53CpbZu@5c zbTO!Os~=JR)WeO5jO^r_TisgeSq9o!5-;X9!DLZrs_Jj)8~i<5C0f5Y=qZQ@s1KNM2sknVk;^fW5iQ=2moH^a5Me?Xrd3 zj5xP92mU_8d>Rj*Snocy4Tnm`f~ChC;eK%cn1C%Pl20VIwCp`2YUO~Q_4D(n??v6u zWvS8AF5Lm#+UQE=J9^#CpZ`=+_e_V&7NS-UPa@9K5TF%yyzs?}Y?g(n_GrRfFX47@ zk$sK9V0;s4SE?}vb~FhabBBNK>9G~e4Xm_UPz0~c=h42KHAroP_#O;qA2-;hGg2RB z&U0USU$CU;I`?&{dM2rP0qgo7uY~v?uLR;9>3`sp2FO(NbI-n%!Fsbpt>VmC77gYV z3TVYRV-LIE5h49K2)|~&3k7-E8U49Chltw@N2bUk80q6L^v(;6YMIH4^Wkh?b>%Q6 zc5QOVkMOwewiQiKbFaODX|LM`UB1?U) z%S?^Y_+VORV*#R52|r6Y>k@;_g=g>AeX@qDyi%w44pw$$lI#`{Ap=%+P6t*tPv(!V zPlCtjr~tC_KJP|nDrSEg=_6J{a!Cl$GRJ$i7qf2Pr~pijbyPJfbsuwGynJ)$f4hB9Q|P?oH8`M}*9J#9ZAW~M;>FeqlGO8HRLA#LpR zoJHF~+Wr*Ep(6M<1GXO%foFoFCaa|I;wj`~w)jHhZY~cfS?O~dhoAhY&tqJmJ~OMJ^ysjXqhEW& zwBlWMy`WUTyj_}1U0@2xn2@eY(cI1M_`wmN&TN%cnXSo4qsKidBqW3y2c3u>iZG;N zCDpIN^M{gEMp*)kYO@XQW8SE`>HS9jeQo#}vvv_wf0c$*_=jKt^Igk4!uO?~4CL`~ zpR4kY$1zduPWzZ zNPQb)x=C+^40$8x7=-xxpDC)hr)USQP(oc)m41EaOv3~hmaZO{;(Cs+jI;~Qq3F;T-IX$MLIgqN&>;- z5d{rp6N~1Nw63pT>r~6NvT#J1{(c$%3p_Fboq{wUF;SMdcexM9ibWVy&jM2I0%8U^ zpzEDx1L9i7A@ccRSN*$oh|+o{uh)me=4qxGv(e8k9*7{#=09JF*fcWJL~zkF@wV8p zmG36?JHD0uo6?OIgm6t~s6JmoM%@y2Nf`Hd zN`=41BEI%AV@UQ1z!yv&s>ZDrI}q2*+F6Us(l~#w1mQ)tYcLl5^UT)AR)Wi9*iC?U zcn_EY`u}NC*0d=J-3;wVoFR&h*LYgMM{dEG;Xgi!I-U8z#pF2u<`CWOs43f%m{5!* zl(z^98auVZ;O^{S2k)7XLf$(jcEi}{5i?zJ5uKr2KNL^7lx4^3rYj@INUNOoSUB6% zE!55Q=XRm;*s56DJkb;t$0la<7~4{#%owmFj{bt}XeaEh>4WdlUmmg8Ne$80TAKDD zFDaP;L*l8MIIWvk9kXu<=ZqEpgDI;T4S69E3D-75Sd`@6@gXr7_R`rWupCl9{e(y(VHrKM z@KiXF6&>?~X5jJjIuC4>fu^paDfWSuQ(JWIk_<{K&NCXvsN>g+go}(tdOZ>v>QJED zE}>%1YssIBpR^BAm}_=)>pebXua1uGG@@e%4>%pZTTij@mh!C;l$grAhCBw;iw>n! z*}e06AQ+;EFG@B?UrG#0oNu`TLv}S12xs}gzipT2XgJ_M0~G!Ov`OApRkgXTL6n5?S1gslVS9~cWH^kiA9 z{9hE2Q6|PT6+}kE9k_Fk^6cAzl~)rF>tu(loHP&GIxY@UZy=&eC1%D=zsFsBTq`^c zs<&GZk*(GF%0+YrrmT_O$beMJgcPpjv!SIn!Ifasw%+@G?!3(tq(r;Rw~-<}G=Fmg zJh1ifl6JdwV7P%J!}$~qec?C5vrf0^_k#4^Pz})?QdG!6g*QGj%93EW9Y3H(04hsM zGMxi2r2z_0+$GZHuo7y|dVaS1p(1bbncBkGZhan4Ei8$dz%*8}U!ClxQ8^ti_hT5Z z!|6)i$nMF5YD=R8cJe7DE*k-E(A#u`q7ivET=%Kk>V2e)=C?bmi4S{+MpCI{My)Ar z#nqkwQ}Hgxlak!K^OH$fSx-z+b-$du$)h@f+IdpB237)=4vi|pQm(D0GnF5~)%sJ2 zP!rxpV$bq7gSUphmv$*^&krIQb)DTOvEB+&>2J7p*0-WxxL=dE-IDKbqd4V*Ze%4V z6S3{K6h^QF(B?DhSPkCV79Q5^yl8ho&>jl_)EQvRWfT+zN(M-5YVn}o3Z%C{#7}r* z{t$aJR{Kerye-DnJW3@M+rnnOu(P)TVjKqy(-eRpmE#VCZ5 z^kwJ8S{Wg+&GUq}PlVKd*$Tm97Sqr>$H@yrUwYo3gW1@&mflWqdL$?*3FJI|Rl1LY zno|+U9lrWWJE?BrXp<~fb^H_5jRHC1MkK^zvV2GYb(nzD*J4Q$8rXM(*yb!91c;l= zXrYkdFrWss04Jl6O5|IIKd`<1P(Dxn626&!?vt?XgeCe=k>sGS&tC>UM;o0Lg2AAs zaqN<>X>2{jRT^-K(e&%u|Ez{Tx(u-I&Q9M7+9ieOn!Tvr{o>QH;a5#T_2VJpE6l^Mny(UhF=yq#FoVl@l5mq5uaiC8~h=ooq0fCQP0F_FFj207)cPCMY&v z5V}FYEo6m&$&r8oGp#8BBFxb*5}Y#nGWyTO7*E%~*^koh9!CTiT9$r9>%kY#UcLWP zJ$d+_VOg8j>n&HjT(Bo61T5=*h=#aMPo9hs6%*s~HG+p}ZS~tw(9hSwJM`&?^lr9> zH5;0r_Oj5~3Jc!j!c=_NxF%G=OVjfEi{Qs`Z_ieb8AEycwg2mi;C6g1QSBuv z&4%;#-uIq$_>-tMg*HK@xNsmhmKk=gTQUGdw#h@TeyulQ!DoWUR_tJ6_(h?U%YlKc0Vx}? z40+Cks9~{+j7KzFzTiCU*-IKJkj_T3t<@Inx{(aalOP*TragRLxRb8Z&|XX*mzdts ziH)dH+hc#E_9X^{L|gZ2nUiq~a{Ym^sjbp~sXB<_rnFiU1~d7R^e8Zf*{^(wsCvNA zVG%%OBZ{i;v`et|Qp~FIm+js5OD_Azym&xG8N?Q`M#2-T zY)5VjNc5?BMRtGLu!Ur#7xjRx5v)O3>)zcas`_|V_p!_prJM)y>%wdGaU;1gdPN4uy znsPy2@wep0;a<Ox)FE8dFbkUhRWzO+9U# zPZ870STM{a@c~uEX&hEbBVgUIU$!1^dhouKm(^`Ty~G{KS021R6zCSr8=dh>J9&~U zhMpg^eR>fStMZ0KRu$&;k+NfIdOyT5)ssv~BQo(i?+$X?;s~Z%(kbmh_|7}BG?sih z4!n!V<FfjqeVqI+unEUvth>=duSKi*(wn8F*8qh}+u>i63~ zzWXt+cZdL}fEwGiBuhd}LKd22_z{ENJ8mp?$Yv%mcROye=S}K&PwFBuwE!wSM#CY< zQhwf{H9w;_m|7XEx6K0S!_KiS?94gM+OWR(@DCD4TB@Gd|3LXuX;RZpS`s|@e%t0L zT(u6mB_ZQ^@z84{)(0xC@`*7f6JP^U~$=DV0L7pMxLuL!^eRa2C%2{SLL!1;qIoxm|{*#**uRaRLJP z&Ra%+ko8}LK7Sp-(_;l4h@Yn#&JHgg^Q=|}pf1hGD5>nzq&aq{Tdv{qrqfh@%so$i z(0a#K(E?VFC$H8za5PK%mNxqZ4{qjxilu^F%wU*Kii z`L9kdSfDfi*9_ceL0nN-2 zGV<)5^i{wN8@Eyxu%Xi9wcswv9Ad$~VfSf-f`&IRZqTX)e1MT-dRw;GHTg&c|9e?H z%ho$^)Ov+2$V^Gqc`p7|E^T~Cs4K+=y@8?QdM+OlV61NW@(-(9z9726C71Sg3~!Geb7`MP7M=bBo9pP;%Zup;b$>w6QDcQo_#jUz@f_iF?bJ&U=KU z5dO_f@^;F$=!GTzrb3RcxpLIrDe^iSNw{kxV;T&&H=;lj%D;;rWjYjYOM)_|5b6vw zDuR{R-!A`_V6xI$8CLq=%`x77b-_Q+fO6E4l3c~HP5YiCEWgz7jrg+as&$DjUEPF-*8U<1(4Puj(1K+S12?WQ z?BL7d*Ylc{at!~pD6gZlY*d+>k(D{9dd1(KZwI`rI!ql8w!>1}o%cZ2;kB|suTISj0g+aaZ zM;l|oA{S(8V}SCkK2IJRuvThu7}d2x@LAAxL9U92E0Fy+f{A-tYhfjFl0Bi`r5dZa9CUY$?2lmp<2cUi{d1rbbWw^OMh5zPv7=3Z{ zeJUAuChZ=GFRC-O;Lv30Bm5~C`l830y^ z-choy{T}HCs30;0nl3jqqX7_4WtWkdnQlebDj{Ce)$iD>*HRT3^R5uI-?IxSm}hA$ zIVt;!HZ0RF*a(+%X?UCc?%_pigaD*hXI+n6#u(gc$0bAn{WHw>hA%*}LNx06>Qdk1 zDQ`WjeCnB*o?oJKj;+)v*dxczK46MQ;?KoeD8q6Q`yWFq@iw1v;{aSd_}4eK*IcJ| z8+Va-m17b@K4Ay@9{e{Zj)5LUkM_bFDVoisSOI;lPS!l7UEaQmvC5A#Be)dJ_FGDO zamc=m&L%hOL#pBIIjJwS>90*%BEg?tj620Irntxrg5{8^+<9d~bk?=zk~)p-{zF-1 z&_}A!=>;5e?gzc2nt!^RhV8TavQYq5G@F?><`~Le?JEEkdg~Ji)fU&jrI8>A<;QTh zEpuf37Y4U`oK?nKI`ZV-$V1;|GUDTBT8R1$J-AshGyOS;iHR9ah6CzmJfNt`?|N=t zaviZY-=KgDV39L+bVsvpRPPm#vh!vY!)<8u8(X5Py`|LNluP zQml9<db9LQG>FtVpJu5GC_1yEJFbq!TP#IX2+d@I~Cu zda7YW9Vwo_|(>To`8bXJ_?YTP+YxdIN6_ zHVY3F3*2S06Rm>Wujkxg@LKpY?XdGw%jTLXDZTixa`RstHhHTvfnuX8IL^D74#PJ- zh<={|h&Iwf-ukkkV!)Of9B0$5Xe?L7Et4m*wnw@Q)~8dh7ax4OJyyPdL1OG2_8pJ8 zb>OrprYt0ACma3kc;E3>%j)>VL*CO$xh?mHvi^GG=kDZQBN>7WZ}0X95uoh4k>SOk z9rmiD9ct79+-+FM#P{wVY0@%ao|s6eE-Q~Mf;rMqcBgUEO3n8ok(g;yuLr^)`4CT2 zcRdWyWO|5aZM(ev6`XtPtNV+@VR@Sn{fd=5ktljoc{DUE6Qwwm`Ak@qusCW+H#co0 zxTxzoKAkP7pQ_PxX`GLejL^P$zVcnu&C*q5L_u921zzJy9?2;8<&(W)F&ravcuA1S zARm_puvWqyO{-JhuOfjQ!a=61xBrAmVyJt%R)Ps`*aI4n{P{zRD^e#)zwW=Vun-{x z6sOFLLL8T5zmRGJIz$79^cPcbUCjo zEtvV67nRi69q(^DN=xAJpnyjy^!wZUyz6r|fNtW-ct*x*^|6~R7U;(E$FyAZA21m0 zM*N>!CR?sv-Q#tU!Q~>CUAnEaB6hZ@rPZG@R!Ih71@GBiXe+@y>{@A(%Y~aa0G>{N zZqMtUj`u0Jl~d)o)R*aeB?|2e^W&`txmg1_S(hyz$|5_9FHY+|oyAkDAUeCPV+fTk zY}G~+Sn-&`L+dr+sLUxi*+%yTW6nZpB)d;gOu6kZ#OQ#*a#Juxq3@O|)mt9~iEDC9 zr!|!`BC+xVX0mJq|Cx-abJR>vZR|)FQ9af{7?+p$8|Hz09jvyMLqzv)Y!yrHhPlwS zD5Z;pv!BuOqx^ZD7x=4qP^6>i8^9NXgOg3lW_JGT#Yx5NLCS36Xs!I z2K(e51ffEI>u8*q#go2Pwj%8NM>g8Cy9LoE1{x>Uok`>X!%es1Bj$l9;(FTgZbt)9 zw5e46rzn=A&wRJ+Xx1^i??2B)hjb&P0m7g+6&J-#t@kbPeO-a@UNKdxS4UAqo3a4R z$*6skeR5(!>72iEhbop*T6q<~RgLgu{cnaHN}z${`quCja6Un2?bHSyvL|D=FSprf z0vn?m36X9fe7ID45Q1CoPN*w!hGVSX5Y~&hPDg0NBF?@J0aCQcN)KRIDB2&CJ@c2} z8?$#2G|VtQ{I>m`mx3Pd^VdMzLl>#XQ=vYoNC3x#V3}1U4>7!58Q&$m$Ew>f%>KlK?j32*QSgR}jp}Ot)A(BKwf`!zoTv2=47@6|P<| zmT*?O)9v5JkqQ)6HHYITG)J6yFcz3_a^M9`!7~oK~^Gl6VC!y3` zi?VyfBU$xhUdR*Dr02 zZjgVM@Ts!L$O}>3xXkqRt!)J_GaZ?_B2gXPt&#V?{SX`FV&-rwBsh@m{%4$wtZqiz zH+8y2;_!0qyIRqSd=5KTZQS{%AJ)G(2v3Di@z>{33?EJB8GIT!LR5Y~SHYOXBU6XB_lWp6!dr$NH-jDZ}aPG6$+WT79|Jr|0p4u~9yP1Hh zd~evUW>SXm1GAjoevbDR!G&^seuORm@IgS7-x*EJn`gg1%iIi?HG$UZ*XG00eA(^; zryn0U;?`T>8TYPk_`--m7-x+7wZTd3hT$J|(ZYGbef)fD^=a{>6slNkX$o{iR#kU0B*n zBWZKwW|p(K+VcvzOLhuBTh(20<29)MIXtKPGrgdgm4CN??Ao%=54`N?$va&2>W^7q zr0iEUY8H6H-K*wjC>iW~^X7T3*WFVxg>RWEymRWQ>J&su{@n&(QE?qdz*R8ANbCWb zz1{Tg0T>G$p(DkDb4lUO11k2}Pef-7FbHiy#0hV5FN{3pyy0ie8UySeffT;t_^u$f zTi}xvAxX9$dZKN`?GBFdMntQ$ddvu6;E9iECQwnnHvUlv0rKnKsA0|Lh!r zsb(Ktdy}42*y3C7k2y0LIR)PJ*yv0x0ZMuk0$%(WB&S9FVeMn1oli6?!8EB* z6sijh_JAE_^vPxbLiC)4$lbMK5kIIL=Noy#k1T;e7yE%Zliq(`cij#Lqb{_qdMy z+J1(YxV$!e`9PvH3bFsmXcpE_Rzm9+*MRl0)l-^_NGNGl)s~@4EFSt@sDh^3F-ahHChs($|Qym}1-~MnK!A#>V zp5{#N5?+ikadEPpyeGpN7uzvre=LJZPpIOG!Bre;{HuftwC@zCh3pe6MvAD{EcKL^ z)Em_(BJ(?j%Z^AqMf}*3Er4XbRqKveID8G_zm(hYZwATbmQ?K$PnGqVB$7-L99BB{ zH&2E)s)|bpk7n#Td;1kj+N#BSKyNC0khKskI6LY^F}x9^!4%X^;Ki)3_BpXIN(-#Y z%xyJ@re0bRy$4c$c4zlfJ!zB1vGF}_pW*#-O+0-I{z47v7axb9rhGb{%8U+UYViDN zQf;QigVVXtyyQS+jM4Blp+&2uBm2t$)jDbp;m`d$& zs&FW*$3PpO!p%v6hv8F^M=6p2loPD>01O}UCRs;i4l1c!a8V$?Iborw*7&C|Fl_T2 zAT(B$(BElDKeV4GH5e}n=q16IRBMmf><<;6r!i&3TwDMty2?vcnP~%d%ldoU#-NHU zCBqPr)>vv$YXaayts`994*`&c4WFR-S0 zL~8H{Xr!rp>k26$TRt&IVh=iP)z@+i24zrt5aHOViNFP{yT*#`&b4>qs-fcD_Q1&96CUeTe8?A=nXQf8!llc^SZ+%X{HCdi&+~!W0PEX zFRCJ^j{CL;Yiy?h@q#LQFqPJ0^IYVbR{RvHC1)*BLI%4xm7^w1TKi$%; zdUdHeCv&qf+zv_|K2}s?1K5U4#i!2h`;{RRO*5!^`p|=*F7t1f5emr~{4!{Jb0O{r zU40S}w0(40mb79Nb#;K>KOe0#w^>Qb1>%X8)`_n>>KD~3)T2LU-K=zhhT^x`cXx*i>=5 z>&mzXLJ4HFeXE#;=*`t+s+dqGq=7KEMpf8xF$%4=AG_eb6S$q&{HhnJH*$d*Q|oKm z_oWBW9rd-ov-es-7M(GBgRsb30*fncyc8BZbjkj zdgfz8`C8o8bLjQKs!4uv+3t4Pp##NSOsMFHr3oJ~Go|sI?o+SW_X;`}~%;-%l&g&;E7SIvBG z*P|Vn<5}Ufj{d}Gmp|ZqE_QfKlh=lej~68?KRcC!(-|o|k7{u93UU?l2f*%X@xe0#gSw=2wClf=>nC*v$(~5pFCBI{vF3j1B5Rom1T$#e6H!Wi8KgJF zIa309o)aN#a2*MNi_)mUd8#Vh&^xTRRrtN{uO98IvrxOLneq|i*o;s>)*`?)upC48F~Ri#bs2B4c%FgVY6dThjK`NZsUAn1CK{3(Z-cT*$s2@ zah~F#0Qr+#wv}$chA&&=SD` z48!X^r#E&ShCrUzneKY??$gHNF4M+5W~{L$Ek*FET}8iWJCEt>r7#hkoAxo=a%Oax z#iR&Me|#K-)T!tC zWzYcK!6cVvUW_c*K*25ep(rvs{|3d$t3#X9!!fVoEW#03T8cL?THaGxQ4AFT?@P?bYD{li3&)a4ZOs~_JI9TPXB+-VX=OADEEk0Q=5wjz4& z4iPIe&5~c~*lrIrAyIj^wBsG&Vs;2Ua?DCJ2cw}rb^b7Mb-)QvFzmEg$K3+mpy@pW z1kpJR-MN3nM0Bq6IAmvk3%=cbHU9#^iD1E@H>g@flV))3XEWlq z&H=x~(BgzYA&4Y0YI;v|B${+fJ+1q-CqboFF7 z2{{Ld(C*JEB|3?9e&kfqHaNH`uNL`x)IZAq(P0wZ*81<-OH@g^RGG#b ziFSWf;KUW+N&%jyrpf`k_-iCeCv~`M65;e;s!k;+o}CSv^_Uli+|PxTqUXyxpv#Ac zPtVq?8RZpFo-~Km6}DYlc*8$>@ zR|svl7NM%^X2McCG?u@PVRx1|tQE$X-h$bTrm=b0OhQEevneSWpsp)FR!Z%|DIEs! z8~}zaoC#ew(=sk=p9Pw9wxfR&&qdwB8)nmzkHD(l+5LI-TtoMK1(Af7BiC?+JYRZu z8h@TY5F48Z)`%};k}@xF7<&jm#hwJ8+vxdhs^guFCPp)Awpoxxmtakv%kBSFb0>I6 zBG(n4=w|D+S1`}@)(@kzB0`T}|uW}N9D z`!qS@dxc-@6>PhI{+P)h!7l;3*fgiesPCQZ1ik5gkFpMdG{=))bDT|ZE;a>V*Mc>u zqk7lDU?0q&5l4M`TzXdr#HAA%y*!aMt$GAc#T5*}H1nd=C8aX`eC9@kNB7VuIX=kQ zTHKlJmfn7!_`~1>`kdE)iB5k*ofzG?>?B81AmnRqWX=CGGNAAq8gHh*nN~AhOY@a9 z%e&^2XVP;1t?ikVe$3OpWnQqSQneG=yHR9UHd79~Uxh^6at_)-NY+ybUu(eb41$R{ zxM9b$RT*()XA)}= zJ7@JG_Ox$E3*|IXE_rB8kUB?N7bMV#uNRHz%wYKz-IqI^u1oqf;-_FQ#XnhOEX=LF z4@Cje&!F3`HlV)+s>Dpy9b9*u>VSuAt|x`` z7oMIf`^z&4#cRZQO~{j%13xtmu`#$*#}5!?9ub-FQO3v*$MA#yN@O%|PBkCzt<-MeP$3p-`rbJY|* zznEu${cQ$rETy!kshcV{yXl|=>t1r?Wf$xZU|>^Yvou-Nu#`xphs)Z@?_2hnO8Lw` zbiEbOILl*j`QgiYBlL-u|Q zC;t=246G?nxv1;#v#lS`9V-l8zbXdDnvA6z!4602%J=?6YdfgKWhdSak987xUMhvx zI*o=l=uk67&NM*njNfNYH_aK4|DkDVf$%j^L8@-q=VD}P;W5mH`|{UkjCPl2I6?g4 zXr=gp@_^GCMUZc&5t$E5%&V6J9U*S{+A0pfB|yK~%#-ZJhYTP}!>&dZH;>~>z0I;o z)xH|0uq%1+uhgKM3oPNQmO?{ZFom%!?{ef$G&=jlV0(>O=P=I5Exyi~T^ZhknX}-J z2}Fc&J({@ss*m3NxKJ=-vFDW|b{@t4J3#wguZF`A3v{W*7z%75GYJ zaaC5T)QWs&lgNBlay%YoP$kR+&`(Bx+p~3a%P6I24~D|18IA0Bdwng2gnr%;T(vyp zkp9oUx{o zJ-q&3-L^ex;z4xX6A)`x?-14Qtv-W8dcr^VshGR#$7Bc=_$-4up- zX(sOp0J%WA5lYF(Ny+$Ry!G_Mk=5%o&&sNRh%45k@IupJz0?lY7rUZm^DQzO+2ngQ zRa%u3HemQOd|ay+wP4zQ!={>ig-k%6t@Y(}Ip8W-wKLZODyL;v9X>EX9n-aPHqY*z zuu049;zZtlBvNH3T0IA{(z8YN4lvg$B@}=X+$OBPf*FVZy)!i|H#yV#IcFwq%CS`c z`?>9nz%uV3+$Fb;QsCU3XQM|rsSU~AT|KCQ1E^1J=x(CR;kvMr7Q+*dEWbSJG@_XP z)N3t|D3?boW6H~aie-iJXMv%tsuFe&`xxjIhjJ(=8i|=|E^8?ojc$Fr*N3^<{M(IM zb*_rh=Ta+L{g|l%#Sv51@i;}$AJy6(=(*)?1NhM#1~F}o9Rj>}L*by& zh$^aCdO*%oxsS3|7SZ0>f)*sOtO=qL7XHCrwz`6gb+oZXVP+|01Ky7N_UpzitrZ8z z2`qZ`gFnn>d93BlrI(UvsE{j-(!LstR0-Z6pFlglFTV!m!fOpsSff$=J&}87h1bHg z$m~%3cvh!4&5Zm*+3ozfavJON%zJO_LRfy zj13tW_J_GM;aL*8X^Vqsk20KvVaz)j6+T15gP1e!po1@AO#VupI@XlC?ti<6mK2n-6QNIIzowGY`kC_n0aD zO2G0MuQf^cRrf&KzF*?hxg@?iFpEa6pzD zV8vEIUoAfU(5mvZ=#kBzeO4XbqM_PF zy=9E0-qC3^STlSPZcSccxje7jmh@*beD@o<%`>gO`9JT24OMbA=)>Ayju1oez|X9j z#Kzm!-4!5230ciuWjEr(6dBGt-iaHT*6xp^*WpL6SA-(@@0c9-4Ndo-M>IbVs+d!B z%N$n=bLXlEI$e$`(*@ByqwvGyhx*t$VZa0p&dP}`J7>Ujq-mB@^-cRmGjh}lB1uRr z$ob1fnvM0MEgR=J*8=?12#j%WnO4O%o&{i?Q53T7Z}Svs<{}3rpzEEY?fns+w`$wB zj0ok?m|b;kNeD2%m#fex7ZJtnEsS@OfDoMIkn<@}BQ`|Bxd}~;lh|l`@obBDd^<@= ztHI}Bre?Lz{DMi$2ShA!w{uiLTa=*Kq`n2od>s|xLSAMB;6|D1KpyG8<97qwJlFL} z$^H!ZKy9XYC)3iF?_WU7S>(pTfoaxt6Lv00rIY)$Q7e9#ne9~ZvfX&?FC}uIt3Ks= zwkMp)f&7V`GpU&%rxij?uN5ivmR)itryG279eTU>ejE4ZX*>Z&wdqhNT4!sh4^Njz zYu~3%AKds(5;lGN=h@- zX^6yOhLQ5Gj(g&1aR}c>)coLQiCcV|b{vq-6j*?J$8{WCzERrMxgeRfH6|wu+nVQP z7|bxBCo_E8`#?B6uSfC*b*gf+cjPGAp%S2Gini9yW}i4h)!)o`gt1jdOIY%X%8zDK z=F&0br(7q;*LVr@9R-6X_brWk5dy_e)3p5U)vJ<*s~7@P13k_6-I`jqK(p%YJiijh z=x=+`=h;~Z`6Wsr4S&*_JZZOA_)9IQsk_cWt@ktmR(sTLuVo0ktQ$+m~{Rd`s3F*<17J z0ZCbVQbq21-=)*!ogv|R?9to`UnUif!ez$mw~tBV9AOKO&9&}%m^`#aO_mSVc#%3) zN+z#G3~nrLju<}?$S!3ZKV-DsHJ>)Y(_|kxF5B0owr70`Jq_VJW3vYd*7g9-j#E}c z$6icOJ}l?ot-{q|ogkf#U`H+qsZy{??zg(l%Rad>vz@XX*2Sjp(*=-} zrdOUtWA`+y0HKPEzMggvw}O|l2W{kl>c5#qdd7~;TGX+api$fL@bTmCzOUzUhQzxv z%Wbn)L9HqS?Z5ECu_c0%)X>QFn~C#F?z)IGoyBQ_;6DfD-|jlcJbHbz^`GhK%Fz`G z@_XS)%d2*+^z(?7Mj039<@w>q61SFi?V5nycRYLTXFG7JR<_#44430q9X3$QrJ4+m z!4NzwuNh>BOG_B&A&``$eloZ045AhuROM6XudGcCYB9G2QRPy5keEzhsN+Iy0zL-A zRJClbQS?qlwl^PJfT+f99*s5*(!1Za<(K@fbcs9C3;JRv13!fVW2OiHTb9YDaixnx z?9bT=g1?`AbZ^8NAz8ZL&5h@5l)murd40Fo_t4X>D&xu~F0#LO_k4Jen1vziW6Es6 z0TcE?!QBFr*m2sqz8O^K^w0X@sK?i>IVVrI#A1O?b(w57Vpiqgb%^newJlo}c{OW( zhi)<#Nb`#prB9&IcPl_q!FEE7p9C9Es~hhIYpo4nJC8UF@4vfi>i>vH+EpcHHFgXO zPk^!25Ee&SAHR}A`g$jh7&RJxVj4Uwky1&XuT8~IEtT?Z15M5LU#ePx)D1QJ2syizR(ELkui)_gG+~R-w%Mp6H=%A*880lgbK6FeRJqK~L zp9SuU*eYQ=1(G2@0xRsmLIJdMN#rYe1tu_)+=7;(va?A#vaHt~2_q8hR$O$UV2_`L z5-PZB=F|2TrT~eVUj<602)+=i>uQARU>8&L?ev-;=mx~66P5MQ*Wl}2XihY|I;qWSk;ctqOs zGXlh6A@OHQ>#@R(Tm+s@lgYFg;bES{k3m+$YK$bSd#Lb&w}aDHyA|)({fiV3#fK$hya0D(~UoL&tmb zw=(|XABV92!{+xB7Na`s{^rD8k>VntI$Q2P{F6WPt^oi;!8Dx?|0dCs2U*!nYwD-u zK@gFA@&S`!fx!MTOoE9w<;-`|k?yx;+?q_Nx1Rql7ygqK4o5(edLU&?Woy ze)2?sq5^q)L!FoX$D}Yk6d-mFF8bj$+jUPFCVAIcHYQEvSRb)x@RwOOpPzXsPJTMF zAxLndS$tYm?w0qgkl@0cTMY*DVG*pkAHna%P$_db zTYDpgB}_ODRSPqH0Xd!hN?%iEs4NUDONuqSf-gP{Sav&*_bIU`pz!R#hRM8mV4=n}zj$dPdY2wBLG~F$gik`AW3Sz9s=UBOy0f1mhT$&{Y`Qv^QAdU zlG}+HqhV)&otRg^c~Ao+;e;Q_c#nFu)$9W7mh_ef90Zi`#CmTA4zj4;Dl0r-ggzWPHSnGPnxIE-gNp! zJkRxq`LWZV0qJ$h(`#{Nnq(E?#3XF^{hpgMABB@?$xz&+*>q$#r(sbzROr&KA9?kvM4`C|W zyEC!H<1uZ$!fh9i-^I#?J7CKGp((4l4#N@GF%vVwybX9 z2e}MsNpfrJ>UU2Ph!dughva7k-Q_eBAs=kX*9nw3aR$a{9xpepR%|Z z8u`Pxv)FZdX*WiH;0ifkZOy&CUl+U?OaQ*2l|e=xPOv{D;XcACy14bjC?h)jEW)my zT%plfygo-t%QB5EVN!k=ak`OxHLn`in6;O*_VJhG-(xC{=u9v3??DG-^=X0PU54W3cQG zxgtGx>VV)flO+)#P}1pmdr7zDBUe&eXtJ|Tu9=CS?DsAWic3reS&U9S0=o+ckjE!h z$!BQ-2nTs;>~HPO@o;F*=7P$WIV=tPn^GTE*@qtw3fu$TQyHGy4#3?UDV-hz%0-DJ zH{VvgDb|cRg5K^tqpQ-Nu$M-kVbLbeUycf=0XsFo#YNY(U3h2Nfk-yzmu_pkee-^HSF~J5!mJp=)(#uN>sxw6xw^_m8 zv7NLCx>*BtkpNFqL6RS@PoBGy5xbR34gA2c2GOJlBBoQ8!)z0X^fSUC)Yt2A@={;^q`P+A&p<-GvnT>Ka5ZVu75?C60agvmo zK$O`VdqG;7bEE)^p%0brS=yngPpC=to;T7oTjd9Z$}u68{lIXS{1tQl1gCL%|AmnX z8wM4(qirh+J-xDJ>)3>9%7ACQsN1yMC6G9^Ji@C_p8%JObIHySqn=bgWRG`G|3r)# z-7vXukgK!mx<=LMbwA<#6~d1}h?Np+akzaqQdV>r$P?7gq1evZ6NXUn;?RM`Q4c!_h-sXwm%yr>jVQP z4A%ZYlJ(l~hs}s9oxrZT-q2ssX6Fo_-Ib_eQO^1%QGa-$F-FdrQ~=smn(q0POa29m zcvD*DGyxmsL7c{~8kwuQ?i=S)eZO+=&}1Os$!ruoQdtF2;W+szDMf9|Z_av}F}kW- zi~-=D{LfbDAv)!h=F_DDK&o2J>k{9tr*I;%)dEInV^DE5lzi-Z#p!{49?ykw!*}ru8*fkpZ`#QCf2Z{fcAUw-z^LPd#2`m#Y#xB#Kk%HQ+@E;N} zrhm0s8+N$DizAJ)L{9K<-#|^^J|*SusfvC`(R-7awIe#$0|Mt!^--npKZ?5#Nfn)j zbpJ}_rm-VkH`ZgNJ#c}6;-5J#FYleX2o1|ZHWK~hQ(MH=FcbA} zl?CZk;mYN#xf3B&XJxG6`og*`V&r5{R2yc{>MaK(^4Paf>($d_H9Q;E*n+m{I7~p~5d!L3y;UAR2W$$((y}|W^>EMC>iKTTMMA-b(MN`&Xd{~BDMBxl!}AnI z6y#y~RpjN`z<<^xBjp5I3HvTdMp~e zCJTzg%e!qew5jToffKl+E;R(_TK-iX3h22?tRO!=O;^DC zupGa4^`rIWfB5Go=xidd9Pn7Fn8MK(PWie>6ACPOxfdo0R9k4EyVf|Fb&}xlm-! zzM7s102?k(<7*Lap@Lts>mp+AS2DwhcTi61fuFLLv|c*#QgcUk3c3(1FkZ--?@Yhh z6O!P2VIjtL1`^|$S_eQFS}FI-}O@wtJATcOFd zz4kepynJ5f?^ib?H?Yig8uR$^AR@+9bFCU#SJb?EyTyZF-dw|^*BHQCOvH_CuoN6vkg#Ee))(_1`N1D z#K`M8;1|jB%S!|a30)ia!)Vq#Vf}H|Vv)CV%j7%Rt4MdbXr1Rj5`QhYT)L>FegmLf-pO4Bet`IJ zAbfz7=qw!sGGnzQ>a%n1gHj+RRRPB;MW%`jiu;eJ67;FrG*TT&hCN3m91pjpIG(l#1<@I-uy~H99${#jHH4QCskl2PHap{- zhgmF8LmnchBx6bMGtGmfgXs`nO}s2gO}mYw3aO=WG7vd&1(69>LRL8&5FQKprJeT< z*glA@(1Hutd6JN&-Pqa($MV9NJUd040Ov5QCou#6xLwbCgxX!t_tVUT`#Yy)e&d}| zE-R`%LvdwKWag?CN;6?ydA_h&6H!)$vyN!9+UV!sGSEl_-5`pawj_z-jxj3P{{4u zhcajv$!JBe7GaZ>c`D(}AxE#V7@6l32>K`$8AR~xTzI1t$DO!c?mNyOxH0TJYvGcnYVH9_fa2#7hxN7?o=5UW32UT{8IEz^vAewIFpocJ`b ziKHGL%j*rg-TV18!fE1%>qqxe^sndWTK2Uu@n?O#mKW$>5n;%apB4HDpzHhR@gG`S z!u$*L^-}d<<*B{zvU521XU0>gW^2#0>l^+e26bGRjt=tfFDSU3k(TP1?wbBukN6Zp z8W0o|mS{NZxTFdrzSw63s}3K(El?appjX$a%NUt|$OM^xq{wXzw`lcg^pFUo(rjO= zBcT?Y%ZQTL)bs*uhtl1Q`&+w{ED+|~?j;NNM;<#~&a_1$tyIHDX4?eTWgH4LRl1V@8Pio| z6e0SmoDb;5v_LPG_GYhLi5PhVnA|{dR>tl(wlZRH*Y{IzsQFUYp5L$ad2^S>tD{Ht zQonme_SlPLo;{_|Ee+8ydl?IttBI)-)N=hQZ`5*~bb@quyb+b8HGj{*k*cZ+ws7Br zE3(+$YB)IQ5dL71Is-ny(Ucea_Gxi`()pwCSw5q-9bBN@!xLKb455&oaK#}v*o&Cj zF$X1a#@ZlHcDU8XV0Y7lQ{P~B8Od#GKte;e!@z)a50$zPnsQ}I`I*~}5KqxHGHln$ zL2)0p6ua2ha;r%G#N)m)WIa%tNqGn|PMJ1!RFjgB&Uw4CJx%irG4^-BLPcg$z*p@j z%0HyTqD8I@*}>sb5~Fx{Phf?xq>A$PU)D0z_?pi~j}UPUSJUCD?!N$Np^K!tbP=gtuDQB+p^&_E_A_58=y?o z?_24)4?#cE0K>+sw5s=@CPu!{9074vGu<_&zcFfarnrIk9^!xCdjKw=6n#5)9jS9+ ztRDLar+pG()#ETT(NU`s`oNX1K1BlRQwj!52ed(9?c^?2KJ#KSejjVzAS?}CAf>cl z;SHs4}x5oP9a@$N3)pYvwd8@ZO>d8+h{| z!nfxHOREKoYs+V>$%X57rEQz;*V+VUCtGbg70Vr>O(C<=F3g3KruhOo`W~3m$r0DZ zM&R#g+cT5Bv9UD7%RX|Zp1%5uXZrQE*tqeP+&J!&|!cN~LIWf?6j4>L+CE^>OxVfNf5;0gjGTP*+DPQLt zH&o|0ufBUP&Y{BOmn~P#{4sq{mgh9n_M%pMFwGR{5NoTwo@rZ<@yxYPXcKc+`JhKa!nsOc2uFXHQ&@;xbZ5W|fA+HtRO!u#A zW%JR~#!&=SClXq4D!S@%Qe)Jo;;$kb{y0h;KA=_2)~)c_o|`qQW=K>ofa78vF7#pz z`bMWQe1_(WpKQSNW2*P`ZcI&MXe|57VU!TnAy^y-fjAvDP7@RszeEpsys2S6v)daz zE)~&$=nATZuiw404yRWaT7+XD4ht-j?4bUA-0*!$cNhA6w7ZYjwJR}N8RHs`;BTDn z4$iR5){{8Ezj6<88lFDi*@$UHjWf*kZJEu7V=XNcjURset`E3x1^k=L$Q|6DVd4)b zJEzez0JOE?+jv8CWM7r9K$1nqg)#5X-rWB{oFLTP+(G9-O$r>voM(lDqxCgH!ltpFvW zT>q#y!p6geO1B1Y&aq;yOaOXRnyl05Lhi8y{-sp`qD zRprTd?4~s0%ew@;fi_6nxt3s^>UTN&*XKf^x_Gt;h5sgr@TrHWh<{C`+?N;Akz2?wO#kcuh?@eHVwCqxPnKmN#!t zyUSTE7?u{s!@X|xn23xwI^$8u^b+_Rn0yzrxuTH_;%zB!ZvSRH@ znrE?vtY3{HB9}jY&Iwwg=iwFQ!UUTH-iJBPBfwzp8pYtmdI%Hz2~g_&wR@)bpM)v& zYm+Yq^sd7&oK^4knj0=gdaFVrVztd(FPD$F;5F8xgy=@71v@%gifbc3u^xmFEc8 z)C(62<#2qGD_S&}Za5IPyVroz}&<-*g{1rQ;TnJM+vJioPl zi4xqInURF@SbrP)>anmv>v51!%neo>&nc2C)AsZQl$PFsc|lZc#od-Hp+YyY37V=yXU+lpKxC1{2Ps#1hKegK#o5Lv5WXj;}^vQh#f@<>1D_{oDFR z4(73Szx9YGR5&=A>IY5B C3Wh6`~3h|zEWfjK{wD=gBvZ60)wTkcvR{@6zcH9;1dtrl^2@)}VwyD2m&Y;G-Sbw)axh8}|}y1dA-(y7BG+-96k z)`SDzMsiSr{=`i1&xywebR2y)ltTQ5i|SSy1@pM_vp3NsU|KNsXLqPgFFKv!v*uP* za#Cow2W{Vcjq`-*z?EWf za9f{*@Q_QX1sQTY!R6?y6<~_Ex7ULpOR4xoZx>J#r0r;Y!ZemqaVfy9jkW$DA{oO) z=2SaS;63N3SjxVRTFbf@Vv5M|+rtrCeB2GQ*XoV(m4#4;oiAkf#~*F-Wj{H?nu>?5 z$TmQod_5!F9=>l08g?A1;t+%}l;^b>-f(%!)%gNRsySGI}777g5@2vvg+;~gCu;***vJ*Hws$A8%A9Z8D z^kgqp4#;OSBX@HAcPP~}od()^Bu-|vssq0gev)Ob@4d38Ol@r_>wY(jYem&;TXT4u z`v$~72E}h?mc{x8ET~Md;c5zL>4XGflQYlLZIR!%uR(Lq+?RIPyo<(Xpkht)KfA=K z#esZ)y8Q_|)PFPHde1vyR>L^Kg$i3Pk${N6bcdJDV0f;; zso&=yVrY#6^INNsnUSP?_mV6@LLUUE)fmR`13rBcmavaxS+fw}aVZ!8>h_luSMAkgh(U(mab~~{<(N_A+D)`x z5eL#@$=sUCyHptJh==fKGw}<}HUm~cX^g16c4d?#tqcup7h^1g+MJab2kg7Alqvvq z+MMm&OSN=nN%`c{(r+LC>t^S7;atrUgy0C95g@sN^OaAlB);v()M4r~4}V5=(>mC8 z3ERE9>e&i-H&9HKk!GyVIR)e*DO(B-_~(jre>OC&Zx52dUW_O_8e5);wyM%EtW?kp zhqkL%b*S9nB~+Gp`unYRAVe3Oe7Wp=IMO1-OLzur7GQq8%=Pi|D^T+Lj6P$1Q7hTg zYISjQX~3y{ar3l{0x@T4RH>d|fILfLp9SRbD0#IH#`}jHK`R!MQ$C)K+i3-<~OSG`|9F5C) zGoY{=yjw=0#F|>fy2RT_ zqpK__!PQ{C!+UjzXRwpGHUr>Xy}xwCm%q&cp?X2c)fect;EeJMJ9-hV!lAERc8@93 zZ@|3f7xh0~XP5%L8gc1baLgwlk%ETTfT01qIRmt$zK7&?MZNOW#F>T<6qSxnjoOn| z6*;OPc~*Gim#tOH)tH`e@WayT5I&l@O6fx!53blF2Bs|iyj(s}{(3tXZt^)ghD4EI8Rw zO$jNrsC(8OX63~&^xsVj$b`;ZC*6gXE}Qr4Q{GXgn-cW_iYT{XhCwD6BKdYLalg;- z9^RVSJ$3Hyr)&?BnncP^%8@xn6@rhdBoH<`4Dxdadc=%k;--$0+%4NIq5VgJdexQ9 zvL~m&DMNkrN_rx@YfDeZaTt0K59RTvnb_w|ztkg`y$SK}j@5Es2)}uks#n_Vq=j%Up()$j zt6tEJA^98`g8z1Vv_ojrERrr=gs%MoibOu=?l7M0s$;Rx$5hWZ4F6CYPQ6SFXCg** z4;tY>R2T%89-D$>KKUH7s`df+gU{PSv+gizb7{#^n_2Tm$U!q7fPg+5S*0uPLb4v&2nZJ{OO(RxeC1q4!tI4e1 z^_FRN6SYc=nn%D9j&rDfVr+lWfo@!Jirc<*|6c%e1&sQYlL9h|bG+ibgf~G^uKVHq zBv#FL??QGY%6adPRrB6^knKyM-1q)iHUGT}SqPK^-yaJX*zQ9XQ#)FF1}xlzzrUHQ z4rJTW?oxFIteU_i!7DXc4sQK)@6CxR>(`hQP*5*FehDsDdbd|>1oC3^Ksa&y(zg~U zwYxn;Y~1Z9?0wcvrhT_R)_aTWq+wDBdCo8?WPJHBDO~Q$he-*?J1L;wC~5UDeiKw~ znt2oWNi2tg%sN>(7D8bDSRMtLb+j$CYJN|`h3~P&2`!~|)$b{|Y9cExX!*XsIV!Rf zaMeU6YWS>11Bw22ji_z8YPw9)xKB-XarX@T`hdVt$o^mwe z1LLcYMtoSVW5UBJrfrb|nw#+OOcVdEf^tlFXl-yZ_7z7)<*Hs< zyjY)p-OBbTJCyzT29rK8o^deg1LA8BCVg0JJJId+hu)C_GD>uNxsjV!F|{3(=21MOBotq9t25>Z0n8Rda>7kcGW{Q9T1z&DrKcwykaN7N)oUmyxrrg<#PYQp?x4)T z+n1BeZD(o;EoT;D|4YHFU;Dtn#Jpk``;fv~OV)xiGP>AnHu2D3Kyx7DlA4oa{>+k^ zm}GtiH6t}%CMy2XS>{%!=%dDd98L5ZI(xyLvGJDi)z$5@lw%L)w~-*_No^zu`SLar zT<%Y>k=pMYDWYE!sebU|lKM4~`n1don@A7m(-}>qZ%61!O{BKMen}H4EJwnwwfo-R z5dB#9`vm8cnn(|n=QNQXAYa`?dRXocFp-G&jTF(ZiBvuKE0X#(k@~dE>zYW9=hF#I zr0+-QIZY%&VZWq_w1o|;(q0)OV~+J$qzw^f{WEEcXXkNbT2+l+dq% z)HwE0N&Ol~eM;t)4J3Fxozg&hJVDQDAT{;%OBzV)zMyXZons%Z=TAg>pggU8wEmz( zq=)7H0Q;!~-T&9&EYP5}*Uv~;FTx7usEfEv!PQitXY;{80i5YgM;KHkN$96`qqm||qyOVI$ zM3!C94q}eoDY$APV+^XcLyK!@7t5c5tES8PJF^;+h1AymXTZYu*vjb4YDgB3QzRr# zS-<952?h1?zGS%EiN55|jX-+H9tbD8l0Ol({)BP*5*#c*EsRP2%Vq$n{7#HHV{bAlCz8qtVNR dz0WcN9vZ#;-~aQztpET2`+tR^&IT6e6aX7$2p9kW literal 37243 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 iNo${kKW8=7^Wn~Uo{hi%`n9b8|MMS%z?~gpv Date: Mon, 21 Oct 2024 15:55:57 +0200 Subject: [PATCH 08/53] change serviceTimeSelection and remove from interface --- .../DefaultUnhandledServicesSolution.java | 108 ++++++++++-------- ...rateSmallScaleCommercialTrafficDemand.java | 38 +++++- .../UnhandledServicesSolution.java | 22 ++-- 3 files changed, 105 insertions(+), 63 deletions(-) diff --git a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/DefaultUnhandledServicesSolution.java b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/DefaultUnhandledServicesSolution.java index 4928ce2a401..d436dc6320d 100644 --- a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/DefaultUnhandledServicesSolution.java +++ b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/DefaultUnhandledServicesSolution.java @@ -34,61 +34,12 @@ public List createListOfCarrierWithUnhandledJobs(Scenario scenario){ return carriersWithUnhandledJobs; } - public int getServiceTimePerStop(Carrier carrier, GenerateSmallScaleCommercialTrafficDemand.CarrierAttributes carrierAttributes, int additionalTravelBufferPerIterationInMinutes) { - GenerateSmallScaleCommercialTrafficDemand.ServiceDurationPerCategoryKey key = null; - if (carrierAttributes.smallScaleCommercialTrafficType().equals( - GenerateSmallScaleCommercialTrafficDemand.SmallScaleCommercialTrafficType.commercialPersonTraffic.toString())) - key = GenerateSmallScaleCommercialTrafficDemand.makeServiceDurationPerCategoryKey(carrierAttributes.selectedStartCategory(), null, carrierAttributes.smallScaleCommercialTrafficType()); - else if (carrierAttributes.smallScaleCommercialTrafficType().equals( - GenerateSmallScaleCommercialTrafficDemand.SmallScaleCommercialTrafficType.goodsTraffic.toString())) { - key = GenerateSmallScaleCommercialTrafficDemand.makeServiceDurationPerCategoryKey(carrierAttributes.selectedStartCategory(), carrierAttributes.modeORvehType(), carrierAttributes.smallScaleCommercialTrafficType()); - } - - //possible new Version by Ricardo - double maxVehicleAvailability = carrier.getCarrierCapabilities().getCarrierVehicles().values().stream().mapToDouble(vehicle -> vehicle.getLatestEndTime() - vehicle.getEarliestStartTime()).max().orElse(0); - int usedTravelTimeBuffer = additionalTravelBufferPerIterationInMinutes * 60; // buffer for the driving time; for unsolved carriers the buffer will be increased over time - for (int j = 0; j < 200; j++) { - GenerateSmallScaleCommercialTrafficDemand.DurationsBounds serviceDurationBounds = generator.getServiceDurationTimeSelector().get(key).sample(); - - for (int i = 0; i < 10; i++) { - int serviceDurationLowerBound = serviceDurationBounds.minDuration(); - int serviceDurationUpperBound = serviceDurationBounds.maxDuration(); - int possibleValue = rnd.nextInt(serviceDurationLowerBound * 60, serviceDurationUpperBound * 60); - // checks if the service duration will not exceed the vehicle availability including the buffer - if (possibleValue + usedTravelTimeBuffer <= maxVehicleAvailability) - return possibleValue; - } - if (j > 100){ - CarrierVehicle carrierVehicleToChange = carrier.getCarrierCapabilities().getCarrierVehicles().values().stream().sorted(Comparator.comparingDouble(vehicle -> vehicle.getLatestEndTime() - vehicle.getEarliestStartTime())).toList().getFirst(); - log.info("Changing vehicle availability for carrier {}. Old maxVehicleAvailability: {}", carrier.getId(), maxVehicleAvailability); - int tourDuration = 0; - int vehicleStartTime = 0; - int vehicleEndTime = 0; - while (tourDuration < maxVehicleAvailability) { - GenerateSmallScaleCommercialTrafficDemand.TourStartAndDuration t = generator.getTourDistribution().get(carrierAttributes.smallScaleCommercialTrafficType()).sample(); - vehicleStartTime = t.getVehicleStartTime(); - tourDuration = t.getVehicleTourDuration(); - vehicleEndTime = vehicleStartTime + tourDuration; - } - CarrierVehicle newCarrierVehicle = CarrierVehicle.Builder.newInstance(carrierVehicleToChange.getId(), carrierVehicleToChange.getLinkId(), - carrierVehicleToChange.getType()).setEarliestStart(vehicleStartTime).setLatestEnd(vehicleEndTime).build(); - carrier.getCarrierCapabilities().getCarrierVehicles().remove(carrierVehicleToChange.getId()); - carrier.getCarrierCapabilities().getCarrierVehicles().put(newCarrierVehicle.getId(), newCarrierVehicle); - maxVehicleAvailability = carrier.getCarrierCapabilities().getCarrierVehicles().values().stream().mapToDouble(vehicle -> vehicle.getLatestEndTime() - vehicle.getEarliestStartTime()).max().orElse(0); - log.info("New maxVehicleAvailability: {}", maxVehicleAvailability); - } - } - - throw new RuntimeException("No possible service duration found for employee category '" + carrierAttributes.selectedStartCategory() + "' and mode '" - + carrierAttributes.modeORvehType() + "' in traffic type '" + carrierAttributes.smallScaleCommercialTrafficType() + "'"); - } - /** * Redraws the service-durations of all {@link CarrierService}s of the given {@link Carrier}. */ private void redrawAllServiceDurations(Carrier carrier, GenerateSmallScaleCommercialTrafficDemand.CarrierAttributes carrierAttributes, int additionalTravelBufferPerIterationInMinutes) { for (CarrierService service : carrier.getServices().values()) { - double newServiceDuration = getServiceTimePerStop(carrier, carrierAttributes, additionalTravelBufferPerIterationInMinutes); + double newServiceDuration = generator.getServiceTimePerStop(carrier, carrierAttributes, additionalTravelBufferPerIterationInMinutes); CarrierService redrawnService = CarrierService.Builder.newInstance(service.getId(), service.getLocationLinkId()) .setServiceDuration(newServiceDuration).setServiceStartTimeWindow(service.getServiceStartTimeWindow()).build(); carrier.getServices().put(redrawnService.getId(), redrawnService); @@ -133,4 +84,61 @@ public void tryToSolveAllCarriersCompletely(Scenario scenario, List non } } + /** + * Change the service duration for a given carrier, because the service could not be handled in the last solution. + * + * @param carrier The carrier for which we generate the serviceTime + * @param carrierAttributes attributes of the carrier to generate the service time for. + * @param key key for the service duration + * @param additionalTravelBufferPerIterationInMinutes additional buffer for the travel time + * @return new service duration + */ + @Override + public int changeServiceTimePerStop(Carrier carrier, GenerateSmallScaleCommercialTrafficDemand.CarrierAttributes carrierAttributes, + GenerateSmallScaleCommercialTrafficDemand.ServiceDurationPerCategoryKey key, + int additionalTravelBufferPerIterationInMinutes) { + + double maxVehicleAvailability = carrier.getCarrierCapabilities().getCarrierVehicles().values().stream().mapToDouble(vehicle -> vehicle.getLatestEndTime() - vehicle.getEarliestStartTime()).max().orElse(0); + int usedTravelTimeBuffer = additionalTravelBufferPerIterationInMinutes * 60; // buffer for the driving time; for unsolved carriers the buffer will be increased over time + for (int j = 0; j < 200; j++) { + if (generator.getServiceDurationTimeSelector().get(key) == null) { + System.out.println("key: " + key); + System.out.println(generator.getServiceDurationTimeSelector().keySet()); + throw new RuntimeException("No service duration found for employee category '" + carrierAttributes.selectedStartCategory() + "' and mode '" + + carrierAttributes.modeORvehType() + "' in traffic type '" + carrierAttributes.smallScaleCommercialTrafficType() + "'"); + } + GenerateSmallScaleCommercialTrafficDemand.DurationsBounds serviceDurationBounds = generator.getServiceDurationTimeSelector().get(key).sample(); + + for (int i = 0; i < 10; i++) { + int serviceDurationLowerBound = serviceDurationBounds.minDuration(); + int serviceDurationUpperBound = serviceDurationBounds.maxDuration(); + int possibleValue = rnd.nextInt(serviceDurationLowerBound * 60, serviceDurationUpperBound * 60); + // checks if the service duration will not exceed the vehicle availability including the buffer + if (possibleValue + usedTravelTimeBuffer <= maxVehicleAvailability) + return possibleValue; + } + if (j > 100){ + CarrierVehicle carrierVehicleToChange = carrier.getCarrierCapabilities().getCarrierVehicles().values().stream().sorted(Comparator.comparingDouble(vehicle -> vehicle.getLatestEndTime() - vehicle.getEarliestStartTime())).toList().getFirst(); + log.info("Changing vehicle availability for carrier {}. Old maxVehicleAvailability: {}", carrier.getId(), maxVehicleAvailability); + int tourDuration = 0; + int vehicleStartTime = 0; + int vehicleEndTime = 0; + while (tourDuration < maxVehicleAvailability) { + GenerateSmallScaleCommercialTrafficDemand.TourStartAndDuration t = generator.getTourDistribution().get(carrierAttributes.smallScaleCommercialTrafficType()).sample(); + vehicleStartTime = t.getVehicleStartTime(); + tourDuration = t.getVehicleTourDuration(); + vehicleEndTime = vehicleStartTime + tourDuration; + } + CarrierVehicle newCarrierVehicle = CarrierVehicle.Builder.newInstance(carrierVehicleToChange.getId(), carrierVehicleToChange.getLinkId(), + carrierVehicleToChange.getType()).setEarliestStart(vehicleStartTime).setLatestEnd(vehicleEndTime).build(); + carrier.getCarrierCapabilities().getCarrierVehicles().remove(carrierVehicleToChange.getId()); + carrier.getCarrierCapabilities().getCarrierVehicles().put(newCarrierVehicle.getId(), newCarrierVehicle); + maxVehicleAvailability = carrier.getCarrierCapabilities().getCarrierVehicles().values().stream().mapToDouble(vehicle -> vehicle.getLatestEndTime() - vehicle.getEarliestStartTime()).max().orElse(0); + log.info("New maxVehicleAvailability: {}", maxVehicleAvailability); + } + } + + throw new RuntimeException("No possible service duration found for employee category '" + carrierAttributes.selectedStartCategory() + "' and mode '" + + carrierAttributes.modeORvehType() + "' in traffic type '" + carrierAttributes.smallScaleCommercialTrafficType() + "'"); + } } diff --git a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java index 553b9abc689..2d26c267b66 100644 --- a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java +++ b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java @@ -750,11 +750,11 @@ private void createServices(Carrier newCarrier, CarrierAttributes inhabitantAttributes = new CarrierAttributes(carrierAttributes.purpose, carrierAttributes.startZone, carrierAttributes.odMatrixEntry.possibleStartCategories.getFirst(), carrierAttributes.modeORvehType, carrierAttributes.smallScaleCommercialTrafficType, carrierAttributes.vehicleDepots, carrierAttributes.odMatrixEntry); - serviceTimePerStop = unhandledServicesSolution.getServiceTimePerStop(newCarrier, inhabitantAttributes, 0); + serviceTimePerStop = getServiceTimePerStop(newCarrier, inhabitantAttributes, 0); } else { - serviceTimePerStop = unhandledServicesSolution.getServiceTimePerStop(newCarrier, carrierAttributes, 0); + serviceTimePerStop = getServiceTimePerStop(newCarrier, carrierAttributes, 0); } TimeWindow serviceTimeWindow = TimeWindow.newInstance(0, @@ -764,6 +764,40 @@ private void createServices(Carrier newCarrier, } } + /** + * Give a service duration based on the purpose and the trafficType under a given probability + * + * @param carrier The carrier for which the service time should be calculated + * @param carrierAttributes The attributes of the carrier + * @param additionalTravelBufferPerIterationInMinutes Additional travel buffer per recalculation iteration for a carrier in minutes + * @return The service time in seconds + */ + public Integer getServiceTimePerStop(Carrier carrier, GenerateSmallScaleCommercialTrafficDemand.CarrierAttributes carrierAttributes, + int additionalTravelBufferPerIterationInMinutes) { + GenerateSmallScaleCommercialTrafficDemand.ServiceDurationPerCategoryKey key; + if (carrierAttributes.smallScaleCommercialTrafficType().equals( + GenerateSmallScaleCommercialTrafficDemand.SmallScaleCommercialTrafficType.commercialPersonTraffic.toString())) + key = GenerateSmallScaleCommercialTrafficDemand.makeServiceDurationPerCategoryKey(carrierAttributes.selectedStartCategory(), null, + carrierAttributes.smallScaleCommercialTrafficType()); + else if (carrierAttributes.smallScaleCommercialTrafficType().equals( + GenerateSmallScaleCommercialTrafficDemand.SmallScaleCommercialTrafficType.goodsTraffic.toString())) { + key = GenerateSmallScaleCommercialTrafficDemand.makeServiceDurationPerCategoryKey(carrierAttributes.selectedStartCategory(), + carrierAttributes.modeORvehType(), carrierAttributes.smallScaleCommercialTrafficType()); + } else { + throw new RuntimeException("Unknown traffic type: " + carrierAttributes.smallScaleCommercialTrafficType()); + } + // additionalTravelBufferPerIterationInMinutes is only used for recalculation of the service time if a carrier solution could not handle all services + if (additionalTravelBufferPerIterationInMinutes == 0) { + GenerateSmallScaleCommercialTrafficDemand.DurationsBounds serviceDurationBounds = serviceDurationTimeSelector.get(key).sample(); + + int serviceDurationLowerBound = serviceDurationBounds.minDuration(); + int serviceDurationUpperBound = serviceDurationBounds.maxDuration(); + return rnd.nextInt(serviceDurationLowerBound * 60, serviceDurationUpperBound * 60); + } else { + return unhandledServicesSolution.changeServiceTimePerStop(carrier, carrierAttributes, key, additionalTravelBufferPerIterationInMinutes); + } + } + /** * Adds a service with the given attributes to the carrier. */ diff --git a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/UnhandledServicesSolution.java b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/UnhandledServicesSolution.java index e5db51e8557..c65c75deee7 100644 --- a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/UnhandledServicesSolution.java +++ b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/UnhandledServicesSolution.java @@ -17,17 +17,6 @@ public interface UnhandledServicesSolution { */ List createListOfCarrierWithUnhandledJobs(Scenario scenario); - /** - * Give a service duration based on the purpose and the trafficType under a given probability - * - * @param carrier The carrier for which we generate the serviceTime - * @param carrierAttributes attributes of the carrier to generate the service time for. - * selectedStartCategory: the category of the employee - * @param additionalTravelBufferPerIterationInMinutes additional buffer for the travel time - * @return the service duration - */ - int getServiceTimePerStop(Carrier carrier, GenerateSmallScaleCommercialTrafficDemand.CarrierAttributes carrierAttributes, int additionalTravelBufferPerIterationInMinutes); - /** * * Checks and recalculates plans of carriers, which did not serve all services. @@ -36,4 +25,15 @@ public interface UnhandledServicesSolution { * @param nonCompleteSolvedCarriers List of carriers, that are not solved. Can be obtained by {@link UnhandledServicesSolution#createListOfCarrierWithUnhandledJobs(Scenario)} */ void tryToSolveAllCarriersCompletely(Scenario scenario, List nonCompleteSolvedCarriers); + + /** + * Change the service duration for a given carrier, because the service could not be handled in the last solution. + * + * @param carrier The carrier for which we generate the serviceTime + * @param carrierAttributes attributes of the carrier to generate the service time for. + * @param key key for the service duration + * @param additionalTravelBufferPerIterationInMinutes additional buffer for the travel time + * @return new service duration + */ + int changeServiceTimePerStop(Carrier carrier, GenerateSmallScaleCommercialTrafficDemand.CarrierAttributes carrierAttributes, GenerateSmallScaleCommercialTrafficDemand.ServiceDurationPerCategoryKey key, int additionalTravelBufferPerIterationInMinutes); } From 7467e7060694a7425c3a23bf96f0ec9792643917 Mon Sep 17 00:00:00 2001 From: Ricardo Ewert Date: Tue, 29 Oct 2024 13:50:09 +0100 Subject: [PATCH 09/53] clean up --- .../DefaultUnhandledServicesSolution.java | 1 - .../GenerateSmallScaleCommercialTrafficDemand.java | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/DefaultUnhandledServicesSolution.java b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/DefaultUnhandledServicesSolution.java index d436dc6320d..735a2d8f44a 100644 --- a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/DefaultUnhandledServicesSolution.java +++ b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/DefaultUnhandledServicesSolution.java @@ -56,7 +56,6 @@ public void tryToSolveAllCarriersCompletely(Scenario scenario, List non for (Carrier nonCompleteSolvedCarrier : nonCompleteSolvedCarriers) { //Delete old plan of carrier nonCompleteSolvedCarrier.clearPlans(); - nonCompleteSolvedCarrier.setSelectedPlan(null); GenerateSmallScaleCommercialTrafficDemand.CarrierAttributes carrierAttributes = generator.getCarrierId2carrierAttributes().get(nonCompleteSolvedCarrier.getId()); // Generate new services. The new service batch should have a smaller sum of serviceDurations than before (or otherwise it will not change anything) diff --git a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java index 2d26c267b66..f25ab4df11f 100644 --- a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java +++ b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java @@ -731,8 +731,7 @@ public void createCarriers(Scenario scenario, /** * Generates and adds the services for the given carrier. */ - private void createServices(Carrier newCarrier, - CarrierAttributes carrierAttributes) { + private void createServices(Carrier newCarrier, CarrierAttributes carrierAttributes) { log.info("Create services for carrier: {}", newCarrier.getId()); for (String stopZone : odMatrix.getListOfZones()) { int trafficVolumeForOD = Math.round((float)odMatrix.getTripDistributionValue(carrierAttributes.startZone, @@ -848,7 +847,6 @@ private void createNewCarrierAndAddVehicleTypes(Scenario scenario, String carrie for (String singleDepot : carrierAttributes.vehicleDepots) { GenerateSmallScaleCommercialTrafficDemand.TourStartAndDuration t = tourDistribution.get(carrierAttributes.smallScaleCommercialTrafficType).sample(); - int vehicleStartTime = t.getVehicleStartTime(); int tourDuration = t.getVehicleTourDuration(); int vehicleEndTime = vehicleStartTime + tourDuration; From b07ce9950fc30b74fd0fd1dce25fac356786af88 Mon Sep 17 00:00:00 2001 From: u229187 Date: Tue, 5 Nov 2024 10:54:29 +0100 Subject: [PATCH 10/53] solve windows related problems in drt-extensions-tests --- .../contrib/drt/extension/fiss/RunFissDrtScenarioIT.java | 2 +- .../shifts/run/RunPrebookingShiftDrtScenarioIT.java | 6 +++--- .../operations/shifts/run/RunShiftDrtScenarioIT.java | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/fiss/RunFissDrtScenarioIT.java b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/fiss/RunFissDrtScenarioIT.java index 120cff4f5a3..1c46945920b 100644 --- a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/fiss/RunFissDrtScenarioIT.java +++ b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/fiss/RunFissDrtScenarioIT.java @@ -139,7 +139,7 @@ void test() { config.controller().setWriteEventsInterval(1); config.controller().setOverwriteFileSetting(OutputDirectoryHierarchy.OverwriteFileSetting.deleteDirectoryIfExists); - config.controller().setOutputDirectory("test/output/holzkirchen_shifts"); + config.controller().setOutputDirectory("test/output/RunFissDrtScenarioIT"); DrtOperationsParams operationsParams = (DrtOperationsParams) drtWithShiftsConfigGroup.createParameterSet(DrtOperationsParams.SET_NAME); ShiftsParams shiftsParams = (ShiftsParams) operationsParams.createParameterSet(ShiftsParams.SET_NAME); diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/operations/shifts/run/RunPrebookingShiftDrtScenarioIT.java b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/operations/shifts/run/RunPrebookingShiftDrtScenarioIT.java index 01f5e27b837..50f97972417 100644 --- a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/operations/shifts/run/RunPrebookingShiftDrtScenarioIT.java +++ b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/operations/shifts/run/RunPrebookingShiftDrtScenarioIT.java @@ -71,7 +71,7 @@ void testWithReattempts() { MultiModeDrtConfigGroup multiModeDrtConfigGroup = new MultiModeDrtConfigGroup(DrtWithExtensionsConfigGroup::new); DrtWithExtensionsConfigGroup drtWithShiftsConfigGroup = (DrtWithExtensionsConfigGroup) multiModeDrtConfigGroup.createParameterSet("drt"); - final Controler run = prepare(drtWithShiftsConfigGroup, multiModeDrtConfigGroup); + final Controler run = prepare(drtWithShiftsConfigGroup, multiModeDrtConfigGroup, "_testWithReattempts"); Multiset> submittedPersons = HashMultiset.create(); Multiset> scheduledPersons = HashMultiset.create(); @@ -125,7 +125,7 @@ void testWithoutReattempts() { MultiModeDrtConfigGroup multiModeDrtConfigGroup = new MultiModeDrtConfigGroup(DrtWithExtensionsConfigGroup::new); DrtWithExtensionsConfigGroup drtWithShiftsConfigGroup = (DrtWithExtensionsConfigGroup) multiModeDrtConfigGroup.createParameterSet("drt"); - final Controler run = prepare(drtWithShiftsConfigGroup, multiModeDrtConfigGroup); + final Controler run = prepare(drtWithShiftsConfigGroup, multiModeDrtConfigGroup, "_testWithoutReattempts"); Multiset> submittedPersons = HashMultiset.create(); Multiset> scheduledPersons = HashMultiset.create(); @@ -175,7 +175,7 @@ public void install() { } @NotNull - private Controler prepare(DrtWithExtensionsConfigGroup drtWithShiftsConfigGroup, MultiModeDrtConfigGroup multiModeDrtConfigGroup) { + private Controler prepare(DrtWithExtensionsConfigGroup drtWithShiftsConfigGroup, MultiModeDrtConfigGroup multiModeDrtConfigGroup, String outputSuffix) { drtWithShiftsConfigGroup.mode = TransportMode.drt; DefaultDrtOptimizationConstraintsSet defaultConstraintsSet = (DefaultDrtOptimizationConstraintsSet) drtWithShiftsConfigGroup.addOrGetDrtOptimizationConstraintsParams() diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/operations/shifts/run/RunShiftDrtScenarioIT.java b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/operations/shifts/run/RunShiftDrtScenarioIT.java index acfc878a000..6f10693a452 100644 --- a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/operations/shifts/run/RunShiftDrtScenarioIT.java +++ b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/operations/shifts/run/RunShiftDrtScenarioIT.java @@ -132,7 +132,7 @@ void test() { config.controller().setWriteEventsInterval(1); config.controller().setOverwriteFileSetting(OutputDirectoryHierarchy.OverwriteFileSetting.deleteDirectoryIfExists); - config.controller().setOutputDirectory("test/output/holzkirchen_shifts"); + config.controller().setOutputDirectory("test/output/RunShiftDrtScenarioIT"); DrtOperationsParams operationsParams = (DrtOperationsParams) drtWithShiftsConfigGroup.createParameterSet(DrtOperationsParams.SET_NAME); ShiftsParams shiftsParams = (ShiftsParams) operationsParams.createParameterSet(ShiftsParams.SET_NAME); From 85dc616d2173e3ea50f99a6e462d8386aca76913 Mon Sep 17 00:00:00 2001 From: u229187 Date: Tue, 5 Nov 2024 13:18:50 +0100 Subject: [PATCH 11/53] change output dir --- .../operations/shifts/run/RunPrebookingShiftDrtScenarioIT.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/operations/shifts/run/RunPrebookingShiftDrtScenarioIT.java b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/operations/shifts/run/RunPrebookingShiftDrtScenarioIT.java index 50f97972417..61e3a64a97a 100644 --- a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/operations/shifts/run/RunPrebookingShiftDrtScenarioIT.java +++ b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/operations/shifts/run/RunPrebookingShiftDrtScenarioIT.java @@ -245,7 +245,7 @@ private Controler prepare(DrtWithExtensionsConfigGroup drtWithShiftsConfigGroup, config.controller().setWriteEventsInterval(1); config.controller().setOverwriteFileSetting(OutputDirectoryHierarchy.OverwriteFileSetting.deleteDirectoryIfExists); - config.controller().setOutputDirectory("test/output/prebooking_shifts"); + config.controller().setOutputDirectory("test/output/prebooking_shifts"+outputSuffix); DrtOperationsParams operationsParams = (DrtOperationsParams) drtWithShiftsConfigGroup.createParameterSet(DrtOperationsParams.SET_NAME); ShiftsParams shiftsParams = (ShiftsParams) operationsParams.createParameterSet(ShiftsParams.SET_NAME); From 65edb802c2e672bfdbfa60e5fefea6ea4cdc56a3 Mon Sep 17 00:00:00 2001 From: rakow Date: Tue, 5 Nov 2024 15:26:23 +0100 Subject: [PATCH 12/53] Extend trip analysis (#3540) * write mode chains in trip analysis * add output to write mode shares per purpose * write mode share per purpose --- .../analysis/population/TripAnalysis.java | 133 +++++++++++++++--- .../population/TripByGroupAnalysis.java | 2 +- .../simwrapper/dashboard/DashboardTests.java | 1 + 3 files changed, 116 insertions(+), 20 deletions(-) diff --git a/contribs/application/src/main/java/org/matsim/application/analysis/population/TripAnalysis.java b/contribs/application/src/main/java/org/matsim/application/analysis/population/TripAnalysis.java index 893c05cf9fd..2365ed8a189 100644 --- a/contribs/application/src/main/java/org/matsim/application/analysis/population/TripAnalysis.java +++ b/contribs/application/src/main/java/org/matsim/application/analysis/population/TripAnalysis.java @@ -4,10 +4,7 @@ import it.unimi.dsi.fastutil.ints.IntList; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; -import it.unimi.dsi.fastutil.objects.Object2IntLinkedOpenHashMap; -import it.unimi.dsi.fastutil.objects.Object2IntMap; -import it.unimi.dsi.fastutil.objects.Object2LongMap; -import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap; +import it.unimi.dsi.fastutil.objects.*; import org.apache.commons.csv.CSVFormat; import org.apache.commons.csv.CSVPrinter; import org.apache.commons.math3.analysis.interpolation.LoessInterpolator; @@ -27,6 +24,7 @@ import org.matsim.core.utils.io.IOUtils; import picocli.CommandLine; import tech.tablesaw.api.*; +import tech.tablesaw.columns.strings.AbstractStringColumn; import tech.tablesaw.io.csv.CsvReadOptions; import tech.tablesaw.joining.DataFrameJoiner; import tech.tablesaw.selection.Selection; @@ -37,6 +35,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.*; +import java.util.stream.Collectors; import java.util.stream.IntStream; import static tech.tablesaw.aggregate.AggregateFunctions.count; @@ -46,8 +45,9 @@ requires = {"trips.csv", "persons.csv"}, produces = { "mode_share.csv", "mode_share_per_dist.csv", "mode_users.csv", "trip_stats.csv", - "mode_share_per_%s.csv", "population_trip_stats.csv", "trip_purposes_by_hour.csv", - "mode_share_distance_distribution.csv", "mode_shift.csv", + "mode_share_per_purpose.csv", "mode_share_per_%s.csv", + "population_trip_stats.csv", "trip_purposes_by_hour.csv", + "mode_share_distance_distribution.csv", "mode_shift.csv", "mode_chains.csv", "mode_choices.csv", "mode_choice_evaluation.csv", "mode_choice_evaluation_per_mode.csv", "mode_confusion_matrix.csv", "mode_prediction_error.csv" } @@ -283,10 +283,15 @@ public Integer call() throws Exception { joined.addColumns(dist_group); + TextColumn purpose = joined.textColumn("end_activity_type"); + + // Remove suffix durations like _345 + purpose.set(Selection.withRange(0, purpose.size()), purpose.replaceAll("_[0-9]{2,}$", "")); + writeModeShare(joined, labels); if (groups != null) { - groups.analyzeModeShare(joined, labels, modeOrder, (g) -> output.getPath("mode_share_per_%s.csv", g)); + groups.writeModeShare(joined, labels, modeOrder, (g) -> output.getPath("mode_share_per_%s.csv", g)); } if (persons.containsColumn(ATTR_REF_MODES)) { @@ -305,17 +310,24 @@ public Integer call() throws Exception { writePopulationStats(persons, joined); - writeTripStats(joined); - - writeTripPurposes(joined); - - writeTripDistribution(joined); - - writeModeShift(joined); + tryRun(this::writeTripStats, joined); + tryRun(this::writeTripPurposes, joined); + tryRun(this::writeTripDistribution, joined); + tryRun(this::writeModeShift, joined); + tryRun(this::writeModeChains, joined); + tryRun(this::writeModeStatsPerPurpose, joined); return 0; } + private void tryRun(ThrowingConsumer f, Table df) { + try { + f.accept(df); + } catch (IOException e) { + log.error("Error while running method", e); + } + } + private void writeModeShare(Table trips, List labels) { Table aggr = trips.summarize("trip_id", count).by("dist_group", "main_mode"); @@ -502,11 +514,6 @@ private void writeTripPurposes(Table trips) { IntColumn.create("arrival_h", arrival.intStream().toArray()) ); - TextColumn purpose = trips.textColumn("end_activity_type"); - - // Remove suffix durations like _345 - purpose.set(Selection.withRange(0, purpose.size()), purpose.replaceAll("_[0-9]{2,}$", "")); - Table tArrival = trips.summarize("trip_id", count).by("end_activity_type", "arrival_h"); tArrival.column(0).setName("purpose"); @@ -610,6 +617,89 @@ private void writeModeShift(Table trips) throws IOException { aggr.write().csv(output.getPath("mode_shift.csv").toFile()); } + /** + * Collects information about all modes used during one day. + */ + private void writeModeChains(Table trips) throws IOException { + + Map> modesPerPerson = new LinkedHashMap<>(); + + for (Row trip : trips) { + String id = trip.getString("person"); + String mode = trip.getString("main_mode"); + modesPerPerson.computeIfAbsent(id, s -> new LinkedList<>()).add(mode); + } + + // Store other values explicitly + ObjectDoubleMutablePair other = ObjectDoubleMutablePair.of("other", 0); + Object2DoubleMap chains = new Object2DoubleOpenHashMap<>(); + for (List modes : modesPerPerson.values()) { + String key; + if (modes.size() == 1) + key = modes.getFirst(); + else if (modes.size() > 6) { + other.right(other.rightDouble() + 1); + continue; + } else + key = String.join("-", modes); + + chains.mergeDouble(key, 1, Double::sum); + } + + + List> counts = chains.object2DoubleEntrySet().stream() + .map(e -> ObjectDoubleMutablePair.of(e.getKey(), (int) e.getDoubleValue())) + .sorted(Comparator.comparingDouble(p -> -p.rightDouble())) + .collect(Collectors.toList()); + + // Aggregate entries to prevent file from getting too large + for (int i = 250; i < counts.size(); i++) { + other.right(other.rightDouble() + counts.get(i).rightDouble()); + } + counts = counts.subList(0, Math.min(counts.size(), 250)); + counts.add(other); + + counts.sort(Comparator.comparingDouble(p -> -p.rightDouble())); + + + try (CSVPrinter printer = new CSVPrinter(Files.newBufferedWriter(output.getPath("mode_chains.csv")), CSVFormat.DEFAULT)) { + + printer.printRecord("modes", "count", "share"); + + double total = counts.stream().mapToDouble(ObjectDoubleMutablePair::rightDouble).sum(); + for (ObjectDoubleMutablePair p : counts) { + printer.printRecord(p.left(), (int) p.rightDouble(), p.rightDouble() / total); + } + } + } + + @SuppressWarnings("unchecked") + private void writeModeStatsPerPurpose(Table trips) { + + Table aggr = trips.summarize("trip_id", count).by("end_activity_type", "main_mode"); + + Comparator cmp = Comparator.comparing(row -> row.getString("end_activity_type")); + aggr = aggr.sortOn(cmp.thenComparing(row -> row.getString("main_mode"))); + + aggr.doubleColumn(aggr.columnCount() - 1).setName("share"); + aggr.column("end_activity_type").setName("purpose"); + + Set purposes = (Set) aggr.column("purpose").asSet(); + + // Norm each purpose to 1 + // It was not clear if the purpose is a string or text colum, therefor this code uses the abstract version + for (String label : purposes) { + DoubleColumn all = aggr.doubleColumn("share"); + Selection sel = ((AbstractStringColumn) aggr.column("purpose")).isEqualTo(label); + + double total = all.where(sel).sum(); + if (total > 0) + all.set(sel, all.divide(total)); + } + + aggr.write().csv(output.getPath("mode_share_per_purpose.csv").toFile()); + } + /** * How shape file filtering should be applied. */ @@ -619,4 +709,9 @@ enum LocationFilter { home, none } + + @FunctionalInterface + private interface ThrowingConsumer { + void accept(T t) throws IOException; + } } diff --git a/contribs/application/src/main/java/org/matsim/application/analysis/population/TripByGroupAnalysis.java b/contribs/application/src/main/java/org/matsim/application/analysis/population/TripByGroupAnalysis.java index b63a58f5ed8..5f7e8894500 100644 --- a/contribs/application/src/main/java/org/matsim/application/analysis/population/TripByGroupAnalysis.java +++ b/contribs/application/src/main/java/org/matsim/application/analysis/population/TripByGroupAnalysis.java @@ -100,7 +100,7 @@ final class TripByGroupAnalysis { } } - void analyzeModeShare(Table trips, List dists, List modeOrder, Function output) { + void writeModeShare(Table trips, List dists, List modeOrder, Function output) { for (Group group : groups) { diff --git a/contribs/simwrapper/src/test/java/org/matsim/simwrapper/dashboard/DashboardTests.java b/contribs/simwrapper/src/test/java/org/matsim/simwrapper/dashboard/DashboardTests.java index dca4a209df1..223b0fdaaec 100644 --- a/contribs/simwrapper/src/test/java/org/matsim/simwrapper/dashboard/DashboardTests.java +++ b/contribs/simwrapper/src/test/java/org/matsim/simwrapper/dashboard/DashboardTests.java @@ -76,6 +76,7 @@ void trip() { Assertions.assertThat(out) .isDirectoryContaining("glob:**trip_stats.csv") .isDirectoryContaining("glob:**mode_share.csv") + .isDirectoryContaining("glob:**mode_share_per_purpose.csv") .isDirectoryContaining("glob:**mode_shift.csv"); } From c43bf1c812ca7047e8f470d07473f31241aff361 Mon Sep 17 00:00:00 2001 From: rakow Date: Tue, 5 Nov 2024 16:00:52 +0100 Subject: [PATCH 13/53] Consider stationary agents in scenario cut-out (#3541) --- .../scenario/CreateScenarioCutOut.java | 74 +++++++++---------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/contribs/application/src/main/java/org/matsim/application/prepare/scenario/CreateScenarioCutOut.java b/contribs/application/src/main/java/org/matsim/application/prepare/scenario/CreateScenarioCutOut.java index 6559a9c5c97..4dcd8a6bf5a 100644 --- a/contribs/application/src/main/java/org/matsim/application/prepare/scenario/CreateScenarioCutOut.java +++ b/contribs/application/src/main/java/org/matsim/application/prepare/scenario/CreateScenarioCutOut.java @@ -2,10 +2,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.locationtech.jts.geom.Coordinate; -import org.locationtech.jts.geom.Geometry; -import org.locationtech.jts.geom.GeometryFactory; -import org.locationtech.jts.geom.LineString; +import org.locationtech.jts.geom.*; import org.matsim.api.core.v01.Coord; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.Scenario; @@ -30,6 +27,7 @@ import org.matsim.core.population.algorithms.ParallelPersonAlgorithmUtils; import org.matsim.core.population.algorithms.PersonAlgorithm; import org.matsim.core.population.routes.NetworkRoute; +import org.matsim.core.router.DefaultAnalysisMainModeIdentifier; import org.matsim.core.router.TripStructureUtils; import org.matsim.core.router.TripStructureUtils.Trip; import org.matsim.core.router.costcalculators.OnlyTimeDependentTravelDisutility; @@ -453,7 +451,13 @@ private Coord getActivityCoord(Activity activity) { if (scenario.getActivityFacilities() != null && activity.getFacilityId() != null && scenario.getActivityFacilities().getFacilities().containsKey(activity.getFacilityId())) return scenario.getActivityFacilities().getFacilities().get(activity.getFacilityId()).getCoord(); - return activity.getCoord(); + if (activity.getCoord() != null) + return activity.getCoord(); + + if (activity.getLinkId() != null && scenario.getNetwork().getLinks().containsKey(activity.getLinkId())) + return scenario.getNetwork().getLinks().get(activity.getLinkId()).getCoord(); + + return null; } /** @@ -501,34 +505,44 @@ public void run(Person person) { boolean keepPerson = false; List trips = TripStructureUtils.getTrips(person.getSelectedPlan()); - + List activities = TripStructureUtils.getActivities(person.getSelectedPlan(), TripStructureUtils.StageActivityHandling.ExcludeStageActivities); Set> linkIds = new HashSet<>(); Set> facilityIds = new HashSet<>(); - for (Trip trip : trips) { - Coord originCoord = getActivityCoord(trip.getOriginActivity()); - Coord destinationCoord = getActivityCoord(trip.getDestinationActivity()); - - if (originCoord == null || destinationCoord == null) { - if (noActCoordsWarnings++ < 10) - log.info("Activity coords of trip is null. Skipping Trip..."); + // Check activities first, some agent might be stationary + for (Activity act : activities) { + Coord coord = getActivityCoord(act); - continue; + if (coord == null && noActCoordsWarnings++ < 10) { + log.info("Activity coords for agent {} are null. Skipping Trip...", person.getId()); } - // keep all agents starting or ending in area - if (geom.contains(MGC.coord2Point(originCoord)) || geom.contains(MGC.coord2Point(destinationCoord))) { + if (coord != null && geom.contains(MGC.coord2Point(coord))) { keepPerson = true; } - LineString line = geoFactory.createLineString(new Coordinate[]{ - MGC.coord2Coordinate(originCoord), - MGC.coord2Coordinate(destinationCoord) - }); + if (act.getFacilityId() != null) + facilityIds.add(act.getFacilityId()); - // also keep persons traveling through or close to area (beeline) - if (line.intersects(geom)) { - keepPerson = true; + if (act.getLinkId() != null) + linkIds.add(act.getLinkId()); + + } + + for (Trip trip : trips) { + Coord originCoord = getActivityCoord(trip.getOriginActivity()); + Coord destinationCoord = getActivityCoord(trip.getDestinationActivity()); + + if (originCoord != null && destinationCoord != null) { + LineString line = geoFactory.createLineString(new Coordinate[]{ + MGC.coord2Coordinate(originCoord), + MGC.coord2Coordinate(destinationCoord) + }); + + // also keep persons traveling through or close to area (beeline) + if (line.intersects(geom)) { + keepPerson = true; + } } //Save route links @@ -564,20 +578,6 @@ public void run(Person person) { } // There is no additional link freespeed information, that we could save. So we are finished here } - - if (trip.getOriginActivity().getFacilityId() != null) - facilityIds.add(trip.getOriginActivity().getFacilityId()); - - if (trip.getDestinationActivity().getFacilityId() != null) - facilityIds.add(trip.getDestinationActivity().getFacilityId()); - - if (trip.getOriginActivity().getLinkId() != null) { - linkIds.add(trip.getOriginActivity().getLinkId()); - } - - if (trip.getDestinationActivity().getLinkId() != null) { - linkIds.add(trip.getDestinationActivity().getLinkId()); - } } } From a39f46ec9f1149f9216318bbbff45a880308f96c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 15:04:50 +0000 Subject: [PATCH 14/53] build(deps): bump io.grpc:grpc-all from 1.66.0 to 1.68.1 Bumps [io.grpc:grpc-all](https://github.com/grpc/grpc-java) from 1.66.0 to 1.68.1. - [Release notes](https://github.com/grpc/grpc-java/releases) - [Commits](https://github.com/grpc/grpc-java/compare/v1.66.0...v1.68.1) --- updated-dependencies: - dependency-name: io.grpc:grpc-all dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- contribs/hybridsim/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contribs/hybridsim/pom.xml b/contribs/hybridsim/pom.xml index d8f69b28046..7bb94a4feff 100644 --- a/contribs/hybridsim/pom.xml +++ b/contribs/hybridsim/pom.xml @@ -11,7 +11,7 @@ 4.28.3 - 1.66.0 + 1.68.1 From a56eb9cfe680bccc2535eb2f69af52f1211d484d Mon Sep 17 00:00:00 2001 From: schlenther Date: Tue, 5 Nov 2024 17:51:11 +0100 Subject: [PATCH 15/53] use files from main output directory instead of from last iteration --- .../matsim/contrib/drt/extension/dashboards/DrtDashboard.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/dashboards/DrtDashboard.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/dashboards/DrtDashboard.java index 6131d9f0edd..d20c0192c3e 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/dashboards/DrtDashboard.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/dashboards/DrtDashboard.java @@ -134,7 +134,7 @@ public void configure(Header header, Layout layout) { viz.title = "Spatial rejection distribution"; viz.description = "Requested (and rejected) origins and destinations."; viz.projection = this.crs; - viz.file = data.output("ITERS/it." + lastIteration + "/*rejections_" + drtConfigGroup.mode + ".csv"); + viz.file = data.output("*rejections_" + drtConfigGroup.mode + ".csv"); viz.addAggregation("rejections", "origins", "fromX", "fromY", "destinations", "toX", "toY"); viz.center = data.context().getCenter(); @@ -222,7 +222,7 @@ public void configure(Header header, Layout layout) { .el(Area.class, (viz, data) -> { viz.title = "Vehicle occupancy"; //actually, without title the area plot won't work viz.description = "Number of passengers on board at a time"; - viz.dataset = data.output("ITERS/it." + lastIteration + "/*occupancy_time_profiles_" + drtConfigGroup.mode + ".txt"); + viz.dataset = data.output("/*occupancy_time_profiles_" + drtConfigGroup.mode + ".txt"); viz.x = "time"; viz.xAxisName = "Time"; viz.yAxisName = "Vehicles [1]"; From 4b0bc878de4d0e8a33db126dbbc3a8ce4106b4e0 Mon Sep 17 00:00:00 2001 From: Marcel Rieser Date: Wed, 6 Nov 2024 09:45:57 +0100 Subject: [PATCH 16/53] fix some edge cases when routing on networks with turn restrictions If the destination node was a "colored node", i.e. a node part of a restricted route, it has a different internal index than the original node that we compare against. Thus check also the orignial node index in such cases. --- .../java/org/matsim/core/router/speedy/SpeedyALT.java | 6 ++++++ .../org/matsim/core/router/speedy/SpeedyDijkstra.java | 6 ++++++ .../java/org/matsim/core/router/speedy/SpeedyGraph.java | 8 +++++++- .../org/matsim/core/router/speedy/SpeedyGraphBuilder.java | 4 ++-- 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/matsim/src/main/java/org/matsim/core/router/speedy/SpeedyALT.java b/matsim/src/main/java/org/matsim/core/router/speedy/SpeedyALT.java index 47c2f16de86..62b5d21590e 100644 --- a/matsim/src/main/java/org/matsim/core/router/speedy/SpeedyALT.java +++ b/matsim/src/main/java/org/matsim/core/router/speedy/SpeedyALT.java @@ -91,6 +91,7 @@ public Path calcLeastCostPath(Node startNode, Node endNode, double startTime, Pe Arrays.fill(this.iterationIds, this.currentIteration); this.currentIteration = Integer.MIN_VALUE; } + boolean hasTurnRestrictions = this.graph.hasTurnRestrictions(); int startNodeIndex = startNode.getId().index(); int endNodeIndex = endNode.getId().index(); @@ -111,6 +112,11 @@ public Path calcLeastCostPath(Node startNode, Node endNode, double startTime, Pe foundEndNode = true; break; } + // if turn restrictions are used, we might be on a colored node, so check for the original node + if (hasTurnRestrictions && this.graph.getNode(nodeIdx).getId().index() == endNodeIndex) { + foundEndNode = true; + break; + } // ignore dead-ends int deadend = this.astarData.getNodeDeadend(nodeIdx); diff --git a/matsim/src/main/java/org/matsim/core/router/speedy/SpeedyDijkstra.java b/matsim/src/main/java/org/matsim/core/router/speedy/SpeedyDijkstra.java index 735a9795fcf..ec3eb1b3035 100644 --- a/matsim/src/main/java/org/matsim/core/router/speedy/SpeedyDijkstra.java +++ b/matsim/src/main/java/org/matsim/core/router/speedy/SpeedyDijkstra.java @@ -73,6 +73,7 @@ public Path calcLeastCostPath(Node startNode, Node endNode, double startTime, Pe this.currentIteration = Integer.MIN_VALUE; } + boolean hasTurnRestrictions = this.graph.hasTurnRestrictions(); int startNodeIndex = startNode.getId().index(); int endNodeIndex = endNode.getId().index(); @@ -88,6 +89,11 @@ public Path calcLeastCostPath(Node startNode, Node endNode, double startTime, Pe foundEndNode = true; break; } + // if turn restrictions are used, we might be on a colored node, so check for the original node + if (hasTurnRestrictions && this.graph.getNode(nodeIdx).getId().index() == endNodeIndex) { + foundEndNode = true; + break; + } double currTime = getTimeRaw(nodeIdx); if (Double.isInfinite(currTime)) { diff --git a/matsim/src/main/java/org/matsim/core/router/speedy/SpeedyGraph.java b/matsim/src/main/java/org/matsim/core/router/speedy/SpeedyGraph.java index e7cd69bcf3d..7666909ca01 100644 --- a/matsim/src/main/java/org/matsim/core/router/speedy/SpeedyGraph.java +++ b/matsim/src/main/java/org/matsim/core/router/speedy/SpeedyGraph.java @@ -54,14 +54,16 @@ public class SpeedyGraph { private final int[] linkData; private final Link[] links; private final Node[] nodes; + private final boolean hasTurnRestrictions; - SpeedyGraph(int[] nodeData, int[] linkData, Node[] nodes, Link[] links) { + SpeedyGraph(int[] nodeData, int[] linkData, Node[] nodes, Link[] links, boolean hasTurnRestrictions) { this.nodeData = nodeData; this.linkData = linkData; this.nodes = nodes; this.links = links; this.nodeCount = this.nodes.length; this.linkCount = this.links.length; + this.hasTurnRestrictions = hasTurnRestrictions; } public LinkIterator getOutLinkIterator() { @@ -80,6 +82,10 @@ Node getNode(int index) { return this.nodes[index]; } + boolean hasTurnRestrictions() { + return this.hasTurnRestrictions; + } + public interface LinkIterator { void reset(int nodeIdx); diff --git a/matsim/src/main/java/org/matsim/core/router/speedy/SpeedyGraphBuilder.java b/matsim/src/main/java/org/matsim/core/router/speedy/SpeedyGraphBuilder.java index 724343da24d..54f41ee1aa4 100644 --- a/matsim/src/main/java/org/matsim/core/router/speedy/SpeedyGraphBuilder.java +++ b/matsim/src/main/java/org/matsim/core/router/speedy/SpeedyGraphBuilder.java @@ -132,7 +132,7 @@ private SpeedyGraph buildWithTurnRestrictions(Network network) { addLink(link); } - return new SpeedyGraph(this.nodeData, this.linkData, this.nodes, this.links); + return new SpeedyGraph(this.nodeData, this.linkData, this.nodes, this.links, true); } private ColoredLink applyTurnRestriction(TurnRestrictionsContext context, Collection>> restrictions, Link startingLink) { @@ -314,7 +314,7 @@ private SpeedyGraph buildWithoutTurnRestrictions(Network network) { addLink(link); } - return new SpeedyGraph(this.nodeData, this.linkData, this.nodes, this.links); + return new SpeedyGraph(this.nodeData, this.linkData, this.nodes, this.links, false); } private void addLink(Link link) { From 06be1b0344abc35c30777536646b1d2577d113c8 Mon Sep 17 00:00:00 2001 From: rakow Date: Thu, 7 Nov 2024 09:32:21 +0100 Subject: [PATCH 17/53] improve consistency checks (#3547) --- .../VspConfigConsistencyCheckerImpl.java | 46 +++++++------------ 1 file changed, 16 insertions(+), 30 deletions(-) diff --git a/matsim/src/main/java/org/matsim/core/config/consistency/VspConfigConsistencyCheckerImpl.java b/matsim/src/main/java/org/matsim/core/config/consistency/VspConfigConsistencyCheckerImpl.java index 9fd9e5045b7..a7dba48bdb6 100644 --- a/matsim/src/main/java/org/matsim/core/config/consistency/VspConfigConsistencyCheckerImpl.java +++ b/matsim/src/main/java/org/matsim/core/config/consistency/VspConfigConsistencyCheckerImpl.java @@ -46,13 +46,7 @@ * */ public final class VspConfigConsistencyCheckerImpl implements ConfigConsistencyChecker { - // yyyy TODOS: - // VSP now regularly uses marg utls of travelling != null to fit distance distributions. There should be a switch to switch off the warnings. - - // VSP says that people < 18J should not use car, and implements that via car availability. How to handle that? - - // private static final Logger log = LogManager.getLogger(VspConfigConsistencyCheckerImpl.class); public VspConfigConsistencyCheckerImpl() { @@ -96,10 +90,6 @@ public void checkConsistency(Config config) { problem = checkLocationChoiceConfigGroup( config, problem ); - // === mode choice: - - problem = checkModeChoiceConfigGroup( config, lvl, problem ); - // === planCalcScore: problem = checkPlanCalcScoreConfigGroup( config, lvl, problem ); @@ -116,10 +106,6 @@ public void checkConsistency(Config config) { problem = checkQsimConfigGroup( config, lvl, problem ); - // === subtour mode choice: - - problem = checkSubtourModeChoiceConfigGroup( config, lvl, problem ); - // === strategy: problem = checkStrategyConfigGroup( config, lvl, problem ); @@ -157,20 +143,20 @@ public void checkConsistency(Config config) { } } - private boolean checkSubtourModeChoiceConfigGroup( Config config, Level lvl, boolean problem ){ - if ( config.subtourModeChoice().considerCarAvailability() ) { -// problem = true; - log.log( lvl, "you are considering car abailability; vsp config is not doing that. Instead, we are using a daily monetary constant for car."); - } - return problem; - } - private boolean checkModeChoiceConfigGroup( Config config, Level lvl, boolean problem ){ - if ( !config.changeMode().getIgnoreCarAvailability() ) { -// problem = true; - log.log( lvl, "you are considering car abailability; vsp config is not doing that. Instead, we are using a daily monetary constant for car."); - } - return problem; - } +// private boolean checkSubtourModeChoiceConfigGroup( Config config, Level lvl, boolean problem ){ +// if ( config.subtourModeChoice().considerCarAvailability() ) { +//// problem = true; +// log.log( lvl, "you are considering car abailability; vsp config is not doing that. Instead, we are using a daily monetary constant for car."); +// } +// return problem; +// } +// private boolean checkModeChoiceConfigGroup( Config config, Level lvl, boolean problem ){ +// if ( !config.changeMode().getIgnoreCarAvailability() ) { +//// problem = true; +// log.log( lvl, "you are considering car abailability; vsp config is not doing that. Instead, we are using a daily monetary constant for car."); +// } +// return problem; +// } private static boolean checkGlobalConfigGroup( Config config, Level lvl, boolean problem ){ if ( config.global().isInsistingOnDeprecatedConfigVersion() ) { problem = true ; @@ -263,7 +249,7 @@ private static boolean checkQsimConfigGroup( Config config, Level lvl, boolean p if ( config.qsim().getVehiclesSource()==VehiclesSource.defaultVehicle ) { log.log( lvl, "found qsim.vehiclesSource=defaultVehicle; vsp should use one of the other settings or talk to kai"); } - if ( config.qsim().getLinkDynamics() != QSimConfigGroup.LinkDynamics.PassingQ ) { + if ( config.qsim().getLinkDynamics() != QSimConfigGroup.LinkDynamics.PassingQ && config.qsim().getMainModes().contains(TransportMode.bike) ) { log.log( lvl, "found qsim.linkDynamics=" + config.qsim().getLinkDynamics() + "; vsp should use PassingQ or talk to kai"); } @@ -428,7 +414,7 @@ private static boolean checkPlanCalcScoreConfigGroup( Config config, Level lvl, // added may'23 for ( ModeParams params : config.scoring().getModes().values() ){ if ( config.vspExperimental().getCheckingOfMarginalUtilityOfTravellng()== CheckingOfMarginalUtilityOfTravellng.allZero ){ - if( params.getMarginalUtilityOfTraveling() != 0. ){ + if( params.getMarginalUtilityOfTraveling() != 0. && !params.getMode().equals( TransportMode.ride ) && !params.getMode().equals( TransportMode.bike ) ){ log.log( lvl, "You are setting the marginal utility of traveling with mode " + params.getMode() + " to " + params.getMarginalUtilityOfTraveling() + ". VSP standard is to set this to zero. Please document carefully why you are using a value different from zero, e.g. by showing distance distributions." ); } From 2ddddaad667a8d59f7181f3a00eca357caabd3df Mon Sep 17 00:00:00 2001 From: Ricardo Ewert Date: Thu, 7 Nov 2024 10:55:28 +0100 Subject: [PATCH 18/53] add exception in certain situations --- .../GenerateSmallScaleCommercialTrafficDemand.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java index f25ab4df11f..071d9375c29 100644 --- a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java +++ b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java @@ -481,7 +481,8 @@ private void solveSeparatedVRPs(Scenario originalScenario) throws Exception { // Map the values to the new subcarriers for (Id oldCarrierId : carrierId2subCarrierIds.keySet()) { for (Id newCarrierId : carrierId2subCarrierIds.get(oldCarrierId)) { - carrierId2carrierAttributes.put(newCarrierId, carrierId2carrierAttributes.get(oldCarrierId)); + if (carrierId2carrierAttributes.putIfAbsent(newCarrierId, carrierId2carrierAttributes.get(oldCarrierId)) != null) + throw new Exception("CarrierAttributes already exist for the carrier " + newCarrierId.toString()); } } @@ -709,7 +710,8 @@ public void createCarriers(Scenario scenario, CarrierAttributes carrierAttributes = new CarrierAttributes(purpose, startZone, selectedStartCategory, modeORvehType, smallScaleCommercialTrafficType, vehicleDepots, odMatrixEntry); - carrierId2carrierAttributes.put(Id.create(carrierName, Carrier.class), carrierAttributes); + if(carrierId2carrierAttributes.putIfAbsent(Id.create(carrierName, Carrier.class), carrierAttributes) != null) + throw new RuntimeException("CarrierAttributes already exist for the carrier " + carrierName); createNewCarrierAndAddVehicleTypes( scenario, carrierName, carrierAttributes, From 0ab49befc13b74a70b9b97c2d3e68a683213c15c Mon Sep 17 00:00:00 2001 From: schlenther Date: Thu, 7 Nov 2024 12:48:11 +0100 Subject: [PATCH 19/53] TODO comment --- .../src/main/java/org/matsim/contrib/noise/Grid.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/contribs/noise/src/main/java/org/matsim/contrib/noise/Grid.java b/contribs/noise/src/main/java/org/matsim/contrib/noise/Grid.java index 6815899be8a..ea63e77e905 100644 --- a/contribs/noise/src/main/java/org/matsim/contrib/noise/Grid.java +++ b/contribs/noise/src/main/java/org/matsim/contrib/noise/Grid.java @@ -271,6 +271,14 @@ private void setActivityCoord2NearestReceiverPointId () { for (Coord coord : consideredActivityCoordsForSpatialFunctionality) { // TODO maybe add a check here so we consider only the rp in the 9 surrounding cells? + + //TODO: ts, nov' 24: this might lead to problems, when we conduct noise analysis only in a (small) focus area of the scenario + // i.e. when the Grid is considerable smaller than the network (e.g. by setting a corresponding shp when run through simwrapper). + // The problem would be that the edge cells are then filled with activities from the outside. Maybe we should only consider activities that are inside the grid (+ maybe a small buffer)!? + // As consideredActivityCoordsForSpatialFunctionality is cleared after running this method, here, we can conduct the filtering, here. + // In other words: activityCoord2receiverPointId is all that needs to be changes in this class. + // However, we then need to account for null values when querying that map from PersonActivityTracker. + ReceiverPoint rp = qTree.getClosest(coord.getX(), coord.getY()); if(rp != null) { if(activityCoord2receiverPointId.put(coord, rp.getId()) != null){ From e1ee2469878c590b9d401b2642e48d28692f0883 Mon Sep 17 00:00:00 2001 From: Ricardo Ewert Date: Thu, 7 Nov 2024 13:11:18 +0100 Subject: [PATCH 20/53] update service time selection --- ...rateSmallScaleCommercialTrafficDemand.java | 45 +++++++++++-------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java index 071d9375c29..4ec1f9a0395 100644 --- a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java +++ b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java @@ -680,14 +680,26 @@ public void createCarriers(Scenario scenario, vehicleTypes.add(possibleVehicleType); } - // find a (random) start category with existing employees in this zone Collections.shuffle(odMatrixEntry.possibleStartCategories, rnd); String selectedStartCategory = odMatrixEntry.possibleStartCategories.getFirst(); + // Find a (random) start category with existing employees in this zone + // we start with count = 1 because the first category is already selected, and if this category has employees, we can use it. + // Otherwise, we have to find another category. for (int count = 1; resultingDataPerZone.get(startZone).getDouble(selectedStartCategory) == 0; count++) { - if (count <= odMatrixEntry.possibleStartCategories.size()) - selectedStartCategory = odMatrixEntry.possibleStartCategories.get(rnd.nextInt(odMatrixEntry.possibleStartCategories.size())); - else + if (count < odMatrixEntry.possibleStartCategories.size()) + selectedStartCategory = odMatrixEntry.possibleStartCategories.get(count); + else { + // if no possible start category with employees is found, take a random category of the stop categories, + // the reason that no start category with employees is found is that traffic volume for employees in general is created, + // so that it is possible that we have traffic, although we have no employees in the given start category. + // That's why we exclude Inhabitants as a possible start category. selectedStartCategory = odMatrixEntry.possibleStopCategories.get(rnd.nextInt(odMatrixEntry.possibleStopCategories.size())); + if (selectedStartCategory.equals("Inhabitants")) + selectedStartCategory = odMatrixEntry.possibleStopCategories.get(rnd.nextInt(odMatrixEntry.possibleStopCategories.size())); + if (resultingDataPerZone.get(startZone).getDouble(selectedStartCategory) > 0) + log.warn("No possible start category with employees found for zone {}. Take a random category of the stop categories: {}. The possible start categories are: {}", + startZone, selectedStartCategory, odMatrixEntry.possibleStartCategories); + } } // Generate carrierName @@ -746,20 +758,10 @@ private void createServices(Carrier newCarrier, CarrierAttributes carrierAttribu while (resultingDataPerZone.get(stopZone).getDouble(selectedStopCategory) == 0) selectedStopCategory = carrierAttributes.odMatrixEntry.possibleStopCategories.get(rnd.nextInt(carrierAttributes.odMatrixEntry.possibleStopCategories.size())); for (int i = 0; i < numberOfJobs; i++) { - int serviceTimePerStop; - if (carrierAttributes.selectedStartCategory.equals("Inhabitants")){ - CarrierAttributes inhabitantAttributes = new CarrierAttributes(carrierAttributes.purpose, carrierAttributes.startZone, - carrierAttributes.odMatrixEntry.possibleStartCategories.getFirst(), carrierAttributes.modeORvehType, - carrierAttributes.smallScaleCommercialTrafficType, carrierAttributes.vehicleDepots, carrierAttributes.odMatrixEntry); - serviceTimePerStop = getServiceTimePerStop(newCarrier, inhabitantAttributes, 0); - - } - else { - serviceTimePerStop = getServiceTimePerStop(newCarrier, carrierAttributes, 0); - } + // additionalTravelBufferPerIterationInMinutes is only used for recalculation of the service time if a carrier solution could not handle all services + int serviceTimePerStop = getServiceTimePerStop(newCarrier, carrierAttributes, 0); - TimeWindow serviceTimeWindow = TimeWindow.newInstance(0, - 36 * 3600); // extended time window, so that late tours can handle it + TimeWindow serviceTimeWindow = TimeWindow.newInstance(0, 36 * 3600); // extended time window, so that late tours can handle it createService(newCarrier, carrierAttributes.vehicleDepots, selectedStopCategory, stopZone, serviceTimePerStop, serviceTimeWindow); } } @@ -776,10 +778,15 @@ private void createServices(Carrier newCarrier, CarrierAttributes carrierAttribu public Integer getServiceTimePerStop(Carrier carrier, GenerateSmallScaleCommercialTrafficDemand.CarrierAttributes carrierAttributes, int additionalTravelBufferPerIterationInMinutes) { GenerateSmallScaleCommercialTrafficDemand.ServiceDurationPerCategoryKey key; + // we use the start category for the service time selection because the start category represents the employees if (carrierAttributes.smallScaleCommercialTrafficType().equals( - GenerateSmallScaleCommercialTrafficDemand.SmallScaleCommercialTrafficType.commercialPersonTraffic.toString())) - key = GenerateSmallScaleCommercialTrafficDemand.makeServiceDurationPerCategoryKey(carrierAttributes.selectedStartCategory(), null, + GenerateSmallScaleCommercialTrafficDemand.SmallScaleCommercialTrafficType.commercialPersonTraffic.toString())) { + if (!carrierAttributes.odMatrixEntry().possibleStartCategories.contains(carrierAttributes.selectedStartCategory())) + key = GenerateSmallScaleCommercialTrafficDemand.makeServiceDurationPerCategoryKey(carrierAttributes.odMatrixEntry().possibleStartCategories.get(rnd.nextInt(carrierAttributes.odMatrixEntry().possibleStartCategories.size())), null, carrierAttributes.smallScaleCommercialTrafficType()); + else + key = GenerateSmallScaleCommercialTrafficDemand.makeServiceDurationPerCategoryKey(carrierAttributes.selectedStartCategory(), null, carrierAttributes.smallScaleCommercialTrafficType()); + } else if (carrierAttributes.smallScaleCommercialTrafficType().equals( GenerateSmallScaleCommercialTrafficDemand.SmallScaleCommercialTrafficType.goodsTraffic.toString())) { key = GenerateSmallScaleCommercialTrafficDemand.makeServiceDurationPerCategoryKey(carrierAttributes.selectedStartCategory(), From a55fcb505a3b673c4685b9af88769123b3eef243 Mon Sep 17 00:00:00 2001 From: Ricardo Ewert Date: Thu, 7 Nov 2024 13:11:31 +0100 Subject: [PATCH 21/53] formatting --- .../GenerateSmallScaleCommercialTrafficDemand.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java index 4ec1f9a0395..094c2f753f4 100644 --- a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java +++ b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java @@ -725,9 +725,7 @@ public void createCarriers(Scenario scenario, if(carrierId2carrierAttributes.putIfAbsent(Id.create(carrierName, Carrier.class), carrierAttributes) != null) throw new RuntimeException("CarrierAttributes already exist for the carrier " + carrierName); - createNewCarrierAndAddVehicleTypes( - scenario, carrierName, carrierAttributes, - vehicleTypes, numberOfDepots, fleetSize, + createNewCarrierAndAddVehicleTypes(scenario, carrierName, carrierAttributes, vehicleTypes, numberOfDepots, fleetSize, fixedNumberOfVehiclePerTypeAndLocation); // Now Create services for this carrier From 9cb20696abf3deae82a5dd732742090840522ff4 Mon Sep 17 00:00:00 2001 From: rakow Date: Thu, 7 Nov 2024 14:20:14 +0100 Subject: [PATCH 22/53] Inline xml writing into Event class (#3539) * put separate method for writing xml representation into event * inline writing of xml for most common attributes * fix activity end event * update comments --- .../emissions/events/EmissionEvent.java | 17 ++++ .../api/core/v01/events/ActivityEndEvent.java | 14 +++- .../core/v01/events/ActivityStartEvent.java | 16 +++- .../org/matsim/api/core/v01/events/Event.java | 66 +++++++++++++++ .../api/core/v01/events/LinkEnterEvent.java | 7 ++ .../api/core/v01/events/LinkLeaveEvent.java | 7 ++ .../core/v01/events/PersonArrivalEvent.java | 12 +++ .../core/v01/events/PersonDepartureEvent.java | 13 +++ .../v01/events/PersonEntersVehicleEvent.java | 7 ++ .../v01/events/PersonLeavesVehicleEvent.java | 7 ++ .../api/core/v01/events/PersonMoneyEvent.java | 21 +++++ .../api/core/v01/events/PersonScoreEvent.java | 11 +++ .../api/core/v01/events/PersonStuckEvent.java | 13 +++ .../v01/events/TransitDriverStartsEvent.java | 30 +++++-- .../core/v01/events/VehicleAbortsEvent.java | 6 ++ .../events/algorithms/EventWriterXML.java | 77 +++--------------- .../org/matsim/core/utils/io/XmlUtils.java | 80 ++++++++++++++++++- 17 files changed, 323 insertions(+), 81 deletions(-) diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/events/EmissionEvent.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/events/EmissionEvent.java index ae7c9c59e2a..180e79ca9fc 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/events/EmissionEvent.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/events/EmissionEvent.java @@ -25,6 +25,7 @@ import org.matsim.api.core.v01.events.Event; import org.matsim.api.core.v01.network.Link; import org.matsim.contrib.emissions.Pollutant; +import org.matsim.core.utils.io.XmlUtils; import org.matsim.vehicles.Vehicle; import java.util.Map; @@ -67,4 +68,20 @@ public Map getAttributes() { } return attributes; } + + @Override + public void writeAsXML(StringBuilder out) { + // Writes common attributes + writeXMLStart(out); + + XmlUtils.writeEncodedAttributeKeyValue(out, ATTRIBUTE_LINK_ID, this.linkId.toString()); + XmlUtils.writeEncodedAttributeKeyValue(out, ATTRIBUTE_VEHICLE_ID, this.vehicleId.toString()); + + for (Map.Entry entry : emissions.entrySet()) { + out.append(entry.getKey().name()).append("=\""); + out.append((double) entry.getValue()).append("\" "); + } + + writeXMLEnd(out); + } } diff --git a/matsim/src/main/java/org/matsim/api/core/v01/events/ActivityEndEvent.java b/matsim/src/main/java/org/matsim/api/core/v01/events/ActivityEndEvent.java index 39e0e36bbac..76bc4427498 100644 --- a/matsim/src/main/java/org/matsim/api/core/v01/events/ActivityEndEvent.java +++ b/matsim/src/main/java/org/matsim/api/core/v01/events/ActivityEndEvent.java @@ -29,6 +29,8 @@ import org.matsim.api.core.v01.population.Person; import org.matsim.facilities.ActivityFacility; +import static org.matsim.core.utils.io.XmlUtils.writeEncodedAttributeKeyValue; + public final class ActivityEndEvent extends Event implements HasPersonId, HasLinkId, HasFacilityId, BasicLocation { public static final String EVENT_TYPE = "actend"; @@ -49,7 +51,7 @@ public ActivityEndEvent( final double time, final Id agentId, final Id agentId, final Id linkId, + public ActivityEndEvent(final double time, final Id agentId, final Id linkId, final Id facilityId, final String acttype, final Coord coord) { super(time); this.linkId = linkId; @@ -79,7 +81,7 @@ public String getActType() { @Override public Id getPersonId() { return this.personId; } - + @Override public Map getAttributes() { Map attr = super.getAttributes(); @@ -95,4 +97,12 @@ public void setCoord( Coord coord ) { // yy this is to retrofit the coordinate into existing events that don't have it. this.coord = coord; } + + @Override + public void writeAsXML(StringBuilder out) { + // Writes common attributes + writeXMLStart(out); + writeEncodedAttributeKeyValue(out, ATTRIBUTE_ACTTYPE, this.acttype); + writeXMLEnd(out); + } } diff --git a/matsim/src/main/java/org/matsim/api/core/v01/events/ActivityStartEvent.java b/matsim/src/main/java/org/matsim/api/core/v01/events/ActivityStartEvent.java index f58a5b9a506..b0786093572 100644 --- a/matsim/src/main/java/org/matsim/api/core/v01/events/ActivityStartEvent.java +++ b/matsim/src/main/java/org/matsim/api/core/v01/events/ActivityStartEvent.java @@ -20,8 +20,6 @@ package org.matsim.api.core.v01.events; -import java.util.Map; - import org.matsim.api.core.v01.BasicLocation; import org.matsim.api.core.v01.Coord; import org.matsim.api.core.v01.Id; @@ -29,6 +27,10 @@ import org.matsim.api.core.v01.population.Person; import org.matsim.facilities.ActivityFacility; +import java.util.Map; + +import static org.matsim.core.utils.io.XmlUtils.writeEncodedAttributeKeyValue; + public class ActivityStartEvent extends Event implements HasFacilityId, HasPersonId, HasLinkId, BasicLocation{ public static final String EVENT_TYPE = "actstart"; @@ -91,7 +93,7 @@ public String getActType() { @Override public Id getPersonId() { return this.personId; } - + @Override public Map getAttributes() { Map attr = super.getAttributes(); @@ -109,4 +111,12 @@ public void setCoord( Coord coord ) { // yy this is to retrofit the coordinate into existing events that don't have it. :-( kai, mar'20 this.coord = coord; } + + @Override + public void writeAsXML(StringBuilder out) { + // Writes common attributes + writeXMLStart(out); + writeEncodedAttributeKeyValue(out, ATTRIBUTE_ACTTYPE, this.acttype); + writeXMLEnd(out); + } } diff --git a/matsim/src/main/java/org/matsim/api/core/v01/events/Event.java b/matsim/src/main/java/org/matsim/api/core/v01/events/Event.java index 09852740b7a..c51a90610fe 100644 --- a/matsim/src/main/java/org/matsim/api/core/v01/events/Event.java +++ b/matsim/src/main/java/org/matsim/api/core/v01/events/Event.java @@ -24,6 +24,9 @@ import java.util.Map; import org.matsim.api.core.v01.BasicLocation; +import org.matsim.core.utils.io.XmlUtils; + +import static org.matsim.core.utils.io.XmlUtils.writeEncodedAttributeValue; public abstract class Event { @@ -105,6 +108,69 @@ public boolean equals(Object obj) { public int hashCode() { return getAttributes().hashCode(); // Two equal events must at least have the same attributes, so they will get the same hashCode like this. } + + + /** + * Write the start of the xml representation and some common attributes. This method should be called first by {@link #writeAsXML(StringBuilder)}. + */ + protected final void writeXMLStart(StringBuilder out) { + out.append("\t\n"); + } + + /** + * Write a xml representation of this event to the given writer. + * The implementation must write the whole xml element . Starting with \t and adding a newline at the end. + * + * The provided default implementation writes the whole element based on {@link #getAttributes()}. This is slow and should be overridden. + * The overriding implementation must *not* call the super method. + */ + public void writeAsXML(StringBuilder out) { + out.append("\t attr = getAttributes(); + for (Map.Entry entry : attr.entrySet()) { + out.append(entry.getKey()); + out.append("=\""); + out.append(XmlUtils.encodeAttributeValue(entry.getValue())); + out.append("\" "); + } + out.append(" />\n"); + } + } diff --git a/matsim/src/main/java/org/matsim/api/core/v01/events/LinkEnterEvent.java b/matsim/src/main/java/org/matsim/api/core/v01/events/LinkEnterEvent.java index 63250efa333..310521abc11 100644 --- a/matsim/src/main/java/org/matsim/api/core/v01/events/LinkEnterEvent.java +++ b/matsim/src/main/java/org/matsim/api/core/v01/events/LinkEnterEvent.java @@ -73,4 +73,11 @@ public Map getAttributes() { // linkId, vehicleId handled by superclass return atts; } + + @Override + public void writeAsXML(StringBuilder out) { + // Writes all common attributes + writeXMLStart(out); + writeXMLEnd(out); + } } diff --git a/matsim/src/main/java/org/matsim/api/core/v01/events/LinkLeaveEvent.java b/matsim/src/main/java/org/matsim/api/core/v01/events/LinkLeaveEvent.java index 06018363204..0491771b110 100644 --- a/matsim/src/main/java/org/matsim/api/core/v01/events/LinkLeaveEvent.java +++ b/matsim/src/main/java/org/matsim/api/core/v01/events/LinkLeaveEvent.java @@ -76,4 +76,11 @@ public Map getAttributes() { // linkId, vehicleId handled by superclass return atts; } + + @Override + public void writeAsXML(StringBuilder out) { + // Writes all common attributes + writeXMLStart(out); + writeXMLEnd(out); + } } diff --git a/matsim/src/main/java/org/matsim/api/core/v01/events/PersonArrivalEvent.java b/matsim/src/main/java/org/matsim/api/core/v01/events/PersonArrivalEvent.java index 6e947aaff11..9e45e10e7da 100644 --- a/matsim/src/main/java/org/matsim/api/core/v01/events/PersonArrivalEvent.java +++ b/matsim/src/main/java/org/matsim/api/core/v01/events/PersonArrivalEvent.java @@ -26,6 +26,8 @@ import org.matsim.api.core.v01.network.Link; import org.matsim.api.core.v01.population.Person; +import static org.matsim.core.utils.io.XmlUtils.writeEncodedAttributeKeyValue; + public class PersonArrivalEvent extends Event implements HasPersonId, HasLinkId { public static final String EVENT_TYPE = "arrival"; @@ -71,4 +73,14 @@ public Map getAttributes() { } return attr; } + + @Override + public void writeAsXML(StringBuilder out) { + // Writes all common attributes + writeXMLStart(out); + if (this.legMode != null) { + writeEncodedAttributeKeyValue(out, ATTRIBUTE_LEGMODE, this.legMode); + } + writeXMLEnd(out); + } } diff --git a/matsim/src/main/java/org/matsim/api/core/v01/events/PersonDepartureEvent.java b/matsim/src/main/java/org/matsim/api/core/v01/events/PersonDepartureEvent.java index 425d8ad4e78..d98e05e8708 100644 --- a/matsim/src/main/java/org/matsim/api/core/v01/events/PersonDepartureEvent.java +++ b/matsim/src/main/java/org/matsim/api/core/v01/events/PersonDepartureEvent.java @@ -25,6 +25,7 @@ import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; import org.matsim.api.core.v01.population.Person; +import org.matsim.core.utils.io.XmlUtils; public class PersonDepartureEvent extends Event implements HasPersonId, HasLinkId { @@ -82,4 +83,16 @@ public Map getAttributes() { } return attr; } + + @Override + public void writeAsXML(StringBuilder out) { + writeXMLStart(out); + if (this.legMode != null) { + XmlUtils.writeEncodedAttributeKeyValue(out, ATTRIBUTE_LEGMODE, this.legMode); + } + if (this.routingMode != null) { + XmlUtils.writeEncodedAttributeKeyValue(out, ATTRIBUTE_ROUTING_MODE, this.routingMode); + } + writeXMLEnd(out); + } } diff --git a/matsim/src/main/java/org/matsim/api/core/v01/events/PersonEntersVehicleEvent.java b/matsim/src/main/java/org/matsim/api/core/v01/events/PersonEntersVehicleEvent.java index a3e051f44c4..db694dff953 100644 --- a/matsim/src/main/java/org/matsim/api/core/v01/events/PersonEntersVehicleEvent.java +++ b/matsim/src/main/java/org/matsim/api/core/v01/events/PersonEntersVehicleEvent.java @@ -68,4 +68,11 @@ public Map getAttributes() { // personId, vehicleId handled by superclass return atts; } + + @Override + public void writeAsXML(StringBuilder out) { + // Writes all common attributes + writeXMLStart(out); + writeXMLEnd(out); + } } diff --git a/matsim/src/main/java/org/matsim/api/core/v01/events/PersonLeavesVehicleEvent.java b/matsim/src/main/java/org/matsim/api/core/v01/events/PersonLeavesVehicleEvent.java index 27a3b5b2bdd..3a2bad23e44 100644 --- a/matsim/src/main/java/org/matsim/api/core/v01/events/PersonLeavesVehicleEvent.java +++ b/matsim/src/main/java/org/matsim/api/core/v01/events/PersonLeavesVehicleEvent.java @@ -69,4 +69,11 @@ public Map getAttributes() { // personId, vehicleId handled by superclass return attrs; } + + @Override + public void writeAsXML(StringBuilder out) { + // Writes all common attributes + writeXMLStart(out); + writeXMLEnd(out); + } } diff --git a/matsim/src/main/java/org/matsim/api/core/v01/events/PersonMoneyEvent.java b/matsim/src/main/java/org/matsim/api/core/v01/events/PersonMoneyEvent.java index e61a8a85b32..1b08399d47f 100644 --- a/matsim/src/main/java/org/matsim/api/core/v01/events/PersonMoneyEvent.java +++ b/matsim/src/main/java/org/matsim/api/core/v01/events/PersonMoneyEvent.java @@ -25,6 +25,8 @@ import java.util.Map; +import static org.matsim.core.utils.io.XmlUtils.writeEncodedAttributeKeyValue; + /** * This event specifies that an agent has gained (or paid) some money. * Scoring functions should handle these Events by adding the amount somehow @@ -134,4 +136,23 @@ public Map getAttributes() { } return attr; } + + @Override + public void writeAsXML(StringBuilder out) { + // Writes all common attributes + writeXMLStart(out); + + out.append("amount=\"").append(this.amount).append("\" "); + if (this.purpose != null) { + writeEncodedAttributeKeyValue(out, ATTRIBUTE_PURPOSE, this.purpose); + } + if (this.transactionPartner != null) { + writeEncodedAttributeKeyValue(out, ATTRIBUTE_TRANSACTION_PARTNER, this.transactionPartner); + } + if (this.reference != null) { + writeEncodedAttributeKeyValue(out, ATTRIBUTE_REFERENCE, this.reference); + } + + writeXMLEnd(out); + } } diff --git a/matsim/src/main/java/org/matsim/api/core/v01/events/PersonScoreEvent.java b/matsim/src/main/java/org/matsim/api/core/v01/events/PersonScoreEvent.java index 96019b6242f..893769df004 100644 --- a/matsim/src/main/java/org/matsim/api/core/v01/events/PersonScoreEvent.java +++ b/matsim/src/main/java/org/matsim/api/core/v01/events/PersonScoreEvent.java @@ -20,6 +20,7 @@ import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.population.Person; +import org.matsim.core.utils.io.XmlUtils; import java.util.Map; @@ -75,4 +76,14 @@ public Map getAttributes() { } return attr; } + + @Override + public void writeAsXML(StringBuilder out) { + writeXMLStart(out); + out.append("amount=\"").append(this.amount).append("\" "); + if (this.kind != null) { + XmlUtils.writeEncodedAttributeKeyValue(out, ATTRIBUTE_KIND, this.kind); + } + writeXMLEnd(out); + } } diff --git a/matsim/src/main/java/org/matsim/api/core/v01/events/PersonStuckEvent.java b/matsim/src/main/java/org/matsim/api/core/v01/events/PersonStuckEvent.java index b2439dd8b96..2eca25c0eab 100644 --- a/matsim/src/main/java/org/matsim/api/core/v01/events/PersonStuckEvent.java +++ b/matsim/src/main/java/org/matsim/api/core/v01/events/PersonStuckEvent.java @@ -25,6 +25,7 @@ import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; import org.matsim.api.core.v01.population.Person; +import org.matsim.core.utils.io.XmlUtils; public class PersonStuckEvent extends Event implements HasPersonId, HasLinkId { @@ -71,4 +72,16 @@ public Map getAttributes() { } return attr; } + + @Override + public void writeAsXML(StringBuilder out) { + // Writes all common attributes + writeXMLStart(out); + + if (this.legMode != null) { + XmlUtils.writeEncodedAttributeKeyValue(out, ATTRIBUTE_LEGMODE, this.legMode); + } + + writeXMLEnd(out); + } } diff --git a/matsim/src/main/java/org/matsim/api/core/v01/events/TransitDriverStartsEvent.java b/matsim/src/main/java/org/matsim/api/core/v01/events/TransitDriverStartsEvent.java index f58b1536fa9..801b2ec44c4 100644 --- a/matsim/src/main/java/org/matsim/api/core/v01/events/TransitDriverStartsEvent.java +++ b/matsim/src/main/java/org/matsim/api/core/v01/events/TransitDriverStartsEvent.java @@ -23,6 +23,7 @@ import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.population.Person; +import org.matsim.core.utils.io.XmlUtils; import org.matsim.pt.transitSchedule.api.Departure; import org.matsim.pt.transitSchedule.api.TransitLine; import org.matsim.pt.transitSchedule.api.TransitRoute; @@ -45,7 +46,7 @@ public class TransitDriverStartsEvent extends Event { private final Id transitLineId; private final Id departureId; - public TransitDriverStartsEvent(final double time, final Id driverId, final Id vehicleId, + public TransitDriverStartsEvent(final double time, final Id driverId, final Id vehicleId, final Id transitLineId, final Id transitRouteId, final Id departureId) { super(time); this.driverId = driverId; @@ -54,23 +55,23 @@ public TransitDriverStartsEvent(final double time, final Id driverId, fi this.transitLineId = transitLineId; this.departureId = departureId; } - + public Id getDriverId() { return driverId; } - + public Id getVehicleId() { return vehicleId; } - + public Id getTransitRouteId() { return transitRouteId; } - + public Id getTransitLineId() { return transitLineId; } - + public Id getDepartureId() { return departureId; } @@ -79,7 +80,7 @@ public Id getDepartureId() { public String getEventType() { return EVENT_TYPE; } - + @Override public Map getAttributes() { Map atts = super.getAttributes(); @@ -90,4 +91,17 @@ public Map getAttributes() { atts.put(ATTRIBUTE_DEPARTURE_ID, this.getDepartureId().toString()); return atts; } -} \ No newline at end of file + + @Override + public void writeAsXML(StringBuilder out) { + writeXMLStart(out); + + XmlUtils.writeEncodedAttributeKeyValue(out, ATTRIBUTE_DRIVER_ID, this.getDriverId().toString()); + XmlUtils.writeEncodedAttributeKeyValue(out, ATTRIBUTE_VEHICLE_ID, this.getVehicleId().toString()); + XmlUtils.writeEncodedAttributeKeyValue(out, ATTRIBUTE_TRANSIT_LINE_ID, this.getTransitLineId().toString()); + XmlUtils.writeEncodedAttributeKeyValue(out, ATTRIBUTE_TRANSIT_ROUTE_ID, this.getTransitRouteId().toString()); + XmlUtils.writeEncodedAttributeKeyValue(out, ATTRIBUTE_DEPARTURE_ID, this.getDepartureId().toString()); + + writeXMLEnd(out); + } +} diff --git a/matsim/src/main/java/org/matsim/api/core/v01/events/VehicleAbortsEvent.java b/matsim/src/main/java/org/matsim/api/core/v01/events/VehicleAbortsEvent.java index a623a758bd0..ba0ec9bbeff 100644 --- a/matsim/src/main/java/org/matsim/api/core/v01/events/VehicleAbortsEvent.java +++ b/matsim/src/main/java/org/matsim/api/core/v01/events/VehicleAbortsEvent.java @@ -61,4 +61,10 @@ public Map getAttributes() { // linkId, vehicleId handled by superclass return atts; } + + @Override + public void writeAsXML(StringBuilder out) { + writeXMLStart(out); + writeXMLEnd(out); + } } diff --git a/matsim/src/main/java/org/matsim/core/events/algorithms/EventWriterXML.java b/matsim/src/main/java/org/matsim/core/events/algorithms/EventWriterXML.java index 54b731771e1..4b29ae4ac55 100644 --- a/matsim/src/main/java/org/matsim/core/events/algorithms/EventWriterXML.java +++ b/matsim/src/main/java/org/matsim/core/events/algorithms/EventWriterXML.java @@ -32,13 +32,17 @@ import java.io.OutputStreamWriter; import java.io.UncheckedIOException; import java.nio.charset.StandardCharsets; -import java.util.Map; public class EventWriterXML implements EventWriter, BasicEventHandler { private static final Logger LOG = LogManager.getLogger(EventWriterXML.class); private final BufferedWriter out; + /** + * Cache for StringBuilder instances to avoid creating a new one for each event. + */ + private final ThreadLocal stringBuilder = ThreadLocal.withInitial(StringBuilder::new); + public EventWriterXML(final String outfilename) { this.out = IOUtils.getBufferedWriter(outfilename); this.writeHeader(); @@ -83,73 +87,14 @@ public void reset(final int iter) { @Override public void handleEvent(final Event event) { try { - this.out.append("\t attr = event.getAttributes(); - for (Map.Entry entry : attr.entrySet()) { - this.out.append(entry.getKey()); - this.out.append("=\""); - this.out.append(encodeAttributeValue(entry.getValue())); - this.out.append("\" "); - } - this.out.append(" />\n"); - } catch (IOException e) { - LOG.error(e.getMessage(), e); - } - } + StringBuilder b = stringBuilder.get(); - // the following method was taken from MatsimXmlWriter in order to correctly encode attributes, but - // to forego the overhead of using the full MatsimXmlWriter. - /** - * Encodes the given string in such a way that it no longer contains - * characters that have a special meaning in xml. - * - * @see http://www.w3.org/International/questions/qa-escapes#use - * @param attributeValue - * @return String with some characters replaced by their xml-encoding. - */ - private String encodeAttributeValue(final String attributeValue) { - if (attributeValue == null) { - return null; - } - int len = attributeValue.length(); - boolean encode = false; - for (int pos = 0; pos < len; pos++) { - char ch = attributeValue.charAt(pos); - if (ch == '<') { - encode = true; - break; - } else if (ch == '>') { - encode = true; - break; - } else if (ch == '\"') { - encode = true; - break; - } else if (ch == '&') { - encode = true; - break; - } - } - if (encode) { - StringBuilder bf = new StringBuilder(attributeValue.length() + 30); - for (int pos = 0; pos < len; pos++) { - char ch = attributeValue.charAt(pos); - if (ch == '<') { - bf.append("<"); - } else if (ch == '>') { - bf.append(">"); - } else if (ch == '\"') { - bf.append("""); - } else if (ch == '&') { - bf.append("&"); - } else { - bf.append(ch); - } - } + b.setLength(0); + event.writeAsXML(b); + this.out.append(b); - return bf.toString(); + } catch (IOException e) { + LOG.error(e.getMessage(), e); } - return attributeValue; - } - } diff --git a/matsim/src/main/java/org/matsim/core/utils/io/XmlUtils.java b/matsim/src/main/java/org/matsim/core/utils/io/XmlUtils.java index 57fa2f0b63a..85df85a9fd5 100644 --- a/matsim/src/main/java/org/matsim/core/utils/io/XmlUtils.java +++ b/matsim/src/main/java/org/matsim/core/utils/io/XmlUtils.java @@ -39,12 +39,88 @@ private XmlUtils() { * @return String with some characters replaced by their xml-encoding. */ public static String encodeAttributeValue(final String attributeValue) { - if (attributeValue.contains("&") || attributeValue.contains("\"") || attributeValue.contains("<") || attributeValue.contains(">")) { - return attributeValue.replace("&", "&").replace("\"", """).replace("<", "<").replace(">", ">"); + if (attributeValue == null) { + return null; + } + int len = attributeValue.length(); + boolean encode = false; + for (int pos = 0; pos < len; pos++) { + char ch = attributeValue.charAt(pos); + if (ch == '<') { + encode = true; + break; + } else if (ch == '>') { + encode = true; + break; + } else if (ch == '\"') { + encode = true; + break; + } else if (ch == '&') { + encode = true; + break; + } + } + if (encode) { + StringBuilder bf = new StringBuilder(attributeValue.length() + 30); + for (int pos = 0; pos < len; pos++) { + char ch = attributeValue.charAt(pos); + if (ch == '<') { + bf.append("<"); + } else if (ch == '>') { + bf.append(">"); + } else if (ch == '\"') { + bf.append("""); + } else if (ch == '&') { + bf.append("&"); + } else { + bf.append(ch); + } + } + + return bf.toString(); } return attributeValue; } + /** + * Write encoded attribute value to the given StringBuilder. + * This is an optimized version of {@link #encodeAttributeValue(String)}, which does not create any intermediate objects. + */ + public static StringBuilder writeEncodedAttributeValue(StringBuilder out, String attributeValue) { + + if (attributeValue == null) { + // By convention, null values are written as "null" in the xml output. + out.append("null"); + return out; + } + + int len = attributeValue.length(); + + for (int pos = 0; pos < len; pos++) { + char ch = attributeValue.charAt(pos); + switch (ch) { + case '<' -> out.append("<"); + case '>' -> out.append(">"); + case '\"' -> out.append("""); + case '&' -> out.append("&"); + default -> out.append(ch); + }; + } + + return out; + } + + /** + * Helper function to write an attribute key-value pair to the given StringBuilder. + * Note, do not use this for primitive types as these don't need to be encoded and the {@link StringBuilder} has specialized methods fot these. + */ + public static StringBuilder writeEncodedAttributeKeyValue(StringBuilder out, String key, String value) { + out.append(key).append("=\""); + writeEncodedAttributeValue(out, value); + out.append("\" "); + return out; + } + public static String encodeContent(final String content) { if (content.contains("&") || content.contains("<") || content.contains(">")) { return content.replace("&", "&").replace("<", "<").replace(">", ">"); From 426bec15f24e3e5d9950037a74c072424004e98c Mon Sep 17 00:00:00 2001 From: rakow Date: Thu, 7 Nov 2024 15:23:28 +0100 Subject: [PATCH 23/53] Don't assume car network mode as default (#3532) * don't assume default network mode car * catch possible null ids * better error message if network mode is null * fix some tests for new network mode behaviour * add missing network modes in tests * update vehicleTypes * better error message * Fix emission test --------- Co-authored-by: Ricardo Ewert --- .../emissions/TestPositionEmissionModule.java | 2 +- .../carriers/CarrierVehicleTypeReaderV1.java | 4 ++++ .../carriers/CarrierVehicleTypeTest.java | 3 +++ .../minibus/hook/PVehiclesFactory.java | 18 ++++++++++-------- .../exampleServiceCarrier/vehicleTypes.xml.gz | Bin 464 -> 481 bytes .../vehicleTypes.xml.gz | Bin 464 -> 481 bytes .../vehicleTypes.xml | 9 +++++---- .../sample_emissionVehicles_v2.xml | 6 +++++- .../freight-chessboard-9x9/vehicleTypes.xml | 4 +++- .../org/matsim/vehicles/VehicleReaderV1.java | 5 +++++ .../java/org/matsim/vehicles/VehicleType.java | 15 +++++++++++++-- .../org/matsim/vehicles/VehicleUtils.java | 10 +++++++--- .../qnetsimengine/SpeedCalculatorTest.java | 4 ++-- 13 files changed, 58 insertions(+), 22 deletions(-) diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestPositionEmissionModule.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestPositionEmissionModule.java index a3059795499..1f0ccd3eaf5 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestPositionEmissionModule.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestPositionEmissionModule.java @@ -201,7 +201,7 @@ public void handleEvent(Event event) { } private VehicleType createVehicleType() { - VehicleType vehicleType = VehicleUtils.createVehicleType(Id.create("dieselCarFullSpecified", VehicleType.class)); + VehicleType vehicleType = VehicleUtils.createVehicleType(Id.create("dieselCarFullSpecified", VehicleType.class), TransportMode.car); EngineInformation engineInformation = vehicleType.getEngineInformation(); VehicleUtils.setHbefaVehicleCategory(engineInformation, "PASSENGER_CAR"); VehicleUtils.setHbefaTechnology(engineInformation, "diesel"); diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierVehicleTypeReaderV1.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierVehicleTypeReaderV1.java index 61718d49850..92e2bacc590 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierVehicleTypeReaderV1.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierVehicleTypeReaderV1.java @@ -24,6 +24,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.TransportMode; import org.matsim.core.gbl.Gbl; import org.matsim.core.utils.io.MatsimXmlParser; import org.matsim.vehicles.CostInformation; @@ -54,6 +55,9 @@ public void startTag( String name, Attributes attributes, Stack context if(name.equals("vehicleType")){ Id currentTypeId = Id.create( attributes.getValue( "id" ), VehicleType.class ); this.currentType = VehicleUtils.getFactory().createVehicleType( currentTypeId ) ; + // If no network mode is given, assume car, this is to be backwards compatible + // The v2 format will not make this assumption, and the network mode will be required + this.currentType.setNetworkMode(TransportMode.car); } if(name.equals("allowableWeight")){ // String weight = atts.getValue("weight"); diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierVehicleTypeTest.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierVehicleTypeTest.java index 24328872de2..a95fac8d1ec 100644 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierVehicleTypeTest.java +++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierVehicleTypeTest.java @@ -26,6 +26,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.TransportMode; import org.matsim.freight.carriers.CarrierVehicleTypes; import org.matsim.testcases.MatsimTestUtils; import org.matsim.vehicles.*; @@ -53,6 +54,7 @@ public void setUp() { VehicleCapacity vehicleCapacity = mediumType.getCapacity(); vehicleCapacity.setWeightInTons( 30 ); mediumType.setDescription( "Medium Vehicle" ).setMaximumVelocity( 13.89 ); + mediumType.setNetworkMode(TransportMode.truck); types = new CarrierVehicleTypes(); types.getVehicleTypes().put( mediumType.getId(), mediumType ); } @@ -77,6 +79,7 @@ public void setUp() { capacity.setWeightInTons( 16 ) ; // VehicleType smallType = CarriersUtils.CarrierVehicleTypeBuilder.newInstance( smallTypeId, mediumType ) smallType.setDescription( "Small Vehicle" ).setMaximumVelocity( 10.0 ) ; + smallType.setNetworkMode(TransportMode.car); types.getVehicleTypes().put( smallType.getId(), smallType); } } diff --git a/contribs/minibus/src/main/java/org/matsim/contrib/minibus/hook/PVehiclesFactory.java b/contribs/minibus/src/main/java/org/matsim/contrib/minibus/hook/PVehiclesFactory.java index cca689ac56c..7069b4c3b0a 100644 --- a/contribs/minibus/src/main/java/org/matsim/contrib/minibus/hook/PVehiclesFactory.java +++ b/contribs/minibus/src/main/java/org/matsim/contrib/minibus/hook/PVehiclesFactory.java @@ -22,6 +22,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.TransportMode; import org.matsim.contrib.minibus.PConfigGroup; import org.matsim.pt.transitSchedule.api.Departure; import org.matsim.pt.transitSchedule.api.TransitLine; @@ -31,15 +32,15 @@ /** * Generates vehicles for a whole transit schedule - * + * * @author aneumann * */ class PVehiclesFactory { - + @SuppressWarnings("unused") private final static Logger log = LogManager.getLogger(PVehiclesFactory.class); - + private final PConfigGroup pConfig; public PVehiclesFactory(PConfigGroup pConfig) { @@ -48,11 +49,11 @@ public PVehiclesFactory(PConfigGroup pConfig) { /** * Create vehicles for each departure of the given transit schedule. - * + * * @return Vehicles used by paratranit lines */ - public Vehicles createVehicles(TransitSchedule pTransitSchedule){ - Vehicles vehicles = VehicleUtils.createVehiclesContainer(); + public Vehicles createVehicles(TransitSchedule pTransitSchedule){ + Vehicles vehicles = VehicleUtils.createVehiclesContainer(); VehiclesFactory vehFactory = vehicles.getFactory(); VehicleType vehType = vehFactory.createVehicleType(Id.create(this.pConfig.getPIdentifier(), VehicleType.class)); // VehicleCapacity capacity = new VehicleCapacity(); @@ -61,11 +62,12 @@ public Vehicles createVehicles(TransitSchedule pTransitSchedule){ // vehType.setCapacity(capacity); vehType.setPcuEquivalents(this.pConfig.getPassengerCarEquivalents()); vehType.setMaximumVelocity(this.pConfig.getVehicleMaximumVelocity()); + vehType.setNetworkMode(TransportMode.car); VehicleUtils.setAccessTime(vehType, this.pConfig.getDelayPerBoardingPassenger()); VehicleUtils.setEgressTime(vehType, this.pConfig.getDelayPerAlightingPassenger()); VehicleUtils.setDoorOperationMode(vehType, this.pConfig.getDoorOperationMode()) ; vehicles.addVehicleType( vehType); - + for (TransitLine line : pTransitSchedule.getTransitLines().values()) { for (TransitRoute route : line.getRoutes().values()) { for (Departure departure : route.getDepartures().values()) { @@ -76,7 +78,7 @@ public Vehicles createVehicles(TransitSchedule pTransitSchedule){ } } } - + return vehicles; } } diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/existingModels/exampleServiceCarrier/vehicleTypes.xml.gz b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/existingModels/exampleServiceCarrier/vehicleTypes.xml.gz index e9f770072c4e13491f3d1e7b22fe04b5f0b1bf7e..1e5c09a053f5911d55b48f3c517e58e94df6191d 100644 GIT binary patch literal 481 zcmV<70UrJziwFn{+#qKJ0Cr_)X=7|f7gupA z0F9zjn|&_6Y#*bgxGU!KtiwvH8Xs_{jrI(7z>~)1qVm37B}w1+aU;FcO-y#5>~xJT zDSatkaI3-T-?077h`UbHtK{qYd7~<9WTcJr(kK-3S@?Kp<;Ko4DH+bbdJkUdCx0sW z)?LSGJh)P@(pmN{ieS^ox&|C%)7A)5DYC&5@C3d>_{$C$xnc}k#_TNWedR%s@m7Ba zLp>ZFx^aQU{jru7*7w_uZqEC*r$+rzQFbR$@DpSuI%Rbm=8Ah58{q9x9kOK78lg(IQfYqzhs=YsBp|$H zu^Q4nY`Q#eH|Tq^hc%T5lmA>OX-7zwOk5}~m{NzwykyGQ_@}14#gpaY Xf+dUpVaYtZkfq`WDSWpuK?DE*(@OKc literal 464 zcmV;>0Wba^iwFo8y%b9-;-{>!IM%6-()=8rm>>?`| zpcbZ6FQpZpj1GEiy2o3LPD`<^*qLrSJ z&&7o_jljp#Wla}G-tSpOUr^TQgq2;Wt8O7Cz}ua8D)XaMlnUN)A^jd4(jMd`2H`Km z*?t|j~P0GU9hhO87@DR8|NR6NMR#KtiMszQQ;lmQ^%_y2k}3)L?3!w zXV>4;=}UNpbaA2}Z81A^FY_bB>I88ce(Dr)OnfTwIl!~&3Et`1yh(Y&1=T;=`87BD G0{{S~3gk2Z diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/existingModels/exampleShipmentCarrier/vehicleTypes.xml.gz b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/existingModels/exampleShipmentCarrier/vehicleTypes.xml.gz index e9f770072c4e13491f3d1e7b22fe04b5f0b1bf7e..b110aa96838b29814f48bb865a2b7dab2a10f81b 100644 GIT binary patch literal 481 zcmV<70UrJziwFoI+#qKJ0Cr_)X=7|f7gupA z0F9zjn|&_6Y#*bgxGU!KtiwvH8Xs_{jrI(7z>~)1qVm37B}w1+aU;FcO-y#5>~xJT zDSatkaI3-T-?077h`UbHtK{qYd7~<9WTcJr(kK-3S@?Kp<;Ko4DH+bbdJkUdCx0sW z)?LSGJh)P@(pmN{ieS^ox&|C%)7A)5DYC&5@C3d>_{$C$xnc}k#_TNWedR%s@m7Ba zLp>ZFx^aQU{jru7*7w_uZqEC*r$+rzQFbR$@DpSuI%Rbm=8Ah58{q9x9kOK78lg(IQfYqzhs=YsBp|$H zu^Q4nY`Q#eH|Tq^hc%T5lmA>OX-7zwOk5}~m{NzwykyGQ_@}14#gpaY Xf+dUpVaYtZkfq`WDSWpuK?DE*{7CcE literal 464 zcmV;>0Wba^iwFo8y%b9-;-{>!IM%6-()=8rm>>?`| zpcbZ6FQpZpj1GEiy2o3LPD`<^*qLrSJ z&&7o_jljp#Wla}G-tSpOUr^TQgq2;Wt8O7Cz}ua8D)XaMlnUN)A^jd4(jMd`2H`Km z*?t|j~P0GU9hhO87@DR8|NR6NMR#KtiMszQQ;lmQ^%_y2k}3)L?3!w zXV>4;=}UNpbaA2}Z81A^FY_bB>I88ce(Dr)OnfTwIl!~&3Et`1yh(Y&1=T;=`87BD G0{{S~3gk2Z diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/vehicleTypes.xml b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/vehicleTypes.xml index efe44ed5710..48a47d32b8b 100644 --- a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/vehicleTypes.xml +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/vehicleTypes.xml @@ -146,7 +146,7 @@ - + Heavy Vehicle 26t @@ -167,7 +167,7 @@ - + Heavy Vehicle 40t @@ -187,7 +187,7 @@ - + @@ -226,5 +226,6 @@ + - \ No newline at end of file + diff --git a/examples/scenarios/emissions-sampleScenario/testv2_Vehv2/sample_emissionVehicles_v2.xml b/examples/scenarios/emissions-sampleScenario/testv2_Vehv2/sample_emissionVehicles_v2.xml index 566a49585bd..36079e8d101 100644 --- a/examples/scenarios/emissions-sampleScenario/testv2_Vehv2/sample_emissionVehicles_v2.xml +++ b/examples/scenarios/emissions-sampleScenario/testv2_Vehv2/sample_emissionVehicles_v2.xml @@ -14,6 +14,7 @@ average + @@ -27,6 +28,7 @@ PC-P-Euro-1 + @@ -40,6 +42,7 @@ PC-D-Euro-3 + @@ -56,6 +59,7 @@ average + @@ -66,4 +70,4 @@ - \ No newline at end of file + diff --git a/examples/scenarios/freight-chessboard-9x9/vehicleTypes.xml b/examples/scenarios/freight-chessboard-9x9/vehicleTypes.xml index 27a7d8e1255..df4c6c7c95f 100644 --- a/examples/scenarios/freight-chessboard-9x9/vehicleTypes.xml +++ b/examples/scenarios/freight-chessboard-9x9/vehicleTypes.xml @@ -10,11 +10,13 @@ A heavy truck + A light truck + - \ No newline at end of file + diff --git a/matsim/src/main/java/org/matsim/vehicles/VehicleReaderV1.java b/matsim/src/main/java/org/matsim/vehicles/VehicleReaderV1.java index 697958b0fd6..b2847dc404e 100644 --- a/matsim/src/main/java/org/matsim/vehicles/VehicleReaderV1.java +++ b/matsim/src/main/java/org/matsim/vehicles/VehicleReaderV1.java @@ -3,6 +3,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.TransportMode; import org.matsim.core.utils.io.MatsimXmlParser; import org.xml.sax.Attributes; @@ -38,6 +39,10 @@ public void endTag( final String name, final String content, final Stack public void startTag( final String name, final Attributes atts, final Stack context ){ if( VehicleSchemaV1Names.VEHICLETYPE.equalsIgnoreCase( name ) ){ this.currentVehType = this.builder.createVehicleType( Id.create( atts.getValue( VehicleSchemaV1Names.ID ), VehicleType.class ) ); + // In the old format there is no network mode, and everything was basically a car. + // Vehicle type does not contain a default network mode anymore, therefore we need to set it here. + this.currentVehType.setNetworkMode( TransportMode.car ); + } else if( VehicleSchemaV1Names.LENGTH.equalsIgnoreCase( name ) ){ this.currentVehType.setLength( Double.parseDouble( atts.getValue( VehicleSchemaV1Names.METER ) ) ); } else if( VehicleSchemaV1Names.WIDTH.equalsIgnoreCase( name ) ){ diff --git a/matsim/src/main/java/org/matsim/vehicles/VehicleType.java b/matsim/src/main/java/org/matsim/vehicles/VehicleType.java index 9aef2a705e1..512705d4f0d 100644 --- a/matsim/src/main/java/org/matsim/vehicles/VehicleType.java +++ b/matsim/src/main/java/org/matsim/vehicles/VehicleType.java @@ -26,6 +26,8 @@ import org.matsim.utils.objectattributes.attributable.Attributes; import org.matsim.utils.objectattributes.attributable.AttributesImpl; +import java.util.Objects; + /** * @author dgrether */ @@ -46,13 +48,22 @@ public final class VehicleType implements Attributable, Identifiable id; private final Attributes attributes = new AttributesImpl(); VehicleType( Id typeId ) { this.id = typeId; + // For car typ default network mode is assumed, for others it needs to be set explicitly. + if (typeId != null && Objects.equals(typeId.toString(), TransportMode.car)) + this.networkMode = TransportMode.car; + } + + VehicleType(Id typeId, String networkMode) { + this.id = typeId; + this.networkMode = networkMode; } + public final String getDescription() { return description; } @@ -114,7 +125,7 @@ public final CostInformation getCostInformation() { return costInformation; } public final String getNetworkMode() { - return networkMode; + return Objects.requireNonNull(networkMode, () -> "Network mode not set for vehicle type %s. Network mode needs to be set explicitly for non car modes. You can do this in XML by adding \t\n".formatted(id, id)); } public final VehicleType setNetworkMode( String networkMode ) { this.networkMode = networkMode; diff --git a/matsim/src/main/java/org/matsim/vehicles/VehicleUtils.java b/matsim/src/main/java/org/matsim/vehicles/VehicleUtils.java index aac3e537da9..b5908ff38c1 100644 --- a/matsim/src/main/java/org/matsim/vehicles/VehicleUtils.java +++ b/matsim/src/main/java/org/matsim/vehicles/VehicleUtils.java @@ -64,6 +64,10 @@ public static VehicleType createVehicleType( Id typeId ){ return new VehicleType( typeId ); } + public static VehicleType createVehicleType( Id typeId, String networkMode){ + return new VehicleType( typeId, networkMode ); + } + public static VehiclesFactory getFactory() { return new VehiclesFactoryImpl(); } @@ -75,9 +79,9 @@ public static Vehicles createVehiclesContainer() { public static VehicleType createDefaultVehicleType() { VehicleType defaultVehicleType = VehicleUtils.getFactory() .createVehicleType(Id.create(DEFAULT_VEHICLE_TYPE_ID, VehicleType.class)); - + defaultVehicleType.getCapacity().setSeats(4); - + return defaultVehicleType; } @@ -434,7 +438,7 @@ public static void writeVehicles( Vehicles vehicles, String filename ) { new MatsimVehicleWriter( vehicles ).writeFile( filename ); } - + public static Id getInitialLinkId(Vehicle vehicle) { String attribute = (String) vehicle.getAttributes().getAttribute(INITIAL_LINK_ID); return attribute == null ? null : Id.createLinkId(attribute); diff --git a/matsim/src/test/java/org/matsim/core/mobsim/qsim/qnetsimengine/SpeedCalculatorTest.java b/matsim/src/test/java/org/matsim/core/mobsim/qsim/qnetsimengine/SpeedCalculatorTest.java index ed394e4bd46..a697a42a9a7 100644 --- a/matsim/src/test/java/org/matsim/core/mobsim/qsim/qnetsimengine/SpeedCalculatorTest.java +++ b/matsim/src/test/java/org/matsim/core/mobsim/qsim/qnetsimengine/SpeedCalculatorTest.java @@ -40,7 +40,7 @@ public class SpeedCalculatorTest{ @Test void limitedByVehicleSpeed() { Link link = createLinkWithNoGradientAndNoSpecialSurface(); - VehicleType type = VehicleUtils.createVehicleType(Id.create("no-bike", VehicleType.class ) ); + VehicleType type = VehicleUtils.createVehicleType(Id.create("no-bike", VehicleType.class ), TransportMode.car ); type.setMaximumVelocity(link.getFreespeed() / 2); // less than the link's freespeed QVehicle vehicle = new QVehicleImpl(VehicleUtils.createVehicle(Id.createVehicleId(1), type)); @@ -55,7 +55,7 @@ void limitedByLinkSpeed() { Link link = createLinkWithNoGradientAndNoSpecialSurface(); - VehicleType type = VehicleUtils.createVehicleType(Id.create("no-bike", VehicleType.class ) ); + VehicleType type = VehicleUtils.createVehicleType(Id.create("no-bike", VehicleType.class ), TransportMode.car ); type.setMaximumVelocity(link.getFreespeed() * 2); // _more_ than the link's freespeed QVehicle vehicle = new QVehicleImpl(VehicleUtils.createVehicle(Id.createVehicleId(1), type)); From 52efba4e1b374e3d4a94d72b8a9ee53ea4c08a56 Mon Sep 17 00:00:00 2001 From: GregorRyb <43266258+GregorRyb@users.noreply.github.com> Date: Thu, 7 Nov 2024 15:55:13 +0100 Subject: [PATCH 24/53] add qsim modes to default traffic dashboard (#3551) Co-authored-by: rakow --- .../java/org/matsim/simwrapper/DefaultDashboardProvider.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/DefaultDashboardProvider.java b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/DefaultDashboardProvider.java index a01674f4856..5cb80fec839 100644 --- a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/DefaultDashboardProvider.java +++ b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/DefaultDashboardProvider.java @@ -8,6 +8,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Set; /** * Default dashboards suited for every run. @@ -19,7 +20,7 @@ public List getDashboards(Config config, SimWrapper simWrapper) { List result = new ArrayList<>(List.of( new OverviewDashboard(), new TripDashboard(), - new TrafficDashboard() + new TrafficDashboard(Set.copyOf(config.qsim().getMainModes())) )); if (config.transit().isUseTransit()) { From 2aef5f6e7d1fc88617a71c946bb19a95679642e8 Mon Sep 17 00:00:00 2001 From: schlenther Date: Thu, 7 Nov 2024 17:02:17 +0100 Subject: [PATCH 25/53] compute noise damages only for activities that are inside the specified grid --- .../java/org/matsim/contrib/noise/Grid.java | 33 +++++++++++-------- .../contrib/noise/NoiseContextImpl.java | 4 +-- .../dashboard/NoiseDashboardTests.java | 17 +++++++++- 3 files changed, 37 insertions(+), 17 deletions(-) diff --git a/contribs/noise/src/main/java/org/matsim/contrib/noise/Grid.java b/contribs/noise/src/main/java/org/matsim/contrib/noise/Grid.java index ea63e77e905..48eb2951430 100644 --- a/contribs/noise/src/main/java/org/matsim/contrib/noise/Grid.java +++ b/contribs/noise/src/main/java/org/matsim/contrib/noise/Grid.java @@ -268,27 +268,32 @@ private void setActivityCoord2NearestReceiverPointId () { counter.printCounter(); counter = new Counter("compute nearest receiver-points #"); + Counter otherCounter = new Counter("activities outside grid #"); for (Coord coord : consideredActivityCoordsForSpatialFunctionality) { // TODO maybe add a check here so we consider only the rp in the 9 surrounding cells? - - //TODO: ts, nov' 24: this might lead to problems, when we conduct noise analysis only in a (small) focus area of the scenario - // i.e. when the Grid is considerable smaller than the network (e.g. by setting a corresponding shp when run through simwrapper). - // The problem would be that the edge cells are then filled with activities from the outside. Maybe we should only consider activities that are inside the grid (+ maybe a small buffer)!? - // As consideredActivityCoordsForSpatialFunctionality is cleared after running this method, here, we can conduct the filtering, here. - // In other words: activityCoord2receiverPointId is all that needs to be changes in this class. - // However, we then need to account for null values when querying that map from PersonActivityTracker. - - ReceiverPoint rp = qTree.getClosest(coord.getX(), coord.getY()); - if(rp != null) { - if(activityCoord2receiverPointId.put(coord, rp.getId()) != null){ - log.warn("this must not happen"); + // ts, nov' 24: ---> might be done by the following filtering (by grid) ?? + + // Filter activity coords that are within the quadTree. + // I do not know, why whe put a buffer around the grid when instantiating the QuadTree, above, but I'll keep it for now + // tschlenther, nov '24 + if (coord.getX() >= xCoordMin && coord.getX() <= xCoordMax && + coord.getY() >= yCoordMin && coord.getY() <= yCoordMax){ + + ReceiverPoint rp = qTree.getClosest(coord.getX(), coord.getY()); + if(rp != null) { + if(activityCoord2receiverPointId.put(coord, rp.getId()) != null){ + log.warn("this must not happen"); + } } - } - counter.incCounter(); + counter.incCounter(); + } else { + otherCounter.incCounter(); + } } counter.printCounter(); + otherCounter.printCounter(); } private void readReceiverPoints(String file, CoordinateTransformation ct) throws IOException { diff --git a/contribs/noise/src/main/java/org/matsim/contrib/noise/NoiseContextImpl.java b/contribs/noise/src/main/java/org/matsim/contrib/noise/NoiseContextImpl.java index d941615320a..bad61d3696c 100644 --- a/contribs/noise/src/main/java/org/matsim/contrib/noise/NoiseContextImpl.java +++ b/contribs/noise/src/main/java/org/matsim/contrib/noise/NoiseContextImpl.java @@ -201,9 +201,9 @@ private void checkConsistency() { || this.grid.getGridParams().getReceiverPointsGridMinX() != 0. || this.grid.getGridParams().getReceiverPointsGridMaxY() != 0. || this.grid.getGridParams().getReceiverPointsGridMinY() != 0.) { - log.warn("In order to keep track of the agent activities, the grid of receiver points should not be limited to a set of predefined coordinates." + log.warn("In order to keep track of ALL the agent activities, the grid of receiver points should not be limited to a set of predefined coordinates." + "For a grid covering all activity locations, set the minimum and maximum x/y parameters to 0.0. " - + "There will be more agents mapped to the receiver points at the edges. Only the inner receiver points should be used for analysis."); + + "Damages will be computed only for activities that are performed within the receiver point grid."); } if (this.grid.getGridParams().getReceiverPointsGridMinX() == 0. && this.grid.getGridParams().getReceiverPointsGridMinY() == 0. && this.grid.getGridParams().getReceiverPointsGridMaxX() == 0. && this.grid.getGridParams().getReceiverPointsGridMaxY() == 0.) { 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 a4ce705e001..178bfa9109f 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 @@ -1,5 +1,6 @@ package org.matsim.simwrapper.dashboard; +import com.opencsv.CSVReader; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -15,6 +16,7 @@ import org.matsim.testcases.MatsimTestUtils; +import java.io.FileReader; import java.net.URL; import java.nio.file.Path; @@ -51,6 +53,19 @@ void generate() { .isDirectoryContaining("glob:**damages_receiverPoint_per_day.avro") .isDirectoryContaining("glob:**noise_stats.csv"); - //TODO check content / values of the files + double totalDamages; + double totalImmissions; + try { + CSVReader reader = new CSVReader(new FileReader(utils.getOutputDirectory() + "analysis/noise/noise_stats.csv")); + reader.skip(1); + totalDamages = Double.parseDouble(reader.readNext()[1]); + totalImmissions = Double.parseDouble(reader.readNext()[1]); + } catch (Exception e) { + throw new RuntimeException(e); + } + + Assertions.assertThat(totalDamages == 3573114.25); + Assertions.assertThat( totalImmissions == 2.688); + } } From 5b9c39653cab24da72465567e68c64f5b9d28598 Mon Sep 17 00:00:00 2001 From: vsp-gleich Date: Fri, 8 Nov 2024 19:29:00 +0100 Subject: [PATCH 26/53] carry on stopAreaId to derived TransitStopFacilities and set stopAreaId to the original TransitStopFacility when not present yet (#3554) --- .../java/org/matsim/pt/utils/CreatePseudoNetwork.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/matsim/src/main/java/org/matsim/pt/utils/CreatePseudoNetwork.java b/matsim/src/main/java/org/matsim/pt/utils/CreatePseudoNetwork.java index 906c97396ee..104860e67bb 100644 --- a/matsim/src/main/java/org/matsim/pt/utils/CreatePseudoNetwork.java +++ b/matsim/src/main/java/org/matsim/pt/utils/CreatePseudoNetwork.java @@ -152,7 +152,14 @@ private Link getNetworkLink(final TransitRouteStop fromStop, final TransitRouteS } Id newId = Id.create(toFacility.getId().toString() + "." + Integer.toString(copies.size() + 1), TransitStopFacility.class); TransitStopFacility newFacility = this.schedule.getFactory().createTransitStopFacility(newId, toFacility.getCoord(), toFacility.getIsBlockingLane()); - newFacility.setStopAreaId(Id.create(toFacility.getId(), TransitStopArea.class)); + Id transitStopAreaId; + if (toFacility.getStopAreaId() == null) { + transitStopAreaId = Id.create(toFacility.getId(), TransitStopArea.class); + toFacility.setStopAreaId(transitStopAreaId); + } else { + transitStopAreaId = toFacility.getStopAreaId(); + } + newFacility.setStopAreaId(transitStopAreaId); newFacility.setLinkId(link.getId()); newFacility.setName(toFacility.getName()); copies.add(newFacility); From dfcee21fc4481eba3d5f61b23c6022cf281c1336 Mon Sep 17 00:00:00 2001 From: schlenther Date: Mon, 11 Nov 2024 16:26:35 +0100 Subject: [PATCH 27/53] defaults for networkModesToIgnore + consistency checks/warnings --- .../analysis/noise/NoiseAnalysis.java | 21 +++++------ .../contrib/noise/NoiseConfigGroup.java | 36 +++++++++++++++++-- 2 files changed, 45 insertions(+), 12 deletions(-) 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 a3f321c7f38..bac5eaadd7c 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 @@ -66,7 +66,7 @@ public class NoiseAnalysis implements MATSimAppCommand { @CommandLine.Option(names = "--consider-activities", split = ",", description = "Considered activities for noise calculation." + " Use asterisk ('*') for acttype prefixes, if all such acts shall be considered.", defaultValue = "home*,work*,educ*,leisure*") - private Set considerActivities; + private Set consideredActivities; @CommandLine.Option(names = "--noise-barrier", description = "Path to the noise barrier File", defaultValue = "") private String noiseBarrierFile; @@ -86,19 +86,20 @@ public Integer call() throws Exception { boolean overrideParameters = ! ConfigUtils.hasModule(config, NoiseConfigGroup.class); NoiseConfigGroup noiseParameters = ConfigUtils.addOrGetModule(config, NoiseConfigGroup.class); - if(overrideParameters){ + if (overrideParameters){ log.warn("no NoiseConfigGroup was configured before. Will set some standards. You should check the next lines in the log file and the output_config.xml!"); - noiseParameters.setConsideredActivitiesForReceiverPointGridArray(considerActivities.toArray(String[]::new)); - noiseParameters.setConsideredActivitiesForDamageCalculationArray(considerActivities.toArray(String[]::new)); + noiseParameters.setConsideredActivitiesForReceiverPointGridArray(consideredActivities.toArray(String[]::new)); + noiseParameters.setConsideredActivitiesForDamageCalculationArray(consideredActivities.toArray(String[]::new)); { - Set set = CollectionUtils.stringArrayToSet( new String[]{TransportMode.bike, TransportMode.walk, TransportMode.transit_walk, TransportMode.non_network_walk} ); - noiseParameters.setNetworkModesToIgnoreSet( set ); - } - { - String[] set = new String[]{"freight"}; - noiseParameters.setHgvIdPrefixesArray( set ); + //the default settings are now actually the same as what we 'override' here, but let's leave it here for clarity. + Set ignoredNetworkModes = CollectionUtils.stringArrayToSet( new String[]{TransportMode.bike, TransportMode.walk, TransportMode.transit_walk, TransportMode.non_network_walk} ); + noiseParameters.setNetworkModesToIgnoreSet( ignoredNetworkModes ); + + String[] hgvIdPrefixes = {"lkw", "truck", "freight"}; + noiseParameters.setHgvIdPrefixesArray( hgvIdPrefixes ); } + //use actual speed and not freespeed noiseParameters.setUseActualSpeedLevel(true); //use the valid speed range (recommended by IK) 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 06e793c85d9..c2c9bc8d039 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 @@ -26,6 +26,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; 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.core.config.Config; import org.matsim.core.config.ConfigGroup; @@ -134,9 +135,9 @@ public enum NoiseAllocationApproach { private NoiseAllocationApproach noiseAllocationApproach = NoiseAllocationApproach.AverageCost; private String[] hgvIdPrefixes = {"lkw", "truck", "freight"}; + private Set networkModesToIgnore = CollectionUtils.stringArrayToSet( new String[]{TransportMode.bike, TransportMode.walk, TransportMode.transit_walk, TransportMode.non_network_walk} ); private Set busIdIdentifier = new HashSet<>(); private Set> tunnelLinkIDs = new HashSet<>(); - private Set networkModesToIgnore = new HashSet<>(); private double noiseTollFactor = 1.0; @@ -209,7 +210,7 @@ public Map getComments() { comments.put(USE_DEM, "Set to 'true' if a DEM (digital elevation model) should be used for road gradients. Otherwise set to 'false'."); comments.put(DEM_FILE, "Path to the geoTiff file of the DEM."); - comments.put(NETWORK_MODES_TO_IGNORE, "Specifies the network modes to be excluded from the noise computation, e.g. 'bike'."); + comments.put(NETWORK_MODES_TO_IGNORE, "Specifies the network modes to be excluded from the noise computation. By default, the following modes are excluded: [bike, walk, transit_walk, non_network_walk]."); comments.put(NOISE_COMPUTATION_METHOD, "Specifies the computation method of different guidelines: " + Arrays.toString(NoiseComputationMethod.values())); @@ -313,6 +314,37 @@ private void checkNoiseParametersForConsistency(Config config) { this.considerNoiseBarriers = false; } } + + List walkAndBikeModes = List.of(TransportMode.bike, TransportMode.walk, TransportMode.transit_walk, TransportMode.non_network_walk); + String exclude = "["; + for (String mode : walkAndBikeModes){ + exclude += mode + ","; + } + exclude = exclude.substring(0, exclude.lastIndexOf(',')) + "]"; + String warning = "You should set networkModesToIgnore such that all of the standard walk and bike modes are included!" + + " These are " + exclude + "."; + if (this.networkModesToIgnore.isEmpty() || + ! this.networkModesToIgnore.containsAll(walkAndBikeModes)){ + boolean bikeOrWalkIsNetworkMode = config.routing().getNetworkModes().stream() + .filter(networkMode -> networkModesToIgnore.contains(networkMode)) + .findAny() + .isPresent(); + if (bikeOrWalkIsNetworkMode){ + //TODO: use enum for consistencyCheckLevel and replace all RunTimeExceptions thrown within this class. + throw new RuntimeException(warning + " You configured one of these modes as networkMode in config().routing.getNetworkModes()! This will lead to wrong results!" + + "Make sure ignore all network modes that do not model a car, a heavy-goods-vehicle (HGV) or a transit vehicle to be considered by the noise analysis!!! Will abort now..."); + } else { + log.warn( warning + + " Otherwise, your results will turn wrong as soon as you are routing these modes on the network (which luckily appears not to be the case in your current setup)."); + } + } + + Set defaultHGVIdPrefixes = Set.of("lkw", "truck", "freight"); + + if (! defaultHGVIdPrefixes.stream().allMatch(defaultPrefix -> + Arrays.stream(this.hgvIdPrefixes).anyMatch(prefix -> defaultPrefix.equals(prefix)))){ + log.warn("You are not considering all of [lkw, truck, freight] as HGV prefixes, which you should! Especially when you use scenarios created by VSP!!"); + } } // ######################################################################################################## From 504fb7eadd93ecd0474e9b79085b1fc32ccf375e Mon Sep 17 00:00:00 2001 From: rakow Date: Tue, 12 Nov 2024 10:20:31 +0100 Subject: [PATCH 28/53] Add more linktypes to the SUMO converter (#3559) * add more link types to the sumo converter * add osm types to hbefa mapping * update the link types --- .../prepare/network/params/ApplyNetworkParams.java | 5 ++++- .../java/org/matsim/contrib/emissions/OsmHbefaMapping.java | 2 ++ .../matsim/contrib/osm/networkReader/LinkProperties.java | 1 + .../java/org/matsim/contrib/sumo/SumoNetworkConverter.java | 6 +++++- 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/contribs/application/src/main/java/org/matsim/application/prepare/network/params/ApplyNetworkParams.java b/contribs/application/src/main/java/org/matsim/application/prepare/network/params/ApplyNetworkParams.java index 048e2fa81b7..120f9711ba6 100644 --- a/contribs/application/src/main/java/org/matsim/application/prepare/network/params/ApplyNetworkParams.java +++ b/contribs/application/src/main/java/org/matsim/application/prepare/network/params/ApplyNetworkParams.java @@ -257,7 +257,10 @@ private boolean applyFreeSpeed(Link link, Feature ft) { return false; link.setFreespeed(freeSpeed); - link.getAttributes().putAttribute("speed_factor", freeSpeed); + link.getAttributes().putAttribute( + "speed_factor", + BigDecimal.valueOf(freeSpeed).setScale(5, RoundingMode.HALF_EVEN).doubleValue() + ); return modified; } diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/OsmHbefaMapping.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/OsmHbefaMapping.java index ccce2492711..fb492e2bfd3 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/OsmHbefaMapping.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/OsmHbefaMapping.java @@ -85,6 +85,8 @@ public static OsmHbefaMapping build() { mapping.put("residential", new Hbefa("Access",30,50)); mapping.put("service", new Hbefa("Access",30,50)); mapping.put("living", new Hbefa("Access",30,50)); + mapping.put("cycleway", new Hbefa("Access",30,50)); + mapping.put("path", new Hbefa("Access",30,50)); return mapping; } diff --git a/contribs/osm/src/main/java/org/matsim/contrib/osm/networkReader/LinkProperties.java b/contribs/osm/src/main/java/org/matsim/contrib/osm/networkReader/LinkProperties.java index 41d2b302d37..6d8ddbac9c8 100644 --- a/contribs/osm/src/main/java/org/matsim/contrib/osm/networkReader/LinkProperties.java +++ b/contribs/osm/src/main/java/org/matsim/contrib/osm/networkReader/LinkProperties.java @@ -18,6 +18,7 @@ public class LinkProperties { public static final int LEVEL_UNCLASSIFIED = 6; public static final int LEVEL_RESIDENTIAL = 7; public static final int LEVEL_LIVING_STREET = 8; + public static final int LEVEL_PATH = 9; /** * Assume for links with max speed lower than 51km/h to be in urban areas. diff --git a/contribs/sumo/src/main/java/org/matsim/contrib/sumo/SumoNetworkConverter.java b/contribs/sumo/src/main/java/org/matsim/contrib/sumo/SumoNetworkConverter.java index b563e1325d4..b384b50d8d0 100644 --- a/contribs/sumo/src/main/java/org/matsim/contrib/sumo/SumoNetworkConverter.java +++ b/contribs/sumo/src/main/java/org/matsim/contrib/sumo/SumoNetworkConverter.java @@ -246,7 +246,11 @@ public SumoNetworkHandler convert(Network network) throws ParserConfigurationExc Map linkProperties = LinkProperties.createLinkProperties(); // add additional service tag - linkProperties.put(OsmTags.SERVICE, new LinkProperties(LinkProperties.LEVEL_LIVING_STREET, 1, 15 / 3.6, 450, false)); + linkProperties.put(OsmTags.SERVICE, new LinkProperties(LinkProperties.LEVEL_PATH, 1, 15 / 3.6, 450, false)); + linkProperties.put(OsmTags.PATH, new LinkProperties(LinkProperties.LEVEL_PATH, 1, 15 / 3.6, 300, false)); + + // This is for bikes + linkProperties.put(OsmTags.CYCLEWAY, new LinkProperties(LinkProperties.LEVEL_PATH, 1, 15 / 3.6, 300, false)); for (SumoNetworkHandler.Edge edge : sumoHandler.edges.values()) { From cc8d18d550502efe3fea5536ca9481e8b11475db Mon Sep 17 00:00:00 2001 From: Ricardo Ewert <60344745+rewertvsp@users.noreply.github.com> Date: Tue, 12 Nov 2024 16:25:15 +0100 Subject: [PATCH 29/53] add networkMode to defaultVehicleType (#3560) * add networkMode * use enum for mode selection --- matsim/src/main/java/org/matsim/vehicles/VehicleUtils.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/matsim/src/main/java/org/matsim/vehicles/VehicleUtils.java b/matsim/src/main/java/org/matsim/vehicles/VehicleUtils.java index b5908ff38c1..7c263b086e3 100644 --- a/matsim/src/main/java/org/matsim/vehicles/VehicleUtils.java +++ b/matsim/src/main/java/org/matsim/vehicles/VehicleUtils.java @@ -27,6 +27,7 @@ import org.apache.logging.log4j.Logger; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; import org.matsim.api.core.v01.network.Link; import org.matsim.api.core.v01.population.Person; import org.matsim.core.gbl.Gbl; @@ -81,7 +82,7 @@ public static VehicleType createDefaultVehicleType() { .createVehicleType(Id.create(DEFAULT_VEHICLE_TYPE_ID, VehicleType.class)); defaultVehicleType.getCapacity().setSeats(4); - + defaultVehicleType.setNetworkMode(TransportMode.car); return defaultVehicleType; } From f376874a3dbec98fb1cf8298db34526268a8fdca Mon Sep 17 00:00:00 2001 From: Ricardo Ewert Date: Tue, 12 Nov 2024 20:22:57 +0100 Subject: [PATCH 30/53] use fix output names for analysis --- .../analysis/RunFreightAnalysisEventBased.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/analysis/RunFreightAnalysisEventBased.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/analysis/RunFreightAnalysisEventBased.java index 751e96a2f45..7269a70ac7f 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/analysis/RunFreightAnalysisEventBased.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/analysis/RunFreightAnalysisEventBased.java @@ -38,6 +38,7 @@ import java.io.File; import java.io.IOException; +import java.nio.file.Path; //import static org.matsim.application.ApplicationUtils.globFile; @@ -80,13 +81,15 @@ public RunFreightAnalysisEventBased(String simOutputPath, String analysisOutputP // Path carriersPath = globFile(simOutputPath, "*output_carriers.*"); // Path carriersVehicleTypesPath = globFile(simOutputPath, "*output_carriersVehicleTypes.*"); -// this.EVENTS_PATH = simOutputPath.resolve("*output_events.xml.gz"); -// Path vehiclesPath = simOutputPath.resolve("*output_allVehicles.xml.gz"); -// Path networkPath = simOutputPath.resolve("*output_network.xml.gz"); -// Path carriersPath = simOutputPath.resolve("*output_carriers.xml.gz"); -// Path carriersVehicleTypesPath = simOutputPath.resolve("*output_carriersVehicleTypes.xml.gz"); -// -// createScenarioForFreightAnalysis(vehiclesPath, networkPath, carriersPath, carriersVehicleTypesPath, globalCrs); + // the better version with the globFile method is not available since there is a circular dependency between the modules application and freight + + this.EVENTS_PATH = Path.of(simOutputPath).resolve("output_events.xml.gz").toString(); + String vehiclesPath = Path.of(simOutputPath).resolve("output_allVehicles.xml.gz").toString(); + String networkPath = Path.of(simOutputPath).resolve("output_network.xml.gz").toString(); + String carriersPath = Path.of(simOutputPath).resolve("output_carriers.xml.gz").toString(); + String carriersVehicleTypesPath = Path.of(simOutputPath).resolve("output_carriersVehicleTypes.xml.gz").toString(); + + createScenarioForFreightAnalysis(vehiclesPath, networkPath, carriersPath, carriersVehicleTypesPath, globalCrs); } /** From 7b0d4654d345343b3229d94fa7525a9889c29125 Mon Sep 17 00:00:00 2001 From: vsp-gleich Date: Wed, 13 Nov 2024 10:06:31 +0100 Subject: [PATCH 31/53] Pt pax volumes into pt dashboard (#3552) * cleanup, remove features without tests * add pt passenger volumes to PublicTransitDashboard by running PtStop2StopAnalysis * clean up * add support for sampleScaleFactor, fix bug in link list introduced with last commit * small improvements, add some todos * simplified tests, use unfiltered avro network for pt * clean input string for mode filter --------- Co-authored-by: rakow Co-authored-by: rakow --- contribs/application/pom.xml | 2 +- .../analysis/pt/PublicTransitAnalysis.java | 105 ++++++++ .../prepare/network/CreateAvroNetwork.java | 5 +- .../dashboard/PublicTransitDashboard.java | 9 +- .../matsim/simwrapper/viz/TransitViewer.java | 17 +- .../simwrapper/dashboard/DashboardTests.java | 72 ++---- .../pt/stop2stop/PtStop2StopAnalysis.java | 225 +++++------------- .../pt/stop2stop/PtStop2StopAnalysis2Shp.java | 164 ------------- .../PtStop2StopAnalysisControlerListener.java | 3 +- .../pt/stop2stop/PtStop2StopAnalysisTest.java | 127 +++++----- 10 files changed, 276 insertions(+), 453 deletions(-) create mode 100644 contribs/application/src/main/java/org/matsim/application/analysis/pt/PublicTransitAnalysis.java delete mode 100644 matsim/src/main/java/org/matsim/analysis/pt/stop2stop/PtStop2StopAnalysis2Shp.java diff --git a/contribs/application/pom.xml b/contribs/application/pom.xml index 83422007fee..e8ec00d4800 100644 --- a/contribs/application/pom.xml +++ b/contribs/application/pom.xml @@ -87,7 +87,7 @@ com.github.matsim-org gtfs2matsim - 0bd5850fd6 + 47b0802a29 diff --git a/contribs/application/src/main/java/org/matsim/application/analysis/pt/PublicTransitAnalysis.java b/contribs/application/src/main/java/org/matsim/application/analysis/pt/PublicTransitAnalysis.java new file mode 100644 index 00000000000..e8785b30cda --- /dev/null +++ b/contribs/application/src/main/java/org/matsim/application/analysis/pt/PublicTransitAnalysis.java @@ -0,0 +1,105 @@ +/* *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2024 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.application.analysis.pt; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.matsim.analysis.pt.stop2stop.PtStop2StopAnalysis; +import org.matsim.api.core.v01.Scenario; +import org.matsim.application.ApplicationUtils; +import org.matsim.application.CommandSpec; +import org.matsim.application.MATSimAppCommand; +import org.matsim.application.analysis.emissions.AirPollutionAnalysis; +import org.matsim.application.options.InputOptions; +import org.matsim.application.options.OutputOptions; +import org.matsim.application.options.SampleOptions; +import org.matsim.core.api.experimental.events.EventsManager; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.events.EventsUtils; +import org.matsim.core.events.MatsimEventsReader; +import org.matsim.core.scenario.ScenarioUtils; +import picocli.CommandLine; + +@CommandLine.Command( + name = "transit", description = "General public transit analysis.", + mixinStandardHelpOptions = true, showDefaultValues = true +) +@CommandSpec(requireRunDirectory = true, + produces = { + "pt_pax_volumes.csv.gz", + } +) +public class PublicTransitAnalysis implements MATSimAppCommand { + + private static final Logger log = LogManager.getLogger(PublicTransitAnalysis.class); + + @CommandLine.Mixin + private final InputOptions input = InputOptions.ofCommand(PublicTransitAnalysis.class); + @CommandLine.Mixin + private final OutputOptions output = OutputOptions.ofCommand(PublicTransitAnalysis.class); + @CommandLine.Mixin + private SampleOptions sample; + + public static void main(String[] args) { + new PublicTransitAnalysis().execute(args); + } + + @Override + public Integer call() throws Exception { + + Config config = prepareConfig(); + Scenario scenario = ScenarioUtils.loadScenario(config); + EventsManager eventsManager = EventsUtils.createEventsManager(); + + String eventsFile = ApplicationUtils.matchInput("events", input.getRunDirectory()).toString(); + + PtStop2StopAnalysis ptStop2StopEventHandler = new PtStop2StopAnalysis(scenario.getTransitVehicles(), sample.getUpscaleFactor()); + eventsManager.addHandler(ptStop2StopEventHandler); + eventsManager.initProcessing(); + MatsimEventsReader matsimEventsReader = new MatsimEventsReader(eventsManager); + matsimEventsReader.readFile(eventsFile); + + log.info("Done reading the events file."); + log.info("Finish processing..."); + eventsManager.finishProcessing(); + + ptStop2StopEventHandler.writeStop2StopEntriesByDepartureCsv(output.getPath("pt_pax_volumes.csv.gz"), + ",", ";"); + + return 0; + } + + private Config prepareConfig() { + Config config = ConfigUtils.loadConfig(ApplicationUtils.matchInput("config.xml", input.getRunDirectory()).toAbsolutePath().toString()); + + config.vehicles().setVehiclesFile(ApplicationUtils.matchInput("vehicles", input.getRunDirectory()).toAbsolutePath().toString()); + config.network().setInputFile(ApplicationUtils.matchInput("network", input.getRunDirectory()).toAbsolutePath().toString()); + config.transit().setTransitScheduleFile(ApplicationUtils.matchInput("transitSchedule", input.getRunDirectory()).toAbsolutePath().toString()); + config.transit().setVehiclesFile(ApplicationUtils.matchInput("transitVehicles", input.getRunDirectory()).toAbsolutePath().toString()); + config.plans().setInputFile(null); + config.facilities().setInputFile(null); + config.eventsManager().setNumberOfThreads(null); + config.eventsManager().setEstimatedNumberOfEvents(null); + config.global().setNumberOfThreads(1); + + return config; + } +} diff --git a/contribs/application/src/main/java/org/matsim/application/prepare/network/CreateAvroNetwork.java b/contribs/application/src/main/java/org/matsim/application/prepare/network/CreateAvroNetwork.java index c94b17f9335..04f06a7df91 100644 --- a/contribs/application/src/main/java/org/matsim/application/prepare/network/CreateAvroNetwork.java +++ b/contribs/application/src/main/java/org/matsim/application/prepare/network/CreateAvroNetwork.java @@ -108,8 +108,11 @@ public Integer call() throws Exception { filter = filter.and(link -> p.matcher(link.getId().toString()).matches()); } + // Strings that could have been added in the list, due to command line parsing + modes.removeIf(m -> m.isBlank() || m.equals("none") || m.equals("\"") || m.equals("\"\"")); + // At least one of the specified modes needs to be contained - if (!modes.isEmpty() && !modes.equals(Set.of("none"))) { + if (!modes.isEmpty()) { filter = filter.and(link -> modes.stream().anyMatch(m -> link.getAllowedModes().contains(m))); } diff --git a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/PublicTransitDashboard.java b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/PublicTransitDashboard.java index fc902474591..50960fbaffe 100644 --- a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/PublicTransitDashboard.java +++ b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/PublicTransitDashboard.java @@ -1,5 +1,7 @@ package org.matsim.simwrapper.dashboard; +import org.matsim.application.analysis.pt.PublicTransitAnalysis; +import org.matsim.application.prepare.network.CreateAvroNetwork; import org.matsim.simwrapper.Dashboard; import org.matsim.simwrapper.Header; import org.matsim.simwrapper.Layout; @@ -34,8 +36,13 @@ public void configure(Header header, Layout layout) { viz.title = "Transit Viewer"; viz.height = 12d; viz.description = "Visualize the transit schedule."; - viz.network = "(*.)?output_network.xml.gz"; + + // Include a network that has not been filtered + viz.network = data.withContext("all").compute(CreateAvroNetwork.class, "network.avro", + "--mode-filter", "", "--shp", "none"); + viz.transitSchedule = data.output("(*.)?output_transitSchedule.xml.gz"); + viz.ptStop2stopFile = data.compute(PublicTransitAnalysis.class, "pt_pax_volumes.csv.gz"); if (!customRouteTypes.isEmpty()) viz.customRouteTypes = customRouteTypes; diff --git a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/viz/TransitViewer.java b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/viz/TransitViewer.java index 4f6622d2b11..bf32176b9ab 100644 --- a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/viz/TransitViewer.java +++ b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/viz/TransitViewer.java @@ -15,19 +15,17 @@ public class TransitViewer extends Viz { @JsonProperty(required = true) public String transitSchedule; + @JsonProperty + public String ptStop2stopFile; + public List customRouteTypes; public TransitViewer() { super("transit"); } - public CustomRouteType addCustomRouteType(String label, String color, boolean hide) { - CustomRouteType crt = new CustomRouteType(); - crt.label = label; - crt.color = color; - crt.hide = hide; - customRouteTypes.add(crt); - return crt; + public static CustomRouteType customRouteType(String label, String color) { + return new CustomRouteType(label, color); } public static class CustomRouteType { @@ -36,6 +34,11 @@ public static class CustomRouteType { public Boolean hide; Match match; + private CustomRouteType(String label, String color) { + this.label = label; + this.color = color; + } + public CustomRouteType addMatchTransportMode(String... transportMode) { if (match == null) match = new Match(); diff --git a/contribs/simwrapper/src/test/java/org/matsim/simwrapper/dashboard/DashboardTests.java b/contribs/simwrapper/src/test/java/org/matsim/simwrapper/dashboard/DashboardTests.java index 223b0fdaaec..e3e92fa87a7 100644 --- a/contribs/simwrapper/src/test/java/org/matsim/simwrapper/dashboard/DashboardTests.java +++ b/contribs/simwrapper/src/test/java/org/matsim/simwrapper/dashboard/DashboardTests.java @@ -29,7 +29,7 @@ public class DashboardTests { private void run(Dashboard... dashboards) { Config config = TestScenario.loadConfig(utils); - config.controller().setLastIteration(2); + config.controller().setLastIteration(1); SimWrapperConfigGroup group = ConfigUtils.addOrGetModule(config, SimWrapperConfigGroup.class); group.sampleSize = 0.001; @@ -43,41 +43,29 @@ private void run(Dashboard... dashboards) { controler.run(); } + @Test void defaults() { - Path out = Path.of(utils.getOutputDirectory(), "analysis", "population"); + Path out = Path.of(utils.getOutputDirectory(), "analysis"); run(); // Ensure default dashboards have been added Assertions.assertThat(out) - .isDirectoryContaining("glob:**stuck_agents.csv"); - } - - @Test - void stuckAgents() { - - Path out = Path.of(utils.getOutputDirectory(), "analysis", "population"); - - run(new StuckAgentDashboard()); - - Assertions.assertThat(out) - .isDirectoryContaining("glob:**stuck_agents.csv"); - - } - - @Test - void trip() { - - Path out = Path.of(utils.getOutputDirectory(), "analysis", "population"); - - run(new TripDashboard()); - Assertions.assertThat(out) - .isDirectoryContaining("glob:**trip_stats.csv") - .isDirectoryContaining("glob:**mode_share.csv") - .isDirectoryContaining("glob:**mode_share_per_purpose.csv") - .isDirectoryContaining("glob:**mode_shift.csv"); + // Stuck agents + .isDirectoryRecursivelyContaining("glob:**stuck_agents.csv") + // Trip stats + .isDirectoryRecursivelyContaining("glob:**trip_stats.csv") + .isDirectoryRecursivelyContaining("glob:**mode_share.csv") + .isDirectoryRecursivelyContaining("glob:**mode_share_per_purpose.csv") + .isDirectoryRecursivelyContaining("glob:**mode_shift.csv") + // Traffic stats + .isDirectoryRecursivelyContaining("glob:**traffic_stats_by_link_daily.csv") + .isDirectoryRecursivelyContaining("glob:**traffic_stats_by_road_type_and_hour.csv") + .isDirectoryRecursivelyContaining("glob:**traffic_stats_by_road_type_daily.csv") + // PT + .isDirectoryRecursivelyContaining("glob:**pt_pax_volumes.csv.gz"); } @Test @@ -129,21 +117,6 @@ void populationAttribute() { .isDirectoryContaining("glob:**total_agents.csv"); - } - - @Test - void traffic() { - - Path out = Path.of(utils.getOutputDirectory(), "analysis", "traffic"); - - run(new TrafficDashboard()); - - Assertions.assertThat(out) - .isDirectoryContaining("glob:**traffic_stats_by_link_daily.csv") - .isDirectoryContaining("glob:**traffic_stats_by_road_type_and_hour.csv") - .isDirectoryContaining("glob:**traffic_stats_by_road_type_daily.csv"); - - } @Test @@ -164,19 +137,20 @@ void ptCustom() { PublicTransitDashboard pt = new PublicTransitDashboard(); // bus - TransitViewer.CustomRouteType crt = new TransitViewer.CustomRouteType(); - crt.label = "Bus"; - crt.color = "#109192"; + TransitViewer.CustomRouteType crt = TransitViewer.customRouteType("Bus", "#109192"); crt.addMatchGtfsRouteType(3); // rail - TransitViewer.CustomRouteType crtRail = new TransitViewer.CustomRouteType(); - crtRail.label = "Rail"; - crtRail.color = "#EC0016"; + TransitViewer.CustomRouteType crtRail = TransitViewer.customRouteType("Rail", "#EC0016"); crtRail.addMatchGtfsRouteType(2); pt.withCustomRouteTypes(crt, crtRail); run(pt); + + Path out = Path.of(utils.getOutputDirectory(), "analysis", "pt"); + + Assertions.assertThat(out) + .isDirectoryContaining("glob:**pt_pax_volumes.csv.gz"); } } diff --git a/matsim/src/main/java/org/matsim/analysis/pt/stop2stop/PtStop2StopAnalysis.java b/matsim/src/main/java/org/matsim/analysis/pt/stop2stop/PtStop2StopAnalysis.java index 222b2d825af..370c8567348 100644 --- a/matsim/src/main/java/org/matsim/analysis/pt/stop2stop/PtStop2StopAnalysis.java +++ b/matsim/src/main/java/org/matsim/analysis/pt/stop2stop/PtStop2StopAnalysis.java @@ -42,24 +42,26 @@ import org.matsim.vehicles.Vehicles; import java.io.IOException; +import java.net.URL; +import java.nio.file.Path; import java.util.*; -import java.util.function.BinaryOperator; import java.util.stream.Collectors; /** * Processes events to create a csv file with passenger volumes, delays and similar information for each stop to stop * segment of a pt {@link org.matsim.pt.transitSchedule.api.Departure}. - * + *

* This class is entirely based on events. In case simulated pt should deviate from the * {@link org.matsim.pt.transitSchedule.api.TransitSchedule} this class provides data on what the simulation really gave * ignoring the TransitSchedule. - * - * Currently there are no integrity checks, if the sequence of events is wrong or an event is missing, this class might + *

+ * Currently, there are no integrity checks, if the sequence of events is wrong or an event is missing, this class might * silently produce invalid output. * This class was intended to be run after the last iteration and the simulation has finished and no preconditions were * taken for TransitVehicle fleets which might change over the course of iterations (e.g. minibus). So running this * class as an EventsListener during the simulation might give wrong results and might need work to get the transit - * vehicles updated before mobsim in each iteration. + * vehicles updated before mobsim in each iteration. Still it could be useful to run in each iteration in special cases, + * such as the minibus contrib. * * @author vsp-gleich */ @@ -70,10 +72,16 @@ public class PtStop2StopAnalysis implements TransitDriverStartsEventHandler, Veh private final Vehicles transitVehicles; // for vehicle capacity private final Map, PtVehicleData> transitVehicle2temporaryVehicleData = new HashMap<>(); private final List stop2StopEntriesForEachDeparture; // the output + private final double sampleUpscaleFactor; private static final Logger log = LogManager.getLogger(PtStop2StopAnalysis.class); - public PtStop2StopAnalysis(Vehicles transitVehicles) { + /** + * @param transitVehicles needed to look up vehicle capacity + * @param sampleUpscaleFactor : factor to scale up output passenger volumes to 100% + */ + public PtStop2StopAnalysis(Vehicles transitVehicles, double sampleUpscaleFactor) { this.transitVehicles = transitVehicles; + this.sampleUpscaleFactor = sampleUpscaleFactor; // set initial capacity to rough estimate of 30 entries by vehicle (should be sufficient) stop2StopEntriesForEachDeparture = new ArrayList<>(transitVehicles.getVehicles().size() * 30); } @@ -95,7 +103,7 @@ public void handleEvent(TransitDriverStartsEvent event) { public void handleEvent(VehicleArrivesAtFacilityEvent event) { PtVehicleData ptVehicleData = transitVehicle2temporaryVehicleData.get(event.getVehicleId()); if (ptVehicleData == null) { - log.error("Encountered a VehicleArrivesAtFacilityEvent without a previous TransitDriverStartsEvent for vehicle " + event.getVehicleId() + " at facility " + event.getFacilityId() + " at time " + event.getTime() + ". This should not happen, this analysis might fail subsequently."); + log.error("Encountered a VehicleArrivesAtFacilityEvent without a previous TransitDriverStartsEvent for vehicle {} at facility {} at time {}. This should not happen, this analysis might fail subsequently.", event.getVehicleId(), event.getFacilityId(), event.getTime()); } else { ptVehicleData.lastVehicleArrivesAtFacilityEvent = event; } @@ -108,16 +116,17 @@ public void handleEvent(VehicleArrivesAtFacilityEvent event) { public void handleEvent(VehicleDepartsAtFacilityEvent event) { PtVehicleData ptVehicleData = transitVehicle2temporaryVehicleData.get(event.getVehicleId()); if (ptVehicleData == null) { - log.error("Encountered a VehicleDepartsAtFacilityEvent without a previous TransitDriverStartsEvent for vehicle " + event.getVehicleId() + " at facility " + event.getFacilityId() + " at time " + event.getTime() + ". This should not happen, this analysis might fail subsequently."); + log.error("Encountered a VehicleDepartsAtFacilityEvent without a previous TransitDriverStartsEvent for vehicle {} at facility {} at time {}. This should not happen, this analysis might fail subsequently.", event.getVehicleId(), event.getFacilityId(), event.getTime()); } else { // produce output entry - stop2StopEntriesForEachDeparture.add(new Stop2StopEntry(ptVehicleData.transitLineId, - ptVehicleData.transitRouteId, ptVehicleData.departureId, event.getFacilityId(), - ptVehicleData.stopSequenceCounter, ptVehicleData.lastStopId, - ptVehicleData.lastVehicleArrivesAtFacilityEvent.getTime() - ptVehicleData.lastVehicleArrivesAtFacilityEvent.getDelay(), - ptVehicleData.lastVehicleArrivesAtFacilityEvent.getDelay(), event.getTime() - event.getDelay(), - event.getDelay(), ptVehicleData.currentPax, ptVehicleData.totalVehicleCapacity, - ptVehicleData.alightings, ptVehicleData.boardings, ptVehicleData.linksTravelledOnSincePreviousStop)); + stop2StopEntriesForEachDeparture.add(new Stop2StopEntry(ptVehicleData.transitLineId, + ptVehicleData.transitRouteId, ptVehicleData.departureId, event.getFacilityId(), + ptVehicleData.stopSequenceCounter, ptVehicleData.lastStopId, + ptVehicleData.lastVehicleArrivesAtFacilityEvent.getTime() - ptVehicleData.lastVehicleArrivesAtFacilityEvent.getDelay(), + ptVehicleData.lastVehicleArrivesAtFacilityEvent.getDelay(), event.getTime() - event.getDelay(), + event.getDelay(), ptVehicleData.currentPax * sampleUpscaleFactor, ptVehicleData.totalVehicleCapacity, + ptVehicleData.alightings * sampleUpscaleFactor, ptVehicleData.boardings * sampleUpscaleFactor, + List.copyOf(ptVehicleData.linksTravelledOnSincePreviousStop))); // calculate number of passengers at departure // (the Stop2StopEntry before needed the number of passengers at arrival so do not move this up!) ptVehicleData.currentPax = ptVehicleData.currentPax - ptVehicleData.alightings + ptVehicleData.boardings; @@ -167,8 +176,8 @@ public void handleEvent(PersonLeavesVehicleEvent event) { @Override public void reset(int iteration) { - if(transitVehicle2temporaryVehicleData.size() > 0) { - log.warn(transitVehicle2temporaryVehicleData.size() + " transit vehicles did not finish service in the last iteration."); + if(!transitVehicle2temporaryVehicleData.isEmpty()) { + log.warn("{} transit vehicles did not finish service in the last iteration.", transitVehicle2temporaryVehicleData.size()); } transitVehicle2temporaryVehicleData.clear(); stop2StopEntriesForEachDeparture.clear(); @@ -225,132 +234,48 @@ private PtVehicleData(Id transitLineId, Id transitRou } } - /** - * output data structure - */ - static final class Stop2StopEntry { - final Id transitLineId;// for aggregation -> set null or leave out and use Map lineId -> Stop2StopEntry? - final Id transitRouteId; - final Id departureId; - final Id stopId; - final int stopSequence; - final Id stopPreviousId; - final double arrivalTimeScheduled; - final double arrivalDelay; - final double departureTimeScheduled; - final double departureDelay; - final int passengersAtArrival; - final double totalVehicleCapacity; - final int passengersAlighting; - final int passengersBoarding; - final List> linkIdsSincePreviousStop; - - Stop2StopEntry(Id transitLineId, Id transitRouteId, - Id departureId, Id stopId, int stopSequence, - Id stopPreviousId, double arrivalTimeScheduled, double arrivalDelay, - double departureTimeScheduled, double departureDelay, int passengersAtArrival, - double totalVehicleCapacity, int passengersAlighting, int passengersBoarding, - List> linkIdsSincePreviousStop) { - this.transitLineId = transitLineId; - this.transitRouteId = transitRouteId; - this.departureId = departureId; - this.stopId = stopId; - this.stopSequence = stopSequence; - this.stopPreviousId = stopPreviousId; - this.arrivalTimeScheduled = arrivalTimeScheduled; - this.arrivalDelay = arrivalDelay; - this.departureTimeScheduled = departureTimeScheduled; - this.departureDelay = departureDelay; - this.passengersAtArrival = passengersAtArrival; - this.totalVehicleCapacity = totalVehicleCapacity; - this.passengersAlighting = passengersAlighting; - this.passengersBoarding = passengersBoarding; - this.linkIdsSincePreviousStop = List.copyOf(linkIdsSincePreviousStop); - } - - // getter for usage of standard Comparator implementations below and more - public Id getTransitLineId() { - return transitLineId; - } - - public Id getTransitRouteId() { - return transitRouteId; - } - - public Id getDepartureId() { - return departureId; - } - - public Id getStopId() { - return stopId; - } - - public int getStopSequence() { - return stopSequence; - } - - public Id getStopPreviousId() { - return stopPreviousId; - } - - public double getArrivalTimeScheduled() { - return arrivalTimeScheduled; - } - - public double getArrivalDelay() { - return arrivalDelay; - } - - public double getDepartureTimeScheduled() { - return departureTimeScheduled; - } - - public double getDepartureDelay() { - return departureDelay; - } - - public int getPassengersAtArrival() { - return passengersAtArrival; - } - - public double getTotalVehicleCapacity() { - return totalVehicleCapacity; - } - - public int getPassengersAlighting() { - return passengersAlighting; - } - - public int getPassengersBoarding() { - return passengersBoarding; - } - - public List> getLinkIdsSincePreviousStop() { - return linkIdsSincePreviousStop; - } - } + /** + * output data structure + * + * @param transitLineId for aggregation -> set null or leave out and use Map lineId -> Stop2StopEntry? + */ + record Stop2StopEntry(Id transitLineId, Id transitRouteId, Id departureId, Id stopId, + int stopSequence, Id stopPreviousId, double arrivalTimeScheduled, double arrivalDelay, + double departureTimeScheduled, double departureDelay, double passengersAtArrival, double totalVehicleCapacity, + double passengersAlighting, double passengersBoarding, List> linkIdsSincePreviousStop) {} static final String[] HEADER = {"transitLine", "transitRoute", "departure", "stop", "stopSequence", "stopPrevious", "arrivalTimeScheduled", "arrivalDelay", "departureTimeScheduled", "departureDelay", "passengersAtArrival", "totalVehicleCapacity", "passengersAlighting", "passengersBoarding", "linkIdsSincePreviousStop"}; - public static Comparator stop2StopEntryByTransitLineComparator = - Comparator.nullsLast(Comparator.comparing(Stop2StopEntry::getTransitLineId)); - public static Comparator stop2StopEntryByTransitRouteComparator = - Comparator.nullsLast(Comparator.comparing(Stop2StopEntry::getTransitRouteId)); - public static Comparator stop2StopEntryByDepartureComparator = - Comparator.nullsLast(Comparator.comparing(Stop2StopEntry::getDepartureId)); - public static Comparator stop2StopEntryByStopSequenceComparator = - Comparator.nullsLast(Comparator.comparing(Stop2StopEntry::getStopSequence)); + static Comparator stop2StopEntryByTransitLineComparator = + Comparator.nullsLast(Comparator.comparing(Stop2StopEntry::transitLineId)); + static Comparator stop2StopEntryByTransitRouteComparator = + Comparator.nullsLast(Comparator.comparing(Stop2StopEntry::transitRouteId)); + static Comparator stop2StopEntryByDepartureComparator = + Comparator.nullsLast(Comparator.comparing(Stop2StopEntry::departureId)); + static Comparator stop2StopEntryByStopSequenceComparator = + Comparator.nullsLast(Comparator.comparing(Stop2StopEntry::stopSequence)); + + public void writeStop2StopEntriesByDepartureCsv(String fileName, String columnSeparator, String listSeparatorInsideColumn) { + writeStop2StopEntriesByDepartureCsv(IOUtils.getFileUrl(fileName), columnSeparator, listSeparatorInsideColumn); + } + + public void writeStop2StopEntriesByDepartureCsv(Path path, String columnSeparator, String listSeparatorInsideColumn) { + writeStop2StopEntriesByDepartureCsv(IOUtils.getFileUrl(path.toString()), columnSeparator, listSeparatorInsideColumn); + } - public void writeStop2StopEntriesByDepartureCsv(String fileName, String columnSeparator, String listSeparatorInsideColumn) { + public void writeStop2StopEntriesByDepartureCsv(URL url, String columnSeparator, String listSeparatorInsideColumn) { stop2StopEntriesForEachDeparture.sort(stop2StopEntryByTransitLineComparator. thenComparing(stop2StopEntryByTransitRouteComparator). thenComparing(stop2StopEntryByDepartureComparator). thenComparing(stop2StopEntryByStopSequenceComparator)); - try (CSVPrinter printer = new CSVPrinter(IOUtils.getBufferedWriter(fileName), - CSVFormat.DEFAULT.withDelimiter(columnSeparator.charAt(0)).withHeader(HEADER)) + try (CSVPrinter printer = new CSVPrinter(IOUtils.getBufferedWriter(url), + CSVFormat.Builder.create() + .setDelimiter(columnSeparator) + .setHeader(HEADER) + .build()) ) { for (Stop2StopEntry entry : stop2StopEntriesForEachDeparture) { printer.print(entry.transitLineId); @@ -367,45 +292,15 @@ public void writeStop2StopEntriesByDepartureCsv(String fileName, String columnSe printer.print(entry.totalVehicleCapacity); printer.print(entry.passengersAlighting); printer.print(entry.passengersBoarding); - printer.print(entry.linkIdsSincePreviousStop.stream().map(id -> id.toString()).collect(Collectors.joining(listSeparatorInsideColumn))); + printer.print(entry.linkIdsSincePreviousStop.stream().map(Object::toString).collect(Collectors.joining(listSeparatorInsideColumn))); printer.println(); } } catch (IOException e) { - e.printStackTrace(); + log.error(e); } } - public List getStop2StopEntriesByDeparture () { + List getStop2StopEntriesByDeparture () { return List.copyOf(stop2StopEntriesForEachDeparture); } - - static final class Stop2StopAggregation { - - private final int departures; - private final long passengers; - private final double totalVehicleCapacity; - - Stop2StopAggregation (int departures, long passengers, double totalVehicleCapacity) { - this.departures = departures; - this.passengers = passengers; - this.totalVehicleCapacity = totalVehicleCapacity; - } - - public int getDepartures() { - return departures; - } - - public long getPassengers() { - return passengers; - } - - public double getTotalVehicleCapacity() { - return totalVehicleCapacity; - } - } - - public static BinaryOperator aggregateStop2StopAggregations() { - return (entry1, entry2) -> new PtStop2StopAnalysis.Stop2StopAggregation(entry1.getDepartures() + entry2.getDepartures(), entry1.getPassengers() + entry2.getPassengers(), - entry1.getTotalVehicleCapacity() + entry2.getTotalVehicleCapacity()); - } } diff --git a/matsim/src/main/java/org/matsim/analysis/pt/stop2stop/PtStop2StopAnalysis2Shp.java b/matsim/src/main/java/org/matsim/analysis/pt/stop2stop/PtStop2StopAnalysis2Shp.java deleted file mode 100644 index 1599a5ba979..00000000000 --- a/matsim/src/main/java/org/matsim/analysis/pt/stop2stop/PtStop2StopAnalysis2Shp.java +++ /dev/null @@ -1,164 +0,0 @@ -/* *********************************************************************** * - * project: org.matsim.* - * * - * *********************************************************************** * - * * - * copyright : (C) 2021 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.analysis.pt.stop2stop; - -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.geotools.api.feature.simple.SimpleFeature; -import org.geotools.feature.simple.SimpleFeatureBuilder; -import org.geotools.feature.simple.SimpleFeatureTypeBuilder; -import org.locationtech.jts.geom.Coordinate; -import org.locationtech.jts.geom.GeometryFactory; -import org.locationtech.jts.geom.LineString; -import org.matsim.api.core.v01.Id; -import org.matsim.api.core.v01.Scenario; -import org.matsim.api.core.v01.network.Link; -import org.matsim.core.utils.geometry.geotools.MGC; -import org.matsim.core.utils.gis.GeoFileWriter; -import org.matsim.core.utils.io.IOUtils; -import org.matsim.pt.transitSchedule.api.TransitLine; - -import java.io.IOException; -import java.util.*; -import java.util.stream.Collectors; - -import static org.matsim.analysis.pt.stop2stop.PtStop2StopAnalysis.aggregateStop2StopAggregations; - -/** - * Write a shape file with passenger volumes, delays and similar information for each stop to stop - * segment of a pt {@link org.matsim.pt.transitSchedule.api.TransitLine}. - * - * @author vsp-gleich - */ -public class PtStop2StopAnalysis2Shp { - - private static final String[] headerCsv = {"link", "transitLine", "stop", "departures", "passengers", "totalVehicleCapacity"}; - private static final Logger log = LogManager.getLogger(PtStop2StopAnalysis2Shp.class); - - public static void writePtStop2StopAnalysisByTransitLine2ShpFile( - final Scenario scenario, final List stop2StopEntriesForEachDeparture, String shpFileName, String coordinateSystem) { - - // sum per link and transit line - Map, Map, PtStop2StopAnalysis.Stop2StopAggregation>> stop2stopByLinkAndTransitLineAggregates = aggregatePerLinkAndLine(stop2StopEntriesForEachDeparture); - - SimpleFeatureTypeBuilder simpleFeatureBuilder = new SimpleFeatureTypeBuilder(); - try { - simpleFeatureBuilder.setCRS(MGC.getCRS(coordinateSystem)); - } catch (IllegalArgumentException e) { - log.warn("Coordinate reference system \"" + coordinateSystem + "\" is unknown."); - } - - simpleFeatureBuilder.setName("ptLinkPerLinePaxFeature"); - // note: column names may not be longer than 10 characters. Otherwise the name is cut after the 10th character and the avalue is NULL in QGis - simpleFeatureBuilder.add("the_geom", LineString.class); - simpleFeatureBuilder.add("linkId", String.class); - simpleFeatureBuilder.add("lineId", String.class); - // simpleFeatureBuilder.add("transitStopIdPrevious", String.class); //not unique, could be multiple - // simpleFeatureBuilder.add("transitStopIdFollowing", String.class); //not unique, could be multiple - simpleFeatureBuilder.add("departures", Integer.class); - simpleFeatureBuilder.add("passengers", Double.class); - simpleFeatureBuilder.add("totVehCapa", Double.class); - simpleFeatureBuilder.add("loadFactor", Double.class); - SimpleFeatureBuilder linkFeatureBuilder = new SimpleFeatureBuilder(simpleFeatureBuilder.buildFeatureType()); - - Collection features = new ArrayList<>(); - GeometryFactory geofac = new GeometryFactory(); - - for(Map.Entry, Map, PtStop2StopAnalysis.Stop2StopAggregation>> entryLinkLevel: stop2stopByLinkAndTransitLineAggregates.entrySet()) { - for (Map.Entry, PtStop2StopAnalysis.Stop2StopAggregation> entryLineLevel : entryLinkLevel.getValue().entrySet()) { - createLinkFeatureFromStop2StopAggregation(scenario, linkFeatureBuilder, features, geofac, entryLinkLevel.getKey(), entryLineLevel.getKey().toString(), entryLineLevel.getValue()); - } - } - - // sum per link of all transit lines - Map, PtStop2StopAnalysis.Stop2StopAggregation> stop2stopByLinkAggregates = stop2StopEntriesForEachDeparture.stream() - .flatMap(stop2StopEntry -> stop2StopEntry.linkIdsSincePreviousStop.stream() - .map(linkId -> new AbstractMap.SimpleEntry<>(linkId, stop2StopEntry))) - .collect(Collectors.toMap( - entry -> entry.getKey(), - entry -> new PtStop2StopAnalysis.Stop2StopAggregation(1, entry.getValue().passengersAtArrival, entry.getValue().totalVehicleCapacity), - aggregateStop2StopAggregations(), - HashMap::new)); - - for(Map.Entry, PtStop2StopAnalysis.Stop2StopAggregation> entryLinkLevel: stop2stopByLinkAggregates.entrySet()) { - createLinkFeatureFromStop2StopAggregation(scenario, linkFeatureBuilder, features, geofac, entryLinkLevel.getKey(), "all", entryLinkLevel.getValue()); - } - - // TODO: add stops? - GeoFileWriter.writeGeometries(features, shpFileName); - } - - public static void writePtStop2StopAnalysisByTransitLine2CsvFile( - final List stop2StopEntriesForEachDeparture, String fileNameCsv, String separatorCsv) { - - // sum per link and transit line - Map, Map, PtStop2StopAnalysis.Stop2StopAggregation>> stop2stopByLinkAndTransitLineAggregates = aggregatePerLinkAndLine(stop2StopEntriesForEachDeparture); - - try (CSVPrinter printer = new CSVPrinter(IOUtils.getBufferedWriter(fileNameCsv), - CSVFormat.DEFAULT.withDelimiter(separatorCsv.charAt(0)).withHeader(headerCsv)) - ) { - for(Map.Entry, Map, PtStop2StopAnalysis.Stop2StopAggregation>> entryLinkLevel: stop2stopByLinkAndTransitLineAggregates.entrySet()) { - for (Map.Entry, PtStop2StopAnalysis.Stop2StopAggregation> entryLineLevel : entryLinkLevel.getValue().entrySet()) { - printer.print(entryLinkLevel.getKey()); - printer.print(entryLineLevel.getKey()); - printer.print(entryLineLevel.getValue().getDepartures()); - printer.print(entryLineLevel.getValue().getPassengers()); - printer.print(entryLineLevel.getValue().getTotalVehicleCapacity()); - printer.println(); - } - } - } catch (IOException e) { - e.printStackTrace(); - } - } - - private static Map, Map, PtStop2StopAnalysis.Stop2StopAggregation>> aggregatePerLinkAndLine(List stop2StopEntriesForEachDeparture) { - return stop2StopEntriesForEachDeparture.stream() - .flatMap(stop2StopEntry -> stop2StopEntry.linkIdsSincePreviousStop.stream() - .map(linkId -> new AbstractMap.SimpleEntry<>(linkId, stop2StopEntry))) - .collect(Collectors.groupingBy(entry -> entry.getKey(), Collectors.toMap( - entry -> entry.getValue().transitLineId, - entry -> new PtStop2StopAnalysis.Stop2StopAggregation(1, entry.getValue().passengersAtArrival, entry.getValue().totalVehicleCapacity), - aggregateStop2StopAggregations(), - TreeMap::new))); - } - - private static void createLinkFeatureFromStop2StopAggregation(Scenario scenario, SimpleFeatureBuilder linkFeatureBuilder, Collection features, GeometryFactory geofac, Id linkId, String transitLineId, PtStop2StopAnalysis.Stop2StopAggregation stop2StopAggregation) { - Link link = scenario.getNetwork().getLinks().get(linkId); - LineString ls = geofac.createLineString(new Coordinate[] {MGC.coord2Coordinate(link.getFromNode().getCoord()), - MGC.coord2Coordinate(link.getToNode().getCoord())}); - Object[] linkFeatureAttributes = new Object[7]; - linkFeatureAttributes[0] = ls; - linkFeatureAttributes[1] = linkId; - linkFeatureAttributes[2] = transitLineId; - linkFeatureAttributes[3] = stop2StopAggregation.getDepartures(); - linkFeatureAttributes[4] = stop2StopAggregation.getPassengers(); - linkFeatureAttributes[5] = stop2StopAggregation.getTotalVehicleCapacity(); - linkFeatureAttributes[6] = stop2StopAggregation.getPassengers() / stop2StopAggregation.getTotalVehicleCapacity(); - try { - features.add(linkFeatureBuilder.buildFeature(stop2StopAggregation + "_line_" + transitLineId, linkFeatureAttributes)); - } catch (IllegalArgumentException e) { - e.printStackTrace(); - } - } - -} diff --git a/matsim/src/main/java/org/matsim/analysis/pt/stop2stop/PtStop2StopAnalysisControlerListener.java b/matsim/src/main/java/org/matsim/analysis/pt/stop2stop/PtStop2StopAnalysisControlerListener.java index 8259ad38828..7047436a44e 100644 --- a/matsim/src/main/java/org/matsim/analysis/pt/stop2stop/PtStop2StopAnalysisControlerListener.java +++ b/matsim/src/main/java/org/matsim/analysis/pt/stop2stop/PtStop2StopAnalysisControlerListener.java @@ -46,7 +46,8 @@ public class PtStop2StopAnalysisControlerListener implements IterationStartsList PtStop2StopAnalysisControlerListener(Scenario scenario, EventsManager eventsManager, OutputDirectoryHierarchy controlerIO) { this.eventsManager = eventsManager; this.controlerIO = controlerIO; - ptStop2StopAnalysis = new PtStop2StopAnalysis(scenario.getTransitVehicles()); + // TODO: Sample size is only available in simwrapper config group which is not available here. Setting to 1, needs to be upscaled later. + ptStop2StopAnalysis = new PtStop2StopAnalysis(scenario.getTransitVehicles(), 1.0); sep = scenario.getConfig().global().getDefaultDelimiter(); sep2 = sep.equals(";") ? "_" : ";"; // TODO: move sep2 to global config } diff --git a/matsim/src/test/java/org/matsim/analysis/pt/stop2stop/PtStop2StopAnalysisTest.java b/matsim/src/test/java/org/matsim/analysis/pt/stop2stop/PtStop2StopAnalysisTest.java index 88e5fb60349..f7d680241db 100644 --- a/matsim/src/test/java/org/matsim/analysis/pt/stop2stop/PtStop2StopAnalysisTest.java +++ b/matsim/src/test/java/org/matsim/analysis/pt/stop2stop/PtStop2StopAnalysisTest.java @@ -42,7 +42,6 @@ import java.util.ArrayList; import java.util.List; -import java.util.stream.Collectors; /** * @author dtamleh @@ -107,7 +106,7 @@ void testPtStop2StopAnalysisSingle() { String networkMode_bus = TransportMode.car; - PtStop2StopAnalysis ptStop2StopAnalysis = new PtStop2StopAnalysis(scenario.getTransitVehicles()); + PtStop2StopAnalysis ptStop2StopAnalysis = new PtStop2StopAnalysis(scenario.getTransitVehicles(), 1.0); ParallelEventsManager events = new ParallelEventsManager(false); events.addHandler(ptStop2StopAnalysis); @@ -141,34 +140,34 @@ void testPtStop2StopAnalysisSingle() { // Tests List line1_route1_dep1_stop1 = ptStop2StopAnalysis.getStop2StopEntriesByDeparture().stream() - .filter(entry -> entry.transitLineId.equals(transitLineId_bus1) && entry.transitRouteId.equals(transitRouteId_bus1_route1) - && entry.departureId.equals(departureId_bus1_route1_dep1) && entry.stopId.equals(transitStopFacilityId1) - && entry.stopSequence == 0).collect(Collectors.toList()); + .filter(entry -> entry.transitLineId().equals(transitLineId_bus1) && entry.transitRouteId().equals(transitRouteId_bus1_route1) + && entry.departureId().equals(departureId_bus1_route1_dep1) && entry.stopId().equals(transitStopFacilityId1) + && entry.stopSequence() == 0).toList(); System.out.println(line1_route1_dep1_stop1.size()); Assertions.assertEquals(1, line1_route1_dep1_stop1.size(), "Either no entry or more than entry for " + transitLineId_bus1 + ", " + transitRouteId_bus1_route1 + ", " + departureId_bus1_route1_dep1 + ", " + departureId_bus1_route1_dep1 + ", " + transitStopFacilityId1 + ", 0"); - Assertions.assertNull(line1_route1_dep1_stop1.get(0).stopPreviousId, "There should be no previous stop, but there was"); - Assertions.assertEquals(1.0, line1_route1_dep1_stop1.get(0).arrivalTimeScheduled, MatsimTestUtils.EPSILON, "Wrong arrivalTimeScheduled"); - Assertions.assertEquals(0.0, line1_route1_dep1_stop1.get(0).arrivalDelay, MatsimTestUtils.EPSILON, "Wrong arrivalDelay"); - Assertions.assertEquals(3.0, line1_route1_dep1_stop1.get(0).departureTimeScheduled, MatsimTestUtils.EPSILON); - Assertions.assertEquals(0.0, line1_route1_dep1_stop1.get(0).departureDelay, MatsimTestUtils.EPSILON); - Assertions.assertEquals(0.0, line1_route1_dep1_stop1.get(0).passengersAtArrival, MatsimTestUtils.EPSILON); - Assertions.assertEquals(veh_bus1.getType().getCapacity().getSeats() + veh_bus1.getType().getCapacity().getStandingRoom(), line1_route1_dep1_stop1.get(0).totalVehicleCapacity, MatsimTestUtils.EPSILON); - Assertions.assertEquals(0.0, line1_route1_dep1_stop1.get(0).passengersAlighting, MatsimTestUtils.EPSILON); - Assertions.assertEquals(2.0, line1_route1_dep1_stop1.get(0).passengersBoarding, MatsimTestUtils.EPSILON); + Assertions.assertNull(line1_route1_dep1_stop1.get(0).stopPreviousId(), "There should be no previous stop, but there was"); + Assertions.assertEquals(1.0, line1_route1_dep1_stop1.get(0).arrivalTimeScheduled(), MatsimTestUtils.EPSILON, "Wrong arrivalTimeScheduled"); + Assertions.assertEquals(0.0, line1_route1_dep1_stop1.get(0).arrivalDelay(), MatsimTestUtils.EPSILON, "Wrong arrivalDelay"); + Assertions.assertEquals(3.0, line1_route1_dep1_stop1.get(0).departureTimeScheduled(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(0.0, line1_route1_dep1_stop1.get(0).departureDelay(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(0.0, line1_route1_dep1_stop1.get(0).passengersAtArrival(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(veh_bus1.getType().getCapacity().getSeats() + veh_bus1.getType().getCapacity().getStandingRoom(), line1_route1_dep1_stop1.get(0).totalVehicleCapacity(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(0.0, line1_route1_dep1_stop1.get(0).passengersAlighting(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(2.0, line1_route1_dep1_stop1.get(0).passengersBoarding(), MatsimTestUtils.EPSILON); List> linkList = new ArrayList<>(); linkList.add(linkId1); - Assertions.assertEquals(linkList, line1_route1_dep1_stop1.get(0).linkIdsSincePreviousStop, "Wrong links"); + Assertions.assertEquals(linkList, line1_route1_dep1_stop1.get(0).linkIdsSincePreviousStop(), "Wrong links"); List line1_route1_dep1_stop3 = ptStop2StopAnalysis.getStop2StopEntriesByDeparture().stream() - .filter(entry -> entry.transitLineId.equals(transitLineId_bus1) && entry.transitRouteId.equals(transitRouteId_bus1_route1) - && entry.departureId.equals(departureId_bus1_route1_dep1) && entry.stopId.equals(transitStopFacilityId3) - && entry.stopSequence == 2).collect(Collectors.toList()); + .filter(entry -> entry.transitLineId().equals(transitLineId_bus1) && entry.transitRouteId().equals(transitRouteId_bus1_route1) + && entry.departureId().equals(departureId_bus1_route1_dep1) && entry.stopId().equals(transitStopFacilityId3) + && entry.stopSequence() == 2).toList(); Assertions.assertEquals(1, line1_route1_dep1_stop3.size(), "Either no entry or more than entry for " + transitLineId_bus1 + ", " + transitRouteId_bus1_route1 + ", " + departureId_bus1_route1_dep1 + ", " + departureId_bus1_route1_dep1 + ", " + transitStopFacilityId3 + ", 0"); - Assertions.assertEquals(transitStopFacilityId2, line1_route1_dep1_stop3.get(0).stopPreviousId, "There is no previous stop"); - Assertions.assertEquals(12.0, line1_route1_dep1_stop3.get(0).departureTimeScheduled, MatsimTestUtils.EPSILON); - Assertions.assertEquals(12.0, line1_route1_dep1_stop3.get(0).arrivalTimeScheduled, MatsimTestUtils.EPSILON, "Wrong arrivalTimeScheduled"); - Assertions.assertEquals(-1.0, line1_route1_dep1_stop3.get(0).arrivalDelay, MatsimTestUtils.EPSILON, "Wrong arrival delay"); - Assertions.assertEquals(1.0, line1_route1_dep1_stop3.get(0).departureDelay, MatsimTestUtils.EPSILON, "Wrong departure delay"); + Assertions.assertEquals(transitStopFacilityId2, line1_route1_dep1_stop3.get(0).stopPreviousId(), "There is no previous stop"); + Assertions.assertEquals(12.0, line1_route1_dep1_stop3.get(0).departureTimeScheduled(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(12.0, line1_route1_dep1_stop3.get(0).arrivalTimeScheduled(), MatsimTestUtils.EPSILON, "Wrong arrivalTimeScheduled"); + Assertions.assertEquals(-1.0, line1_route1_dep1_stop3.get(0).arrivalDelay(), MatsimTestUtils.EPSILON, "Wrong arrival delay"); + Assertions.assertEquals(1.0, line1_route1_dep1_stop3.get(0).departureDelay(), MatsimTestUtils.EPSILON, "Wrong departure delay"); } // ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -257,7 +256,7 @@ void testPtStop2StopAnalysisMulti() { String networkMode_bus = TransportMode.car; String networkMode_train = TransportMode.train; - PtStop2StopAnalysis ptStop2StopAnalysis = new PtStop2StopAnalysis(scenario.getTransitVehicles()); + PtStop2StopAnalysis ptStop2StopAnalysis = new PtStop2StopAnalysis(scenario.getTransitVehicles(), 1.0); ParallelEventsManager events = new ParallelEventsManager(false); events.addHandler(ptStop2StopAnalysis); @@ -444,54 +443,54 @@ void testPtStop2StopAnalysisMulti() { // Tests - List bus1_dep1_stop1 = ptStop2StopAnalysis.getStop2StopEntriesByDeparture().stream().filter(entry -> entry.transitLineId.equals(transitLineId_bus1) && entry.transitRouteId.equals(transitRouteId_bus1_route1) && entry.departureId.equals(departureId_bus1_dep1) && entry.stopId.equals(transitStopFacilityId1) && entry.stopSequence == 0).collect(Collectors.toList()); + List bus1_dep1_stop1 = ptStop2StopAnalysis.getStop2StopEntriesByDeparture().stream().filter(entry -> entry.transitLineId().equals(transitLineId_bus1) && entry.transitRouteId().equals(transitRouteId_bus1_route1) && entry.departureId().equals(departureId_bus1_dep1) && entry.stopId().equals(transitStopFacilityId1) && entry.stopSequence() == 0).toList(); Assertions.assertEquals(1, bus1_dep1_stop1.size(), "Either no entry or more than entry for " + transitLineId_bus1 + ", " + transitRouteId_bus1_route1 + ", " + departureId_bus1_dep1 + ", " + departureId_bus1_dep1 + ", " + transitStopFacilityId1 + ", 0"); - Assertions.assertNull(bus1_dep1_stop1.get(0).stopPreviousId, "There should be no previous stop, but there was"); - Assertions.assertEquals(1.0, bus1_dep1_stop1.get(0).arrivalTimeScheduled, MatsimTestUtils.EPSILON, "Wrong arrivalTimeScheduled"); - Assertions.assertEquals(0.0, bus1_dep1_stop1.get(0).arrivalDelay, MatsimTestUtils.EPSILON, "Wrong arrivalDelay"); - Assertions.assertEquals(3.0, bus1_dep1_stop1.get(0).departureTimeScheduled, MatsimTestUtils.EPSILON); - Assertions.assertEquals(0.0, bus1_dep1_stop1.get(0).departureDelay, MatsimTestUtils.EPSILON); - Assertions.assertEquals(0.0, bus1_dep1_stop1.get(0).passengersAtArrival, MatsimTestUtils.EPSILON); - Assertions.assertEquals(veh_bus1_dep1.getType().getCapacity().getSeats() + veh_bus1_dep1.getType().getCapacity().getStandingRoom(), bus1_dep1_stop1.get(0).totalVehicleCapacity, MatsimTestUtils.EPSILON); - Assertions.assertEquals(0.0, bus1_dep1_stop1.get(0).passengersAlighting, MatsimTestUtils.EPSILON); - Assertions.assertEquals(2.0, bus1_dep1_stop1.get(0).passengersBoarding, MatsimTestUtils.EPSILON); + Assertions.assertNull(bus1_dep1_stop1.get(0).stopPreviousId(), "There should be no previous stop, but there was"); + Assertions.assertEquals(1.0, bus1_dep1_stop1.get(0).arrivalTimeScheduled(), MatsimTestUtils.EPSILON, "Wrong arrivalTimeScheduled"); + Assertions.assertEquals(0.0, bus1_dep1_stop1.get(0).arrivalDelay(), MatsimTestUtils.EPSILON, "Wrong arrivalDelay"); + Assertions.assertEquals(3.0, bus1_dep1_stop1.get(0).departureTimeScheduled(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(0.0, bus1_dep1_stop1.get(0).departureDelay(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(0.0, bus1_dep1_stop1.get(0).passengersAtArrival(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(veh_bus1_dep1.getType().getCapacity().getSeats() + veh_bus1_dep1.getType().getCapacity().getStandingRoom(), bus1_dep1_stop1.get(0).totalVehicleCapacity(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(0.0, bus1_dep1_stop1.get(0).passengersAlighting(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(2.0, bus1_dep1_stop1.get(0).passengersBoarding(), MatsimTestUtils.EPSILON); List> linkList = new ArrayList<>(); linkList.add(linkId1); - Assertions.assertEquals(linkList, bus1_dep1_stop1.get(0).linkIdsSincePreviousStop, "Wrong links"); + Assertions.assertEquals(linkList, bus1_dep1_stop1.get(0).linkIdsSincePreviousStop(), "Wrong links"); - List bus1_dep1_stop3 = ptStop2StopAnalysis.getStop2StopEntriesByDeparture().stream().filter(entry -> entry.transitLineId.equals(transitLineId_bus1) && entry.transitRouteId.equals(transitRouteId_bus1_route1) && entry.departureId.equals(departureId_bus1_dep1) && entry.stopId.equals(transitStopFacilityId4) && entry.stopSequence == 2).collect(Collectors.toList()); + List bus1_dep1_stop3 = ptStop2StopAnalysis.getStop2StopEntriesByDeparture().stream().filter(entry -> entry.transitLineId().equals(transitLineId_bus1) && entry.transitRouteId().equals(transitRouteId_bus1_route1) && entry.departureId().equals(departureId_bus1_dep1) && entry.stopId().equals(transitStopFacilityId4) && entry.stopSequence() == 2).toList(); System.out.println(bus1_dep1_stop3.isEmpty()); Assertions.assertEquals(1, bus1_dep1_stop3.size(), "Either no entry or more than entry for " + transitLineId_bus1 + ", " + transitRouteId_bus1_route1 + ", " + departureId_bus1_dep1 + ", " + departureId_bus1_dep1 + ", " + transitStopFacilityId4 + ", 0"); - Assertions.assertEquals(0.0, bus1_dep1_stop3.get(0).arrivalDelay, MatsimTestUtils.EPSILON, "Wrong arrivalDelay"); - Assertions.assertEquals(15.0, bus1_dep1_stop3.get(0).departureTimeScheduled, MatsimTestUtils.EPSILON); - Assertions.assertEquals(0.0, bus1_dep1_stop3.get(0).departureDelay, MatsimTestUtils.EPSILON); - Assertions.assertEquals(3.0, bus1_dep1_stop3.get(0).passengersAtArrival, MatsimTestUtils.EPSILON); - Assertions.assertEquals(veh_bus1_dep1.getType().getCapacity().getSeats() + veh_bus1_dep1.getType().getCapacity().getStandingRoom(), bus1_dep1_stop1.get(0).totalVehicleCapacity, MatsimTestUtils.EPSILON); - Assertions.assertEquals(3.0, bus1_dep1_stop3.get(0).passengersAlighting, MatsimTestUtils.EPSILON); - Assertions.assertEquals(0.0, bus1_dep1_stop3.get(0).passengersBoarding, MatsimTestUtils.EPSILON); - - List bus1_dep1_stop4 = ptStop2StopAnalysis.getStop2StopEntriesByDeparture().stream().filter(entry -> entry.transitLineId.equals(transitLineId_bus1) && entry.transitRouteId.equals(transitRouteId_bus1_route2) && entry.departureId.equals(departureId_bus1_dep1) && entry.stopId.equals(transitStopFacilityId2) && entry.stopSequence == 1).collect(Collectors.toList()); + Assertions.assertEquals(0.0, bus1_dep1_stop3.get(0).arrivalDelay(), MatsimTestUtils.EPSILON, "Wrong arrivalDelay"); + Assertions.assertEquals(15.0, bus1_dep1_stop3.get(0).departureTimeScheduled(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(0.0, bus1_dep1_stop3.get(0).departureDelay(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(3.0, bus1_dep1_stop3.get(0).passengersAtArrival(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(veh_bus1_dep1.getType().getCapacity().getSeats() + veh_bus1_dep1.getType().getCapacity().getStandingRoom(), bus1_dep1_stop1.get(0).totalVehicleCapacity(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(3.0, bus1_dep1_stop3.get(0).passengersAlighting(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(0.0, bus1_dep1_stop3.get(0).passengersBoarding(), MatsimTestUtils.EPSILON); + + List bus1_dep1_stop4 = ptStop2StopAnalysis.getStop2StopEntriesByDeparture().stream().filter(entry -> entry.transitLineId().equals(transitLineId_bus1) && entry.transitRouteId().equals(transitRouteId_bus1_route2) && entry.departureId().equals(departureId_bus1_dep1) && entry.stopId().equals(transitStopFacilityId2) && entry.stopSequence() == 1).toList(); Assertions.assertEquals(1, bus1_dep1_stop4.size(), "Either no entry or more than entry for " + transitLineId_bus1 + ", " + transitRouteId_bus1_route2 + ", " + departureId_bus1_dep1 + ", " + departureId_bus1_dep1 + ", " + transitStopFacilityId2 + ", 0"); - Assertions.assertEquals(28.0, bus1_dep1_stop4.get(0).arrivalTimeScheduled, MatsimTestUtils.EPSILON, "Wrong arrivalTimeScheduled"); - Assertions.assertEquals(0.0, bus1_dep1_stop4.get(0).arrivalDelay, MatsimTestUtils.EPSILON, "Wrong arrivalDelay"); - Assertions.assertEquals(29.0, bus1_dep1_stop4.get(0).departureTimeScheduled, MatsimTestUtils.EPSILON); - Assertions.assertEquals(0.0, bus1_dep1_stop4.get(0).departureDelay, MatsimTestUtils.EPSILON); - Assertions.assertEquals(5.0, bus1_dep1_stop4.get(0).passengersAtArrival, MatsimTestUtils.EPSILON); - Assertions.assertEquals(veh_bus1_dep1.getType().getCapacity().getSeats() + veh_bus1_dep1.getType().getCapacity().getStandingRoom(), bus1_dep1_stop1.get(0).totalVehicleCapacity, MatsimTestUtils.EPSILON); - Assertions.assertEquals(2.0, bus1_dep1_stop4.get(0).passengersAlighting, MatsimTestUtils.EPSILON); - Assertions.assertEquals(2.0, bus1_dep1_stop4.get(0).passengersBoarding, MatsimTestUtils.EPSILON); - - List train1_dep1_stop4 = ptStop2StopAnalysis.getStop2StopEntriesByDeparture().stream().filter(entry -> entry.transitLineId.equals(transitLineId_train1) && entry.transitRouteId.equals(transitRouteId_train1_route1) && entry.departureId.equals(departureId_train1_dep1) && entry.stopId.equals(transitStopFacilityId6) && entry.stopSequence == 3).collect(Collectors.toList()); + Assertions.assertEquals(28.0, bus1_dep1_stop4.get(0).arrivalTimeScheduled(), MatsimTestUtils.EPSILON, "Wrong arrivalTimeScheduled"); + Assertions.assertEquals(0.0, bus1_dep1_stop4.get(0).arrivalDelay(), MatsimTestUtils.EPSILON, "Wrong arrivalDelay"); + Assertions.assertEquals(29.0, bus1_dep1_stop4.get(0).departureTimeScheduled(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(0.0, bus1_dep1_stop4.get(0).departureDelay(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(5.0, bus1_dep1_stop4.get(0).passengersAtArrival(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(veh_bus1_dep1.getType().getCapacity().getSeats() + veh_bus1_dep1.getType().getCapacity().getStandingRoom(), bus1_dep1_stop1.get(0).totalVehicleCapacity(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(2.0, bus1_dep1_stop4.get(0).passengersAlighting(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(2.0, bus1_dep1_stop4.get(0).passengersBoarding(), MatsimTestUtils.EPSILON); + + List train1_dep1_stop4 = ptStop2StopAnalysis.getStop2StopEntriesByDeparture().stream().filter(entry -> entry.transitLineId().equals(transitLineId_train1) && entry.transitRouteId().equals(transitRouteId_train1_route1) && entry.departureId().equals(departureId_train1_dep1) && entry.stopId().equals(transitStopFacilityId6) && entry.stopSequence() == 3).toList(); Assertions.assertEquals(1, train1_dep1_stop4.size(), "Either no entry or more than entry for " + transitLineId_train1 + ", " + transitRouteId_train1_route1 + ", " + departureId_train1_dep1 + ", " + transitStopFacilityId6 + ", 0"); - Assertions.assertEquals(19.0, train1_dep1_stop4.get(0).arrivalTimeScheduled, MatsimTestUtils.EPSILON, "Wrong arrivalTimeScheduled"); - Assertions.assertEquals(0.0, train1_dep1_stop4.get(0).arrivalDelay, MatsimTestUtils.EPSILON, "Wrong arrivalDelay"); - Assertions.assertEquals(21.0, train1_dep1_stop4.get(0).departureTimeScheduled, MatsimTestUtils.EPSILON); - Assertions.assertEquals(0.0, train1_dep1_stop4.get(0).departureDelay, MatsimTestUtils.EPSILON); - Assertions.assertEquals(6.0, train1_dep1_stop4.get(0).passengersAtArrival, MatsimTestUtils.EPSILON); - Assertions.assertEquals(veh_bus1_dep1.getType().getCapacity().getSeats() + veh_bus1_dep1.getType().getCapacity().getStandingRoom(), bus1_dep1_stop1.get(0).totalVehicleCapacity, MatsimTestUtils.EPSILON); - Assertions.assertEquals(4.0, train1_dep1_stop4.get(0).passengersAlighting, MatsimTestUtils.EPSILON); - Assertions.assertEquals(1.0, train1_dep1_stop4.get(0).passengersBoarding, MatsimTestUtils.EPSILON); + Assertions.assertEquals(19.0, train1_dep1_stop4.get(0).arrivalTimeScheduled(), MatsimTestUtils.EPSILON, "Wrong arrivalTimeScheduled"); + Assertions.assertEquals(0.0, train1_dep1_stop4.get(0).arrivalDelay(), MatsimTestUtils.EPSILON, "Wrong arrivalDelay"); + Assertions.assertEquals(21.0, train1_dep1_stop4.get(0).departureTimeScheduled(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(0.0, train1_dep1_stop4.get(0).departureDelay(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(6.0, train1_dep1_stop4.get(0).passengersAtArrival(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(veh_bus1_dep1.getType().getCapacity().getSeats() + veh_bus1_dep1.getType().getCapacity().getStandingRoom(), bus1_dep1_stop1.get(0).totalVehicleCapacity(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(4.0, train1_dep1_stop4.get(0).passengersAlighting(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(1.0, train1_dep1_stop4.get(0).passengersBoarding(), MatsimTestUtils.EPSILON); } -} \ No newline at end of file +} From 78a98c2eebc3383ed15467fa12a9dcda2c9286ed Mon Sep 17 00:00:00 2001 From: Ricardo Ewert Date: Wed, 13 Nov 2024 13:33:15 +0100 Subject: [PATCH 32/53] update default vehicleTypes incl. HBEFA categories and updated costs --- .../test.output_events.xml.gz | Bin 69240 -> 70357 bytes .../vehicleTypes.xml | 180 +++++++++--------- 2 files changed, 90 insertions(+), 90 deletions(-) diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/test.output_events.xml.gz b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/test.output_events.xml.gz index 23c2766f7c3d3b51432ff2bca512c0fb5805a36d..8feaf9c0273377f893b88ae0fa43e340cb410e7f 100644 GIT binary patch literal 70357 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�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 literal 69240 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 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/vehicleTypes.xml b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/vehicleTypes.xml index 48a47d32b8b..2b11da8b0cb 100644 --- a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/vehicleTypes.xml +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/vehicleTypes.xml @@ -5,20 +5,22 @@ Golf 1.4 Trendline - - - + + - diesel + PASSENGER_CAR + petrol + average + average - + - 0.00948 - 0.00948 + 0.0049 + 0.0049 @@ -26,21 +28,22 @@ - - - Heavy Vehicle 26t - + - + VW Caddy 2.0 Maxi TDI + + - 0.0 - diesel + PASSENGER_CAR + diesel + average + average - + 0.0049 0.0049 @@ -51,180 +54,177 @@ - - - Light Vehicle 7.5t - + - + Mercedes 313 CDI + + + LIGHT_COMMERCIAL_VEHICLE diesel + average + average - + 0.0049 0.0049 - + + - - - Medium Vehicle 18t - - - + Mercedes 313 CDI + + + LIGHT_COMMERCIAL_VEHICLE diesel + average + average - + 0.0049 0.0049 - + - - - Mercedes 313 CDI - + - + Light Vehicle 7.5t + + + LIGHT_COMMERCIAL_VEHICLE diesel + average + average - + 0.0049 0.0049 - + + - - - VW Caddy 2.0 Maxi TDI - - - + Medium Vehicle 18t + + + HEAVY_GOODS_VEHICLE diesel + average + average - + - 0.00948 - 0.00948 + 0.0049 + 0.0049 - + + - - - Heavy Vehicle 26t - - - + Medium Vehicle 18t + + + HEAVY_GOODS_VEHICLE diesel + average + average - - + + + 0.0049 + 0.0049 + - + - Heavy Vehicle 40t - - - - + + + + HEAVY_GOODS_VEHICLE diesel + average + average - - - - - - - - - - Light Vehicle 7.5t Frozen - - - - - - - diesel + 0.00559 + 0.00559 - - - - + - - - + + Waste collection vehicle - - + + HEAVY_GOODS_VEHICLE + diesel + average + average 0.5 - 60.0 - diesel + 0.0006 - + + 0.0 + 0.0 + From 8969b53e4879a344e3691536ae02dbe84cd6e890 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20H=C3=B6rl?= Date: Fri, 15 Nov 2024 15:32:47 +0100 Subject: [PATCH 33/53] feat: make chargers attributable (#3565) --- .../contrib/ev/infrastructure/Charger.java | 3 +- .../ev/infrastructure/ChargerDefaultImpl.java | 6 + .../ev/infrastructure/ChargerReader.java | 44 ++++++- .../infrastructure/ChargerSpecification.java | 3 +- .../ev/infrastructure/ChargerWriter.java | 34 +++++- .../ChargingInfrastructureModule.java | 23 +++- .../ImmutableChargerSpecification.java | 15 +++ .../ChargerReaderWriterTest.java | 108 ++++++++++++++++++ matsim/src/main/resources/dtd/chargers_v1.dtd | 9 +- 9 files changed, 231 insertions(+), 14 deletions(-) create mode 100644 contribs/ev/src/test/java/org/matsim/contrib/ev/infrastructure/ChargerReaderWriterTest.java diff --git a/contribs/ev/src/main/java/org/matsim/contrib/ev/infrastructure/Charger.java b/contribs/ev/src/main/java/org/matsim/contrib/ev/infrastructure/Charger.java index 9bd2ef5bde9..921b950e41c 100644 --- a/contribs/ev/src/main/java/org/matsim/contrib/ev/infrastructure/Charger.java +++ b/contribs/ev/src/main/java/org/matsim/contrib/ev/infrastructure/Charger.java @@ -24,8 +24,9 @@ import org.matsim.api.core.v01.Identifiable; import org.matsim.api.core.v01.network.Link; import org.matsim.contrib.ev.charging.ChargingLogic; +import org.matsim.utils.objectattributes.attributable.Attributable; -public interface Charger extends BasicLocation, Identifiable { +public interface Charger extends BasicLocation, Identifiable, Attributable { ChargerSpecification getSpecification(); ChargingLogic getLogic(); diff --git a/contribs/ev/src/main/java/org/matsim/contrib/ev/infrastructure/ChargerDefaultImpl.java b/contribs/ev/src/main/java/org/matsim/contrib/ev/infrastructure/ChargerDefaultImpl.java index d2efb68578d..7ceb1007f92 100644 --- a/contribs/ev/src/main/java/org/matsim/contrib/ev/infrastructure/ChargerDefaultImpl.java +++ b/contribs/ev/src/main/java/org/matsim/contrib/ev/infrastructure/ChargerDefaultImpl.java @@ -26,6 +26,7 @@ import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; import org.matsim.contrib.ev.charging.ChargingLogic; +import org.matsim.utils.objectattributes.attributable.Attributes; import com.google.common.base.Preconditions; @@ -77,6 +78,11 @@ public int getPlugCount() { return specification.getPlugCount(); } + @Override + public Attributes getAttributes() { + return specification.getAttributes(); + } + //TODO in order to add a separate coord: adapt DTD, ChargerSpecification and ChargerReader/Writer // Additionally, the reader and writer should convert coordinates if CRS different than that of the network @Override diff --git a/contribs/ev/src/main/java/org/matsim/contrib/ev/infrastructure/ChargerReader.java b/contribs/ev/src/main/java/org/matsim/contrib/ev/infrastructure/ChargerReader.java index 9864622b4cb..b3d6a4d6c36 100644 --- a/contribs/ev/src/main/java/org/matsim/contrib/ev/infrastructure/ChargerReader.java +++ b/contribs/ev/src/main/java/org/matsim/contrib/ev/infrastructure/ChargerReader.java @@ -20,19 +20,33 @@ package org.matsim.contrib.ev.infrastructure; +import java.util.HashMap; +import java.util.Map; import java.util.Optional; import java.util.Stack; import org.matsim.api.core.v01.Id; import org.matsim.contrib.ev.EvUnits; +import org.matsim.contrib.ev.infrastructure.ImmutableChargerSpecification.ChargerSpecificationBuilder; import org.matsim.core.utils.io.MatsimXmlParser; +import org.matsim.utils.objectattributes.AttributeConverter; +import org.matsim.utils.objectattributes.attributable.AttributesImpl; +import org.matsim.utils.objectattributes.attributable.AttributesXmlReaderDelegate; import org.xml.sax.Attributes; public final class ChargerReader extends MatsimXmlParser { private final static String CHARGER = "charger"; + private final static String ATTRIBUTES = "attributes"; + private final static String ATTRIBUTE = "attribute"; private final ChargingInfrastructureSpecification chargingInfrastructure; + private Map, AttributeConverter> attributeConverters = new HashMap<>(); + private final AttributesXmlReaderDelegate attributesReader = new AttributesXmlReaderDelegate(); + + private ChargerSpecificationBuilder currentBuilder = null; + private AttributesImpl currentAttributes = null; + public ChargerReader(ChargingInfrastructureSpecification chargingInfrastructure) { super(ValidationType.DTD_ONLY); this.chargingInfrastructure = chargingInfrastructure; @@ -41,15 +55,30 @@ public ChargerReader(ChargingInfrastructureSpecification chargingInfrastructure) @Override public void startTag(String name, Attributes atts, Stack context) { if (CHARGER.equals(name)) { - chargingInfrastructure.addChargerSpecification(createSpecification(atts)); + currentBuilder = createSpecification(atts); + } else if (ATTRIBUTES.equals(name)) { + currentAttributes = new AttributesImpl(); + attributesReader.startTag(name, atts, context, currentAttributes); + } else if (ATTRIBUTE.equals(name)) { + attributesReader.startTag(name, atts, context, currentAttributes); } } @Override public void endTag(String name, String content, Stack context) { + if (CHARGER.equals(name)) { + chargingInfrastructure.addChargerSpecification(currentBuilder.build()); + currentBuilder = null; + } else if (ATTRIBUTES.equals(name)) { + attributesReader.endTag(name, content, context); + currentBuilder.attributes(currentAttributes); + currentAttributes = null; + } else if (ATTRIBUTE.equals(name)) { + attributesReader.endTag(name, content, context); + } } - private ChargerSpecification createSpecification(Attributes atts) { + private ChargerSpecificationBuilder createSpecification(Attributes atts) { return ImmutableChargerSpecification.newBuilder() .id(Id.create(atts.getValue("id"), Charger.class)) .linkId(Id.createLinkId(atts.getValue("link"))) @@ -58,7 +87,14 @@ private ChargerSpecification createSpecification(Attributes atts) { .plugPower(EvUnits.kW_to_W(Double.parseDouble(atts.getValue("plug_power")))) .plugCount(Optional.ofNullable(atts.getValue("plug_count")) .map(Integer::parseInt) - .orElse(ChargerSpecification.DEFAULT_PLUG_COUNT)) - .build(); + .orElse(ChargerSpecification.DEFAULT_PLUG_COUNT)); } + + public void putAttributeConverters(Map, AttributeConverter> converters) { + this.attributeConverters.putAll(converters); + } + + public void putAttributeConverter(Class key, AttributeConverter converter) { + this.attributeConverters.put(key, converter); + } } diff --git a/contribs/ev/src/main/java/org/matsim/contrib/ev/infrastructure/ChargerSpecification.java b/contribs/ev/src/main/java/org/matsim/contrib/ev/infrastructure/ChargerSpecification.java index 14aafb14d12..73272087d0a 100644 --- a/contribs/ev/src/main/java/org/matsim/contrib/ev/infrastructure/ChargerSpecification.java +++ b/contribs/ev/src/main/java/org/matsim/contrib/ev/infrastructure/ChargerSpecification.java @@ -23,6 +23,7 @@ import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.Identifiable; import org.matsim.api.core.v01.network.Link; +import org.matsim.utils.objectattributes.attributable.Attributable; /** * ChargerSpecification is assumed to be immutable. @@ -34,7 +35,7 @@ * * @author Michal Maciejewski (michalm) */ -public interface ChargerSpecification extends Identifiable { +public interface ChargerSpecification extends Identifiable, Attributable { String DEFAULT_CHARGER_TYPE = "default"; int DEFAULT_PLUG_COUNT = 1; diff --git a/contribs/ev/src/main/java/org/matsim/contrib/ev/infrastructure/ChargerWriter.java b/contribs/ev/src/main/java/org/matsim/contrib/ev/infrastructure/ChargerWriter.java index 8955b266984..f62ee0729f6 100644 --- a/contribs/ev/src/main/java/org/matsim/contrib/ev/infrastructure/ChargerWriter.java +++ b/contribs/ev/src/main/java/org/matsim/contrib/ev/infrastructure/ChargerWriter.java @@ -20,18 +20,27 @@ package org.matsim.contrib.ev.infrastructure; +import java.io.IOException; +import java.io.UncheckedIOException; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.stream.Stream; import org.matsim.contrib.ev.EvUnits; import org.matsim.core.utils.collections.Tuple; import org.matsim.core.utils.io.MatsimXmlWriter; +import org.matsim.utils.objectattributes.AttributeConverter; +import org.matsim.utils.objectattributes.attributable.AttributesXmlWriterDelegate; public final class ChargerWriter extends MatsimXmlWriter { private final Stream chargerSpecifications; + private Map, AttributeConverter> attributeConverters = new HashMap<>(); + private final AttributesXmlWriterDelegate attributesWriter = new AttributesXmlWriterDelegate(); + public ChargerWriter(Stream chargerSpecifications) { this.chargerSpecifications = chargerSpecifications; } @@ -45,13 +54,34 @@ public void write(String file) { close(); } - private void writeChargers() { + private void writeChargers() throws UncheckedIOException { chargerSpecifications.forEach(c -> { List> atts = Arrays.asList(Tuple.of("id", c.getId().toString()), Tuple.of("link", c.getLinkId() + ""), Tuple.of("type", c.getChargerType()), Tuple.of("plug_power", EvUnits.W_to_kW(c.getPlugPower()) + ""), Tuple.of("plug_count", c.getPlugCount() + "")); - writeStartTag("charger", atts, true); + if (c.getAttributes().size() == 0) { + writeStartTag("charger", atts, true); + } else { + writeStartTag("charger", atts, false); + + try { + this.writer.write("\n"); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + + attributesWriter.writeAttributes("\t\t", this.writer, c.getAttributes(), false); + writeEndTag("charger"); + } }); } + + public void putAttributeConverters(Map, AttributeConverter> converters) { + this.attributeConverters.putAll(converters); + } + + public void putAttributeConverter(Class key, AttributeConverter converter) { + this.attributeConverters.put(key, converter); + } } diff --git a/contribs/ev/src/main/java/org/matsim/contrib/ev/infrastructure/ChargingInfrastructureModule.java b/contribs/ev/src/main/java/org/matsim/contrib/ev/infrastructure/ChargingInfrastructureModule.java index f44bee53f11..dd85c2bb83b 100644 --- a/contribs/ev/src/main/java/org/matsim/contrib/ev/infrastructure/ChargingInfrastructureModule.java +++ b/contribs/ev/src/main/java/org/matsim/contrib/ev/infrastructure/ChargingInfrastructureModule.java @@ -20,12 +20,16 @@ package org.matsim.contrib.ev.infrastructure; +import java.util.Collections; +import java.util.Map; + import org.matsim.api.core.v01.network.Network; import org.matsim.contrib.ev.EvConfigGroup; import org.matsim.contrib.ev.charging.ChargingLogic; import org.matsim.core.config.ConfigGroup; import org.matsim.core.controler.AbstractModule; import org.matsim.core.mobsim.qsim.AbstractQSimModule; +import org.matsim.utils.objectattributes.AttributeConverter; import com.google.inject.Inject; import com.google.inject.Key; @@ -55,11 +59,20 @@ public ChargingInfrastructureModule(Key networkKey) { public void install() { bind(Network.class).annotatedWith(Names.named(CHARGERS)).to(networkKey).asEagerSingleton(); - bind(ChargingInfrastructureSpecification.class).toProvider(() -> { - ChargingInfrastructureSpecification chargingInfrastructureSpecification = new ChargingInfrastructureSpecificationDefaultImpl(); - new ChargerReader(chargingInfrastructureSpecification).parse( - ConfigGroup.getInputFileURL(getConfig().getContext(), evCfg.chargersFile)); - return chargingInfrastructureSpecification; + bind(ChargingInfrastructureSpecification.class).toProvider(new Provider<>() { + @Inject + private Map,AttributeConverter> attributeConverters = Collections.emptyMap(); + + public ChargingInfrastructureSpecification get() { + ChargingInfrastructureSpecification chargingInfrastructureSpecification = new ChargingInfrastructureSpecificationDefaultImpl(); + + ChargerReader reader = new ChargerReader(chargingInfrastructureSpecification); + reader.putAttributeConverters(attributeConverters); + reader.parse( + ConfigGroup.getInputFileURL(getConfig().getContext(), evCfg.chargersFile)); + + return chargingInfrastructureSpecification; + } }).asEagerSingleton(); installQSimModule(new AbstractQSimModule() { diff --git a/contribs/ev/src/main/java/org/matsim/contrib/ev/infrastructure/ImmutableChargerSpecification.java b/contribs/ev/src/main/java/org/matsim/contrib/ev/infrastructure/ImmutableChargerSpecification.java index a3d7192b793..2987fe88677 100644 --- a/contribs/ev/src/main/java/org/matsim/contrib/ev/infrastructure/ImmutableChargerSpecification.java +++ b/contribs/ev/src/main/java/org/matsim/contrib/ev/infrastructure/ImmutableChargerSpecification.java @@ -24,6 +24,8 @@ import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; +import org.matsim.utils.objectattributes.attributable.Attributes; +import org.matsim.utils.objectattributes.attributable.AttributesImpl; import com.google.common.base.MoreObjects; import com.google.common.base.Preconditions; @@ -39,6 +41,7 @@ public class ImmutableChargerSpecification implements ChargerSpecification { private final String chargerType; private final double plugPower; private final int plugCount; + private final Attributes attributes; private ImmutableChargerSpecification( ChargerSpecificationBuilder builder ) { id = Objects.requireNonNull(builder.id); @@ -46,6 +49,7 @@ private ImmutableChargerSpecification( ChargerSpecificationBuilder builder ) { chargerType = Objects.requireNonNull(builder.chargerType); plugPower = Objects.requireNonNull(builder.plugPower); plugCount = Objects.requireNonNull(builder.plugCount); + attributes = builder.attributes != null ? builder.attributes : new AttributesImpl(); Preconditions.checkArgument(plugPower >= 0, "Negative plugPower of charger: %s", id); Preconditions.checkArgument(plugCount >= 0, "Negative plugCount of charger: %s", id); @@ -90,6 +94,11 @@ public int getPlugCount() { return plugCount; } + @Override + public Attributes getAttributes() { + return attributes; + } + @Override public String toString() { return MoreObjects.toStringHelper(this) @@ -107,6 +116,7 @@ public static final class ChargerSpecificationBuilder{ private String chargerType; private Double plugPower; private Integer plugCount; + private Attributes attributes; private ChargerSpecificationBuilder() { } @@ -136,6 +146,11 @@ public ChargerSpecificationBuilder plugCount( int val ) { return this; } + public ChargerSpecificationBuilder attributes( Attributes val ) { + attributes = val; + return this; + } + public ImmutableChargerSpecification build() { return new ImmutableChargerSpecification(this); } diff --git a/contribs/ev/src/test/java/org/matsim/contrib/ev/infrastructure/ChargerReaderWriterTest.java b/contribs/ev/src/test/java/org/matsim/contrib/ev/infrastructure/ChargerReaderWriterTest.java new file mode 100644 index 00000000000..eb6e0f5c65f --- /dev/null +++ b/contribs/ev/src/test/java/org/matsim/contrib/ev/infrastructure/ChargerReaderWriterTest.java @@ -0,0 +1,108 @@ +package org.matsim.contrib.ev.infrastructure; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.matsim.api.core.v01.Id; +import org.matsim.testcases.MatsimTestUtils; +import org.matsim.utils.objectattributes.attributable.AttributesImpl; + +public class ChargerReaderWriterTest { + @RegisterExtension + MatsimTestUtils utils = new MatsimTestUtils(); + + @Test + public void testReadWriteChargers() { + ChargingInfrastructureSpecificationDefaultImpl infrastructure = new ChargingInfrastructureSpecificationDefaultImpl(); + + infrastructure.addChargerSpecification(ImmutableChargerSpecification.newBuilder() + .id(Id.create("charger1", Charger.class)) // + .chargerType("type1") // + .linkId(Id.createLinkId("link1")) // + .plugCount(1) // + .plugPower(1000.0) // + .build()); + + infrastructure.addChargerSpecification(ImmutableChargerSpecification.newBuilder() + .id(Id.create("charger2", Charger.class)) // + .chargerType("type2") // + .linkId(Id.createLinkId("link2")) // + .plugCount(2) // + .plugPower(2000.0) // + .build()); + + String path = utils.getOutputDirectory() + "/chargers.xml"; + new ChargerWriter(infrastructure.getChargerSpecifications().values().stream()).write(path); + + ChargingInfrastructureSpecificationDefaultImpl readInfrastructure = new ChargingInfrastructureSpecificationDefaultImpl(); + new ChargerReader(readInfrastructure).readFile(path); + + ChargerSpecification spec1 = readInfrastructure.getChargerSpecifications() + .get(Id.create("charger1", Charger.class)); + assertEquals("type1", spec1.getChargerType()); + assertEquals(Id.createLinkId("link1"), spec1.getLinkId()); + assertEquals(1, spec1.getPlugCount()); + assertEquals(1000.0, spec1.getPlugPower()); + + ChargerSpecification spec2 = readInfrastructure.getChargerSpecifications() + .get(Id.create("charger2", Charger.class)); + assertEquals("type2", spec2.getChargerType()); + assertEquals(Id.createLinkId("link2"), spec2.getLinkId()); + assertEquals(2, spec2.getPlugCount()); + assertEquals(2000.0, spec2.getPlugPower()); + } + + @Test + public void testReadWriteChargersWithAttributes() { + ChargingInfrastructureSpecificationDefaultImpl infrastructure = new ChargingInfrastructureSpecificationDefaultImpl(); + + AttributesImpl attributes1 = new AttributesImpl(); + attributes1.putAttribute("attribute1", "value1"); + + infrastructure.addChargerSpecification(ImmutableChargerSpecification.newBuilder() + .id(Id.create("charger1", Charger.class)) // + .chargerType("type1") // + .linkId(Id.createLinkId("link1")) // + .plugCount(1) // + .plugPower(1000.0) // + .attributes(attributes1) // + .build()); + + AttributesImpl attributes2 = new AttributesImpl(); + attributes2.putAttribute("attribute2", "value2"); + + infrastructure.addChargerSpecification(ImmutableChargerSpecification.newBuilder() + .id(Id.create("charger2", Charger.class)) // + .chargerType("type2") // + .linkId(Id.createLinkId("link2")) // + .plugCount(2) // + .plugPower(2000.0) // + .attributes(attributes2) // + .build()); + + String path = utils.getOutputDirectory() + "/chargers_with_attributes.xml"; + new ChargerWriter(infrastructure.getChargerSpecifications().values().stream()).write(path); + + ChargingInfrastructureSpecificationDefaultImpl readInfrastructure = new ChargingInfrastructureSpecificationDefaultImpl(); + new ChargerReader(readInfrastructure).readFile(path); + + ChargerSpecification spec1 = readInfrastructure.getChargerSpecifications() + .get(Id.create("charger1", Charger.class)); + assertEquals("type1", spec1.getChargerType()); + assertEquals(Id.createLinkId("link1"), spec1.getLinkId()); + assertEquals(1, spec1.getPlugCount()); + assertEquals(1000.0, spec1.getPlugPower()); + + assertEquals("value1", (String) spec1.getAttributes().getAttribute("attribute1")); + + ChargerSpecification spec2 = readInfrastructure.getChargerSpecifications() + .get(Id.create("charger2", Charger.class)); + assertEquals("type2", spec2.getChargerType()); + assertEquals(Id.createLinkId("link2"), spec2.getLinkId()); + assertEquals(2, spec2.getPlugCount()); + assertEquals(2000.0, spec2.getPlugPower()); + + assertEquals("value2", (String) spec2.getAttributes().getAttribute("attribute2")); + } +} diff --git a/matsim/src/main/resources/dtd/chargers_v1.dtd b/matsim/src/main/resources/dtd/chargers_v1.dtd index 5e849dddd91..c9c4f13184d 100644 --- a/matsim/src/main/resources/dtd/chargers_v1.dtd +++ b/matsim/src/main/resources/dtd/chargers_v1.dtd @@ -9,7 +9,7 @@ - + @@ -21,3 +21,10 @@ plug_power CDATA #REQUIRED plug_count CDATA #IMPLIED type CDATA #IMPLIED > + + + + + From 826595e62b4e302cb2c19cefa934a418f04486e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20H=C3=B6rl?= Date: Fri, 15 Nov 2024 15:57:11 +0100 Subject: [PATCH 34/53] feat: generalize multimodal link chooser (#3536) * feat: generalize multimodal link chooser * update test * make method private --- .../org/matsim/core/router/MultimodalLinkChooser.java | 5 ++--- .../core/router/MultimodalLinkChooserDefaultImpl.java | 11 ++++++++++- .../router/NetworkRoutingInclAccessEgressModule.java | 5 ++--- ...java => MultimodalLinkChooserDefaultImplTest.java} | 8 +++++--- 4 files changed, 19 insertions(+), 10 deletions(-) rename matsim/src/test/java/org/matsim/core/router/{MultimodalLinkChooserTest.java => MultimodalLinkChooserDefaultImplTest.java} (92%) diff --git a/matsim/src/main/java/org/matsim/core/router/MultimodalLinkChooser.java b/matsim/src/main/java/org/matsim/core/router/MultimodalLinkChooser.java index a7239e98198..4d8cf318622 100644 --- a/matsim/src/main/java/org/matsim/core/router/MultimodalLinkChooser.java +++ b/matsim/src/main/java/org/matsim/core/router/MultimodalLinkChooser.java @@ -2,9 +2,8 @@ import org.matsim.api.core.v01.network.Link; import org.matsim.api.core.v01.network.Network; -import org.matsim.facilities.Facility; public interface MultimodalLinkChooser { - - public Link decideOnLink( final Facility facility, final Network network ); + public Link decideAccessLink(RoutingRequest request, Network network); + public Link decideEgressLink(RoutingRequest request, Network network); } diff --git a/matsim/src/main/java/org/matsim/core/router/MultimodalLinkChooserDefaultImpl.java b/matsim/src/main/java/org/matsim/core/router/MultimodalLinkChooserDefaultImpl.java index cd37d0f0098..00b93eb363a 100644 --- a/matsim/src/main/java/org/matsim/core/router/MultimodalLinkChooserDefaultImpl.java +++ b/matsim/src/main/java/org/matsim/core/router/MultimodalLinkChooserDefaultImpl.java @@ -15,7 +15,16 @@ class MultimodalLinkChooserDefaultImpl implements MultimodalLinkChooser { private static final Logger log = LogManager.getLogger( FacilitiesUtils.class ) ; @Override - public Link decideOnLink(Facility facility, Network network) { + public Link decideAccessLink(RoutingRequest request, Network network) { + return decideOnLink(request.getFromFacility(), network); + } + + @Override + public Link decideEgressLink(RoutingRequest request, Network network) { + return decideOnLink(request.getToFacility(), network); + } + + private Link decideOnLink(Facility facility, Network network) { Link accessActLink = null ; Id accessActLinkId = null ; diff --git a/matsim/src/main/java/org/matsim/core/router/NetworkRoutingInclAccessEgressModule.java b/matsim/src/main/java/org/matsim/core/router/NetworkRoutingInclAccessEgressModule.java index 1a24567b1dd..39338b527dd 100644 --- a/matsim/src/main/java/org/matsim/core/router/NetworkRoutingInclAccessEgressModule.java +++ b/matsim/src/main/java/org/matsim/core/router/NetworkRoutingInclAccessEgressModule.java @@ -140,9 +140,8 @@ public synchronized List calcRoute(RoutingRequest request Gbl.assertNotNull(fromFacility); Gbl.assertNotNull(toFacility); - Link accessActLink = multimodalLinkChooser.decideOnLink(fromFacility, filteredNetwork); - - Link egressActLink = multimodalLinkChooser.decideOnLink(toFacility, filteredNetwork); + Link accessActLink = multimodalLinkChooser.decideAccessLink(request, filteredNetwork); + Link egressActLink = multimodalLinkChooser.decideEgressLink(request, filteredNetwork); double now = departureTime; diff --git a/matsim/src/test/java/org/matsim/core/router/MultimodalLinkChooserTest.java b/matsim/src/test/java/org/matsim/core/router/MultimodalLinkChooserDefaultImplTest.java similarity index 92% rename from matsim/src/test/java/org/matsim/core/router/MultimodalLinkChooserTest.java rename to matsim/src/test/java/org/matsim/core/router/MultimodalLinkChooserDefaultImplTest.java index 78a0dba6426..cb93b4aff0b 100644 --- a/matsim/src/test/java/org/matsim/core/router/MultimodalLinkChooserTest.java +++ b/matsim/src/test/java/org/matsim/core/router/MultimodalLinkChooserDefaultImplTest.java @@ -41,7 +41,7 @@ * */ -public class MultimodalLinkChooserTest { +public class MultimodalLinkChooserDefaultImplTest { @Test void testDecideOnLink() { @@ -75,11 +75,13 @@ void testDecideOnLink() { MultimodalLinkChooser linkChooser = new MultimodalLinkChooserDefaultImpl(); - Link linkFromFacLinkId = linkChooser.decideOnLink(facilityLinkIdNotNull, network); + RoutingRequest request = DefaultRoutingRequest.of(facilityLinkIdNotNull, facilityLinkIdNull, 0, null, null); + + Link linkFromFacLinkId = linkChooser.decideAccessLink(request, network); Assertions.assertEquals(networkLink, linkFromFacLinkId); - Link linkFromFacCoord = linkChooser.decideOnLink(facilityLinkIdNull, network); + Link linkFromFacCoord = linkChooser.decideEgressLink(request, network); Assertions.assertEquals(networkLink, linkFromFacCoord); From ecd5343ad7bf97ef3e510321598d23e79e870787 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20R=C3=B6der?= Date: Wed, 13 Nov 2024 11:23:11 +0100 Subject: [PATCH 35/53] flush only at the end Otherwise, compression algorithms cannot reach their full potential --- .../src/main/java/org/matsim/facilities/FacilitiesWriterV1.java | 1 - .../src/main/java/org/matsim/facilities/FacilitiesWriterV2.java | 1 - 2 files changed, 2 deletions(-) diff --git a/matsim/src/main/java/org/matsim/facilities/FacilitiesWriterV1.java b/matsim/src/main/java/org/matsim/facilities/FacilitiesWriterV1.java index b312ad56cc6..17751b78d4c 100644 --- a/matsim/src/main/java/org/matsim/facilities/FacilitiesWriterV1.java +++ b/matsim/src/main/java/org/matsim/facilities/FacilitiesWriterV1.java @@ -99,7 +99,6 @@ private void writeFacility(final ActivityFacilityImpl f) { } this.attributesWriter.writeAttributes("\t\t", this.writer, f.getAttributes(), false); this.endFacility(); - this.writer.flush(); } catch (IOException e) { throw new UncheckedIOException(e); } diff --git a/matsim/src/main/java/org/matsim/facilities/FacilitiesWriterV2.java b/matsim/src/main/java/org/matsim/facilities/FacilitiesWriterV2.java index a740d2ae014..d156cda5ff0 100644 --- a/matsim/src/main/java/org/matsim/facilities/FacilitiesWriterV2.java +++ b/matsim/src/main/java/org/matsim/facilities/FacilitiesWriterV2.java @@ -99,7 +99,6 @@ private void writeFacility(final ActivityFacilityImpl f) { } this.attributesWriter.writeAttributes("\t\t", this.writer, f.getAttributes(), false); this.endFacility(); - this.writer.flush(); } catch (IOException e) { throw new UncheckedIOException(e); } From f394017c877838887774e64502b53b782a9b5390 Mon Sep 17 00:00:00 2001 From: Tobias Kohl Date: Mon, 18 Nov 2024 15:24:17 +0100 Subject: [PATCH 36/53] introduce now necessary network mode to generated vehicles --- .../org/matsim/pt/utils/CreateVehiclesForSchedule.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/matsim/src/main/java/org/matsim/pt/utils/CreateVehiclesForSchedule.java b/matsim/src/main/java/org/matsim/pt/utils/CreateVehiclesForSchedule.java index 3adbd0b8407..287fac979f9 100644 --- a/matsim/src/main/java/org/matsim/pt/utils/CreateVehiclesForSchedule.java +++ b/matsim/src/main/java/org/matsim/pt/utils/CreateVehiclesForSchedule.java @@ -21,6 +21,7 @@ package org.matsim.pt.utils; import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.TransportMode; import org.matsim.pt.transitSchedule.api.Departure; import org.matsim.pt.transitSchedule.api.TransitLine; import org.matsim.pt.transitSchedule.api.TransitRoute; @@ -45,13 +46,18 @@ public CreateVehiclesForSchedule(final TransitSchedule schedule, final Vehicles this.schedule = schedule; this.vehicles = vehicles; } - + public void run() { + run(TransportMode.car); + } + + public void run(String networkMode) { VehiclesFactory vb = this.vehicles.getFactory(); VehicleType vehicleType = vb.createVehicleType(Id.create("defaultTransitVehicleType", VehicleType.class)); // VehicleCapacity capacity = new VehicleCapacity(); vehicleType.getCapacity().setSeats( 101 ); vehicleType.getCapacity().setStandingRoom( 0 ); + vehicleType.setNetworkMode(networkMode); // vehicleType.setCapacity(capacity); this.vehicles.addVehicleType(vehicleType); From b1ba80707f1c0ca7beab49955d253e72376adb00 Mon Sep 17 00:00:00 2001 From: janekdererste Date: Mon, 18 Nov 2024 16:27:45 +0100 Subject: [PATCH 37/53] Deprecate withHoles options for 'TrafficDynamics'. Also, we have deprecated everything except INFLOW_FROM_FDIAG in InflowCapacitySetting --- .../core/config/groups/QSimConfigGroup.java | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/matsim/src/main/java/org/matsim/core/config/groups/QSimConfigGroup.java b/matsim/src/main/java/org/matsim/core/config/groups/QSimConfigGroup.java index f8d59f01e01..97c175243e0 100644 --- a/matsim/src/main/java/org/matsim/core/config/groups/QSimConfigGroup.java +++ b/matsim/src/main/java/org/matsim/core/config/groups/QSimConfigGroup.java @@ -431,8 +431,15 @@ public void setInsertingWaitingVehiclesBeforeDrivingVehicles(boolean val) { this.insertingWaitingVehiclesBeforeDrivingVehicles = val; } + /** + * This determines the traffic dynamics of a link. The default is 'queue', but the recommended setting is kinematic waves. + * + * DEPRECATION NOTE: 'withHoles' is deprecated, use 'kinematicWaves' instead, as that uses 'withHoles' and adds an inflow capacity on top. + */ public enum TrafficDynamics { - queue, withHoles, + queue, + @Deprecated + withHoles, kinematicWaves // MATSim-630; previously, the switch was InflowConstraint.maxflowFromFdiag. Amit Jan 2017. } @@ -440,11 +447,19 @@ public enum TrafficDynamics { * Defines how the qsim sets the inflow and/or how it reacts to link attributes which are inconsistent with regard to the fundamental diagram.
* *

  • Note that {@code MAX_CAP_FOR_ONE_LANE} is backwards-compatible but always sets the inflow capacity to the maximum according to the fundamental diagram for one lane, - * so it essentially sets the inflow capacity too low for multiple-lane-links.
  • - *
  • {@code INFLOW_FROM_FDIAG} sets the inflow capacity to maximum flow capacity according to the fundamental diagram, assuming the nr of lanes in the link attributes to be correct.
  • - *
  • {@code NR_OF_LANES_FROM_FDIAG} sets the number of lanes to minimum required according to the fundamental diagram, assuming the flow capacity in the link attributes to be correct.
  • + * so it essentially sets the inflow capacity too low for multiple-lane-links. DEPRECATED: This is only for backwards compatibility. Use + * INFLOW_FROM_FDIAG instead. + *
  • {@code INFLOW_FROM_FDIAG} sets the inflow capacity to maximum flow capacity according to the + * fundamental diagram, assuming the nr of lanes in the link attributes to be correct.
  • + *
  • {@code NR_OF_LANES_FROM_FDIAG} sets the number of lanes to minimum required according to the fundamental + * diagram, assuming the flow capacity in the link attributes to be correct. DEPRECATED: In practice the other setting is used most often! Use\ + * INFLOW_FROM_FDIAG instead.
  • */ - public enum InflowCapacitySetting {INFLOW_FROM_FDIAG, NR_OF_LANES_FROM_FDIAG, MAX_CAP_FOR_ONE_LANE} + public enum InflowCapacitySetting {INFLOW_FROM_FDIAG, + @Deprecated + NR_OF_LANES_FROM_FDIAG, + @Deprecated + MAX_CAP_FOR_ONE_LANE} @StringSetter(TRAFFIC_DYNAMICS) public void setTrafficDynamics(final TrafficDynamics str) { From b123ef4c3b47d59adf1bcd89c5ad0ae332421809 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20H=C3=B6rl?= Date: Tue, 19 Nov 2024 13:53:13 +0100 Subject: [PATCH 38/53] feat(dvrp): cached free-speed matrices (#3567) * feat(dvrp): cached travel time matrices * cleanup --- .../router/DvrpModeRoutingNetworkModule.java | 15 +- .../matsim/contrib/dvrp/run/DvrpModule.java | 14 +- .../skims/DvrpTravelTimeMatrixParams.java | 4 + .../zone/skims/FreeSpeedTravelTimeMatrix.java | 167 ++++++++++++++++++ .../skims/FreeSpeedTravelTimeMatrixTest.java | 41 +++++ 5 files changed, 236 insertions(+), 5 deletions(-) diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/router/DvrpModeRoutingNetworkModule.java b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/router/DvrpModeRoutingNetworkModule.java index 076ce4876ec..3b8463a1119 100644 --- a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/router/DvrpModeRoutingNetworkModule.java +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/router/DvrpModeRoutingNetworkModule.java @@ -20,6 +20,7 @@ package org.matsim.contrib.dvrp.router; +import java.io.File; import java.util.Collections; import java.util.Set; @@ -32,6 +33,7 @@ import org.matsim.contrib.zone.skims.FreeSpeedTravelTimeMatrix; import org.matsim.contrib.zone.skims.TravelTimeMatrix; import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigGroup; import org.matsim.core.config.groups.GlobalConfigGroup; import org.matsim.core.config.groups.QSimConfigGroup; import org.matsim.core.network.NetworkUtils; @@ -86,9 +88,16 @@ public void install() { DvrpTravelTimeMatrixParams matrixParams = dvrpConfigGroup.getTravelTimeMatrixParams(); ZoneSystem zoneSystem = ZoneSystemUtils.createZoneSystem(getConfig().getContext(), network, matrixParams.getZoneSystemParams(), getConfig().global().getCoordinateSystem(), zone -> true); - return FreeSpeedTravelTimeMatrix.createFreeSpeedMatrix(network, zoneSystem, - matrixParams, globalConfigGroup.getNumberOfThreads(), - qSimConfigGroup.getTimeStepSize()); + + + if (matrixParams.cachePath == null) { + return FreeSpeedTravelTimeMatrix.createFreeSpeedMatrix(network, zoneSystem, matrixParams, globalConfigGroup.getNumberOfThreads(), + qSimConfigGroup.getTimeStepSize()); + } else { + File cachePath = new File(ConfigGroup.getInputFileURL(getConfig().getContext(), matrixParams.cachePath).getPath()); + return FreeSpeedTravelTimeMatrix.createFreeSpeedMatrixFromCache(network, zoneSystem, matrixParams, globalConfigGroup.getNumberOfThreads(), + qSimConfigGroup.getTimeStepSize(), cachePath); + } })).in(Singleton.class); } else { //use DVRP-routing (dvrp-global) network diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/run/DvrpModule.java b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/run/DvrpModule.java index d31fe11499d..769ea423515 100644 --- a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/run/DvrpModule.java +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/run/DvrpModule.java @@ -19,7 +19,7 @@ package org.matsim.contrib.dvrp.run; -import jakarta.inject.Provider; +import java.io.File; import org.matsim.api.core.v01.network.Network; import org.matsim.contrib.common.zones.ZoneSystem; @@ -33,6 +33,7 @@ import org.matsim.contrib.zone.skims.DvrpTravelTimeMatrixParams; import org.matsim.contrib.zone.skims.FreeSpeedTravelTimeMatrix; import org.matsim.contrib.zone.skims.TravelTimeMatrix; +import org.matsim.core.config.ConfigGroup; import org.matsim.core.config.groups.QSimConfigGroup; import org.matsim.core.controler.AbstractModule; import org.matsim.core.mobsim.framework.MobsimTimer; @@ -44,6 +45,8 @@ import com.google.inject.name.Named; import com.google.inject.name.Names; +import jakarta.inject.Provider; + /** * This module initialises generic (i.e. not taxi or drt-specific) AND global (not mode-specific) dvrp objects. *

    @@ -90,8 +93,15 @@ public TravelTimeMatrix get() { DvrpTravelTimeMatrixParams matrixParams = dvrpConfigGroup.getTravelTimeMatrixParams(); ZoneSystem zoneSystem = ZoneSystemUtils.createZoneSystem(getConfig().getContext(), network, matrixParams.getZoneSystemParams(), getConfig().global().getCoordinateSystem(), zone -> true); - return FreeSpeedTravelTimeMatrix.createFreeSpeedMatrix(network, zoneSystem, params, numberOfThreads, + + if (params.cachePath == null) { + return FreeSpeedTravelTimeMatrix.createFreeSpeedMatrix(network, zoneSystem, params, numberOfThreads, qSimConfigGroup.getTimeStepSize()); + } else { + File cachePath = new File(ConfigGroup.getInputFileURL(getConfig().getContext(), params.cachePath).getPath()); + return FreeSpeedTravelTimeMatrix.createFreeSpeedMatrixFromCache(network, zoneSystem, params, numberOfThreads, + qSimConfigGroup.getTimeStepSize(), cachePath); + } } }).in(Singleton.class); diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/zone/skims/DvrpTravelTimeMatrixParams.java b/contribs/dvrp/src/main/java/org/matsim/contrib/zone/skims/DvrpTravelTimeMatrixParams.java index 52c3c332f09..9b959a87ba2 100644 --- a/contribs/dvrp/src/main/java/org/matsim/contrib/zone/skims/DvrpTravelTimeMatrixParams.java +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/zone/skims/DvrpTravelTimeMatrixParams.java @@ -28,6 +28,7 @@ import org.matsim.contrib.common.zones.systems.grid.GISFileZoneSystemParams; import org.matsim.contrib.common.zones.systems.grid.h3.H3GridZoneSystemParams; import org.matsim.contrib.common.zones.systems.grid.square.SquareGridZoneSystemParams; +import org.matsim.core.config.ReflectiveConfigGroup.Parameter; /** * @author Michal Maciejewski (michalm) @@ -59,6 +60,9 @@ public class DvrpTravelTimeMatrixParams extends ReflectiveConfigGroupWithConfigu @NotNull private ZoneSystemParams zoneSystemParams; + @Parameter + @Comment("Caches the travel time matrix data into a binary file. If the file exists, the matrix will be read from the file, if not, the file will be created.") + public String cachePath = null; public DvrpTravelTimeMatrixParams() { super(SET_NAME); diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/zone/skims/FreeSpeedTravelTimeMatrix.java b/contribs/dvrp/src/main/java/org/matsim/contrib/zone/skims/FreeSpeedTravelTimeMatrix.java index 6351dd3bce8..356625f4295 100644 --- a/contribs/dvrp/src/main/java/org/matsim/contrib/zone/skims/FreeSpeedTravelTimeMatrix.java +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/zone/skims/FreeSpeedTravelTimeMatrix.java @@ -20,14 +20,34 @@ package org.matsim.contrib.zone.skims; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; + +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.IdSet; import org.matsim.api.core.v01.network.Network; import org.matsim.api.core.v01.network.Node; +import org.matsim.contrib.common.zones.Zone; import org.matsim.contrib.common.zones.ZoneSystem; import org.matsim.contrib.common.zones.ZoneSystemUtils; import org.matsim.contrib.dvrp.router.TimeAsTravelDisutility; import org.matsim.contrib.dvrp.trafficmonitoring.QSimFreeSpeedTravelTime; +import org.matsim.contrib.zone.skims.SparseMatrix.NodeAndTime; +import org.matsim.contrib.zone.skims.SparseMatrix.SparseRow; import org.matsim.core.router.util.TravelTime; +import com.google.common.base.Verify; +import com.google.common.collect.Sets; + /** * @author Michal Maciejewski (michalm) */ @@ -68,4 +88,151 @@ public int getTravelTime(Node fromNode, Node toNode, double departureTime) { public int getZonalTravelTime(Node fromNode, Node toNode, double departureTime) { return freeSpeedTravelTimeMatrix.get(zoneSystem.getZoneForNodeId(fromNode.getId()).orElseThrow(), zoneSystem.getZoneForNodeId(toNode.getId()).orElseThrow()); } + + public static FreeSpeedTravelTimeMatrix createFreeSpeedMatrixFromCache(Network dvrpNetwork, ZoneSystem zoneSystem, DvrpTravelTimeMatrixParams params, int numberOfThreads, double qSimTimeStepSize, File cachePath) { + boolean exists = cachePath.exists(); + + final FreeSpeedTravelTimeMatrix matrix; + if (exists) { + matrix = new FreeSpeedTravelTimeMatrix(dvrpNetwork, zoneSystem, cachePath); + } else { + matrix = createFreeSpeedMatrix(dvrpNetwork, zoneSystem, params, numberOfThreads, qSimTimeStepSize); + matrix.write(cachePath, dvrpNetwork); + } + + return matrix; + } + + public FreeSpeedTravelTimeMatrix(Network dvrpNetwork, ZoneSystem zoneSystem, File cachePath) { + this.zoneSystem = zoneSystem; + + try (DataInputStream inputStream = new DataInputStream(new FileInputStream(cachePath))) { + // number of zones + int numberOfZones = inputStream.readInt(); + Verify.verify(numberOfZones == zoneSystem.getZones().size()); + + // read zone list + List> zoneIds = new ArrayList<>(numberOfZones); + for (int i = 0; i < numberOfZones; i++) { + zoneIds.add(Id.create(inputStream.readUTF(), Zone.class)); + } + + IdSet systemZones = new IdSet<>(Zone.class); + systemZones.addAll(zoneSystem.getZones().keySet()); + + IdSet dataZones = new IdSet<>(Zone.class); + dataZones.addAll(zoneIds); + + Verify.verify(Sets.difference(systemZones, dataZones).size() == 0); + Verify.verify(Sets.difference(dataZones, systemZones).size() == 0); + + // fill matrix + freeSpeedTravelTimeMatrix = new Matrix(new HashSet<>(zoneSystem.getZones().values())); + + for (var from : zoneIds) { + for (var to : zoneIds) { + Zone fromZone = zoneSystem.getZones().get(from); + Zone toZone = zoneSystem.getZones().get(to); + freeSpeedTravelTimeMatrix.set(fromZone, toZone, inputStream.readInt()); + } + } + + // sparse matrix available? + boolean hasSparseMatrix = inputStream.readBoolean(); + + if (!hasSparseMatrix) { + freeSpeedTravelTimeSparseMatrix = null; + } else { + freeSpeedTravelTimeSparseMatrix = new SparseMatrix(); + + // read nodes + int numberOfNodes = inputStream.readInt(); + Verify.verify(numberOfNodes == dvrpNetwork.getNodes().size()); + + List nodes = new ArrayList<>(numberOfNodes); + for (int i = 0; i < numberOfNodes; i++) { + Id nodeId = Id.createNodeId(inputStream.readUTF()); + nodes.add(Objects.requireNonNull(dvrpNetwork.getNodes().get(nodeId))); + } + + // read rows + for (int i = 0; i < numberOfNodes; i++) { + Node from = nodes.get(i); + int numberOfElements = inputStream.readInt(); + + if (numberOfElements > 0) { + List nodeTimeList = new ArrayList<>(numberOfElements); + + for (int j = 0; j < numberOfElements; j++) { + Node to = nodes.get(inputStream.readInt()); + int value = inputStream.readInt(); + + nodeTimeList.add(new NodeAndTime(to.getId().index(), value)); + } + + SparseRow row = new SparseRow(nodeTimeList); + freeSpeedTravelTimeSparseMatrix.setRow(from, row); + } + } + } + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void write(File outputPath, Network dvrpNetwork) { + try (DataOutputStream outputStream = new DataOutputStream(new FileOutputStream(outputPath))) { + // obtain fixed order of zones + List zones = new ArrayList<>(zoneSystem.getZones().values()); + outputStream.writeInt(zones.size()); + for (Zone zone : zones) { + outputStream.writeUTF(zone.getId().toString()); + } + + // write matrix + for (var from : zones) { + for (var to : zones) { + int value = freeSpeedTravelTimeMatrix.get(from, to); + outputStream.writeInt(value); + } + } + + // write if sparse exists + outputStream.writeBoolean(freeSpeedTravelTimeSparseMatrix != null); + + if (freeSpeedTravelTimeSparseMatrix != null) { + // obtain fixed order of nodes + List nodes = new ArrayList<>(dvrpNetwork.getNodes().values()); + outputStream.writeInt(nodes.size()); + for (Node node : nodes) { + outputStream.writeUTF(node.getId().toString()); + } + + for (Node from : nodes) { + // write size of the matrix row + int rowSize = 0; + + for (Node to : nodes) { + int value = freeSpeedTravelTimeSparseMatrix.get(from, to); + if (value >= 0) { + rowSize++; + } + } + + outputStream.writeInt(rowSize); + + // write matrix row + for (Node to : nodes) { + int value = freeSpeedTravelTimeSparseMatrix.get(from, to); + if (value >= 0) { + outputStream.writeInt(nodes.indexOf(to)); + outputStream.writeInt(value); + } + } + } + } + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } } diff --git a/contribs/dvrp/src/test/java/org/matsim/contrib/zone/skims/FreeSpeedTravelTimeMatrixTest.java b/contribs/dvrp/src/test/java/org/matsim/contrib/zone/skims/FreeSpeedTravelTimeMatrixTest.java index 8aaf6001258..2cf4cc30934 100644 --- a/contribs/dvrp/src/test/java/org/matsim/contrib/zone/skims/FreeSpeedTravelTimeMatrixTest.java +++ b/contribs/dvrp/src/test/java/org/matsim/contrib/zone/skims/FreeSpeedTravelTimeMatrixTest.java @@ -22,7 +22,10 @@ import static org.assertj.core.api.Assertions.assertThat; +import java.io.File; + import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; import org.matsim.api.core.v01.Coord; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Network; @@ -30,12 +33,16 @@ import org.matsim.contrib.common.zones.ZoneSystem; import org.matsim.contrib.common.zones.systems.grid.square.SquareGridZoneSystem; import org.matsim.core.network.NetworkUtils; +import org.matsim.testcases.MatsimTestUtils; /** * @author Michal Maciejewski (michalm) */ public class FreeSpeedTravelTimeMatrixTest { + @RegisterExtension + MatsimTestUtils utils = new MatsimTestUtils(); + private final Network network = NetworkUtils.createNetwork(); private final Node nodeA = NetworkUtils.createAndAddNode(network, Id.createNodeId("A"), new Coord(0, 0)); private final Node nodeB = NetworkUtils.createAndAddNode(network, Id.createNodeId("B"), new Coord(150, 150)); @@ -66,6 +73,23 @@ void matrix() { assertThat(matrix.getTravelTime(nodeC, nodeA, 0)).isEqualTo(0); assertThat(matrix.getTravelTime(nodeB, nodeC, 0)).isEqualTo(20 + 1); // 1 s for moving over nodes assertThat(matrix.getTravelTime(nodeC, nodeB, 0)).isEqualTo(10 + 1); // 1 s for moving over nodes + + // write and read cache + File cachePath = new File(utils.getOutputDirectory(), "cache.bin"); + matrix.write(cachePath, network); + matrix = FreeSpeedTravelTimeMatrix.createFreeSpeedMatrixFromCache(network, zoneSystem, null, 1, 1, cachePath); + + // distances between central nodes: A and B + assertThat(matrix.getTravelTime(nodeA, nodeA, 0)).isEqualTo(0); + assertThat(matrix.getTravelTime(nodeA, nodeB, 0)).isEqualTo(10 + 1); // 1 s for moving over nodes + assertThat(matrix.getTravelTime(nodeB, nodeA, 0)).isEqualTo(20 + 1); // 1 s for moving over nodes + assertThat(matrix.getTravelTime(nodeB, nodeB, 0)).isEqualTo(0); + + // non-central node: C and A are in the same zone; A is the central node + assertThat(matrix.getTravelTime(nodeA, nodeC, 0)).isEqualTo(0); + assertThat(matrix.getTravelTime(nodeC, nodeA, 0)).isEqualTo(0); + assertThat(matrix.getTravelTime(nodeB, nodeC, 0)).isEqualTo(20 + 1); // 1 s for moving over nodes + assertThat(matrix.getTravelTime(nodeC, nodeB, 0)).isEqualTo(10 + 1); // 1 s for moving over nodes } @Test @@ -87,5 +111,22 @@ void sparseMatrix() { assertThat(matrix.getTravelTime(nodeC, nodeA, 0)).isEqualTo(9 + 1); // 1 s for moving over nodes assertThat(matrix.getTravelTime(nodeB, nodeC, 0)).isEqualTo(20 + 11 + 2); // 2 s for moving over nodes assertThat(matrix.getTravelTime(nodeC, nodeB, 0)).isEqualTo(10 + 9 + 2); // 2 s for moving over nodes + + // write and read cache + File cachePath = new File(utils.getOutputDirectory(), "cache.bin"); + matrix.write(cachePath, network); + matrix = FreeSpeedTravelTimeMatrix.createFreeSpeedMatrixFromCache(network, zoneSystem, null, 1, 1, cachePath); + + // distances between central nodes: A and B + assertThat(matrix.getTravelTime(nodeA, nodeA, 0)).isEqualTo(0); + assertThat(matrix.getTravelTime(nodeA, nodeB, 0)).isEqualTo(10 + 1); // 1 s for moving over nodes + assertThat(matrix.getTravelTime(nodeB, nodeA, 0)).isEqualTo(20 + 1); // 1 s for moving over nodes + assertThat(matrix.getTravelTime(nodeB, nodeB, 0)).isEqualTo(0); + + // non-central node: C and A are in the same zone; A is the central node + assertThat(matrix.getTravelTime(nodeA, nodeC, 0)).isEqualTo(11 + 1); // 1 s for moving over nodes + assertThat(matrix.getTravelTime(nodeC, nodeA, 0)).isEqualTo(9 + 1); // 1 s for moving over nodes + assertThat(matrix.getTravelTime(nodeB, nodeC, 0)).isEqualTo(20 + 11 + 2); // 2 s for moving over nodes + assertThat(matrix.getTravelTime(nodeC, nodeB, 0)).isEqualTo(10 + 9 + 2); // 2 s for moving over nodes } } From 64c38d20449b3950727522f700e2e06ffe2e657a Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Tue, 19 Nov 2024 14:47:19 +0100 Subject: [PATCH 39/53] Update pom.xml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit use §{project.parent.version}, because the expression ${parent.version} is deprecated. --- contribs/decongestion/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contribs/decongestion/pom.xml b/contribs/decongestion/pom.xml index 62d2f912040..992bd7c6a12 100644 --- a/contribs/decongestion/pom.xml +++ b/contribs/decongestion/pom.xml @@ -8,7 +8,7 @@ org.matsim.contrib otfvis - ${parent.version} + ${project.parent.version} test From 9a3872d58e83cea697720c3d560311f5b31fb7f3 Mon Sep 17 00:00:00 2001 From: Ricardo Ewert Date: Thu, 21 Nov 2024 14:02:27 +0100 Subject: [PATCH 40/53] update log massage --- .../freightDemandGeneration/FreightDemandGenerationUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contribs/application/src/main/java/org/matsim/freightDemandGeneration/FreightDemandGenerationUtils.java b/contribs/application/src/main/java/org/matsim/freightDemandGeneration/FreightDemandGenerationUtils.java index c60a8a39390..ede28ace76d 100644 --- a/contribs/application/src/main/java/org/matsim/freightDemandGeneration/FreightDemandGenerationUtils.java +++ b/contribs/application/src/main/java/org/matsim/freightDemandGeneration/FreightDemandGenerationUtils.java @@ -152,7 +152,7 @@ static void createDemandLocationsFile(Controler controler) { writer.flush(); } catch (IOException e) { - e.printStackTrace(); + log.error("Could not write job locations file under " + "/outputLocationFile.xml.gz"); } log.info("Wrote job locations file under " + "/outputLocationFile.xml.gz"); } From ecb29e8e767b221aab8cb7428d65415b80f1c484 Mon Sep 17 00:00:00 2001 From: Ricardo Ewert Date: Fri, 22 Nov 2024 09:53:28 +0100 Subject: [PATCH 41/53] rename method --- .../matsim/freightDemandGeneration/DemandReaderFromCSV.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DemandReaderFromCSV.java b/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DemandReaderFromCSV.java index e39eedd9ad4..d79a6e77a1c 100644 --- a/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DemandReaderFromCSV.java +++ b/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DemandReaderFromCSV.java @@ -1003,7 +1003,7 @@ else if (numberOfPickupLocations != null) { } } if (combineSimilarJobs) - reduceNumberOfJobsIfSameCharacteristics(scenario, newDemandInformationElement); + combineSimilarJobs(scenario, newDemandInformationElement); } /** Creates a single shipment. @@ -1163,8 +1163,8 @@ private static int calculateDemandBasedOnLinkLength(int countOfLinks, int distri * @param scenario Scenario * @param newDemandInformationElement single DemandInformationElement */ - private static void reduceNumberOfJobsIfSameCharacteristics(Scenario scenario, - DemandInformationElement newDemandInformationElement) { + private static void combineSimilarJobs(Scenario scenario, + DemandInformationElement newDemandInformationElement) { log.warn( "The number of Jobs will be reduced if jobs have the same characteristics (e.g. time, location, carrier)"); From eec0eaa3b7f6a0e4d0c5f93e716d0fa7d2ea6442 Mon Sep 17 00:00:00 2001 From: Ricardo Ewert Date: Fri, 22 Nov 2024 09:54:16 +0100 Subject: [PATCH 42/53] rename method --- .../org/matsim/freightDemandGeneration/DemandReaderFromCSV.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DemandReaderFromCSV.java b/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DemandReaderFromCSV.java index d79a6e77a1c..25041119435 100644 --- a/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DemandReaderFromCSV.java +++ b/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DemandReaderFromCSV.java @@ -746,7 +746,7 @@ else if (samplingOption.equals("changeNumberOfLocationsWithDemand")) { } } if (combineSimilarJobs) - reduceNumberOfJobsIfSameCharacteristics(scenario, newDemandInformationElement); + combineSimilarJobs(scenario, newDemandInformationElement); } /** From 42e2633ce0bb69e933855fb2682e4e1647652e75 Mon Sep 17 00:00:00 2001 From: Ricardo Ewert Date: Fri, 22 Nov 2024 11:16:52 +0100 Subject: [PATCH 43/53] add configurable implementation of job duration calculation --- .../DefaultJobDurationCalculator.java | 42 ++++++++++ .../DemandReaderFromCSV.java | 84 +++++++++++-------- .../FreightDemandGeneration.java | 18 +++- .../JobDurationCalculator.java | 15 ++++ 4 files changed, 120 insertions(+), 39 deletions(-) create mode 100644 contribs/application/src/main/java/org/matsim/freightDemandGeneration/DefaultJobDurationCalculator.java create mode 100644 contribs/application/src/main/java/org/matsim/freightDemandGeneration/JobDurationCalculator.java diff --git a/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DefaultJobDurationCalculator.java b/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DefaultJobDurationCalculator.java new file mode 100644 index 00000000000..d64b7aad509 --- /dev/null +++ b/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DefaultJobDurationCalculator.java @@ -0,0 +1,42 @@ +package org.matsim.freightDemandGeneration; + +import org.matsim.freight.carriers.Carrier; + +public class DefaultJobDurationCalculator implements JobDurationCalculator { + @Override + public double calculateServiceDuration(Integer serviceTimePerUnit, int demandForThisService) { + return getDefaultCalculation(serviceTimePerUnit, demandForThisService); + } + + @Override + public double calculatePickupDuration(Integer pickupDurationPerUnit, int demandForThisShipment) { + return getDefaultCalculation(pickupDurationPerUnit, demandForThisShipment); + } + + @Override + public double calculateDeliveryDuration(Integer deliveryDurationPerUnit, int demandForThisShipment) { + return getDefaultCalculation(deliveryDurationPerUnit, demandForThisShipment); + } + + @Override + public void recalculateServiceDurations(Carrier thisCarrier) { + // Do nothing + } + + @Override + public void recalculateShipmentDurations(Carrier thisCarrier) { + // Do nothing + } + + /** + * @param serviceTimePerUnit service time per unit + * @param demandForThisService demand for this service + * @return default calculation + */ + private int getDefaultCalculation(int serviceTimePerUnit, int demandForThisService) { + if (demandForThisService == 0) + return serviceTimePerUnit; + else + return serviceTimePerUnit * demandForThisService; + } +} diff --git a/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DemandReaderFromCSV.java b/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DemandReaderFromCSV.java index 25041119435..7407561a78c 100644 --- a/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DemandReaderFromCSV.java +++ b/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DemandReaderFromCSV.java @@ -324,16 +324,18 @@ public String getTypeOfDemand() { * @param crsTransformationNetworkAndShape CoordinateTransformation for the network and shape file * @param population Population * @param shapeCategory Column name in the shape file for the data connection in the csv files - * @throws IOException if the csv file cannot be read + * @param jobDurationCalculator Calculator for the job duration + * @throws IOException if the csv file cannot be read */ static void readAndCreateDemand(Scenario scenario, Path csvLocationDemand, ShpOptions.Index indexShape, boolean combineSimilarJobs, - CoordinateTransformation crsTransformationNetworkAndShape, Population population, String shapeCategory) throws IOException { + CoordinateTransformation crsTransformationNetworkAndShape, Population population, String shapeCategory, + JobDurationCalculator jobDurationCalculator) throws IOException { Set demandInformation = readDemandInformation(csvLocationDemand); checkNewDemand(scenario, demandInformation, indexShape, shapeCategory); createDemandForCarriers(scenario, indexShape, demandInformation, population, combineSimilarJobs, - crsTransformationNetworkAndShape); + crsTransformationNetworkAndShape, jobDurationCalculator); } /** @@ -538,25 +540,26 @@ static void checkNewDemand(Scenario scenario, Set dema /** * Creates for every demand information the services/shipments for the carriers * - * @param scenario Scenario - * @param indexShape ShpOptions.Index for the shape file - * @param demandInformation Set with the demand information - * @param population Population - * @param combineSimilarJobs boolean if the jobs of the same carrier with same location and time will be combined - * @param crsTransformationNetworkAndShape CoordinateTransformation for the network and shape file + * @param scenario Scenario + * @param indexShape ShpOptions.Index for the shape file + * @param demandInformation Set with the demand information + * @param population Population + * @param combineSimilarJobs boolean if the jobs of the same carrier with same location and time will be combined + * @param crsTransformationNetworkAndShape CoordinateTransformation for the network and shape file + * @param jobDurationCalculator Calculator for the job duration */ static void createDemandForCarriers(Scenario scenario, ShpOptions.Index indexShape, - Set demandInformation, Population population, boolean combineSimilarJobs, - CoordinateTransformation crsTransformationNetworkAndShape) { + Set demandInformation, Population population, boolean combineSimilarJobs, + CoordinateTransformation crsTransformationNetworkAndShape, JobDurationCalculator jobDurationCalculator) { for (DemandInformationElement newDemandInformationElement : demandInformation) { log.info("Create demand for carrier {}", newDemandInformationElement.getCarrierName()); if (newDemandInformationElement.getTypeOfDemand().equals("service")) - createServices(scenario, newDemandInformationElement, indexShape, population, combineSimilarJobs, - crsTransformationNetworkAndShape); + createServices(scenario, newDemandInformationElement, indexShape, population, + crsTransformationNetworkAndShape, jobDurationCalculator); else if (newDemandInformationElement.getTypeOfDemand().equals("shipment")) - createShipments(scenario, newDemandInformationElement, indexShape, population, combineSimilarJobs, - crsTransformationNetworkAndShape); + createShipments(scenario, newDemandInformationElement, indexShape, population, + crsTransformationNetworkAndShape, jobDurationCalculator); } } @@ -564,16 +567,16 @@ else if (newDemandInformationElement.getTypeOfDemand().equals("shipment")) /** * Creates the services. * - * @param scenario Scenario - * @param newDemandInformationElement single DemandInformationElement - * @param indexShape ShpOptions.Index - * @param population Population - * @param combineSimilarJobs boolean if the jobs of the same carrier with same location and time will be combined - * @param crsTransformationNetworkAndShape CoordinateTransformation for the network and shape file + * @param scenario Scenario + * @param newDemandInformationElement single DemandInformationElement + * @param indexShape ShpOptions.Index + * @param population Population + * @param crsTransformationNetworkAndShape CoordinateTransformation for the network and shape file + * @param jobDurationCalculator Calculator for the job duration */ private static void createServices(Scenario scenario, DemandInformationElement newDemandInformationElement, - ShpOptions.Index indexShape, Population population, boolean combineSimilarJobs, - CoordinateTransformation crsTransformationNetworkAndShape) { + ShpOptions.Index indexShape, Population population, + CoordinateTransformation crsTransformationNetworkAndShape, JobDurationCalculator jobDurationCalculator) { int countOfLinks = 1; int distributedDemand = 0; @@ -643,8 +646,8 @@ else if (samplingOption.equals("changeNumberOfLocationsWithDemand")) { Link link = findNextUsedLink(scenario, indexShape, possibleLinksForService, numberOfJobs, areasForServiceLocations, locationsOfServices, usedServiceLocations, possiblePersonsForService, nearestLinkPerPerson, crsTransformationNetworkAndShape, i); - double serviceTime = newDemandInformationElement.getFirstJobElementTimePerUnit(); int demandForThisLink = 1; + double serviceTime = jobDurationCalculator.calculateServiceDuration(newDemandInformationElement.getFirstJobElementTimePerUnit(), demandForThisLink); usedServiceLocations.add(link.getId().toString()); Id idNewService = Id.create( createJobId(scenario, newDemandInformationElement, link.getId(), null), @@ -680,6 +683,9 @@ else if (samplingOption.equals("changeNumberOfLocationsWithDemand")) { singleDemandForThisLink = demandForThisLink - (numberOfJobsForDemand - 1) * singleDemandForThisLink; double serviceTime = newDemandInformationElement.getFirstJobElementTimePerUnit() * singleDemandForThisLink; + double serviceTime = jobDurationCalculator.calculateServiceDuration( + newDemandInformationElement.getFirstJobElementTimePerUnit(), singleDemandForThisLink); + Id idNewService = Id.create( createJobId(scenario, newDemandInformationElement, link.getId(), null), CarrierService.class); @@ -728,6 +734,8 @@ else if (samplingOption.equals("changeNumberOfLocationsWithDemand")) { serviceTime = newDemandInformationElement.getFirstJobElementTimePerUnit(); else serviceTime = newDemandInformationElement.getFirstJobElementTimePerUnit() * demandForThisLink; + double serviceTime = jobDurationCalculator.calculateServiceDuration( + newDemandInformationElement.getFirstJobElementTimePerUnit(), singleDemandForThisLink); usedServiceLocations.add(link.getId().toString()); Id idNewService = Id.create( @@ -752,16 +760,16 @@ else if (samplingOption.equals("changeNumberOfLocationsWithDemand")) { /** * Creates the shipments of a carrier. * - * @param scenario Scenario - * @param newDemandInformationElement single DemandInformationElement - * @param indexShape ShpOptions.Index for the shape file - * @param population Population - * @param combineSimilarJobs boolean if the jobs of the same carrier with same location and time will be combined - * @param crsTransformationNetworkAndShape CoordinateTransformation for the network and shape file + * @param scenario Scenario + * @param newDemandInformationElement single DemandInformationElement + * @param indexShape ShpOptions.Index for the shape file + * @param population Population + * @param crsTransformationNetworkAndShape CoordinateTransformation for the network and shape file + * @param jobDurationCalculator Calculator for the job duration */ private static void createShipments(Scenario scenario, DemandInformationElement newDemandInformationElement, - ShpOptions.Index indexShape, Population population, boolean combineSimilarJobs, - CoordinateTransformation crsTransformationNetworkAndShape) { + ShpOptions.Index indexShape, Population population, + CoordinateTransformation crsTransformationNetworkAndShape, JobDurationCalculator jobDurationCalculator) { int countOfLinks = 1; int distributedDemand = 0; @@ -900,7 +908,7 @@ else if (population == null) if (!usedDeliveryLocations.contains(linkDelivery.getId().toString())) usedDeliveryLocations.add(linkDelivery.getId().toString()); - createSingleShipment(scenario, newDemandInformationElement, linkPickup, linkDelivery, demandForThisLink); + createSingleShipment(scenario, newDemandInformationElement, linkPickup, linkDelivery, demandForThisLink, jobDurationCalculator); } } else // creates a demand on each link, demand depends on the length of the link @@ -968,7 +976,7 @@ else if (numberOfPickupLocations != null) { if (demandForThisLink > 0) { createSingleShipment(scenario, newDemandInformationElement, linkPickup, linkDelivery, - demandForThisLink); + demandForThisLink, jobDurationCalculator); } distributedDemand = distributedDemand + demandForThisLink; } @@ -998,7 +1006,7 @@ else if (numberOfPickupLocations != null) { usedDeliveryLocations.add(linkDelivery.getId().toString()); createSingleShipment(scenario, newDemandInformationElement, linkPickup, linkDelivery, - demandForThisLink); + demandForThisLink, jobDurationCalculator); distributedDemand = distributedDemand + demandForThisLink; } } @@ -1012,9 +1020,10 @@ else if (numberOfPickupLocations != null) { * @param linkPickup Link for the pickup * @param linkDelivery Link for the delivery * @param demandForThisLink Demand for this link + * @param jobDurationCalculator Calculator for the job duration */ private static void createSingleShipment(Scenario scenario, DemandInformationElement newDemandInformationElement, - Link linkPickup, Link linkDelivery, int demandForThisLink) { + Link linkPickup, Link linkDelivery, int demandForThisLink, JobDurationCalculator jobDurationCalculator) { Carrier thisCarrier = CarriersUtils.getCarriers(scenario).getCarriers() .get(Id.create(newDemandInformationElement.getCarrierName(), Carrier.class)); @@ -1038,6 +1047,9 @@ private static void createSingleShipment(Scenario scenario, DemandInformationEle serviceTimePickup = newDemandInformationElement.getFirstJobElementTimePerUnit() * singleDemandForThisLink; serviceTimeDelivery = newDemandInformationElement.getSecondJobElementTimePerUnit() * singleDemandForThisLink; } + double serviceTimePickup = jobDurationCalculator.calculatePickupDuration(newDemandInformationElement.getFirstJobElementTimePerUnit(), singleDemandForThisLink); + double serviceTimeDelivery = jobDurationCalculator.calculateDeliveryDuration(newDemandInformationElement.getSecondJobElementTimePerUnit(), singleDemandForThisLink); + CarrierShipment thisShipment = CarrierShipment.Builder .newInstance(idNewShipment, linkPickup.getId(), linkDelivery.getId(), singleDemandForThisLink) .setPickupServiceTime(serviceTimePickup).setPickupTimeWindow(timeWindowPickup) diff --git a/contribs/application/src/main/java/org/matsim/freightDemandGeneration/FreightDemandGeneration.java b/contribs/application/src/main/java/org/matsim/freightDemandGeneration/FreightDemandGeneration.java index 368dddaad69..ac3c44cb5a6 100644 --- a/contribs/application/src/main/java/org/matsim/freightDemandGeneration/FreightDemandGeneration.java +++ b/contribs/application/src/main/java/org/matsim/freightDemandGeneration/FreightDemandGeneration.java @@ -62,6 +62,8 @@ + " * these files are given in the example project. See: TODO", showDefaultValues = true) public class FreightDemandGeneration implements MATSimAppCommand { + private final JobDurationCalculator jobDurationCalculator; + private enum CarrierInputOptions { readCarrierFile, createCarriersFromCSV, addCSVDataToExistingCarrierFileData } @@ -154,6 +156,16 @@ private enum OptionsOfVRPSolutions { @CommandLine.Option(names = "--defaultJspritIterations", description = "Set the default number of jsprit iterations.") private int defaultJspritIterations; + public FreightDemandGeneration() { + this.jobDurationCalculator = new DefaultJobDurationCalculator(); + log.info("Using default {} for job duration calculation", jobDurationCalculator.getClass().getSimpleName()); + } + + public FreightDemandGeneration(JobDurationCalculator jobDurationCalculator) { + this.jobDurationCalculator = jobDurationCalculator; + log.info("Using {} for job duration calculation", jobDurationCalculator.getClass().getSimpleName()); + } + public static void main(String[] args) { System.exit(new CommandLine(new FreightDemandGeneration()).execute(args)); } @@ -353,7 +365,7 @@ private void createDemand(DemandGenerationOptions selectedDemandGenerationOption case createDemandFromCSV -> // creates the demand by using the information given in the read csv file DemandReaderFromCSV.readAndCreateDemand(scenario, csvLocationDemand, indexShape, combineSimilarJobs, - crsTransformationNetworkAndShape, null, shapeCategory); + crsTransformationNetworkAndShape, null, shapeCategory, jobDurationCalculator); case createDemandFromCSVAndUsePopulation -> { /* * Option creates the demand by using the information given in the read csv file @@ -399,14 +411,14 @@ private void createDemand(DemandGenerationOptions selectedDemandGenerationOption case useHolePopulation: // uses the hole population as possible demand locations DemandReaderFromCSV.readAndCreateDemand(scenario, csvLocationDemand, indexShape, - combineSimilarJobs, crsTransformationNetworkAndShape, population, shapeCategory); + combineSimilarJobs, crsTransformationNetworkAndShape, population, shapeCategory, jobDurationCalculator); break; case usePopulationInShape: // uses only the population with home location in the given shape file FreightDemandGenerationUtils.reducePopulationToShapeArea(population, shp.createIndex(populationCRS, "_")); DemandReaderFromCSV.readAndCreateDemand(scenario, csvLocationDemand, indexShape, - combineSimilarJobs, crsTransformationNetworkAndShape, population, shapeCategory); + combineSimilarJobs, crsTransformationNetworkAndShape, population, shapeCategory, jobDurationCalculator); break; default: throw new RuntimeException("No valid population option selected!"); diff --git a/contribs/application/src/main/java/org/matsim/freightDemandGeneration/JobDurationCalculator.java b/contribs/application/src/main/java/org/matsim/freightDemandGeneration/JobDurationCalculator.java new file mode 100644 index 00000000000..3c38935138d --- /dev/null +++ b/contribs/application/src/main/java/org/matsim/freightDemandGeneration/JobDurationCalculator.java @@ -0,0 +1,15 @@ +package org.matsim.freightDemandGeneration; + +import org.matsim.freight.carriers.Carrier; + +public interface JobDurationCalculator { + double calculateServiceDuration(Integer serviceDurationPerUnit, int demandForThisService); + + double calculatePickupDuration(Integer pickupDurationPerUnit, int demandForThisShipment); + + double calculateDeliveryDuration(Integer deliveryDurationPerUnit, int demandForThisShipment); + + void recalculateServiceDurations(Carrier thisCarrier); + + void recalculateShipmentDurations(Carrier thisCarrier); +} From ed9cd02dd5d9ecc6a07ff4bcaa56f1c36b2d0102 Mon Sep 17 00:00:00 2001 From: Ricardo Ewert Date: Fri, 22 Nov 2024 11:18:41 +0100 Subject: [PATCH 44/53] update method of cutting jobs in possible parts --- .../DemandReaderFromCSV.java | 76 +++++++++---------- 1 file changed, 37 insertions(+), 39 deletions(-) diff --git a/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DemandReaderFromCSV.java b/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DemandReaderFromCSV.java index 7407561a78c..44e4b158650 100644 --- a/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DemandReaderFromCSV.java +++ b/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DemandReaderFromCSV.java @@ -676,13 +676,16 @@ else if (samplingOption.equals("changeNumberOfLocationsWithDemand")) { countOfLinks++; Carrier thisCarrier = CarriersUtils.getCarriers(scenario).getCarriers() .get(Id.create(newDemandInformationElement.getCarrierName(), Carrier.class)); - int numberOfJobsForDemand = calculateNumberOfJobsForDemand(thisCarrier, demandForThisLink); - for (int i = 0; i < numberOfJobsForDemand; i++) { - int singleDemandForThisLink = demandForThisLink / numberOfJobsForDemand; - if (i == numberOfJobsForDemand - 1) - singleDemandForThisLink = demandForThisLink - (numberOfJobsForDemand - 1) * singleDemandForThisLink; - double serviceTime = newDemandInformationElement.getFirstJobElementTimePerUnit() - * singleDemandForThisLink; + int handledDemand = 0; + //the number of jobs on this link is calculated based on the available vehicles + double largestPossibleDemandSize = getLargestVehicleCapacity(thisCarrier); + while (handledDemand < demandForThisLink) { + int singleDemandForThisLink; + if (demandForThisLink - handledDemand < largestPossibleDemandSize) + singleDemandForThisLink = demandForThisLink - handledDemand; + else + singleDemandForThisLink = (int)largestPossibleDemandSize; + handledDemand = handledDemand + singleDemandForThisLink; double serviceTime = jobDurationCalculator.calculateServiceDuration( newDemandInformationElement.getFirstJobElementTimePerUnit(), singleDemandForThisLink); @@ -724,16 +727,16 @@ else if (samplingOption.equals("changeNumberOfLocationsWithDemand")) { int demandForThisLink = calculateDemandForThisLink(demandToDistribute, numberOfJobs, distributedDemand, i); Carrier thisCarrier = CarriersUtils.getCarriers(scenario).getCarriers() .get(Id.create(newDemandInformationElement.getCarrierName(), Carrier.class)); - int numberOfJobsForDemand = calculateNumberOfJobsForDemand(thisCarrier, demandForThisLink); - for (int j = 0; j < numberOfJobsForDemand; j++) { - int singleDemandForThisLink = demandForThisLink / numberOfJobsForDemand; - if (j == numberOfJobsForDemand - 1) - singleDemandForThisLink = demandForThisLink - (numberOfJobsForDemand - 1) * singleDemandForThisLink; - double serviceTime; - if (singleDemandForThisLink == 0) - serviceTime = newDemandInformationElement.getFirstJobElementTimePerUnit(); + int handledDemand = 0; + //the number of jobs on this link is calculated based on the available vehicles + double largestPossibleDemandSize = getLargestVehicleCapacity(thisCarrier); + while (handledDemand < demandForThisLink || demandToDistribute == 0) { + int singleDemandForThisLink; + if (demandForThisLink - handledDemand < largestPossibleDemandSize) + singleDemandForThisLink = demandForThisLink - handledDemand; else - serviceTime = newDemandInformationElement.getFirstJobElementTimePerUnit() * demandForThisLink; + singleDemandForThisLink = (int)largestPossibleDemandSize; + handledDemand = handledDemand + singleDemandForThisLink; double serviceTime = jobDurationCalculator.calculateServiceDuration( newDemandInformationElement.getFirstJobElementTimePerUnit(), singleDemandForThisLink); usedServiceLocations.add(link.getId().toString()); @@ -748,6 +751,8 @@ else if (samplingOption.equals("changeNumberOfLocationsWithDemand")) { CarriersUtils.getCarriers(scenario).getCarriers() .get(Id.create(newDemandInformationElement.getCarrierName(), Carrier.class)).getServices() .put(thisService.getId(), thisService); + if (demandToDistribute == 0) + break; } } distributedDemand = distributedDemand + demandForThisLink; @@ -1014,7 +1019,9 @@ else if (numberOfPickupLocations != null) { combineSimilarJobs(scenario, newDemandInformationElement); } - /** Creates a single shipment. + /** + * Creates a single shipment. + * * @param scenario Scenario * @param newDemandInformationElement single DemandInformationElement * @param linkPickup Link for the pickup @@ -1027,26 +1034,20 @@ private static void createSingleShipment(Scenario scenario, DemandInformationEle Carrier thisCarrier = CarriersUtils.getCarriers(scenario).getCarriers() .get(Id.create(newDemandInformationElement.getCarrierName(), Carrier.class)); - int numberOfJobsForDemand = calculateNumberOfJobsForDemand(thisCarrier, demandForThisLink); - + double largestPossibleDemandSize = getLargestVehicleCapacity(thisCarrier); + int handledDemand = 0; TimeWindow timeWindowPickup = newDemandInformationElement.getFirstJobElementTimeWindow(); TimeWindow timeWindowDelivery = newDemandInformationElement.getSecondJobElementTimeWindow(); - for (int i = 0; i < numberOfJobsForDemand; i++) { + while (handledDemand < demandForThisLink || demandForThisLink == 0) { Id idNewShipment = Id.create(createJobId(scenario, newDemandInformationElement, linkPickup.getId(), linkDelivery.getId()), CarrierShipment.class); - double serviceTimePickup; - double serviceTimeDelivery; - int singleDemandForThisLink = Math.round ((float) demandForThisLink / numberOfJobsForDemand); - if (i == numberOfJobsForDemand - 1) - singleDemandForThisLink = demandForThisLink - (numberOfJobsForDemand - 1) * singleDemandForThisLink; - if (singleDemandForThisLink == 0) { - serviceTimePickup = newDemandInformationElement.getFirstJobElementTimePerUnit(); - serviceTimeDelivery = newDemandInformationElement.getSecondJobElementTimePerUnit(); - } else { - serviceTimePickup = newDemandInformationElement.getFirstJobElementTimePerUnit() * singleDemandForThisLink; - serviceTimeDelivery = newDemandInformationElement.getSecondJobElementTimePerUnit() * singleDemandForThisLink; - } + int singleDemandForThisLink; + if (demandForThisLink - handledDemand < largestPossibleDemandSize) + singleDemandForThisLink = demandForThisLink - handledDemand; + else + singleDemandForThisLink = (int)largestPossibleDemandSize; + handledDemand = handledDemand + singleDemandForThisLink; double serviceTimePickup = jobDurationCalculator.calculatePickupDuration(newDemandInformationElement.getFirstJobElementTimePerUnit(), singleDemandForThisLink); double serviceTimeDelivery = jobDurationCalculator.calculateDeliveryDuration(newDemandInformationElement.getSecondJobElementTimePerUnit(), singleDemandForThisLink); @@ -1056,6 +1057,8 @@ private static void createSingleShipment(Scenario scenario, DemandInformationEle .setDeliveryServiceTime(serviceTimeDelivery).setDeliveryTimeWindow(timeWindowDelivery) .build(); thisCarrier.getShipments().put(thisShipment.getId(), thisShipment); + if (demandForThisLink == 0) + break; } } @@ -1063,21 +1066,16 @@ private static void createSingleShipment(Scenario scenario, DemandInformationEle * Method calculates the number of jobs for a demand on one link based on the largest vehicle capacity of the carrier. * * @param thisCarrier the carrier of a job - * @param demandForThisLink Demand for this link * @return Number of jobs for this demand */ - private static int calculateNumberOfJobsForDemand(Carrier thisCarrier, int demandForThisLink) { + private static double getLargestVehicleCapacity(Carrier thisCarrier) { double largestVehicleCapacity = 0; for (CarrierVehicle vehicle : thisCarrier.getCarrierCapabilities().getCarrierVehicles().values()) { if (vehicle.getType().getCapacity().getOther() > largestVehicleCapacity) { largestVehicleCapacity = vehicle.getType().getCapacity().getOther(); } } - if (demandForThisLink > largestVehicleCapacity) { - log.info("Demand {} is larger than the largest vehicle capacity ({}). Splitting demand into multiple jobs.", demandForThisLink, largestVehicleCapacity); - return (int) Math.ceil((double) demandForThisLink / largestVehicleCapacity); - } - return 1; + return largestVehicleCapacity; } /** From 0a1da4dd34d2e0b79a3159bfbc1b45fe0c025cb9 Mon Sep 17 00:00:00 2001 From: Ricardo Ewert Date: Fri, 22 Nov 2024 11:21:05 +0100 Subject: [PATCH 45/53] update combineJobs method and ad related test --- .../DemandReaderFromCSV.java | 158 ++++++++-------- .../DemandReaderFromCSVTest.java | 172 +++++++++++++++++- 2 files changed, 239 insertions(+), 91 deletions(-) diff --git a/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DemandReaderFromCSV.java b/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DemandReaderFromCSV.java index 44e4b158650..3935e982e8f 100644 --- a/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DemandReaderFromCSV.java +++ b/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DemandReaderFromCSV.java @@ -561,7 +561,8 @@ else if (newDemandInformationElement.getTypeOfDemand().equals("shipment")) createShipments(scenario, newDemandInformationElement, indexShape, population, crsTransformationNetworkAndShape, jobDurationCalculator); } - + if (combineSimilarJobs) + combineSimilarJobs(scenario, jobDurationCalculator); } /** @@ -758,8 +759,6 @@ else if (samplingOption.equals("changeNumberOfLocationsWithDemand")) { distributedDemand = distributedDemand + demandForThisLink; } } - if (combineSimilarJobs) - combineSimilarJobs(scenario, newDemandInformationElement); } /** @@ -1015,8 +1014,6 @@ else if (numberOfPickupLocations != null) { distributedDemand = distributedDemand + demandForThisLink; } } - if (combineSimilarJobs) - combineSimilarJobs(scenario, newDemandInformationElement); } /** @@ -1170,109 +1167,104 @@ private static int calculateDemandBasedOnLinkLength(int countOfLinks, int distri * If jobs of a carrier have the same characteristics (time window, location), * they will be combined to one job. * - * @param scenario Scenario - * @param newDemandInformationElement single DemandInformationElement + * @param scenario Scenario + * @param jobDurationCalculator Calculator for the job duration */ - private static void combineSimilarJobs(Scenario scenario, - DemandInformationElement newDemandInformationElement) { + private static void combineSimilarJobs(Scenario scenario, JobDurationCalculator jobDurationCalculator) { log.warn( "The number of Jobs will be reduced if jobs have the same characteristics (e.g. time, location, carrier)"); - int connectedJobs = 0; - if (newDemandInformationElement.getTypeOfDemand().equals("shipment")) { - HashMap, CarrierShipment> shipmentsToRemove = new HashMap<>(); - ArrayList shipmentsToAdd = new ArrayList<>(); - Carrier thisCarrier = CarriersUtils.getCarriers(scenario).getCarriers() - .get(Id.create(newDemandInformationElement.getCarrierName(), Carrier.class)); - for (Id baseShipmentId : thisCarrier.getShipments().keySet()) { - if (!shipmentsToRemove.containsKey(baseShipmentId)) { - CarrierShipment baseShipment = thisCarrier.getShipments().get(baseShipmentId); - HashMap, CarrierShipment> shipmentsToConnect = new HashMap<>(); - shipmentsToConnect.put(baseShipmentId, baseShipment); - for (Id thisShipmentId : thisCarrier.getShipments().keySet()) { - if (!shipmentsToRemove.containsKey(thisShipmentId)) { - CarrierShipment thisShipment = thisCarrier.getShipments().get(thisShipmentId); - if (baseShipment.getId() != thisShipment.getId() + for (Carrier thisCarrier : CarriersUtils.getCarriers(scenario).getCarriers().values()) { + if (!thisCarrier.getShipments().isEmpty()) { + int shipmentsBeforeConnection = thisCarrier.getShipments().size(); + HashMap, CarrierShipment> shipmentsToRemove = new HashMap<>(); + ArrayList shipmentsToAdd = new ArrayList<>(); + for (Id baseShipmentId : thisCarrier.getShipments().keySet()) { + if (!shipmentsToRemove.containsKey(baseShipmentId)) { + CarrierShipment baseShipment = thisCarrier.getShipments().get(baseShipmentId); + HashMap, CarrierShipment> shipmentsToConnect = new HashMap<>(); + shipmentsToConnect.put(baseShipmentId, baseShipment); + for (Id thisShipmentId : thisCarrier.getShipments().keySet()) { + if (!shipmentsToRemove.containsKey(thisShipmentId)) { + CarrierShipment thisShipment = thisCarrier.getShipments().get(thisShipmentId); + if (baseShipment.getId() != thisShipment.getId() && baseShipment.getFrom() == thisShipment.getFrom() && baseShipment.getTo() == thisShipment.getTo() && baseShipment.getPickupTimeWindow() == thisShipment.getPickupTimeWindow() && baseShipment.getDeliveryTimeWindow() == thisShipment.getDeliveryTimeWindow()) - shipmentsToConnect.put(thisShipmentId, thisShipment); + shipmentsToConnect.put(thisShipmentId, thisShipment); + } } - } - Id idNewShipment = baseShipment.getId(); - int demandForThisLink = 0; - double serviceTimePickup = 0; - double serviceTimeDelivery = 0; - for (CarrierShipment carrierShipment : shipmentsToConnect.values()) { - demandForThisLink = demandForThisLink + carrierShipment.getSize(); - serviceTimePickup = serviceTimePickup + carrierShipment.getPickupServiceTime(); - serviceTimeDelivery = serviceTimeDelivery + carrierShipment.getDeliveryServiceTime(); - shipmentsToRemove.put(carrierShipment.getId(), carrierShipment); - connectedJobs++; - } - CarrierShipment newShipment = CarrierShipment.Builder + Id idNewShipment = baseShipment.getId(); + int demandForThisLink = 0; + double serviceTimePickup = 0; + double serviceTimeDelivery = 0; + for (CarrierShipment carrierShipment : shipmentsToConnect.values()) { + demandForThisLink = demandForThisLink + carrierShipment.getSize(); + serviceTimePickup = serviceTimePickup + carrierShipment.getPickupServiceTime(); + serviceTimeDelivery = serviceTimeDelivery + carrierShipment.getDeliveryServiceTime(); + shipmentsToRemove.put(carrierShipment.getId(), carrierShipment); + } + CarrierShipment newShipment = CarrierShipment.Builder .newInstance(idNewShipment, baseShipment.getFrom(), baseShipment.getTo(), demandForThisLink) .setPickupServiceTime(serviceTimePickup) .setPickupTimeWindow(baseShipment.getPickupTimeWindow()) .setDeliveryServiceTime(serviceTimeDelivery) .setDeliveryTimeWindow(baseShipment.getDeliveryTimeWindow()).build(); - - shipmentsToAdd.add(newShipment); - connectedJobs++; + shipmentsToAdd.add(newShipment); + } } - } - for (CarrierShipment id : shipmentsToRemove.values()) - thisCarrier.getShipments().remove(id.getId(), id); + for (CarrierShipment id : shipmentsToRemove.values()) + thisCarrier.getShipments().remove(id.getId(), id); - for (CarrierShipment carrierShipment : shipmentsToAdd) { - thisCarrier.getShipments().put(carrierShipment.getId(), carrierShipment); + for (CarrierShipment carrierShipment : shipmentsToAdd) { + thisCarrier.getShipments().put(carrierShipment.getId(), carrierShipment); + } + jobDurationCalculator.recalculateShipmentDurations(thisCarrier); + log.warn("Number of reduced shipments for carrier {}: {}", thisCarrier.getId().toString(), shipmentsBeforeConnection - thisCarrier.getShipments().size()); } - log.warn("Number of reduced shipments: {}", connectedJobs); - } - if (newDemandInformationElement.getTypeOfDemand().equals("service")) { - HashMap, CarrierService> servicesToRemove = new HashMap<>(); - ArrayList servicesToAdd = new ArrayList<>(); - Carrier thisCarrier = CarriersUtils.getCarriers(scenario).getCarriers() - .get(Id.create(newDemandInformationElement.getCarrierName(), Carrier.class)); - for (Id baseServiceId : thisCarrier.getServices().keySet()) { - if (!servicesToRemove.containsKey(baseServiceId)) { - CarrierService baseService = thisCarrier.getServices().get(baseServiceId); - HashMap, CarrierService> servicesToConnect = new HashMap<>(); - servicesToConnect.put(baseServiceId, baseService); - for (Id thisServiceId : thisCarrier.getServices().keySet()) { - if (!servicesToRemove.containsKey(thisServiceId)) { - CarrierService thisService = thisCarrier.getServices().get(thisServiceId); - if (baseService.getId() != thisService.getId() + if (!thisCarrier.getServices().isEmpty()) { + int servicesBeforeConnection = thisCarrier.getServices().size(); + HashMap, CarrierService> servicesToRemove = new HashMap<>(); + ArrayList servicesToAdd = new ArrayList<>(); + for (Id baseServiceId : thisCarrier.getServices().keySet()) { + if (!servicesToRemove.containsKey(baseServiceId)) { + CarrierService baseService = thisCarrier.getServices().get(baseServiceId); + HashMap, CarrierService> servicesToConnect = new HashMap<>(); + servicesToConnect.put(baseServiceId, baseService); + for (Id thisServiceId : thisCarrier.getServices().keySet()) { + if (!servicesToRemove.containsKey(thisServiceId)) { + CarrierService thisService = thisCarrier.getServices().get(thisServiceId); + if (baseService.getId() != thisService.getId() && baseService.getLocationLinkId() == thisService.getLocationLinkId() && baseService - .getServiceStartTimeWindow() == thisService.getServiceStartTimeWindow()) - servicesToConnect.put(thisServiceId, thisService); + .getServiceStartTimeWindow() == thisService.getServiceStartTimeWindow()) + servicesToConnect.put(thisServiceId, thisService); + } } - } - Id idNewService = baseService.getId(); - int demandForThisLink = 0; - double serviceTimeService = 0; - for (CarrierService carrierService : servicesToConnect.values()) { - demandForThisLink = demandForThisLink + carrierService.getCapacityDemand(); - serviceTimeService = serviceTimeService + carrierService.getServiceDuration(); - servicesToRemove.put(carrierService.getId(), carrierService); - connectedJobs++; - } - CarrierService newService = CarrierService.Builder + Id idNewService = baseService.getId(); + int demandForThisLink = 0; + double serviceTimeService = 0; + for (CarrierService carrierService : servicesToConnect.values()) { + demandForThisLink = demandForThisLink + carrierService.getCapacityDemand(); + serviceTimeService = serviceTimeService + carrierService.getServiceDuration(); + servicesToRemove.put(carrierService.getId(), carrierService); + } + CarrierService newService = CarrierService.Builder .newInstance(idNewService, baseService.getLocationLinkId()) .setServiceDuration(serviceTimeService) .setServiceStartTimeWindow(baseService.getServiceStartTimeWindow()) .setCapacityDemand(demandForThisLink).build(); - servicesToAdd.add(newService); - connectedJobs++; + servicesToAdd.add(newService); + } } + for (CarrierService id : servicesToRemove.values()) + thisCarrier.getServices().remove(id.getId(), id); + for (CarrierService carrierService : servicesToAdd) { + thisCarrier.getServices().put(carrierService.getId(), carrierService); + } + jobDurationCalculator.recalculateServiceDurations(thisCarrier); + log.warn("Number of reduced services for carrier {}: {}", thisCarrier.getId().toString(), servicesBeforeConnection - thisCarrier.getServices().size()); } - for (CarrierService id : servicesToRemove.values()) - thisCarrier.getServices().remove(id.getId(), id); - for (CarrierService carrierService : servicesToAdd) { - thisCarrier.getServices().put(carrierService.getId(), carrierService); - } - log.warn("Number of reduced shipments: {}", connectedJobs); } } diff --git a/contribs/application/src/test/java/org/matsim/freightDemandGeneration/DemandReaderFromCSVTest.java b/contribs/application/src/test/java/org/matsim/freightDemandGeneration/DemandReaderFromCSVTest.java index c27b251afc4..9cd21c16d9d 100644 --- a/contribs/application/src/test/java/org/matsim/freightDemandGeneration/DemandReaderFromCSVTest.java +++ b/contribs/application/src/test/java/org/matsim/freightDemandGeneration/DemandReaderFromCSVTest.java @@ -79,10 +79,10 @@ void demandCreationWithSampleWithChangeNumberOfLocations() throws IOException { String populationLocation = utils.getPackageInputDirectory() + "testPopulation.xml"; Population population = PopulationUtils.readPopulation(populationLocation); FreightDemandGenerationUtils.preparePopulation(population, 0.5, 1.0, "changeNumberOfLocationsWithDemand"); - + Boolean combineSimilarJobs = false; // run methods createDemandAndCheckCarrier(carrierCSVLocation, scenario, freightCarriersConfigGroup, indexShape, demandCSVLocation, shapeCategory, - population); + population, combineSimilarJobs); Network network = scenario.getNetwork(); @@ -147,10 +147,11 @@ void demandCreationWithSampleWithDemandOnLocation() throws IOException { String populationLocation = utils.getPackageInputDirectory() + "testPopulation.xml"; Population population = PopulationUtils.readPopulation(populationLocation); FreightDemandGenerationUtils.preparePopulation(population, 0.5, 1.0, "changeDemandOnLocation"); + Boolean combineSimilarJobs = false; - createDemandAndCheckCarrier(carrierCSVLocation, scenario, freightCarriersConfigGroup, indexShape, demandCSVLocation, shapeCategory, population); + createDemandAndCheckCarrier(carrierCSVLocation, scenario, freightCarriersConfigGroup, indexShape, demandCSVLocation, shapeCategory, + population, combineSimilarJobs); - // check carrier 1 Network network = scenario.getNetwork(); checkCarrier1and2(scenario, network, indexShape); @@ -194,6 +195,74 @@ void demandCreationWithSampleWithDemandOnLocation() throws IOException { } } + @Test + void demandCreationWithSampleWithDemandOnLocationWithCombiningJobs() throws IOException { + // read inputs + Config config = ConfigUtils.createConfig(); + config.network().setInputFile( + "https://raw.githubusercontent.com/matsim-org/matsim-libs/master/examples/scenarios/freight-chessboard-9x9/grid9x9.xml"); + Scenario scenario = ScenarioUtils.loadScenario(config); + FreightCarriersConfigGroup freightCarriersConfigGroup = ConfigUtils.addOrGetModule(scenario.getConfig(), + FreightCarriersConfigGroup.class); + freightCarriersConfigGroup.setCarriersVehicleTypesFile(utils.getPackageInputDirectory() + "testVehicleTypes.xml"); + Path carrierCSVLocation = Path.of(utils.getPackageInputDirectory() + "testCarrierCSV.csv"); + Path demandCSVLocation = Path.of(utils.getPackageInputDirectory() + "testDemandCSV.csv"); + Path shapeFilePath = Path.of(utils.getPackageInputDirectory() + "testShape/testShape.shp"); + ShpOptions shp = new ShpOptions(shapeFilePath, "WGS84", null); + String shapeCategory = "Ortsteil"; + ShpOptions.Index indexShape = shp.createIndex("Ortsteil"); + String populationLocation = utils.getPackageInputDirectory() + "testPopulation.xml"; + Population population = PopulationUtils.readPopulation(populationLocation); + FreightDemandGenerationUtils.preparePopulation(population, 0.5, 1.0, "changeDemandOnLocation"); + Boolean combineSimilarJobs = true; + + createDemandAndCheckCarrier(carrierCSVLocation, scenario, freightCarriersConfigGroup, indexShape, demandCSVLocation, shapeCategory, + population, combineSimilarJobs); + + Network network = scenario.getNetwork(); + + checkCarrier1and2WithCombiningJobs(scenario, network, indexShape); + int countDemand; + Object2IntMap countShipmentsWithCertainDemand; + Map> locationsPerShipmentElement; + + // check carrier 3 + Carrier testCarrier3 = CarriersUtils.getCarriers(scenario).getCarriers() + .get(Id.create("testCarrier3", Carrier.class)); + Assertions.assertEquals(0, testCarrier3.getServices().size()); + Assertions.assertEquals(2, testCarrier3.getShipments().size()); + countShipmentsWithCertainDemand = new Object2IntOpenHashMap<>(); + locationsPerShipmentElement = new HashMap<>(); + countDemand = 0; + for (CarrierShipment shipment : testCarrier3.getShipments().values()) { + countShipmentsWithCertainDemand.merge((Integer) shipment.getSize(), 1, Integer::sum); + countDemand = countDemand + shipment.getSize(); + Assertions.assertEquals(10, shipment.getSize()); + Assertions.assertEquals(4000, shipment.getPickupServiceTime(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(2500, shipment.getDeliveryServiceTime(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(TimeWindow.newInstance(8000, 50000), shipment.getPickupTimeWindow()); + Assertions.assertEquals(TimeWindow.newInstance(10000, 60000), shipment.getDeliveryTimeWindow()); + locationsPerShipmentElement.computeIfAbsent("ShipmentElement1_pickup", (k) -> new HashSet<>()) + .add(shipment.getFrom().toString()); + locationsPerShipmentElement.computeIfAbsent("ShipmentElement1_delivery", (k) -> new HashSet<>()) + .add(shipment.getTo().toString()); + } + Assertions.assertEquals(20, countDemand); + Assertions.assertEquals(2, countShipmentsWithCertainDemand.getInt(10)); + Assertions.assertEquals(1, locationsPerShipmentElement.get("ShipmentElement1_pickup").size()); + Assertions.assertEquals(2, locationsPerShipmentElement.get("ShipmentElement1_delivery").size()); + for (String locationsOfShipmentElement : locationsPerShipmentElement.get("ShipmentElement1_delivery")) { + Link link = network.getLinks().get(Id.createLinkId(locationsOfShipmentElement)); + Assertions.assertTrue( + FreightDemandGenerationUtils.checkPositionInShape(link, null, indexShape, null, null)); + Assertions.assertTrue(FreightDemandGenerationUtils.checkPositionInShape(link, null, indexShape, + new String[] { "area1" }, null)); + Assertions.assertFalse(FreightDemandGenerationUtils.checkPositionInShape(link, null, indexShape, + new String[] { "area2" }, null)); + } + } + + @Test void demandCreationNoSampling() throws IOException { // read inputs @@ -213,10 +282,11 @@ void demandCreationNoSampling() throws IOException { String populationLocation = utils.getPackageInputDirectory() + "testPopulation.xml"; Population population = PopulationUtils.readPopulation(populationLocation); FreightDemandGenerationUtils.preparePopulation(population, 0.5, 0.5, "changeDemandOnLocation"); + Boolean combineSimilarJobs = false; // run methods createDemandAndCheckCarrier(carrierCSVLocation, scenario, freightCarriersConfigGroup, indexShape, demandCSVLocation, shapeCategory, - population); + population, combineSimilarJobs); // check carrier 1 Network network = scenario.getNetwork(); @@ -367,7 +437,8 @@ void csvDemandReader() throws IOException { private static void createDemandAndCheckCarrier(Path carrierCSVLocation, Scenario scenario, FreightCarriersConfigGroup freightCarriersConfigGroup, ShpOptions.Index indexShape, Path demandCSVLocation, String shapeCategory, - Population population) throws IOException { + Population population, Boolean combineSimilarJobs) throws IOException { + JobDurationCalculator jobDurationCalculator = new DefaultJobDurationCalculator(); // run methods Set allNewCarrierInformation = CarrierReaderFromCSV .readCarrierInformation(carrierCSVLocation); @@ -375,8 +446,8 @@ private static void createDemandAndCheckCarrier(Path carrierCSVLocation, Scenari indexShape, 1, null); Set demandInformation = DemandReaderFromCSV.readDemandInformation(demandCSVLocation); DemandReaderFromCSV.checkNewDemand(scenario, demandInformation, indexShape, shapeCategory); - DemandReaderFromCSV.createDemandForCarriers(scenario, indexShape, demandInformation, population, false, - null); + DemandReaderFromCSV.createDemandForCarriers(scenario, indexShape, demandInformation, population, combineSimilarJobs, + null, jobDurationCalculator); Assertions.assertEquals(3, CarriersUtils.getCarriers(scenario).getCarriers().size()); Assertions.assertTrue( CarriersUtils.getCarriers(scenario).getCarriers().containsKey(Id.create("testCarrier1", Carrier.class))); @@ -491,4 +562,89 @@ private static void checkCarrier1and2(Scenario scenario, Network network, ShpOpt Assertions.assertEquals(1, locationsPerShipmentElement.get("ShipmentElement2_pickup").size()); Assertions.assertEquals(2, locationsPerShipmentElement.get("ShipmentElement2_delivery").size()); } + + /** + * Results after combing jobs. + * + * @param scenario the scenario + * @param network the network + * @param indexShape the index of the shape + */ + private static void checkCarrier1and2WithCombiningJobs(Scenario scenario, Network network, ShpOptions.Index indexShape) { + Carrier testCarrier1 = CarriersUtils.getCarriers(scenario).getCarriers() + .get(Id.create("testCarrier1", Carrier.class)); + Assertions.assertEquals(8, testCarrier1.getServices().size()); + Assertions.assertEquals(0, testCarrier1.getShipments().size()); + Object2IntMap countServicesWithCertainDemand = new Object2IntOpenHashMap<>(); + Map> locationsPerServiceElement = new HashMap<>(); + int countDemand = 0; + for (CarrierService service : testCarrier1.getServices().values()) { + countServicesWithCertainDemand.merge((Integer) service.getCapacityDemand(), 1, Integer::sum); + countDemand = countDemand + service.getCapacityDemand(); + if (service.getCapacityDemand() == 0) { + Assertions.assertEquals(180, service.getServiceDuration(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(TimeWindow.newInstance(3000, 13000), service.getServiceStartTimeWindow()); + locationsPerServiceElement.computeIfAbsent("serviceElement1", (k) -> new HashSet<>()) + .add(service.getLocationLinkId().toString()); + } else { + Assertions.assertEquals(service.getCapacityDemand() * 100, service.getServiceDuration(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(TimeWindow.newInstance(5000, 20000), service.getServiceStartTimeWindow()); + locationsPerServiceElement.computeIfAbsent("serviceElement2", (k) -> new HashSet<>()) + .add(service.getLocationLinkId().toString()); + } + } + Assertions.assertEquals(12, countDemand); + Assertions.assertEquals(4, countServicesWithCertainDemand.getInt(0)); + Assertions.assertEquals(4, locationsPerServiceElement.get("serviceElement1").size()); + for (String locationsOfServiceElement : locationsPerServiceElement.get("serviceElement1")) { + Link link = network.getLinks().get(Id.createLinkId(locationsOfServiceElement)); + Assertions.assertTrue( + FreightDemandGenerationUtils.checkPositionInShape(link, null, indexShape, null, null)); + Assertions.assertFalse(FreightDemandGenerationUtils.checkPositionInShape(link, null, indexShape, + new String[] { "area1" }, null)); + Assertions.assertTrue(FreightDemandGenerationUtils.checkPositionInShape(link, null, indexShape, + new String[] { "area2" }, null)); + } + Assertions.assertEquals(4, locationsPerServiceElement.get("serviceElement2").size()); + Assertions.assertTrue(locationsPerServiceElement.get("serviceElement2").contains("i(2,0)")); + + // check carrier 2 + Carrier testCarrier2 = CarriersUtils.getCarriers(scenario).getCarriers() + .get(Id.create("testCarrier2", Carrier.class)); + Assertions.assertEquals(0, testCarrier2.getServices().size()); + Assertions.assertEquals(6, testCarrier2.getShipments().size()); + Object2IntMap countShipmentsWithCertainDemand = new Object2IntOpenHashMap<>(); + Map> locationsPerShipmentElement = new HashMap<>(); + countDemand = 0; + for (CarrierShipment shipment : testCarrier2.getShipments().values()) { + countShipmentsWithCertainDemand.merge((Integer) shipment.getSize(), 1, Integer::sum); + countDemand = countDemand + shipment.getSize(); + if (shipment.getSize() == 0) { + Assertions.assertEquals(300, shipment.getPickupServiceTime(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(350, shipment.getDeliveryServiceTime(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(TimeWindow.newInstance(10000, 45000), shipment.getPickupTimeWindow()); + Assertions.assertEquals(TimeWindow.newInstance(11000, 44000), shipment.getDeliveryTimeWindow()); + locationsPerShipmentElement.computeIfAbsent("ShipmentElement1_pickup", (k) -> new HashSet<>()) + .add(shipment.getFrom().toString()); + locationsPerShipmentElement.computeIfAbsent("ShipmentElement1_delivery", (k) -> new HashSet<>()) + .add(shipment.getTo().toString()); + } else { + Assertions.assertEquals(shipment.getSize() * 200, shipment.getPickupServiceTime(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(shipment.getSize() * 200, shipment.getDeliveryServiceTime(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(TimeWindow.newInstance(11000, 44000), shipment.getPickupTimeWindow()); + Assertions.assertEquals(TimeWindow.newInstance(20000, 40000), shipment.getDeliveryTimeWindow()); + locationsPerShipmentElement.computeIfAbsent("ShipmentElement2_pickup", (k) -> new HashSet<>()) + .add(shipment.getFrom().toString()); + locationsPerShipmentElement.computeIfAbsent("ShipmentElement2_delivery", (k) -> new HashSet<>()) + .add(shipment.getTo().toString()); + } + } + Assertions.assertEquals(15, countDemand); + Assertions.assertEquals(4, countShipmentsWithCertainDemand.getInt(0)); + Assertions.assertEquals(4, locationsPerShipmentElement.get("ShipmentElement1_pickup").size()); + Assertions.assertEquals(1, locationsPerShipmentElement.get("ShipmentElement1_delivery").size()); + Assertions.assertTrue(locationsPerShipmentElement.get("ShipmentElement1_delivery").contains("i(2,0)")); + Assertions.assertEquals(1, locationsPerShipmentElement.get("ShipmentElement2_pickup").size()); + Assertions.assertEquals(2, locationsPerShipmentElement.get("ShipmentElement2_delivery").size()); + } } From d16f8588f0fde3cd5fe111c44d5bfb740297c3cc Mon Sep 17 00:00:00 2001 From: Tarek Chouaki Date: Fri, 22 Nov 2024 13:42:45 +0100 Subject: [PATCH 46/53] Fix: Non-deterministic behaviour of SwissRailRaptor (#3568) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: RaptorDeterminismTest * feat: DeterminismTest * fix: deterministic creation of stops quad tree * fix: more deterministic SwissRailRaptorCore.calcLeastCostRoute * chore: code commenting --------- Co-authored-by: Tarek Chouaki Co-authored-by: Sebastian Hörl --- .../discrete_mode_choice/DeterminismTest.java | 55 +++++ .../pt/raptor/SwissRailRaptorCore.java | 18 +- .../pt/raptor/SwissRailRaptorData.java | 15 +- .../ch/sbb/matsim/RaptorDeterminismTest.java | 207 ++++++++++++++++++ 4 files changed, 271 insertions(+), 24 deletions(-) create mode 100644 contribs/discrete_mode_choice/src/test/java/org/matsim/contrib/discrete_mode_choice/DeterminismTest.java create mode 100644 matsim/src/test/java/ch/sbb/matsim/RaptorDeterminismTest.java diff --git a/contribs/discrete_mode_choice/src/test/java/org/matsim/contrib/discrete_mode_choice/DeterminismTest.java b/contribs/discrete_mode_choice/src/test/java/org/matsim/contrib/discrete_mode_choice/DeterminismTest.java new file mode 100644 index 00000000000..bebc456de8f --- /dev/null +++ b/contribs/discrete_mode_choice/src/test/java/org/matsim/contrib/discrete_mode_choice/DeterminismTest.java @@ -0,0 +1,55 @@ +package org.matsim.contrib.discrete_mode_choice; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Scenario; +import org.matsim.contribs.discrete_mode_choice.modules.DiscreteModeChoiceModule; +import org.matsim.contribs.discrete_mode_choice.modules.ModeAvailabilityModule; +import org.matsim.contribs.discrete_mode_choice.modules.config.DiscreteModeChoiceConfigGroup; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy; +import org.matsim.core.gbl.MatsimRandom; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.core.utils.misc.CRCChecksum; +import org.matsim.examples.ExamplesUtils; + +import java.net.URL; + +public class DeterminismTest { + private static void runConfig(URL configUrl, String outputDirectory) { + Config config = ConfigUtils.loadConfig(configUrl, new DiscreteModeChoiceConfigGroup()); + config.controller().setLastIteration(2); + config.controller().setOutputDirectory(outputDirectory); + config.controller().setOverwriteFileSetting(OutputDirectoryHierarchy.OverwriteFileSetting.deleteDirectoryIfExists); + Scenario scenario = ScenarioUtils.createScenario(config); + ScenarioUtils.loadScenario(scenario); + Controler controler = new Controler(scenario); + controler.addOverridingModule(new DiscreteModeChoiceModule()); + controler.addOverridingModule(new ModeAvailabilityModule()); + controler.run(); + } + + + @Test + public void testSimulationDeterminism() { + Logger logger = LogManager.getLogger(DeterminismTest.class); + logger.info("Testing simulation determinism"); + URL configUrl = IOUtils.extendUrl(ExamplesUtils.getTestScenarioURL("siouxfalls-2014"), "config_default.xml"); + int samples = 10; + for(int i=0; i destinationStops = new HashMap<>(); + // Using a LinkedHashMap instead of a regular HashMap here is necessary to have a deterministic behaviour + Map destinationStops = new LinkedHashMap<>(); // go through all egressStops; check if already in destinationStops; if so, check if current cost is smaller; if so, then replace. This can // presumably happen when the same stop can be reached at lower cost by a different egress mode. (*) @@ -141,7 +134,8 @@ public RaptorRoute calcLeastCostRoute(double depTime, Facility fromFacility, Fac } // same as (*) for access stops: - Map initialStops = new HashMap<>(); + // Also, using a LinkedHashMap instead of a regular HashMap here is necessary to have a deterministic behaviour + Map initialStops = new LinkedHashMap<>(); for (InitialStop accessStop : accessStops) { InitialStop alternative = initialStops.get(accessStop.stop); if (alternative == null || accessStop.accessCost < alternative.accessCost) { @@ -833,7 +827,7 @@ private void handleTransfers(boolean strict, RaptorParameters raptorParams, Cach final int firstTransferIndex; final int lastTransferIndex; final RTransfer[] transfers; - + if (!useAdaptiveTransferCalculation) { // efficient lookup from the precomputed transfer candidates transfers = this.data.transfers; diff --git a/matsim/src/main/java/ch/sbb/matsim/routing/pt/raptor/SwissRailRaptorData.java b/matsim/src/main/java/ch/sbb/matsim/routing/pt/raptor/SwissRailRaptorData.java index a02b58c7b35..e4d4f28a1c5 100644 --- a/matsim/src/main/java/ch/sbb/matsim/routing/pt/raptor/SwissRailRaptorData.java +++ b/matsim/src/main/java/ch/sbb/matsim/routing/pt/raptor/SwissRailRaptorData.java @@ -20,17 +20,7 @@ package ch.sbb.matsim.routing.pt.raptor; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.function.Supplier; import javax.annotation.Nullable; @@ -148,7 +138,8 @@ public static SwissRailRaptorData create(TransitSchedule schedule, @Nullable Veh // enumerate TransitStopFacilities along their usage in transit routes to (hopefully) achieve a better memory locality // well, I'm not even sure how often we'll need the transit stop facilities, likely we'll use RouteStops more often Map stopFacilityIndices = new HashMap<>((int) (schedule.getFacilities().size() * 1.5)); - Map routeStopsPerStopFacility = new HashMap<>(); + // Using a LinkedHashMap instead of a regular HashMap here is necessary to have a deterministic behaviour + Map routeStopsPerStopFacility = new LinkedHashMap<>(); boolean useModeMapping = staticConfig.isUseModeMappingForPassengers(); for (TransitLine line : schedule.getTransitLines().values()) { diff --git a/matsim/src/test/java/ch/sbb/matsim/RaptorDeterminismTest.java b/matsim/src/test/java/ch/sbb/matsim/RaptorDeterminismTest.java new file mode 100644 index 00000000000..99689ade903 --- /dev/null +++ b/matsim/src/test/java/ch/sbb/matsim/RaptorDeterminismTest.java @@ -0,0 +1,207 @@ +package ch.sbb.matsim; + +import ch.sbb.matsim.routing.pt.raptor.SwissRailRaptorData; +import ch.sbb.matsim.routing.pt.raptor.RaptorStopFinder; +import ch.sbb.matsim.routing.pt.raptor.RaptorParametersForPerson; +import ch.sbb.matsim.routing.pt.raptor.SwissRailRaptor; +import ch.sbb.matsim.routing.pt.raptor.RaptorParameters; +import ch.sbb.matsim.routing.pt.raptor.InitialStop; +import com.google.inject.Injector; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.population.*; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.events.EventsManagerModule; +import org.matsim.core.router.TripRouter; +import org.matsim.core.router.TripRouterModule; +import org.matsim.core.router.TripStructureUtils; +import org.matsim.core.router.costcalculators.TravelDisutilityModule; +import org.matsim.core.scenario.ScenarioByInstanceModule; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.trafficmonitoring.TravelTimeCalculatorModule; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.core.utils.timing.TimeInterpretationModule; +import org.matsim.examples.ExamplesUtils; +import org.matsim.facilities.ActivityFacilities; +import org.matsim.facilities.FacilitiesUtils; +import org.matsim.facilities.Facility; +import org.matsim.pt.routes.DefaultTransitPassengerRoute; +import org.matsim.pt.transitSchedule.api.TransitStopFacility; + + +import java.net.URL; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Optional; + +public class RaptorDeterminismTest { + + public static boolean comparePlan(List left, List right) { + if(left.size() != right.size()) { + return false; + } + for(int i=0; i[] transitStopFacilitiesByScenario = new List[scenarioSamples]; + List[] personLists = new List[scenarioSamples]; + TripRouter[] tripRouters = new TripRouter[scenarioSamples]; + + logger.info(String.format("Loading scenario %d times", scenarioSamples)); + for(int scenarioIndex=0; scenarioIndex(scenario.getTransitSchedule().getFacilities().values()); + swissRailRaptorData[scenarioIndex] = swissRailRaptors[scenarioIndex].getUnderlyingData(); + personLists[scenarioIndex] = scenario.getPopulation().getPersons().values().stream().toList(); + + tripRouters[scenarioIndex] = injector.getInstance(TripRouter.class); + } + + logger.info(String.format("Comparing stop facilities order %d", scenarioSamples)); + + for(int scenarioIndex=1; scenarioIndex referenceElements = tripRouters[0].calcRoute("pt", fromFacility, toFacility, referenceTrip.getOriginActivity().getEndTime().seconds(), referencePerson, referenceTrip.getTripAttributes()); + + for(int scenarioIndex=1; scenarioIndex referenceInitialStops = raptorStopFinders[0].findStops(fromFacility, toFacility, referencePerson, referenceTrip.getOriginActivity().getEndTime().seconds(), referenceTrip.getTripAttributes(), referenceRaptorParameters, swissRailRaptorData[0], direction); + List sortedReferenceInitialStops = new ArrayList<>(referenceInitialStops); + sortedReferenceInitialStops.sort(Comparator.comparing(InitialStop::toString)); + + List comparedInitialStops = raptorStopFinders[scenarioIndex].findStops(otherFromFacility, otherToFacility, referencePerson, referenceTrip.getOriginActivity().getEndTime().seconds(), referenceTrip.getTripAttributes(), otherRaptorParameters, swissRailRaptorData[scenarioIndex], direction); + + assert referenceInitialStops.size() == comparedInitialStops.size(); + + List sortedComparedInitialStops = new ArrayList<>(comparedInitialStops); + sortedComparedInitialStops.sort(Comparator.comparing(InitialStop::toString)); + for(int j=0; j comparedElements = tripRouters[scenarioIndex].calcRoute("pt", otherFromFacility, otherToFacility, referenceTrip.getOriginActivity().getEndTime().seconds(), otherPerson, referenceTrip.getTripAttributes()); + assert comparePlan(referenceElements, comparedElements); + } + } + } + } + +} From 2cce61477c003e836362ae21cd70c73fb4062297 Mon Sep 17 00:00:00 2001 From: Ricardo Ewert Date: Fri, 22 Nov 2024 21:21:59 +0100 Subject: [PATCH 47/53] relocate method --- .../freightDemandGeneration/DemandReaderFromCSV.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DemandReaderFromCSV.java b/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DemandReaderFromCSV.java index 3935e982e8f..63179128cc4 100644 --- a/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DemandReaderFromCSV.java +++ b/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DemandReaderFromCSV.java @@ -562,7 +562,8 @@ else if (newDemandInformationElement.getTypeOfDemand().equals("shipment")) crsTransformationNetworkAndShape, jobDurationCalculator); } if (combineSimilarJobs) - combineSimilarJobs(scenario, jobDurationCalculator); + combineSimilarJobs(scenario); + jobDurationCalculator.recalculateJobDurations(scenario); } /** @@ -1168,9 +1169,8 @@ private static int calculateDemandBasedOnLinkLength(int countOfLinks, int distri * they will be combined to one job. * * @param scenario Scenario - * @param jobDurationCalculator Calculator for the job duration */ - private static void combineSimilarJobs(Scenario scenario, JobDurationCalculator jobDurationCalculator) { + private static void combineSimilarJobs(Scenario scenario) { log.warn( "The number of Jobs will be reduced if jobs have the same characteristics (e.g. time, location, carrier)"); @@ -1220,7 +1220,7 @@ private static void combineSimilarJobs(Scenario scenario, JobDurationCalculator for (CarrierShipment carrierShipment : shipmentsToAdd) { thisCarrier.getShipments().put(carrierShipment.getId(), carrierShipment); } - jobDurationCalculator.recalculateShipmentDurations(thisCarrier); + log.warn("Number of reduced shipments for carrier {}: {}", thisCarrier.getId().toString(), shipmentsBeforeConnection - thisCarrier.getShipments().size()); } if (!thisCarrier.getServices().isEmpty()) { @@ -1262,7 +1262,6 @@ private static void combineSimilarJobs(Scenario scenario, JobDurationCalculator for (CarrierService carrierService : servicesToAdd) { thisCarrier.getServices().put(carrierService.getId(), carrierService); } - jobDurationCalculator.recalculateServiceDurations(thisCarrier); log.warn("Number of reduced services for carrier {}: {}", thisCarrier.getId().toString(), servicesBeforeConnection - thisCarrier.getServices().size()); } } From a79f6552d8aa23aa3c7a5a0f31f2923cc3cf3635 Mon Sep 17 00:00:00 2001 From: Ricardo Ewert Date: Fri, 22 Nov 2024 21:26:44 +0100 Subject: [PATCH 48/53] update interface and implementation --- .../DefaultJobDurationCalculator.java | 19 ++++------- .../JobDurationCalculator.java | 32 ++++++++++++++++--- 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DefaultJobDurationCalculator.java b/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DefaultJobDurationCalculator.java index d64b7aad509..42ddbc4068a 100644 --- a/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DefaultJobDurationCalculator.java +++ b/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DefaultJobDurationCalculator.java @@ -1,6 +1,6 @@ package org.matsim.freightDemandGeneration; -import org.matsim.freight.carriers.Carrier; +import org.matsim.api.core.v01.Scenario; public class DefaultJobDurationCalculator implements JobDurationCalculator { @Override @@ -19,24 +19,19 @@ public double calculateDeliveryDuration(Integer deliveryDurationPerUnit, int dem } @Override - public void recalculateServiceDurations(Carrier thisCarrier) { - // Do nothing - } - - @Override - public void recalculateShipmentDurations(Carrier thisCarrier) { - // Do nothing + public void recalculateJobDurations(Scenario scenario) { + // do nothing } /** - * @param serviceTimePerUnit service time per unit + * @param timePerUnit time per unit * @param demandForThisService demand for this service * @return default calculation */ - private int getDefaultCalculation(int serviceTimePerUnit, int demandForThisService) { + private int getDefaultCalculation(int timePerUnit, int demandForThisService) { if (demandForThisService == 0) - return serviceTimePerUnit; + return timePerUnit; else - return serviceTimePerUnit * demandForThisService; + return timePerUnit * demandForThisService; } } diff --git a/contribs/application/src/main/java/org/matsim/freightDemandGeneration/JobDurationCalculator.java b/contribs/application/src/main/java/org/matsim/freightDemandGeneration/JobDurationCalculator.java index 3c38935138d..85d30908fa0 100644 --- a/contribs/application/src/main/java/org/matsim/freightDemandGeneration/JobDurationCalculator.java +++ b/contribs/application/src/main/java/org/matsim/freightDemandGeneration/JobDurationCalculator.java @@ -1,15 +1,39 @@ package org.matsim.freightDemandGeneration; -import org.matsim.freight.carriers.Carrier; +import org.matsim.api.core.v01.Scenario; public interface JobDurationCalculator { + /** + * Calculates the duration of a service in seconds. + * + * @param serviceDurationPerUnit in seconds + * @param demandForThisService amount of demand for this service + * @return duration in seconds + */ double calculateServiceDuration(Integer serviceDurationPerUnit, int demandForThisService); + /** + * Calculates the duration of a pickup in seconds. + * + * @param pickupDurationPerUnit in seconds + * @param demandForThisShipment amount of demand for this shipment + * @return duration in seconds + */ double calculatePickupDuration(Integer pickupDurationPerUnit, int demandForThisShipment); + /** + * Calculates the duration of a delivery in seconds. + * + * @param deliveryDurationPerUnit in seconds + * @param demandForThisShipment amount of demand for this shipment + * @return duration in seconds + */ double calculateDeliveryDuration(Integer deliveryDurationPerUnit, int demandForThisShipment); - void recalculateServiceDurations(Carrier thisCarrier); - - void recalculateShipmentDurations(Carrier thisCarrier); + /** + * Recalculates the job durations for all jobs in the scenario. The devault implementation does nothing. + * + * @param scenario scenario + */ + void recalculateJobDurations(Scenario scenario); } From d10e7b2aa426ba944189d6db6f48e6b8325908a9 Mon Sep 17 00:00:00 2001 From: steffenaxer <26229392+steffenaxer@users.noreply.github.com> Date: Sat, 23 Nov 2024 15:27:22 +0100 Subject: [PATCH 49/53] Improve SquareGridZoneSystem performance --- .../grid/square/SquareGridZoneSystem.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/contribs/common/src/main/java/org/matsim/contrib/common/zones/systems/grid/square/SquareGridZoneSystem.java b/contribs/common/src/main/java/org/matsim/contrib/common/zones/systems/grid/square/SquareGridZoneSystem.java index b1319fed1a9..f96e7427b81 100644 --- a/contribs/common/src/main/java/org/matsim/contrib/common/zones/systems/grid/square/SquareGridZoneSystem.java +++ b/contribs/common/src/main/java/org/matsim/contrib/common/zones/systems/grid/square/SquareGridZoneSystem.java @@ -36,6 +36,7 @@ import java.util.*; import java.util.function.Predicate; +import java.util.stream.Collectors; public class SquareGridZoneSystem implements GridZoneSystem { @@ -55,6 +56,7 @@ public class SquareGridZoneSystem implements GridZoneSystem { private final IdMap zones = new IdMap<>(Zone.class); private final IdMap> zoneToLinksMap = new IdMap<>(Zone.class); + private final Map> index2Link; private final Network network; @@ -76,6 +78,7 @@ public SquareGridZoneSystem(Network network, double cellSize, boolean filterByNe this.rows = Math.max(1, (int) Math.ceil((maxY - minY) / cellSize)); this.cols = Math.max(1, (int)Math.ceil((maxX - minX) / cellSize)); this.internalZones = new Zone[rows * cols +1]; + this.index2Link = getIndexToLink(network); if(filterByNetwork) { network.getLinks().values().forEach(l -> getOrCreateZone(l.getToNode().getCoord())); @@ -126,13 +129,7 @@ private Optional getOrCreateZone(Coord coord) { if(zoneFilter.test(zone)) { internalZones[index] = zone; zones.put(zone.getId(), zone); - - for (Link link : network.getLinks().values()) { - if (getIndex(link.getToNode().getCoord()) == index) { - List links = zoneToLinksMap.computeIfAbsent(zone.getId(), zoneId -> new ArrayList<>()); - links.add(link); - } - } + zoneToLinksMap.computeIfAbsent(zone.getId(), zoneId -> new ArrayList<>()).addAll(index2Link.get(index)); } else { return Optional.empty(); } @@ -140,6 +137,11 @@ private Optional getOrCreateZone(Coord coord) { return Optional.of(zone); } + private Map> getIndexToLink(Network network) { + return network.getLinks().values().stream() + .collect(Collectors.groupingBy(link -> getIndex(link.getToNode().getCoord()))); + } + private PreparedPolygon getGeometry(int r, int c) { List coords = new ArrayList<>(); coords.add(new Coord(minX + c * cellSize, minY + r * cellSize)); From f3ab912fbdba4d078793aa1f2f39d3b85cfff1c6 Mon Sep 17 00:00:00 2001 From: steffenaxer <26229392+steffenaxer@users.noreply.github.com> Date: Sat, 23 Nov 2024 15:51:20 +0100 Subject: [PATCH 50/53] Bugfix --- .../systems/grid/square/SquareGridZoneSystem.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/contribs/common/src/main/java/org/matsim/contrib/common/zones/systems/grid/square/SquareGridZoneSystem.java b/contribs/common/src/main/java/org/matsim/contrib/common/zones/systems/grid/square/SquareGridZoneSystem.java index f96e7427b81..f47ed5669c9 100644 --- a/contribs/common/src/main/java/org/matsim/contrib/common/zones/systems/grid/square/SquareGridZoneSystem.java +++ b/contribs/common/src/main/java/org/matsim/contrib/common/zones/systems/grid/square/SquareGridZoneSystem.java @@ -56,7 +56,7 @@ public class SquareGridZoneSystem implements GridZoneSystem { private final IdMap zones = new IdMap<>(Zone.class); private final IdMap> zoneToLinksMap = new IdMap<>(Zone.class); - private final Map> index2Link; + private final Map> index2Links; private final Network network; @@ -78,7 +78,7 @@ public SquareGridZoneSystem(Network network, double cellSize, boolean filterByNe this.rows = Math.max(1, (int) Math.ceil((maxY - minY) / cellSize)); this.cols = Math.max(1, (int)Math.ceil((maxX - minX) / cellSize)); this.internalZones = new Zone[rows * cols +1]; - this.index2Link = getIndexToLink(network); + this.index2Links = getIndexToLink(network); if(filterByNetwork) { network.getLinks().values().forEach(l -> getOrCreateZone(l.getToNode().getCoord())); @@ -129,7 +129,12 @@ private Optional getOrCreateZone(Coord coord) { if(zoneFilter.test(zone)) { internalZones[index] = zone; zones.put(zone.getId(), zone); - zoneToLinksMap.computeIfAbsent(zone.getId(), zoneId -> new ArrayList<>()).addAll(index2Link.get(index)); + List linkList = zoneToLinksMap.computeIfAbsent(zone.getId(), zoneId -> new ArrayList<>()); + List links = index2Links.get(index); + if(links!=null) + { + linkList.addAll(links); + } } else { return Optional.empty(); } From 77c2647c37a057aeb6c356f3eeb0132c5cee08ce Mon Sep 17 00:00:00 2001 From: nkuehnel Date: Mon, 25 Nov 2024 13:43:51 +0100 Subject: [PATCH 51/53] add zonal rejection (rates) to output --- .../zonal/DrtZonalWaitTimesAnalyzer.java | 44 ++++++++++++++----- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtZonalWaitTimesAnalyzer.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtZonalWaitTimesAnalyzer.java index ce140ce1772..610511c61e2 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtZonalWaitTimesAnalyzer.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtZonalWaitTimesAnalyzer.java @@ -37,6 +37,7 @@ import org.matsim.contrib.drt.analysis.DrtEventSequenceCollector; import org.matsim.contrib.drt.analysis.DrtEventSequenceCollector.EventSequence; import org.matsim.contrib.drt.run.DrtConfigGroup; +import org.matsim.contrib.dvrp.optimizer.Request; import org.matsim.core.controler.events.IterationEndsEvent; import org.matsim.core.controler.events.ShutdownEvent; import org.matsim.core.controler.listener.IterationEndsListener; @@ -79,7 +80,7 @@ public void notifyIterationEnds(IterationEndsEvent event) { } public void write(String fileName) { - Map, DescriptiveStatistics> zoneStats = createZonalStats(); + Map, ZonalStatistics> zoneStats = createZonalStats(); BufferedWriter bw = IOUtils.getBufferedWriter(fileName); try { DecimalFormat format = new DecimalFormat(); @@ -90,7 +91,8 @@ public void write(String fileName) { String header = new StringJoiner(delimiter) .add("zone").add("centerX").add("centerY").add("nRequests") .add("sumWaitTime").add("meanWaitTime").add("min").add("max") - .add("p95").add("p90").add("p80").add("p75").add("p50").toString(); + .add("p95").add("p90").add("p80").add("p75").add("p50") + .add("rejections").add("rejectionRate").toString(); bw.append(header); // sorted output SortedSet> zoneIdsAndOutside = new TreeSet<>(zones.getZones().keySet()); @@ -100,7 +102,8 @@ public void write(String fileName) { Zone drtZone = zones.getZones().get(zoneId); String centerX = drtZone != null ? String.valueOf(drtZone.getCentroid().getX()) : notAvailableString; String centerY = drtZone != null ? String.valueOf(drtZone.getCentroid().getY()) : notAvailableString; - DescriptiveStatistics stats = zoneStats.get(zoneId); + DescriptiveStatistics stats = zoneStats.get(zoneId).waitStats; + Set> rejections = zoneStats.get(zoneId).rejections; bw.newLine(); bw.append( new StringJoiner(delimiter) @@ -116,7 +119,10 @@ public void write(String fileName) { .add(String.valueOf(stats.getPercentile(90))) .add(String.valueOf(stats.getPercentile(80))) .add(String.valueOf(stats.getPercentile(75))) - .add(String.valueOf(stats.getPercentile(50))).toString() + .add(String.valueOf(stats.getPercentile(50))) + .add(String.valueOf(rejections.size())) + .add(String.valueOf(rejections.size() / (double) (rejections.size() + stats.getN()))) + .toString() ); } bw.flush(); @@ -126,13 +132,15 @@ public void write(String fileName) { } } - private Map, DescriptiveStatistics> createZonalStats() { - Map, DescriptiveStatistics> zoneStats = new IdMap<>(Zone.class); + record ZonalStatistics(DescriptiveStatistics waitStats, Set> rejections){} + + private Map, ZonalStatistics> createZonalStats() { + Map, ZonalStatistics> zoneStats = new IdMap<>(Zone.class); // prepare stats for all zones for (Id zoneId : zones.getZones().keySet()) { - zoneStats.put(zoneId, new DescriptiveStatistics()); + zoneStats.put(zoneId, new ZonalStatistics(new DescriptiveStatistics(), new HashSet<>())); } - zoneStats.put(zoneIdForOutsideOfZonalSystem, new DescriptiveStatistics()); + zoneStats.put(zoneIdForOutsideOfZonalSystem, new ZonalStatistics(new DescriptiveStatistics(), new HashSet<>())); for (EventSequence seq : requestAnalyzer.getPerformedRequestSequences().values()) { for (Map.Entry, EventSequence.PersonEvents> entry : seq.getPersonEvents().entrySet()) { @@ -140,10 +148,17 @@ private Map, DescriptiveStatistics> createZonalStats() { Id zone = zones.getZoneForLinkId(seq.getSubmitted().getFromLinkId()) .map(Identifiable::getId).orElse(zoneIdForOutsideOfZonalSystem); double waitTime = entry.getValue().getPickedUp().get() .getTime() - seq.getSubmitted().getTime(); - zoneStats.get(zone).addValue(waitTime); + zoneStats.get(zone).waitStats.addValue(waitTime); } } } + + for (EventSequence seq : requestAnalyzer.getRejectedRequestSequences().values()) { + Id zone = zones.getZoneForLinkId(seq.getSubmitted().getFromLinkId()) + .map(Identifiable::getId).orElse(zoneIdForOutsideOfZonalSystem); + zoneStats.get(zone).rejections.add(seq.getSubmitted().getRequestId()); + } + return zoneStats; } @@ -191,16 +206,19 @@ private Collection convertGeometriesToSimpleFeatures(String targe simpleFeatureBuilder.add("p80", Double.class); simpleFeatureBuilder.add("p75", Double.class); simpleFeatureBuilder.add("p50", Double.class); + simpleFeatureBuilder.add("rejections", Double.class); + simpleFeatureBuilder.add("rejectRate", Double.class); SimpleFeatureBuilder builder = new SimpleFeatureBuilder(simpleFeatureBuilder.buildFeatureType()); Collection features = new ArrayList<>(); - Map, DescriptiveStatistics> zoneStats = createZonalStats(); + Map, ZonalStatistics> zoneStats = createZonalStats(); for (Zone zone : zones.getZones().values()) { - Object[] routeFeatureAttributes = new Object[14]; + Object[] routeFeatureAttributes = new Object[16]; Geometry geometry = zone.getPreparedGeometry() != null ? zone.getPreparedGeometry().getGeometry() : null; - DescriptiveStatistics stats = zoneStats.get(zone.getId()); + DescriptiveStatistics stats = zoneStats.get(zone.getId()).waitStats; + Set> rejections = zoneStats.get(zone.getId()).rejections; routeFeatureAttributes[0] = geometry; routeFeatureAttributes[1] = zone.getId(); routeFeatureAttributes[2] = zone.getCentroid().getX(); @@ -215,6 +233,8 @@ private Collection convertGeometriesToSimpleFeatures(String targe routeFeatureAttributes[11] = stats.getPercentile(80); routeFeatureAttributes[12] = stats.getPercentile(75); routeFeatureAttributes[13] = stats.getPercentile(50); + routeFeatureAttributes[14] = rejections.size(); + routeFeatureAttributes[15] = rejections.size() / (double) (rejections.size() + stats.getN()); try { features.add(builder.buildFeature(zone.getId().toString(), routeFeatureAttributes)); From b74b3acd28679ebaab670119355ff3f8f4c55497 Mon Sep 17 00:00:00 2001 From: u229187 Date: Mon, 25 Nov 2024 14:24:37 +0100 Subject: [PATCH 52/53] change output dir --- .../cadyts/marginals/ModalDistanceAndCountsCadytsIT.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/contribs/vsp/src/test/java/playground/vsp/cadyts/marginals/ModalDistanceAndCountsCadytsIT.java b/contribs/vsp/src/test/java/playground/vsp/cadyts/marginals/ModalDistanceAndCountsCadytsIT.java index dbdb804cb9b..3f1ed342aa5 100644 --- a/contribs/vsp/src/test/java/playground/vsp/cadyts/marginals/ModalDistanceAndCountsCadytsIT.java +++ b/contribs/vsp/src/test/java/playground/vsp/cadyts/marginals/ModalDistanceAndCountsCadytsIT.java @@ -1,5 +1,4 @@ package playground.vsp.cadyts.marginals; -import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; @@ -63,13 +62,14 @@ private static DistanceDistribution createDistanceDistribution() { return result; } - private Config createConfig() { + private Config createConfig(String outputSuffix) { Config config = ConfigUtils.createConfig(); String[] modes = new String[]{TransportMode.car, TransportMode.bike}; config.routing().setNetworkRouteConsistencyCheck(RoutingConfigGroup.NetworkRouteConsistencyCheck.disable); - config.controller().setOutputDirectory(this.utils.getOutputDirectory()); + String outputDirectory = this.utils.getOutputDirectory(); + config.controller().setOutputDirectory(outputDirectory.substring(0,outputDirectory.length()-1)+outputSuffix); config.controller().setOverwriteFileSetting(OutputDirectoryHierarchy.OverwriteFileSetting.deleteDirectoryIfExists); config.controller().setLastIteration(40); @@ -244,7 +244,7 @@ private static Plan createPlan(String mode, String endLink, Network network, Pop @MethodSource("arguments") void test(double countsWeight, double modalDistanceWeight) { - Config config = createConfig(); + Config config = createConfig(countsWeight+"_"+modalDistanceWeight); CadytsConfigGroup cadytsConfigGroup = new CadytsConfigGroup(); cadytsConfigGroup.setWriteAnalysisFile(true); config.addModule(cadytsConfigGroup); From fa0499046a6f9d5557cf3b6ffd7bf7620a5b3809 Mon Sep 17 00:00:00 2001 From: "Johan W. Joubert" Date: Tue, 26 Nov 2024 08:47:25 +0100 Subject: [PATCH 53/53] =?UTF-8?q?Renamed=20packaged=20in=20line=20with=20f?= =?UTF-8?q?reight=20and=20vsp=E2=80=99s=20logistics?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../freightreceiver => freight/receiver}/Order.java | 2 +- .../freightreceiver => freight/receiver}/ProductType.java | 2 +- .../freightreceiver => freight/receiver}/Receiver.java | 2 +- .../receiver}/ReceiverAgent.java | 2 +- .../receiver}/ReceiverConfigGroup.java | 2 +- .../receiver}/ReceiverControlerListener.java | 6 +++--- .../receiver}/ReceiverCostAllocation.java | 2 +- .../receiver}/ReceiverCostAllocationEqualProportion.java | 2 +- .../receiver}/ReceiverCostAllocationFixed.java | 2 +- .../receiver}/ReceiverCostAllocationType.java | 2 +- .../receiver}/ReceiverImpl.java | 2 +- .../receiver}/ReceiverModule.java | 5 +++-- .../receiver}/ReceiverOrder.java | 2 +- .../receiver}/ReceiverPlan.java | 4 ++-- .../receiver}/ReceiverProduct.java | 2 +- .../receiver}/ReceiverReplanningType.java | 2 +- .../receiver}/ReceiverScoreStats.java | 4 ++-- .../receiver}/ReceiverScoringFunctionFactory.java | 2 +- .../ReceiverScoringFunctionFactoryMoneyOnly.java | 2 +- .../receiver}/ReceiverTracker.java | 2 +- .../ReceiverTriggersCarrierReplanningListener.java | 4 ++-- .../receiver}/ReceiverUtils.java | 2 +- .../freightreceiver => freight/receiver}/Receivers.java | 2 +- .../receiver}/ReceiversReader.java | 2 +- .../receiver}/ReceiversReaderV2.java | 4 ++-- .../receiver}/ReceiversWriter.java | 2 +- .../receiver}/ReceiversWriterHandler.java | 2 +- .../receiver}/ReceiversWriterHandlerImplV1.java | 2 +- .../receiver}/ReceiversWriterHandlerImplV2.java | 2 +- .../receiver}/ReorderPolicy.java | 2 +- .../receiver}/SSReorderPolicy.java | 2 +- .../receiver}/UsecasesCarrierScoringFunctionFactory.java | 2 +- .../receiver}/collaboration/Coalition.java | 4 ++-- .../receiver}/collaboration/CollaborationUtils.java | 4 ++-- .../receiver}/collaboration/CollaborationUtilsNew.java | 4 ++-- .../receiver}/collaboration/MutableCoalition.java | 4 ++-- .../receiver}/collaboration/OrderSizeMutator.java | 8 ++++---- .../receiver}/collaboration/TimeWindowMutator.java | 4 ++-- .../receiver}/multiday/MultidayUtils.java | 2 +- .../receiver}/replanning/CollaborationStatusMutator.java | 6 +++--- .../replanning/OrderFrequencyStrategyManager.java | 8 ++++---- .../receiver}/replanning/ReceiverReplanningUtils.java | 4 ++-- .../receiver}/replanning/ReceiverStrategyManager.java | 6 +++--- .../receiver}/replanning/ReceiverStrategyManagerImpl.java | 6 +++--- .../receiver}/replanning/ServiceTimeMutator.java | 8 ++++---- .../replanning/ServiceTimeStrategyManagerProvider.java | 6 +++--- .../replanning/TimeWindowStrategyManagerFactory.java | 6 +++--- .../receiver}/replanning/TimeWindowUpperBoundMutator.java | 4 ++-- .../run/chessboard/ReceiverChessboardParameters.java | 4 ++-- .../run/chessboard/ReceiverChessboardScenario.java | 6 +++--- .../RunReceiverChessboardWithEqualProportionCost.java | 8 ++++---- .../RunReceiverChessboardWithFixedCarrierCost.java | 8 ++++---- .../receiver}/ReceiverCostAllocationFixedTest.java | 2 +- .../receiver}/ReceiverPlanTest.java | 2 +- .../receiver}/ReceiversReaderTest.java | 4 ++-- .../receiver}/ReceiversTest.java | 4 ++-- .../receiver}/ReceiversWriterTest.java | 4 ++-- .../receiver}/SSReorderPolicyTest.java | 2 +- .../receiver}/ReceiversReaderTest/receivers_v2_basic.xml | 0 .../receiver}/ReceiversReaderTest/receivers_v2_full.xml | 0 .../receiver}/ReceiversTest/receivers_v2.xml | 0 61 files changed, 104 insertions(+), 103 deletions(-) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/Order.java (99%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/ProductType.java (98%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/Receiver.java (98%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/ReceiverAgent.java (98%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/ReceiverConfigGroup.java (99%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/ReceiverControlerListener.java (98%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/ReceiverCostAllocation.java (96%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/ReceiverCostAllocationEqualProportion.java (98%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/ReceiverCostAllocationFixed.java (97%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/ReceiverCostAllocationType.java (96%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/ReceiverImpl.java (99%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/ReceiverModule.java (96%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/ReceiverOrder.java (98%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/ReceiverPlan.java (98%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/ReceiverProduct.java (98%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/ReceiverReplanningType.java (96%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/ReceiverScoreStats.java (98%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/ReceiverScoringFunctionFactory.java (97%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/ReceiverScoringFunctionFactoryMoneyOnly.java (98%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/ReceiverTracker.java (98%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/ReceiverTriggersCarrierReplanningListener.java (98%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/ReceiverUtils.java (98%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/Receivers.java (99%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/ReceiversReader.java (98%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/ReceiversReaderV2.java (98%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/ReceiversWriter.java (99%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/ReceiversWriterHandler.java (98%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/ReceiversWriterHandlerImplV1.java (99%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/ReceiversWriterHandlerImplV2.java (99%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/ReorderPolicy.java (97%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/SSReorderPolicy.java (98%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/UsecasesCarrierScoringFunctionFactory.java (99%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/collaboration/Coalition.java (86%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/collaboration/CollaborationUtils.java (97%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/collaboration/CollaborationUtilsNew.java (70%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/collaboration/MutableCoalition.java (93%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/collaboration/OrderSizeMutator.java (93%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/collaboration/TimeWindowMutator.java (98%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/multiday/MultidayUtils.java (89%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/replanning/CollaborationStatusMutator.java (88%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/replanning/OrderFrequencyStrategyManager.java (91%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/replanning/ReceiverReplanningUtils.java (81%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/replanning/ReceiverStrategyManager.java (88%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/replanning/ReceiverStrategyManagerImpl.java (94%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/replanning/ServiceTimeMutator.java (93%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/replanning/ServiceTimeStrategyManagerProvider.java (95%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/replanning/TimeWindowStrategyManagerFactory.java (92%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/replanning/TimeWindowUpperBoundMutator.java (97%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/run/chessboard/ReceiverChessboardParameters.java (94%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/run/chessboard/ReceiverChessboardScenario.java (98%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/run/chessboard/RunReceiverChessboardWithEqualProportionCost.java (93%) rename contribs/freightreceiver/src/main/java/org/matsim/{contrib/freightreceiver => freight/receiver}/run/chessboard/RunReceiverChessboardWithFixedCarrierCost.java (93%) rename contribs/freightreceiver/src/test/java/org/matsim/{contrib/freightreceiver => freight/receiver}/ReceiverCostAllocationFixedTest.java (88%) rename contribs/freightreceiver/src/test/java/org/matsim/{contrib/freightreceiver => freight/receiver}/ReceiverPlanTest.java (97%) rename contribs/freightreceiver/src/test/java/org/matsim/{contrib/freightreceiver => freight/receiver}/ReceiversReaderTest.java (98%) rename contribs/freightreceiver/src/test/java/org/matsim/{contrib/freightreceiver => freight/receiver}/ReceiversTest.java (97%) rename contribs/freightreceiver/src/test/java/org/matsim/{contrib/freightreceiver => freight/receiver}/ReceiversWriterTest.java (96%) rename contribs/freightreceiver/src/test/java/org/matsim/{contrib/freightreceiver => freight/receiver}/SSReorderPolicyTest.java (97%) rename contribs/freightreceiver/test/input/org/matsim/{contrib/freightreceiver => freight/receiver}/ReceiversReaderTest/receivers_v2_basic.xml (100%) rename contribs/freightreceiver/test/input/org/matsim/{contrib/freightreceiver => freight/receiver}/ReceiversReaderTest/receivers_v2_full.xml (100%) rename contribs/freightreceiver/test/input/org/matsim/{contrib/freightreceiver => freight/receiver}/ReceiversTest/receivers_v2.xml (100%) diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/Order.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/Order.java similarity index 99% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/Order.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/Order.java index 6060e7ba4ee..d2cd76201eb 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/Order.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/Order.java @@ -16,7 +16,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ProductType.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ProductType.java similarity index 98% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ProductType.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ProductType.java index 4589cd7b3b9..6c7b6f84f97 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ProductType.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ProductType.java @@ -16,7 +16,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.Identifiable; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/Receiver.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/Receiver.java similarity index 98% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/Receiver.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/Receiver.java index 631130ba87a..3faee4fc53b 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/Receiver.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/Receiver.java @@ -16,7 +16,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverAgent.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverAgent.java similarity index 98% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverAgent.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverAgent.java index df29bc43a71..df4c6d6f948 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverAgent.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverAgent.java @@ -16,7 +16,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverConfigGroup.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverConfigGroup.java similarity index 99% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverConfigGroup.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverConfigGroup.java index dfbc6cbe4a5..e42150f9b8f 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverConfigGroup.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverConfigGroup.java @@ -15,7 +15,7 @@ * See also COPYING, LICENSE and WARRANTY file * * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverControlerListener.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverControlerListener.java similarity index 98% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverControlerListener.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverControlerListener.java index 10fe1be6bdd..852452663a6 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverControlerListener.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverControlerListener.java @@ -16,7 +16,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import com.google.inject.Inject; import org.apache.logging.log4j.LogManager; @@ -29,8 +29,8 @@ import org.matsim.freight.carriers.CarriersUtils; import org.matsim.freight.carriers.ScheduledTour; import org.matsim.freight.carriers.Tour; -import org.matsim.contrib.freightreceiver.collaboration.CollaborationUtils; -import org.matsim.contrib.freightreceiver.replanning.ReceiverStrategyManager; +import org.matsim.freight.receiver.collaboration.CollaborationUtils; +import org.matsim.freight.receiver.replanning.ReceiverStrategyManager; import org.matsim.core.config.ConfigUtils; import org.matsim.core.controler.events.*; import org.matsim.core.controler.listener.*; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverCostAllocation.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverCostAllocation.java similarity index 96% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverCostAllocation.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverCostAllocation.java index 72ccdeb68fa..c01f7425f9b 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverCostAllocation.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverCostAllocation.java @@ -18,7 +18,7 @@ * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.matsim.freight.carriers.Carrier; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverCostAllocationEqualProportion.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverCostAllocationEqualProportion.java similarity index 98% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverCostAllocationEqualProportion.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverCostAllocationEqualProportion.java index 6f85efcd2f1..ae79d2db6c5 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverCostAllocationEqualProportion.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverCostAllocationEqualProportion.java @@ -18,7 +18,7 @@ * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import com.google.inject.Inject; import org.matsim.api.core.v01.Id; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverCostAllocationFixed.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverCostAllocationFixed.java similarity index 97% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverCostAllocationFixed.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverCostAllocationFixed.java index 5f3a6a2dea2..fed9d76f609 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverCostAllocationFixed.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverCostAllocationFixed.java @@ -17,7 +17,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.apache.logging.log4j.LogManager; import org.matsim.freight.carriers.Carrier; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverCostAllocationType.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverCostAllocationType.java similarity index 96% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverCostAllocationType.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverCostAllocationType.java index 9ad1862b9c9..c4b110f8266 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverCostAllocationType.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverCostAllocationType.java @@ -18,7 +18,7 @@ * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; /** * The supported ways in which the carrier's cost is spread among the receivers. diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverImpl.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverImpl.java similarity index 99% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverImpl.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverImpl.java index 1f29889a0a6..59b70767176 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverImpl.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverImpl.java @@ -16,7 +16,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverModule.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverModule.java similarity index 96% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverModule.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverModule.java index aac11b5e7b2..a108dbf87f4 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverModule.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverModule.java @@ -16,14 +16,15 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import org.matsim.freight.carriers.Carrier; -import org.matsim.contrib.freightreceiver.replanning.*; import org.matsim.core.config.ConfigUtils; import org.matsim.core.controler.AbstractModule; +import org.matsim.freight.receiver.replanning.ReceiverReplanningUtils; +import org.matsim.freight.receiver.replanning.ReceiverStrategyManager; public final class ReceiverModule extends AbstractModule { final private static Logger LOG = LogManager.getLogger(ReceiverModule.class); diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverOrder.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverOrder.java similarity index 98% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverOrder.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverOrder.java index 081004dcb71..cad5c103842 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverOrder.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverOrder.java @@ -16,7 +16,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverPlan.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverPlan.java similarity index 98% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverPlan.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverPlan.java index 0497d364b3d..88a8fe76268 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverPlan.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverPlan.java @@ -16,7 +16,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -25,7 +25,7 @@ import org.matsim.api.core.v01.population.Person; import org.matsim.freight.carriers.Carrier; import org.matsim.freight.carriers.TimeWindow; -import org.matsim.contrib.freightreceiver.collaboration.CollaborationUtils; +import org.matsim.freight.receiver.collaboration.CollaborationUtils; import org.matsim.utils.objectattributes.attributable.Attributable; import org.matsim.utils.objectattributes.attributable.Attributes; import org.matsim.utils.objectattributes.attributable.AttributesImpl; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverProduct.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverProduct.java similarity index 98% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverProduct.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverProduct.java index 40489f44c23..5e734d77247 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverProduct.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverProduct.java @@ -16,7 +16,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; /** * Returns a new instance of a receiver product with associated information, diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverReplanningType.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverReplanningType.java similarity index 96% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverReplanningType.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverReplanningType.java index d8bd5df43dc..f1845f3d2cb 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverReplanningType.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverReplanningType.java @@ -15,7 +15,7 @@ * See also COPYING, LICENSE and WARRANTY file * * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; public enum ReceiverReplanningType { serviceTime, timeWindow, orderFrequency, afterHoursTimeWindow diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverScoreStats.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverScoreStats.java similarity index 98% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverScoreStats.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverScoreStats.java index a9a63491a07..a6b260fc449 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverScoreStats.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverScoreStats.java @@ -1,11 +1,11 @@ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import com.google.inject.Inject; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.matsim.api.core.v01.Scenario; import org.matsim.freight.carriers.CarriersUtils; -import org.matsim.contrib.freightreceiver.collaboration.CollaborationUtils; +import org.matsim.freight.receiver.collaboration.CollaborationUtils; import org.matsim.core.config.ConfigUtils; import org.matsim.core.controler.events.IterationEndsEvent; import org.matsim.core.controler.events.ShutdownEvent; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverScoringFunctionFactory.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverScoringFunctionFactory.java similarity index 97% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverScoringFunctionFactory.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverScoringFunctionFactory.java index 81e60676e02..ade37d5354e 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverScoringFunctionFactory.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverScoringFunctionFactory.java @@ -16,7 +16,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.matsim.core.scoring.ScoringFunction; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverScoringFunctionFactoryMoneyOnly.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverScoringFunctionFactoryMoneyOnly.java similarity index 98% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverScoringFunctionFactoryMoneyOnly.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverScoringFunctionFactoryMoneyOnly.java index 57357050ebb..e937074d616 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverScoringFunctionFactoryMoneyOnly.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverScoringFunctionFactoryMoneyOnly.java @@ -16,7 +16,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.apache.logging.log4j.LogManager; import org.matsim.core.scoring.ScoringFunction; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverTracker.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverTracker.java similarity index 98% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverTracker.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverTracker.java index a03dc19cf06..e1fd6bc7ef5 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverTracker.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverTracker.java @@ -16,7 +16,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.Scenario; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverTriggersCarrierReplanningListener.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverTriggersCarrierReplanningListener.java similarity index 98% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverTriggersCarrierReplanningListener.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverTriggersCarrierReplanningListener.java index 62a2a507aa2..2b8c4a6dfb9 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverTriggersCarrierReplanningListener.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverTriggersCarrierReplanningListener.java @@ -15,7 +15,7 @@ * See also COPYING, LICENSE and WARRANTY file * * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import com.graphhopper.jsprit.core.algorithm.VehicleRoutingAlgorithm; import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem; @@ -29,7 +29,7 @@ import org.matsim.freight.carriers.jsprit.MatsimJspritFactory; import org.matsim.freight.carriers.jsprit.NetworkBasedTransportCosts; import org.matsim.freight.carriers.jsprit.NetworkRouter; -import org.matsim.contrib.freightreceiver.collaboration.CollaborationUtils; +import org.matsim.freight.receiver.collaboration.CollaborationUtils; import org.matsim.core.config.ConfigUtils; import org.matsim.core.controler.events.IterationStartsEvent; import org.matsim.core.controler.listener.IterationStartsListener; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverUtils.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverUtils.java similarity index 98% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverUtils.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverUtils.java index dcd2861daed..e9b1b293368 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverUtils.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverUtils.java @@ -1,4 +1,4 @@ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/Receivers.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/Receivers.java similarity index 99% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/Receivers.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/Receivers.java index 3d042480928..640aa31d6b8 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/Receivers.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/Receivers.java @@ -16,7 +16,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiversReader.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiversReader.java similarity index 98% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiversReader.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiversReader.java index 63afdf1c4cd..1c68dd3dbfe 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiversReader.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiversReader.java @@ -18,7 +18,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.matsim.core.utils.io.MatsimXmlParser; import org.xml.sax.Attributes; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiversReaderV2.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiversReaderV2.java similarity index 98% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiversReaderV2.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiversReaderV2.java index 2036326c078..b886be795f8 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiversReaderV2.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiversReaderV2.java @@ -18,13 +18,13 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; import org.matsim.freight.carriers.Carrier; import org.matsim.freight.carriers.TimeWindow; -import org.matsim.contrib.freightreceiver.collaboration.CollaborationUtils; +import org.matsim.freight.receiver.collaboration.CollaborationUtils; import org.matsim.core.api.internal.MatsimReader; import org.matsim.core.utils.io.MatsimXmlParser; import org.matsim.core.utils.misc.Counter; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiversWriter.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiversWriter.java similarity index 99% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiversWriter.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiversWriter.java index cd9e2f33a06..68b37813398 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiversWriter.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiversWriter.java @@ -18,7 +18,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiversWriterHandler.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiversWriterHandler.java similarity index 98% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiversWriterHandler.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiversWriterHandler.java index 09172159e06..1ceacde5d4b 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiversWriterHandler.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiversWriterHandler.java @@ -18,7 +18,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.matsim.freight.carriers.TimeWindow; import java.io.BufferedWriter; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiversWriterHandlerImplV1.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiversWriterHandlerImplV1.java similarity index 99% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiversWriterHandlerImplV1.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiversWriterHandlerImplV1.java index ecc7b58f43e..4e5a4b2e262 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiversWriterHandlerImplV1.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiversWriterHandlerImplV1.java @@ -18,7 +18,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.matsim.freight.carriers.TimeWindow; import org.matsim.core.utils.misc.Time; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiversWriterHandlerImplV2.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiversWriterHandlerImplV2.java similarity index 99% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiversWriterHandlerImplV2.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiversWriterHandlerImplV2.java index c2b8fe50f1b..b9091c62111 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiversWriterHandlerImplV2.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiversWriterHandlerImplV2.java @@ -18,7 +18,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.matsim.freight.carriers.TimeWindow; import org.matsim.core.utils.misc.Time; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReorderPolicy.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReorderPolicy.java similarity index 97% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReorderPolicy.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReorderPolicy.java index e04152e5e30..9447bb3b8bc 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReorderPolicy.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReorderPolicy.java @@ -18,7 +18,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.matsim.utils.objectattributes.attributable.Attributable; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/SSReorderPolicy.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/SSReorderPolicy.java similarity index 98% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/SSReorderPolicy.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/SSReorderPolicy.java index 9928bbc6191..f9620ef58b2 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/SSReorderPolicy.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/SSReorderPolicy.java @@ -18,7 +18,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.matsim.utils.objectattributes.attributable.Attributes; import org.matsim.utils.objectattributes.attributable.AttributesImpl; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/UsecasesCarrierScoringFunctionFactory.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/UsecasesCarrierScoringFunctionFactory.java similarity index 99% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/UsecasesCarrierScoringFunctionFactory.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/UsecasesCarrierScoringFunctionFactory.java index 5cc872f2b50..f1287ff4de3 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/UsecasesCarrierScoringFunctionFactory.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/UsecasesCarrierScoringFunctionFactory.java @@ -1,4 +1,4 @@ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/collaboration/Coalition.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/collaboration/Coalition.java similarity index 86% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/collaboration/Coalition.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/collaboration/Coalition.java index 9afea8cdc9e..77e28d853e6 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/collaboration/Coalition.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/collaboration/Coalition.java @@ -1,7 +1,7 @@ -package org.matsim.contrib.freightreceiver.collaboration; +package org.matsim.freight.receiver.collaboration; import org.matsim.freight.carriers.Carrier; -import org.matsim.contrib.freightreceiver.Receiver; +import org.matsim.freight.receiver.Receiver; import org.matsim.utils.objectattributes.attributable.Attributable; import java.util.Collection; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/collaboration/CollaborationUtils.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/collaboration/CollaborationUtils.java similarity index 97% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/collaboration/CollaborationUtils.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/collaboration/CollaborationUtils.java index 25e73445613..3775eec413b 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/collaboration/CollaborationUtils.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/collaboration/CollaborationUtils.java @@ -1,4 +1,4 @@ -package org.matsim.contrib.freightreceiver.collaboration; +package org.matsim.freight.receiver.collaboration; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -7,7 +7,7 @@ import org.matsim.freight.carriers.Carrier; import org.matsim.freight.carriers.CarriersUtils; import org.matsim.freight.carriers.Carriers; -import org.matsim.contrib.freightreceiver.*; +import org.matsim.freight.receiver.*; public class CollaborationUtils{ private CollaborationUtils(){} // do not instantiate diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/collaboration/CollaborationUtilsNew.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/collaboration/CollaborationUtilsNew.java similarity index 70% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/collaboration/CollaborationUtilsNew.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/collaboration/CollaborationUtilsNew.java index c3c3d3d544e..68576dc0ea3 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/collaboration/CollaborationUtilsNew.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/collaboration/CollaborationUtilsNew.java @@ -1,7 +1,7 @@ -package org.matsim.contrib.freightreceiver.collaboration; +package org.matsim.freight.receiver.collaboration; import org.matsim.freight.carriers.Carriers; -import org.matsim.contrib.freightreceiver.*; +import org.matsim.freight.receiver.Receivers; /** * Class with utilities to handle the collaboration between {@link Carriers} diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/collaboration/MutableCoalition.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/collaboration/MutableCoalition.java similarity index 93% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/collaboration/MutableCoalition.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/collaboration/MutableCoalition.java index 4799f493912..c6597ff695d 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/collaboration/MutableCoalition.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/collaboration/MutableCoalition.java @@ -1,8 +1,8 @@ -package org.matsim.contrib.freightreceiver.collaboration; +package org.matsim.freight.receiver.collaboration; import org.matsim.freight.carriers.Carrier; -import org.matsim.contrib.freightreceiver.Receiver; +import org.matsim.freight.receiver.Receiver; import org.matsim.utils.objectattributes.attributable.Attributes; import org.matsim.utils.objectattributes.attributable.AttributesImpl; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/collaboration/OrderSizeMutator.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/collaboration/OrderSizeMutator.java similarity index 93% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/collaboration/OrderSizeMutator.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/collaboration/OrderSizeMutator.java index 99b91c04395..118f6ed3b84 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/collaboration/OrderSizeMutator.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/collaboration/OrderSizeMutator.java @@ -16,11 +16,11 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver.collaboration; +package org.matsim.freight.receiver.collaboration; -import org.matsim.contrib.freightreceiver.Order; -import org.matsim.contrib.freightreceiver.ReceiverOrder; -import org.matsim.contrib.freightreceiver.ReceiverPlan; +import org.matsim.freight.receiver.Order; +import org.matsim.freight.receiver.ReceiverOrder; +import org.matsim.freight.receiver.ReceiverPlan; import org.matsim.core.gbl.MatsimRandom; import org.matsim.core.replanning.ReplanningContext; import org.matsim.core.replanning.modules.GenericPlanStrategyModule; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/collaboration/TimeWindowMutator.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/collaboration/TimeWindowMutator.java similarity index 98% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/collaboration/TimeWindowMutator.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/collaboration/TimeWindowMutator.java index bf972b057fe..abd734db026 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/collaboration/TimeWindowMutator.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/collaboration/TimeWindowMutator.java @@ -19,10 +19,10 @@ /** * */ -package org.matsim.contrib.freightreceiver.collaboration; +package org.matsim.freight.receiver.collaboration; import org.matsim.freight.carriers.TimeWindow; -import org.matsim.contrib.freightreceiver.ReceiverPlan; +import org.matsim.freight.receiver.ReceiverPlan; import org.matsim.core.gbl.MatsimRandom; import org.matsim.core.replanning.ReplanningContext; import org.matsim.core.replanning.modules.GenericPlanStrategyModule; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/multiday/MultidayUtils.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/multiday/MultidayUtils.java similarity index 89% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/multiday/MultidayUtils.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/multiday/MultidayUtils.java index 46fad091944..b5aad6ea53a 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/multiday/MultidayUtils.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/multiday/MultidayUtils.java @@ -1,4 +1,4 @@ -package org.matsim.contrib.freightreceiver.multiday; +package org.matsim.freight.receiver.multiday; import org.matsim.core.utils.misc.OptionalTime; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/CollaborationStatusMutator.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/CollaborationStatusMutator.java similarity index 88% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/CollaborationStatusMutator.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/CollaborationStatusMutator.java index 018a8f64c87..caa840d48c1 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/CollaborationStatusMutator.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/CollaborationStatusMutator.java @@ -1,9 +1,9 @@ -package org.matsim.contrib.freightreceiver.replanning; +package org.matsim.freight.receiver.replanning; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; -import org.matsim.contrib.freightreceiver.ReceiverPlan; -import org.matsim.contrib.freightreceiver.collaboration.CollaborationUtils; +import org.matsim.freight.receiver.ReceiverPlan; +import org.matsim.freight.receiver.collaboration.CollaborationUtils; import org.matsim.core.replanning.ReplanningContext; import org.matsim.core.replanning.modules.GenericPlanStrategyModule; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/OrderFrequencyStrategyManager.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/OrderFrequencyStrategyManager.java similarity index 91% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/OrderFrequencyStrategyManager.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/OrderFrequencyStrategyManager.java index f74750d9924..eb14b8eeb22 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/OrderFrequencyStrategyManager.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/OrderFrequencyStrategyManager.java @@ -1,11 +1,11 @@ -package org.matsim.contrib.freightreceiver.replanning; +package org.matsim.freight.receiver.replanning; import com.google.inject.Inject; import com.google.inject.Provider; import org.matsim.api.core.v01.Scenario; -import org.matsim.contrib.freightreceiver.Receiver; -import org.matsim.contrib.freightreceiver.ReceiverPlan; -import org.matsim.contrib.freightreceiver.collaboration.OrderSizeMutator; +import org.matsim.freight.receiver.Receiver; +import org.matsim.freight.receiver.ReceiverPlan; +import org.matsim.freight.receiver.collaboration.OrderSizeMutator; import org.matsim.core.replanning.GenericPlanStrategyImpl; import org.matsim.core.replanning.selectors.ExpBetaPlanChanger; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/ReceiverReplanningUtils.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/ReceiverReplanningUtils.java similarity index 81% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/ReceiverReplanningUtils.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/ReceiverReplanningUtils.java index 2bdc4eadbb7..71309261c26 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/ReceiverReplanningUtils.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/ReceiverReplanningUtils.java @@ -1,7 +1,7 @@ -package org.matsim.contrib.freightreceiver.replanning; +package org.matsim.freight.receiver.replanning; import com.google.inject.Provider; -import org.matsim.contrib.freightreceiver.ReceiverReplanningType; +import org.matsim.freight.receiver.ReceiverReplanningType; /** * A single entry point for receiver replanning. diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/ReceiverStrategyManager.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/ReceiverStrategyManager.java similarity index 88% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/ReceiverStrategyManager.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/ReceiverStrategyManager.java index 0ef128e441a..f10d7d98145 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/ReceiverStrategyManager.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/ReceiverStrategyManager.java @@ -18,11 +18,11 @@ * *********************************************************************** */ -package org.matsim.contrib.freightreceiver.replanning; +package org.matsim.freight.receiver.replanning; import org.matsim.freight.carriers.controler.CarrierStrategyManager; -import org.matsim.contrib.freightreceiver.Receiver; -import org.matsim.contrib.freightreceiver.ReceiverPlan; +import org.matsim.freight.receiver.Receiver; +import org.matsim.freight.receiver.ReceiverPlan; import org.matsim.core.replanning.GenericStrategyManager; /** diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/ReceiverStrategyManagerImpl.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/ReceiverStrategyManagerImpl.java similarity index 94% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/ReceiverStrategyManagerImpl.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/ReceiverStrategyManagerImpl.java index 4b56bee4470..c164c64a039 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/ReceiverStrategyManagerImpl.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/ReceiverStrategyManagerImpl.java @@ -18,11 +18,11 @@ * *********************************************************************** */ -package org.matsim.contrib.freightreceiver.replanning; +package org.matsim.freight.receiver.replanning; import org.matsim.api.core.v01.population.HasPlansAndId; -import org.matsim.contrib.freightreceiver.Receiver; -import org.matsim.contrib.freightreceiver.ReceiverPlan; +import org.matsim.freight.receiver.Receiver; +import org.matsim.freight.receiver.ReceiverPlan; import org.matsim.core.replanning.GenericPlanStrategy; import org.matsim.core.replanning.GenericStrategyManager; import org.matsim.core.replanning.GenericStrategyManagerImpl; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/ServiceTimeMutator.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/ServiceTimeMutator.java similarity index 93% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/ServiceTimeMutator.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/ServiceTimeMutator.java index 842ad6c5584..7488cc3e748 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/ServiceTimeMutator.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/ServiceTimeMutator.java @@ -16,13 +16,13 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver.replanning; +package org.matsim.freight.receiver.replanning; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; -import org.matsim.contrib.freightreceiver.Order; -import org.matsim.contrib.freightreceiver.ReceiverOrder; -import org.matsim.contrib.freightreceiver.ReceiverPlan; +import org.matsim.freight.receiver.Order; +import org.matsim.freight.receiver.ReceiverOrder; +import org.matsim.freight.receiver.ReceiverPlan; import org.matsim.core.replanning.ReplanningContext; import org.matsim.core.replanning.modules.GenericPlanStrategyModule; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/ServiceTimeStrategyManagerProvider.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/ServiceTimeStrategyManagerProvider.java similarity index 95% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/ServiceTimeStrategyManagerProvider.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/ServiceTimeStrategyManagerProvider.java index 6271e402b57..c88b09a261d 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/ServiceTimeStrategyManagerProvider.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/ServiceTimeStrategyManagerProvider.java @@ -1,10 +1,10 @@ -package org.matsim.contrib.freightreceiver.replanning; +package org.matsim.freight.receiver.replanning; import com.google.inject.Inject; import com.google.inject.Provider; import org.matsim.api.core.v01.Scenario; -import org.matsim.contrib.freightreceiver.Receiver; -import org.matsim.contrib.freightreceiver.ReceiverPlan; +import org.matsim.freight.receiver.Receiver; +import org.matsim.freight.receiver.ReceiverPlan; import org.matsim.core.replanning.GenericPlanStrategy; import org.matsim.core.replanning.GenericPlanStrategyImpl; import org.matsim.core.replanning.selectors.ExpBetaPlanChanger; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/TimeWindowStrategyManagerFactory.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/TimeWindowStrategyManagerFactory.java similarity index 92% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/TimeWindowStrategyManagerFactory.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/TimeWindowStrategyManagerFactory.java index e19d1437dc0..87926d796a2 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/TimeWindowStrategyManagerFactory.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/TimeWindowStrategyManagerFactory.java @@ -1,13 +1,13 @@ /** * */ -package org.matsim.contrib.freightreceiver.replanning; +package org.matsim.freight.receiver.replanning; import com.google.inject.Inject; import com.google.inject.Provider; import org.matsim.api.core.v01.Scenario; -import org.matsim.contrib.freightreceiver.Receiver; -import org.matsim.contrib.freightreceiver.ReceiverPlan; +import org.matsim.freight.receiver.Receiver; +import org.matsim.freight.receiver.ReceiverPlan; import org.matsim.core.replanning.GenericPlanStrategyImpl; import org.matsim.core.replanning.selectors.ExpBetaPlanChanger; import org.matsim.core.utils.misc.Time; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/TimeWindowUpperBoundMutator.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/TimeWindowUpperBoundMutator.java similarity index 97% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/TimeWindowUpperBoundMutator.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/TimeWindowUpperBoundMutator.java index 97ea20b2e20..553504a7862 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/TimeWindowUpperBoundMutator.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/TimeWindowUpperBoundMutator.java @@ -16,10 +16,10 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver.replanning; +package org.matsim.freight.receiver.replanning; import org.matsim.freight.carriers.TimeWindow; -import org.matsim.contrib.freightreceiver.ReceiverPlan; +import org.matsim.freight.receiver.ReceiverPlan; import org.matsim.core.gbl.MatsimRandom; import org.matsim.core.replanning.ReplanningContext; import org.matsim.core.replanning.modules.GenericPlanStrategyModule; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/run/chessboard/ReceiverChessboardParameters.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/run/chessboard/ReceiverChessboardParameters.java similarity index 94% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/run/chessboard/ReceiverChessboardParameters.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/run/chessboard/ReceiverChessboardParameters.java index b5b946942b0..327c65716d6 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/run/chessboard/ReceiverChessboardParameters.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/run/chessboard/ReceiverChessboardParameters.java @@ -16,9 +16,9 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver.run.chessboard; +package org.matsim.freight.receiver.run.chessboard; -import org.matsim.contrib.freightreceiver.ReceiverReplanningType; +import org.matsim.freight.receiver.ReceiverReplanningType; /** * Class to help with setting experimental parameters. These parameters are diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/run/chessboard/ReceiverChessboardScenario.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/run/chessboard/ReceiverChessboardScenario.java similarity index 98% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/run/chessboard/ReceiverChessboardScenario.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/run/chessboard/ReceiverChessboardScenario.java index b5b2f535b45..fd036695370 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/run/chessboard/ReceiverChessboardScenario.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/run/chessboard/ReceiverChessboardScenario.java @@ -18,7 +18,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver.run.chessboard; +package org.matsim.freight.receiver.run.chessboard; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -29,8 +29,8 @@ import org.matsim.api.core.v01.network.NetworkWriter; import org.matsim.freight.carriers.*; import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; -import org.matsim.contrib.freightreceiver.*; -import org.matsim.contrib.freightreceiver.collaboration.CollaborationUtils; +import org.matsim.freight.receiver.*; +import org.matsim.freight.receiver.collaboration.CollaborationUtils; import org.matsim.core.config.Config; import org.matsim.core.config.ConfigUtils; import org.matsim.core.config.ConfigWriter; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/run/chessboard/RunReceiverChessboardWithEqualProportionCost.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/run/chessboard/RunReceiverChessboardWithEqualProportionCost.java similarity index 93% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/run/chessboard/RunReceiverChessboardWithEqualProportionCost.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/run/chessboard/RunReceiverChessboardWithEqualProportionCost.java index 469f45574ee..4e7b9b2607a 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/run/chessboard/RunReceiverChessboardWithEqualProportionCost.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/run/chessboard/RunReceiverChessboardWithEqualProportionCost.java @@ -18,7 +18,7 @@ * *********************************************************************** */ -package org.matsim.contrib.freightreceiver.run.chessboard; +package org.matsim.freight.receiver.run.chessboard; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -26,9 +26,9 @@ import org.matsim.freight.carriers.CarriersUtils; import org.matsim.freight.carriers.Carriers; import org.matsim.freight.carriers.usecases.analysis.CarrierScoreStats; -import org.matsim.contrib.freightreceiver.ReceiverModule; -import org.matsim.contrib.freightreceiver.ReceiverReplanningType; -import org.matsim.contrib.freightreceiver.ReceiverUtils; +import org.matsim.freight.receiver.ReceiverModule; +import org.matsim.freight.receiver.ReceiverReplanningType; +import org.matsim.freight.receiver.ReceiverUtils; import org.matsim.core.controler.Controler; import org.matsim.core.controler.MatsimServices; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/run/chessboard/RunReceiverChessboardWithFixedCarrierCost.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/run/chessboard/RunReceiverChessboardWithFixedCarrierCost.java similarity index 93% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/run/chessboard/RunReceiverChessboardWithFixedCarrierCost.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/run/chessboard/RunReceiverChessboardWithFixedCarrierCost.java index 112785c45b8..2570eb80c16 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/run/chessboard/RunReceiverChessboardWithFixedCarrierCost.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/run/chessboard/RunReceiverChessboardWithFixedCarrierCost.java @@ -18,7 +18,7 @@ * *********************************************************************** */ -package org.matsim.contrib.freightreceiver.run.chessboard; +package org.matsim.freight.receiver.run.chessboard; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -26,9 +26,9 @@ import org.matsim.freight.carriers.CarriersUtils; import org.matsim.freight.carriers.Carriers; import org.matsim.freight.carriers.usecases.analysis.CarrierScoreStats; -import org.matsim.contrib.freightreceiver.ReceiverModule; -import org.matsim.contrib.freightreceiver.ReceiverReplanningType; -import org.matsim.contrib.freightreceiver.ReceiverUtils; +import org.matsim.freight.receiver.ReceiverModule; +import org.matsim.freight.receiver.ReceiverReplanningType; +import org.matsim.freight.receiver.ReceiverUtils; import org.matsim.core.controler.Controler; import org.matsim.core.controler.MatsimServices; diff --git a/contribs/freightreceiver/src/test/java/org/matsim/contrib/freightreceiver/ReceiverCostAllocationFixedTest.java b/contribs/freightreceiver/src/test/java/org/matsim/freight/receiver/ReceiverCostAllocationFixedTest.java similarity index 88% rename from contribs/freightreceiver/src/test/java/org/matsim/contrib/freightreceiver/ReceiverCostAllocationFixedTest.java rename to contribs/freightreceiver/src/test/java/org/matsim/freight/receiver/ReceiverCostAllocationFixedTest.java index 8faf02fd1c0..4189a6e9779 100644 --- a/contribs/freightreceiver/src/test/java/org/matsim/contrib/freightreceiver/ReceiverCostAllocationFixedTest.java +++ b/contribs/freightreceiver/src/test/java/org/matsim/freight/receiver/ReceiverCostAllocationFixedTest.java @@ -1,4 +1,4 @@ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; diff --git a/contribs/freightreceiver/src/test/java/org/matsim/contrib/freightreceiver/ReceiverPlanTest.java b/contribs/freightreceiver/src/test/java/org/matsim/freight/receiver/ReceiverPlanTest.java similarity index 97% rename from contribs/freightreceiver/src/test/java/org/matsim/contrib/freightreceiver/ReceiverPlanTest.java rename to contribs/freightreceiver/src/test/java/org/matsim/freight/receiver/ReceiverPlanTest.java index 9933bda39d7..ea784499f81 100644 --- a/contribs/freightreceiver/src/test/java/org/matsim/contrib/freightreceiver/ReceiverPlanTest.java +++ b/contribs/freightreceiver/src/test/java/org/matsim/freight/receiver/ReceiverPlanTest.java @@ -16,7 +16,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.matsim.api.core.v01.Id; diff --git a/contribs/freightreceiver/src/test/java/org/matsim/contrib/freightreceiver/ReceiversReaderTest.java b/contribs/freightreceiver/src/test/java/org/matsim/freight/receiver/ReceiversReaderTest.java similarity index 98% rename from contribs/freightreceiver/src/test/java/org/matsim/contrib/freightreceiver/ReceiversReaderTest.java rename to contribs/freightreceiver/src/test/java/org/matsim/freight/receiver/ReceiversReaderTest.java index 970641df24e..6a893a9409f 100644 --- a/contribs/freightreceiver/src/test/java/org/matsim/contrib/freightreceiver/ReceiversReaderTest.java +++ b/contribs/freightreceiver/src/test/java/org/matsim/freight/receiver/ReceiversReaderTest.java @@ -18,7 +18,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -26,7 +26,7 @@ import org.matsim.api.core.v01.Id; import org.matsim.freight.carriers.Carrier; import org.matsim.freight.carriers.TimeWindow; -import org.matsim.contrib.freightreceiver.collaboration.CollaborationUtils; +import org.matsim.freight.receiver.collaboration.CollaborationUtils; import org.matsim.core.utils.misc.Time; import org.matsim.testcases.MatsimTestUtils; diff --git a/contribs/freightreceiver/src/test/java/org/matsim/contrib/freightreceiver/ReceiversTest.java b/contribs/freightreceiver/src/test/java/org/matsim/freight/receiver/ReceiversTest.java similarity index 97% rename from contribs/freightreceiver/src/test/java/org/matsim/contrib/freightreceiver/ReceiversTest.java rename to contribs/freightreceiver/src/test/java/org/matsim/freight/receiver/ReceiversTest.java index 35dbed33c31..8ca84ad87f8 100644 --- a/contribs/freightreceiver/src/test/java/org/matsim/contrib/freightreceiver/ReceiversTest.java +++ b/contribs/freightreceiver/src/test/java/org/matsim/freight/receiver/ReceiversTest.java @@ -1,11 +1,11 @@ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.Scenario; -import org.matsim.contrib.freightreceiver.run.chessboard.ReceiverChessboardScenario; +import org.matsim.freight.receiver.run.chessboard.ReceiverChessboardScenario; import org.matsim.testcases.MatsimTestUtils; import java.util.Collection; diff --git a/contribs/freightreceiver/src/test/java/org/matsim/contrib/freightreceiver/ReceiversWriterTest.java b/contribs/freightreceiver/src/test/java/org/matsim/freight/receiver/ReceiversWriterTest.java similarity index 96% rename from contribs/freightreceiver/src/test/java/org/matsim/contrib/freightreceiver/ReceiversWriterTest.java rename to contribs/freightreceiver/src/test/java/org/matsim/freight/receiver/ReceiversWriterTest.java index 34a66898d68..1f9a453ce08 100644 --- a/contribs/freightreceiver/src/test/java/org/matsim/contrib/freightreceiver/ReceiversWriterTest.java +++ b/contribs/freightreceiver/src/test/java/org/matsim/freight/receiver/ReceiversWriterTest.java @@ -18,13 +18,13 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import org.matsim.api.core.v01.Scenario; -import org.matsim.contrib.freightreceiver.run.chessboard.ReceiverChessboardScenario; +import org.matsim.freight.receiver.run.chessboard.ReceiverChessboardScenario; import org.matsim.testcases.MatsimTestUtils; import java.io.File; diff --git a/contribs/freightreceiver/src/test/java/org/matsim/contrib/freightreceiver/SSReorderPolicyTest.java b/contribs/freightreceiver/src/test/java/org/matsim/freight/receiver/SSReorderPolicyTest.java similarity index 97% rename from contribs/freightreceiver/src/test/java/org/matsim/contrib/freightreceiver/SSReorderPolicyTest.java rename to contribs/freightreceiver/src/test/java/org/matsim/freight/receiver/SSReorderPolicyTest.java index 1841ae963fc..c22aea6a54b 100644 --- a/contribs/freightreceiver/src/test/java/org/matsim/contrib/freightreceiver/SSReorderPolicyTest.java +++ b/contribs/freightreceiver/src/test/java/org/matsim/freight/receiver/SSReorderPolicyTest.java @@ -18,7 +18,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.junit.jupiter.api.Assertions; diff --git a/contribs/freightreceiver/test/input/org/matsim/contrib/freightreceiver/ReceiversReaderTest/receivers_v2_basic.xml b/contribs/freightreceiver/test/input/org/matsim/freight/receiver/ReceiversReaderTest/receivers_v2_basic.xml similarity index 100% rename from contribs/freightreceiver/test/input/org/matsim/contrib/freightreceiver/ReceiversReaderTest/receivers_v2_basic.xml rename to contribs/freightreceiver/test/input/org/matsim/freight/receiver/ReceiversReaderTest/receivers_v2_basic.xml diff --git a/contribs/freightreceiver/test/input/org/matsim/contrib/freightreceiver/ReceiversReaderTest/receivers_v2_full.xml b/contribs/freightreceiver/test/input/org/matsim/freight/receiver/ReceiversReaderTest/receivers_v2_full.xml similarity index 100% rename from contribs/freightreceiver/test/input/org/matsim/contrib/freightreceiver/ReceiversReaderTest/receivers_v2_full.xml rename to contribs/freightreceiver/test/input/org/matsim/freight/receiver/ReceiversReaderTest/receivers_v2_full.xml diff --git a/contribs/freightreceiver/test/input/org/matsim/contrib/freightreceiver/ReceiversTest/receivers_v2.xml b/contribs/freightreceiver/test/input/org/matsim/freight/receiver/ReceiversTest/receivers_v2.xml similarity index 100% rename from contribs/freightreceiver/test/input/org/matsim/contrib/freightreceiver/ReceiversTest/receivers_v2.xml rename to contribs/freightreceiver/test/input/org/matsim/freight/receiver/ReceiversTest/receivers_v2.xml