From d0d043a671a860c0aaa6528b6b3f01fad5b53f74 Mon Sep 17 00:00:00 2001 From: t-ober <63147366+t-ober@users.noreply.github.com> Date: Mon, 22 Nov 2021 11:59:59 +0100 Subject: [PATCH 01/15] include line sections --- src/main/python/powerFactory2json/pf2json.py | 2 +- .../python/powerFactory2json/pf2jsonUtils.py | 9 +++- .../model/PreprocessedPfGridModel.scala | 49 +++++++------------ .../model/RawPfGridModel.scala | 18 ++++--- .../powerFactory2psdm/model/entity/Line.scala | 14 +++--- .../model/entity/LineSection.scala | 41 ++++++++++++++++ 6 files changed, 82 insertions(+), 51 deletions(-) create mode 100644 src/main/scala/edu/ie3/powerFactory2psdm/model/entity/LineSection.scala diff --git a/src/main/python/powerFactory2json/pf2json.py b/src/main/python/powerFactory2json/pf2json.py index 6f7473a3..4fae5f49 100644 --- a/src/main/python/powerFactory2json/pf2json.py +++ b/src/main/python/powerFactory2json/pf2json.py @@ -28,7 +28,7 @@ def get_attribute_dicts(raw_elements, attributes_to_include): elements = [] single_node_connection = ["ElmLod", "ElmLodlv", "ElmLodmv", "ElmPvsys", "ElmSym", "ElmGenstat", "ElmXnet"] edges = ["ElmLne", "ElmCoup"] - typed_models = ["ElmLne", "ElmTr2"] + typed_models = ["ElmLne", "ElmTr2", "ElmLnesec"] for raw_element in raw_elements: element_class = raw_element.GetClassName() element = get_attribute_dict(raw_element, attributes_to_include) diff --git a/src/main/python/powerFactory2json/pf2jsonUtils.py b/src/main/python/powerFactory2json/pf2jsonUtils.py index 7f687463..22577e36 100644 --- a/src/main/python/powerFactory2json/pf2jsonUtils.py +++ b/src/main/python/powerFactory2json/pf2jsonUtils.py @@ -13,11 +13,15 @@ 'extGrid': '*.ElmXnet', 'powerPlants': '*.ElmSym', # renewable power plants 'pvs': '*.ElmPvsys', # additional photovoltaic units - 'switches': '*.ElmCoup' + 'switches': '*.ElmCoup', + 'lineSections': '*.ElmLnesec' } attributes4export = { + 'lineSections': [ + "dline" + ], 'conElms': [], 'nodes': [ "vtarget", @@ -27,7 +31,8 @@ ], 'lines': [ "dline", - "GPScoords" + "GPScoords", + "cubsecs" ], 'lineTypes': [ "rline", diff --git a/src/main/scala/edu/ie3/powerFactory2psdm/model/PreprocessedPfGridModel.scala b/src/main/scala/edu/ie3/powerFactory2psdm/model/PreprocessedPfGridModel.scala index dd6a15e4..4976cdd1 100644 --- a/src/main/scala/edu/ie3/powerFactory2psdm/model/PreprocessedPfGridModel.scala +++ b/src/main/scala/edu/ie3/powerFactory2psdm/model/PreprocessedPfGridModel.scala @@ -8,36 +8,10 @@ package edu.ie3.powerFactory2psdm.model import com.typesafe.scalalogging.LazyLogging import edu.ie3.powerFactory2psdm.config.ConversionConfigUtils.ParameterSource -import edu.ie3.powerFactory2psdm.exception.pf.{ - ConversionException, - GridConfigurationException, - MissingParameterException -} -import edu.ie3.powerFactory2psdm.model.RawPfGridModel.{ - LineTypes, - Lines, - Loads, - LoadsLV, - LoadsMV, - Nodes, - ProjectSettings, - StatGen, - Switches, - TrafoTypes2w, - Trafos2w -} -import edu.ie3.powerFactory2psdm.model.entity.{ - Line, - Load, - Node, - StaticGenerator, - Switch, - Transformer2W -} -import edu.ie3.powerFactory2psdm.model.entity.types.{ - LineType, - Transformer2WType -} +import edu.ie3.powerFactory2psdm.exception.pf.{ConversionException, GridConfigurationException, MissingParameterException} +import edu.ie3.powerFactory2psdm.model.RawPfGridModel.{LineSections, LineTypes, Lines, Loads, LoadsLV, LoadsMV, Nodes, ProjectSettings, StatGen, Switches, TrafoTypes2w, Trafos2w} +import edu.ie3.powerFactory2psdm.model.entity.{Line, LineSection, Load, Node, StaticGenerator, Switch, Transformer2W} +import edu.ie3.powerFactory2psdm.model.entity.types.{LineType, Transformer2WType} import edu.ie3.powerFactory2psdm.model.setting.{ConversionPrefixes, UnitSystem} /** Representation of the grid which is to be converted to a PSDM @@ -108,6 +82,10 @@ object PreprocessedPfGridModel extends LazyLogging { logger debug "There are no lines in the grid." List.empty[LineTypes] }) + val rawLineSections = rawGrid.lineSections.getOrElse({ + logger debug "There are no line sections in the grid." + List.empty[LineSections] + }) val rawSwitches = rawGrid.switches.getOrElse({ logger debug "There are no switches in the grid." List.empty[Switches] @@ -129,7 +107,7 @@ object PreprocessedPfGridModel extends LazyLogging { }) val models = - rawNodes ++ rawLines ++ rawLineTypes ++ rawSwitches ++ rawTrafos2W ++ rawTrafoTpyes2W ++ rawLoads ++ rawStaticGenerators + rawNodes ++ rawLines ++ rawLineTypes ++ rawLineSections ++ rawSwitches ++ rawTrafos2W ++ rawTrafoTpyes2W ++ rawLoads ++ rawStaticGenerators val modelIds = models.map { case node: Nodes => node.id.getOrElse( @@ -145,6 +123,12 @@ object PreprocessedPfGridModel extends LazyLogging { s"Line type $lineType has no defined id" ) ) + case lineSection: LineSections => + lineSection.id.getOrElse( + throw MissingParameterException( + s"Line section $lineSection has no defined id" + ) + ) case switch: Switches => switch.id.getOrElse( throw MissingParameterException(s"Switch $switch has no defined id") @@ -195,7 +179,8 @@ object PreprocessedPfGridModel extends LazyLogging { } val nodes = rawNodes.map(Node.build) - val lines = rawLines.map(line => Line.build(line)) + val lineSectionsMap = LineSection.buildLineSectionMap(rawLineSections) + val lines = rawLines.map(line => Line.build(line, lineSectionsMap)) val lineTypes = rawLineTypes.map(LineType.build) val switches = rawSwitches.flatMap(Switch.maybeBuild) val transformers2W = rawTrafos2W.map(Transformer2W.build) diff --git a/src/main/scala/edu/ie3/powerFactory2psdm/model/RawPfGridModel.scala b/src/main/scala/edu/ie3/powerFactory2psdm/model/RawPfGridModel.scala index 43bcfe67..3712412e 100644 --- a/src/main/scala/edu/ie3/powerFactory2psdm/model/RawPfGridModel.scala +++ b/src/main/scala/edu/ie3/powerFactory2psdm/model/RawPfGridModel.scala @@ -1,14 +1,9 @@ -/* - * © 2021. TU Dortmund University, - * Institute of Energy Systems, Energy Efficiency and Energy Economics, - * Research group Distribution grid planning and operation - */ - package edu.ie3.powerFactory2psdm.model import edu.ie3.powerFactory2psdm.model.RawPfGridModel.{ ExtGrid, PowerPlants, Trafos3w, + LineSections, Lines, Pvs, Switches, @@ -29,6 +24,7 @@ final case class RawPfGridModel( loadsMV: Option[List[LoadsMV]], nodes: Option[List[Nodes]], projectSettings: Option[List[ProjectSettings]], + lineSections: Option[List[LineSections]], powerPlants: Option[List[PowerPlants]], trafoTypes3w: Option[List[TrafoTypes3w]], pvs: Option[List[Pvs]], @@ -52,8 +48,6 @@ object RawPfGridModel { bus2Id: Option[String] ) - final case class Pvs() - final case class ConElms(id: Option[String], pfCls: Option[String]) final case class Loads( @@ -102,6 +96,14 @@ object RawPfGridModel { final case class ExtGrid(id: Option[String], busId: Option[String]) + final case class LineSections( + id: Option[String], + dline: Option[Double], + typeId: Option[String] + ) + + final case class Pvs() + final case class TrafoTypes2w( utrnH: Option[Double], nntap0: Option[Double], diff --git a/src/main/scala/edu/ie3/powerFactory2psdm/model/entity/Line.scala b/src/main/scala/edu/ie3/powerFactory2psdm/model/entity/Line.scala index 5fdf1a34..43a610be 100644 --- a/src/main/scala/edu/ie3/powerFactory2psdm/model/entity/Line.scala +++ b/src/main/scala/edu/ie3/powerFactory2psdm/model/entity/Line.scala @@ -22,14 +22,15 @@ final case class Line( id: String, nodeAId: String, nodeBId: String, - typeId: String, + typeId: Option[String], + lineSections: Option[List[LineSection]], length: Double, gpsCoords: Option[(List[(Double, Double)])] ) extends EntityModel with Edge object Line { - def build(rawLine: Lines): Line = { + def build(rawLine: Lines, lineSectionsMap: Map[String, List[LineSection]]): Line = { val id = rawLine.id.getOrElse( throw MissingParameterException(s"There is no id for line $rawLine") ) @@ -39,12 +40,8 @@ object Line { val nodeBId = rawLine.bus2Id.getOrElse( throw MissingParameterException(s"Line: $id has no defined node b") ) - val typId = rawLine.typeId.getOrElse( - throw MissingParameterException( - s"Line: $id has no defined type - line conversion without defined type" + - s" is not supported " - ) - ) + val typId = rawLine.typeId + val lineSections = lineSectionsMap.get(id) val length = rawLine.dline.getOrElse( throw MissingParameterException( s"Line: $id has no defined length" @@ -65,6 +62,7 @@ object Line { nodeAId, nodeBId, typId, + lineSections, length, gpsCoords ) diff --git a/src/main/scala/edu/ie3/powerFactory2psdm/model/entity/LineSection.scala b/src/main/scala/edu/ie3/powerFactory2psdm/model/entity/LineSection.scala new file mode 100644 index 00000000..8f521157 --- /dev/null +++ b/src/main/scala/edu/ie3/powerFactory2psdm/model/entity/LineSection.scala @@ -0,0 +1,41 @@ +package edu.ie3.powerFactory2psdm.model.entity + +import edu.ie3.powerFactory2psdm.exception.pf.{ConversionException, MissingParameterException} +import edu.ie3.powerFactory2psdm.model.RawPfGridModel.LineSections +import org.apache.commons.lang3.Conversion + +final case class LineSection( + id: String, + length: Double, + typeId: String +) extends EntityModel + + +object LineSection { + + def build(rawLineSection: LineSections): LineSection = { + val id = rawLineSection.id.getOrElse( + throw MissingParameterException(s"There is no id for line section $rawLineSection") + ) + val length = rawLineSection.dline.getOrElse( + throw MissingParameterException(s"There is no defined length for line section $id") + ) + val typeId = rawLineSection.typeId.getOrElse( + throw MissingParameterException(s"There is no defined type line section $id") + ) + LineSection(id, length, typeId) + } + + def buildLineSectionMap(rawLineSections: List[LineSections]): Map[String, List[LineSection]] = { + val lineSections = rawLineSections.map(build) + lineSections.groupBy(lineSection => getLineId(lineSection.id)) + } + + def getLineId(lineSectionId: String): String = { + val lineIdRegEx = raw".+?(?=\\[\w\s]*\.ElmLnesec)".r + lineIdRegEx.findFirstIn(lineSectionId) match { + case Some(id) => id + case None => throw ConversionException(s"Can't extract line id from line section: $lineSectionId") + } + } +} From 3b3f25d71d50c884440ff9c7cfc73e979b96eaf5 Mon Sep 17 00:00:00 2001 From: t-ober <63147366+t-ober@users.noreply.github.com> Date: Mon, 22 Nov 2021 16:37:59 +0100 Subject: [PATCH 02/15] line type conversion with sections --- .../converter/LineConverter.scala | 41 ++++++++---- .../converter/types/LineTypeConverter.scala | 66 +++++++++++++++++++ .../model/PreprocessedPfGridModel.scala | 36 ++++++++-- .../model/RawPfGridModel.scala | 6 ++ .../powerFactory2psdm/model/entity/Line.scala | 5 +- .../model/entity/LineSection.scala | 39 ++++++++--- 6 files changed, 167 insertions(+), 26 deletions(-) diff --git a/src/main/scala/edu/ie3/powerFactory2psdm/converter/LineConverter.scala b/src/main/scala/edu/ie3/powerFactory2psdm/converter/LineConverter.scala index e6c6eec3..8c661676 100644 --- a/src/main/scala/edu/ie3/powerFactory2psdm/converter/LineConverter.scala +++ b/src/main/scala/edu/ie3/powerFactory2psdm/converter/LineConverter.scala @@ -47,34 +47,53 @@ object LineConverter { lineTypes: Map[String, LineTypeInput] ): List[LineInput] = { lines.map(line => { + val lineType = (line.typeId, line.lineSections) match { + case (Some(lineTypeId), None) => + getLineType(lineTypeId, lineTypes).getOrElse( + throw ConversionException( + s"Could not convert line: $line due to failed line type retrieval." + ) + ) + case (None, Some(lineSections)) => + LineTypeConverter.convert( + line.id, + line.length, + lineSections, + lineTypes + ) + case (Some(_), Some(_)) => { + throw ConversionException( + s"Line: ${line.id} has line types and line sections which both define line types. " + + s"This error should not happen since PowerFactory only lets you define one of the two." + ) + } + case (None, None) => + throw ConversionException( + s"Could not convert line: ${line.id} since there is no defined type in the model and there are no line section that specify the type" + ) + } ( getNode(line.nodeAId, nodes), - getNode(line.nodeBId, nodes), - getLineType(line.typeId, lineTypes) + getNode(line.nodeBId, nodes) ) match { - case (Success(nodeA), Success(nodeB), Success(lineType)) => - convert( + case (Success(nodeA), Success(nodeB)) => + LineConverter.convert( line, lineLengthPrefix, lineType, nodeA, nodeB ) - case (Failure(exc), _, _) => + case (Failure(exc), _) => throw ConversionException( s"Can't retrieve ${line.nodeAId} for line ${line.id}", exc ) - case (_, Failure(exc), _) => + case (_, Failure(exc)) => throw ConversionException( s"Can't retrieve ${line.nodeBId} for line ${line.id}", exc ) - case (_, _, Failure(exc)) => - throw ConversionException( - s"Could not convert line: $line due to failed line type retrieval.", - exc - ) } }) } diff --git a/src/main/scala/edu/ie3/powerFactory2psdm/converter/types/LineTypeConverter.scala b/src/main/scala/edu/ie3/powerFactory2psdm/converter/types/LineTypeConverter.scala index 0f144f88..9761bc3c 100644 --- a/src/main/scala/edu/ie3/powerFactory2psdm/converter/types/LineTypeConverter.scala +++ b/src/main/scala/edu/ie3/powerFactory2psdm/converter/types/LineTypeConverter.scala @@ -7,10 +7,16 @@ package edu.ie3.powerFactory2psdm.converter.types import edu.ie3.datamodel.models.input.connector.`type`.LineTypeInput import edu.ie3.powerFactory2psdm.exception.pf.ConversionException +import edu.ie3.powerFactory2psdm.model.entity.LineSection import edu.ie3.powerFactory2psdm.model.entity.types.LineType import edu.ie3.powerFactory2psdm.util.QuantityUtils.RichQuantityDouble +import edu.ie3.util.quantities.interfaces.SpecificConductance +import tech.units.indriya.ComparableQuantity +import tech.units.indriya.quantity.Quantities import java.util.UUID +import javax.measure.quantity.{ElectricCurrent, ElectricPotential} +import scala.math.{abs, min} import scala.util.{Failure, Success, Try} /** Functionality to translate a [[LineType]] to a [[LineTypeInput]] @@ -31,6 +37,66 @@ object LineTypeConverter { ) } + def convert( + lineId: String, + lineLength: Double, + lineSections: List[LineSection], + lineTypes: Map[String, LineTypeInput] + ): LineTypeInput = { + + val aggregatedLineSectionLength = + lineSections.map(section => section.length).sum + + val totalLength = lineLength - aggregatedLineSectionLength match { + case x if abs(x) < 1e-3 => lineLength + case x if x < 0 => aggregatedLineSectionLength + case x if x > 0 => lineLength + } + + if (abs(lineLength - aggregatedLineSectionLength) < 1e-3) { + val weightedLineTypes = lineSections.map(section => { + val lineType = getLineType(section.typeId, lineTypes) + .getOrElse( + throw ConversionException( + s"Can't find line type ${section.typeId} of section ${section.id} within the converted line types." + ) + ) + (section.length, lineType) + }) + val lineType = new LineTypeInput( + UUID.randomUUID(), + "Custom_line_type_" + lineId, + 0.asMicroSiemensPerKilometre, + 0.asMicroSiemensPerKilometre, + 0.asOhmPerKilometre, + 0.asOhmPerKilometre, + Double.MaxValue.asKiloAmpere, + Double.MaxValue.asKiloVolt + ) + + val weightedLineType = + weightedLineTypes.foldLeft(lineType)((averageType, current) => { + val currentLine = current._2 + val weightingFactor = current._1 / totalLength + new LineTypeInput( + averageType.getUuid, + averageType.getId, + averageType.getB.add(currentLine.getB.multiply(weightingFactor)), + averageType.getG.add(currentLine.getG.multiply(weightingFactor)), + averageType.getR.add(currentLine.getR.multiply(weightingFactor)), + averageType.getX.add(currentLine.getX.multiply(weightingFactor)), + if (averageType.getiMax().isLessThan(currentLine.getiMax())) + averageType.getiMax() + else currentLine.getiMax(), + if (averageType.getvRated().equals(Double.MaxValue.asKiloVolt)) + currentLine.getvRated() + else averageType.getvRated() + ) + }) + weightedLineType + } + } + def getLineType( id: String, lineTypes: Map[String, LineTypeInput] diff --git a/src/main/scala/edu/ie3/powerFactory2psdm/model/PreprocessedPfGridModel.scala b/src/main/scala/edu/ie3/powerFactory2psdm/model/PreprocessedPfGridModel.scala index 4976cdd1..cd36b3a3 100644 --- a/src/main/scala/edu/ie3/powerFactory2psdm/model/PreprocessedPfGridModel.scala +++ b/src/main/scala/edu/ie3/powerFactory2psdm/model/PreprocessedPfGridModel.scala @@ -8,10 +8,38 @@ package edu.ie3.powerFactory2psdm.model import com.typesafe.scalalogging.LazyLogging import edu.ie3.powerFactory2psdm.config.ConversionConfigUtils.ParameterSource -import edu.ie3.powerFactory2psdm.exception.pf.{ConversionException, GridConfigurationException, MissingParameterException} -import edu.ie3.powerFactory2psdm.model.RawPfGridModel.{LineSections, LineTypes, Lines, Loads, LoadsLV, LoadsMV, Nodes, ProjectSettings, StatGen, Switches, TrafoTypes2w, Trafos2w} -import edu.ie3.powerFactory2psdm.model.entity.{Line, LineSection, Load, Node, StaticGenerator, Switch, Transformer2W} -import edu.ie3.powerFactory2psdm.model.entity.types.{LineType, Transformer2WType} +import edu.ie3.powerFactory2psdm.exception.pf.{ + ConversionException, + GridConfigurationException, + MissingParameterException +} +import edu.ie3.powerFactory2psdm.model.RawPfGridModel.{ + LineSections, + LineTypes, + Lines, + Loads, + LoadsLV, + LoadsMV, + Nodes, + ProjectSettings, + StatGen, + Switches, + TrafoTypes2w, + Trafos2w +} +import edu.ie3.powerFactory2psdm.model.entity.{ + Line, + LineSection, + Load, + Node, + StaticGenerator, + Switch, + Transformer2W +} +import edu.ie3.powerFactory2psdm.model.entity.types.{ + LineType, + Transformer2WType +} import edu.ie3.powerFactory2psdm.model.setting.{ConversionPrefixes, UnitSystem} /** Representation of the grid which is to be converted to a PSDM diff --git a/src/main/scala/edu/ie3/powerFactory2psdm/model/RawPfGridModel.scala b/src/main/scala/edu/ie3/powerFactory2psdm/model/RawPfGridModel.scala index 3712412e..8c68949a 100644 --- a/src/main/scala/edu/ie3/powerFactory2psdm/model/RawPfGridModel.scala +++ b/src/main/scala/edu/ie3/powerFactory2psdm/model/RawPfGridModel.scala @@ -1,3 +1,9 @@ +/* + * © 2021. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation + */ + package edu.ie3.powerFactory2psdm.model import edu.ie3.powerFactory2psdm.model.RawPfGridModel.{ ExtGrid, diff --git a/src/main/scala/edu/ie3/powerFactory2psdm/model/entity/Line.scala b/src/main/scala/edu/ie3/powerFactory2psdm/model/entity/Line.scala index 43a610be..957f5619 100644 --- a/src/main/scala/edu/ie3/powerFactory2psdm/model/entity/Line.scala +++ b/src/main/scala/edu/ie3/powerFactory2psdm/model/entity/Line.scala @@ -30,7 +30,10 @@ final case class Line( with Edge object Line { - def build(rawLine: Lines, lineSectionsMap: Map[String, List[LineSection]]): Line = { + def build( + rawLine: Lines, + lineSectionsMap: Map[String, List[LineSection]] + ): Line = { val id = rawLine.id.getOrElse( throw MissingParameterException(s"There is no id for line $rawLine") ) diff --git a/src/main/scala/edu/ie3/powerFactory2psdm/model/entity/LineSection.scala b/src/main/scala/edu/ie3/powerFactory2psdm/model/entity/LineSection.scala index 8f521157..de96488f 100644 --- a/src/main/scala/edu/ie3/powerFactory2psdm/model/entity/LineSection.scala +++ b/src/main/scala/edu/ie3/powerFactory2psdm/model/entity/LineSection.scala @@ -1,32 +1,48 @@ +/* + * © 2021. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation + */ + package edu.ie3.powerFactory2psdm.model.entity -import edu.ie3.powerFactory2psdm.exception.pf.{ConversionException, MissingParameterException} +import edu.ie3.powerFactory2psdm.exception.pf.{ + ConversionException, + MissingParameterException +} import edu.ie3.powerFactory2psdm.model.RawPfGridModel.LineSections import org.apache.commons.lang3.Conversion final case class LineSection( - id: String, - length: Double, - typeId: String + id: String, + length: Double, + typeId: String ) extends EntityModel - object LineSection { def build(rawLineSection: LineSections): LineSection = { val id = rawLineSection.id.getOrElse( - throw MissingParameterException(s"There is no id for line section $rawLineSection") + throw MissingParameterException( + s"There is no id for line section $rawLineSection" + ) ) val length = rawLineSection.dline.getOrElse( - throw MissingParameterException(s"There is no defined length for line section $id") + throw MissingParameterException( + s"There is no defined length for line section $id" + ) ) val typeId = rawLineSection.typeId.getOrElse( - throw MissingParameterException(s"There is no defined type line section $id") + throw MissingParameterException( + s"There is no defined type line section $id" + ) ) LineSection(id, length, typeId) } - def buildLineSectionMap(rawLineSections: List[LineSections]): Map[String, List[LineSection]] = { + def buildLineSectionMap( + rawLineSections: List[LineSections] + ): Map[String, List[LineSection]] = { val lineSections = rawLineSections.map(build) lineSections.groupBy(lineSection => getLineId(lineSection.id)) } @@ -35,7 +51,10 @@ object LineSection { val lineIdRegEx = raw".+?(?=\\[\w\s]*\.ElmLnesec)".r lineIdRegEx.findFirstIn(lineSectionId) match { case Some(id) => id - case None => throw ConversionException(s"Can't extract line id from line section: $lineSectionId") + case None => + throw ConversionException( + s"Can't extract line id from line section: $lineSectionId" + ) } } } From 9f817c875462c906129e0b389445eeff3b6e5692 Mon Sep 17 00:00:00 2001 From: t-ober <63147366+t-ober@users.noreply.github.com> Date: Mon, 22 Nov 2021 16:44:48 +0100 Subject: [PATCH 03/15] fmt --- .../ie3/powerFactory2psdm/converter/LineConverter.scala | 2 -- .../converter/types/LineTypeConverter.scala | 7 +------ 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/main/scala/edu/ie3/powerFactory2psdm/converter/LineConverter.scala b/src/main/scala/edu/ie3/powerFactory2psdm/converter/LineConverter.scala index 8c661676..60787ed0 100644 --- a/src/main/scala/edu/ie3/powerFactory2psdm/converter/LineConverter.scala +++ b/src/main/scala/edu/ie3/powerFactory2psdm/converter/LineConverter.scala @@ -7,7 +7,6 @@ package edu.ie3.powerFactory2psdm.converter import edu.ie3.datamodel.models.StandardUnits -import tech.units.indriya.unit.Units.METRE import edu.ie3.datamodel.models.input.NodeInput import edu.ie3.datamodel.models.input.connector.LineInput import edu.ie3.datamodel.models.input.connector.`type`.LineTypeInput @@ -20,7 +19,6 @@ import edu.ie3.powerFactory2psdm.exception.pf.ConversionException import edu.ie3.powerFactory2psdm.model.entity.Line import edu.ie3.powerFactory2psdm.model.setting.ConversionPrefixes.ConversionPrefix import edu.ie3.powerFactory2psdm.util.QuantityUtils.RichQuantityDouble -import tech.units.indriya.quantity.Quantities import java.util.UUID import scala.util.{Failure, Success} diff --git a/src/main/scala/edu/ie3/powerFactory2psdm/converter/types/LineTypeConverter.scala b/src/main/scala/edu/ie3/powerFactory2psdm/converter/types/LineTypeConverter.scala index 9761bc3c..39786cdc 100644 --- a/src/main/scala/edu/ie3/powerFactory2psdm/converter/types/LineTypeConverter.scala +++ b/src/main/scala/edu/ie3/powerFactory2psdm/converter/types/LineTypeConverter.scala @@ -10,13 +10,8 @@ import edu.ie3.powerFactory2psdm.exception.pf.ConversionException import edu.ie3.powerFactory2psdm.model.entity.LineSection import edu.ie3.powerFactory2psdm.model.entity.types.LineType import edu.ie3.powerFactory2psdm.util.QuantityUtils.RichQuantityDouble -import edu.ie3.util.quantities.interfaces.SpecificConductance -import tech.units.indriya.ComparableQuantity -import tech.units.indriya.quantity.Quantities - import java.util.UUID -import javax.measure.quantity.{ElectricCurrent, ElectricPotential} -import scala.math.{abs, min} +import scala.math.abs import scala.util.{Failure, Success, Try} /** Functionality to translate a [[LineType]] to a [[LineTypeInput]] From 22461e28884c67420b6616a093cf1739e6bff031 Mon Sep 17 00:00:00 2001 From: t-ober <63147366+t-ober@users.noreply.github.com> Date: Tue, 23 Nov 2021 07:43:37 +0100 Subject: [PATCH 04/15] clean up --- .../converter/types/LineTypeConverter.scala | 3 -- .../common/ConverterTestData.scala | 3 +- .../types/LineTypeConverterSpec.scala | 47 +++++++++++++++++++ .../model/entity/LineSpec.scala | 8 ++-- 4 files changed, 53 insertions(+), 8 deletions(-) diff --git a/src/main/scala/edu/ie3/powerFactory2psdm/converter/types/LineTypeConverter.scala b/src/main/scala/edu/ie3/powerFactory2psdm/converter/types/LineTypeConverter.scala index 39786cdc..863a9d13 100644 --- a/src/main/scala/edu/ie3/powerFactory2psdm/converter/types/LineTypeConverter.scala +++ b/src/main/scala/edu/ie3/powerFactory2psdm/converter/types/LineTypeConverter.scala @@ -47,8 +47,6 @@ object LineTypeConverter { case x if x < 0 => aggregatedLineSectionLength case x if x > 0 => lineLength } - - if (abs(lineLength - aggregatedLineSectionLength) < 1e-3) { val weightedLineTypes = lineSections.map(section => { val lineType = getLineType(section.typeId, lineTypes) .getOrElse( @@ -89,7 +87,6 @@ object LineTypeConverter { ) }) weightedLineType - } } def getLineType( diff --git a/src/test/scala/edu/ie3/powerFactory2psdm/common/ConverterTestData.scala b/src/test/scala/edu/ie3/powerFactory2psdm/common/ConverterTestData.scala index ecc61af7..a62f206f 100644 --- a/src/test/scala/edu/ie3/powerFactory2psdm/common/ConverterTestData.scala +++ b/src/test/scala/edu/ie3/powerFactory2psdm/common/ConverterTestData.scala @@ -493,7 +493,8 @@ object ConverterTestData extends LazyLogging { "someLine", "someNode", "someSlackNode", - "someLineType", + Some("someLineType"), + None, 1.5, Some(List((11.1123, 52.1425), (11.1153, 52.1445))) ), diff --git a/src/test/scala/edu/ie3/powerFactory2psdm/converter/types/LineTypeConverterSpec.scala b/src/test/scala/edu/ie3/powerFactory2psdm/converter/types/LineTypeConverterSpec.scala index 68355149..24073c83 100644 --- a/src/test/scala/edu/ie3/powerFactory2psdm/converter/types/LineTypeConverterSpec.scala +++ b/src/test/scala/edu/ie3/powerFactory2psdm/converter/types/LineTypeConverterSpec.scala @@ -6,10 +6,16 @@ package edu.ie3.powerFactory2psdm.converter.types +import edu.ie3.datamodel.models.input.connector.`type`.LineTypeInput import edu.ie3.powerFactory2psdm.common.ConverterTestData.getLineTypePair +import edu.ie3.powerFactory2psdm.model.entity.LineSection +import edu.ie3.powerFactory2psdm.util.QuantityUtils.RichQuantityDouble +import edu.ie3.scalatest.QuantityMatchers.equalWithTolerance import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpecLike +import java.util.UUID + class LineTypeConverterSpec extends Matchers with AnyWordSpecLike { "The line type converter" should { @@ -26,5 +32,46 @@ class LineTypeConverterSpec extends Matchers with AnyWordSpecLike { actual.getiMax shouldBe expected.getiMax actual.getvRated shouldBe expected.getvRated } + + "generate a line type from line sections" in { + val lineTypes = Map( + "lineTypeA" -> new LineTypeInput( + UUID.randomUUID(), + "lineTypeA", + 1.asMicroSiemensPerKilometre, + 1.asMicroSiemensPerKilometre, + 1.asOhmPerKilometre, + 1.asOhmPerKilometre, + 1.asKiloAmpere, + 20.asKiloVolt + ), + "lineTypeB" -> new LineTypeInput( + UUID.randomUUID(), + "lineTypeB", + 2.asMicroSiemensPerKilometre, + 2.asMicroSiemensPerKilometre, + 2.asOhmPerKilometre, + 2.asOhmPerKilometre, + 2.asKiloAmpere, + 20.asKiloVolt + ) + ) + val lineSections = List(LineSection( + id = "lineSectionA", + length = 1, + typeId = "lineTypeA" + ), LineSection( + id = "lineSectionB", + length = 1, + typeId = "lineTypeB" + )) + val actual = LineTypeConverter.convert("testLine", 2, lineSections, lineTypes) + actual.getB should equalWithTolerance(1.5.asMicroSiemensPerKilometre) + actual.getG should equalWithTolerance(1.5.asMicroSiemensPerKilometre) + actual.getR should equalWithTolerance(1.5.asOhmPerKilometre) + actual.getX should equalWithTolerance(1.5.asOhmPerKilometre) + actual.getiMax should equalWithTolerance(1.asKiloAmpere) + actual.getvRated should equalWithTolerance(20.asKiloVolt) + } } } diff --git a/src/test/scala/edu/ie3/powerFactory2psdm/model/entity/LineSpec.scala b/src/test/scala/edu/ie3/powerFactory2psdm/model/entity/LineSpec.scala index 196bc605..8b8702e4 100644 --- a/src/test/scala/edu/ie3/powerFactory2psdm/model/entity/LineSpec.scala +++ b/src/test/scala/edu/ie3/powerFactory2psdm/model/entity/LineSpec.scala @@ -32,26 +32,26 @@ class LineSpec extends Matchers with AnyWordSpecLike { "throw an exception if the id is missing" in { val line = input.copy(id = None) - val exc = intercept[MissingParameterException](Line.build(line)) + val exc = intercept[MissingParameterException](Line.build(line, Map())) exc.getMessage shouldBe s"There is no id for line $line" } "throw an exception if the bus1Id is missing" in { val id = "BrokenLine1.ElmLne" val line = input.copy(id = Some(id), bus1Id = None) - val exc = intercept[MissingParameterException](Line.build(line)) + val exc = intercept[MissingParameterException](Line.build(line, Map())) exc.getMessage shouldBe s"Line: $id has no defined node a" } "throw an exception if the bus2Id is missing" in { val id = "BrokenLine2.ElmLne" val line = input.copy(id = Some(id), bus2Id = None) - val exc = intercept[MissingParameterException](Line.build(line)) + val exc = intercept[MissingParameterException](Line.build(line, Map())) exc.getMessage shouldBe s"Line: $id has no defined node b" } "build a fully configured line correctly" in { - val line = Line.build(input) + val line = Line.build(input, Map()) line.id shouldBe "SomeLine.ElmLne" line.nodeAId shouldBe "SomeBusA" line.nodeBId shouldBe "SomeBusB" From 400b86e7c8f6c5b2d697dede3b29ccca91d767db Mon Sep 17 00:00:00 2001 From: t-ober <63147366+t-ober@users.noreply.github.com> Date: Tue, 23 Nov 2021 07:45:58 +0100 Subject: [PATCH 05/15] fmt --- .../converter/types/LineTypeConverter.scala | 76 +++++++++---------- .../types/LineTypeConverterSpec.scala | 24 +++--- 2 files changed, 52 insertions(+), 48 deletions(-) diff --git a/src/main/scala/edu/ie3/powerFactory2psdm/converter/types/LineTypeConverter.scala b/src/main/scala/edu/ie3/powerFactory2psdm/converter/types/LineTypeConverter.scala index 863a9d13..6e1b6aca 100644 --- a/src/main/scala/edu/ie3/powerFactory2psdm/converter/types/LineTypeConverter.scala +++ b/src/main/scala/edu/ie3/powerFactory2psdm/converter/types/LineTypeConverter.scala @@ -47,46 +47,46 @@ object LineTypeConverter { case x if x < 0 => aggregatedLineSectionLength case x if x > 0 => lineLength } - val weightedLineTypes = lineSections.map(section => { - val lineType = getLineType(section.typeId, lineTypes) - .getOrElse( - throw ConversionException( - s"Can't find line type ${section.typeId} of section ${section.id} within the converted line types." - ) + val weightedLineTypes = lineSections.map(section => { + val lineType = getLineType(section.typeId, lineTypes) + .getOrElse( + throw ConversionException( + s"Can't find line type ${section.typeId} of section ${section.id} within the converted line types." ) - (section.length, lineType) - }) - val lineType = new LineTypeInput( - UUID.randomUUID(), - "Custom_line_type_" + lineId, - 0.asMicroSiemensPerKilometre, - 0.asMicroSiemensPerKilometre, - 0.asOhmPerKilometre, - 0.asOhmPerKilometre, - Double.MaxValue.asKiloAmpere, - Double.MaxValue.asKiloVolt - ) + ) + (section.length, lineType) + }) + val lineType = new LineTypeInput( + UUID.randomUUID(), + "Custom_line_type_" + lineId, + 0.asMicroSiemensPerKilometre, + 0.asMicroSiemensPerKilometre, + 0.asOhmPerKilometre, + 0.asOhmPerKilometre, + Double.MaxValue.asKiloAmpere, + Double.MaxValue.asKiloVolt + ) - val weightedLineType = - weightedLineTypes.foldLeft(lineType)((averageType, current) => { - val currentLine = current._2 - val weightingFactor = current._1 / totalLength - new LineTypeInput( - averageType.getUuid, - averageType.getId, - averageType.getB.add(currentLine.getB.multiply(weightingFactor)), - averageType.getG.add(currentLine.getG.multiply(weightingFactor)), - averageType.getR.add(currentLine.getR.multiply(weightingFactor)), - averageType.getX.add(currentLine.getX.multiply(weightingFactor)), - if (averageType.getiMax().isLessThan(currentLine.getiMax())) - averageType.getiMax() - else currentLine.getiMax(), - if (averageType.getvRated().equals(Double.MaxValue.asKiloVolt)) - currentLine.getvRated() - else averageType.getvRated() - ) - }) - weightedLineType + val weightedLineType = + weightedLineTypes.foldLeft(lineType)((averageType, current) => { + val currentLine = current._2 + val weightingFactor = current._1 / totalLength + new LineTypeInput( + averageType.getUuid, + averageType.getId, + averageType.getB.add(currentLine.getB.multiply(weightingFactor)), + averageType.getG.add(currentLine.getG.multiply(weightingFactor)), + averageType.getR.add(currentLine.getR.multiply(weightingFactor)), + averageType.getX.add(currentLine.getX.multiply(weightingFactor)), + if (averageType.getiMax().isLessThan(currentLine.getiMax())) + averageType.getiMax() + else currentLine.getiMax(), + if (averageType.getvRated().equals(Double.MaxValue.asKiloVolt)) + currentLine.getvRated() + else averageType.getvRated() + ) + }) + weightedLineType } def getLineType( diff --git a/src/test/scala/edu/ie3/powerFactory2psdm/converter/types/LineTypeConverterSpec.scala b/src/test/scala/edu/ie3/powerFactory2psdm/converter/types/LineTypeConverterSpec.scala index 24073c83..e3c64c1a 100644 --- a/src/test/scala/edu/ie3/powerFactory2psdm/converter/types/LineTypeConverterSpec.scala +++ b/src/test/scala/edu/ie3/powerFactory2psdm/converter/types/LineTypeConverterSpec.scala @@ -56,16 +56,20 @@ class LineTypeConverterSpec extends Matchers with AnyWordSpecLike { 20.asKiloVolt ) ) - val lineSections = List(LineSection( - id = "lineSectionA", - length = 1, - typeId = "lineTypeA" - ), LineSection( - id = "lineSectionB", - length = 1, - typeId = "lineTypeB" - )) - val actual = LineTypeConverter.convert("testLine", 2, lineSections, lineTypes) + val lineSections = List( + LineSection( + id = "lineSectionA", + length = 1, + typeId = "lineTypeA" + ), + LineSection( + id = "lineSectionB", + length = 1, + typeId = "lineTypeB" + ) + ) + val actual = + LineTypeConverter.convert("testLine", 2, lineSections, lineTypes) actual.getB should equalWithTolerance(1.5.asMicroSiemensPerKilometre) actual.getG should equalWithTolerance(1.5.asMicroSiemensPerKilometre) actual.getR should equalWithTolerance(1.5.asOhmPerKilometre) From ec7e76fc1a519f322c412c443d409322180afe0b Mon Sep 17 00:00:00 2001 From: t-ober <63147366+t-ober@users.noreply.github.com> Date: Tue, 23 Nov 2021 08:07:11 +0100 Subject: [PATCH 06/15] fix test --- .../edu/ie3/powerFactory2psdm/util/QuantityUtils.scala | 8 +++++++- .../converter/types/LineTypeConverterSpec.scala | 5 ++++- .../ie3/powerFactory2psdm/util/QuantityUtilsSpec.scala | 9 +++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/main/scala/edu/ie3/powerFactory2psdm/util/QuantityUtils.scala b/src/main/scala/edu/ie3/powerFactory2psdm/util/QuantityUtils.scala index 74977d64..d2b37518 100644 --- a/src/main/scala/edu/ie3/powerFactory2psdm/util/QuantityUtils.scala +++ b/src/main/scala/edu/ie3/powerFactory2psdm/util/QuantityUtils.scala @@ -71,7 +71,7 @@ object QuantityUtils { def asMicroSiemensPerKilometre: ComparableQuantity[SpecificConductance] = Quantities.getQuantity( value, - MetricPrefix.MICRO(SIEMENS_PER_KILOMETRE) + MICRO_SIEMENS_PER_KILOMETRE ) def asOhm: ComparableQuantity[ElectricResistance] = Quantities.getQuantity( @@ -98,6 +98,12 @@ object QuantityUtils { MetricPrefix.MEGA(VOLTAMPERE) ) + def asAmpere: ComparableQuantity[ElectricCurrent] = + Quantities.getQuantity( + value, + AMPERE + ) + def asKiloAmpere: ComparableQuantity[ElectricCurrent] = Quantities.getQuantity( value, diff --git a/src/test/scala/edu/ie3/powerFactory2psdm/converter/types/LineTypeConverterSpec.scala b/src/test/scala/edu/ie3/powerFactory2psdm/converter/types/LineTypeConverterSpec.scala index e3c64c1a..f44b1d12 100644 --- a/src/test/scala/edu/ie3/powerFactory2psdm/converter/types/LineTypeConverterSpec.scala +++ b/src/test/scala/edu/ie3/powerFactory2psdm/converter/types/LineTypeConverterSpec.scala @@ -68,13 +68,16 @@ class LineTypeConverterSpec extends Matchers with AnyWordSpecLike { typeId = "lineTypeB" ) ) + + implicit val quantityTolerance: Double = 1e-6 + val actual = LineTypeConverter.convert("testLine", 2, lineSections, lineTypes) actual.getB should equalWithTolerance(1.5.asMicroSiemensPerKilometre) actual.getG should equalWithTolerance(1.5.asMicroSiemensPerKilometre) actual.getR should equalWithTolerance(1.5.asOhmPerKilometre) actual.getX should equalWithTolerance(1.5.asOhmPerKilometre) - actual.getiMax should equalWithTolerance(1.asKiloAmpere) + actual.getiMax should equalWithTolerance(1000.asAmpere) actual.getvRated should equalWithTolerance(20.asKiloVolt) } } diff --git a/src/test/scala/edu/ie3/powerFactory2psdm/util/QuantityUtilsSpec.scala b/src/test/scala/edu/ie3/powerFactory2psdm/util/QuantityUtilsSpec.scala index 71bff958..01d23dd9 100644 --- a/src/test/scala/edu/ie3/powerFactory2psdm/util/QuantityUtilsSpec.scala +++ b/src/test/scala/edu/ie3/powerFactory2psdm/util/QuantityUtilsSpec.scala @@ -120,6 +120,15 @@ class QuantityUtilsSpec extends Matchers with AnyWordSpecLike { ) } + "convert a double to ampere" in { + value.asAmpere should equalWithTolerance( + Quantities.getQuantity( + value, + AMPERE + ) + ) + } + "convert a double to kilo ampere" in { value.asKiloAmpere should equalWithTolerance( Quantities.getQuantity( From 60f6c0f588b72c89ab92744536db41cbeb212db4 Mon Sep 17 00:00:00 2001 From: t-ober <63147366+t-ober@users.noreply.github.com> Date: Tue, 23 Nov 2021 09:38:50 +0100 Subject: [PATCH 07/15] adjust utils test --- .../edu/ie3/powerFactory2psdm/util/QuantityUtilsSpec.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/scala/edu/ie3/powerFactory2psdm/util/QuantityUtilsSpec.scala b/src/test/scala/edu/ie3/powerFactory2psdm/util/QuantityUtilsSpec.scala index 01d23dd9..767aaef8 100644 --- a/src/test/scala/edu/ie3/powerFactory2psdm/util/QuantityUtilsSpec.scala +++ b/src/test/scala/edu/ie3/powerFactory2psdm/util/QuantityUtilsSpec.scala @@ -16,6 +16,7 @@ import edu.ie3.util.quantities.PowerSystemUnits.{ KILOVOLT, KILOWATT, KILOWATTHOUR, + MICRO_SIEMENS_PER_KILOMETRE, OHM_PER_KILOMETRE, PERCENT_PER_HOUR, PU, @@ -74,7 +75,7 @@ class QuantityUtilsSpec extends Matchers with AnyWordSpecLike { "convert a double to micro siemens per kilometre" in { value.asMicroSiemensPerKilometre should equalWithTolerance( - Quantities.getQuantity(value, MetricPrefix.MICRO(SIEMENS_PER_KILOMETRE)) + Quantities.getQuantity(value, MICRO_SIEMENS_PER_KILOMETRE) ) } From a56439a0cdae24883c1c1282134c742575b2c3b5 Mon Sep 17 00:00:00 2001 From: t-ober <63147366+t-ober@users.noreply.github.com> Date: Wed, 24 Nov 2021 08:08:02 +0100 Subject: [PATCH 08/15] update test grid --- src/test/resources/pfGrids/exampleGrid.json | 145 ++++++++++++-------- 1 file changed, 89 insertions(+), 56 deletions(-) diff --git a/src/test/resources/pfGrids/exampleGrid.json b/src/test/resources/pfGrids/exampleGrid.json index 1a534fa4..0bd5c791 100644 --- a/src/test/resources/pfGrids/exampleGrid.json +++ b/src/test/resources/pfGrids/exampleGrid.json @@ -477,60 +477,55 @@ ], "lines": [ { - "id": "Grid.ElmNet\\Line_0002_0003.ElmLne", + "id": "Grid.ElmNet\\Line_0002_0005.ElmLne", "GPScoords": [ [] ], + "cubsecs": [], "dline": 1.0, "bus1Id": "Grid.ElmNet\\Bus_0002.ElmTerm", - "bus2Id": "Grid.ElmNet\\Bus_0003.ElmTerm", - "typeId": "TypLne 0002 to 0003.TypLne" + "bus2Id": "Grid.ElmNet\\Bus_0005.ElmTerm", + "typeId": "TypLne 0002 to 0005.TypLne" }, { "id": "Grid.ElmNet\\Line_0010_0011.ElmLne", "GPScoords": [ [] ], + "cubsecs": [], "dline": 1.0, "bus1Id": "Grid.ElmNet\\Bus_0010.ElmTerm", "bus2Id": "Grid.ElmNet\\Bus_0011.ElmTerm", "typeId": "TypLne 0010 to 0011.TypLne" }, - { - "id": "Grid.ElmNet\\Line_0012_0013.ElmLne", - "GPScoords": [ - [] - ], - "dline": 1.0, - "bus1Id": "Grid.ElmNet\\Bus_0012.ElmTerm", - "bus2Id": "Grid.ElmNet\\Bus_0013.ElmTerm", - "typeId": "TypLne 0012 to 0013.TypLne" - }, { "id": "Grid.ElmNet\\Line_0013_0014.ElmLne", "GPScoords": [ [] ], + "cubsecs": [], "dline": 1.0, "bus1Id": "Grid.ElmNet\\Bus_0013.ElmTerm", "bus2Id": "Grid.ElmNet\\Bus_0014.ElmTerm", "typeId": "TypLne 0013 to 0014.TypLne" }, { - "id": "Grid.ElmNet\\Line_0002_0005.ElmLne", + "id": "Grid.ElmNet\\Line_0002_0003.ElmLne", "GPScoords": [ [] ], + "cubsecs": [], "dline": 1.0, "bus1Id": "Grid.ElmNet\\Bus_0002.ElmTerm", - "bus2Id": "Grid.ElmNet\\Bus_0005.ElmTerm", - "typeId": "TypLne 0002 to 0005.TypLne" + "bus2Id": "Grid.ElmNet\\Bus_0003.ElmTerm", + "typeId": "TypLne 0002 to 0003.TypLne" }, { "id": "Grid.ElmNet\\Line_0006_0013.ElmLne", "GPScoords": [ [] ], + "cubsecs": [], "dline": 1.0, "bus1Id": "Grid.ElmNet\\Bus_0013.ElmTerm", "bus2Id": "Grid.ElmNet\\Bus_0006.ElmTerm", @@ -541,6 +536,7 @@ "GPScoords": [ [] ], + "cubsecs": [], "dline": 1.0, "bus1Id": "Grid.ElmNet\\Bus_0005.ElmTerm", "bus2Id": "Grid.ElmNet\\Bus_0004.ElmTerm", @@ -551,6 +547,7 @@ "GPScoords": [ [] ], + "cubsecs": [], "dline": 1.0, "bus1Id": "Grid.ElmNet\\Bus_0011.ElmTerm", "bus2Id": "Grid.ElmNet\\Bus_0006.ElmTerm", @@ -561,6 +558,7 @@ "GPScoords": [ [] ], + "cubsecs": [], "dline": 1.0, "bus1Id": "Grid.ElmNet\\Bus_0006.ElmTerm", "bus2Id": "Grid.ElmNet\\Bus_0012.ElmTerm", @@ -571,6 +569,7 @@ "GPScoords": [ [] ], + "cubsecs": [], "dline": 1.0, "bus1Id": "Grid.ElmNet\\Bus_0009.ElmTerm", "bus2Id": "Grid.ElmNet\\Bus_0010.ElmTerm", @@ -581,6 +580,7 @@ "GPScoords": [ [] ], + "cubsecs": [], "dline": 1.0, "bus1Id": "Grid.ElmNet\\Bus_0014.ElmTerm", "bus2Id": "Grid.ElmNet\\Bus_0009.ElmTerm", @@ -602,13 +602,14 @@ 13.8273 ] ], + "cubsecs": [], "dline": 1.7364000082015991, "bus1Id": "Grid.ElmNet\\Bus_0001.ElmTerm", "bus2Id": "Grid.ElmNet\\Bus_0002.ElmTerm", "typeId": "TypLne 0001 to 0002.TypLne" }, { - "id": "Grid.ElmNet\\Line_0001_0005.ElmLne", + "id": "Grid.ElmNet\\Line_0001_0002/2.ElmLne", "GPScoords": [ [ 1.0, @@ -623,13 +624,14 @@ 3.0 ] ], + "cubsecs": [], "dline": 1.0, "bus1Id": "Grid.ElmNet\\Bus_0001.ElmTerm", - "bus2Id": "Grid.ElmNet\\Bus_0005.ElmTerm", - "typeId": "TypLne 0001 to 0005.TypLne" + "bus2Id": "Grid.ElmNet\\Bus_0002.ElmTerm", + "typeId": "TypLne 0001 to 0002.TypLne" }, { - "id": "Grid.ElmNet\\Line_0001_0002/2.ElmLne", + "id": "Grid.ElmNet\\Line_0002_0004.ElmLne", "GPScoords": [ [ 1.0, @@ -644,13 +646,14 @@ 3.0 ] ], + "cubsecs": [], "dline": 1.0, - "bus1Id": "Grid.ElmNet\\Bus_0001.ElmTerm", - "bus2Id": "Grid.ElmNet\\Bus_0002.ElmTerm", - "typeId": "TypLne 0001 to 0002.TypLne" + "bus1Id": "Grid.ElmNet\\Bus_0002.ElmTerm", + "bus2Id": "Grid.ElmNet\\Bus_0004.ElmTerm", + "typeId": "TypLne 0002 to 0004.TypLne" }, { - "id": "Grid.ElmNet\\Line_0002_0004.ElmLne", + "id": "Grid.ElmNet\\Line_0003_0004.ElmLne", "GPScoords": [ [ 1.0, @@ -665,13 +668,14 @@ 3.0 ] ], + "cubsecs": [], "dline": 1.0, - "bus1Id": "Grid.ElmNet\\Bus_0002.ElmTerm", + "bus1Id": "Grid.ElmNet\\Bus_0003.ElmTerm", "bus2Id": "Grid.ElmNet\\Bus_0004.ElmTerm", - "typeId": "TypLne 0002 to 0004.TypLne" + "typeId": "TypLne 0003 to 0004.TypLne" }, { - "id": "Grid.ElmNet\\Line_0003_0004.ElmLne", + "id": "Grid.ElmNet\\Line_0001_0005.ElmLne", "GPScoords": [ [ 1.0, @@ -686,21 +690,33 @@ 3.0 ] ], + "cubsecs": [], "dline": 1.0, - "bus1Id": "Grid.ElmNet\\Bus_0003.ElmTerm", - "bus2Id": "Grid.ElmNet\\Bus_0004.ElmTerm", - "typeId": "TypLne 0003 to 0004.TypLne" + "bus1Id": "Grid.ElmNet\\Bus_0001.ElmTerm", + "bus2Id": "Grid.ElmNet\\Bus_0005.ElmTerm", + "typeId": "TypLne 0001 to 0005.TypLne" + }, + { + "id": "Grid.ElmNet\\Line_0012_0013.ElmLne", + "GPScoords": [ + [] + ], + "cubsecs": [], + "dline": 0.30000001192092896, + "bus1Id": "Grid.ElmNet\\Bus_0012.ElmTerm", + "bus2Id": "Grid.ElmNet\\Bus_0013.ElmTerm", + "typeId": "TypLne 0012 to 0013.TypLne" } ], "lineTypes": [ { - "id": "TypLne 0002 to 0003.TypLne", - "bline": 251.37741088867188, + "id": "TypLne 0002 to 0005.TypLne", + "bline": 195.13314819335938, "gline": 0.0, - "rline": 8.18753719329834, + "rline": 9.922967910766602, "sline": 1.0, "uline": 132.0, - "xline": 34.49428176879883 + "xline": 30.296852111816406 }, { "id": "TypLne 0010 to 0011.TypLne", @@ -711,15 +727,6 @@ "uline": 33.0, "xline": 2.0916426181793213 }, - { - "id": "TypLne 0012 to 0013.TypLne", - "bline": 0.0, - "gline": 0.0, - "rline": 2.4058187007904053, - "sline": 1.0, - "uline": 33.0, - "xline": 2.1766932010650635 - }, { "id": "TypLne 0013 to 0014.TypLne", "bline": 0.0, @@ -730,13 +737,13 @@ "xline": 3.78993821144104 }, { - "id": "TypLne 0002 to 0005.TypLne", - "bline": 195.13314819335938, + "id": "TypLne 0002 to 0003.TypLne", + "bline": 251.37741088867188, "gline": 0.0, - "rline": 9.922967910766602, + "rline": 8.18753719329834, "sline": 1.0, "uline": 132.0, - "xline": 30.296852111816406 + "xline": 34.49428176879883 }, { "id": "TypLne 0006 to 0013.TypLne", @@ -801,15 +808,6 @@ "uline": 132.0, "xline": 20.61956214904785 }, - { - "id": "TypLne 0001 to 0005.TypLne", - "bline": 282.369140625, - "gline": 0.0, - "rline": 9.41418743133545, - "sline": 1.0, - "uline": 132.0, - "xline": 38.86250305175781 - }, { "id": "TypLne 0002 to 0004.TypLne", "bline": 214.64646911621094, @@ -827,6 +825,24 @@ "sline": 1.0, "uline": 132.0, "xline": 29.80026626586914 + }, + { + "id": "TypLne 0001 to 0005.TypLne", + "bline": 282.369140625, + "gline": 0.0, + "rline": 9.41418743133545, + "sline": 1.0, + "uline": 132.0, + "xline": 38.86250305175781 + }, + { + "id": "TypLne 0012 to 0013.TypLne", + "bline": 0.0, + "gline": 0.0, + "rline": 2.4058187007904053, + "sline": 1.0, + "uline": 33.0, + "xline": 2.1766932010650635 } ], "trafos2w": [ @@ -1192,5 +1208,22 @@ "bus1Id": "Grid.ElmNet\\Ortsnetzstation.ElmTrfstat\\1.ElmTerm", "bus2Id": "Grid.ElmNet\\Bus_0015.ElmTerm" } + ], + "lineSections": [ + { + "id": "Grid.ElmNet\\Line_0001_0005.ElmLne\\Leitungssektion 1.ElmLnesec", + "dline": 0.5, + "typeId": "TypLne 0001 to 0005.TypLne" + }, + { + "id": "Grid.ElmNet\\Line_0001_0005.ElmLne\\Leitungssektion 2.ElmLnesec", + "dline": 0.5, + "typeId": "TypLne 0002 to 0004.TypLne" + }, + { + "id": "Grid.ElmNet\\Line_0012_0013.ElmLne\\Leitungssektion.ElmLnesec", + "dline": 0.30000001192092896, + "typeId": "TypLne 0009 to 0010.TypLne" + } ] } \ No newline at end of file From 01795ed38ed933213a69b28de438f81c4f287a21 Mon Sep 17 00:00:00 2001 From: t-ober <63147366+t-ober@users.noreply.github.com> Date: Wed, 24 Nov 2021 13:52:33 +0100 Subject: [PATCH 09/15] fix line type generation --- .../converter/LineConverter.scala | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/main/scala/edu/ie3/powerFactory2psdm/converter/LineConverter.scala b/src/main/scala/edu/ie3/powerFactory2psdm/converter/LineConverter.scala index 60787ed0..f516c260 100644 --- a/src/main/scala/edu/ie3/powerFactory2psdm/converter/LineConverter.scala +++ b/src/main/scala/edu/ie3/powerFactory2psdm/converter/LineConverter.scala @@ -46,25 +46,19 @@ object LineConverter { ): List[LineInput] = { lines.map(line => { val lineType = (line.typeId, line.lineSections) match { - case (Some(lineTypeId), None) => - getLineType(lineTypeId, lineTypes).getOrElse( - throw ConversionException( - s"Could not convert line: $line due to failed line type retrieval." - ) - ) - case (None, Some(lineSections)) => + case (_, Some(lineSections)) => LineTypeConverter.convert( line.id, line.length, lineSections, lineTypes ) - case (Some(_), Some(_)) => { - throw ConversionException( - s"Line: ${line.id} has line types and line sections which both define line types. " + - s"This error should not happen since PowerFactory only lets you define one of the two." + case (Some(lineTypeId), None) => + getLineType(lineTypeId, lineTypes).getOrElse( + throw ConversionException( + s"Could not convert line: $line due to failed line type retrieval." + ) ) - } case (None, None) => throw ConversionException( s"Could not convert line: ${line.id} since there is no defined type in the model and there are no line section that specify the type" From 7b7c91a04af24ab3d13cc9a54ea38719bec2ec9c Mon Sep 17 00:00:00 2001 From: t-ober <63147366+t-ober@users.noreply.github.com> Date: Fri, 26 Nov 2021 08:13:27 +0100 Subject: [PATCH 10/15] add import --- .../edu/ie3/powerFactory2psdm/converter/LineConverter.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/scala/edu/ie3/powerFactory2psdm/converter/LineConverter.scala b/src/main/scala/edu/ie3/powerFactory2psdm/converter/LineConverter.scala index 8d6dc7eb..f516c260 100644 --- a/src/main/scala/edu/ie3/powerFactory2psdm/converter/LineConverter.scala +++ b/src/main/scala/edu/ie3/powerFactory2psdm/converter/LineConverter.scala @@ -13,6 +13,7 @@ import edu.ie3.datamodel.models.input.connector.`type`.LineTypeInput import edu.ie3.datamodel.models.input.system.characteristic.OlmCharacteristicInput import edu.ie3.datamodel.utils.GridAndGeoUtils import edu.ie3.powerFactory2psdm.converter.NodeConverter.getNode +import edu.ie3.powerFactory2psdm.converter.types.LineTypeConverter import edu.ie3.powerFactory2psdm.converter.types.LineTypeConverter.getLineType import edu.ie3.powerFactory2psdm.exception.pf.ConversionException import edu.ie3.powerFactory2psdm.model.entity.Line From 9a4bb7d86f9ac16ddebf4c167673a90a18a911f7 Mon Sep 17 00:00:00 2001 From: t-ober <63147366+t-ober@users.noreply.github.com> Date: Mon, 29 Nov 2021 12:18:09 +0100 Subject: [PATCH 11/15] adjust test grid --- src/test/resources/pfGrids/exampleGrid.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/resources/pfGrids/exampleGrid.json b/src/test/resources/pfGrids/exampleGrid.json index 0bd5c791..05539667 100644 --- a/src/test/resources/pfGrids/exampleGrid.json +++ b/src/test/resources/pfGrids/exampleGrid.json @@ -439,11 +439,11 @@ "vtarget": 1.0, "conElms": [ { - "id": "Grid.ElmNet\\LS/TR Schalter(1).ElmCoup", + "id": "Grid.ElmNet\\Ortsnetzstation.ElmTrfstat\\S1.ElmCoup", "pfCls": "ElmCoup" }, { - "id": "Grid.ElmNet\\Ortsnetzstation.ElmTrfstat\\S1.ElmCoup", + "id": "Grid.ElmNet\\LS/TR Schalter(1).ElmCoup", "pfCls": "ElmCoup" } ] From 79c95408bd09439ba75ed95a90d0877c8d9b0b0f Mon Sep 17 00:00:00 2001 From: t-ober <63147366+t-ober@users.noreply.github.com> Date: Wed, 29 Dec 2021 09:53:47 +0100 Subject: [PATCH 12/15] rework line section length comparison --- .../converter/types/LineTypeConverter.scala | 42 +++++++++++++++---- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/src/main/scala/edu/ie3/powerFactory2psdm/converter/types/LineTypeConverter.scala b/src/main/scala/edu/ie3/powerFactory2psdm/converter/types/LineTypeConverter.scala index 6e1b6aca..a3e420ab 100644 --- a/src/main/scala/edu/ie3/powerFactory2psdm/converter/types/LineTypeConverter.scala +++ b/src/main/scala/edu/ie3/powerFactory2psdm/converter/types/LineTypeConverter.scala @@ -5,18 +5,20 @@ */ package edu.ie3.powerFactory2psdm.converter.types +import com.typesafe.scalalogging.LazyLogging import edu.ie3.datamodel.models.input.connector.`type`.LineTypeInput import edu.ie3.powerFactory2psdm.exception.pf.ConversionException import edu.ie3.powerFactory2psdm.model.entity.LineSection import edu.ie3.powerFactory2psdm.model.entity.types.LineType import edu.ie3.powerFactory2psdm.util.QuantityUtils.RichQuantityDouble + import java.util.UUID import scala.math.abs import scala.util.{Failure, Success, Try} /** Functionality to translate a [[LineType]] to a [[LineTypeInput]] */ -object LineTypeConverter { +object LineTypeConverter extends LazyLogging { def convert(input: LineType): LineTypeInput = { @@ -32,6 +34,22 @@ object LineTypeConverter { ) } + /** In PowerFactory lines can be made up of line sections. We convert them to + * a single line by using the aggregated length of the line sections and + * generate a line type by calculating the weighted (by line length) average + * of the parameters. + * + * @param lineId + * name of the line made up of line sections + * @param lineLength + * the noted length of the line + * @param lineSections + * a list of the line sections + * @param lineTypes + * mapping of line types + * @return + * the averaged line type as [[LineTypeInput]] + */ def convert( lineId: String, lineLength: Double, @@ -42,11 +60,19 @@ object LineTypeConverter { val aggregatedLineSectionLength = lineSections.map(section => section.length).sum - val totalLength = lineLength - aggregatedLineSectionLength match { - case x if abs(x) < 1e-3 => lineLength - case x if x < 0 => aggregatedLineSectionLength - case x if x > 0 => lineLength + // sanity check of total line length versus aggregated line length of all corresponding line sections + lineLength - aggregatedLineSectionLength match { + case x if abs(x) < 1e-9 => + case x if x < 0 => + logger.error( + s"The line length of line: $lineId is smaller than the aggregated length of line sections by ${(1 - (lineLength / aggregatedLineSectionLength)) * 100}% which distorts results. This should be prevented by PF and therefore not happen." + ) + case x if x > 0 => + logger.error( + s"The line length of line: $lineId is greater than the aggregated length of line sections by ${((lineLength / aggregatedLineSectionLength) - 1) * 100}% which distorts results. This should be prevented by PF and therefore not happen." + ) } + val weightedLineTypes = lineSections.map(section => { val lineType = getLineType(section.typeId, lineTypes) .getOrElse( @@ -56,7 +82,7 @@ object LineTypeConverter { ) (section.length, lineType) }) - val lineType = new LineTypeInput( + val emptyLineType = new LineTypeInput( UUID.randomUUID(), "Custom_line_type_" + lineId, 0.asMicroSiemensPerKilometre, @@ -68,9 +94,9 @@ object LineTypeConverter { ) val weightedLineType = - weightedLineTypes.foldLeft(lineType)((averageType, current) => { + weightedLineTypes.foldLeft(emptyLineType)((averageType, current) => { val currentLine = current._2 - val weightingFactor = current._1 / totalLength + val weightingFactor = current._1 / lineLength new LineTypeInput( averageType.getUuid, averageType.getId, From 45231f521c52bbe22645d9d0ca1117f29e8bcdb4 Mon Sep 17 00:00:00 2001 From: t-ober <63147366+t-ober@users.noreply.github.com> Date: Wed, 29 Dec 2021 09:54:38 +0100 Subject: [PATCH 13/15] direct return --- .../converter/types/LineTypeConverter.scala | 38 +++++++++---------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/src/main/scala/edu/ie3/powerFactory2psdm/converter/types/LineTypeConverter.scala b/src/main/scala/edu/ie3/powerFactory2psdm/converter/types/LineTypeConverter.scala index a3e420ab..dd5aba27 100644 --- a/src/main/scala/edu/ie3/powerFactory2psdm/converter/types/LineTypeConverter.scala +++ b/src/main/scala/edu/ie3/powerFactory2psdm/converter/types/LineTypeConverter.scala @@ -93,26 +93,24 @@ object LineTypeConverter extends LazyLogging { Double.MaxValue.asKiloVolt ) - val weightedLineType = - weightedLineTypes.foldLeft(emptyLineType)((averageType, current) => { - val currentLine = current._2 - val weightingFactor = current._1 / lineLength - new LineTypeInput( - averageType.getUuid, - averageType.getId, - averageType.getB.add(currentLine.getB.multiply(weightingFactor)), - averageType.getG.add(currentLine.getG.multiply(weightingFactor)), - averageType.getR.add(currentLine.getR.multiply(weightingFactor)), - averageType.getX.add(currentLine.getX.multiply(weightingFactor)), - if (averageType.getiMax().isLessThan(currentLine.getiMax())) - averageType.getiMax() - else currentLine.getiMax(), - if (averageType.getvRated().equals(Double.MaxValue.asKiloVolt)) - currentLine.getvRated() - else averageType.getvRated() - ) - }) - weightedLineType + weightedLineTypes.foldLeft(emptyLineType)((averageType, current) => { + val currentLine = current._2 + val weightingFactor = current._1 / lineLength + new LineTypeInput( + averageType.getUuid, + averageType.getId, + averageType.getB.add(currentLine.getB.multiply(weightingFactor)), + averageType.getG.add(currentLine.getG.multiply(weightingFactor)), + averageType.getR.add(currentLine.getR.multiply(weightingFactor)), + averageType.getX.add(currentLine.getX.multiply(weightingFactor)), + if (averageType.getiMax().isLessThan(currentLine.getiMax())) + averageType.getiMax() + else currentLine.getiMax(), + if (averageType.getvRated().equals(Double.MaxValue.asKiloVolt)) + currentLine.getvRated() + else averageType.getvRated() + ) + }) } def getLineType( From 88628c70db13ffbd1d77705cd6ca97e2323d3cac Mon Sep 17 00:00:00 2001 From: t-ober <63147366+t-ober@users.noreply.github.com> Date: Wed, 29 Dec 2021 10:20:12 +0100 Subject: [PATCH 14/15] add some documentatipn --- .../powerFactory2psdm/converter/LineConverter.scala | 4 ++++ .../converter/types/LineTypeConverter.scala | 2 +- .../edu/ie3/powerFactory2psdm/model/entity/Line.scala | 10 +++++++++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/main/scala/edu/ie3/powerFactory2psdm/converter/LineConverter.scala b/src/main/scala/edu/ie3/powerFactory2psdm/converter/LineConverter.scala index f516c260..e16d1f65 100644 --- a/src/main/scala/edu/ie3/powerFactory2psdm/converter/LineConverter.scala +++ b/src/main/scala/edu/ie3/powerFactory2psdm/converter/LineConverter.scala @@ -45,6 +45,10 @@ object LineConverter { lineTypes: Map[String, LineTypeInput] ): List[LineInput] = { lines.map(line => { + /* + Here we check if this is a line with line section and therefore multiple line types in which case we create an + averaged line type. If it isn't we just retrieve the line sections from the converted line types. + */ val lineType = (line.typeId, line.lineSections) match { case (_, Some(lineSections)) => LineTypeConverter.convert( diff --git a/src/main/scala/edu/ie3/powerFactory2psdm/converter/types/LineTypeConverter.scala b/src/main/scala/edu/ie3/powerFactory2psdm/converter/types/LineTypeConverter.scala index dd5aba27..b4ce511f 100644 --- a/src/main/scala/edu/ie3/powerFactory2psdm/converter/types/LineTypeConverter.scala +++ b/src/main/scala/edu/ie3/powerFactory2psdm/converter/types/LineTypeConverter.scala @@ -8,7 +8,7 @@ package edu.ie3.powerFactory2psdm.converter.types import com.typesafe.scalalogging.LazyLogging import edu.ie3.datamodel.models.input.connector.`type`.LineTypeInput import edu.ie3.powerFactory2psdm.exception.pf.ConversionException -import edu.ie3.powerFactory2psdm.model.entity.LineSection +import edu.ie3.powerFactory2psdm.model.entity.{Line, LineSection} import edu.ie3.powerFactory2psdm.model.entity.types.LineType import edu.ie3.powerFactory2psdm.util.QuantityUtils.RichQuantityDouble diff --git a/src/main/scala/edu/ie3/powerFactory2psdm/model/entity/Line.scala b/src/main/scala/edu/ie3/powerFactory2psdm/model/entity/Line.scala index 957f5619..c831fb9c 100644 --- a/src/main/scala/edu/ie3/powerFactory2psdm/model/entity/Line.scala +++ b/src/main/scala/edu/ie3/powerFactory2psdm/model/entity/Line.scala @@ -17,6 +17,14 @@ import edu.ie3.powerFactory2psdm.model.RawPfGridModel.Lines * id of connected node * @param nodeBId * id of connected node + * @param typeId + * id of the corresponding line type + * @param lineSections + * optional list of line sections the line consists of + * @param length + * length of the line + * @param gpsCoords + * optional list of gps coordinates of geo position of the line */ final case class Line( id: String, @@ -25,7 +33,7 @@ final case class Line( typeId: Option[String], lineSections: Option[List[LineSection]], length: Double, - gpsCoords: Option[(List[(Double, Double)])] + gpsCoords: Option[List[(Double, Double)]] ) extends EntityModel with Edge From e932e7ada882b501944fd912bca555bef481654c Mon Sep 17 00:00:00 2001 From: t-ober <63147366+t-ober@users.noreply.github.com> Date: Wed, 29 Dec 2021 10:23:31 +0100 Subject: [PATCH 15/15] more scaladocs --- .../model/entity/LineSection.scala | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/main/scala/edu/ie3/powerFactory2psdm/model/entity/LineSection.scala b/src/main/scala/edu/ie3/powerFactory2psdm/model/entity/LineSection.scala index de96488f..ef4f1aa7 100644 --- a/src/main/scala/edu/ie3/powerFactory2psdm/model/entity/LineSection.scala +++ b/src/main/scala/edu/ie3/powerFactory2psdm/model/entity/LineSection.scala @@ -13,6 +13,15 @@ import edu.ie3.powerFactory2psdm.exception.pf.{ import edu.ie3.powerFactory2psdm.model.RawPfGridModel.LineSections import org.apache.commons.lang3.Conversion +/** A section of an electrical [[Line]] + * + * @param id + * its identifier + * @param length + * its length + * @param typeId + * the identifier of its type + */ final case class LineSection( id: String, length: Double, @@ -34,7 +43,7 @@ object LineSection { ) val typeId = rawLineSection.typeId.getOrElse( throw MissingParameterException( - s"There is no defined type line section $id" + s"There is no defined type for line section $id" ) ) LineSection(id, length, typeId) @@ -47,7 +56,7 @@ object LineSection { lineSections.groupBy(lineSection => getLineId(lineSection.id)) } - def getLineId(lineSectionId: String): String = { + private def getLineId(lineSectionId: String): String = { val lineIdRegEx = raw".+?(?=\\[\w\s]*\.ElmLnesec)".r lineIdRegEx.findFirstIn(lineSectionId) match { case Some(id) => id