diff --git a/matsim/src/main/java/org/matsim/core/network/turnRestrictions/DisallowedNextLinksUtils.java b/matsim/src/main/java/org/matsim/core/network/turnRestrictions/DisallowedNextLinksUtils.java index a787f1c9fe5..6c9f804bb77 100644 --- a/matsim/src/main/java/org/matsim/core/network/turnRestrictions/DisallowedNextLinksUtils.java +++ b/matsim/src/main/java/org/matsim/core/network/turnRestrictions/DisallowedNextLinksUtils.java @@ -51,6 +51,68 @@ public static boolean isValid(Network network) { return errors.isEmpty(); } + /** + * Remove link sequences of DisallowedNextLinks which contain missing links or + * wrong modes. + * + * @param network + */ + public static void clean(Network network) { + Map, ? extends Link> links = network.getLinks(); + + links.values().forEach(link -> { + + DisallowedNextLinks dnl = NetworkUtils.getDisallowedNextLinks(link); + if (dnl == null) { + return; + } + + // remove link sequences for modes, that are not allowed on this link + for (Entry>>> entry : dnl.getAsMap().entrySet()) { + final String mode = entry.getKey(); + final int linkSequencesCount = entry.getValue().size(); + + if (!link.getAllowedModes().contains(mode)) { + dnl.removeDisallowedLinkSequences(mode); + LOG.info("Link {}: Removed all {} disallowed next link sequences of mode {}" + + " because {} is not allowed", link.getId(), linkSequencesCount, mode, mode); + } + } + + // keep only valid link sequences + for (Entry>>> entry : dnl.getAsMap().entrySet()) { + final String mode = entry.getKey(); + final List>> linkSequences = entry.getValue(); + + // find valid link sequences + List>> validLinkSequences = linkSequences.stream() + // links of sequence exist in network + .filter(linkIds -> linkIds.stream().allMatch(links::containsKey)) + // links all have mode in allowed modes + .filter(linkIds -> linkIds.stream() + .map(links::get) + .map(Link::getAllowedModes) + .allMatch(allowedModes -> allowedModes.contains(mode))) + .toList(); + + // update mode with valid link sequences + final int invalidLinkSequencesCount = linkSequences.size() - validLinkSequences.size(); + if (invalidLinkSequencesCount > 0) { + dnl.removeDisallowedLinkSequences(mode); + validLinkSequences.forEach(linkIds -> dnl.addDisallowedLinkSequence(mode, linkIds)); + LOG.info("Link {}: Removed {} disallowed next link sequences for mode {}", + link.getId(), invalidLinkSequencesCount, mode); + } + } + + // remove attribute completely, if it contains no link sequences anymore. + if (dnl.isEmpty()) { + NetworkUtils.removeDisallowedNextLinks(link); + } + + }); + } + // Helpers private static List getErrors(Map, ? extends Link> links, Id linkId, @@ -60,9 +122,15 @@ private static List getErrors(Map, ? extends Link> links, Id
  • >>> entry : disallowedNextLinks.getAsMap().entrySet()) { + String mode = entry.getKey(); List>> linkSequences = entry.getValue(); + for (List> linkSequence : linkSequences) { + // check for (1) link sequences being a valid sequence and (2) links existing errors.addAll(isNextLinkSequenceOf(links, link, linkSequence)); + + // check for allowedModes on this and next links + errors.addAll(isInAllowedModes(links, mode, link, linkSequence)); } } return errors; @@ -98,4 +166,25 @@ private static boolean isNextLinkOf(Link link, Id nextLinkId) { return toNode.getOutLinks().get(nextLinkId) != null; } + private static List isInAllowedModes(Map, ? extends Link> links, String mode, Link link, + List> nextLinkIds) { + + List messages = new ArrayList<>(); + + if (!link.getAllowedModes().contains(mode)) { + messages.add(String.format("Link %s does not allow mode %s", + link.getId(), mode)); + } + + for (Id nextLinkId : nextLinkIds) { + Link nextLink = links.get(nextLinkId); + if (nextLink != null && !nextLink.getAllowedModes().contains(mode)) { + messages.add(String.format("Next link %s does not allow mode %s", + nextLink.getId(), mode)); + } + } + + return messages; + } + } diff --git a/matsim/src/test/java/org/matsim/core/network/DisallowedNextLinksUtilsTest.java b/matsim/src/test/java/org/matsim/core/network/DisallowedNextLinksUtilsTest.java index 9ff42900a83..9232e8ac28e 100644 --- a/matsim/src/test/java/org/matsim/core/network/DisallowedNextLinksUtilsTest.java +++ b/matsim/src/test/java/org/matsim/core/network/DisallowedNextLinksUtilsTest.java @@ -2,21 +2,25 @@ import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.Set; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Coord; import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.TransportMode; import org.matsim.api.core.v01.network.Link; import org.matsim.api.core.v01.network.Network; +import org.matsim.api.core.v01.network.Node; import org.matsim.core.network.turnRestrictions.DisallowedNextLinks; import org.matsim.core.network.turnRestrictions.DisallowedNextLinksUtils; -public class DisallowedNextLinksUtilsTest { - - Network n = DisallowedNextLinksTest.createNetwork(); +class DisallowedNextLinksUtilsTest { @Test void testEquals1() { + Network n = DisallowedNextLinksTest.createNetwork(); Network n2 = DisallowedNextLinksTest.createNetwork(); Assertions.assertTrue(NetworkUtils.compare(n, n2)); @@ -24,7 +28,6 @@ void testEquals1() { @Test void testEquals2() { - Network n1 = DisallowedNextLinksTest.createNetwork(); { Link l1 = n1.getLinks().get(Id.createLinkId("1")); @@ -44,6 +47,7 @@ void testEquals2() { @Test void testNotEquals() { + Network n = DisallowedNextLinksTest.createNetwork(); Network n2 = DisallowedNextLinksTest.createNetwork(); Link l1 = n2.getLinks().get(Id.createLinkId("1")); DisallowedNextLinks dnl0 = NetworkUtils.getOrCreateDisallowedNextLinks(l1); @@ -54,11 +58,13 @@ void testNotEquals() { @Test void testNoDisallowedNextLinks() { + Network n = DisallowedNextLinksTest.createNetwork(); Assertions.assertTrue(DisallowedNextLinksUtils.isValid(n)); } @Test void testIsNotValid1() { + Network n = DisallowedNextLinksTest.createNetwork(); Map, ? extends Link> links = n.getLinks(); Link l1 = links.get(Id.createLinkId("1")); Link l3 = links.get(Id.createLinkId("3")); @@ -72,6 +78,7 @@ void testIsNotValid1() { @Test void testIsNotValid2() { + Network n = DisallowedNextLinksTest.createNetwork(); Map, ? extends Link> links = n.getLinks(); Link l1 = links.get(Id.createLinkId("1")); Link l3 = links.get(Id.createLinkId("3")); @@ -85,10 +92,13 @@ void testIsNotValid2() { @Test void testIsValid() { + Network n = DisallowedNextLinksTest.createNetwork(); Map, ? extends Link> links = n.getLinks(); Link l1 = links.get(Id.createLinkId("1")); Link l3 = links.get(Id.createLinkId("3")); Link l5 = links.get(Id.createLinkId("5")); + NetworkUtils.addAllowedMode(l1, "bike"); + NetworkUtils.addAllowedMode(l3, "bike"); DisallowedNextLinks dnl = NetworkUtils.getOrCreateDisallowedNextLinks(l1); dnl.addDisallowedLinkSequence("car", List.of(l3.getId(), l5.getId())); @@ -96,4 +106,190 @@ void testIsValid() { Assertions.assertTrue(DisallowedNextLinksUtils.isValid(n)); } + + @Test + void testClean() { + + Network network = createNetwork(); + + Link l01 = network.getLinks().get(Id.createLinkId("01")); + DisallowedNextLinks dnl01 = NetworkUtils.getOrCreateDisallowedNextLinks(l01); + dnl01.addDisallowedLinkSequence(TransportMode.car, List.of(Id.createLinkId("12"), Id.createLinkId("23"))); + dnl01.addDisallowedLinkSequence(TransportMode.car, List.of(Id.createLinkId("14"))); + + network.removeLink(Id.createLinkId("23")); + + Assertions.assertNotNull(NetworkUtils.getDisallowedNextLinks(l01)); + Assertions.assertFalse(DisallowedNextLinksUtils.isValid(network)); + + // * -------------------------------------------------- + + DisallowedNextLinksUtils.clean(network); + + // * -------------------------------------------------- + + Assertions.assertTrue(DisallowedNextLinksUtils.isValid(network)); + + DisallowedNextLinks dnl = NetworkUtils + .getOrCreateDisallowedNextLinks(network.getLinks().get(Id.createLinkId("01"))); + Assertions.assertEquals(List.of(List.of(Id.createLinkId("14"))), + dnl.getDisallowedLinkSequences(TransportMode.car)); + + } + + @Test + void testCleanCompletely() { + + Network network = createNetwork(); + + Link l01 = network.getLinks().get(Id.createLinkId("01")); + DisallowedNextLinks dnl01 = NetworkUtils.getOrCreateDisallowedNextLinks(l01); + dnl01.addDisallowedLinkSequence(TransportMode.car, List.of(Id.createLinkId("12"), Id.createLinkId("23"))); + + network.removeLink(Id.createLinkId("23")); + + Assertions.assertFalse(DisallowedNextLinksUtils.isValid(network)); + + // * -------------------------------------------------- + + DisallowedNextLinksUtils.clean(network); + + // * -------------------------------------------------- + + Assertions.assertTrue(DisallowedNextLinksUtils.isValid(network)); + + Assertions.assertTrue(network.getLinks().values().stream() + .map(NetworkUtils::getDisallowedNextLinks) + .allMatch(Objects::isNull)); + + } + + @Test + void testCleanWrongMode() { + + Network network = createNetwork(); + + Link l01 = network.getLinks().get(Id.createLinkId("01")); + DisallowedNextLinks dnl01 = NetworkUtils.getOrCreateDisallowedNextLinks(l01); + dnl01.addDisallowedLinkSequence(TransportMode.bike, List.of(Id.createLinkId("12"), Id.createLinkId("23"))); + + Assertions.assertFalse(DisallowedNextLinksUtils.isValid(network)); + + // * -------------------------------------------------- + + DisallowedNextLinksUtils.clean(network); + + // * -------------------------------------------------- + + Assertions.assertTrue(DisallowedNextLinksUtils.isValid(network)); + + Assertions.assertTrue(network.getLinks().values().stream() + .map(NetworkUtils::getDisallowedNextLinks) + .allMatch(Objects::isNull)); + + } + + @Test + void testCleanWrongModeOnNextLink() { + + Network network = createNetwork(); + + Link l01 = network.getLinks().get(Id.createLinkId("01")); + DisallowedNextLinks dnl01 = NetworkUtils.getOrCreateDisallowedNextLinks(l01); + dnl01.addDisallowedLinkSequence(TransportMode.car, List.of(Id.createLinkId("12"), Id.createLinkId("23"))); + + Link l12 = network.getLinks().get(Id.createLinkId("12")); + l12.setAllowedModes(Set.of(TransportMode.bike)); + + Assertions.assertFalse(DisallowedNextLinksUtils.isValid(network)); + + // * -------------------------------------------------- + + DisallowedNextLinksUtils.clean(network); + + // * -------------------------------------------------- + + Assertions.assertTrue(DisallowedNextLinksUtils.isValid(network)); + + Assertions.assertTrue(network.getLinks().values().stream() + .map(NetworkUtils::getDisallowedNextLinks) + .allMatch(Objects::isNull)); + + } + + // Helpers + + static Network createNetwork() { + Network network = NetworkUtils.createNetwork(); + + Node n0 = NetworkUtils.createNode(Id.createNodeId("0"), new Coord(0, -0)); + Node n1 = NetworkUtils.createNode(Id.createNodeId("1"), new Coord(0, -1)); + Node n2 = NetworkUtils.createNode(Id.createNodeId("2"), new Coord(-1, -2)); + Node n3 = NetworkUtils.createNode(Id.createNodeId("3"), new Coord(-1, -3)); + Node n4 = NetworkUtils.createNode(Id.createNodeId("4"), new Coord(0, -4)); + Node n5 = NetworkUtils.createNode(Id.createNodeId("5"), new Coord(1, -1)); + Node n6 = NetworkUtils.createNode(Id.createNodeId("6"), new Coord(0, -6)); + + network.addNode(n0); + network.addNode(n1); + network.addNode(n2); + network.addNode(n3); + network.addNode(n4); + network.addNode(n5); + network.addNode(n6); + + // * n0 + // l01 l10 (0110) + // * n1 - l15 l51 (1551) - n5 + // l12 l21 (1221) \ + // * n2 + // l23 l32 (2332) | l14 l41 (1441) + // * n3 + // l34 l43 (3443) / + // * n4 + // l46 l64 (4664) + // * n6 + + Link l01 = NetworkUtils.createLink(Id.createLinkId("01"), n0, n1, network, 1, 1, 300, 1); + Link l10 = NetworkUtils.createLink(Id.createLinkId("10"), n1, n0, network, 1, 1, 300, 1); + + Link l12 = NetworkUtils.createLink(Id.createLinkId("12"), n1, n2, network, 1, 1, 300, 1); + Link l21 = NetworkUtils.createLink(Id.createLinkId("21"), n2, n1, network, 1, 1, 300, 1); + + Link l14 = NetworkUtils.createLink(Id.createLinkId("14"), n1, n4, network, 1, 1, 300, 1); + Link l41 = NetworkUtils.createLink(Id.createLinkId("41"), n4, n1, network, 1, 1, 300, 1); + + Link l23 = NetworkUtils.createLink(Id.createLinkId("23"), n2, n3, network, 1, 1, 300, 1); + Link l32 = NetworkUtils.createLink(Id.createLinkId("32"), n3, n2, network, 1, 1, 300, 1); + + Link l34 = NetworkUtils.createLink(Id.createLinkId("34"), n3, n4, network, 1, 1, 300, 1); + Link l43 = NetworkUtils.createLink(Id.createLinkId("43"), n4, n3, network, 1, 1, 300, 1); + + Link l15 = NetworkUtils.createLink(Id.createLinkId("15"), n1, n5, network, 1, 1, 300, 1); + Link l51 = NetworkUtils.createLink(Id.createLinkId("51"), n5, n1, network, 1, 1, 300, 1); + + Link l46 = NetworkUtils.createLink(Id.createLinkId("46"), n4, n6, network, 1, 1, 300, 1); + Link l64 = NetworkUtils.createLink(Id.createLinkId("64"), n6, n4, network, 1, 1, 300, 1); + + network.addLink(l01); + network.addLink(l10); + network.addLink(l12); + network.addLink(l21); + network.addLink(l14); + network.addLink(l41); + network.addLink(l23); + network.addLink(l32); + network.addLink(l34); + network.addLink(l43); + network.addLink(l15); + network.addLink(l51); + network.addLink(l46); + network.addLink(l64); + + for (Link link : network.getLinks().values()) { + link.setAllowedModes(Set.of(TransportMode.car)); + } + + return network; + } }