Skip to content

Commit

Permalink
further steps towards consolidation of dvrp and drt zone systems
Browse files Browse the repository at this point in the history
  • Loading branch information
nkuehnel committed Apr 15, 2024
1 parent 71fccea commit 9696c61
Show file tree
Hide file tree
Showing 25 changed files with 120 additions and 129 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@
import org.matsim.api.core.v01.network.Link;
import org.matsim.api.core.v01.network.Node;

import javax.annotation.Nullable;
import java.util.List;
import java.util.Map;
import java.util.Optional;

public interface ZoneSystem {
@Nullable
Zone getZoneForLinkId(Id<Link> link);
Optional<Zone> getZoneForLinkId(Id<Link> link);

Zone getZoneForNodeId(Node node);
Optional<Zone> getZoneForNodeId(Node node);

List<Link> getLinksForZoneId(Id<Zone> zone);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
import org.matsim.api.core.v01.network.Node;
import org.matsim.contrib.common.zones.util.ZoneFinder;

import javax.annotation.Nullable;
import java.util.*;
import java.util.function.Consumer;

public class ZoneSystemImpl implements ZoneSystem {

Expand All @@ -32,11 +32,10 @@ public ZoneSystemImpl(Collection<Zone> zones, ZoneFinder zoneFinder, Network net
this.link2zone.putAll(linkToZoneMap);

for (Link link : network.getLinks().values()) {
Zone zone = zoneFinder.findZone(link.getToNode().getCoord());
if(zone != null) {
zoneFinder.findZone(link.getToNode().getCoord()).ifPresent(zone -> {
List<Link> links = zoneToLinksMap.computeIfAbsent(zone.getId(), zoneId1 -> new ArrayList<>());
links.add(link);
}
links.add(link);
});
}
}

Expand All @@ -46,14 +45,13 @@ public ZoneSystemImpl(Collection<Zone> zones, ZoneFinder zoneFinder, Network net
* Result may be null in case the given link is outside of the service area.
*/
@Override
@Nullable
public Zone getZoneForLinkId(Id<Link> link) {
return link2zone.get(link);
public Optional<Zone> getZoneForLinkId(Id<Link> link) {
return Optional.ofNullable(link2zone.get(link));
}

@Override
public Zone getZoneForNodeId(Node node) {
return nodeToZoneMap.get(node.getId());
public Optional<Zone> getZoneForNodeId(Node node) {
return Optional.ofNullable(nodeToZoneMap.get(node.getId()));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

import static java.util.stream.Collectors.toList;

Expand Down Expand Up @@ -97,14 +98,16 @@ public static Map<Id<Zone>, Zone> readZones(URL zonesXmlUrl, URL zonesShpUrl) {
public static IdMap<Link, Zone> createLinkToZoneMap(Network network, ZoneFinder zoneFinder) {
return EntryStream.of(network.getLinks())
.mapValues(link -> zoneFinder.findZone(link.getToNode().getCoord()))
.filterValues(Objects::nonNull)
.filterValues(Optional::isPresent)
.mapValues(Optional::get)
.collect(IdCollectors.toIdMap(Link.class, Map.Entry::getKey, Map.Entry::getValue));
}

public static IdMap<Node, Zone> createNodeToZoneMap(Network network, ZoneFinder zoneFinder) {
return EntryStream.of(network.getNodes())
.mapValues(node -> zoneFinder.findZone(node.getCoord()))
.filterValues(Objects::nonNull)
.filterValues(Optional::isPresent)
.mapValues(Optional::get)
.collect(IdCollectors.toIdMap(Node.class, Map.Entry::getKey, Map.Entry::getValue));

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,7 @@

import static java.util.stream.Collectors.*;

import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
import java.util.function.BinaryOperator;
import java.util.stream.Collectors;

Expand All @@ -39,9 +35,9 @@
import org.matsim.core.utils.geometry.geotools.MGC;

//TODO add zone indexing?
public class ZonalSystems {
public class ZoneSystems {
public static Set<Zone> filterZonesWithNodes(Collection<? extends Node> nodes, ZoneSystem zoneSystem) {
return nodes.stream().map(zoneSystem::getZoneForNodeId).collect(toSet());
return nodes.stream().map(zoneSystem::getZoneForNodeId).filter(Optional::isPresent).map(Optional::get).collect(toSet());
}

public static List<Node> selectNodesWithinArea(Collection<? extends Node> nodes, List<PreparedGeometry> areaGeoms) {
Expand All @@ -53,12 +49,12 @@ public static List<Node> selectNodesWithinArea(Collection<? extends Node> nodes,

public static Map<Zone, Node> computeMostCentralNodes(Collection<? extends Node> nodes, ZoneSystem zoneSystem) {
BinaryOperator<Node> chooseMoreCentralNode = (n1, n2) -> {
Zone zone = zoneSystem.getZoneForNodeId(n1);
Zone zone = zoneSystem.getZoneForNodeId(n1).orElseThrow();
return DistanceUtils.calculateSquaredDistance(n1, zone) <= DistanceUtils.calculateSquaredDistance(n2,
zone) ? n1 : n2;
};
return nodes.stream()
.map(n -> Pair.of(n, zoneSystem.getZoneForNodeId(n)))
.map(n -> Pair.of(n, zoneSystem.getZoneForNodeId(n).orElseThrow()))
.collect(toMap(Pair::getValue, Pair::getKey, chooseMoreCentralNode));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,19 @@
import org.matsim.contrib.common.zones.Zone;
import org.matsim.contrib.common.zones.ZoneSystem;

import javax.annotation.Nullable;
import java.util.*;

import static java.util.stream.Collectors.toMap;

public class SquareGridSystem implements ZoneSystem {
public class SquareGridZoneSystem implements ZoneSystem {
private final SquareGrid grid;
private final Map<Id<Zone>, Zone> zones;

private final IdMap<Zone, List<Link>> zoneToLinksMap = new IdMap<>(Zone.class);
private final Network network;


public SquareGridSystem(Network network, double cellSize) {
public SquareGridZoneSystem(Network network, double cellSize) {
this.network = network;
this.grid = new SquareGrid(network.getNodes().values(), cellSize);
zones = network.getNodes().values().stream()
Expand All @@ -58,15 +57,14 @@ public Map<Id<Zone>, Zone> getZones() {
return Collections.unmodifiableMap(zones);
}

@Nullable
@Override
public Zone getZoneForLinkId(Id<Link> link) {
return grid.getZone(network.getLinks().get(link).getToNode().getCoord());
public Optional<Zone> getZoneForLinkId(Id<Link> link) {
return Optional.ofNullable(grid.getZone(network.getLinks().get(link).getToNode().getCoord()));
}

@Override
public Zone getZoneForNodeId(Node node) {
return grid.getZone(node.getCoord());
public Optional<Zone> getZoneForNodeId(Node node) {
return Optional.ofNullable(grid.getZone(node.getCoord()));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import org.matsim.core.utils.geometry.transformations.TransformationFactory;

import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

Expand All @@ -41,8 +41,8 @@ public static ZoneSystem createFromPreparedGeometries(Network network, Map<Strin

Set<Id<Zone>> requiredZones = network.getLinks().values().stream()
.map(link -> h3ZoneFinder.findZone(link.getToNode().getCoord()))
.filter(Objects::nonNull) // Filter out any null zones
.map(Identifiable::getId) // Convert Zone to Id<Zone>, adjust this line if findZone() directly returns Id<Zone>
.filter(Optional::isPresent) // Filter out any null zones
.map(op -> op.get().getId()) // Convert Zone to Id<Zone>, adjust this line if findZone() directly returns Id<Zone>
.collect(Collectors.toSet()); // Collect unique Ids into a Set

zones.keySet().retainAll(requiredZones);
Expand All @@ -67,10 +67,10 @@ private static class H3ZoneFinder implements ZoneFinder {
}

@Override
public Zone findZone(Coord coord) {
public Optional<Zone> findZone(Coord coord) {
LatLng latLng = H3GridUtils.coordToLatLng(ct.transform(coord));
Id<Zone> zoneId = ZoneSystemUtils.createZoneId(h3.latLngToCellAddress(latLng.lat, latLng.lng, resolution));
return zones.getOrDefault(zoneId, null);
return Optional.ofNullable(zones.get(zoneId));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import org.matsim.api.core.v01.Coord;
import org.matsim.contrib.common.zones.Zone;

import java.util.Optional;

public interface ZoneFinder {
Zone findZone(Coord coord);
Optional<Zone> findZone(Coord coord);
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import java.util.List;
import java.util.Map;
import java.util.Optional;

import org.locationtech.jts.geom.Envelope;
import org.locationtech.jts.geom.Point;
Expand Down Expand Up @@ -52,21 +53,21 @@ public ZoneFinderImpl(Map<Id<Zone>, Zone> zones) {

@Override
@SuppressWarnings("unchecked")
public Zone findZone(Coord coord) {
public Optional<Zone> findZone(Coord coord) {
Point point = MGC.coord2Point(coord);
Envelope env = point.getEnvelopeInternal();

Zone zone = getSmallestZoneContainingPoint(quadTree.query(env), point);
if (zone != null) {
return zone;
return Optional.of(zone);
}

if (expansionDistance > 0) {
env.expandBy(expansionDistance);
zone = getNearestZone(quadTree.query(env), point);
}

return zone;
return Optional.ofNullable(zone);
}

private Zone getSmallestZoneContainingPoint(List<Zone> zones, Point point) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,11 @@ void test_Holzkirchen_Resolution3() {
assertThat(drtZonalSystem.getZones().containsKey(createZoneId("831f8dfffffffff"))).isTrue();

// center of Holzkirchen
assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(358598)).getId()).isEqualTo(createZoneId("831f8dfffffffff"));
assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(358598)).orElseThrow().getId()).isEqualTo(createZoneId("831f8dfffffffff"));
// Thanning (Western border of network)
assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(78976)).getId()).isEqualTo(createZoneId("831f8dfffffffff"));
assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(78976)).orElseThrow().getId()).isEqualTo(createZoneId("831f8dfffffffff"));
// between Gross- and Kleinpienzenau (Southeastern border of network)
assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(59914)).getId()).isEqualTo(createZoneId("831f89fffffffff"));
assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(59914)).orElseThrow().getId()).isEqualTo(createZoneId("831f89fffffffff"));

//check all links are mapped
for (Link link : network.getLinks().values()) {
Expand All @@ -81,11 +81,11 @@ void test_Holzkirchen_Resolution5() {
assertThat(drtZonalSystem.getZones().containsKey(createZoneId("851f89d3fffffff"))).isTrue();

// center of Holzkirchen
assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(358598)).getId()).isEqualTo(createZoneId("851f8d6bfffffff"));
assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(358598)).orElseThrow().getId()).isEqualTo(createZoneId("851f8d6bfffffff"));
// Thanning (Western border of network)
assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(78976)).getId()).isEqualTo(createZoneId("851f88b7fffffff"));
assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(78976)).orElseThrow().getId()).isEqualTo(createZoneId("851f88b7fffffff"));
// between Gross- and Kleinpienzenau (Southeastern border of network)
assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(59914)).getId()).isEqualTo(createZoneId("851f89d3fffffff"));
assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(59914)).orElseThrow().getId()).isEqualTo(createZoneId("851f89d3fffffff"));

//check all links are mapped
for (Link link : network.getLinks().values()) {
Expand All @@ -109,11 +109,11 @@ void test_Holzkirchen_Resolution6() {
assertThat(drtZonalSystem.getZones().containsKey(createZoneId("861f89d37ffffff"))).isTrue();

// center of Holzkirchen
assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(358598)).getId()).isEqualTo(createZoneId("861f8d697ffffff"));
assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(358598)).orElseThrow().getId()).isEqualTo(createZoneId("861f8d697ffffff"));
// Thanning (Western border of network)
assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(78976)).getId()).isEqualTo(createZoneId("861f88b47ffffff"));
assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(78976)).orElseThrow().getId()).isEqualTo(createZoneId("861f88b47ffffff"));
// between Gross- and Kleinpienzenau (Southeastern border of network)
assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(59914)).getId()).isEqualTo(createZoneId("861f89d07ffffff"));
assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(59914)).orElseThrow().getId()).isEqualTo(createZoneId("861f89d07ffffff"));

