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
8 changes: 7 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,20 +77,25 @@ 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'
exclude group: 'org.apache.logging.log4j'
exclude group: 'com.github.ie3-institute'
}

implementation 'org.scalanlp:breeze_3:2.0'

// Graphs
implementation 'org.jgrapht:jgrapht-core:1.5.1'

Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/config/config-template.conf
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ generation: {
lv: {
amountOfGridGenerators: Int | 10 # Amount of actors actually building the grids
amountOfRegionCoordinators: Int | 5 # Amount of actors coordinating generation per municipality
loadDensity: Double # Estimation for energy usage of a building in W / m²
restrictSubgridsToLanduseAreas: Boolean | false # If sub grids should be bound to landuse areas
distinctHouseConnections: Boolean | false # If there shall be distinct lines for house connection
}
}
7 changes: 6 additions & 1 deletion src/main/scala/edu/ie3/osmogrid/cfg/ConfigFailFast.scala
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ object ConfigFailFast {
case Lv(
amountOfGridGenerators,
amountOfRegionCoordinators,
distinctHouseConnections
distinctHouseConnections,
loadDensity
) =>
if (amountOfGridGenerators < 1)
throw IllegalConfigException(
Expand All @@ -48,6 +49,10 @@ object ConfigFailFast {
throw IllegalConfigException(
s"The amount of lv region coordination actors needs to be at least 1 (provided: $amountOfRegionCoordinators)."
)
if (loadDensity < 0)
throw IllegalConfigException(
s"The load density of a building in an lv grid needs to be positive (provided: $loadDensity)."
)
}

private def checkInputConfig(input: OsmoGridConfig.Input): Unit =
Expand Down
30 changes: 26 additions & 4 deletions src/main/scala/edu/ie3/osmogrid/cfg/OsmoGridConfig.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* © 2021. TU Dortmund University,
* © 2022. TU Dortmund University,
* Institute of Energy Systems, Energy Efficiency and Energy Economics,
* Research group Distribution grid planning and operation
*/
Expand All @@ -19,7 +19,9 @@ object OsmoGridConfig {
final case class Lv(
amountOfGridGenerators: scala.Int,
amountOfRegionCoordinators: scala.Int,
distinctHouseConnections: scala.Boolean
distinctHouseConnections: scala.Boolean,
loadDensity: scala.Double,
restrictSubgridsToLanduseAreas: scala.Boolean
)
object Lv {
def apply(
Expand All @@ -35,12 +37,32 @@ object OsmoGridConfig {
amountOfRegionCoordinators =
if (c.hasPathOrNull("amountOfRegionCoordinators"))
c.getInt("amountOfRegionCoordinators")
else 50,
else 5,
distinctHouseConnections = c.hasPathOrNull(
"distinctHouseConnections"
) && c.getBoolean("distinctHouseConnections")
) && c.getBoolean("distinctHouseConnections"),
loadDensity = $_reqDbl(parentPath, c, "loadDensity", $tsCfgValidator),
restrictSubgridsToLanduseAreas = c.hasPathOrNull(
"restrictSubgridsToLanduseAreas"
) && c.getBoolean("restrictSubgridsToLanduseAreas")
)
}
private def $_reqDbl(
parentPath: java.lang.String,
c: com.typesafe.config.Config,
path: java.lang.String,
$tsCfgValidator: $TsCfgValidator
): scala.Double = {
if (c == null) 0
else
try c.getDouble(path)
catch {
case e: com.typesafe.config.ConfigException =>
$tsCfgValidator.addBadPath(parentPath + path, e)
0
}
}

}

def apply(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* © 2021. TU Dortmund University,
* Institute of Energy Systems, Energy Efficiency and Energy Economics,
* Research group Distribution grid planning and operation
*/

package edu.ie3.osmogrid.exception

final case class IllegalCalculationException(
msg: String = "",
cause: Throwable = None.orNull
) extends Exception(msg, cause)
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* © 2021. TU Dortmund University,
* Institute of Energy Systems, Energy Efficiency and Energy Economics,
* Research group Distribution grid planning and operation
*/

package edu.ie3.osmogrid.exception

class TestPreparationFailedException(
msg: String = "",
cause: Throwable = None.orNull
) extends Exception(msg, cause)
110 changes: 110 additions & 0 deletions src/main/scala/edu/ie3/osmogrid/lv/LoadCalculation.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
* © 2022. TU Dortmund University,
* Institute of Energy Systems, Energy Efficiency and Energy Economics,
* Research group Distribution grid planning and operation
*/

package edu.ie3.osmogrid.lv

import de.osmogrid.util.quantities.PowerDensity
import edu.ie3.osmogrid.exception.IllegalCalculationException
import edu.ie3.osmogrid.model.LoadLocation
import edu.ie3.osmogrid.model.WayUtils.RichClosedWay
import edu.ie3.util.osm.OsmEntities.Way
import edu.ie3.util.osm.{OsmEntities, OsmModel}
import org.slf4j.Logger
import tech.units.indriya.ComparableQuantity

import javax.measure.quantity.Power
import scala.collection.generic.DefaultSerializable
import scala.collection.immutable.{AbstractSeq, StrictOptimizedSeqOps}
import scala.util.{Failure, Success, Try}

trait LoadCalculation {

/** Determine the locations and the estimated consumed power of loads
*
* @param osmContainer
* Container with all available osm entities
* @param loadDensity
* Load density per square metre
* @param logger
* Logger to document the results
* @return
* A [[List]] of [[LoadLocation]]s
*/
protected def determineLoadLocations(
osmContainer: OsmModel,
loadDensity: ComparableQuantity[PowerDensity]
)(implicit logger: Logger): Seq[LoadLocation[_]] = {
val results =
loadLocationsFromOsmContainer(osmContainer, loadDensity).groupBy(
_._2.isSuccess
)

/* Report on failed entities */
results.get(false).map(_.map(_._1)) match {
case Some(failedEntityIds) =>
logger.warn(
s"Determination of load locations failed for the following ${failedEntityIds.length} entities:\n\t${failedEntityIds
.mkString("\n\t")}"
)
case None =>
logger.debug("No error during determination of load locations.")
}

/* Extract the valid results */
results
.get(true)
.map {
_.map {
case (_, Success(loadLocation)) => loadLocation
case (id, Failure(_)) =>
throw RuntimeException(
"Filtering of successful load location determination obviously went wrong."
)
}
}
.getOrElse(List.empty[LoadLocation[_]])
}

private def loadLocationsFromOsmContainer(
osmContainer: OsmModel,
loadDensity: ComparableQuantity[PowerDensity]
) = {
OsmModel
.extractBuildings(osmContainer.ways)
.map(way => way.osmId -> loadFromWay(way, loadDensity))
}

/** Determine the load of a building, if it is modeled as a way
*
* @param way
* Way, describing the building
* @param loadDensity
* Assumed load density
* @return
*/
private def loadFromWay(
way: Way,
loadDensity: ComparableQuantity[PowerDensity]
): Try[LoadLocation[Way]] = way match {
case closedWay @ OsmEntities.ClosedWay(
uuid,
osmId,
lastEdited,
tags,
nodes
) =>
closedWay.area.map { area =>
val load = loadDensity.multiply(area).asType(classOf[Power])
LoadLocation(closedWay.center, load, closedWay)
}
case OsmEntities.OpenWay(_, osmId, _, _, _) =>
Failure(
IllegalCalculationException(
s"Cannot determine the area of a building with id '$osmId' from an open way."
)
)
}
}
52 changes: 52 additions & 0 deletions src/main/scala/edu/ie3/osmogrid/lv/LoadClustering.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* © 2022. TU Dortmund University,
* Institute of Energy Systems, Energy Efficiency and Energy Economics,
* Research group Distribution grid planning and operation
*/

package edu.ie3.osmogrid.lv

import edu.ie3.osmogrid.model.LoadLocation
import edu.ie3.util.geo.GeoUtils
import edu.ie3.util.osm.OsmModel
import net.morbz.osmonaut.osm.LatLon

import scala.jdk.CollectionConverters._

trait LoadClustering {

def clusterLoads(
loadLocations: Seq[LoadLocation[_]],
osmContainer: OsmModel,
restrictSubgridsToLanduseAreas: Boolean
): Unit = {
/* Build sub groups if necessary */
val subGroups = if (restrictSubgridsToLanduseAreas) {
/* There shall be sub groups per land use area */
OsmModel
.extractLandUses(osmContainer.ways)
.map(landUseArea =>
loadLocations.filter(loadLocation =>
// TODO: Check if coordinate is inside landuse, whenever the PowerSystemUtils are ready
true
)
)
} else {
Seq(loadLocations)
}

/** TODO
* 1) Go through all sub groups and check, if they are fully connected. If not: Split them up.
* 2) Check for minimum cluster size and ignore those, that don't fulfill this requirement
* For each sub group:
* 3) Calculate the number of needed clusters
* 4) Determine clusters
* 5) Rebuild a graph per cluster
* 6) Possibly assign a unique number to the cluster
*
* Needed data
* - Targeted power of a substation (maybe as a list?)
* - Minimum power of a substation
*/
}
}
Loading