diff --git a/CHANGELOG.md b/CHANGELOG.md index 97ac7e74..ae61cc8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Switched from `osm4scala` to `openstreetmap.osmosis` [#409](https://github.com/ie3-institute/OSMoGrid/issues/409) - Changed transformer input parameter to PSDM requirements [#417](https://github.com/ie3-institute/OSMoGrid/issues/417) - Adapted run initialization [#404](https://github.com/ie3-institute/OSMoGrid/issues/404) +- Refactoring of 'getAllUniqueCombinations' to avoid nested loops [#431](https://github.com/ie3-institute/OSMoGrid/issues/431) ### Fixed - Fixed bug in `LvGridGeneratorSupport` [#388](https://github.com/ie3-institute/OSMoGrid/issues/388) diff --git a/src/main/scala/utils/Connections.scala b/src/main/scala/utils/Connections.scala index 915657c8..668682fe 100644 --- a/src/main/scala/utils/Connections.scala +++ b/src/main/scala/utils/Connections.scala @@ -6,6 +6,7 @@ package utils +import com.typesafe.scalalogging.LazyLogging import edu.ie3.datamodel.graph.{DistanceWeightedEdge, DistanceWeightedGraph} import edu.ie3.datamodel.models.input.NodeInput import edu.ie3.datamodel.models.input.connector.LineInput @@ -26,6 +27,7 @@ import utils.OsmoGridUtils.getAllUniqueCombinations import javax.measure.quantity.Length import scala.collection.mutable +import scala.collection.parallel.CollectionConverters._ import scala.jdk.CollectionConverters._ /** This utility object contains all known [[Connection]]s. @@ -101,7 +103,7 @@ case class Connections[T]( } } -object Connections { +object Connections extends LazyLogging { val log: Logger = LoggerFactory.getLogger(Connections.getClass) /** Utility object for connections. @@ -201,23 +203,34 @@ object Connections { val vertexes = graph.vertexSet().asScala val paths = vertexes.map { v => v -> shortestPath.getPaths(v) }.toMap - getAllUniqueCombinations(graph.vertexSet().asScala.toList).map { - case (nodeA, nodeB) => - val path = paths(nodeA).getPath(nodeB) + if (vertexes.size > 1000) + logger.info( + s"Needs to find shortest path connections for ${vertexes.size} vertices. This may take a while." + ) + val connections = + getAllUniqueCombinations(graph.vertexSet().asScala.toList).par.map { + case (nodeA, nodeB) => + val path = paths(nodeA).getPath(nodeB) + + if (path == null) { + throw GridException( + s"No path could be found between $nodeA and $nodeB, because either node is not connected to the graph." + ) + } - if (path == null) { - throw GridException( - s"No path could be found between $nodeA and $nodeB, because either node is not connected to the graph." + Connection( + nodeA, + nodeB, + Quantities.getQuantity(path.getWeight, Units.METRE), + Some(path) ) - } - - Connection( - nodeA, - nodeB, - Quantities.getQuantity(path.getWeight, Units.METRE), - Some(path) - ) - } + + }.toList + if (vertexes.size > 1000) + logger.info( + s"Finished search for shortest path connections for ${vertexes.size} vertices." + ) + connections } /** Method for creating undirected [[Connection]]s. Excluding connections that diff --git a/src/main/scala/utils/OsmoGridUtils.scala b/src/main/scala/utils/OsmoGridUtils.scala index 735ca9ad..3fcc1947 100644 --- a/src/main/scala/utils/OsmoGridUtils.scala +++ b/src/main/scala/utils/OsmoGridUtils.scala @@ -8,12 +8,7 @@ package utils import edu.ie3.datamodel.models.OperationTime import edu.ie3.datamodel.models.input.connector.Transformer2WInput -import edu.ie3.datamodel.models.input.container.{ - GraphicElements, - JointGridContainer, - RawGridElements, - SystemParticipants -} +import edu.ie3.datamodel.models.input.container.JointGridContainer import edu.ie3.datamodel.models.input.{NodeInput, OperatorInput} import edu.ie3.datamodel.models.voltagelevels.VoltageLevel import edu.ie3.osmogrid.cfg.OsmoGridConfig.Voltage @@ -34,7 +29,6 @@ import org.locationtech.jts.geom.{Coordinate, Polygon} import tech.units.indriya.ComparableQuantity import tech.units.indriya.unit.Units -import java.util import java.util.UUID import javax.measure.quantity.{Area, Power} import scala.collection.parallel.ParSeq @@ -139,36 +133,17 @@ object OsmoGridUtils { * @return * a list of all unique connections */ - def getAllUniqueCombinations[T]( - nodes: List[T] - ): List[(T, T)] = { + def getAllUniqueCombinations[T](nodes: List[T]): List[(T, T)] = { if (nodes.size < 2) { List.empty - } else if (nodes.size == 2) { - List((nodes(0), nodes(1))) } else { - val connections: util.List[(T, T)] = - new util.ArrayList[(T, T)] - - // algorithm to find all unique combinations - nodes.foreach(nodeA => { - nodes.foreach(nodeB => { - // it makes no sense to connect a node to itself => nodeA and nodeB cannot be the same - if (nodeA != nodeB) { - // two combinations possible - val t1 = (nodeA, nodeB) - val t2 = (nodeB, nodeA) - - // if none of the combinations is already added, the first combination is added - if (!connections.contains(t1) && !connections.contains(t2)) { - connections.add(t1) - } - } - }) - }) - - // returns all unique connections - connections.asScala.toList + for { + // Loops through all nodes as a and combines each node a with each b + // of the same nodes list. Nodes as b are restricted to those that + // occur later in the list than each node a respectively. + (a, i) <- nodes.zipWithIndex + b <- nodes.drop(i + 1) + } yield (a, b) } }