Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ apply from: scriptsLocation + 'tscfg.gradle'
repositories {
mavenCentral() //searches in bintray's repository 'jCenter', which contains Maven Central
maven { url 'https://www.jitpack.io' } // allows github repos as dependencies
maven { url 'https://oss.sonatype.org/service/local/repositories/snapshots/content' }
}

dependencies {
Expand All @@ -76,13 +77,16 @@ dependencies {

// todo CLEANUP following old dependencies
// ie³ power system utils
implementation('com.github.ie3-institute:PowerSystemUtils:1.5.3') {
implementation('com.github.ie3-institute:PowerSystemUtils:1.6-SNAPSHOT') {
exclude group: 'org.slf4j'
exclude group: 'org.apache.logging.log4j'
exclude group: 'com.github.ie3-institute'
exclude group: 'com.github.johanneshiry', module: 'OSMonaut'
}

// indriya
implementation 'tech.units:indriya:2.1.2'

// ie³ power system data model
implementation('com.github.ie3-institute:PowerSystemDataModel:2.0.1') {
exclude group: 'org.slf4j'
Expand Down
27 changes: 25 additions & 2 deletions src/main/scala/edu/ie3/osmogrid/guardian/OsmoGridGuardian.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,16 @@ import edu.ie3.osmogrid.io.output.ResultListener
import edu.ie3.osmogrid.io.output.ResultListener.{GridResult, ResultEvent}
import edu.ie3.osmogrid.lv.LvCoordinator
import edu.ie3.osmogrid.lv.LvCoordinator.ReqLvGrids
import edu.ie3.util.osm.OsmModel

import scala.jdk.CollectionConverters.*
import org.locationtech.jts.geom.{
Coordinate,
LinearRing,
Polygon,
GeometryFactory
}
import org.locationtech.jts.geom.impl.CoordinateArraySequenceFactory
import scala.jdk.CollectionConverters._
import scala.util.{Failure, Success, Try}

object OsmoGridGuardian {
Expand Down Expand Up @@ -59,7 +67,22 @@ object OsmoGridGuardian {
ctx.log.debug("Starting low voltage grid coordinator.")
val lvCoordinator = ctx.spawn(LvCoordinator(), "LvCoordinator")
ctx.watchWith(lvCoordinator, LvCoordinatorDied)
lvCoordinator ! ReqLvGrids(lvConfig, ctx.self)
val osmModel = OsmModel(
List.empty,
List.empty,
None,
new Polygon(
new LinearRing(
CoordinateArraySequenceFactory
.instance()
.create(Array.empty[Coordinate]),
new GeometryFactory()
),
Array.empty[LinearRing],
new GeometryFactory()
)
) // TODO actually use imported input data
lvCoordinator ! ReqLvGrids(lvConfig, osmModel, ctx.self)
awaitLvGrids(inputProvider, resultEventListener)
case unsupported =>
ctx.log.error(
Expand Down
159 changes: 156 additions & 3 deletions src/main/scala/edu/ie3/osmogrid/lv/LvCoordinator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,35 @@ import akka.actor.typed.scaladsl.{Behaviors, Routers}
import edu.ie3.datamodel.models.input.container.SubGridContainer
import edu.ie3.osmogrid.cfg.OsmoGridConfig
import edu.ie3.osmogrid.cfg.OsmoGridConfig.Generation.Lv
import edu.ie3.osmogrid.guardian.OsmoGridGuardian
import edu.ie3.osmogrid.guardian.OsmoGridGuardian.{
OsmoGridGuardianEvent,
RepLvGrids
}
import edu.ie3.osmogrid.lv.LvGenerator
import edu.ie3.util.osm.{OsmEntities, OsmModel}
import org.locationtech.jts.geom.impl.CoordinateArraySequence
import org.locationtech.jts.geom.{
Coordinate,
GeometryFactory,
LinearRing,
Polygon,
PrecisionModel
}

object LvCoordinator {
sealed trait LvCoordinatorEvent
final case class ReqLvGrids(
cfg: OsmoGridConfig.Generation.Lv,
osmModel: OsmModel,
replyTo: ActorRef[OsmoGridGuardianEvent]
) extends LvCoordinatorEvent
final case class RepLvGrids(grids: Vector[SubGridContainer])
extends LvCoordinatorEvent

// TODO replace with geoutils
private val DEFAULT_GEOMETRY_FACTORY: GeometryFactory =
new GeometryFactory(new PrecisionModel(), 4326)

def apply(): Behavior[LvCoordinatorEvent] = idle

Expand All @@ -35,7 +52,8 @@ object LvCoordinator {
amountOfRegionCoordinators,
distinctHouseConnections
),
replyTo
osmModel,
guardian
) =>
ctx.log.info("Starting generation of low voltage grids!")
/* TODO:
Expand Down Expand Up @@ -65,11 +83,146 @@ object LvCoordinator {
val lvRegionCoordinatorProxy =
ctx.spawn(lvRegionCoordinatorPool, "LvRegionCoordinatorPool")

replyTo ! RepLvGrids(Vector.empty[SubGridContainer])
Behaviors.stopped
val boundaries = buildBoundaryPolygons(osmModel)

def filterWay(polygon: Polygon, way: OsmEntities.Way) = {
val majority = (way.nodes.size + 1) / 2
way.nodes
.filter { node =>
polygon.covers(node.coordinates)
}
.sizeCompare(majority) > 0
}

def filterRelation(
polygon: Polygon,
relation: OsmEntities.Relation
): Boolean = {
val majority = (relation.elements.size + 1) / 2
relation.elements
.map(_.element)
.filter {
case node: OsmEntities.Node =>
polygon.covers(node.coordinates)
case way: OsmEntities.Way =>
filterWay(polygon, way)
case relation: OsmEntities.Relation =>
filterRelation(polygon, relation)
}
.sizeCompare(majority) > 0
}

// TODO this scala-esk way might be inefficient, find better way
boundaries.foreach { polygon =>
val nodes = osmModel.nodes.filter { node =>
polygon.covers(node.coordinates)
}
val ways = osmModel.ways.filter { way =>
filterWay(polygon, way)
}
val relations = osmModel.relations.map {
_.filter { relation =>
filterRelation(polygon, relation)
}
}

val model = OsmModel(nodes, ways, relations, polygon)

lvRegionCoordinatorProxy ! LvRegionCoordinator.ReqLvGrids(
model,
ctx.self
)
}

/* Wait for the incoming data and check, if all replies are received. */
awaitReplies(0, guardian)
case unsupported =>
ctx.log.error(s"Received unsupported message: $unsupported")
Behaviors.stopped
}
}

private def awaitReplies(
awaitedReplies: Int,
guardian: ActorRef[OsmoGridGuardianEvent],
collectedGrids: Vector[SubGridContainer] = Vector.empty
): Behaviors.Receive[LvCoordinatorEvent] = Behaviors.receive {
case (ctx, RepLvGrids(grids)) =>
val stillAwaited = awaitedReplies - 1
ctx.log.debug(
s"Received another ${grids.length} sub grids. ${if (stillAwaited == 0) "All requests are answered."
else s"Still awaiting $stillAwaited replies."}."
)
val updatedGrids = collectedGrids ++ grids
if (stillAwaited == 0) {
ctx.log.info(
s"Received ${updatedGrids.length} sub grid containers in total. Join and send them to the guardian."
)
guardian ! OsmoGridGuardian.RepLvGrids(updatedGrids)
Behaviors.stopped
} else
awaitReplies(stillAwaited, guardian, updatedGrids)
case (ctx, unsupported) =>
ctx.log.error(s"Received unsupported message: $unsupported")
Behaviors.stopped
}

private def buildBoundaryPolygons(osmModel: OsmModel) = {
extractBoundaries(osmModel).map { r =>
// combine all ways of a boundary relation to one sequence of coordinates
val coordinates = r.elements
.flatMap { case OsmEntities.RelationElement(element, "outer") =>
element match {
case way: OsmEntities.Way =>
way.nodes
case _ => List.empty
}
}
.map { el =>
el.coordinates.getCoordinate
}
.toArray

buildPolygon(coordinates)
}
}

/** Returns a list of boundary relations consisting of counties ("Gemeinden")
* and independent towns ("Kreisfreie Städte").
*
* Should work in most places in Germany.
* @param osmModel
* the OSM model
* @return
* list of boundary relations
*/
private def extractBoundaries(
osmModel: OsmModel
): List[OsmEntities.Relation] = {
val relations = osmModel.relations.getOrElse(throw new RuntimeException())

val boundaries = relations.filter {
_.tags.get("boundary").contains("administrative")
}

val municipalities =
boundaries.filter(_.tags.get("admin_level").contains("8"))

// independent towns with tag de:place=city https://forum.openstreetmap.org/viewtopic.php?id=21788
val independentCities = boundaries.filter { b =>
b.tags.get("admin_level").contains("6") && b.tags
.get("de:place")
.contains("city")
}

municipalities.appendedAll(independentCities)
}

// TODO replace with convenience function in PowerSystemUtils
private def buildPolygon(coordinates: Array[Coordinate]): Polygon = {
val arrayCoordinates = new CoordinateArraySequence(coordinates)
val linearRing =
new LinearRing(arrayCoordinates, DEFAULT_GEOMETRY_FACTORY)
new Polygon(linearRing, Array[LinearRing](), DEFAULT_GEOMETRY_FACTORY)
}
}
7 changes: 6 additions & 1 deletion src/main/scala/edu/ie3/osmogrid/lv/LvRegionCoordinator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,17 @@
package edu.ie3.osmogrid.lv

import akka.actor.typed.scaladsl.Behaviors

import akka.actor.typed.ActorRef
import edu.ie3.osmogrid.lv.LvCoordinator.LvCoordinatorEvent
import edu.ie3.osmogrid.lv.LvGenerator.LvGeneratorEvent
import edu.ie3.util.osm.OsmModel

object LvRegionCoordinator {
sealed trait LvRegionCoordinatorEvent
final case class ReqLvGrids(
osmModel: OsmModel,
replyTo: ActorRef[LvCoordinatorEvent]
) extends LvRegionCoordinatorEvent

def apply(
lvGeneratorPool: ActorRef[LvGeneratorEvent]
Expand Down