From 9dd01da8d63910b4ead35b0ff93423a7a44f799b Mon Sep 17 00:00:00 2001 From: nkuehnel Date: Wed, 13 Mar 2024 16:21:41 +0100 Subject: [PATCH 1/5] initial h3 implementation for drt zonal systems --- contribs/drt-extensions/pom.xml | 7 +- .../drt/extension/h3/drtZone/H3GridUtils.java | 113 ++++++++++++ .../h3/drtZone/H3ModeZonalSystemModule.java | 59 ++++++ .../drt/extension/h3/drtZone/H3Utils.java | 27 +++ .../extension/h3/drtZone/H3ZonalSystem.java | 75 ++++++++ .../h3/RunDrtWithH3ZonalSystemIT.java | 88 +++++++++ .../h3/drtZone/H3DrtZonalSystemTest.java | 170 ++++++++++++++++++ .../drt/analysis/zonal/DrtGridUtils.java | 13 +- .../zonal/DrtModeZonalSystemModule.java | 16 +- .../analysis/zonal/DrtZonalSystemTest.java | 6 +- 10 files changed, 556 insertions(+), 18 deletions(-) create mode 100644 contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/h3/drtZone/H3GridUtils.java create mode 100644 contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/h3/drtZone/H3ModeZonalSystemModule.java create mode 100644 contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/h3/drtZone/H3Utils.java create mode 100644 contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/h3/drtZone/H3ZonalSystem.java create mode 100644 contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/h3/RunDrtWithH3ZonalSystemIT.java create mode 100644 contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/h3/drtZone/H3DrtZonalSystemTest.java diff --git a/contribs/drt-extensions/pom.xml b/contribs/drt-extensions/pom.xml index 3e2cbf8dcf7..130ecb31138 100644 --- a/contribs/drt-extensions/pom.xml +++ b/contribs/drt-extensions/pom.xml @@ -48,11 +48,16 @@ 16.0-SNAPSHOT test - + org.mockito mockito-core + + com.uber + h3 + 4.1.1 + diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/h3/drtZone/H3GridUtils.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/h3/drtZone/H3GridUtils.java new file mode 100644 index 00000000000..ad1e94e43a1 --- /dev/null +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/h3/drtZone/H3GridUtils.java @@ -0,0 +1,113 @@ +package org.matsim.contrib.drt.extension.h3.drtZone; + +import com.uber.h3core.AreaUnit; +import com.uber.h3core.H3Core; +import com.uber.h3core.LengthUnit; +import com.uber.h3core.util.LatLng; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.GeometryFactory; +import org.locationtech.jts.geom.Polygon; +import org.locationtech.jts.geom.prep.PreparedGeometry; +import org.locationtech.jts.geom.prep.PreparedGeometryFactory; +import org.matsim.api.core.v01.Coord; +import org.matsim.api.core.v01.network.Network; +import org.matsim.contrib.zone.util.NetworkWithZonesUtils; +import org.matsim.core.network.NetworkUtils; +import org.matsim.core.utils.geometry.CoordUtils; +import org.matsim.core.utils.geometry.CoordinateTransformation; +import org.matsim.core.utils.geometry.transformations.TransformationFactory; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author nkuehnel / MOIA + */ +public class H3GridUtils { + + static final Logger log = LogManager.getLogger(H3GridUtils.class); + + public static Map createH3GridFromNetwork(Network network, int resolution, String crs) { + + H3Core h3 = H3Utils.getInstance(); + + log.info("start creating H3 grid from network at resolution " + resolution); + double hexagonEdgeLengthAvg = h3.getHexagonEdgeLengthAvg(resolution, LengthUnit.m); + log.info("Average edge length: " + hexagonEdgeLengthAvg + " meters."); + log.info("Average centroid distance: " + hexagonEdgeLengthAvg * Math.sqrt(3) + " meters."); + log.info("Average hexagon area: " + h3.getHexagonAreaAvg(resolution, AreaUnit.m2) + " m^2"); + + double[] boundingbox = NetworkUtils.getBoundingBox(network.getNodes().values()); + double minX = boundingbox[0]; + double maxX = boundingbox[2]; + double minY = boundingbox[1]; + double maxY = boundingbox[3]; + + GeometryFactory gf = new GeometryFactory(); + PreparedGeometryFactory preparedGeometryFactory = new PreparedGeometryFactory(); + Map grid = new HashMap<>(); + CoordinateTransformation toLatLong = TransformationFactory.getCoordinateTransformation(crs, TransformationFactory.WGS84); + CoordinateTransformation fromLatLong = TransformationFactory.getCoordinateTransformation(TransformationFactory.WGS84, crs); + + List boundingBoxPoints = new ArrayList<>(); + + Coord bottomLeft = toLatLong.transform(new Coord(minX, minY)); + Coord topLeft = toLatLong.transform(new Coord(minX, maxY)); + Coord topRight = toLatLong.transform(new Coord(maxX, maxY)); + Coord bottomRight = toLatLong.transform(new Coord(maxX, minY)); + + boundingBoxPoints.add(coordToLatLng(bottomLeft)); + boundingBoxPoints.add(coordToLatLng(topLeft)); + boundingBoxPoints.add(coordToLatLng(topRight)); + boundingBoxPoints.add(coordToLatLng(bottomRight)); + boundingBoxPoints.add(coordToLatLng(bottomLeft)); + + long millis = System.currentTimeMillis(); + + //get cells in a finer resolution to catch links at the border + List h3Grid = h3.polygonToCellAddresses(boundingBoxPoints, Collections.emptyList(), Math.min(H3Utils.MAX_RES, resolution)); + h3Grid = h3Grid + .parallelStream() + //also include neighbors with distance 1 + .flatMap(h3Id -> h3.gridDisk(h3Id, 1).stream()) + .distinct() + .toList(); + + if(h3Grid.isEmpty()) { + // bounding box too small to cover even a single H3 cell for a significant part. Use bounding box coords directly. + h3Grid = boundingBoxPoints.stream().map(corner -> h3.latLngToCellAddress(corner.lat, corner.lng, resolution)).distinct().toList(); + } + + log.info("Obtained " + h3Grid.size() + " H3 cells in " + (System.currentTimeMillis() - millis) + " ms."); + + + for (String h3Id : h3Grid) { + List coordinateList = h3.cellToBoundary(h3Id) + .stream() + .map(latLng -> CoordUtils.createGeotoolsCoordinate(fromLatLong.transform(latLngToCoord(latLng)))) + .collect(Collectors.toList()); + + if (!coordinateList.isEmpty()) { + coordinateList.add(coordinateList.get(0)); + } + + Polygon polygon = new Polygon(gf.createLinearRing(coordinateList.toArray(new Coordinate[0])), null, gf); + grid.put(h3Id, preparedGeometryFactory.create(polygon)); + } + + log.info("finished creating H3 grid from network."); + return grid; + } + + public static LatLng coordToLatLng(Coord coord) { + //invert coordinate order + return new LatLng(coord.getY(), coord.getX()); + } + + public static Coord latLngToCoord(LatLng latLng) { + //invert coordinate order + return new Coord(latLng.lng, latLng.lat); + } +} diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/h3/drtZone/H3ModeZonalSystemModule.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/h3/drtZone/H3ModeZonalSystemModule.java new file mode 100644 index 00000000000..69a41bfa12e --- /dev/null +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/h3/drtZone/H3ModeZonalSystemModule.java @@ -0,0 +1,59 @@ +package org.matsim.contrib.drt.extension.h3.drtZone; + +import com.google.common.base.Preconditions; +import org.locationtech.jts.geom.prep.PreparedGeometry; +import org.matsim.api.core.v01.network.Network; +import org.matsim.contrib.drt.analysis.zonal.DrtZonalSystem; +import org.matsim.contrib.drt.analysis.zonal.DrtZonalSystemParams; +import org.matsim.contrib.drt.run.DrtConfigGroup; +import org.matsim.contrib.dvrp.run.AbstractDvrpModeModule; +import org.matsim.core.config.ConfigGroup; + +import java.util.Map; + +import static org.matsim.contrib.drt.analysis.zonal.DrtGridUtils.filterGridWithinServiceArea; +import static org.matsim.utils.gis.shp2matsim.ShpGeometryUtils.loadPreparedGeometries; + +/** + * @author nkuehnel / MOIA + */ +public class H3ModeZonalSystemModule extends AbstractDvrpModeModule { + + private final DrtConfigGroup drtCfg; + private final String crs; + private final int resolution; + + public H3ModeZonalSystemModule(DrtConfigGroup drtCfg, String crs, int resolution) { + super(drtCfg.getMode()); + this.drtCfg = drtCfg; + this.crs = crs; + this.resolution = resolution; + } + @Override + public void install() { + + DrtZonalSystemParams params = drtCfg.getZonalSystemParams().orElseThrow(); + + bindModal(DrtZonalSystem.class).toProvider(modalProvider(getter -> { + Network network = getter.getModal(Network.class); + switch (params.zonesGeneration) { + case ShapeFile: + throw new IllegalArgumentException("Cannot use H3 system with self-provided shapefile"); + case GridFromNetwork: + Preconditions.checkNotNull(params.cellSize); + Map gridFromNetwork = H3GridUtils.createH3GridFromNetwork(network, resolution, crs); + var gridZones = + switch (drtCfg.operationalScheme) { + case stopbased, door2door -> gridFromNetwork; + case serviceAreaBased -> filterGridWithinServiceArea(gridFromNetwork, + loadPreparedGeometries(ConfigGroup.getInputFileURL(getConfig().getContext(), + drtCfg.drtServiceAreaShapeFile))); + }; + return H3ZonalSystem.createFromPreparedGeometries(network, gridZones, crs, resolution); + + default: + throw new RuntimeException("Unsupported zone generation"); + } + })).asEagerSingleton(); + } +} diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/h3/drtZone/H3Utils.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/h3/drtZone/H3Utils.java new file mode 100644 index 00000000000..9e9e13524c9 --- /dev/null +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/h3/drtZone/H3Utils.java @@ -0,0 +1,27 @@ +package org.matsim.contrib.drt.extension.h3.drtZone; + +import com.uber.h3core.H3Core; + +import java.io.IOException; + +/** + * @author nkuehnel / MOIA + */ +public final class H3Utils { + + private static H3Core h3; + + public final static int MAX_RES = 15; + + + public static H3Core getInstance() { + if(h3 == null) { + try { + h3 = H3Core.newInstance(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + return h3; + } +} diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/h3/drtZone/H3ZonalSystem.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/h3/drtZone/H3ZonalSystem.java new file mode 100644 index 00000000000..edb9eaa6374 --- /dev/null +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/h3/drtZone/H3ZonalSystem.java @@ -0,0 +1,75 @@ +package org.matsim.contrib.drt.extension.h3.drtZone; + +import com.uber.h3core.H3Core; +import com.uber.h3core.util.LatLng; +import one.util.streamex.EntryStream; +import one.util.streamex.StreamEx; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.locationtech.jts.geom.prep.PreparedGeometry; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.contrib.drt.analysis.zonal.DrtZonalSystem; +import org.matsim.contrib.drt.analysis.zonal.DrtZone; +import org.matsim.core.utils.geometry.CoordinateTransformation; +import org.matsim.core.utils.geometry.transformations.TransformationFactory; + +import javax.annotation.Nullable; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import static java.util.stream.Collectors.toList; + +/** + * @author nkuehnel / MOIA + */ +public final class H3ZonalSystem { + + static final Logger log = LogManager.getLogger(H3ZonalSystem.class); + + + public static DrtZonalSystem createFromPreparedGeometries(Network network, + Map geometries, + String crs, + int resolution) { + + //geometries without links are skipped + CoordinateTransformation ct = TransformationFactory.getCoordinateTransformation(crs, TransformationFactory.WGS84); + Map> linksByGeometryId = StreamEx.of(network.getLinks().values()) + .mapToEntry(l -> getGeometryIdForLink(l, geometries, resolution, ct), l -> l) + .filterKeys(Objects::nonNull) + .grouping(toList()); + + log.info("Network filtered zone system contains " + linksByGeometryId.size() + " zones for " + + network.getLinks().size() + " links and " + network.getNodes().size() + " nodes."); + + //the zonal system contains only zones that have at least one link + List zones = EntryStream.of(linksByGeometryId) + .mapKeyValue((id, links) -> new DrtZone(id, geometries.get(id), links)) + .collect(toList()); + + return new DrtZonalSystem(zones); + } + + /** + * @param ct + * @param link + * @return the the {@code PreparedGeometry} that contains the {@code linkId}. + * If a given link's {@code Coord} borders two or more cells, the allocation to a cell is random. + * Result may be null in case the given link is outside of the service area. + *

+ * Careful: does not work if grid contains different levels of h3 resolutions. + */ + @Nullable + private static String getGeometryIdForLink(Link link, Map geometries, int resolution, CoordinateTransformation ct) { + H3Core h3 = H3Utils.getInstance(); + LatLng latLng = H3GridUtils.coordToLatLng(ct.transform(link.getToNode().getCoord())); + String s = h3.latLngToCellAddress(latLng.lat, latLng.lng, resolution); + if (geometries.containsKey(s)) { + return s; + } else { + return null; + } + } +} diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/h3/RunDrtWithH3ZonalSystemIT.java b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/h3/RunDrtWithH3ZonalSystemIT.java new file mode 100644 index 00000000000..55933793765 --- /dev/null +++ b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/h3/RunDrtWithH3ZonalSystemIT.java @@ -0,0 +1,88 @@ +package org.matsim.contrib.drt.extension.h3; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.matsim.application.MATSimApplication; +import org.matsim.contrib.drt.analysis.DrtEventSequenceCollector; +import org.matsim.contrib.drt.analysis.zonal.DrtZonalSystem; +import org.matsim.contrib.drt.analysis.zonal.DrtZonalSystemParams; +import org.matsim.contrib.drt.analysis.zonal.DrtZonalWaitTimesAnalyzer; +import org.matsim.contrib.drt.extension.DrtTestScenario; +import org.matsim.contrib.drt.extension.h3.drtZone.H3ModeZonalSystemModule; +import org.matsim.contrib.drt.run.DrtConfigGroup; +import org.matsim.contrib.drt.run.MultiModeDrtConfigGroup; +import org.matsim.contrib.dvrp.run.AbstractDvrpModeModule; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.testcases.MatsimTestUtils; + +import java.io.File; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author nkuehnel / MOIA + */ +public class RunDrtWithH3ZonalSystemIT { + + @RegisterExtension + private MatsimTestUtils utils = new MatsimTestUtils(); + + private Controler controler; + + @BeforeEach + public void setUp() throws Exception { + + Config config = DrtTestScenario.loadConfig(utils); + config.controller().setLastIteration(0); + + controler = MATSimApplication.prepare(new DrtTestScenario(controller -> prepare(controller, config), RunDrtWithH3ZonalSystemIT::prepare), config); + } + + private static void prepare(Controler controler, Config config) { + + MultiModeDrtConfigGroup drtConfigs = ConfigUtils.addOrGetModule(config, MultiModeDrtConfigGroup.class); + for (DrtConfigGroup drtConfig : drtConfigs.getModalElements()) { + controler.addOverridingModule(new AbstractModule() { + @Override + public void install() { + install(new H3ModeZonalSystemModule(drtConfig, config.global().getCoordinateSystem(), 9)); + install(new AbstractDvrpModeModule(drtConfig.mode) { + @Override + public void install() { + bindModal(DrtZonalWaitTimesAnalyzer.class).toProvider(modalProvider( + getter -> new DrtZonalWaitTimesAnalyzer(drtConfig, getter.getModal(DrtEventSequenceCollector.class), + getter.getModal(DrtZonalSystem.class)))).asEagerSingleton(); + addControlerListenerBinding().to(modalKey(DrtZonalWaitTimesAnalyzer.class)); + } + }); + } + }); + + } + } + + private static void prepare(Config config) { + MultiModeDrtConfigGroup drtConfigs = ConfigUtils.addOrGetModule(config, MultiModeDrtConfigGroup.class); + for (DrtConfigGroup drtConfig : drtConfigs.getModalElements()) { + DrtZonalSystemParams params = drtConfig.getZonalSystemParams().orElseThrow(); + params.cellSize = 1.; + params.zonesGeneration = DrtZonalSystemParams.ZoneGeneration.GridFromNetwork; + } + } + + @Test + void run() { + String out = utils.getOutputDirectory(); + controler.run(); + + assertThat(new File(out, "kelheim-mini-drt.drt_waitStats_drt_zonal.gpkg")) + .exists() + .isNotEmpty(); + + } +} + diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/h3/drtZone/H3DrtZonalSystemTest.java b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/h3/drtZone/H3DrtZonalSystemTest.java new file mode 100644 index 00000000000..5cb88e3d851 --- /dev/null +++ b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/h3/drtZone/H3DrtZonalSystemTest.java @@ -0,0 +1,170 @@ +/* + * *********************************************************************** * + * project: org.matsim.* + * *********************************************************************** * + * * + * copyright : (C) 2020 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** * + */ + +package org.matsim.contrib.drt.extension.h3.drtZone; + +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.contrib.drt.analysis.zonal.DrtZonalSystem; +import org.matsim.core.config.ConfigGroup; +import org.matsim.core.network.NetworkUtils; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.utils.geometry.transformations.TransformationFactory; +import org.matsim.examples.ExamplesUtils; + +import java.net.URL; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +/** + * @author nkuehnel / MOIA + */ +public class H3DrtZonalSystemTest { + + @Test + void test_Holzkirchen_Resolution3() { + Network network = getNetwork(); + String crs = TransformationFactory.DHDN_GK4; + int resolution = 3; + DrtZonalSystem drtZonalSystem = H3ZonalSystem.createFromPreparedGeometries(network, + H3GridUtils.createH3GridFromNetwork(network, resolution, crs), crs, resolution); + + assertThat(drtZonalSystem.getZones().containsKey("831f8dfffffffff")).isTrue(); + + // center of Holzkirchen + assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(358598)).getId()).isEqualTo("831f8dfffffffff"); + // Thanning (Western border of network) + assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(78976)).getId()).isEqualTo("831f8dfffffffff"); + // between Gross- and Kleinpienzenau (Southeastern border of network) + assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(59914)).getId()).isEqualTo("831f89fffffffff"); + + //check all links are mapped + for (Link link : network.getLinks().values()) { + assertNotNull(drtZonalSystem.getZoneForLinkId(link.getId())); + } + } + + @Test + void test_Holzkirchen_Resolution5() { + Network network = getNetwork(); + String crs = TransformationFactory.DHDN_GK4; + int resolution = 5; + DrtZonalSystem drtZonalSystem = H3ZonalSystem.createFromPreparedGeometries(network, + H3GridUtils.createH3GridFromNetwork(network, resolution, crs), crs, resolution); + + assertThat(drtZonalSystem.getZones().containsKey("851f88b7fffffff")).isTrue(); + assertThat(drtZonalSystem.getZones().containsKey("851f8d6bfffffff")).isTrue(); + assertThat(drtZonalSystem.getZones().containsKey("851f88a7fffffff")).isTrue(); + assertThat(drtZonalSystem.getZones().containsKey("851f89d3fffffff")).isTrue(); + + // center of Holzkirchen + assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(358598)).getId()).isEqualTo("851f8d6bfffffff"); + // Thanning (Western border of network) + assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(78976)).getId()).isEqualTo("851f88b7fffffff"); + // between Gross- and Kleinpienzenau (Southeastern border of network) + assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(59914)).getId()).isEqualTo("851f89d3fffffff"); + + //check all links are mapped + for (Link link : network.getLinks().values()) { + assertNotNull(drtZonalSystem.getZoneForLinkId(link.getId())); + } + } + + @Test + void test_Holzkirchen_Resolution6() { + Network network = getNetwork(); + String crs = TransformationFactory.DHDN_GK4; + int resolution = 6; + DrtZonalSystem drtZonalSystem = H3ZonalSystem.createFromPreparedGeometries(network, + H3GridUtils.createH3GridFromNetwork(network, resolution, crs), crs, resolution); + + assertThat(drtZonalSystem.getZones().containsKey("861f8d697ffffff")).isTrue(); + assertThat(drtZonalSystem.getZones().containsKey("861f8d687ffffff")).isTrue(); + assertThat(drtZonalSystem.getZones().containsKey("861f8d69fffffff")).isTrue(); + assertThat(drtZonalSystem.getZones().containsKey("861f88a6fffffff")).isTrue(); + assertThat(drtZonalSystem.getZones().containsKey("861f88a6fffffff")).isTrue(); + assertThat(drtZonalSystem.getZones().containsKey("861f89d37ffffff")).isTrue(); + + // center of Holzkirchen + assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(358598)).getId()).isEqualTo("861f8d697ffffff"); + // Thanning (Western border of network) + assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(78976)).getId()).isEqualTo("861f88b47ffffff"); + // between Gross- and Kleinpienzenau (Southeastern border of network) + assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(59914)).getId()).isEqualTo("861f89d07ffffff"); + + //check all links are mapped + for (Link link : network.getLinks().values()) { + assertNotNull(drtZonalSystem.getZoneForLinkId(link.getId())); + } + } + + @Test + void test_Holzkirchen_Resolution10() { + Network network = getNetwork(); + String crs = TransformationFactory.DHDN_GK4; + int resolution = 10; + DrtZonalSystem drtZonalSystem = H3ZonalSystem.createFromPreparedGeometries(network, + H3GridUtils.createH3GridFromNetwork(network, resolution, crs), crs, resolution); + + // center of Holzkirchen + assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(358598)).getId()).isEqualTo("8a1f8d6930b7fff"); + // Thanning (Western border of network) + assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(78976)).getId()).isEqualTo("8a1f88b4025ffff"); + // between Gross- and Kleinpienzenau (Southeastern border of network) + assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(59914)).getId()).isEqualTo("8a1f89d06d5ffff"); + + //check all links are mapped + for (Link link : network.getLinks().values()) { + assertNotNull(drtZonalSystem.getZoneForLinkId(link.getId())); + } + } + + @Test + void test_Holzkirchen_Resolution12() { + Network network = getNetwork(); + String crs = TransformationFactory.DHDN_GK4; + int resolution = 12; + DrtZonalSystem drtZonalSystem = H3ZonalSystem.createFromPreparedGeometries(network, + H3GridUtils.createH3GridFromNetwork(network, resolution, crs), crs, resolution); + + // center of Holzkirchen + assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(358598)).getId()).isEqualTo("8c1f8d6930b63ff"); + // Thanning (Western border of network) + assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(78976)).getId()).isEqualTo("8c1f88b4025d1ff"); + // between Gross- and Kleinpienzenau (Southeastern border of network) + assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(59914)).getId()).isEqualTo("8c1f89d06d581ff"); + + //check all links are mapped + for (Link link : network.getLinks().values()) { + assertNotNull(drtZonalSystem.getZoneForLinkId(link.getId())); + } + } + + + static Network getNetwork() { + Network network = NetworkUtils.createNetwork(); + URL holzkirchen = ConfigGroup.getInputFileURL(ExamplesUtils.getTestScenarioURL("holzkirchen"), "holzkirchenNetwork.xml.gz"); + new MatsimNetworkReader(network).parse(holzkirchen); + return network; + } +} diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtGridUtils.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtGridUtils.java index b33136cec26..c8e9acfde42 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtGridUtils.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtGridUtils.java @@ -74,21 +74,18 @@ public static Map createGridFromNetwork(Network networ } /** - * First creates a grid based on the network bounding box. Then removes all zones that do not intersect the service area. + * Takes an existing grid and removes all zones that do not intersect the service area. * Result may contain zones that are barely included in the service area. But as passengers may walk into the service area, * it seems appropriate that the DrtZonalSystem, which is used for demand estimation, is larger than the service area. * The {@code cellsize} indirectly determines, how much larger the DrtZonalSystem may get. * - * @param network - * @param cellsize + * @param grid a pre-computed grid of zones * @param serviceAreaGeoms geometries that define the service area * @return */ - public static Map createGridFromNetworkWithinServiceArea(Network network, double cellsize, - List serviceAreaGeoms) { - Map grid = createGridFromNetwork(network, cellsize); - log.info("total number of created grid zones = " + grid.size()); - + public static Map filterGridWithinServiceArea(Map grid, + List serviceAreaGeoms) { + log.info("total number of initial grid zones = " + grid.size()); log.info("searching for grid zones within the drt service area..."); Counter counter = new Counter("dealt with zone "); Map zonesWithinServiceArea = EntryStream.of(grid) diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtModeZonalSystemModule.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtModeZonalSystemModule.java index 8d81ba21749..ef95ba40843 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtModeZonalSystemModule.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtModeZonalSystemModule.java @@ -21,11 +21,12 @@ package org.matsim.contrib.drt.analysis.zonal; import static org.matsim.contrib.drt.analysis.zonal.DrtGridUtils.createGridFromNetwork; -import static org.matsim.contrib.drt.analysis.zonal.DrtGridUtils.createGridFromNetworkWithinServiceArea; +import static org.matsim.contrib.drt.analysis.zonal.DrtGridUtils.filterGridWithinServiceArea; import static org.matsim.contrib.drt.run.DrtConfigGroup.OperationalScheme; import static org.matsim.utils.gis.shp2matsim.ShpGeometryUtils.loadPreparedGeometries; import java.util.List; +import java.util.Map; import org.locationtech.jts.geom.prep.PreparedGeometry; import org.matsim.api.core.v01.network.Network; @@ -66,11 +67,14 @@ public void install() { case GridFromNetwork: Preconditions.checkNotNull(params.cellSize); - var gridZones = drtCfg.operationalScheme == OperationalScheme.serviceAreaBased ? - createGridFromNetworkWithinServiceArea(network, params.cellSize, - loadPreparedGeometries(ConfigGroup.getInputFileURL(getConfig().getContext(), - drtCfg.drtServiceAreaShapeFile))) : - createGridFromNetwork(network, params.cellSize); + Map gridFromNetwork = createGridFromNetwork(network, params.cellSize); + var gridZones = + switch (drtCfg.operationalScheme) { + case stopbased, door2door -> gridFromNetwork; + case serviceAreaBased -> filterGridWithinServiceArea(gridFromNetwork, + loadPreparedGeometries(ConfigGroup.getInputFileURL(getConfig().getContext(), + drtCfg.drtServiceAreaShapeFile))); + }; return DrtZonalSystem.createFromPreparedGeometries(network, gridZones); default: diff --git a/contribs/drt/src/test/java/org/matsim/contrib/drt/analysis/zonal/DrtZonalSystemTest.java b/contribs/drt/src/test/java/org/matsim/contrib/drt/analysis/zonal/DrtZonalSystemTest.java index a49cc10a3d0..9baafffb23f 100644 --- a/contribs/drt/src/test/java/org/matsim/contrib/drt/analysis/zonal/DrtZonalSystemTest.java +++ b/contribs/drt/src/test/java/org/matsim/contrib/drt/analysis/zonal/DrtZonalSystemTest.java @@ -62,7 +62,7 @@ void test_gridWithinServiceArea(){ Coordinate min = new Coordinate(-500, 500); Coordinate max = new Coordinate(1500, 1500); List serviceArea = createServiceArea(min,max); - Map grid = DrtGridUtils.createGridFromNetworkWithinServiceArea(createNetwork(), 100, serviceArea); + Map grid = DrtGridUtils.filterGridWithinServiceArea(DrtGridUtils.createGridFromNetwork(createNetwork(), 100), serviceArea); DrtZonalSystem zonalSystem = createFromPreparedGeometries(createNetwork(), grid); @@ -70,7 +70,7 @@ void test_gridWithinServiceArea(){ //link 'da' is outside of the service area Id id = Id.createLinkId("da"); - assertThat(zonalSystem.getZoneForLinkId(id) == null); + assertThat(zonalSystem.getZoneForLinkId(id) == null).isTrue(); } @Test @@ -78,7 +78,7 @@ void test_noZonesWithoutLinks(){ Coordinate min = new Coordinate(1500, 1500); Coordinate max = new Coordinate(2500, 2500); List serviceArea = createServiceArea(min,max); - Map grid = DrtGridUtils.createGridFromNetworkWithinServiceArea(createNetwork(), 100, serviceArea); + Map grid = DrtGridUtils.filterGridWithinServiceArea(DrtGridUtils.createGridFromNetwork(createNetwork(), 100), serviceArea); DrtZonalSystem zonalSystem = createFromPreparedGeometries(createNetwork(), grid); From 60f57adafee491ce15c60b26ea9043f7004b36fd Mon Sep 17 00:00:00 2001 From: nkuehnel Date: Tue, 19 Mar 2024 16:18:01 +0100 Subject: [PATCH 2/5] refactor zones and move them to common contrib add zonal systems params for h3 --- contribs/common/pom.xml | 10 ++ .../org/matsim/contrib/common/zones/Zone.java | 19 +++ .../matsim/contrib/common/zones/ZoneImpl.java | 65 ++++++++++ .../contrib/common/zones/ZoneSystem.java | 14 +++ .../contrib/common/zones/ZoneSystemImpl.java | 43 +++++++ .../contrib/common/zones/ZoneSystemUtils.java | 65 ++++++++++ .../contrib/common/zones/h3}/H3GridUtils.java | 3 +- .../contrib/common/zones/h3}/H3Utils.java | 4 +- .../common/zones/h3/H3ZoneSystemUtils.java} | 28 +++-- contribs/drt-extensions/pom.xml | 5 - .../h3/drtZone/H3ModeZonalSystemModule.java | 59 ---------- .../h3/RunDrtWithH3ZonalSystemIT.java | 8 +- .../h3/drtZone/H3DrtZonalSystemTest.java | 67 ++++++----- contribs/drt/pom.xml | 8 +- .../drt/analysis/zonal/DrtGridUtils.java | 9 +- .../zonal/DrtModeZonalSystemModule.java | 66 +++++++---- .../drt/analysis/zonal/DrtZonalSystem.java | 111 ------------------ .../analysis/zonal/DrtZonalSystemParams.java | 17 ++- .../zonal/DrtZonalWaitTimesAnalyzer.java | 47 ++++---- .../contrib/drt/analysis/zonal/DrtZone.java | 77 ------------ .../zonal/DrtZoneTargetLinkSelector.java | 3 +- .../MostCentralDrtZoneTargetLinkSelector.java | 10 +- .../RandomDrtZoneTargetLinkSelector.java | 3 +- .../zonal/ZonalIdleVehicleCollector.java | 32 ++--- .../zonal/ZonalIdleVehicleXYVisualiser.java | 39 +++--- .../DrtModeFeedforwardRebalanceModule.java | 8 +- ...astHeuristicZonalRelocationCalculator.java | 14 +-- .../FeedforwardRebalancingStrategy.java | 49 ++++---- .../Feedforward/FeedforwardSignalHandler.java | 28 ++--- .../rebalancing/RebalancingUtils.java | 22 ++-- .../NetDepartureReplenishDemandEstimator.java | 30 ++--- .../PreviousIterationDrtDemandEstimator.java | 27 ++--- .../demandestimator/ZonalDemandEstimator.java | 6 +- ...AggregatedMinCostRelocationCalculator.java | 14 +-- .../DrtModeMinCostFlowRebalancingModule.java | 18 ++- .../MinCostFlowRebalancingStrategy.java | 18 +-- .../mincostflow/TransportProblem.java | 12 +- .../ZonalRelocationCalculator.java | 10 +- .../DemandEstimatorAsTargetCalculator.java | 12 +- ...leVehicleDistributionTargetCalculator.java | 26 ++-- .../EqualVehicleDensityTargetCalculator.java | 33 +++--- ...clesToPopulationRatioTargetCalculator.java | 35 +++--- .../RebalancingTargetCalculator.java | 8 +- .../analysis/zonal/DrtZonalSystemTest.java | 25 ++-- .../RandomDrtZoneTargetLinkSelectorTest.java | 4 +- ...eviousIterationDrtDemandEstimatorTest.java | 14 ++- ...ualVehicleDensityTargetCalculatorTest.java | 24 ++-- ...ToPopulationRatioTargetCalculatorTest.java | 87 +++++++------- 48 files changed, 663 insertions(+), 673 deletions(-) create mode 100644 contribs/common/src/main/java/org/matsim/contrib/common/zones/Zone.java create mode 100644 contribs/common/src/main/java/org/matsim/contrib/common/zones/ZoneImpl.java create mode 100644 contribs/common/src/main/java/org/matsim/contrib/common/zones/ZoneSystem.java create mode 100644 contribs/common/src/main/java/org/matsim/contrib/common/zones/ZoneSystemImpl.java create mode 100644 contribs/common/src/main/java/org/matsim/contrib/common/zones/ZoneSystemUtils.java rename contribs/{drt-extensions/src/main/java/org/matsim/contrib/drt/extension/h3/drtZone => common/src/main/java/org/matsim/contrib/common/zones/h3}/H3GridUtils.java (97%) rename contribs/{drt-extensions/src/main/java/org/matsim/contrib/drt/extension/h3/drtZone => common/src/main/java/org/matsim/contrib/common/zones/h3}/H3Utils.java (78%) rename contribs/{drt-extensions/src/main/java/org/matsim/contrib/drt/extension/h3/drtZone/H3ZonalSystem.java => common/src/main/java/org/matsim/contrib/common/zones/h3/H3ZoneSystemUtils.java} (73%) delete mode 100644 contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/h3/drtZone/H3ModeZonalSystemModule.java delete mode 100644 contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtZonalSystem.java delete mode 100644 contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtZone.java diff --git a/contribs/common/pom.xml b/contribs/common/pom.xml index 05952b173e1..106a9e01e46 100644 --- a/contribs/common/pom.xml +++ b/contribs/common/pom.xml @@ -18,5 +18,15 @@ org.assertj assertj-core + + one.util + streamex + 0.8.2 + + + com.uber + h3 + 4.1.1 + diff --git a/contribs/common/src/main/java/org/matsim/contrib/common/zones/Zone.java b/contribs/common/src/main/java/org/matsim/contrib/common/zones/Zone.java new file mode 100644 index 00000000000..dbf0c77caf8 --- /dev/null +++ b/contribs/common/src/main/java/org/matsim/contrib/common/zones/Zone.java @@ -0,0 +1,19 @@ +package org.matsim.contrib.common.zones; + +import org.locationtech.jts.geom.prep.PreparedGeometry; +import org.matsim.api.core.v01.BasicLocation; +import org.matsim.api.core.v01.Coord; +import org.matsim.api.core.v01.Identifiable; +import org.matsim.api.core.v01.network.Link; + +import javax.annotation.Nullable; +import java.util.List; + +public interface Zone extends BasicLocation, Identifiable { + @Nullable + PreparedGeometry getPreparedGeometry(); + + Coord getCentroid(); + + List getLinks(); +} diff --git a/contribs/common/src/main/java/org/matsim/contrib/common/zones/ZoneImpl.java b/contribs/common/src/main/java/org/matsim/contrib/common/zones/ZoneImpl.java new file mode 100644 index 00000000000..64b4a009733 --- /dev/null +++ b/contribs/common/src/main/java/org/matsim/contrib/common/zones/ZoneImpl.java @@ -0,0 +1,65 @@ +package org.matsim.contrib.common.zones; + +import org.locationtech.jts.geom.prep.PreparedGeometry; +import org.matsim.api.core.v01.Coord; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.network.Link; +import org.matsim.core.utils.geometry.geotools.MGC; + +import javax.annotation.Nullable; +import java.util.List; + +public class ZoneImpl implements Zone { + + private final Id id; + @Nullable + private final PreparedGeometry preparedGeometry; //null for virtual/dummy zones + private final List links; + private final Coord centroid; + + public ZoneImpl(Id id, PreparedGeometry preparedGeometry, List links) { + this(id, preparedGeometry, links, MGC.point2Coord(preparedGeometry.getGeometry().getCentroid())); + } + + private ZoneImpl(Id id, @Nullable PreparedGeometry preparedGeometry, List links, Coord centroid) { + this.id = id; + this.preparedGeometry = preparedGeometry; + this.links = links; + this.centroid = centroid; + } + + @Override + public Id getId() { + return id; + } + + @Override + public Coord getCoord() { + return centroid; + } + + @Override + @Nullable + public PreparedGeometry getPreparedGeometry() { + return preparedGeometry; + } + + @Override + public Coord getCentroid() { + return centroid; + } + + @Override + public List getLinks() { + return links; + } + + boolean isDummy() { + return preparedGeometry == null; + } + + public static ZoneImpl createDummyZone(Id id, List links, Coord centroid) { + return new ZoneImpl(id, null, links, centroid); + } + +} diff --git a/contribs/common/src/main/java/org/matsim/contrib/common/zones/ZoneSystem.java b/contribs/common/src/main/java/org/matsim/contrib/common/zones/ZoneSystem.java new file mode 100644 index 00000000000..11299b67ad6 --- /dev/null +++ b/contribs/common/src/main/java/org/matsim/contrib/common/zones/ZoneSystem.java @@ -0,0 +1,14 @@ +package org.matsim.contrib.common.zones; + +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.network.Link; + +import javax.annotation.Nullable; +import java.util.Map; + +public interface ZoneSystem { + @Nullable + Zone getZoneForLinkId(Id linkId); + + Map, Zone> getZones(); +} diff --git a/contribs/common/src/main/java/org/matsim/contrib/common/zones/ZoneSystemImpl.java b/contribs/common/src/main/java/org/matsim/contrib/common/zones/ZoneSystemImpl.java new file mode 100644 index 00000000000..958575ecf40 --- /dev/null +++ b/contribs/common/src/main/java/org/matsim/contrib/common/zones/ZoneSystemImpl.java @@ -0,0 +1,43 @@ +package org.matsim.contrib.common.zones; + +import org.apache.commons.lang3.tuple.Pair; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.IdMap; +import org.matsim.api.core.v01.network.Link; + +import javax.annotation.Nullable; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; + +public class ZoneSystemImpl implements ZoneSystem { + + private final Map, Zone> zones = new IdMap<>(Zone.class); + private final IdMap link2zone = new IdMap<>(Link.class); + + public ZoneSystemImpl(Collection zones) { + zones.forEach(zone -> this.zones.put(zone.getId(), zone)); + zones.stream() + .flatMap(zone -> zone.getLinks().stream().map(link -> Pair.of(link.getId(), zone))) + .forEach(idZonePair -> link2zone.put(idZonePair.getKey(), idZonePair.getValue())); + } + + /** + * @param linkId + * @return the the {@code DrtZone} that contains the {@code linkId}. If the given link's {@code Coord} borders two or more cells, the allocation to a cell is random. + * Result may be null in case the given link is outside of the service area. + */ + @Override + @Nullable + public Zone getZoneForLinkId(Id linkId) { + return link2zone.get(linkId); + } + + /** + * @return the zones + */ + @Override + public Map, Zone> getZones() { + return Collections.unmodifiableMap(zones); + } +} diff --git a/contribs/common/src/main/java/org/matsim/contrib/common/zones/ZoneSystemUtils.java b/contribs/common/src/main/java/org/matsim/contrib/common/zones/ZoneSystemUtils.java new file mode 100644 index 00000000000..26a9a6d31d6 --- /dev/null +++ b/contribs/common/src/main/java/org/matsim/contrib/common/zones/ZoneSystemUtils.java @@ -0,0 +1,65 @@ +package org.matsim.contrib.common.zones; + +import one.util.streamex.EntryStream; +import one.util.streamex.StreamEx; +import org.locationtech.jts.geom.Point; +import org.locationtech.jts.geom.prep.PreparedGeometry; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.utils.geometry.geotools.MGC; + +import javax.annotation.Nullable; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import static java.util.stream.Collectors.toList; + +public final class ZoneSystemUtils { + + + private ZoneSystemUtils() {} + + public static ZoneSystem createFromPreparedGeometries(Network network, + Map geometries) { + + //geometries without links are skipped + Map> linksByGeometryId = StreamEx.of(network.getLinks().values()) + .mapToEntry(l -> getGeometryIdForLink(l, geometries), l -> l) + .filterKeys(Objects::nonNull) + .grouping(toList()); + + //the zonal system contains only zones that have at least one link + List zones = EntryStream.of(linksByGeometryId) + .mapKeyValue((id, links) -> new ZoneImpl(Id.create(id, Zone.class), geometries.get(id), links)) + .collect(toList()); + + return new ZoneSystemImpl(zones); + } + + /** + * @param link + * @return the the {@code PreparedGeometry} that contains the {@code linkId}. + * If a given link's {@code Coord} borders two or more cells, the allocation to a cell is random. + * Result may be null in case the given link is outside of the service area. + */ + @Nullable + private static String getGeometryIdForLink(Link link, Map geometries) { + Point linkCoord = MGC.coord2Point(link.getToNode().getCoord()); + return geometries.entrySet() + .stream() + .filter(e -> e.getValue().intersects(linkCoord)) + .findAny() + .map(Map.Entry::getKey) + .orElse(null); + } + + public static Id createZoneId(String id) { + return Id.create(id, Zone.class); + } + + public static Id createZoneId(long id) { + return Id.create(id, Zone.class); + } +} diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/h3/drtZone/H3GridUtils.java b/contribs/common/src/main/java/org/matsim/contrib/common/zones/h3/H3GridUtils.java similarity index 97% rename from contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/h3/drtZone/H3GridUtils.java rename to contribs/common/src/main/java/org/matsim/contrib/common/zones/h3/H3GridUtils.java index ad1e94e43a1..9139e56442b 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/h3/drtZone/H3GridUtils.java +++ b/contribs/common/src/main/java/org/matsim/contrib/common/zones/h3/H3GridUtils.java @@ -1,4 +1,4 @@ -package org.matsim.contrib.drt.extension.h3.drtZone; +package org.matsim.contrib.common.zones.h3; import com.uber.h3core.AreaUnit; import com.uber.h3core.H3Core; @@ -13,7 +13,6 @@ import org.locationtech.jts.geom.prep.PreparedGeometryFactory; import org.matsim.api.core.v01.Coord; import org.matsim.api.core.v01.network.Network; -import org.matsim.contrib.zone.util.NetworkWithZonesUtils; import org.matsim.core.network.NetworkUtils; import org.matsim.core.utils.geometry.CoordUtils; import org.matsim.core.utils.geometry.CoordinateTransformation; diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/h3/drtZone/H3Utils.java b/contribs/common/src/main/java/org/matsim/contrib/common/zones/h3/H3Utils.java similarity index 78% rename from contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/h3/drtZone/H3Utils.java rename to contribs/common/src/main/java/org/matsim/contrib/common/zones/h3/H3Utils.java index 9e9e13524c9..3bc44478ebf 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/h3/drtZone/H3Utils.java +++ b/contribs/common/src/main/java/org/matsim/contrib/common/zones/h3/H3Utils.java @@ -1,4 +1,4 @@ -package org.matsim.contrib.drt.extension.h3.drtZone; +package org.matsim.contrib.common.zones.h3; import com.uber.h3core.H3Core; @@ -11,7 +11,7 @@ public final class H3Utils { private static H3Core h3; - public final static int MAX_RES = 15; + public final static int MAX_RES = 16; public static H3Core getInstance() { diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/h3/drtZone/H3ZonalSystem.java b/contribs/common/src/main/java/org/matsim/contrib/common/zones/h3/H3ZoneSystemUtils.java similarity index 73% rename from contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/h3/drtZone/H3ZonalSystem.java rename to contribs/common/src/main/java/org/matsim/contrib/common/zones/h3/H3ZoneSystemUtils.java index edb9eaa6374..24c2aeea603 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/h3/drtZone/H3ZonalSystem.java +++ b/contribs/common/src/main/java/org/matsim/contrib/common/zones/h3/H3ZoneSystemUtils.java @@ -1,4 +1,4 @@ -package org.matsim.contrib.drt.extension.h3.drtZone; +package org.matsim.contrib.common.zones.h3; import com.uber.h3core.H3Core; import com.uber.h3core.util.LatLng; @@ -7,10 +7,13 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.locationtech.jts.geom.prep.PreparedGeometry; +import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; import org.matsim.api.core.v01.network.Network; -import org.matsim.contrib.drt.analysis.zonal.DrtZonalSystem; -import org.matsim.contrib.drt.analysis.zonal.DrtZone; +import org.matsim.contrib.common.zones.Zone; +import org.matsim.contrib.common.zones.ZoneImpl; +import org.matsim.contrib.common.zones.ZoneSystem; +import org.matsim.contrib.common.zones.ZoneSystemImpl; import org.matsim.core.utils.geometry.CoordinateTransformation; import org.matsim.core.utils.geometry.transformations.TransformationFactory; @@ -24,15 +27,15 @@ /** * @author nkuehnel / MOIA */ -public final class H3ZonalSystem { +public class H3ZoneSystemUtils { - static final Logger log = LogManager.getLogger(H3ZonalSystem.class); + static final Logger log = LogManager.getLogger(H3ZoneSystemUtils.class); - public static DrtZonalSystem createFromPreparedGeometries(Network network, - Map geometries, - String crs, - int resolution) { + public static ZoneSystem createFromPreparedGeometries(Network network, + Map geometries, + String crs, + int resolution) { //geometries without links are skipped CoordinateTransformation ct = TransformationFactory.getCoordinateTransformation(crs, TransformationFactory.WGS84); @@ -45,11 +48,12 @@ public static DrtZonalSystem createFromPreparedGeometries(Network network, + network.getLinks().size() + " links and " + network.getNodes().size() + " nodes."); //the zonal system contains only zones that have at least one link - List zones = EntryStream.of(linksByGeometryId) - .mapKeyValue((id, links) -> new DrtZone(id, geometries.get(id), links)) + List zones = EntryStream.of(linksByGeometryId) + .mapKeyValue((id, links) -> new ZoneImpl(Id.create(id, Zone.class), geometries.get(id), links) { + }) .collect(toList()); - return new DrtZonalSystem(zones); + return new ZoneSystemImpl(zones); } /** diff --git a/contribs/drt-extensions/pom.xml b/contribs/drt-extensions/pom.xml index 130ecb31138..d3ccd511acd 100644 --- a/contribs/drt-extensions/pom.xml +++ b/contribs/drt-extensions/pom.xml @@ -53,11 +53,6 @@ org.mockito mockito-core - - com.uber - h3 - 4.1.1 - diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/h3/drtZone/H3ModeZonalSystemModule.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/h3/drtZone/H3ModeZonalSystemModule.java deleted file mode 100644 index 69a41bfa12e..00000000000 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/h3/drtZone/H3ModeZonalSystemModule.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.matsim.contrib.drt.extension.h3.drtZone; - -import com.google.common.base.Preconditions; -import org.locationtech.jts.geom.prep.PreparedGeometry; -import org.matsim.api.core.v01.network.Network; -import org.matsim.contrib.drt.analysis.zonal.DrtZonalSystem; -import org.matsim.contrib.drt.analysis.zonal.DrtZonalSystemParams; -import org.matsim.contrib.drt.run.DrtConfigGroup; -import org.matsim.contrib.dvrp.run.AbstractDvrpModeModule; -import org.matsim.core.config.ConfigGroup; - -import java.util.Map; - -import static org.matsim.contrib.drt.analysis.zonal.DrtGridUtils.filterGridWithinServiceArea; -import static org.matsim.utils.gis.shp2matsim.ShpGeometryUtils.loadPreparedGeometries; - -/** - * @author nkuehnel / MOIA - */ -public class H3ModeZonalSystemModule extends AbstractDvrpModeModule { - - private final DrtConfigGroup drtCfg; - private final String crs; - private final int resolution; - - public H3ModeZonalSystemModule(DrtConfigGroup drtCfg, String crs, int resolution) { - super(drtCfg.getMode()); - this.drtCfg = drtCfg; - this.crs = crs; - this.resolution = resolution; - } - @Override - public void install() { - - DrtZonalSystemParams params = drtCfg.getZonalSystemParams().orElseThrow(); - - bindModal(DrtZonalSystem.class).toProvider(modalProvider(getter -> { - Network network = getter.getModal(Network.class); - switch (params.zonesGeneration) { - case ShapeFile: - throw new IllegalArgumentException("Cannot use H3 system with self-provided shapefile"); - case GridFromNetwork: - Preconditions.checkNotNull(params.cellSize); - Map gridFromNetwork = H3GridUtils.createH3GridFromNetwork(network, resolution, crs); - var gridZones = - switch (drtCfg.operationalScheme) { - case stopbased, door2door -> gridFromNetwork; - case serviceAreaBased -> filterGridWithinServiceArea(gridFromNetwork, - loadPreparedGeometries(ConfigGroup.getInputFileURL(getConfig().getContext(), - drtCfg.drtServiceAreaShapeFile))); - }; - return H3ZonalSystem.createFromPreparedGeometries(network, gridZones, crs, resolution); - - default: - throw new RuntimeException("Unsupported zone generation"); - } - })).asEagerSingleton(); - } -} diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/h3/RunDrtWithH3ZonalSystemIT.java b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/h3/RunDrtWithH3ZonalSystemIT.java index 55933793765..86595942ed2 100644 --- a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/h3/RunDrtWithH3ZonalSystemIT.java +++ b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/h3/RunDrtWithH3ZonalSystemIT.java @@ -4,12 +4,11 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import org.matsim.application.MATSimApplication; +import org.matsim.contrib.common.zones.ZoneSystem; import org.matsim.contrib.drt.analysis.DrtEventSequenceCollector; -import org.matsim.contrib.drt.analysis.zonal.DrtZonalSystem; import org.matsim.contrib.drt.analysis.zonal.DrtZonalSystemParams; import org.matsim.contrib.drt.analysis.zonal.DrtZonalWaitTimesAnalyzer; import org.matsim.contrib.drt.extension.DrtTestScenario; -import org.matsim.contrib.drt.extension.h3.drtZone.H3ModeZonalSystemModule; import org.matsim.contrib.drt.run.DrtConfigGroup; import org.matsim.contrib.drt.run.MultiModeDrtConfigGroup; import org.matsim.contrib.dvrp.run.AbstractDvrpModeModule; @@ -46,16 +45,17 @@ private static void prepare(Controler controler, Config config) { MultiModeDrtConfigGroup drtConfigs = ConfigUtils.addOrGetModule(config, MultiModeDrtConfigGroup.class); for (DrtConfigGroup drtConfig : drtConfigs.getModalElements()) { + drtConfig.getZonalSystemParams().get().h3Resolution = 9; + drtConfig.getZonalSystemParams().get().zonesGeneration = DrtZonalSystemParams.ZoneGeneration.H3; controler.addOverridingModule(new AbstractModule() { @Override public void install() { - install(new H3ModeZonalSystemModule(drtConfig, config.global().getCoordinateSystem(), 9)); install(new AbstractDvrpModeModule(drtConfig.mode) { @Override public void install() { bindModal(DrtZonalWaitTimesAnalyzer.class).toProvider(modalProvider( getter -> new DrtZonalWaitTimesAnalyzer(drtConfig, getter.getModal(DrtEventSequenceCollector.class), - getter.getModal(DrtZonalSystem.class)))).asEagerSingleton(); + getter.getModal(ZoneSystem.class)))).asEagerSingleton(); addControlerListenerBinding().to(modalKey(DrtZonalWaitTimesAnalyzer.class)); } }); diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/h3/drtZone/H3DrtZonalSystemTest.java b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/h3/drtZone/H3DrtZonalSystemTest.java index 5cb88e3d851..293fa254280 100644 --- a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/h3/drtZone/H3DrtZonalSystemTest.java +++ b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/h3/drtZone/H3DrtZonalSystemTest.java @@ -24,7 +24,9 @@ import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; import org.matsim.api.core.v01.network.Network; -import org.matsim.contrib.drt.analysis.zonal.DrtZonalSystem; +import org.matsim.contrib.common.zones.ZoneSystem; +import org.matsim.contrib.common.zones.h3.H3GridUtils; +import org.matsim.contrib.common.zones.h3.H3ZoneSystemUtils; import org.matsim.core.config.ConfigGroup; import org.matsim.core.network.NetworkUtils; import org.matsim.core.network.io.MatsimNetworkReader; @@ -35,6 +37,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.matsim.contrib.common.zones.ZoneSystemUtils.createZoneId; /** * @author nkuehnel / MOIA @@ -46,17 +49,17 @@ void test_Holzkirchen_Resolution3() { Network network = getNetwork(); String crs = TransformationFactory.DHDN_GK4; int resolution = 3; - DrtZonalSystem drtZonalSystem = H3ZonalSystem.createFromPreparedGeometries(network, + ZoneSystem drtZonalSystem = H3ZoneSystemUtils.createFromPreparedGeometries(network, H3GridUtils.createH3GridFromNetwork(network, resolution, crs), crs, resolution); - assertThat(drtZonalSystem.getZones().containsKey("831f8dfffffffff")).isTrue(); + assertThat(drtZonalSystem.getZones().containsKey(createZoneId("831f8dfffffffff"))).isTrue(); // center of Holzkirchen - assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(358598)).getId()).isEqualTo("831f8dfffffffff"); + assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(358598)).getId()).isEqualTo(createZoneId("831f8dfffffffff")); // Thanning (Western border of network) - assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(78976)).getId()).isEqualTo("831f8dfffffffff"); + assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(78976)).getId()).isEqualTo(createZoneId("831f8dfffffffff")); // between Gross- and Kleinpienzenau (Southeastern border of network) - assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(59914)).getId()).isEqualTo("831f89fffffffff"); + assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(59914)).getId()).isEqualTo(createZoneId("831f89fffffffff")); //check all links are mapped for (Link link : network.getLinks().values()) { @@ -69,20 +72,20 @@ void test_Holzkirchen_Resolution5() { Network network = getNetwork(); String crs = TransformationFactory.DHDN_GK4; int resolution = 5; - DrtZonalSystem drtZonalSystem = H3ZonalSystem.createFromPreparedGeometries(network, + ZoneSystem drtZonalSystem = H3ZoneSystemUtils.createFromPreparedGeometries(network, H3GridUtils.createH3GridFromNetwork(network, resolution, crs), crs, resolution); - assertThat(drtZonalSystem.getZones().containsKey("851f88b7fffffff")).isTrue(); - assertThat(drtZonalSystem.getZones().containsKey("851f8d6bfffffff")).isTrue(); - assertThat(drtZonalSystem.getZones().containsKey("851f88a7fffffff")).isTrue(); - assertThat(drtZonalSystem.getZones().containsKey("851f89d3fffffff")).isTrue(); + assertThat(drtZonalSystem.getZones().containsKey(createZoneId("851f88b7fffffff"))).isTrue(); + assertThat(drtZonalSystem.getZones().containsKey(createZoneId("851f8d6bfffffff"))).isTrue(); + assertThat(drtZonalSystem.getZones().containsKey(createZoneId("851f88a7fffffff"))).isTrue(); + assertThat(drtZonalSystem.getZones().containsKey(createZoneId("851f89d3fffffff"))).isTrue(); // center of Holzkirchen - assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(358598)).getId()).isEqualTo("851f8d6bfffffff"); + assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(358598)).getId()).isEqualTo(createZoneId("851f8d6bfffffff")); // Thanning (Western border of network) - assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(78976)).getId()).isEqualTo("851f88b7fffffff"); + assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(78976)).getId()).isEqualTo(createZoneId("851f88b7fffffff")); // between Gross- and Kleinpienzenau (Southeastern border of network) - assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(59914)).getId()).isEqualTo("851f89d3fffffff"); + assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(59914)).getId()).isEqualTo(createZoneId("851f89d3fffffff")); //check all links are mapped for (Link link : network.getLinks().values()) { @@ -95,22 +98,22 @@ void test_Holzkirchen_Resolution6() { Network network = getNetwork(); String crs = TransformationFactory.DHDN_GK4; int resolution = 6; - DrtZonalSystem drtZonalSystem = H3ZonalSystem.createFromPreparedGeometries(network, + ZoneSystem drtZonalSystem = H3ZoneSystemUtils.createFromPreparedGeometries(network, H3GridUtils.createH3GridFromNetwork(network, resolution, crs), crs, resolution); - assertThat(drtZonalSystem.getZones().containsKey("861f8d697ffffff")).isTrue(); - assertThat(drtZonalSystem.getZones().containsKey("861f8d687ffffff")).isTrue(); - assertThat(drtZonalSystem.getZones().containsKey("861f8d69fffffff")).isTrue(); - assertThat(drtZonalSystem.getZones().containsKey("861f88a6fffffff")).isTrue(); - assertThat(drtZonalSystem.getZones().containsKey("861f88a6fffffff")).isTrue(); - assertThat(drtZonalSystem.getZones().containsKey("861f89d37ffffff")).isTrue(); + assertThat(drtZonalSystem.getZones().containsKey(createZoneId("861f8d697ffffff"))).isTrue(); + assertThat(drtZonalSystem.getZones().containsKey(createZoneId("861f8d687ffffff"))).isTrue(); + assertThat(drtZonalSystem.getZones().containsKey(createZoneId("861f8d69fffffff"))).isTrue(); + assertThat(drtZonalSystem.getZones().containsKey(createZoneId("861f88a6fffffff"))).isTrue(); + assertThat(drtZonalSystem.getZones().containsKey(createZoneId("861f88a6fffffff"))).isTrue(); + assertThat(drtZonalSystem.getZones().containsKey(createZoneId("861f89d37ffffff"))).isTrue(); // center of Holzkirchen - assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(358598)).getId()).isEqualTo("861f8d697ffffff"); + assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(358598)).getId()).isEqualTo(createZoneId("861f8d697ffffff")); // Thanning (Western border of network) - assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(78976)).getId()).isEqualTo("861f88b47ffffff"); + assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(78976)).getId()).isEqualTo(createZoneId("861f88b47ffffff")); // between Gross- and Kleinpienzenau (Southeastern border of network) - assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(59914)).getId()).isEqualTo("861f89d07ffffff"); + assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(59914)).getId()).isEqualTo(createZoneId("861f89d07ffffff")); //check all links are mapped for (Link link : network.getLinks().values()) { @@ -123,15 +126,15 @@ void test_Holzkirchen_Resolution10() { Network network = getNetwork(); String crs = TransformationFactory.DHDN_GK4; int resolution = 10; - DrtZonalSystem drtZonalSystem = H3ZonalSystem.createFromPreparedGeometries(network, + ZoneSystem drtZonalSystem = H3ZoneSystemUtils.createFromPreparedGeometries(network, H3GridUtils.createH3GridFromNetwork(network, resolution, crs), crs, resolution); // center of Holzkirchen - assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(358598)).getId()).isEqualTo("8a1f8d6930b7fff"); + assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(358598)).getId()).isEqualTo(createZoneId("8a1f8d6930b7fff")); // Thanning (Western border of network) - assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(78976)).getId()).isEqualTo("8a1f88b4025ffff"); + assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(78976)).getId()).isEqualTo(createZoneId("8a1f88b4025ffff")); // between Gross- and Kleinpienzenau (Southeastern border of network) - assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(59914)).getId()).isEqualTo("8a1f89d06d5ffff"); + assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(59914)).getId()).isEqualTo(createZoneId("8a1f89d06d5ffff")); //check all links are mapped for (Link link : network.getLinks().values()) { @@ -144,15 +147,15 @@ void test_Holzkirchen_Resolution12() { Network network = getNetwork(); String crs = TransformationFactory.DHDN_GK4; int resolution = 12; - DrtZonalSystem drtZonalSystem = H3ZonalSystem.createFromPreparedGeometries(network, + ZoneSystem drtZonalSystem = H3ZoneSystemUtils.createFromPreparedGeometries(network, H3GridUtils.createH3GridFromNetwork(network, resolution, crs), crs, resolution); // center of Holzkirchen - assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(358598)).getId()).isEqualTo("8c1f8d6930b63ff"); + assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(358598)).getId()).isEqualTo(createZoneId("8c1f8d6930b63ff")); // Thanning (Western border of network) - assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(78976)).getId()).isEqualTo("8c1f88b4025d1ff"); + assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(78976)).getId()).isEqualTo(createZoneId("8c1f88b4025d1ff")); // between Gross- and Kleinpienzenau (Southeastern border of network) - assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(59914)).getId()).isEqualTo("8c1f89d06d581ff"); + assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(59914)).getId()).isEqualTo(createZoneId("8c1f89d06d581ff")); //check all links are mapped for (Link link : network.getLinks().values()) { diff --git a/contribs/drt/pom.xml b/contribs/drt/pom.xml index a80d854f1b5..f04956d8ea0 100644 --- a/contribs/drt/pom.xml +++ b/contribs/drt/pom.xml @@ -50,19 +50,13 @@ gt-main ${geotools.version} - + org.geotools gt-opengis ${geotools.version} - - one.util - streamex - 0.8.2 - - org.locationtech.jts jts-core diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtGridUtils.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtGridUtils.java index c8e9acfde42..c27203c6ce5 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtGridUtils.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtGridUtils.java @@ -22,10 +22,7 @@ */ package org.matsim.contrib.drt.analysis.zonal; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - +import one.util.streamex.EntryStream; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.locationtech.jts.geom.Coordinate; @@ -37,7 +34,9 @@ import org.matsim.core.network.NetworkUtils; import org.matsim.core.utils.misc.Counter; -import one.util.streamex.EntryStream; +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** * @author jbischoff diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtModeZonalSystemModule.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtModeZonalSystemModule.java index 5875d9451ca..bd3e6b7ddc6 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtModeZonalSystemModule.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtModeZonalSystemModule.java @@ -20,25 +20,26 @@ package org.matsim.contrib.drt.analysis.zonal; -import static org.matsim.contrib.drt.analysis.zonal.DrtGridUtils.createGridFromNetwork; -import static org.matsim.contrib.drt.analysis.zonal.DrtGridUtils.filterGridWithinServiceArea; -import static org.matsim.contrib.drt.run.DrtConfigGroup.OperationalScheme; -import static org.matsim.utils.gis.shp2matsim.ShpGeometryUtils.loadPreparedGeometries; - -import java.util.List; -import java.util.Map; - +import com.google.common.base.Preconditions; +import one.util.streamex.EntryStream; import org.locationtech.jts.geom.prep.PreparedGeometry; import org.matsim.api.core.v01.network.Network; +import org.matsim.contrib.common.zones.ZoneSystem; +import org.matsim.contrib.common.zones.ZoneSystemUtils; +import org.matsim.contrib.common.zones.h3.H3GridUtils; +import org.matsim.contrib.common.zones.h3.H3ZoneSystemUtils; import org.matsim.contrib.drt.analysis.DrtEventSequenceCollector; import org.matsim.contrib.drt.run.DrtConfigGroup; import org.matsim.contrib.dvrp.run.AbstractDvrpModeModule; import org.matsim.core.config.ConfigGroup; import org.matsim.core.controler.MatsimServices; -import com.google.common.base.Preconditions; +import java.util.List; +import java.util.Map; -import one.util.streamex.EntryStream; +import static org.matsim.contrib.drt.analysis.zonal.DrtGridUtils.createGridFromNetwork; +import static org.matsim.contrib.drt.analysis.zonal.DrtGridUtils.filterGridWithinServiceArea; +import static org.matsim.utils.gis.shp2matsim.ShpGeometryUtils.loadPreparedGeometries; /** * @author Michal Maciejewski (michalm) @@ -57,26 +58,41 @@ public void install() { if (drtCfg.getZonalSystemParams().isPresent()) { DrtZonalSystemParams params = drtCfg.getZonalSystemParams().get(); - bindModal(DrtZonalSystem.class).toProvider(modalProvider(getter -> { + bindModal(ZoneSystem.class).toProvider(modalProvider(getter -> { Network network = getter.getModal(Network.class); switch (params.zonesGeneration) { - case ShapeFile: + case ShapeFile: { final List preparedGeometries = loadPreparedGeometries( ConfigGroup.getInputFileURL(getConfig().getContext(), params.zonesShapeFile)); - return DrtZonalSystem.createFromPreparedGeometries(network, + return ZoneSystemUtils.createFromPreparedGeometries(network, EntryStream.of(preparedGeometries).mapKeys(i -> (i + 1) + "").toMap()); + } - case GridFromNetwork: + case GridFromNetwork: { Preconditions.checkNotNull(params.cellSize); Map gridFromNetwork = createGridFromNetwork(network, params.cellSize); - var gridZones = - switch (drtCfg.operationalScheme) { - case stopbased, door2door -> gridFromNetwork; - case serviceAreaBased -> filterGridWithinServiceArea(gridFromNetwork, - loadPreparedGeometries(ConfigGroup.getInputFileURL(getConfig().getContext(), - drtCfg.drtServiceAreaShapeFile))); - }; - return DrtZonalSystem.createFromPreparedGeometries(network, gridZones); + var gridZones = + switch (drtCfg.operationalScheme) { + case stopbased, door2door -> gridFromNetwork; + case serviceAreaBased -> filterGridWithinServiceArea(gridFromNetwork, + loadPreparedGeometries(ConfigGroup.getInputFileURL(getConfig().getContext(), + drtCfg.drtServiceAreaShapeFile))); + }; + return ZoneSystemUtils.createFromPreparedGeometries(network, gridZones); + } + + case H3: + Preconditions.checkNotNull(params.h3Resolution); + String crs = getConfig().global().getCoordinateSystem(); + Map gridFromNetwork = H3GridUtils.createH3GridFromNetwork(network, params.h3Resolution, crs); + var gridZones = + switch (drtCfg.operationalScheme) { + case stopbased, door2door -> gridFromNetwork; + case serviceAreaBased -> filterGridWithinServiceArea(gridFromNetwork, + loadPreparedGeometries(ConfigGroup.getInputFileURL(getConfig().getContext(), + drtCfg.drtServiceAreaShapeFile))); + }; + return H3ZoneSystemUtils.createFromPreparedGeometries(network, gridZones, crs, params.h3Resolution); default: throw new RuntimeException("Unsupported zone generation"); @@ -86,7 +102,7 @@ public void install() { bindModal(DrtZoneTargetLinkSelector.class).toProvider(modalProvider(getter -> { switch (params.targetLinkSelection) { case mostCentral: - return new MostCentralDrtZoneTargetLinkSelector(getter.getModal(DrtZonalSystem.class)); + return new MostCentralDrtZoneTargetLinkSelector(getter.getModal(ZoneSystem.class)); case random: return new RandomDrtZoneTargetLinkSelector(); default: @@ -98,13 +114,13 @@ public void install() { //zonal analysis bindModal(ZonalIdleVehicleXYVisualiser.class).toProvider(modalProvider( getter -> new ZonalIdleVehicleXYVisualiser(getter.get(MatsimServices.class), drtCfg.getMode(), - getter.getModal(DrtZonalSystem.class)))).asEagerSingleton(); + getter.getModal(ZoneSystem.class)))).asEagerSingleton(); addControlerListenerBinding().to(modalKey(ZonalIdleVehicleXYVisualiser.class)); addEventHandlerBinding().to(modalKey(ZonalIdleVehicleXYVisualiser.class)); bindModal(DrtZonalWaitTimesAnalyzer.class).toProvider(modalProvider( getter -> new DrtZonalWaitTimesAnalyzer(drtCfg, getter.getModal(DrtEventSequenceCollector.class), - getter.getModal(DrtZonalSystem.class)))).asEagerSingleton(); + getter.getModal(ZoneSystem.class)))).asEagerSingleton(); addControlerListenerBinding().to(modalKey(DrtZonalWaitTimesAnalyzer.class)); } } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtZonalSystem.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtZonalSystem.java deleted file mode 100644 index 33647f30d80..00000000000 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtZonalSystem.java +++ /dev/null @@ -1,111 +0,0 @@ -/* *********************************************************************** * - * project: org.matsim.* - * * - * *********************************************************************** * - * * - * copyright : (C) 2017 by the members listed in the COPYING, * - * LICENSE and WARRANTY file. * - * email : info at matsim dot org * - * * - * *********************************************************************** * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * See also COPYING, LICENSE and WARRANTY file * - * * - * *********************************************************************** */ - -package org.matsim.contrib.drt.analysis.zonal; - -import static java.util.stream.Collectors.toList; -import static java.util.stream.Collectors.toMap; - -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Objects; - -import javax.annotation.Nullable; - -import org.apache.commons.lang3.tuple.Pair; -import org.locationtech.jts.geom.Point; -import org.locationtech.jts.geom.prep.PreparedGeometry; -import org.matsim.api.core.v01.Id; -import org.matsim.api.core.v01.network.Link; -import org.matsim.api.core.v01.network.Network; -import org.matsim.core.utils.geometry.geotools.MGC; - -import one.util.streamex.EntryStream; -import one.util.streamex.StreamEx; - -/** - * @author jbischoff - * @author Michal Maciejewski (michalm) - * @author Tilmann Schlenther (tschlenther) - */ -public class DrtZonalSystem { - - public static DrtZonalSystem createFromPreparedGeometries(Network network, - Map geometries) { - - //geometries without links are skipped - Map> linksByGeometryId = StreamEx.of(network.getLinks().values()) - .mapToEntry(l -> getGeometryIdForLink(l, geometries), l -> l) - .filterKeys(Objects::nonNull) - .grouping(toList()); - - //the zonal system contains only zones that have at least one link - List zones = EntryStream.of(linksByGeometryId) - .mapKeyValue((id, links) -> new DrtZone(id, geometries.get(id), links)) - .collect(toList()); - - return new DrtZonalSystem(zones); - } - - /** - * @param link - * @return the the {@code PreparedGeometry} that contains the {@code linkId}. - * If a given link's {@code Coord} borders two or more cells, the allocation to a cell is random. - * Result may be null in case the given link is outside of the service area. - */ - @Nullable - private static String getGeometryIdForLink(Link link, Map geometries) { - Point linkCoord = MGC.coord2Point(link.getToNode().getCoord()); - return geometries.entrySet() - .stream() - .filter(e -> e.getValue().intersects(linkCoord)) - .findAny() - .map(Entry::getKey) - .orElse(null); - } - - private final Map zones; - private final Map, DrtZone> link2zone; - - public DrtZonalSystem(Collection zones) { - this.zones = zones.stream().collect(toMap(DrtZone::getId, z -> z)); - this.link2zone = zones.stream() - .flatMap(zone -> zone.getLinks().stream().map(link -> Pair.of(link.getId(), zone))) - .collect(toMap(Pair::getKey, Pair::getValue)); - } - - /** - * @param linkId - * @return the the {@code DrtZone} that contains the {@code linkId}. If the given link's {@code Coord} borders two or more cells, the allocation to a cell is random. - * Result may be null in case the given link is outside of the service area. - */ - @Nullable - public DrtZone getZoneForLinkId(Id linkId) { - return link2zone.get(linkId); - } - - /** - * @return the zones - */ - public Map getZones() { - return zones; - } -} diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtZonalSystemParams.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtZonalSystemParams.java index 01230c1e115..4dd0860b578 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtZonalSystemParams.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtZonalSystemParams.java @@ -22,6 +22,7 @@ import javax.annotation.Nullable; +import org.matsim.contrib.common.zones.h3.H3Utils; import org.matsim.core.config.Config; import org.matsim.core.config.ReflectiveConfigGroup; @@ -40,10 +41,10 @@ public DrtZonalSystemParams() { super(SET_NAME); } - public enum ZoneGeneration {GridFromNetwork, ShapeFile} + public enum ZoneGeneration {GridFromNetwork, ShapeFile, H3} @Parameter - @Comment("Logic for generation of zones for the DRT zonal system. Value can be: [GridFromNetwork, ShapeFile].") + @Comment("Logic for generation of zones for the DRT zonal system. Value can be: [GridFromNetwork, ShapeFile, H3].") @NotNull public ZoneGeneration zonesGeneration = null; @@ -59,6 +60,14 @@ public enum ZoneGeneration {GridFromNetwork, ShapeFile} @Nullable public String zonesShapeFile = null; + @Parameter + @Comment("allows to configure H3 hexagonal zones. Used with zonesGeneration=H3. " + + "Range from 0 (122 cells worldwide) to 15 (569 E^12 cells). " + + "Usually meaningful between resolution 6 (3.7 km avg edge length) " + + "and 10 (70 m avg edge length). ") + @Nullable + public Integer h3Resolution = null; + public enum TargetLinkSelection {random, mostCentral} @Parameter("zoneTargetLinkSelection") @@ -75,5 +84,9 @@ protected void checkConsistency(Config config) { "cellSize must not be null when zonesGeneration is " + ZoneGeneration.GridFromNetwork); Preconditions.checkArgument(zonesGeneration != ZoneGeneration.ShapeFile || zonesShapeFile != null, "zonesShapeFile must not be null when zonesGeneration is " + ZoneGeneration.ShapeFile); + Preconditions.checkArgument(zonesGeneration != ZoneGeneration.H3 || h3Resolution != null, + "H3 resolution must not be null when zonesGeneration is " + ZoneGeneration.H3); + Preconditions.checkArgument(h3Resolution == null || h3Resolution >= 0 && h3Resolution <= H3Utils.MAX_RES, + "H3 resolution must not be null when zonesGeneration is " + ZoneGeneration.H3); } } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtZonalWaitTimesAnalyzer.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtZonalWaitTimesAnalyzer.java index 129c952ec09..4972db0a280 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtZonalWaitTimesAnalyzer.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtZonalWaitTimesAnalyzer.java @@ -20,12 +20,6 @@ package org.matsim.contrib.drt.analysis.zonal; -import java.io.BufferedWriter; -import java.io.IOException; -import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; -import java.util.*; - import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -34,7 +28,10 @@ import org.locationtech.jts.geom.Geometry; import org.locationtech.jts.geom.Polygon; import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.IdMap; import org.matsim.api.core.v01.population.Person; +import org.matsim.contrib.common.zones.Zone; +import org.matsim.contrib.common.zones.ZoneSystem; import org.matsim.contrib.drt.analysis.DrtEventSequenceCollector; import org.matsim.contrib.drt.analysis.DrtEventSequenceCollector.EventSequence; import org.matsim.contrib.drt.run.DrtConfigGroup; @@ -47,17 +44,23 @@ import org.matsim.core.utils.io.IOUtils; import org.opengis.feature.simple.SimpleFeature; +import java.io.BufferedWriter; +import java.io.IOException; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.*; + public final class DrtZonalWaitTimesAnalyzer implements IterationEndsListener, ShutdownListener { private final DrtConfigGroup drtCfg; private final DrtEventSequenceCollector requestAnalyzer; - private final DrtZonalSystem zones; - private static final String zoneIdForOutsideOfZonalSystem = "outsideOfDrtZonalSystem"; + private final ZoneSystem zones; + private static final Id zoneIdForOutsideOfZonalSystem = Id.create("outsideOfDrtZonalSystem", Zone.class); private static final String notAvailableString = "NaN"; private static final Logger log = LogManager.getLogger(DrtZonalWaitTimesAnalyzer.class); public DrtZonalWaitTimesAnalyzer(DrtConfigGroup configGroup, DrtEventSequenceCollector requestAnalyzer, - DrtZonalSystem zones) { + ZoneSystem zones) { this.drtCfg = configGroup; this.requestAnalyzer = requestAnalyzer; this.zones = zones; @@ -73,7 +76,7 @@ public void notifyIterationEnds(IterationEndsEvent event) { public void write(String fileName) { String delimiter = ";"; - Map zoneStats = createZonalStats(); + Map, DescriptiveStatistics> zoneStats = createZonalStats(); BufferedWriter bw = IOUtils.getBufferedWriter(fileName); try { DecimalFormat format = new DecimalFormat(); @@ -83,16 +86,16 @@ public void write(String fileName) { format.setGroupingUsed(false); bw.append("zone;centerX;centerY;nRequests;sumWaitTime;meanWaitTime;min;max;p95;p90;p80;p75;p50"); // sorted output - SortedSet zoneIdsAndOutside = new TreeSet<>(zones.getZones().keySet()); + SortedSet> zoneIdsAndOutside = new TreeSet<>(zones.getZones().keySet()); zoneIdsAndOutside.add(zoneIdForOutsideOfZonalSystem); - for (String zoneId : zoneIdsAndOutside) { - DrtZone drtZone = zones.getZones().get(zoneId); + for (Id zoneId : zoneIdsAndOutside) { + Zone drtZone = zones.getZones().get(zoneId); String centerX = drtZone != null ? String.valueOf(drtZone.getCentroid().getX()) : notAvailableString; String centerY = drtZone != null ? String.valueOf(drtZone.getCentroid().getY()) : notAvailableString; DescriptiveStatistics stats = zoneStats.get(zoneId); bw.newLine(); - bw.append(zoneId) + bw.append(zoneId.toString()) .append(delimiter) .append(centerX) .append(delimiter) @@ -125,10 +128,10 @@ public void write(String fileName) { } } - private Map createZonalStats() { - Map zoneStats = new HashMap<>(); + private Map, DescriptiveStatistics> createZonalStats() { + Map, DescriptiveStatistics> zoneStats = new IdMap<>(Zone.class); // prepare stats for all zones - for (String zoneId : zones.getZones().keySet()) { + for (Id zoneId : zones.getZones().keySet()) { zoneStats.put(zoneId, new DescriptiveStatistics()); } zoneStats.put(zoneIdForOutsideOfZonalSystem, new DescriptiveStatistics()); @@ -136,8 +139,8 @@ private Map createZonalStats() { for (EventSequence seq : requestAnalyzer.getPerformedRequestSequences().values()) { for (Map.Entry, EventSequence.PersonEvents> entry : seq.getPersonEvents().entrySet()) { if(entry.getValue().getPickedUp().isPresent()) { - DrtZone zone = zones.getZoneForLinkId(seq.getSubmitted().getFromLinkId()); - final String zoneStr = zone != null ? zone.getId() : zoneIdForOutsideOfZonalSystem; + Zone zone = zones.getZoneForLinkId(seq.getSubmitted().getFromLinkId()); + final Id zoneStr = zone != null ? zone.getId() : zoneIdForOutsideOfZonalSystem; double waitTime = entry.getValue().getPickedUp().get() .getTime() - seq.getSubmitted().getTime(); zoneStats.get(zoneStr).addValue(waitTime); } @@ -194,9 +197,9 @@ private Collection convertGeometriesToSimpleFeatures(String targe Collection features = new ArrayList<>(); - Map zoneStats = createZonalStats(); + Map, DescriptiveStatistics> zoneStats = createZonalStats(); - for (DrtZone zone : zones.getZones().values()) { + for (Zone zone : zones.getZones().values()) { Object[] routeFeatureAttributes = new Object[14]; Geometry geometry = zone.getPreparedGeometry() != null ? zone.getPreparedGeometry().getGeometry() : null; DescriptiveStatistics stats = zoneStats.get(zone.getId()); @@ -216,7 +219,7 @@ private Collection convertGeometriesToSimpleFeatures(String targe routeFeatureAttributes[13] = stats.getPercentile(50); try { - features.add(builder.buildFeature(zone.getId(), routeFeatureAttributes)); + features.add(builder.buildFeature(zone.getId().toString(), routeFeatureAttributes)); } catch (IllegalArgumentException e) { e.printStackTrace(); } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtZone.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtZone.java deleted file mode 100644 index cca2045837a..00000000000 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtZone.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * *********************************************************************** * - * project: org.matsim.* - * *********************************************************************** * - * * - * copyright : (C) 2020 by the members listed in the COPYING, * - * LICENSE and WARRANTY file. * - * email : info at matsim dot org * - * * - * *********************************************************************** * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * See also COPYING, LICENSE and WARRANTY file * - * * - * *********************************************************************** * - */ - -package org.matsim.contrib.drt.analysis.zonal; - -import java.util.List; - -import javax.annotation.Nullable; - -import org.locationtech.jts.geom.prep.PreparedGeometry; -import org.matsim.api.core.v01.Coord; -import org.matsim.api.core.v01.network.Link; -import org.matsim.core.utils.geometry.geotools.MGC; - -/** - * @author Michal Maciejewski (michalm) - */ -public class DrtZone { - public static DrtZone createDummyZone(String id, List links, Coord centroid) { - return new DrtZone(id, null, links, centroid); - } - - private final String id; - @Nullable - private final PreparedGeometry preparedGeometry; //null for virtual/dummy zones - private final List links; - private final Coord centroid; - - public DrtZone(String id, PreparedGeometry preparedGeometry, List links) { - this(id, preparedGeometry, links, MGC.point2Coord(preparedGeometry.getGeometry().getCentroid())); - } - - private DrtZone(String id, @Nullable PreparedGeometry preparedGeometry, List links, Coord centroid) { - this.id = id; - this.preparedGeometry = preparedGeometry; - this.links = links; - this.centroid = centroid; - } - - public String getId() { - return id; - } - - @Nullable - public PreparedGeometry getPreparedGeometry() { - return preparedGeometry; - } - - public Coord getCentroid() { - return centroid; - } - - public List getLinks() { - return links; - } - - boolean isDummy() { - return preparedGeometry == null; - } -} diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtZoneTargetLinkSelector.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtZoneTargetLinkSelector.java index ac7442ca369..c7c8bbeb240 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtZoneTargetLinkSelector.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtZoneTargetLinkSelector.java @@ -20,9 +20,10 @@ package org.matsim.contrib.drt.analysis.zonal; import org.matsim.api.core.v01.network.Link; +import org.matsim.contrib.common.zones.Zone; public interface DrtZoneTargetLinkSelector { - Link selectTargetLink(DrtZone zone); + Link selectTargetLink(Zone zone); } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/MostCentralDrtZoneTargetLinkSelector.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/MostCentralDrtZoneTargetLinkSelector.java index ce30fc7b5df..22022631dcc 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/MostCentralDrtZoneTargetLinkSelector.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/MostCentralDrtZoneTargetLinkSelector.java @@ -28,14 +28,16 @@ import org.matsim.api.core.v01.network.Link; import org.matsim.api.core.v01.network.Node; +import org.matsim.contrib.common.zones.Zone; +import org.matsim.contrib.common.zones.ZoneSystem; /** * @author tschlenther */ public class MostCentralDrtZoneTargetLinkSelector implements DrtZoneTargetLinkSelector { - private final Map targetLinks; + private final Map targetLinks; - public MostCentralDrtZoneTargetLinkSelector(DrtZonalSystem drtZonalSystem) { + public MostCentralDrtZoneTargetLinkSelector(ZoneSystem drtZonalSystem) { targetLinks = drtZonalSystem.getZones() .values() .stream() @@ -48,11 +50,11 @@ public MostCentralDrtZoneTargetLinkSelector(DrtZonalSystem drtZonalSystem) { } @Override - public Link selectTargetLink(DrtZone zone) { + public Link selectTargetLink(Zone zone) { return this.targetLinks.get(zone); } - private double squaredDistance(DrtZone zone, Node node) { + private double squaredDistance(Zone zone, Node node) { return calculateSquaredDistance(zone.getCentroid(), node.getCoord()); } } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/RandomDrtZoneTargetLinkSelector.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/RandomDrtZoneTargetLinkSelector.java index 2027834e17b..7c7f4413e0a 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/RandomDrtZoneTargetLinkSelector.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/RandomDrtZoneTargetLinkSelector.java @@ -23,6 +23,7 @@ import java.util.function.IntUnaryOperator; import org.matsim.api.core.v01.network.Link; +import org.matsim.contrib.common.zones.Zone; import org.matsim.core.gbl.MatsimRandom; /** @@ -40,7 +41,7 @@ public RandomDrtZoneTargetLinkSelector(IntUnaryOperator random) { } @Override - public Link selectTargetLink(DrtZone zone) { + public Link selectTargetLink(Zone zone) { return zone.getLinks().get(random.applyAsInt(zone.getLinks().size())); } } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/ZonalIdleVehicleCollector.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/ZonalIdleVehicleCollector.java index ddba7676cdf..2626e21fc3f 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/ZonalIdleVehicleCollector.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/ZonalIdleVehicleCollector.java @@ -19,34 +19,31 @@ package org.matsim.contrib.drt.analysis.zonal; +import org.matsim.api.core.v01.Id; +import org.matsim.contrib.common.zones.Zone; +import org.matsim.contrib.common.zones.ZoneSystem; +import org.matsim.contrib.drt.schedule.DrtStayTask; +import org.matsim.contrib.dvrp.fleet.DvrpVehicle; +import org.matsim.contrib.dvrp.vrpagent.*; + import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.function.Consumer; -import org.matsim.api.core.v01.Id; -import org.matsim.contrib.drt.schedule.DrtStayTask; -import org.matsim.contrib.dvrp.fleet.DvrpVehicle; -import org.matsim.contrib.dvrp.vrpagent.AbstractTaskEvent; -import org.matsim.contrib.dvrp.vrpagent.TaskEndedEvent; -import org.matsim.contrib.dvrp.vrpagent.TaskEndedEventHandler; -import org.matsim.contrib.dvrp.vrpagent.TaskStartedEvent; -import org.matsim.contrib.dvrp.vrpagent.TaskStartedEventHandler; - /** * @author jbischoff * @author Michal Maciejewski */ public class ZonalIdleVehicleCollector implements TaskStartedEventHandler, TaskEndedEventHandler { - private final DrtZonalSystem zonalSystem; + private final ZoneSystem zonalSystem; private final String dvrpMode; - private final Map>> vehiclesPerZone = new HashMap<>(); - private final Map, DrtZone> zonePerVehicle = new HashMap<>(); + private final Map>> vehiclesPerZone = new HashMap<>(); - public ZonalIdleVehicleCollector(String dvrpMode, DrtZonalSystem zonalSystem) { + public ZonalIdleVehicleCollector(String dvrpMode, ZoneSystem zonalSystem) { this.dvrpMode = dvrpMode; this.zonalSystem = zonalSystem; } @@ -55,34 +52,31 @@ public ZonalIdleVehicleCollector(String dvrpMode, DrtZonalSystem zonalSystem) { public void handleEvent(TaskStartedEvent event) { handleEvent(event, zone -> { vehiclesPerZone.computeIfAbsent(zone, z -> new HashSet<>()).add(event.getDvrpVehicleId()); - zonePerVehicle.put(event.getDvrpVehicleId(), zone); }); } @Override public void handleEvent(TaskEndedEvent event) { handleEvent(event, zone -> { - zonePerVehicle.remove(event.getDvrpVehicleId()); vehiclesPerZone.get(zone).remove(event.getDvrpVehicleId()); }); } - private void handleEvent(AbstractTaskEvent event, Consumer handler) { + private void handleEvent(AbstractTaskEvent event, Consumer handler) { if (event.getDvrpMode().equals(dvrpMode) && event.getTaskType().equals(DrtStayTask.TYPE)) { - DrtZone zone = zonalSystem.getZoneForLinkId(event.getLinkId()); + Zone zone = zonalSystem.getZoneForLinkId(event.getLinkId()); if (zone != null) { handler.accept(zone); } } } - public Set> getIdleVehiclesPerZone(DrtZone zone) { + public Set> getIdleVehiclesPerZone(Zone zone) { return this.vehiclesPerZone.get(zone); } @Override public void reset(int iteration) { - zonePerVehicle.clear(); vehiclesPerZone.clear(); } } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/ZonalIdleVehicleXYVisualiser.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/ZonalIdleVehicleXYVisualiser.java index ffaa6a8312f..8813f7673ab 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/ZonalIdleVehicleXYVisualiser.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/ZonalIdleVehicleXYVisualiser.java @@ -20,38 +20,35 @@ package org.matsim.contrib.drt.analysis.zonal; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.Map; -import java.util.function.Consumer; - +import com.opencsv.CSVWriter; import org.matsim.api.core.v01.Coord; +import org.matsim.contrib.common.zones.Zone; +import org.matsim.contrib.common.zones.ZoneSystem; import org.matsim.contrib.drt.schedule.DrtStayTask; -import org.matsim.contrib.dvrp.vrpagent.AbstractTaskEvent; -import org.matsim.contrib.dvrp.vrpagent.TaskEndedEvent; -import org.matsim.contrib.dvrp.vrpagent.TaskEndedEventHandler; -import org.matsim.contrib.dvrp.vrpagent.TaskStartedEvent; -import org.matsim.contrib.dvrp.vrpagent.TaskStartedEventHandler; +import org.matsim.contrib.dvrp.vrpagent.*; import org.matsim.core.controler.MatsimServices; import org.matsim.core.controler.events.IterationEndsEvent; import org.matsim.core.controler.listener.IterationEndsListener; import org.matsim.core.utils.collections.Tuple; -import com.opencsv.CSVWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.function.Consumer; public class ZonalIdleVehicleXYVisualiser implements TaskStartedEventHandler, TaskEndedEventHandler, IterationEndsListener { private final String mode; - private final DrtZonalSystem zonalSystem; + private final ZoneSystem zonalSystem; private final MatsimServices services; - private final Map>> zoneEntries = new LinkedHashMap<>(); + private final Map>> zoneEntries = new LinkedHashMap<>(); - public ZonalIdleVehicleXYVisualiser(MatsimServices services, String mode, DrtZonalSystem zonalSystem) { + public ZonalIdleVehicleXYVisualiser(MatsimServices services, String mode, ZoneSystem zonalSystem) { this.services = services; this.mode = mode; this.zonalSystem = zonalSystem; @@ -59,7 +56,7 @@ public ZonalIdleVehicleXYVisualiser(MatsimServices services, String mode, DrtZon } private void initEntryMap() { - for (DrtZone z : zonalSystem.getZones().values()) { + for (Zone z : zonalSystem.getZones().values()) { LinkedList> list = new LinkedList<>(); list.add(new Tuple<>(0d, 0)); zoneEntries.put(z, list); @@ -84,9 +81,9 @@ public void handleEvent(TaskEndedEvent event) { }); } - private void handleEvent(AbstractTaskEvent event, Consumer handler) { + private void handleEvent(AbstractTaskEvent event, Consumer handler) { if (event.getDvrpMode().equals(mode) && event.getTaskType().equals(DrtStayTask.TYPE)) { - DrtZone zone = zonalSystem.getZoneForLinkId(event.getLinkId()); + Zone zone = zonalSystem.getZoneForLinkId(event.getLinkId()); if (zone != null) { handler.accept(zone); } @@ -104,7 +101,7 @@ public void notifyIterationEnds(IterationEndsEvent event) { this.zoneEntries.forEach((zone, entriesList) -> { Coord c = zone.getCentroid(); entriesList.forEach(entry -> writer.writeNext( - new String[] { zone.getId(), "" + c.getX(), "" + c.getY(), "" + entry.getFirst(), + new String[] { zone.getId().toString(), "" + c.getX(), "" + c.getY(), "" + entry.getFirst(), "" + entry.getSecond() }, false)); }); diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/Feedforward/DrtModeFeedforwardRebalanceModule.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/Feedforward/DrtModeFeedforwardRebalanceModule.java index 5980ec233ad..db9f1f45bce 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/Feedforward/DrtModeFeedforwardRebalanceModule.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/Feedforward/DrtModeFeedforwardRebalanceModule.java @@ -22,7 +22,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.matsim.contrib.drt.analysis.zonal.DrtZonalSystem; +import org.matsim.contrib.common.zones.ZoneSystem; import org.matsim.contrib.drt.analysis.zonal.DrtZoneTargetLinkSelector; import org.matsim.contrib.drt.optimizer.rebalancing.RebalancingParams; import org.matsim.contrib.drt.optimizer.rebalancing.RebalancingStrategy; @@ -56,7 +56,7 @@ public void install() { @Override protected void configureQSim() { bindModal(RebalancingStrategy.class).toProvider(modalProvider( - getter -> new FeedforwardRebalancingStrategy(getter.getModal(DrtZonalSystem.class), + getter -> new FeedforwardRebalancingStrategy(getter.getModal(ZoneSystem.class), getter.getModal(Fleet.class), generalParams, strategySpecificParams, getter.getModal(FeedforwardSignalHandler.class), getter.getModal(DrtZoneTargetLinkSelector.class), @@ -67,11 +67,11 @@ protected void configureQSim() { // Create PreviousIterationDepartureRecoder (this will be created only once) bindModal(FeedforwardSignalHandler.class).toProvider(modalProvider( - getter -> new FeedforwardSignalHandler(getter.getModal(DrtZonalSystem.class), strategySpecificParams, + getter -> new FeedforwardSignalHandler(getter.getModal(ZoneSystem.class), strategySpecificParams, getter.getModal(NetDepartureReplenishDemandEstimator.class)))).asEagerSingleton(); bindModal(NetDepartureReplenishDemandEstimator.class).toProvider(modalProvider( - getter -> new NetDepartureReplenishDemandEstimator(getter.getModal(DrtZonalSystem.class), drtCfg, + getter -> new NetDepartureReplenishDemandEstimator(getter.getModal(ZoneSystem.class), drtCfg, strategySpecificParams))).asEagerSingleton(); bindModal(FastHeuristicZonalRelocationCalculator.class).toProvider(modalProvider( diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/Feedforward/FastHeuristicZonalRelocationCalculator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/Feedforward/FastHeuristicZonalRelocationCalculator.java index bb7a1e5b0e6..b3af6a40713 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/Feedforward/FastHeuristicZonalRelocationCalculator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/Feedforward/FastHeuristicZonalRelocationCalculator.java @@ -1,11 +1,7 @@ package org.matsim.contrib.drt.optimizer.rebalancing.Feedforward; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - import org.matsim.api.core.v01.network.Link; -import org.matsim.contrib.drt.analysis.zonal.DrtZone; +import org.matsim.contrib.common.zones.Zone; import org.matsim.contrib.drt.analysis.zonal.DrtZoneTargetLinkSelector; import org.matsim.contrib.drt.optimizer.rebalancing.RebalancingStrategy.Relocation; import org.matsim.contrib.drt.optimizer.rebalancing.mincostflow.AggregatedMinCostRelocationCalculator.DrtZoneVehicleSurplus; @@ -14,6 +10,10 @@ import org.matsim.contrib.drt.optimizer.rebalancing.plusOne.LinkBasedRelocationCalculator; import org.matsim.contrib.dvrp.fleet.DvrpVehicle; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + public class FastHeuristicZonalRelocationCalculator implements ZonalRelocationCalculator { private final DrtZoneTargetLinkSelector drtZoneTargetLinkSelector; @@ -25,13 +25,13 @@ public FastHeuristicZonalRelocationCalculator(DrtZoneTargetLinkSelector drtZoneT @Override public List calcRelocations(List vehicleSurplus, - Map> rebalancableVehiclesPerZone) { + Map> rebalancableVehiclesPerZone) { List targetLinks = new ArrayList<>(); List selectedRebalancableVehicles = new ArrayList<>(); for (DrtZoneVehicleSurplus drtZoneVehicleSurplus : vehicleSurplus) { int surplus = drtZoneVehicleSurplus.surplus; - DrtZone zone = drtZoneVehicleSurplus.zone; + Zone zone = drtZoneVehicleSurplus.zone; if (surplus > 0) { List rebalancableVehiclesInZone = rebalancableVehiclesPerZone.get(zone); diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/Feedforward/FeedforwardRebalancingStrategy.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/Feedforward/FeedforwardRebalancingStrategy.java index fa2e4d84547..3d61a38ee3a 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/Feedforward/FeedforwardRebalancingStrategy.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/Feedforward/FeedforwardRebalancingStrategy.java @@ -1,30 +1,25 @@ package org.matsim.contrib.drt.optimizer.rebalancing.Feedforward; -import static java.util.stream.Collectors.toSet; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.matsim.api.core.v01.network.Link; -import org.matsim.contrib.drt.analysis.zonal.DrtZonalSystem; -import org.matsim.contrib.drt.analysis.zonal.DrtZone; +import org.matsim.contrib.common.zones.Zone; +import org.matsim.contrib.common.zones.ZoneSystem; import org.matsim.contrib.drt.analysis.zonal.DrtZoneTargetLinkSelector; import org.matsim.contrib.drt.optimizer.rebalancing.RebalancingParams; import org.matsim.contrib.drt.optimizer.rebalancing.RebalancingStrategy; import org.matsim.contrib.drt.optimizer.rebalancing.RebalancingUtils; -import org.matsim.contrib.drt.optimizer.rebalancing.mincostflow.AggregatedMinCostRelocationCalculator.DrtZoneVehicleSurplus; +import org.matsim.contrib.drt.optimizer.rebalancing.mincostflow.AggregatedMinCostRelocationCalculator; import org.matsim.contrib.drt.optimizer.rebalancing.mincostflow.TransportProblem.Flow; import org.matsim.contrib.dvrp.fleet.DvrpVehicle; import org.matsim.contrib.dvrp.fleet.Fleet; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static java.util.stream.Collectors.toSet; + /** * This strategy is created based on the Feedforward Fluidic rebalancing * algorithm in AMoDeus. The algorithm send rebalancing vehicles based on the @@ -41,7 +36,7 @@ public class FeedforwardRebalancingStrategy implements RebalancingStrategy { private static final Logger log = LogManager.getLogger(FeedforwardRebalancingStrategy.class); - private final DrtZonalSystem zonalSystem; + private final ZoneSystem zonalSystem; private final Fleet fleet; private final RebalancingParams generalParams; @@ -56,9 +51,9 @@ public class FeedforwardRebalancingStrategy implements RebalancingStrategy { private final DrtZoneTargetLinkSelector drtZoneTargetLinkSelector; private final FastHeuristicZonalRelocationCalculator fastHeuristicRelocationCalculator; - private final Map>> feedforwardSignal; + private final Map>> feedforwardSignal; - public FeedforwardRebalancingStrategy(DrtZonalSystem zonalSystem, Fleet fleet, RebalancingParams generalParams, + public FeedforwardRebalancingStrategy(ZoneSystem zonalSystem, Fleet fleet, RebalancingParams generalParams, FeedforwardRebalancingStrategyParams strategySpecificParams, FeedforwardSignalHandler feedforwardSignalHandler, DrtZoneTargetLinkSelector drtZoneTargetLinkSelector, FastHeuristicZonalRelocationCalculator fastHeuristicRelocationCalculator) { @@ -90,22 +85,22 @@ public FeedforwardRebalancingStrategy(DrtZonalSystem zonalSystem, Fleet fleet, R public List calcRelocations(Stream rebalancableVehicles, double time) { List relocationList = new ArrayList<>(); int timeBin = (int)Math.floor((time + feedforwardSignalLead) / timeBinSize); - Map> rebalancableVehiclesPerZone = RebalancingUtils + Map> rebalancableVehiclesPerZone = RebalancingUtils .groupRebalancableVehicles(zonalSystem, generalParams, rebalancableVehicles, time); - Map> actualRebalancableVehiclesPerZone = new HashMap<>(); + Map> actualRebalancableVehiclesPerZone = new HashMap<>(); // Feedback part if (feedbackSwitch) { - List vehicleSurplusList = new ArrayList<>(); - Map> soonRebalancableVehiclesPerZone = RebalancingUtils + List vehicleSurplusList = new ArrayList<>(); + Map> soonRebalancableVehiclesPerZone = RebalancingUtils .groupSoonIdleVehicles(zonalSystem, generalParams, fleet, time); - for (DrtZone zone : zonalSystem.getZones().values()) { + for (Zone zone : zonalSystem.getZones().values()) { int rebalancable = rebalancableVehiclesPerZone.getOrDefault(zone, List.of()).size(); int soonIdle = soonRebalancableVehiclesPerZone.getOrDefault(zone, List.of()).size(); int surplus = rebalancable + soonIdle - minNumVehiclesPerZone; - vehicleSurplusList.add(new DrtZoneVehicleSurplus(zone, Math.min(surplus, rebalancable))); + vehicleSurplusList.add(new AggregatedMinCostRelocationCalculator.DrtZoneVehicleSurplus(zone, Math.min(surplus, rebalancable))); } relocationList.addAll( @@ -113,7 +108,7 @@ public List calcRelocations(Stream rebalancab // Connection between feedback and feedforward part Set relocatedVehicles = relocationList.stream().map(relocation -> relocation.vehicle) .collect(toSet()); - for (DrtZone zone : rebalancableVehiclesPerZone.keySet()) { + for (Zone zone : rebalancableVehiclesPerZone.keySet()) { actualRebalancableVehiclesPerZone.put(zone, rebalancableVehiclesPerZone.get(zone).stream() .filter(v -> !relocatedVehicles.contains(v)).collect(Collectors.toList())); } @@ -125,9 +120,9 @@ public List calcRelocations(Stream rebalancab // assign rebalance vehicles based on the rebalance plan if (feedforwardSignal.containsKey(timeBin)) { // Generate relocations based on the "rebalancePlanCore" - for (Flow rebalanceInfo : feedforwardSignal.get(timeBin)) { - DrtZone departureZone = rebalanceInfo.origin(); - DrtZone arrivalZone = rebalanceInfo.destination(); + for (Flow rebalanceInfo : feedforwardSignal.get(timeBin)) { + Zone departureZone = rebalanceInfo.origin(); + Zone arrivalZone = rebalanceInfo.destination(); int vehicleToSend = (int) Math.floor(scaling * rebalanceInfo.amount() + rnd.nextDouble()); // Note: we use probability to solve the problem of non-integer value of // vehileToSend after scaling. diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/Feedforward/FeedforwardSignalHandler.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/Feedforward/FeedforwardSignalHandler.java index d670f9be2ec..a8557441636 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/Feedforward/FeedforwardSignalHandler.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/Feedforward/FeedforwardSignalHandler.java @@ -1,16 +1,9 @@ package org.matsim.contrib.drt.optimizer.rebalancing.Feedforward; -import static java.util.stream.Collectors.toList; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.function.ToDoubleFunction; - import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.matsim.contrib.drt.analysis.zonal.DrtZonalSystem; -import org.matsim.contrib.drt.analysis.zonal.DrtZone; +import org.matsim.contrib.common.zones.Zone; +import org.matsim.contrib.common.zones.ZoneSystem; import org.matsim.contrib.drt.optimizer.rebalancing.demandestimator.NetDepartureReplenishDemandEstimator; import org.matsim.contrib.drt.optimizer.rebalancing.mincostflow.AggregatedMinCostRelocationCalculator.DrtZoneVehicleSurplus; import org.matsim.contrib.drt.optimizer.rebalancing.mincostflow.TransportProblem; @@ -18,10 +11,17 @@ import org.matsim.core.controler.events.IterationStartsEvent; import org.matsim.core.controler.listener.IterationStartsListener; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.ToDoubleFunction; + +import static java.util.stream.Collectors.toList; + public class FeedforwardSignalHandler implements IterationStartsListener { private static final Logger log = LogManager.getLogger(FeedforwardSignalHandler.class); - private final DrtZonalSystem zonalSystem; - private final Map>> feedforwardSignal = new HashMap<>(); + private final ZoneSystem zonalSystem; + private final Map>> feedforwardSignal = new HashMap<>(); private final int timeBinSize; private final NetDepartureReplenishDemandEstimator netDepartureReplenishDemandEstimator; @@ -30,7 +30,7 @@ public class FeedforwardSignalHandler implements IterationStartsListener { /** * Constructor */ - public FeedforwardSignalHandler(DrtZonalSystem zonalSystem, + public FeedforwardSignalHandler(ZoneSystem zonalSystem, FeedforwardRebalancingStrategyParams strategySpecificParams, NetDepartureReplenishDemandEstimator netDepartureReplenishDemandEstimator) { this.zonalSystem = zonalSystem; @@ -45,7 +45,7 @@ private void calculateFeedforwardSignal() { int numOfTimeBin = simulationEndTime * 3600 / timeBinSize; log.info("Start calculating rebalnace plan now"); for (int t = 0; t < numOfTimeBin; t++) { - ToDoubleFunction netDepartureInputFunction = netDepartureReplenishDemandEstimator.getExpectedDemandForTimeBin(t); + ToDoubleFunction netDepartureInputFunction = netDepartureReplenishDemandEstimator.getExpectedDemandForTimeBin(t); List vehicleSurpluses = zonalSystem.getZones() .values() .stream() @@ -59,7 +59,7 @@ private void calculateFeedforwardSignal() { log.info("Rebalance plan calculation is now complete! "); } - public Map>> getFeedforwardSignal() { + public Map>> getFeedforwardSignal() { return feedforwardSignal; } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/RebalancingUtils.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/RebalancingUtils.java index da0a741d5e0..8584026e706 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/RebalancingUtils.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/RebalancingUtils.java @@ -26,9 +26,11 @@ import java.util.Map; import java.util.stream.Stream; +import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; -import org.matsim.contrib.drt.analysis.zonal.DrtZonalSystem; -import org.matsim.contrib.drt.analysis.zonal.DrtZone; +import org.matsim.contrib.common.zones.Zone; +import org.matsim.contrib.common.zones.ZoneImpl; +import org.matsim.contrib.common.zones.ZoneSystem; import org.matsim.contrib.dvrp.fleet.DvrpVehicle; import org.matsim.contrib.dvrp.fleet.Fleet; import org.matsim.contrib.dvrp.schedule.Schedule; @@ -40,14 +42,14 @@ * @author Michal Maciejewski (michalm) */ public class RebalancingUtils { - public static Map> groupRebalancableVehicles(DrtZonalSystem zonalSystem, - RebalancingParams params, Stream rebalancableVehicles, double time) { - Map> rebalancableVehiclesPerZone = new HashMap<>(); + public static Map> groupRebalancableVehicles(ZoneSystem zonalSystem, + RebalancingParams params, Stream rebalancableVehicles, double time) { + Map> rebalancableVehiclesPerZone = new HashMap<>(); rebalancableVehicles.filter(v -> v.getServiceEndTime() > time + params.minServiceTime).forEach(v -> { Link link = ((StayTask)v.getSchedule().getCurrentTask()).getLink(); - DrtZone zone = zonalSystem.getZoneForLinkId(link.getId()); + Zone zone = zonalSystem.getZoneForLinkId(link.getId()); if (zone == null) { - zone = DrtZone.createDummyZone("single-vehicle-zone-" + v.getId(), List.of(link), + zone = ZoneImpl.createDummyZone(Id.create("single-vehicle-zone-" + v.getId(), Zone.class), List.of(link), link.getToNode().getCoord()); } rebalancableVehiclesPerZone.computeIfAbsent(zone, z -> new ArrayList<>()).add(v); @@ -56,16 +58,16 @@ public static Map> groupRebalancableVehicles(DrtZonal } // also include vehicles being right now relocated or recharged - public static Map> groupSoonIdleVehicles(DrtZonalSystem zonalSystem, + public static Map> groupSoonIdleVehicles(ZoneSystem zonalSystem, RebalancingParams params, Fleet fleet, double time) { - Map> soonIdleVehiclesPerZone = new HashMap<>(); + Map> soonIdleVehiclesPerZone = new HashMap<>(); for (DvrpVehicle v : fleet.getVehicles().values()) { Schedule s = v.getSchedule(); StayTask stayTask = (StayTask)Schedules.getLastTask(s); if (stayTask.getStatus() == Task.TaskStatus.PLANNED && stayTask.getBeginTime() < time + params.maxTimeBeforeIdle && v.getServiceEndTime() > time + params.minServiceTime) { - DrtZone zone = zonalSystem.getZoneForLinkId(stayTask.getLink().getId()); + Zone zone = zonalSystem.getZoneForLinkId(stayTask.getLink().getId()); if (zone != null) { soonIdleVehiclesPerZone.computeIfAbsent(zone, z -> new ArrayList<>()).add(v); } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/demandestimator/NetDepartureReplenishDemandEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/demandestimator/NetDepartureReplenishDemandEstimator.java index 2529a02b8d3..cc1c0b41dd5 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/demandestimator/NetDepartureReplenishDemandEstimator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/demandestimator/NetDepartureReplenishDemandEstimator.java @@ -1,13 +1,8 @@ package org.matsim.contrib.drt.optimizer.rebalancing.demandestimator; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.function.ToDoubleFunction; - import org.matsim.api.core.v01.Id; -import org.matsim.contrib.drt.analysis.zonal.DrtZonalSystem; -import org.matsim.contrib.drt.analysis.zonal.DrtZone; +import org.matsim.contrib.common.zones.Zone; +import org.matsim.contrib.common.zones.ZoneSystem; import org.matsim.contrib.drt.optimizer.rebalancing.Feedforward.FeedforwardRebalancingStrategyParams; import org.matsim.contrib.drt.passenger.events.DrtRequestSubmittedEvent; import org.matsim.contrib.drt.passenger.events.DrtRequestSubmittedEventHandler; @@ -18,20 +13,25 @@ import org.matsim.contrib.dvrp.passenger.PassengerRequestScheduledEvent; import org.matsim.contrib.dvrp.passenger.PassengerRequestScheduledEventHandler; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.function.ToDoubleFunction; + public class NetDepartureReplenishDemandEstimator implements PassengerRequestScheduledEventHandler, DrtRequestSubmittedEventHandler, PassengerRequestRejectedEventHandler { - private record Trip(int timeBin, DrtZone fromZone, DrtZone toZone) { + private record Trip(int timeBin, Zone fromZone, Zone toZone) { } - private final DrtZonalSystem zonalSystem; + private final ZoneSystem zonalSystem; private final String mode; private final int timeBinSize; - private final Map> currentZoneNetDepartureMap = new HashMap<>(); - private final Map> previousZoneNetDepartureMap = new HashMap<>(); + private final Map> currentZoneNetDepartureMap = new HashMap<>(); + private final Map> previousZoneNetDepartureMap = new HashMap<>(); private final Map, Trip> potentialDrtTripsMap = new HashMap<>(); - public NetDepartureReplenishDemandEstimator(DrtZonalSystem zonalSystem, DrtConfigGroup drtCfg, + public NetDepartureReplenishDemandEstimator(ZoneSystem zonalSystem, DrtConfigGroup drtCfg, FeedforwardRebalancingStrategyParams strategySpecificParams) { this.zonalSystem = zonalSystem; mode = drtCfg.getMode(); @@ -52,8 +52,8 @@ public void handleEvent(DrtRequestSubmittedEvent event) { if (event.getMode().equals(mode)) { // At the submission time, this is only a potential trip. int timeBin = (int)Math.floor(event.getTime() / timeBinSize); - DrtZone departureZoneId = zonalSystem.getZoneForLinkId(event.getFromLinkId()); - DrtZone arrivalZoneId = zonalSystem.getZoneForLinkId(event.getToLinkId()); + Zone departureZoneId = zonalSystem.getZoneForLinkId(event.getFromLinkId()); + Zone arrivalZoneId = zonalSystem.getZoneForLinkId(event.getToLinkId()); potentialDrtTripsMap.put(event.getRequestId(), new Trip(timeBin, departureZoneId, arrivalZoneId)); } } @@ -78,7 +78,7 @@ public void updateForNextIteration() { potentialDrtTripsMap.clear(); } - public ToDoubleFunction getExpectedDemandForTimeBin(int timeBin) { + public ToDoubleFunction getExpectedDemandForTimeBin(int timeBin) { var expectedDemandForTimeBin = previousZoneNetDepartureMap.getOrDefault(timeBin, Collections.emptyMap()); return zone -> expectedDemandForTimeBin.getOrDefault(zone, 0); } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/demandestimator/PreviousIterationDrtDemandEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/demandestimator/PreviousIterationDrtDemandEstimator.java index 003c1649507..f6d2f17745d 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/demandestimator/PreviousIterationDrtDemandEstimator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/demandestimator/PreviousIterationDrtDemandEstimator.java @@ -23,20 +23,19 @@ */ package org.matsim.contrib.drt.optimizer.rebalancing.demandestimator; -import java.util.HashMap; -import java.util.Map; -import java.util.function.ToDoubleFunction; - +import com.google.common.base.Preconditions; import org.apache.commons.lang3.mutable.MutableInt; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.matsim.api.core.v01.events.PersonDepartureEvent; import org.matsim.api.core.v01.events.handler.PersonDepartureEventHandler; -import org.matsim.contrib.drt.analysis.zonal.DrtZonalSystem; -import org.matsim.contrib.drt.analysis.zonal.DrtZone; +import org.matsim.contrib.common.zones.Zone; +import org.matsim.contrib.common.zones.ZoneSystem; import org.matsim.contrib.drt.run.DrtConfigGroup; -import com.google.common.base.Preconditions; +import java.util.HashMap; +import java.util.Map; +import java.util.function.ToDoubleFunction; /** * Aggregates PersonDepartureEvents per iteration for the given mode and returns the numbers from the previous iteration @@ -48,13 +47,13 @@ public final class PreviousIterationDrtDemandEstimator implements ZonalDemandEstimator, PersonDepartureEventHandler { private static final Logger logger = LogManager.getLogger(PreviousIterationDrtDemandEstimator.class); - private final DrtZonalSystem zonalSystem; + private final ZoneSystem zonalSystem; private final String mode; private final int timeBinSize; - private Map> currentIterationDepartures = new HashMap<>(); - private Map> previousIterationDepartures = new HashMap<>(); + private Map> currentIterationDepartures = new HashMap<>(); + private Map> previousIterationDepartures = new HashMap<>(); - public PreviousIterationDrtDemandEstimator(DrtZonalSystem zonalSystem, DrtConfigGroup drtCfg, + public PreviousIterationDrtDemandEstimator(ZoneSystem zonalSystem, DrtConfigGroup drtCfg, int demandEstimationPeriod) { this.zonalSystem = zonalSystem; mode = drtCfg.getMode(); @@ -70,7 +69,7 @@ public void reset(int iteration) { @Override public void handleEvent(PersonDepartureEvent event) { if (event.getLegMode().equals(mode)) { - DrtZone zone = zonalSystem.getZoneForLinkId(event.getLinkId()); + Zone zone = zonalSystem.getZoneForLinkId(event.getLinkId()); if (zone == null) { //might be that somebody walks into the service area or that service area is larger/different than DrtZonalSystem... logger.warn("No zone found for linkId " + event.getLinkId().toString()); @@ -87,10 +86,10 @@ public void handleEvent(PersonDepartureEvent event) { private static final MutableInt ZERO = new MutableInt(0); @Override - public ToDoubleFunction getExpectedDemand(double fromTime, double estimationPeriod) { + public ToDoubleFunction getExpectedDemand(double fromTime, double estimationPeriod) { Preconditions.checkArgument(estimationPeriod == timeBinSize);//TODO add more flexibility later int timeBin = getBinForTime(fromTime); - Map expectedDemandForTimeBin = previousIterationDepartures.getOrDefault(timeBin, Map.of()); + Map expectedDemandForTimeBin = previousIterationDepartures.getOrDefault(timeBin, Map.of()); return zone -> expectedDemandForTimeBin.getOrDefault(zone, ZERO).intValue(); } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/demandestimator/ZonalDemandEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/demandestimator/ZonalDemandEstimator.java index 42d75e30f6e..9faee8637bd 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/demandestimator/ZonalDemandEstimator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/demandestimator/ZonalDemandEstimator.java @@ -23,14 +23,14 @@ */ package org.matsim.contrib.drt.optimizer.rebalancing.demandestimator; -import java.util.function.ToDoubleFunction; +import org.matsim.contrib.common.zones.Zone; -import org.matsim.contrib.drt.analysis.zonal.DrtZone; +import java.util.function.ToDoubleFunction; /** * @author jbischoff * @author Michal Maciejewski (michalm) */ public interface ZonalDemandEstimator { - ToDoubleFunction getExpectedDemand(double fromTime, double estimationPeriod); + ToDoubleFunction getExpectedDemand(double fromTime, double estimationPeriod); } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/mincostflow/AggregatedMinCostRelocationCalculator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/mincostflow/AggregatedMinCostRelocationCalculator.java index 4a16cb05b5d..14130e4d152 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/mincostflow/AggregatedMinCostRelocationCalculator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/mincostflow/AggregatedMinCostRelocationCalculator.java @@ -25,7 +25,7 @@ import org.matsim.api.core.v01.Coord; import org.matsim.api.core.v01.network.Link; -import org.matsim.contrib.drt.analysis.zonal.DrtZone; +import org.matsim.contrib.common.zones.Zone; import org.matsim.contrib.drt.analysis.zonal.DrtZoneTargetLinkSelector; import org.matsim.contrib.drt.optimizer.rebalancing.RebalancingStrategy.Relocation; import org.matsim.contrib.dvrp.fleet.DvrpVehicle; @@ -39,10 +39,10 @@ */ public class AggregatedMinCostRelocationCalculator implements ZonalRelocationCalculator { public static class DrtZoneVehicleSurplus { - public final DrtZone zone; + public final Zone zone; public final int surplus; - public DrtZoneVehicleSurplus(DrtZone zone, int surplus) { + public DrtZoneVehicleSurplus(Zone zone, int surplus) { this.zone = zone; this.surplus = surplus; } @@ -56,14 +56,14 @@ public AggregatedMinCostRelocationCalculator(DrtZoneTargetLinkSelector targetLin @Override public List calcRelocations(List vehicleSurplus, - Map> rebalancableVehiclesPerZone) { + Map> rebalancableVehiclesPerZone) { return calcRelocations(rebalancableVehiclesPerZone, TransportProblem.solveForVehicleSurplus(vehicleSurplus)); } - private List calcRelocations(Map> rebalancableVehiclesPerZone, - List> flows) { + private List calcRelocations(Map> rebalancableVehiclesPerZone, + List> flows) { List relocations = new ArrayList<>(); - for (TransportProblem.Flow flow : flows) { + for (TransportProblem.Flow flow : flows) { List rebalancableVehicles = rebalancableVehiclesPerZone.get(flow.origin()); Link targetLink = targetLinkSelector.selectTargetLink(flow.destination()); diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/mincostflow/DrtModeMinCostFlowRebalancingModule.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/mincostflow/DrtModeMinCostFlowRebalancingModule.java index d624e6a000a..eeef009b3da 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/mincostflow/DrtModeMinCostFlowRebalancingModule.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/mincostflow/DrtModeMinCostFlowRebalancingModule.java @@ -21,17 +21,13 @@ package org.matsim.contrib.drt.optimizer.rebalancing.mincostflow; import org.matsim.api.core.v01.population.Population; -import org.matsim.contrib.drt.analysis.zonal.DrtZonalSystem; +import org.matsim.contrib.common.zones.ZoneSystem; import org.matsim.contrib.drt.analysis.zonal.DrtZoneTargetLinkSelector; import org.matsim.contrib.drt.optimizer.rebalancing.RebalancingParams; import org.matsim.contrib.drt.optimizer.rebalancing.RebalancingStrategy; import org.matsim.contrib.drt.optimizer.rebalancing.demandestimator.PreviousIterationDrtDemandEstimator; import org.matsim.contrib.drt.optimizer.rebalancing.demandestimator.ZonalDemandEstimator; -import org.matsim.contrib.drt.optimizer.rebalancing.targetcalculator.DemandEstimatorAsTargetCalculator; -import org.matsim.contrib.drt.optimizer.rebalancing.targetcalculator.EqualRebalancableVehicleDistributionTargetCalculator; -import org.matsim.contrib.drt.optimizer.rebalancing.targetcalculator.EqualVehicleDensityTargetCalculator; -import org.matsim.contrib.drt.optimizer.rebalancing.targetcalculator.EqualVehiclesToPopulationRatioTargetCalculator; -import org.matsim.contrib.drt.optimizer.rebalancing.targetcalculator.RebalancingTargetCalculator; +import org.matsim.contrib.drt.optimizer.rebalancing.targetcalculator.*; import org.matsim.contrib.drt.run.DrtConfigGroup; import org.matsim.contrib.dvrp.fleet.Fleet; import org.matsim.contrib.dvrp.fleet.FleetSpecification; @@ -59,7 +55,7 @@ public void install() { protected void configureQSim() { bindModal(RebalancingStrategy.class).toProvider(modalProvider( getter -> new MinCostFlowRebalancingStrategy(getter.getModal(RebalancingTargetCalculator.class), - getter.getModal(DrtZonalSystem.class), getter.getModal(Fleet.class), + getter.getModal(ZoneSystem.class), getter.getModal(Fleet.class), getter.getModal(ZonalRelocationCalculator.class), params))).asEagerSingleton(); switch (strategyParams.rebalancingTargetCalculatorType) { @@ -71,19 +67,19 @@ protected void configureQSim() { case EqualRebalancableVehicleDistribution: bindModal(RebalancingTargetCalculator.class).toProvider(modalProvider(getter -> new EqualRebalancableVehicleDistributionTargetCalculator( getter.getModal(ZonalDemandEstimator.class), - getter.getModal(DrtZonalSystem.class), strategyParams.demandEstimationPeriod))).asEagerSingleton(); + getter.getModal(ZoneSystem.class), strategyParams.demandEstimationPeriod))).asEagerSingleton(); break; case EqualVehicleDensity: bindModal(RebalancingTargetCalculator.class).toProvider(modalProvider( - getter -> new EqualVehicleDensityTargetCalculator(getter.getModal(DrtZonalSystem.class), + getter -> new EqualVehicleDensityTargetCalculator(getter.getModal(ZoneSystem.class), getter.getModal(FleetSpecification.class)))).asEagerSingleton(); break; case EqualVehiclesToPopulationRatio: bindModal(RebalancingTargetCalculator.class).toProvider(modalProvider( getter -> new EqualVehiclesToPopulationRatioTargetCalculator( - getter.getModal(DrtZonalSystem.class), getter.get(Population.class), + getter.getModal(ZoneSystem.class), getter.get(Population.class), getter.getModal(FleetSpecification.class)))).asEagerSingleton(); break; @@ -101,7 +97,7 @@ protected void configureQSim() { switch (strategyParams.zonalDemandEstimatorType) { case PreviousIterationDemand: bindModal(PreviousIterationDrtDemandEstimator.class).toProvider(modalProvider( - getter -> new PreviousIterationDrtDemandEstimator(getter.getModal(DrtZonalSystem.class), drtCfg, + getter -> new PreviousIterationDrtDemandEstimator(getter.getModal(ZoneSystem.class), drtCfg, strategyParams.demandEstimationPeriod))).asEagerSingleton(); bindModal(ZonalDemandEstimator.class).to(modalKey(PreviousIterationDrtDemandEstimator.class)); addEventHandlerBinding().to(modalKey(PreviousIterationDrtDemandEstimator.class)); diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/mincostflow/MinCostFlowRebalancingStrategy.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/mincostflow/MinCostFlowRebalancingStrategy.java index b08dcb56e01..4e06666ed05 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/mincostflow/MinCostFlowRebalancingStrategy.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/mincostflow/MinCostFlowRebalancingStrategy.java @@ -25,8 +25,8 @@ import java.util.function.ToDoubleFunction; import java.util.stream.Stream; -import org.matsim.contrib.drt.analysis.zonal.DrtZonalSystem; -import org.matsim.contrib.drt.analysis.zonal.DrtZone; +import org.matsim.contrib.common.zones.Zone; +import org.matsim.contrib.common.zones.ZoneSystem; import org.matsim.contrib.drt.optimizer.rebalancing.RebalancingParams; import org.matsim.contrib.drt.optimizer.rebalancing.RebalancingStrategy; import org.matsim.contrib.drt.optimizer.rebalancing.RebalancingUtils; @@ -41,13 +41,13 @@ public class MinCostFlowRebalancingStrategy implements RebalancingStrategy { private final RebalancingTargetCalculator rebalancingTargetCalculator; - private final DrtZonalSystem zonalSystem; + private final ZoneSystem zonalSystem; private final Fleet fleet; private final ZonalRelocationCalculator relocationCalculator; private final RebalancingParams params; public MinCostFlowRebalancingStrategy(RebalancingTargetCalculator rebalancingTargetCalculator, - DrtZonalSystem zonalSystem, Fleet fleet, ZonalRelocationCalculator relocationCalculator, + ZoneSystem zonalSystem, Fleet fleet, ZonalRelocationCalculator relocationCalculator, RebalancingParams params) { this.rebalancingTargetCalculator = rebalancingTargetCalculator; this.zonalSystem = zonalSystem; @@ -58,20 +58,20 @@ public MinCostFlowRebalancingStrategy(RebalancingTargetCalculator rebalancingTar @Override public List calcRelocations(Stream rebalancableVehicles, double time) { - Map> rebalancableVehiclesPerZone = RebalancingUtils.groupRebalancableVehicles( + Map> rebalancableVehiclesPerZone = RebalancingUtils.groupRebalancableVehicles( zonalSystem, params, rebalancableVehicles, time); if (rebalancableVehiclesPerZone.isEmpty()) { return List.of(); } - Map> soonIdleVehiclesPerZone = RebalancingUtils.groupSoonIdleVehicles(zonalSystem, + Map> soonIdleVehiclesPerZone = RebalancingUtils.groupSoonIdleVehicles(zonalSystem, params, fleet, time); return calculateMinCostRelocations(time, rebalancableVehiclesPerZone, soonIdleVehiclesPerZone); } private List calculateMinCostRelocations(double time, - Map> rebalancableVehiclesPerZone, - Map> soonIdleVehiclesPerZone) { - ToDoubleFunction targetFunction = rebalancingTargetCalculator.calculate(time, + Map> rebalancableVehiclesPerZone, + Map> soonIdleVehiclesPerZone) { + ToDoubleFunction targetFunction = rebalancingTargetCalculator.calculate(time, rebalancableVehiclesPerZone); var minCostFlowRebalancingStrategyParams = (MinCostFlowRebalancingStrategyParams)params.getRebalancingStrategyParams(); double alpha = minCostFlowRebalancingStrategyParams.targetAlpha; diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/mincostflow/TransportProblem.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/mincostflow/TransportProblem.java index b48f0f2e635..ca019b03ea2 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/mincostflow/TransportProblem.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/mincostflow/TransportProblem.java @@ -26,19 +26,19 @@ import org.apache.commons.lang3.tuple.Pair; import org.matsim.contrib.common.util.DistanceUtils; -import org.matsim.contrib.drt.analysis.zonal.DrtZone; import graphs.flows.MinCostFlow; import graphs.flows.MinCostFlow.Edge; +import org.matsim.contrib.common.zones.Zone; /** * @author michalm */ public class TransportProblem { - public static List> solveForVehicleSurplus( + public static List> solveForVehicleSurplus( List vehicleSurplus) { - List> supply = new ArrayList<>(); - List> demand = new ArrayList<>(); + List> supply = new ArrayList<>(); + List> demand = new ArrayList<>(); for (AggregatedMinCostRelocationCalculator.DrtZoneVehicleSurplus s : vehicleSurplus) { if (s.surplus > 0) { supply.add(Pair.of(s.zone, s.surplus)); @@ -46,10 +46,10 @@ public static List> solveForVehicleSurplus( demand.add(Pair.of(s.zone, -s.surplus)); } } - return new TransportProblem(TransportProblem::calcStraightLineDistance).solve(supply, demand); + return new TransportProblem(TransportProblem::calcStraightLineDistance).solve(supply, demand); } - private static int calcStraightLineDistance(DrtZone zone1, DrtZone zone2) { + private static int calcStraightLineDistance(Zone zone1, Zone zone2) { return (int)DistanceUtils.calculateDistance(zone1.getCentroid(), zone2.getCentroid()); } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/mincostflow/ZonalRelocationCalculator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/mincostflow/ZonalRelocationCalculator.java index 8ccfd234b23..a01e6afbfae 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/mincostflow/ZonalRelocationCalculator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/mincostflow/ZonalRelocationCalculator.java @@ -18,14 +18,14 @@ package org.matsim.contrib.drt.optimizer.rebalancing.mincostflow; -import java.util.List; -import java.util.Map; - -import org.matsim.contrib.drt.analysis.zonal.DrtZone; +import org.matsim.contrib.common.zones.Zone; import org.matsim.contrib.drt.optimizer.rebalancing.RebalancingStrategy.Relocation; import org.matsim.contrib.drt.optimizer.rebalancing.mincostflow.AggregatedMinCostRelocationCalculator.DrtZoneVehicleSurplus; import org.matsim.contrib.dvrp.fleet.DvrpVehicle; +import java.util.List; +import java.util.Map; + /** * @author michalm */ @@ -36,5 +36,5 @@ public interface ZonalRelocationCalculator { * @return vehicle relocations */ List calcRelocations(List vehicleSurplus, - Map> rebalancableVehiclesPerZone); + Map> rebalancableVehiclesPerZone); } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/targetcalculator/DemandEstimatorAsTargetCalculator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/targetcalculator/DemandEstimatorAsTargetCalculator.java index 611299b55bf..1ce22dd43e7 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/targetcalculator/DemandEstimatorAsTargetCalculator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/targetcalculator/DemandEstimatorAsTargetCalculator.java @@ -20,14 +20,14 @@ package org.matsim.contrib.drt.optimizer.rebalancing.targetcalculator; +import org.matsim.contrib.common.zones.Zone; +import org.matsim.contrib.drt.optimizer.rebalancing.demandestimator.ZonalDemandEstimator; +import org.matsim.contrib.dvrp.fleet.DvrpVehicle; + import java.util.List; import java.util.Map; import java.util.function.ToDoubleFunction; -import org.matsim.contrib.drt.analysis.zonal.DrtZone; -import org.matsim.contrib.drt.optimizer.rebalancing.demandestimator.ZonalDemandEstimator; -import org.matsim.contrib.dvrp.fleet.DvrpVehicle; - /** * @author michalm */ @@ -41,8 +41,8 @@ public DemandEstimatorAsTargetCalculator(ZonalDemandEstimator demandEstimator, d } @Override - public ToDoubleFunction calculate(double time, - Map> rebalancableVehiclesPerZone) { + public ToDoubleFunction calculate(double time, + Map> rebalancableVehiclesPerZone) { return demandEstimator.getExpectedDemand(time, demandEstimationPeriod); } } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/targetcalculator/EqualRebalancableVehicleDistributionTargetCalculator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/targetcalculator/EqualRebalancableVehicleDistributionTargetCalculator.java index c3975986dce..e03314a8d07 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/targetcalculator/EqualRebalancableVehicleDistributionTargetCalculator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/targetcalculator/EqualRebalancableVehicleDistributionTargetCalculator.java @@ -20,19 +20,19 @@ package org.matsim.contrib.drt.optimizer.rebalancing.targetcalculator; -import static java.util.stream.Collectors.toSet; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.matsim.contrib.common.zones.Zone; +import org.matsim.contrib.common.zones.ZoneSystem; +import org.matsim.contrib.drt.optimizer.rebalancing.demandestimator.ZonalDemandEstimator; +import org.matsim.contrib.dvrp.fleet.DvrpVehicle; import java.util.List; import java.util.Map; import java.util.Set; import java.util.function.ToDoubleFunction; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.matsim.contrib.drt.analysis.zonal.DrtZonalSystem; -import org.matsim.contrib.drt.analysis.zonal.DrtZone; -import org.matsim.contrib.drt.optimizer.rebalancing.demandestimator.ZonalDemandEstimator; -import org.matsim.contrib.dvrp.fleet.DvrpVehicle; +import static java.util.stream.Collectors.toSet; /** * TODO add some description @@ -43,24 +43,24 @@ public class EqualRebalancableVehicleDistributionTargetCalculator implements Reb private static final Logger log = LogManager.getLogger(EqualRebalancableVehicleDistributionTargetCalculator.class); private final ZonalDemandEstimator demandEstimator; - private final DrtZonalSystem zonalSystem; + private final ZoneSystem zonalSystem; private final double demandEstimationPeriod; public EqualRebalancableVehicleDistributionTargetCalculator(ZonalDemandEstimator demandEstimator, - DrtZonalSystem zonalSystem, double demandEstimationPeriod) { + ZoneSystem zonalSystem, double demandEstimationPeriod) { this.demandEstimator = demandEstimator; this.zonalSystem = zonalSystem; this.demandEstimationPeriod = demandEstimationPeriod; } @Override - public ToDoubleFunction calculate(double time, - Map> rebalancableVehiclesPerZone) { + public ToDoubleFunction calculate(double time, + Map> rebalancableVehiclesPerZone) { int numAvailableVehicles = rebalancableVehiclesPerZone.values().stream().mapToInt(List::size).sum(); - ToDoubleFunction currentDemandEstimator = demandEstimator.getExpectedDemand(time, + ToDoubleFunction currentDemandEstimator = demandEstimator.getExpectedDemand(time, demandEstimationPeriod); - Set activeZones = zonalSystem.getZones() + Set activeZones = zonalSystem.getZones() .values() .stream() .filter(zone -> currentDemandEstimator.applyAsDouble(zone) > 0) diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/targetcalculator/EqualVehicleDensityTargetCalculator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/targetcalculator/EqualVehicleDensityTargetCalculator.java index 03b6b8879f4..64a0e6bd0bc 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/targetcalculator/EqualVehicleDensityTargetCalculator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/targetcalculator/EqualVehicleDensityTargetCalculator.java @@ -23,19 +23,18 @@ */ package org.matsim.contrib.drt.optimizer.rebalancing.targetcalculator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.function.ToDoubleFunction; - +import com.google.common.base.Preconditions; import jakarta.validation.constraints.NotNull; - -import org.matsim.contrib.drt.analysis.zonal.DrtZonalSystem; -import org.matsim.contrib.drt.analysis.zonal.DrtZone; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.IdMap; +import org.matsim.contrib.common.zones.Zone; +import org.matsim.contrib.common.zones.ZoneSystem; import org.matsim.contrib.dvrp.fleet.DvrpVehicle; import org.matsim.contrib.dvrp.fleet.FleetSpecification; -import com.google.common.base.Preconditions; +import java.util.List; +import java.util.Map; +import java.util.function.ToDoubleFunction; /** * This class does not really calculate the expected demand but aims to @@ -46,32 +45,32 @@ */ public final class EqualVehicleDensityTargetCalculator implements RebalancingTargetCalculator { - private final Map zoneAreaShares = new HashMap<>(); + private final Map, Double> zoneAreaShares = new IdMap<>(Zone.class); private final FleetSpecification fleetSpecification; - public EqualVehicleDensityTargetCalculator(@NotNull DrtZonalSystem zonalSystem, + public EqualVehicleDensityTargetCalculator(@NotNull ZoneSystem zonalSystem, @NotNull FleetSpecification fleetSpecification) { initAreaShareMap(zonalSystem); this.fleetSpecification = fleetSpecification; } @Override - public ToDoubleFunction calculate(double time, - Map> rebalancableVehiclesPerZone) { - return zone -> zoneAreaShares.getOrDefault(zone, 0.) * fleetSpecification.getVehicleSpecifications().size(); + public ToDoubleFunction calculate(double time, + Map> rebalancableVehiclesPerZone) { + return zone -> zoneAreaShares.getOrDefault(zone.getId(), 0.) * fleetSpecification.getVehicleSpecifications().size(); } - private void initAreaShareMap(DrtZonalSystem zonalSystem) { + private void initAreaShareMap(ZoneSystem zonalSystem) { double areaSum = zonalSystem.getZones() .values() .stream() .mapToDouble(z -> z.getPreparedGeometry().getGeometry().getArea()) .sum(); - for (DrtZone zone : zonalSystem.getZones().values()) { + for (Zone zone : zonalSystem.getZones().values()) { double areaShare = zone.getPreparedGeometry().getGeometry().getArea() / areaSum; Preconditions.checkState(areaShare >= 0. && areaShare <= 1.); - zoneAreaShares.put(zone, areaShare); + zoneAreaShares.put(zone.getId(), areaShare); } } } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/targetcalculator/EqualVehiclesToPopulationRatioTargetCalculator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/targetcalculator/EqualVehiclesToPopulationRatioTargetCalculator.java index 51c23a64db5..7968af6e705 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/targetcalculator/EqualVehiclesToPopulationRatioTargetCalculator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/targetcalculator/EqualVehiclesToPopulationRatioTargetCalculator.java @@ -23,26 +23,25 @@ */ package org.matsim.contrib.drt.optimizer.rebalancing.targetcalculator; -import static java.util.stream.Collectors.collectingAndThen; -import static java.util.stream.Collectors.counting; - -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.function.ToDoubleFunction; -import java.util.stream.Collectors; - import jakarta.validation.constraints.NotNull; - import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.matsim.api.core.v01.population.Activity; import org.matsim.api.core.v01.population.Population; -import org.matsim.contrib.drt.analysis.zonal.DrtZonalSystem; -import org.matsim.contrib.drt.analysis.zonal.DrtZone; +import org.matsim.contrib.common.zones.Zone; +import org.matsim.contrib.common.zones.ZoneSystem; import org.matsim.contrib.dvrp.fleet.DvrpVehicle; import org.matsim.contrib.dvrp.fleet.FleetSpecification; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.ToDoubleFunction; +import java.util.stream.Collectors; + +import static java.util.stream.Collectors.collectingAndThen; +import static java.util.stream.Collectors.counting; + /** * Calculates population size per zone by counting first activites per zone in the selected plans. * Returns the share of population of the total population inside the drt service area for the given zone multiplied with the overall fleet size. @@ -55,11 +54,11 @@ public final class EqualVehiclesToPopulationRatioTargetCalculator implements Reb private static final Logger log = LogManager.getLogger(EqualVehiclesToPopulationRatioTargetCalculator.class); private final int fleetSize; - private final Map activitiesPerZone; + private final Map activitiesPerZone; private final int totalNrActivities; - public EqualVehiclesToPopulationRatioTargetCalculator(DrtZonalSystem zonalSystem, Population population, - @NotNull FleetSpecification fleetSpecification) { + public EqualVehiclesToPopulationRatioTargetCalculator(ZoneSystem zonalSystem, Population population, + @NotNull FleetSpecification fleetSpecification) { log.debug("nr of zones: " + zonalSystem.getZones().size() + "\t nr of persons = " + population.getPersons() .size()); fleetSize = fleetSpecification.getVehicleSpecifications().size(); @@ -68,7 +67,7 @@ public EqualVehiclesToPopulationRatioTargetCalculator(DrtZonalSystem zonalSystem log.debug("nr of persons that have their first activity inside the service area = " + this.totalNrActivities); } - private Map countFirstActsPerZone(DrtZonalSystem zonalSystem, Population population) { + private Map countFirstActsPerZone(ZoneSystem zonalSystem, Population population) { return population.getPersons() .values() .stream() @@ -79,8 +78,8 @@ private Map countFirstActsPerZone(DrtZonalSystem zonalSystem, } @Override - public ToDoubleFunction calculate(double time, - Map> rebalancableVehiclesPerZone) { + public ToDoubleFunction calculate(double time, + Map> rebalancableVehiclesPerZone) { if (totalNrActivities == 0) { return zoneId -> 0; } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/targetcalculator/RebalancingTargetCalculator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/targetcalculator/RebalancingTargetCalculator.java index e7b2e36d1c4..c89ac8677e6 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/targetcalculator/RebalancingTargetCalculator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/targetcalculator/RebalancingTargetCalculator.java @@ -20,16 +20,16 @@ package org.matsim.contrib.drt.optimizer.rebalancing.targetcalculator; +import org.matsim.contrib.common.zones.Zone; +import org.matsim.contrib.dvrp.fleet.DvrpVehicle; + import java.util.List; import java.util.Map; import java.util.function.ToDoubleFunction; -import org.matsim.contrib.drt.analysis.zonal.DrtZone; -import org.matsim.contrib.dvrp.fleet.DvrpVehicle; - /** * @author Michal Maciejewski (michalm) */ public interface RebalancingTargetCalculator { - ToDoubleFunction calculate(double time, Map> rebalancableVehiclesPerZone); + ToDoubleFunction calculate(double time, Map> rebalancableVehiclesPerZone); } diff --git a/contribs/drt/src/test/java/org/matsim/contrib/drt/analysis/zonal/DrtZonalSystemTest.java b/contribs/drt/src/test/java/org/matsim/contrib/drt/analysis/zonal/DrtZonalSystemTest.java index 9baafffb23f..10f50c6d9df 100644 --- a/contribs/drt/src/test/java/org/matsim/contrib/drt/analysis/zonal/DrtZonalSystemTest.java +++ b/contribs/drt/src/test/java/org/matsim/contrib/drt/analysis/zonal/DrtZonalSystemTest.java @@ -20,11 +20,7 @@ package org.matsim.contrib.drt.analysis.zonal; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.matsim.contrib.drt.analysis.zonal.DrtGridUtilsTest.createNetwork; -import static org.matsim.contrib.drt.analysis.zonal.DrtZonalSystem.createFromPreparedGeometries; - +import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.GeometryFactory; @@ -33,11 +29,16 @@ import org.locationtech.jts.geom.prep.PreparedGeometryFactory; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; +import org.matsim.contrib.common.zones.ZoneSystem; import java.util.ArrayList; import java.util.List; import java.util.Map; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.matsim.contrib.common.zones.ZoneSystemUtils.createFromPreparedGeometries; +import static org.matsim.contrib.drt.analysis.zonal.DrtGridUtilsTest.createNetwork; + /** * @author Michal Maciejewski (michalm) */ @@ -45,16 +46,16 @@ public class DrtZonalSystemTest { @Test void test_cellSize100() { - DrtZonalSystem drtZonalSystem = createFromPreparedGeometries(createNetwork(), + ZoneSystem drtZonalSystem = createFromPreparedGeometries(createNetwork(), DrtGridUtils.createGridFromNetwork(createNetwork(), 100)); - assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId("ab")).getId()).isEqualTo("10"); + Assertions.assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId("ab")).getId().toString()).isEqualTo("10"); } @Test void test_cellSize700() { - DrtZonalSystem drtZonalSystem = createFromPreparedGeometries(createNetwork(), + ZoneSystem drtZonalSystem = createFromPreparedGeometries(createNetwork(), DrtGridUtils.createGridFromNetwork(createNetwork(), 700)); - assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId("ab")).getId()).isEqualTo("2"); + Assertions.assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId("ab")).getId().toString()).isEqualTo("2"); } @Test @@ -63,14 +64,14 @@ void test_gridWithinServiceArea(){ Coordinate max = new Coordinate(1500, 1500); List serviceArea = createServiceArea(min,max); Map grid = DrtGridUtils.filterGridWithinServiceArea(DrtGridUtils.createGridFromNetwork(createNetwork(), 100), serviceArea); - DrtZonalSystem zonalSystem = createFromPreparedGeometries(createNetwork(), + ZoneSystem zonalSystem = createFromPreparedGeometries(createNetwork(), grid); assertEquals(2, zonalSystem.getZones().size()); //link 'da' is outside of the service area Id id = Id.createLinkId("da"); - assertThat(zonalSystem.getZoneForLinkId(id) == null).isTrue(); + Assertions.assertThat(zonalSystem.getZoneForLinkId(id) == null).isTrue(); } @Test @@ -79,7 +80,7 @@ void test_noZonesWithoutLinks(){ Coordinate max = new Coordinate(2500, 2500); List serviceArea = createServiceArea(min,max); Map grid = DrtGridUtils.filterGridWithinServiceArea(DrtGridUtils.createGridFromNetwork(createNetwork(), 100), serviceArea); - DrtZonalSystem zonalSystem = createFromPreparedGeometries(createNetwork(), + ZoneSystem zonalSystem = createFromPreparedGeometries(createNetwork(), grid); //service area is off the network - so we should have 0 zones.. diff --git a/contribs/drt/src/test/java/org/matsim/contrib/drt/analysis/zonal/RandomDrtZoneTargetLinkSelectorTest.java b/contribs/drt/src/test/java/org/matsim/contrib/drt/analysis/zonal/RandomDrtZoneTargetLinkSelectorTest.java index fa38b72749b..f77e5fa57a3 100644 --- a/contribs/drt/src/test/java/org/matsim/contrib/drt/analysis/zonal/RandomDrtZoneTargetLinkSelectorTest.java +++ b/contribs/drt/src/test/java/org/matsim/contrib/drt/analysis/zonal/RandomDrtZoneTargetLinkSelectorTest.java @@ -30,6 +30,8 @@ import org.junit.jupiter.api.Test; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; +import org.matsim.contrib.common.zones.Zone; +import org.matsim.contrib.common.zones.ZoneImpl; import org.matsim.testcases.fakes.FakeLink; import org.mockito.ArgumentCaptor; @@ -45,7 +47,7 @@ public class RandomDrtZoneTargetLinkSelectorTest { @Test void testSelectTargetLink_fourLinks() { - DrtZone zone = DrtZone.createDummyZone("zone", List.of(link0, link1, link2, link3), null); + Zone zone = ZoneImpl.createDummyZone(Id.create("zone", Zone.class), List.of(link0, link1, link2, link3), null); //fake random sequence IntUnaryOperator random = mock(IntUnaryOperator.class); diff --git a/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/rebalancing/demandestimator/PreviousIterationDrtDemandEstimatorTest.java b/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/rebalancing/demandestimator/PreviousIterationDrtDemandEstimatorTest.java index 954959480ba..0b93d725f48 100644 --- a/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/rebalancing/demandestimator/PreviousIterationDrtDemandEstimatorTest.java +++ b/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/rebalancing/demandestimator/PreviousIterationDrtDemandEstimatorTest.java @@ -30,8 +30,10 @@ import org.matsim.api.core.v01.TransportMode; import org.matsim.api.core.v01.events.PersonDepartureEvent; import org.matsim.api.core.v01.network.Link; -import org.matsim.contrib.drt.analysis.zonal.DrtZonalSystem; -import org.matsim.contrib.drt.analysis.zonal.DrtZone; +import org.matsim.contrib.common.zones.Zone; +import org.matsim.contrib.common.zones.ZoneImpl; +import org.matsim.contrib.common.zones.ZoneSystem; +import org.matsim.contrib.common.zones.ZoneSystemImpl; import org.matsim.contrib.drt.optimizer.rebalancing.RebalancingParams; import org.matsim.contrib.drt.run.DrtConfigGroup; import org.matsim.testcases.fakes.FakeLink; @@ -46,9 +48,9 @@ public class PreviousIterationDrtDemandEstimatorTest { private final Link link1 = new FakeLink(Id.createLinkId("link_1")); private final Link link2 = new FakeLink(Id.createLinkId("link_2")); - private final DrtZone zone1 = DrtZone.createDummyZone("zone_1", List.of(link1), new Coord()); - private final DrtZone zone2 = DrtZone.createDummyZone("zone_2", List.of(link2), new Coord()); - private final DrtZonalSystem zonalSystem = new DrtZonalSystem(List.of(zone1, zone2)); + private final Zone zone1 = ZoneImpl.createDummyZone(Id.create("zone_1", Zone.class), List.of(link1), new Coord()); + private final Zone zone2 = ZoneImpl.createDummyZone(Id.create("zone_2", Zone.class), List.of(link2), new Coord()); + private final ZoneSystem zonalSystem = new ZoneSystemImpl(List.of(zone1, zone2)); @Test void noDepartures() { @@ -170,7 +172,7 @@ private PersonDepartureEvent departureEvent(double time, Link link, String mode) return new PersonDepartureEvent(time, null, link.getId(), mode, mode); } - private void assertDemand(PreviousIterationDrtDemandEstimator estimator, double fromTime, DrtZone zone, + private void assertDemand(PreviousIterationDrtDemandEstimator estimator, double fromTime, Zone zone, double expectedDemand) { assertThat(estimator.getExpectedDemand(fromTime, ESTIMATION_PERIOD).applyAsDouble(zone)).isEqualTo( expectedDemand); diff --git a/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/rebalancing/targetcalculator/EqualVehicleDensityTargetCalculatorTest.java b/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/rebalancing/targetcalculator/EqualVehicleDensityTargetCalculatorTest.java index 4f51cb334a5..e1ef42a98d1 100644 --- a/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/rebalancing/targetcalculator/EqualVehicleDensityTargetCalculatorTest.java +++ b/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/rebalancing/targetcalculator/EqualVehicleDensityTargetCalculatorTest.java @@ -20,17 +20,14 @@ package org.matsim.contrib.drt.optimizer.rebalancing.targetcalculator; -import static org.assertj.core.api.Assertions.assertThat; - -import java.util.Map; -import java.util.function.ToDoubleFunction; - +import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Network; +import org.matsim.contrib.common.zones.Zone; +import org.matsim.contrib.common.zones.ZoneSystem; +import org.matsim.contrib.common.zones.ZoneSystemUtils; import org.matsim.contrib.drt.analysis.zonal.DrtGridUtils; -import org.matsim.contrib.drt.analysis.zonal.DrtZonalSystem; -import org.matsim.contrib.drt.analysis.zonal.DrtZone; import org.matsim.contrib.drt.run.MultiModeDrtConfigGroup; import org.matsim.contrib.dvrp.fleet.DvrpVehicle; import org.matsim.contrib.dvrp.fleet.FleetSpecification; @@ -42,6 +39,11 @@ import org.matsim.core.utils.io.IOUtils; import org.matsim.examples.ExamplesUtils; +import java.util.Map; +import java.util.function.ToDoubleFunction; + +import static org.assertj.core.api.Assertions.assertThat; + /** * @author Michal Maciejewski (michalm) */ @@ -53,7 +55,7 @@ public class EqualVehicleDensityTargetCalculatorTest { private final Network network = NetworkUtils.readNetwork( config.network().getInputFileURL(config.getContext()).toString()); - private final DrtZonalSystem zonalSystem = DrtZonalSystem.createFromPreparedGeometries(network, + private final ZoneSystem zonalSystem = ZoneSystemUtils.createFromPreparedGeometries(network, DrtGridUtils.createGridFromNetwork(network, 500.)); @Test @@ -91,8 +93,8 @@ private FleetSpecification createFleetSpecification(int count) { return fleetSpecification; } - private void assertTarget(ToDoubleFunction targetFunction, DrtZonalSystem zonalSystem, String zoneId, - double expectedValue) { - assertThat(targetFunction.applyAsDouble(zonalSystem.getZones().get(zoneId))).isEqualTo(expectedValue); + private void assertTarget(ToDoubleFunction targetFunction, ZoneSystem zonalSystem, Id zoneId, + double expectedValue) { + Assertions.assertThat(targetFunction.applyAsDouble(zonalSystem.getZones().get(zoneId))).isEqualTo(expectedValue); } } diff --git a/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/rebalancing/targetcalculator/EqualVehiclesToPopulationRatioTargetCalculatorTest.java b/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/rebalancing/targetcalculator/EqualVehiclesToPopulationRatioTargetCalculatorTest.java index 7d1044fcd6e..7c24bd07c26 100644 --- a/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/rebalancing/targetcalculator/EqualVehiclesToPopulationRatioTargetCalculatorTest.java +++ b/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/rebalancing/targetcalculator/EqualVehiclesToPopulationRatioTargetCalculatorTest.java @@ -33,9 +33,10 @@ import org.matsim.api.core.v01.population.Plan; import org.matsim.api.core.v01.population.Population; import org.matsim.api.core.v01.population.PopulationFactory; +import org.matsim.contrib.common.zones.Zone; +import org.matsim.contrib.common.zones.ZoneSystem; +import org.matsim.contrib.common.zones.ZoneSystemUtils; import org.matsim.contrib.drt.analysis.zonal.DrtGridUtils; -import org.matsim.contrib.drt.analysis.zonal.DrtZonalSystem; -import org.matsim.contrib.drt.analysis.zonal.DrtZone; import org.matsim.contrib.drt.run.MultiModeDrtConfigGroup; import org.matsim.contrib.dvrp.fleet.DvrpVehicle; import org.matsim.contrib.dvrp.fleet.FleetSpecification; @@ -59,7 +60,7 @@ public class EqualVehiclesToPopulationRatioTargetCalculatorTest { private final Network network = NetworkUtils.readNetwork( config.network().getInputFileURL(config.getContext()).toString()); - private final DrtZonalSystem zonalSystem = DrtZonalSystem.createFromPreparedGeometries(network, + private final ZoneSystem zonalSystem = ZoneSystemUtils.createFromPreparedGeometries(network, DrtGridUtils.createGridFromNetwork(network, 500.)); private final Population population = PopulationUtils.createPopulation(config); @@ -67,34 +68,36 @@ public class EqualVehiclesToPopulationRatioTargetCalculatorTest { @Test void testCalculate_oneVehiclePerZone() { - initPopulation(Map.of("2", 1, "4", 1, "8", 1)); + initPopulation(Map.of(ZoneSystemUtils.createZoneId("2"), 1, ZoneSystemUtils.createZoneId("4"), 1, ZoneSystemUtils.createZoneId("8"), 1)); + var targetFunction = new EqualVehiclesToPopulationRatioTargetCalculator(zonalSystem, population, createFleetSpecification(8)).calculate(0, Map.of()); - assertTarget(targetFunction, zonalSystem, "1", 0); - assertTarget(targetFunction, zonalSystem, "2", 8. * (1. / 3)); - assertTarget(targetFunction, zonalSystem, "3", 0); - assertTarget(targetFunction, zonalSystem, "4", 8. * (1. / 3)); - assertTarget(targetFunction, zonalSystem, "5", 0); - assertTarget(targetFunction, zonalSystem, "6", 0); - assertTarget(targetFunction, zonalSystem, "7", 0); - assertTarget(targetFunction, zonalSystem, "8", 8. * (1. / 3)); + assertTarget(targetFunction, zonalSystem, Id.create("1", Zone.class), 0); + assertTarget(targetFunction, zonalSystem, Id.create("2", Zone.class), 8. * (1. / 3)); + assertTarget(targetFunction, zonalSystem, Id.create("3", Zone.class), 0); + assertTarget(targetFunction, zonalSystem, Id.create("4", Zone.class), 8. * (1. / 3)); + assertTarget(targetFunction, zonalSystem, Id.create("5", Zone.class), 0); + assertTarget(targetFunction, zonalSystem, Id.create("6", Zone.class), 0); + assertTarget(targetFunction, zonalSystem, Id.create("7", Zone.class), 0); + assertTarget(targetFunction, zonalSystem, Id.create("8", Zone.class), 8. * (1. / 3)); } @Test void testCalculate_twoVehiclesPerZone() { - initPopulation(Map.of("2", 1, "4", 1, "8", 1)); + initPopulation(Map.of(ZoneSystemUtils.createZoneId("2"), 1, ZoneSystemUtils.createZoneId("4"), 1, ZoneSystemUtils.createZoneId("8"), 1)); + var targetFunction = new EqualVehiclesToPopulationRatioTargetCalculator(zonalSystem, population, createFleetSpecification(16)).calculate(0, Map.of()); - assertTarget(targetFunction, zonalSystem, "1", 0); - assertTarget(targetFunction, zonalSystem, "2", 16 * (1. / 3)); - assertTarget(targetFunction, zonalSystem, "3", 0); - assertTarget(targetFunction, zonalSystem, "4", 16 * (1. / 3)); - assertTarget(targetFunction, zonalSystem, "5", 0); - assertTarget(targetFunction, zonalSystem, "6", 0); - assertTarget(targetFunction, zonalSystem, "7", 0); - assertTarget(targetFunction, zonalSystem, "8", 16. * (1. / 3)); + assertTarget(targetFunction, zonalSystem, Id.create("1", Zone.class), 0); + assertTarget(targetFunction, zonalSystem, Id.create("2", Zone.class), 16 * (1. / 3)); + assertTarget(targetFunction, zonalSystem, Id.create("3", Zone.class), 0); + assertTarget(targetFunction, zonalSystem, Id.create("4", Zone.class), 16 * (1. / 3)); + assertTarget(targetFunction, zonalSystem, Id.create("5", Zone.class), 0); + assertTarget(targetFunction, zonalSystem, Id.create("6", Zone.class), 0); + assertTarget(targetFunction, zonalSystem, Id.create("7", Zone.class), 0); + assertTarget(targetFunction, zonalSystem, Id.create("8", Zone.class), 16. * (1. / 3)); } @Test @@ -103,30 +106,30 @@ void testCalculate_noPopulation() { var targetFunction = new EqualVehiclesToPopulationRatioTargetCalculator(zonalSystem, population, createFleetSpecification(16)).calculate(0, Map.of()); - assertTarget(targetFunction, zonalSystem, "1", 0); - assertTarget(targetFunction, zonalSystem, "2", 0); - assertTarget(targetFunction, zonalSystem, "3", 0); - assertTarget(targetFunction, zonalSystem, "4", 0); - assertTarget(targetFunction, zonalSystem, "5", 0); - assertTarget(targetFunction, zonalSystem, "6", 0); - assertTarget(targetFunction, zonalSystem, "7", 0); - assertTarget(targetFunction, zonalSystem, "8", 0); + assertTarget(targetFunction, zonalSystem, Id.create("1", Zone.class), 0); + assertTarget(targetFunction, zonalSystem, Id.create("2", Zone.class), 0); + assertTarget(targetFunction, zonalSystem, Id.create("3", Zone.class), 0); + assertTarget(targetFunction, zonalSystem, Id.create("4", Zone.class), 0); + assertTarget(targetFunction, zonalSystem, Id.create("5", Zone.class), 0); + assertTarget(targetFunction, zonalSystem, Id.create("6", Zone.class), 0); + assertTarget(targetFunction, zonalSystem, Id.create("7", Zone.class), 0); + assertTarget(targetFunction, zonalSystem, Id.create("8", Zone.class), 0); } @Test void testCalculate_unevenDistributionOfActivitiesInPopulatedZones() { - initPopulation(Map.of("2", 2, "4", 4, "8", 8)); + initPopulation(Map.of(ZoneSystemUtils.createZoneId("2"), 2, ZoneSystemUtils.createZoneId("4"), 4, ZoneSystemUtils.createZoneId("8"), 8)); var targetFunction = new EqualVehiclesToPopulationRatioTargetCalculator(zonalSystem, population, createFleetSpecification(16)).calculate(0, Map.of()); - assertTarget(targetFunction, zonalSystem, "1", 0); - assertTarget(targetFunction, zonalSystem, "2", 16 * (2. / 14)); - assertTarget(targetFunction, zonalSystem, "3", 0); - assertTarget(targetFunction, zonalSystem, "4", 16 * (4. / 14)); - assertTarget(targetFunction, zonalSystem, "5", 0); - assertTarget(targetFunction, zonalSystem, "6", 0); - assertTarget(targetFunction, zonalSystem, "7", 0); - assertTarget(targetFunction, zonalSystem, "8", 16 * (8. / 14)); + assertTarget(targetFunction, zonalSystem, Id.create("1", Zone.class), 0); + assertTarget(targetFunction, zonalSystem, Id.create("2", Zone.class), 16 * (2. / 14)); + assertTarget(targetFunction, zonalSystem, Id.create("3", Zone.class), 0); + assertTarget(targetFunction, zonalSystem, Id.create("4", Zone.class), 16 * (4. / 14)); + assertTarget(targetFunction, zonalSystem, Id.create("5", Zone.class), 0); + assertTarget(targetFunction, zonalSystem, Id.create("6", Zone.class), 0); + assertTarget(targetFunction, zonalSystem, Id.create("7", Zone.class), 0); + assertTarget(targetFunction, zonalSystem, Id.create("8", Zone.class), 16 * (8. / 14)); } private FleetSpecification createFleetSpecification(int count) { @@ -149,7 +152,7 @@ private FleetSpecification createFleetSpecification(int count) { * 2 4 6 8 * 1 3 5 7 */ - private void initPopulation(Map populationPerZone) { + private void initPopulation(Map, Integer> populationPerZone) { populationPerZone.forEach((zoneId, population) -> { for (int i = 0; i < population; i++) { createAndAddPerson(zoneId + "_" + i, zoneId); @@ -157,7 +160,7 @@ private void initPopulation(Map populationPerZone) { }); } - private void createAndAddPerson(String id, String zoneId) { + private void createAndAddPerson(String id, Id zoneId) { Id linkId = zonalSystem.getZones().get(zoneId).getLinks().get(0).getId(); Person person = factory.createPerson(Id.createPersonId(id)); Plan plan = factory.createPlan(); @@ -166,8 +169,8 @@ private void createAndAddPerson(String id, String zoneId) { population.addPerson(person); } - private void assertTarget(ToDoubleFunction targetFunction, DrtZonalSystem zonalSystem, String zoneId, - double expectedValue) { + private void assertTarget(ToDoubleFunction targetFunction, ZoneSystem zonalSystem, Id zoneId, + double expectedValue) { assertThat(targetFunction.applyAsDouble(zonalSystem.getZones().get(zoneId))).isEqualTo(expectedValue); } } From f9abe3968b1a8a398a86281d5c306ca52e610670 Mon Sep 17 00:00:00 2001 From: nkuehnel Date: Tue, 19 Mar 2024 16:21:29 +0100 Subject: [PATCH 3/5] adjust zonal system test --- .../matsim/contrib/drt/analysis/zonal/DrtZonalSystemTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contribs/drt/src/test/java/org/matsim/contrib/drt/analysis/zonal/DrtZonalSystemTest.java b/contribs/drt/src/test/java/org/matsim/contrib/drt/analysis/zonal/DrtZonalSystemTest.java index 10f50c6d9df..e17d38c7901 100644 --- a/contribs/drt/src/test/java/org/matsim/contrib/drt/analysis/zonal/DrtZonalSystemTest.java +++ b/contribs/drt/src/test/java/org/matsim/contrib/drt/analysis/zonal/DrtZonalSystemTest.java @@ -71,7 +71,7 @@ void test_gridWithinServiceArea(){ //link 'da' is outside of the service area Id id = Id.createLinkId("da"); - Assertions.assertThat(zonalSystem.getZoneForLinkId(id) == null).isTrue(); + Assertions.assertThat(zonalSystem.getZoneForLinkId(id)).isNull(); } @Test From 170c111d991d21c2c4c2d8a86a2905d99fc1fdc8 Mon Sep 17 00:00:00 2001 From: nkuehnel Date: Tue, 19 Mar 2024 16:23:27 +0100 Subject: [PATCH 4/5] improve formatting --- .../org/matsim/contrib/common/zones/ZoneSystemUtils.java | 3 +-- .../matsim/contrib/common/zones/h3/H3ZoneSystemUtils.java | 6 ++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/contribs/common/src/main/java/org/matsim/contrib/common/zones/ZoneSystemUtils.java b/contribs/common/src/main/java/org/matsim/contrib/common/zones/ZoneSystemUtils.java index 26a9a6d31d6..d1e3e6f2094 100644 --- a/contribs/common/src/main/java/org/matsim/contrib/common/zones/ZoneSystemUtils.java +++ b/contribs/common/src/main/java/org/matsim/contrib/common/zones/ZoneSystemUtils.java @@ -21,8 +21,7 @@ public final class ZoneSystemUtils { private ZoneSystemUtils() {} - public static ZoneSystem createFromPreparedGeometries(Network network, - Map geometries) { + public static ZoneSystem createFromPreparedGeometries(Network network, Map geometries) { //geometries without links are skipped Map> linksByGeometryId = StreamEx.of(network.getLinks().values()) diff --git a/contribs/common/src/main/java/org/matsim/contrib/common/zones/h3/H3ZoneSystemUtils.java b/contribs/common/src/main/java/org/matsim/contrib/common/zones/h3/H3ZoneSystemUtils.java index 24c2aeea603..f496d62cc5d 100644 --- a/contribs/common/src/main/java/org/matsim/contrib/common/zones/h3/H3ZoneSystemUtils.java +++ b/contribs/common/src/main/java/org/matsim/contrib/common/zones/h3/H3ZoneSystemUtils.java @@ -32,10 +32,8 @@ public class H3ZoneSystemUtils { static final Logger log = LogManager.getLogger(H3ZoneSystemUtils.class); - public static ZoneSystem createFromPreparedGeometries(Network network, - Map geometries, - String crs, - int resolution) { + public static ZoneSystem createFromPreparedGeometries(Network network, Map geometries, + String crs, int resolution) { //geometries without links are skipped CoordinateTransformation ct = TransformationFactory.getCoordinateTransformation(crs, TransformationFactory.WGS84); From 9956761f6f3e2fc0293fd3e370aa36aa0d0103cc Mon Sep 17 00:00:00 2001 From: nkuehnel Date: Tue, 19 Mar 2024 16:32:06 +0100 Subject: [PATCH 5/5] improve formatting further --- .../org/matsim/contrib/drt/analysis/zonal/DrtGridUtils.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtGridUtils.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtGridUtils.java index c27203c6ce5..75101e4bc6c 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtGridUtils.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtGridUtils.java @@ -82,8 +82,7 @@ public static Map createGridFromNetwork(Network networ * @param serviceAreaGeoms geometries that define the service area * @return */ - public static Map filterGridWithinServiceArea(Map grid, - List serviceAreaGeoms) { + public static Map filterGridWithinServiceArea(Map grid, List serviceAreaGeoms) { log.info("total number of initial grid zones = " + grid.size()); log.info("searching for grid zones within the drt service area..."); Counter counter = new Counter("dealt with zone ");