//check all links are mapped
for (Link link : network.getLinks().values()) {
Expand All @@ -130,11 +130,11 @@ void test_Holzkirchen_Resolution10() {
H3GridUtils.createH3GridFromNetwork(network, resolution, crs), crs, resolution);

// center of Holzkirchen
assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(358598)).getId()).isEqualTo(createZoneId("8a1f8d6930b7fff"));
assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(358598)).orElseThrow().getId()).isEqualTo(createZoneId("8a1f8d6930b7fff"));
// Thanning (Western border of network)
assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(78976)).getId()).isEqualTo(createZoneId("8a1f88b4025ffff"));
assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(78976)).orElseThrow().getId()).isEqualTo(createZoneId("8a1f88b4025ffff"));
// between Gross- and Kleinpienzenau (Southeastern border of network)
assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(59914)).getId()).isEqualTo(createZoneId("8a1f89d06d5ffff"));
assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(59914)).orElseThrow().getId()).isEqualTo(createZoneId("8a1f89d06d5ffff"));

//check all links are mapped
for (Link link : network.getLinks().values()) {
Expand All @@ -151,11 +151,11 @@ void test_Holzkirchen_Resolution12() {
H3GridUtils.createH3GridFromNetwork(network, resolution, crs), crs, resolution);

// center of Holzkirchen
assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(358598)).getId()).isEqualTo(createZoneId("8c1f8d6930b63ff"));
assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(358598)).orElseThrow().getId()).isEqualTo(createZoneId("8c1f8d6930b63ff"));
// Thanning (Western border of network)
assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(78976)).getId()).isEqualTo(createZoneId("8c1f88b4025d1ff"));
assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(78976)).orElseThrow().getId()).isEqualTo(createZoneId("8c1f88b4025d1ff"));
// between Gross- and Kleinpienzenau (Southeastern border of network)
assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(59914)).getId()).isEqualTo(createZoneId("8c1f89d06d581ff"));
assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(59914)).orElseThrow().getId()).isEqualTo(createZoneId("8c1f89d06d581ff"));

