From 7d9f7c720740c99728a3ea3ebc400404775864ce Mon Sep 17 00:00:00 2001 From: Ricardo Ewert Date: Mon, 21 Oct 2024 10:11:25 +0200 Subject: [PATCH 1/9] 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 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 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 2/9] 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 3/9] 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 2ddddaad667a8d59f7181f3a00eca357caabd3df Mon Sep 17 00:00:00 2001 From: Ricardo Ewert Date: Thu, 7 Nov 2024 10:55:28 +0100 Subject: [PATCH 4/9] 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 e1ee2469878c590b9d401b2642e48d28692f0883 Mon Sep 17 00:00:00 2001 From: Ricardo Ewert Date: Thu, 7 Nov 2024 13:11:18 +0100 Subject: [PATCH 5/9] 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 6/9] 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 7/9] 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 8/9] 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 9/9] 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()) {