//check all links are mapped
for (Link link : network.getLinks().values()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
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.Identifiable;
import org.matsim.api.core.v01.population.Person;
import org.matsim.contrib.common.zones.Zone;
import org.matsim.contrib.common.zones.ZoneSystem;
Expand Down Expand Up @@ -139,10 +140,10 @@ private Map<Id<Zone>, DescriptiveStatistics> createZonalStats() {
for (EventSequence seq : requestAnalyzer.getPerformedRequestSequences().values()) {
for (Map.Entry<Id<Person>, EventSequence.PersonEvents> entry : seq.getPersonEvents().entrySet()) {
if(entry.getValue().getPickedUp().isPresent()) {
Zone zone = zones.getZoneForLinkId(seq.getSubmitted().getFromLinkId());
final Id<Zone> zoneStr = zone != null ? zone.getId() : zoneIdForOutsideOfZonalSystem;
Id<Zone> zone = zones.getZoneForLinkId(seq.getSubmitted().getFromLinkId())
.map(Identifiable::getId).orElse(zoneIdForOutsideOfZonalSystem);
double waitTime = entry.getValue().getPickedUp().get() .getTime() - seq.getSubmitted().getTime();
zoneStats.get(zoneStr).addValue(waitTime);
zoneStats.get(zone).addValue(waitTime);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,7 @@ public void handleEvent(TaskEndedEvent event) {

private void handleEvent(AbstractTaskEvent event, Consumer<Zone> handler) {
if (event.getDvrpMode().equals(dvrpMode) && event.getTaskType().equals(DrtStayTask.TYPE)) {
Zone zone = zonalSystem.getZoneForLinkId(event.getLinkId());
if (zone != null) {
handler.accept(zone);
}
zonalSystem.getZoneForLinkId(event.getLinkId()).ifPresent(handler);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,7 @@ public void handleEvent(TaskEndedEvent event) {

private void handleEvent(AbstractTaskEvent event, Consumer<Zone> handler) {
if (event.getDvrpMode().equals(mode) && event.getTaskType().equals(DrtStayTask.TYPE)) {
Zone zone = zonalSystem.getZoneForLinkId(event.getLinkId());
if (zone != null) {
handler.accept(zone);
}
zonalSystem.getZoneForLinkId(event.getLinkId()).ifPresent(handler);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,9 @@ public static Map<Zone, List<DvrpVehicle>> groupRebalancableVehicles(ZoneSystem
Map<Zone, List<DvrpVehicle>> rebalancableVehiclesPerZone = new HashMap<>();
rebalancableVehicles.filter(v -> v.getServiceEndTime() > time + params.minServiceTime).forEach(v -> {
Link link = ((StayTask)v.getSchedule().getCurrentTask()).getLink();
Zone zone = zoneSystem.getZoneForLinkId(link.getId());
if (zone == null) {
zone = ZoneImpl.createDummyZone(Id.create("single-vehicle-zone-" + v.getId(), Zone.class),
link.getToNode().getCoord());
}
Zone zone = zoneSystem.getZoneForLinkId(link.getId())
.orElse(ZoneImpl.createDummyZone(Id.create("single-vehicle-zone-" + v.getId(), Zone.class),
link.getToNode().getCoord()));
rebalancableVehiclesPerZone.computeIfAbsent(zone, z -> new ArrayList<>()).add(v);
});
return rebalancableVehiclesPerZone;
Expand All @@ -67,10 +65,10 @@ public static Map<Zone, List<DvrpVehicle>> groupSoonIdleVehicles(ZoneSystem zone
if (stayTask.getStatus() == Task.TaskStatus.PLANNED
&& stayTask.getBeginTime() < time + params.maxTimeBeforeIdle
&& v.getServiceEndTime() > time + params.minServiceTime) {
Zone zone = zoneSystem.getZoneForLinkId(stayTask.getLink().getId());
if (zone != null) {
soonIdleVehiclesPerZone.computeIfAbsent(zone, z -> new ArrayList<>()).add(v);
}
zoneSystem.getZoneForLinkId(stayTask.getLink().getId())
.ifPresent(
zone -> soonIdleVehiclesPerZone.computeIfAbsent(zone, z -> new ArrayList<>()).add(v)
);
}
}
return soonIdleVehiclesPerZone;
Expand Down
Loading

0 comments on commit 9696c61

Please sign in to comment.