From 19e54df0e5fe886bf218d3cf9fa6146b7528bac0 Mon Sep 17 00:00:00 2001 From: Johannes Hiry Date: Mon, 23 Mar 2020 19:08:31 +0100 Subject: [PATCH 01/21] added empty class of InputEntityProcessor --- .../result/InputEntityProcessor.java | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 src/main/java/edu/ie3/datamodel/io/processor/result/InputEntityProcessor.java diff --git a/src/main/java/edu/ie3/datamodel/io/processor/result/InputEntityProcessor.java b/src/main/java/edu/ie3/datamodel/io/processor/result/InputEntityProcessor.java new file mode 100644 index 000000000..365f8428f --- /dev/null +++ b/src/main/java/edu/ie3/datamodel/io/processor/result/InputEntityProcessor.java @@ -0,0 +1,42 @@ +package edu.ie3.datamodel.io.processor.result; + +import edu.ie3.datamodel.io.processor.EntityProcessor; +import edu.ie3.datamodel.models.input.InputEntity; + +import javax.measure.Quantity; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Optional; + + +/** + * //ToDo: Class Description + * + * @version 0.1 + * @since 23.03.20 + */ +public class InputEntityProcessor extends EntityProcessor { + /** + * Create a new EntityProcessor + * + * @param registeredClass the class the entity processor should be able to handle + */ + public InputEntityProcessor(Class registeredClass) { + super(registeredClass); + } + + @Override + protected Optional> processEntity(InputEntity entity) { + return Optional.empty(); + } + + @Override + protected Optional handleProcessorSpecificQuantity(Quantity quantity, String fieldName) { + return Optional.empty(); + } + + @Override + protected List> getAllEligibleClasses() { + return null; + } +} From 31b9b8238ae4ac71ef5367e6e8025ffb4239152d Mon Sep 17 00:00:00 2001 From: Johannes Hiry Date: Tue, 24 Mar 2020 13:25:25 +0100 Subject: [PATCH 02/21] fix InputDatamodelConcept.puml Operable --- docs/uml/InputDatamodelConcept.puml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/uml/InputDatamodelConcept.puml b/docs/uml/InputDatamodelConcept.puml index f538bb23f..6f9111707 100644 --- a/docs/uml/InputDatamodelConcept.puml +++ b/docs/uml/InputDatamodelConcept.puml @@ -8,11 +8,9 @@ abstract Class InputEntity InputEntity --|> UniqueEntity Interface Operable { -+ operationInterval: Interval -+ operatesFrom: ZonedDateTime -+ operatesUntil: ZonedDateTime + inOperation: Boolean -+ operator: OperatorInput ++ getOperator(): OperatorInput ++ getOperationTime(): OperationTime } abstract Class AssetInput { From 062dbb698abbb5c727bcb5205464f21c959b8751 Mon Sep 17 00:00:00 2001 From: Johannes Hiry Date: Tue, 24 Mar 2020 16:35:31 +0100 Subject: [PATCH 03/21] AssetInputProcessor with NodeInput processing capabilities --- .../input/AssetInputEntityFactory.java | 4 +- .../io/factory/input/NodeInputFactory.java | 4 +- .../io/processor/EntityProcessor.java | 183 +++++++++++++++++- .../processor/input/AssetInputProcessor.java | 113 +++++++++++ .../result/InputEntityProcessor.java | 42 ---- .../result/ResultEntityProcessor.java | 73 +------ .../input/AssetInputProcessorTest.groovy | 101 ++++++++++ .../edu/ie3/test/common/GridTestData.groovy | 29 ++- src/test/resources/log4j2-test.xml | 2 +- 9 files changed, 414 insertions(+), 137 deletions(-) create mode 100644 src/main/java/edu/ie3/datamodel/io/processor/input/AssetInputProcessor.java delete mode 100644 src/main/java/edu/ie3/datamodel/io/processor/result/InputEntityProcessor.java create mode 100644 src/test/groovy/edu/ie3/datamodel/io/processor/input/AssetInputProcessorTest.groovy diff --git a/src/main/java/edu/ie3/datamodel/io/factory/input/AssetInputEntityFactory.java b/src/main/java/edu/ie3/datamodel/io/factory/input/AssetInputEntityFactory.java index c402f5614..53baf56bc 100644 --- a/src/main/java/edu/ie3/datamodel/io/factory/input/AssetInputEntityFactory.java +++ b/src/main/java/edu/ie3/datamodel/io/factory/input/AssetInputEntityFactory.java @@ -25,8 +25,8 @@ public abstract class AssetInputEntityFactory { private static final String UUID = "uuid"; - private static final String OPERATES_FROM = "operatesfrom"; - private static final String OPERATES_UNTIL = "operatesuntil"; + public static final String OPERATES_FROM = "operatesfrom"; + public static final String OPERATES_UNTIL = "operatesuntil"; private static final String ID = "id"; public AssetInputEntityFactory(Class... allowedClasses) { diff --git a/src/main/java/edu/ie3/datamodel/io/factory/input/NodeInputFactory.java b/src/main/java/edu/ie3/datamodel/io/factory/input/NodeInputFactory.java index 6364b8100..eabe92493 100644 --- a/src/main/java/edu/ie3/datamodel/io/factory/input/NodeInputFactory.java +++ b/src/main/java/edu/ie3/datamodel/io/factory/input/NodeInputFactory.java @@ -17,10 +17,10 @@ public class NodeInputFactory extends AssetInputEntityFactory { private static final String V_TARGET = "vtarget"; - private static final String V_RATED = "vrated"; + public static final String V_RATED = "vrated"; private static final String SLACK = "slack"; private static final String GEO_POSITION = "geoposition"; - private static final String VOLT_LVL = "voltlvl"; + public static final String VOLT_LVL = "voltlvl"; private static final String SUBNET = "subnet"; public NodeInputFactory() { diff --git a/src/main/java/edu/ie3/datamodel/io/processor/EntityProcessor.java b/src/main/java/edu/ie3/datamodel/io/processor/EntityProcessor.java index d5fcb2b45..4c9ed58a3 100644 --- a/src/main/java/edu/ie3/datamodel/io/processor/EntityProcessor.java +++ b/src/main/java/edu/ie3/datamodel/io/processor/EntityProcessor.java @@ -6,9 +6,14 @@ package edu.ie3.datamodel.io.processor; import edu.ie3.datamodel.exceptions.EntityProcessorException; +import edu.ie3.datamodel.io.factory.input.AssetInputEntityFactory; +import edu.ie3.datamodel.io.factory.input.NodeInputFactory; import edu.ie3.datamodel.io.processor.result.ResultEntityProcessor; +import edu.ie3.datamodel.models.OperationTime; import edu.ie3.datamodel.models.StandardUnits; import edu.ie3.datamodel.models.UniqueEntity; +import edu.ie3.datamodel.models.input.OperatorInput; +import edu.ie3.datamodel.models.voltagelevels.VoltageLevel; import edu.ie3.util.TimeTools; import java.beans.Introspector; import java.lang.reflect.Method; @@ -23,6 +28,8 @@ import org.apache.commons.lang3.ArrayUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.locationtech.jts.geom.Geometry; +import org.locationtech.jts.io.geojson.GeoJsonWriter; /** * Internal API Interface for EntityProcessors. Main purpose is to 'de-serialize' models into a @@ -39,8 +46,18 @@ public abstract class EntityProcessor { protected final String[] headerElements; protected final LinkedHashMap fieldNameToMethod = new LinkedHashMap<>(); + private static final String OPERATION_TIME_FIELD_NAME = OperationTime.class.getSimpleName(); + private static final String OPERATES_FROM = AssetInputEntityFactory.OPERATES_FROM; + private static final String OPERATES_UNTIL = AssetInputEntityFactory.OPERATES_UNTIL; + + private static final String VOLT_LVL_FIELD_NAME = "voltLvl"; + private static final String VOLT_LVL = NodeInputFactory.VOLT_LVL; + private static final String V_RATED = NodeInputFactory.V_RATED; + + private static final GeoJsonWriter geoJsonWriter = new GeoJsonWriter(); + /** Field name of {@link UniqueEntity} uuid */ - private static final String uuidString = "uuid"; + private static final String UUID_FIELD_NAME = "uuid"; /** * Create a new EntityProcessor @@ -59,6 +76,7 @@ public EntityProcessor(Class registeredClass) { * @param cls class to be registered * @return an array of strings of all field values of the registered class */ + // todo JH this method has side effects that should be addressed private String[] registerClass(Class cls, List> eligibleClasses) { if (!eligibleClasses.contains(cls)) throw new EntityProcessorException( @@ -77,7 +95,20 @@ private String[] registerClass(Class cls, List> .forEach( pd -> { // invoke method to get value if (pd.getReadMethod() != null) { - fieldNameToMethod.put(pd.getName(), pd.getReadMethod()); + + // OperationTime needs to be replaced by operatesFrom and operatesUntil + String fieldName = pd.getName(); + if (fieldName.equalsIgnoreCase(OPERATION_TIME_FIELD_NAME)) { + fieldName = OPERATES_FROM; + fieldNameToMethod.put(OPERATES_UNTIL, pd.getReadMethod()); + } + + // VoltageLevel needs to be replaced by id and nominalVoltage + if (fieldName.equalsIgnoreCase(VOLT_LVL_FIELD_NAME)) { + fieldName = V_RATED; + fieldNameToMethod.put(VOLT_LVL, pd.getReadMethod()); + } + fieldNameToMethod.put(fieldName, pd.getReadMethod()); } }); @@ -89,9 +120,10 @@ private String[] registerClass(Class cls, List> // uuid should always be the first element in the map String[] filteredArray = fieldNameToMethod.keySet().stream() - .filter(x -> !x.toLowerCase().contains(uuidString)) + .filter(x -> !x.toLowerCase().contains(UUID_FIELD_NAME)) .toArray(String[]::new); - return ArrayUtils.addAll(new String[] {uuidString}, filteredArray); + + return ArrayUtils.addAll(new String[] {UUID_FIELD_NAME}, filteredArray); } /** @@ -115,14 +147,97 @@ public Optional> handleEntity(T entity) { } /** - * Actual implementation of the handling process. Depends on the entity that should be processed - * and hence needs to be implemented individually + * // todo JH refresh text Actual implementation of the handling process. Depends on the entity + * that should be processed and hence needs to be implemented individually * * @param entity the entity that should be 'de-serialized' into a map of fieldName -> fieldValue * @return an optional Map with fieldName -> fieldValue or an empty optional if an error occurred * during processing */ - protected abstract Optional> processEntity(T entity); + private Optional> processEntity(T entity) { + + Optional> resultMapOpt; + + try { + LinkedHashMap resultMap = new LinkedHashMap<>(); + for (String fieldName : headerElements) { + Method method = fieldNameToMethod.get(fieldName); + Optional methodReturnObjectOpt = Optional.ofNullable(method.invoke(entity)); + + if (methodReturnObjectOpt.isPresent()) { + resultMap.put( + fieldName, processMethodResult(methodReturnObjectOpt.get(), method, fieldName)); + } else { + resultMap.put(fieldName, ""); + } + } + resultMapOpt = Optional.of(resultMap); + } catch (Exception e) { + log.error("Error during entity processing:", e); + resultMapOpt = Optional.empty(); + } + return resultMapOpt; + } + + private String processMethodResult(Object methodReturnObject, Method method, String fieldName) { + + StringBuilder resultStringBuilder = new StringBuilder(); + + switch (method.getReturnType().getSimpleName()) { + // primitives (Boolean, Character, Byte, Short, Integer, Long, Float, Double, String, + case "UUID": + case "boolean": + case "int": + case "String": + resultStringBuilder.append(methodReturnObject.toString()); + break; + case "Quantity": + resultStringBuilder.append( + handleQuantity((Quantity) methodReturnObject, fieldName) + .orElseThrow( + () -> + new EntityProcessorException( + "Unable to process quantity value for attribute '" + + fieldName + + "' in result entity " + + getRegisteredClass().getSimpleName() + + ".class."))); + break; + case "ZonedDateTime": + resultStringBuilder.append(processZonedDateTime((ZonedDateTime) methodReturnObject)); + break; + case "OperationTime": + resultStringBuilder.append( + processOperationTime((OperationTime) methodReturnObject, fieldName)); + break; + case "OperatorInput": + resultStringBuilder.append( + ((OperatorInput) methodReturnObject) + .getUuid()); // todo can be moved to own method as this is needed also for types + break; + case "VoltageLevel": + resultStringBuilder.append( + processVoltageLevel((VoltageLevel) methodReturnObject, fieldName)); + break; + case "Point": + case "LineString": // todo check + resultStringBuilder.append(geoJsonWriter.write((Geometry) methodReturnObject)); + break; + default: + throw new EntityProcessorException( + "Unable to process value for attribute/field '" + + fieldName + + "' and method return type '" + + method.getReturnType().getSimpleName() + + "' for method with name '" + + method.getName() + + "' in system participant result model " + + getRegisteredClass().getSimpleName() + + ".class."); + } + + return resultStringBuilder.toString(); + } /** * Standard method to process a ZonedDateTime to a String based on a method return object NOTE: @@ -136,6 +251,56 @@ protected String processZonedDateTime(ZonedDateTime zonedDateTime) { return TimeTools.toString(zonedDateTime); } + /** + * TODO JH + * + * @param operationTime + * @param fieldName + * @return + */ + protected String processOperationTime(OperationTime operationTime, String fieldName) { + StringBuilder resultStringBuilder = new StringBuilder(); + + if (fieldName.equalsIgnoreCase(OPERATES_FROM)) + operationTime + .getStartDate() + .ifPresent(startDate -> resultStringBuilder.append(processZonedDateTime(startDate))); + + if (fieldName.equalsIgnoreCase(OPERATES_UNTIL)) + operationTime + .getEndDate() + .ifPresent(endDate -> resultStringBuilder.append(processZonedDateTime(endDate))); + + return resultStringBuilder.toString(); + } + + /** + * todo JH + * + * @param voltageLevel + * @return + */ + protected String processVoltageLevel(VoltageLevel voltageLevel, String fieldName) { + + StringBuilder resultStringBuilder = new StringBuilder(); + if (fieldName.equalsIgnoreCase(VOLT_LVL)) resultStringBuilder.append(voltageLevel.getId()); + + if (fieldName.equalsIgnoreCase(V_RATED)) + resultStringBuilder.append( + handleQuantity(voltageLevel.getNominalVoltage(), fieldName) + .orElseThrow( + () -> + new EntityProcessorException( + "Unable to process quantity value for attribute '" + + fieldName + + "' in result entity " + + getRegisteredClass().getSimpleName() + + ".class."))); + ; + + return resultStringBuilder.toString(); + } + /** * Standard method to process a Quantity to a String based on a method return object * @@ -152,6 +317,8 @@ protected Optional handleQuantity(Quantity quantity, String fieldName case "p": case "q": case "energy": + case "vTarget": + case "vrated": normalizedQuantityValue = handleProcessorSpecificQuantity(quantity, fieldName); break; case "soc": @@ -183,7 +350,7 @@ protected Optional handleQuantity(Quantity quantity, String fieldName break; default: log.error( - "Cannot process quantity {} for field with name {} in model processing!", + "Cannot process quantity with value '{}' for field with name {} in model processing!", quantity, fieldName); break; diff --git a/src/main/java/edu/ie3/datamodel/io/processor/input/AssetInputProcessor.java b/src/main/java/edu/ie3/datamodel/io/processor/input/AssetInputProcessor.java new file mode 100644 index 000000000..f39f68244 --- /dev/null +++ b/src/main/java/edu/ie3/datamodel/io/processor/input/AssetInputProcessor.java @@ -0,0 +1,113 @@ +/* + * © 2020. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation +*/ +package edu.ie3.datamodel.io.processor.input; + +import edu.ie3.datamodel.io.processor.EntityProcessor; +import edu.ie3.datamodel.models.StandardUnits; +import edu.ie3.datamodel.models.input.*; +import edu.ie3.datamodel.models.input.connector.*; +import edu.ie3.datamodel.models.input.system.*; +import edu.ie3.datamodel.models.input.thermal.CylindricalStorageInput; +import edu.ie3.datamodel.models.input.thermal.ThermalBusInput; +import edu.ie3.datamodel.models.input.thermal.ThermalHouseInput; +import edu.ie3.datamodel.models.result.system.*; +import java.util.*; +import javax.measure.Quantity; +import javax.measure.quantity.Dimensionless; +import javax.measure.quantity.ElectricPotential; + +/** + * //ToDo: Class Description + * + * @version 0.1 + * @since 23.03.20 + */ +public class AssetInputProcessor extends EntityProcessor { + + /** The entities that can be used within this processor */ + public static final List> eligibleEntityClasses = + Collections.unmodifiableList( + Arrays.asList( + FixedFeedInInput.class, + PvInput.class, + WecInput.class, + ChpInput.class, + BmInput.class, + EvInput.class, + LoadInput.class, + StorageInput.class, + HpInput.class, + LineInput.class, + SwitchInput.class, + Transformer2WInput.class, + Transformer3WInput.class, + ThermalHouseInput.class, + CylindricalStorageInput.class, + ThermalBusInput.class, + MeasurementUnitInput.class, + NodeInput.class, + EvcsInput.class)); + + public AssetInputProcessor(Class registeredClass) { + super(registeredClass); + } + + // @Override + // protected Optional> processEntity(AssetInput entity) { + // Optional> resultMapOpt; + // + // try { + // LinkedHashMap resultMap = new LinkedHashMap<>(); + // for(String fieldName : headerElements) { + // Method method = fieldNameToMethod.get(fieldName); + // Optional methodReturnObjectOpt = + // Optional.ofNullable(method.invoke(entity)); + // + // if(methodReturnObjectOpt.isPresent()) { + // resultMap.put(fieldName, processMethodResult(methodReturnObjectOpt.get(), + // method, fieldName)); + // } else { + // resultMap.put(fieldName, ""); + // } + // } + // resultMapOpt = Optional.of(resultMap); + // } catch(Exception e) { + // log.error("Error during entity processing in ResultEntityProcessor:", e); + // resultMapOpt = Optional.empty(); + // } + // return resultMapOpt; + // } + + @Override + protected Optional handleProcessorSpecificQuantity( + Quantity quantity, String fieldName) { + Optional normalizedQuantityValue = Optional.empty(); + switch (fieldName) { + case "vTarget": + normalizedQuantityValue = + quantityValToOptionalString( + quantity.asType(Dimensionless.class).to(StandardUnits.TARGET_VOLTAGE_MAGNITUDE)); + break; + case "vrated": + normalizedQuantityValue = + quantityValToOptionalString( + quantity.asType(ElectricPotential.class).to(StandardUnits.RATED_VOLTAGE_MAGNITUDE)); + break; + default: + log.error( + "Cannot process quantity with value '{}' for field with name {} in result entity processing!", + quantity, + fieldName); + break; + } + return normalizedQuantityValue; + } + + @Override + protected List> getAllEligibleClasses() { + return eligibleEntityClasses; + } +} diff --git a/src/main/java/edu/ie3/datamodel/io/processor/result/InputEntityProcessor.java b/src/main/java/edu/ie3/datamodel/io/processor/result/InputEntityProcessor.java deleted file mode 100644 index 365f8428f..000000000 --- a/src/main/java/edu/ie3/datamodel/io/processor/result/InputEntityProcessor.java +++ /dev/null @@ -1,42 +0,0 @@ -package edu.ie3.datamodel.io.processor.result; - -import edu.ie3.datamodel.io.processor.EntityProcessor; -import edu.ie3.datamodel.models.input.InputEntity; - -import javax.measure.Quantity; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Optional; - - -/** - * //ToDo: Class Description - * - * @version 0.1 - * @since 23.03.20 - */ -public class InputEntityProcessor extends EntityProcessor { - /** - * Create a new EntityProcessor - * - * @param registeredClass the class the entity processor should be able to handle - */ - public InputEntityProcessor(Class registeredClass) { - super(registeredClass); - } - - @Override - protected Optional> processEntity(InputEntity entity) { - return Optional.empty(); - } - - @Override - protected Optional handleProcessorSpecificQuantity(Quantity quantity, String fieldName) { - return Optional.empty(); - } - - @Override - protected List> getAllEligibleClasses() { - return null; - } -} diff --git a/src/main/java/edu/ie3/datamodel/io/processor/result/ResultEntityProcessor.java b/src/main/java/edu/ie3/datamodel/io/processor/result/ResultEntityProcessor.java index 3507c7662..691a34976 100644 --- a/src/main/java/edu/ie3/datamodel/io/processor/result/ResultEntityProcessor.java +++ b/src/main/java/edu/ie3/datamodel/io/processor/result/ResultEntityProcessor.java @@ -5,7 +5,6 @@ */ package edu.ie3.datamodel.io.processor.result; -import edu.ie3.datamodel.exceptions.EntityProcessorException; import edu.ie3.datamodel.io.factory.result.SystemParticipantResultFactory; import edu.ie3.datamodel.io.processor.EntityProcessor; import edu.ie3.datamodel.models.StandardUnits; @@ -18,8 +17,6 @@ import edu.ie3.datamodel.models.result.system.*; import edu.ie3.datamodel.models.result.thermal.CylindricalStorageResult; import edu.ie3.datamodel.models.result.thermal.ThermalHouseResult; -import java.lang.reflect.Method; -import java.time.ZonedDateTime; import java.util.*; import javax.measure.Quantity; import javax.measure.quantity.Energy; @@ -61,32 +58,6 @@ public ResultEntityProcessor(Class registeredClass) { super(registeredClass); } - @Override - protected Optional> processEntity(ResultEntity entity) { - - Optional> resultMapOpt; - - try { - LinkedHashMap resultMap = new LinkedHashMap<>(); - for (String fieldName : headerElements) { - Method method = fieldNameToMethod.get(fieldName); - Optional methodReturnObjectOpt = Optional.ofNullable(method.invoke(entity)); - - if (methodReturnObjectOpt.isPresent()) { - resultMap.put( - fieldName, processMethodResult(methodReturnObjectOpt.get(), method, fieldName)); - } else { - resultMap.put(fieldName, ""); - } - } - resultMapOpt = Optional.of(resultMap); - } catch (Exception e) { - log.error("Error during entity processing in ResultEntityProcessor:", e); - resultMapOpt = Optional.empty(); - } - return resultMapOpt; - } - @Override protected Optional handleProcessorSpecificQuantity( Quantity quantity, String fieldName) { @@ -109,7 +80,7 @@ protected Optional handleProcessorSpecificQuantity( break; default: log.error( - "Cannot process quantity {} for field with name {} in result entity processing!", + "Cannot process quantity with value '{}' for field with name {} in result entity processing!", quantity, fieldName); break; @@ -121,46 +92,4 @@ protected Optional handleProcessorSpecificQuantity( protected List> getAllEligibleClasses() { return eligibleEntityClasses; } - - private String processMethodResult(Object methodReturnObject, Method method, String fieldName) { - - StringBuilder resultStringBuilder = new StringBuilder(); - - switch (method.getReturnType().getSimpleName()) { - // primitives (Boolean, Character, Byte, Short, Integer, Long, Float, Double, String, - case "UUID": - case "boolean": - case "int": - resultStringBuilder.append(methodReturnObject.toString()); - break; - case "Quantity": - resultStringBuilder.append( - handleQuantity((Quantity) methodReturnObject, fieldName) - .orElseThrow( - () -> - new EntityProcessorException( - "Unable to process quantity value for attribute '" - + fieldName - + "' in result entity " - + getRegisteredClass().getSimpleName() - + ".class."))); - break; - case "ZonedDateTime": - resultStringBuilder.append(processZonedDateTime((ZonedDateTime) methodReturnObject)); - break; - default: - throw new EntityProcessorException( - "Unable to process value for attribute/field '" - + fieldName - + "' and method return type '" - + method.getReturnType().getSimpleName() - + "' for method with name '" - + method.getName() - + "' in system participant result model " - + getRegisteredClass().getSimpleName() - + ".class."); - } - - return resultStringBuilder.toString(); - } } diff --git a/src/test/groovy/edu/ie3/datamodel/io/processor/input/AssetInputProcessorTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/processor/input/AssetInputProcessorTest.groovy new file mode 100644 index 000000000..7433826d8 --- /dev/null +++ b/src/test/groovy/edu/ie3/datamodel/io/processor/input/AssetInputProcessorTest.groovy @@ -0,0 +1,101 @@ +package edu.ie3.datamodel.io.processor.input + +import edu.ie3.datamodel.models.input.NodeInput +import edu.ie3.datamodel.models.input.connector.Transformer2WInput +import edu.ie3.datamodel.models.input.connector.Transformer3WInput +import edu.ie3.test.common.GridTestData +import edu.ie3.util.TimeTools +import spock.lang.Specification + +import java.time.ZoneId + +/** + * //ToDo: Class Description + * + * @version 0.1* @since 24.03.20 + */ +class AssetInputProcessorTest extends Specification { + + def "A ResultEntityProcessor should de-serialize a provided SystemParticipantInput correctly"() { + + + } + + def "A ResultEntityProcessor should de-serialize a provided NodeInput correctly"() { + given: + TimeTools.initialize(ZoneId.of("UTC"), Locale.GERMANY, "yyyy-MM-dd HH:mm:ss") + def sysPartResProcessor = new AssetInputProcessor(NodeInput) + def validResult = GridTestData.nodeA + + Map expectedResults = [ + "uuid" : "5dc88077-aeb6-4711-9142-db57292640b1", + "geoPosition" : "{\"type\":\"Point\",\"coordinates\":[7.411111,51.492528],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}}}", + "id" : "node_a", + "operatesuntil": "2020-03-25 15:11:31", + "operatesfrom" : "2020-03-24 15:11:31", + "operator" : "8f9682df-0744-4b58-a122-f0dc730f6510", + "slack" : "true", + "subnet" : "1", + "vTarget" : "1.0", + "voltlvl" : "Höchstspannung (380 kV)", + "vrated" : "380.0", + ] + + when: "the entity is passed to the processor" + def processingResult = sysPartResProcessor.handleEntity(validResult) + + + then: "make sure that the result is as expected " + processingResult.present + processingResult.get() == expectedResults + +// println "[" +// processingResult.get().each { k, v -> println "\"${k}\":\"${v.replaceAll("\"", \"\\"\")}\"," } +// println "]" + + } + + + def "A ResultEntityProcessor should de-serialize a provided ConnectorInput correctly"() { + given: + TimeTools.initialize(ZoneId.of("UTC"), Locale.GERMANY, "yyyy-MM-dd HH:mm:ss") + def sysPartResProcessor = new AssetInputProcessor(modelClass) + def validInput = modelInstance + + + Map expectedResults = [ + "uuid" : "5dc88077-aeb6-4711-9142-db57292640b1", + "geoPosition" : "{\"type\":\"Point\",\"coordinates\":[7.411111,51.492528],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}}}", + "id" : "node_a", + "operatesuntil": "2020-03-25 15:11:31", + "operatesfrom" : "2020-03-24 15:11:31", + "operator" : "8f9682df-0744-4b58-a122-f0dc730f6510", + "slack" : "true", + "subnet" : "1", + "vTarget" : "1.0", + "voltlvl" : "Höchstspannung (380 kV)", + "vrated" : "380.0", + ] + + when: "the entity is passed to the processor" + def processingResult = sysPartResProcessor.handleEntity(validInput) + + + then: "make sure that the result is as expected " + processingResult.present + processingResult.get() == expectedResults + + where: + modelClass | modelInstance || expectedResult + Transformer3WInput | GridTestData.transformerAtoBtoC || "// todo " + Transformer2WInput | GridTestData.transformerCtoG || "// todo " + // todo JH Line, Switch, Transformer2, Transformer3, + +// println "[" +// processingResult.get().each { k, v -> println "\"${k}\":\"${v.replaceAll("\"", \"\\"\")}\"," } +// println "]" + + } + + +} diff --git a/src/test/groovy/edu/ie3/test/common/GridTestData.groovy b/src/test/groovy/edu/ie3/test/common/GridTestData.groovy index 1675a1d83..372150c3e 100644 --- a/src/test/groovy/edu/ie3/test/common/GridTestData.groovy +++ b/src/test/groovy/edu/ie3/test/common/GridTestData.groovy @@ -8,9 +8,14 @@ import edu.ie3.datamodel.models.input.connector.Transformer3WInput import edu.ie3.datamodel.models.input.connector.type.Transformer2WTypeInput import edu.ie3.datamodel.models.input.connector.type.Transformer3WTypeInput import edu.ie3.datamodel.models.voltagelevels.GermanVoltageLevelUtils +import edu.ie3.util.TimeTools +import org.locationtech.jts.geom.Point +import org.locationtech.jts.io.geojson.GeoJsonReader import tec.uom.se.quantity.Quantities import tec.uom.se.unit.MetricPrefix +import java.time.ZonedDateTime + import static edu.ie3.util.quantities.PowerSystemUnits.DEGREE_GEOM import static edu.ie3.util.quantities.PowerSystemUnits.KILOVOLT import static edu.ie3.util.quantities.PowerSystemUnits.KILOVOLTAMPERE @@ -21,6 +26,8 @@ import static tec.uom.se.unit.Units.SIEMENS class GridTestData { + private static final GeoJsonReader geoJsonReader = new GeoJsonReader(); + private static final Transformer2WTypeInput transformerTypeBtoD = new Transformer2WTypeInput( UUID.randomUUID(), "HS-MS_1", @@ -115,13 +122,13 @@ class GridTestData { ) public static final NodeInput nodeA = new NodeInput( - UUID.randomUUID(), - OperationTime.notLimited(), - OperatorInput.NO_OPERATOR_ASSIGNED, + UUID.fromString("5dc88077-aeb6-4711-9142-db57292640b1"), + OperationTime.builder().withStart(TimeTools.toZonedDateTime("2020-03-24 15:11:31")).withEnd(TimeTools.toZonedDateTime("2020-03-25 15:11:31")).build(), + new OperatorInput(UUID.fromString("8f9682df-0744-4b58-a122-f0dc730f6510"), "TestOperator"), "node_a", Quantities.getQuantity(1d, PU), true, - null, + (Point) geoJsonReader.read("{ \"type\": \"Point\", \"coordinates\": [7.411111, 51.492528] }"), GermanVoltageLevelUtils.EHV_380KV, 1) public static final NodeInput nodeB = new NodeInput( @@ -234,9 +241,9 @@ class GridTestData { true ) public static final Transformer2WInput transformerCtoG = new Transformer2WInput( - UUID.randomUUID(), - OperationTime.notLimited(), - OperatorInput.NO_OPERATOR_ASSIGNED, + UUID.fromString("5dc88077-aeb6-4711-9142-db57292640b1"), + OperationTime.builder().withStart(TimeTools.toZonedDateTime("2020-03-24 15:11:31")).withEnd(TimeTools.toZonedDateTime("2020-03-25 15:11:31")).build(), + new OperatorInput(UUID.fromString("8f9682df-0744-4b58-a122-f0dc730f6510"), "TestOperator"), "2w_parallel_2", nodeC, nodeF, @@ -247,9 +254,9 @@ class GridTestData { ) public static Transformer3WInput transformerAtoBtoC = new Transformer3WInput( - UUID.randomUUID(), - OperationTime.notLimited(), - OperatorInput.NO_OPERATOR_ASSIGNED, + UUID.fromString("5dc88077-aeb6-4711-9142-db57292640b1"), + OperationTime.builder().withStart(TimeTools.toZonedDateTime("2020-03-24 15:11:31")).withEnd(TimeTools.toZonedDateTime("2020-03-25 15:11:31")).build(), + new OperatorInput(UUID.fromString("8f9682df-0744-4b58-a122-f0dc730f6510"), "TestOperator"), "3w_test", nodeA, nodeB, @@ -259,4 +266,6 @@ class GridTestData { 0, true ) + + } diff --git a/src/test/resources/log4j2-test.xml b/src/test/resources/log4j2-test.xml index f166257d1..b8912e9d1 100644 --- a/src/test/resources/log4j2-test.xml +++ b/src/test/resources/log4j2-test.xml @@ -25,7 +25,7 @@ - + From 7561efd0078a8f0586f5c5e8d04df8b0b93d285c Mon Sep 17 00:00:00 2001 From: Johannes Hiry Date: Tue, 24 Mar 2020 17:04:09 +0100 Subject: [PATCH 04/21] support for 2W- and 3W-Transformers in AssetInputProcessor --- .../io/processor/EntityProcessor.java | 10 ++- .../input/AssetInputProcessorTest.groovy | 66 +++++++++++-------- .../edu/ie3/test/common/GridTestData.groovy | 10 +-- 3 files changed, 50 insertions(+), 36 deletions(-) diff --git a/src/main/java/edu/ie3/datamodel/io/processor/EntityProcessor.java b/src/main/java/edu/ie3/datamodel/io/processor/EntityProcessor.java index 4c9ed58a3..a84cb719a 100644 --- a/src/main/java/edu/ie3/datamodel/io/processor/EntityProcessor.java +++ b/src/main/java/edu/ie3/datamodel/io/processor/EntityProcessor.java @@ -6,7 +6,6 @@ package edu.ie3.datamodel.io.processor; import edu.ie3.datamodel.exceptions.EntityProcessorException; -import edu.ie3.datamodel.io.factory.input.AssetInputEntityFactory; import edu.ie3.datamodel.io.factory.input.NodeInputFactory; import edu.ie3.datamodel.io.processor.result.ResultEntityProcessor; import edu.ie3.datamodel.models.OperationTime; @@ -47,8 +46,8 @@ public abstract class EntityProcessor { protected final LinkedHashMap fieldNameToMethod = new LinkedHashMap<>(); private static final String OPERATION_TIME_FIELD_NAME = OperationTime.class.getSimpleName(); - private static final String OPERATES_FROM = AssetInputEntityFactory.OPERATES_FROM; - private static final String OPERATES_UNTIL = AssetInputEntityFactory.OPERATES_UNTIL; + private static final String OPERATES_FROM = "operatesFrom"; + private static final String OPERATES_UNTIL = "operatesUntil"; private static final String VOLT_LVL_FIELD_NAME = "voltLvl"; private static final String VOLT_LVL = NodeInputFactory.VOLT_LVL; @@ -223,6 +222,11 @@ private String processMethodResult(Object methodReturnObject, Method method, Str case "LineString": // todo check resultStringBuilder.append(geoJsonWriter.write((Geometry) methodReturnObject)); break; + case "NodeInput": + case "Transformer3WTypeInput": + case "Transformer2WTypeInput": + resultStringBuilder.append(((UniqueEntity) methodReturnObject).getUuid()); + break; default: throw new EntityProcessorException( "Unable to process value for attribute/field '" diff --git a/src/test/groovy/edu/ie3/datamodel/io/processor/input/AssetInputProcessorTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/processor/input/AssetInputProcessorTest.groovy index 7433826d8..3fa08f6dd 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/processor/input/AssetInputProcessorTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/processor/input/AssetInputProcessorTest.groovy @@ -31,8 +31,8 @@ class AssetInputProcessorTest extends Specification { "uuid" : "5dc88077-aeb6-4711-9142-db57292640b1", "geoPosition" : "{\"type\":\"Point\",\"coordinates\":[7.411111,51.492528],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}}}", "id" : "node_a", - "operatesuntil": "2020-03-25 15:11:31", - "operatesfrom" : "2020-03-24 15:11:31", + "operatesUntil": "2020-03-25 15:11:31", + "operatesFrom" : "2020-03-24 15:11:31", "operator" : "8f9682df-0744-4b58-a122-f0dc730f6510", "slack" : "true", "subnet" : "1", @@ -49,10 +49,6 @@ class AssetInputProcessorTest extends Specification { processingResult.present processingResult.get() == expectedResults -// println "[" -// processingResult.get().each { k, v -> println "\"${k}\":\"${v.replaceAll("\"", \"\\"\")}\"," } -// println "]" - } @@ -62,38 +58,52 @@ class AssetInputProcessorTest extends Specification { def sysPartResProcessor = new AssetInputProcessor(modelClass) def validInput = modelInstance - - Map expectedResults = [ - "uuid" : "5dc88077-aeb6-4711-9142-db57292640b1", - "geoPosition" : "{\"type\":\"Point\",\"coordinates\":[7.411111,51.492528],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}}}", - "id" : "node_a", - "operatesuntil": "2020-03-25 15:11:31", - "operatesfrom" : "2020-03-24 15:11:31", - "operator" : "8f9682df-0744-4b58-a122-f0dc730f6510", - "slack" : "true", - "subnet" : "1", - "vTarget" : "1.0", - "voltlvl" : "Höchstspannung (380 kV)", - "vrated" : "380.0", - ] - when: "the entity is passed to the processor" def processingResult = sysPartResProcessor.handleEntity(validInput) then: "make sure that the result is as expected " processingResult.present - processingResult.get() == expectedResults + + processingResult.get().forEach { k, v -> + if (k != "nodeInternal") // the internal 3w node is always randomly generated, hence we can skip to test on this + assert(v == expectedResult.get(k)) + } + where: modelClass | modelInstance || expectedResult - Transformer3WInput | GridTestData.transformerAtoBtoC || "// todo " - Transformer2WInput | GridTestData.transformerCtoG || "// todo " - // todo JH Line, Switch, Transformer2, Transformer3, + Transformer3WInput | GridTestData.transformerAtoBtoC || [ + "uuid" : "5dc88077-aeb6-4711-9142-db57292640b1", + "autoTap" : "true", + "id" : "3w_test", + "noOfParallelDevices": "1", + "nodeA" : "5dc88077-aeb6-4711-9142-db57292640b1", + "nodeB" : "47d29df0-ba2d-4d23-8e75-c82229c5c758", + "nodeC" : "bd837a25-58f3-44ac-aa90-c6b6e3cd91b2", + "operatesUntil" : "2020-03-25 15:11:31", + "operatesFrom" : "2020-03-24 15:11:31", + "operator" : "8f9682df-0744-4b58-a122-f0dc730f6510", + "tapPos" : "0", + "type" : "5b0ee546-21fb-4a7f-a801-5dbd3d7bb356", + ] + Transformer2WInput | GridTestData.transformerCtoG || [ + "uuid" : "5dc88077-aeb6-4711-9142-db57292640b1", + "autoTap" : "true", + "id" : "2w_parallel_2", + "noOfParallelDevices": "1", + "nodeA" : "bd837a25-58f3-44ac-aa90-c6b6e3cd91b2", + "nodeB" : "aaa74c1a-d07e-4615-99a5-e991f1d81cc4", + "operatesUntil" : "2020-03-25 15:11:31", + "operatesFrom" : "2020-03-24 15:11:31", + "operator" : "8f9682df-0744-4b58-a122-f0dc730f6510", + "tapPos" : "0", + "type" : "08559390-d7c0-4427-a2dc-97ba312ae0ac", + ] + + + // todo JH Line, Switch, -// println "[" -// processingResult.get().each { k, v -> println "\"${k}\":\"${v.replaceAll("\"", \"\\"\")}\"," } -// println "]" } diff --git a/src/test/groovy/edu/ie3/test/common/GridTestData.groovy b/src/test/groovy/edu/ie3/test/common/GridTestData.groovy index 372150c3e..d9b7aa815 100644 --- a/src/test/groovy/edu/ie3/test/common/GridTestData.groovy +++ b/src/test/groovy/edu/ie3/test/common/GridTestData.groovy @@ -80,7 +80,7 @@ class GridTestData { 5 ) private static final Transformer2WTypeInput transformerTypeCtoX = new Transformer2WTypeInput( - UUID.randomUUID(), + UUID.fromString("08559390-d7c0-4427-a2dc-97ba312ae0ac"), "MS-NS_1", Quantities.getQuantity(10.078, OHM), Quantities.getQuantity(23.312, OHM), @@ -98,7 +98,7 @@ class GridTestData { ) private static final Transformer3WTypeInput transformerTypeAtoBtoC = new Transformer3WTypeInput( - UUID.randomUUID(), + UUID.fromString("5b0ee546-21fb-4a7f-a801-5dbd3d7bb356"), "HöS-HS-MS_1", Quantities.getQuantity(120000d, KILOVOLTAMPERE), Quantities.getQuantity(60000d, KILOVOLTAMPERE), @@ -132,7 +132,7 @@ class GridTestData { GermanVoltageLevelUtils.EHV_380KV, 1) public static final NodeInput nodeB = new NodeInput( - UUID.randomUUID(), + UUID.fromString("47d29df0-ba2d-4d23-8e75-c82229c5c758"), OperationTime.notLimited(), OperatorInput.NO_OPERATOR_ASSIGNED, "node_b", @@ -142,7 +142,7 @@ class GridTestData { GermanVoltageLevelUtils.HV, 2) public static final NodeInput nodeC = new NodeInput( - UUID.randomUUID(), + UUID.fromString("bd837a25-58f3-44ac-aa90-c6b6e3cd91b2"), OperationTime.notLimited(), OperatorInput.NO_OPERATOR_ASSIGNED, "node_c", @@ -172,7 +172,7 @@ class GridTestData { GermanVoltageLevelUtils.MV_10KV, 5) public static final NodeInput nodeF = new NodeInput( - UUID.randomUUID(), + UUID.fromString("aaa74c1a-d07e-4615-99a5-e991f1d81cc4"), OperationTime.notLimited(), OperatorInput.NO_OPERATOR_ASSIGNED, "node_f", From 1a3da73946f82739c2492daca80e8ae43f441cb6 Mon Sep 17 00:00:00 2001 From: Johannes Hiry Date: Tue, 24 Mar 2020 17:07:19 +0100 Subject: [PATCH 05/21] change transformer wiring in GridTestData according to the transformer naming --- src/test/groovy/edu/ie3/test/common/GridTestData.groovy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/groovy/edu/ie3/test/common/GridTestData.groovy b/src/test/groovy/edu/ie3/test/common/GridTestData.groovy index d9b7aa815..8d532b496 100644 --- a/src/test/groovy/edu/ie3/test/common/GridTestData.groovy +++ b/src/test/groovy/edu/ie3/test/common/GridTestData.groovy @@ -182,7 +182,7 @@ class GridTestData { GermanVoltageLevelUtils.LV, 6) public static final NodeInput nodeG = new NodeInput( - UUID.randomUUID(), + UUID.fromString("aaa74c1a-d07e-4615-99a5-e991f1d81cc4"), OperationTime.notLimited(), OperatorInput.NO_OPERATOR_ASSIGNED, "node_g", @@ -246,7 +246,7 @@ class GridTestData { new OperatorInput(UUID.fromString("8f9682df-0744-4b58-a122-f0dc730f6510"), "TestOperator"), "2w_parallel_2", nodeC, - nodeF, + nodeG, 1, transformerTypeCtoX, 0, From 7bf078c9f19f36bc5970b15afd6a331bd0970e6e Mon Sep 17 00:00:00 2001 From: Johannes Hiry Date: Tue, 24 Mar 2020 17:56:03 +0100 Subject: [PATCH 06/21] added support for all ConnectorInput entities in EntityProcessor --- .../io/processor/EntityProcessor.java | 22 +++++---- .../input/AssetInputProcessorTest.groovy | 35 ++++++++++++-- .../edu/ie3/test/common/GridTestData.groovy | 48 ++++++++++++++++++- 3 files changed, 93 insertions(+), 12 deletions(-) diff --git a/src/main/java/edu/ie3/datamodel/io/processor/EntityProcessor.java b/src/main/java/edu/ie3/datamodel/io/processor/EntityProcessor.java index a84cb719a..b53a1d98a 100644 --- a/src/main/java/edu/ie3/datamodel/io/processor/EntityProcessor.java +++ b/src/main/java/edu/ie3/datamodel/io/processor/EntityProcessor.java @@ -11,7 +11,6 @@ import edu.ie3.datamodel.models.OperationTime; import edu.ie3.datamodel.models.StandardUnits; import edu.ie3.datamodel.models.UniqueEntity; -import edu.ie3.datamodel.models.input.OperatorInput; import edu.ie3.datamodel.models.voltagelevels.VoltageLevel; import edu.ie3.util.TimeTools; import java.beans.Introspector; @@ -23,6 +22,7 @@ import javax.measure.Quantity; import javax.measure.quantity.Dimensionless; import javax.measure.quantity.ElectricCurrent; +import javax.measure.quantity.Length; import javax.measure.quantity.Power; import org.apache.commons.lang3.ArrayUtils; import org.apache.logging.log4j.LogManager; @@ -209,24 +209,25 @@ private String processMethodResult(Object methodReturnObject, Method method, Str resultStringBuilder.append( processOperationTime((OperationTime) methodReturnObject, fieldName)); break; - case "OperatorInput": - resultStringBuilder.append( - ((OperatorInput) methodReturnObject) - .getUuid()); // todo can be moved to own method as this is needed also for types - break; case "VoltageLevel": resultStringBuilder.append( processVoltageLevel((VoltageLevel) methodReturnObject, fieldName)); break; case "Point": - case "LineString": // todo check + case "LineString": resultStringBuilder.append(geoJsonWriter.write((Geometry) methodReturnObject)); break; case "NodeInput": case "Transformer3WTypeInput": case "Transformer2WTypeInput": + case "LineTypeInput": + case "OperatorInput": resultStringBuilder.append(((UniqueEntity) methodReturnObject).getUuid()); break; + case "Optional": // todo needs to be removed asap as this is very dangerous, but necessary as + // long as #75 is not addressed + resultStringBuilder.append(((Optional) methodReturnObject).orElse("")); + break; default: throw new EntityProcessorException( "Unable to process value for attribute/field '" @@ -235,7 +236,7 @@ private String processMethodResult(Object methodReturnObject, Method method, Str + method.getReturnType().getSimpleName() + "' for method with name '" + method.getName() - + "' in system participant result model " + + "' in in entity model " + getRegisteredClass().getSimpleName() + ".class."); } @@ -352,6 +353,11 @@ protected Optional handleQuantity(Quantity quantity, String fieldName quantityValToOptionalString( quantity.asType(Dimensionless.class).to(StandardUnits.FILL_LEVEL)); break; + case "length": + normalizedQuantityValue = + quantityValToOptionalString( + quantity.asType(Length.class).to(StandardUnits.LINE_LENGTH)); + break; default: log.error( "Cannot process quantity with value '{}' for field with name {} in model processing!", diff --git a/src/test/groovy/edu/ie3/datamodel/io/processor/input/AssetInputProcessorTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/processor/input/AssetInputProcessorTest.groovy index 3fa08f6dd..5beeaf524 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/processor/input/AssetInputProcessorTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/processor/input/AssetInputProcessorTest.groovy @@ -1,6 +1,8 @@ package edu.ie3.datamodel.io.processor.input import edu.ie3.datamodel.models.input.NodeInput +import edu.ie3.datamodel.models.input.connector.LineInput +import edu.ie3.datamodel.models.input.connector.SwitchInput import edu.ie3.datamodel.models.input.connector.Transformer2WInput import edu.ie3.datamodel.models.input.connector.Transformer3WInput import edu.ie3.test.common.GridTestData @@ -65,9 +67,13 @@ class AssetInputProcessorTest extends Specification { then: "make sure that the result is as expected " processingResult.present + println "[" + processingResult.get().each { k, v -> println "\"${k}\":\"${v.replaceAll("\"", "\"")}\"," } + println "]" + processingResult.get().forEach { k, v -> if (k != "nodeInternal") // the internal 3w node is always randomly generated, hence we can skip to test on this - assert(v == expectedResult.get(k)) + assert (v == expectedResult.get(k)) } @@ -101,9 +107,32 @@ class AssetInputProcessorTest extends Specification { "type" : "08559390-d7c0-4427-a2dc-97ba312ae0ac", ] + SwitchInput | GridTestData.switchAtoB || [ + "uuid" : "5dc88077-aeb6-4711-9142-db57287640b1", + "closed" : "true", + "id" : "test_switch_AtoB", + "noOfParallelDevices": "1", + "nodeA" : "5dc88077-aeb6-4711-9142-db57292640b1", + "nodeB" : "47d29df0-ba2d-4d23-8e75-c82229c5c758", + "operatesUntil" : "2020-03-25 15:11:31", + "operatesFrom" : "2020-03-24 15:11:31", + "operator" : "8f9682df-0744-4b58-a122-f0dc730f6510", + ] - // todo JH Line, Switch, - + LineInput | GridTestData.lineCtoD || [ + "uuid" : "91ec3bcf-1777-4d38-af67-0bf7c9fa73c7", + "geoPosition" : "{\"type\":\"LineString\",\"coordinates\":[[7.411111,51.492528],[7.414116,51.484136]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}}}", + "id" : "test_line_AtoB", + "length" : "0.003", + "noOfParallelDevices": "2", + "nodeA" : "bd837a25-58f3-44ac-aa90-c6b6e3cd91b2", + "nodeB" : "bd865a25-58f3-44ac-aa90-c6b6e3cd91b2", + "olmCharacteristic" : "olm", + "operatesUntil" : "2020-03-25 15:11:31", + "operatesFrom" : "2020-03-24 15:11:31", + "operator" : "8f9682df-0744-4b58-a122-f0dc730f6510", + "type" : "3bed3eb3-9790-4874-89b5-a5434d408088", + ] } diff --git a/src/test/groovy/edu/ie3/test/common/GridTestData.groovy b/src/test/groovy/edu/ie3/test/common/GridTestData.groovy index 8d532b496..ae65bee59 100644 --- a/src/test/groovy/edu/ie3/test/common/GridTestData.groovy +++ b/src/test/groovy/edu/ie3/test/common/GridTestData.groovy @@ -3,16 +3,22 @@ package edu.ie3.test.common import edu.ie3.datamodel.models.OperationTime import edu.ie3.datamodel.models.input.NodeInput import edu.ie3.datamodel.models.input.OperatorInput +import edu.ie3.datamodel.models.input.connector.LineInput +import edu.ie3.datamodel.models.input.connector.SwitchInput import edu.ie3.datamodel.models.input.connector.Transformer2WInput import edu.ie3.datamodel.models.input.connector.Transformer3WInput +import edu.ie3.datamodel.models.input.connector.type.LineTypeInput import edu.ie3.datamodel.models.input.connector.type.Transformer2WTypeInput import edu.ie3.datamodel.models.input.connector.type.Transformer3WTypeInput import edu.ie3.datamodel.models.voltagelevels.GermanVoltageLevelUtils import edu.ie3.util.TimeTools +import edu.ie3.util.quantities.PowerSystemUnits +import org.locationtech.jts.geom.LineString import org.locationtech.jts.geom.Point import org.locationtech.jts.io.geojson.GeoJsonReader import tec.uom.se.quantity.Quantities import tec.uom.se.unit.MetricPrefix +import tec.uom.se.unit.Units import java.time.ZonedDateTime @@ -24,6 +30,11 @@ import static tec.uom.se.unit.Units.OHM import static tec.uom.se.unit.Units.PERCENT import static tec.uom.se.unit.Units.SIEMENS +/** + * This class contains a collection of different model instances that can be used for testing purposes. + * Please note that these entities do NOT necessarily form a valid grid. For valid topologies please refer + * to {@link ComplexTopology} + */ class GridTestData { private static final GeoJsonReader geoJsonReader = new GeoJsonReader(); @@ -152,7 +163,7 @@ class GridTestData { GermanVoltageLevelUtils.MV_20KV, 3) public static final NodeInput nodeD = new NodeInput( - UUID.randomUUID(), + UUID.fromString("bd865a25-58f3-44ac-aa90-c6b6e3cd91b2"), OperationTime.notLimited(), OperatorInput.NO_OPERATOR_ASSIGNED, "node_d", @@ -268,4 +279,39 @@ class GridTestData { ) + public static final SwitchInput switchAtoB = new SwitchInput( + UUID.fromString("5dc88077-aeb6-4711-9142-db57287640b1"), + OperationTime.builder().withStart(TimeTools.toZonedDateTime("2020-03-24 15:11:31")).withEnd(TimeTools.toZonedDateTime("2020-03-25 15:11:31")).build(), + new OperatorInput(UUID.fromString("8f9682df-0744-4b58-a122-f0dc730f6510"), "TestOperator"), + "test_switch_AtoB", + nodeA, + nodeB, + true + ) + + private static final LineTypeInput lineTypeInputCtoD = new LineTypeInput( + UUID.fromString("3bed3eb3-9790-4874-89b5-a5434d408088"), + "lineType_AtoB", + Quantities.getQuantity(0.00000000322, PowerSystemUnits.SIEMENS_PER_KILOMETRE), + Quantities.getQuantity(0, PowerSystemUnits.SIEMENS_PER_KILOMETRE), + Quantities.getQuantity(0.437, PowerSystemUnits.OHM_PER_KILOMETRE), + Quantities.getQuantity(0.356, PowerSystemUnits.OHM_PER_KILOMETRE), + Quantities.getQuantity(300, PowerSystemUnits.AMPERE), + Quantities.getQuantity(20, KILOVOLT) + + ) + + public static final LineInput lineCtoD = new LineInput( + UUID.fromString("91ec3bcf-1777-4d38-af67-0bf7c9fa73c7"), + OperationTime.builder().withStart(TimeTools.toZonedDateTime("2020-03-24 15:11:31")).withEnd(TimeTools.toZonedDateTime("2020-03-25 15:11:31")).build(), + new OperatorInput(UUID.fromString("8f9682df-0744-4b58-a122-f0dc730f6510"), "TestOperator"), + "test_line_AtoB", + nodeC, nodeD, + 2, + lineTypeInputCtoD, + Quantities.getQuantity(3, Units.METRE), + (LineString) geoJsonReader.read("{ \"type\": \"LineString\", \"coordinates\": [[7.411111, 51.492528], [7.414116, 51.484136]]}"), + Optional.of("olm") + ) + } From 456258dfbe65eeac9d358df4f295d90e35033b22 Mon Sep 17 00:00:00 2001 From: Johannes Hiry Date: Wed, 25 Mar 2020 11:51:44 +0100 Subject: [PATCH 07/21] added note for thermalBus in ChpInput --- .../java/edu/ie3/datamodel/models/input/system/ChpInput.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/edu/ie3/datamodel/models/input/system/ChpInput.java b/src/main/java/edu/ie3/datamodel/models/input/system/ChpInput.java index cd95b5610..1fea395ed 100644 --- a/src/main/java/edu/ie3/datamodel/models/input/system/ChpInput.java +++ b/src/main/java/edu/ie3/datamodel/models/input/system/ChpInput.java @@ -33,7 +33,7 @@ public class ChpInput extends SystemParticipantInput { * @param operator of the asset * @param id of the asset * @param node the asset is connected to - * @param thermalBus The thermal bus, this model is connected to + * @param thermalBus The thermal bus, this model is connected to (normally equal to the thermal bus of the provided thermal storage!) * @param qCharacteristics Description of a reactive power characteristic * @param type of CHP * @param thermalStorage Thermal storage model @@ -63,7 +63,7 @@ public ChpInput( * @param uuid of the input entity * @param id of the asset * @param node the asset is connected to - * @param thermalBus The thermal bus, this model is connected to + * @param thermalBus The thermal bus, this model is connected to (normally equal to the thermal bus of the provided thermal storage!) * @param qCharacteristics Description of a reactive power characteristic * @param type of CHP * @param thermalStorage Thermal storage model From 5a0c7cea25a32d4455a01551dbb9faa951199dbf Mon Sep 17 00:00:00 2001 From: Johannes Hiry Date: Wed, 25 Mar 2020 13:18:36 +0100 Subject: [PATCH 08/21] extended BdewLoadProfile with method to get a key from a string + adapted StorageStrategy for improved exception --- .../ie3/datamodel/models/BdewLoadProfile.java | 73 ++++++++++----- .../models/input/system/StorageStrategy.java | 90 +++++++++++-------- 2 files changed, 103 insertions(+), 60 deletions(-) diff --git a/src/main/java/edu/ie3/datamodel/models/BdewLoadProfile.java b/src/main/java/edu/ie3/datamodel/models/BdewLoadProfile.java index f95ed051c..8963568e2 100644 --- a/src/main/java/edu/ie3/datamodel/models/BdewLoadProfile.java +++ b/src/main/java/edu/ie3/datamodel/models/BdewLoadProfile.java @@ -2,35 +2,62 @@ * © 2020. TU Dortmund University, * Institute of Energy Systems, Energy Efficiency and Energy Economics, * Research group Distribution grid planning and operation -*/ + */ package edu.ie3.datamodel.models; +import edu.ie3.datamodel.models.input.system.StorageStrategy; + +import java.util.Arrays; +import java.util.stream.Collectors; + + /** * German standard electricity load profiles, defined by the bdew (Bundesverband der Energie- und * Wasserwirtschaft; engl.Federal Association of the Energy and Water Industry). For more details * see https://www.bdew.de/energie/standardlastprofile-strom/ */ public enum BdewLoadProfile implements StandardLoadProfile { - H0("h0"), // Households - L0("l0"), // Agricultural enterprises without further differentiation - L1("l1"), // Agricultural enterprises with dairy sector - L2("l2"), // Agricultural enterprises without dairy sector - G0("g0"), // Businesses without further differentiation - G1("g1"), // Workday businesses from 8 a.m. to 6 p.m. - G2("g2"), // Businesses with high consumption in evening hours - G3("g3"), // Businesses with enduring consumption - G4("g4"), // Vendor or barber shop - G5("g5"), // Bakery - G6("g6"); // Business with main consumption on weekends - - private final String key; - - BdewLoadProfile(String key) { - this.key = key.toLowerCase(); - } - - @Override - public String getKey() { - return key; - } + H0("h0"), // Households + L0("l0"), // Agricultural enterprises without further differentiation + L1("l1"), // Agricultural enterprises with dairy sector + L2("l2"), // Agricultural enterprises without dairy sector + G0("g0"), // Businesses without further differentiation + G1("g1"), // Workday businesses from 8 a.m. to 6 p.m. + G2("g2"), // Businesses with high consumption in evening hours + G3("g3"), // Businesses with enduring consumption + G4("g4"), // Vendor or barber shop + G5("g5"), // Bakery + G6("g6"); // Business with main consumption on weekends + + private final String key; + + BdewLoadProfile(String key) { + this.key = key.toLowerCase(); + } + + /** + * Get the predefined bdew load profile based on the given key + * + * @param key key to check for + * @return The corresponding bdew load profile or throw {@link IllegalArgumentException}, if no + * matching load profile can be found + */ + public static BdewLoadProfile get(String key) { + return Arrays.stream(BdewLoadProfile.values()).filter(loadProfile -> loadProfile.key.equalsIgnoreCase(key)) + .findFirst().orElseThrow(() -> new IllegalArgumentException( + "No predefined bdew load profile with key '" + key + + "' found. Please provide one of the following keys:" + + Arrays.stream(BdewLoadProfile.values()).map(BdewLoadProfile::getKey) + .collect(Collectors.joining(", ")))); + } + + @Override + public String getKey() { + return key; + } + + @Override + public String toString() { + return "BdewLoadProfile{" + "key='" + key + '\'' + '}'; + } } diff --git a/src/main/java/edu/ie3/datamodel/models/input/system/StorageStrategy.java b/src/main/java/edu/ie3/datamodel/models/input/system/StorageStrategy.java index ac0398158..da8f86fee 100644 --- a/src/main/java/edu/ie3/datamodel/models/input/system/StorageStrategy.java +++ b/src/main/java/edu/ie3/datamodel/models/input/system/StorageStrategy.java @@ -2,46 +2,62 @@ * © 2020. TU Dortmund University, * Institute of Energy Systems, Energy Efficiency and Energy Economics, * Research group Distribution grid planning and operation -*/ + */ package edu.ie3.datamodel.models.input.system; import java.util.Arrays; +import java.util.stream.Collectors; -/** Enum listing different pre-defined storage operation strategies */ + +/** + * Enum listing different pre-defined storage operation strategies + */ public enum StorageStrategy { - /** Storage behaves market oriented */ - MARKET_ORIENTED("market"), - /** Storage behaves grid oriented */ - GRID_ORIENTED("grid"), - /** Storage tries to maximize self consumption at the grid node */ - SELF_CONSUMPTION("self"); - - /** Token to recognize strategy from text based input */ - public final String token; - - StorageStrategy(String token) { - this.token = token; - } - - /** - * Get the predefined storage strategy based on the given token - * - * @param token Token to check for - * @return The corresponding storage strategy or throw {@link IllegalArgumentException}, if no - * matching strategy is found - */ - public static StorageStrategy get(String token) { - return Arrays.stream(StorageStrategy.values()) - .filter(storageStrategy -> storageStrategy.token.equalsIgnoreCase(token)) - .findFirst() - .orElseThrow( - () -> - new IllegalArgumentException( - "No predefined storage strategy " + token + " found.")); - } - - @Override - public String toString() { - return "StorageStrategy{" + "token='" + token + '\'' + '}'; - } + /** + * Storage behaves market oriented + */ + MARKET_ORIENTED("market"), + /** + * Storage behaves grid oriented + */ + GRID_ORIENTED("grid"), + /** + * Storage tries to maximize self consumption at the grid node + */ + SELF_CONSUMPTION("self"); + + /** + * Token to recognize strategy from text based input + */ + public final String token; + + StorageStrategy(String token) { + this.token = token; + } + + /** + * Get the predefined storage strategy based on the given token + * + * @param token Token to check for + * @return The corresponding storage strategy or throw {@link IllegalArgumentException}, if no + * matching strategy is found + */ + public static StorageStrategy get(String token) { + return Arrays.stream(StorageStrategy.values()) + .filter(storageStrategy -> storageStrategy.token.equalsIgnoreCase(token)).findFirst() + .orElseThrow(() -> new IllegalArgumentException( + "No predefined storage strategy with token '" + token + + "' found. Please provide one of the followign tokens: " + + Arrays.stream(StorageStrategy.values()).map(StorageStrategy::getToken) + .collect(Collectors.joining(", ")))); + } + + public String getToken() { + return token; + } + + @Override + public String toString() { + return "StorageStrategy{" + "token='" + token + '\'' + '}'; + } } From 3539598fb01a637d0b48c2db4eed504077c92954 Mon Sep 17 00:00:00 2001 From: Johannes Hiry Date: Wed, 25 Mar 2020 13:21:36 +0100 Subject: [PATCH 09/21] new constructors for LoadInput to pass over a string for construction of bdew load profile loads --- .../models/input/system/LoadInput.java | 324 +++++++++++------- 1 file changed, 192 insertions(+), 132 deletions(-) diff --git a/src/main/java/edu/ie3/datamodel/models/input/system/LoadInput.java b/src/main/java/edu/ie3/datamodel/models/input/system/LoadInput.java index 229303b62..fe269183b 100644 --- a/src/main/java/edu/ie3/datamodel/models/input/system/LoadInput.java +++ b/src/main/java/edu/ie3/datamodel/models/input/system/LoadInput.java @@ -2,150 +2,210 @@ * © 2020. TU Dortmund University, * Institute of Energy Systems, Energy Efficiency and Energy Economics, * Research group Distribution grid planning and operation -*/ + */ package edu.ie3.datamodel.models.input.system; +import edu.ie3.datamodel.models.BdewLoadProfile; import edu.ie3.datamodel.models.OperationTime; import edu.ie3.datamodel.models.StandardLoadProfile; import edu.ie3.datamodel.models.StandardUnits; import edu.ie3.datamodel.models.input.NodeInput; import edu.ie3.datamodel.models.input.OperatorInput; + import java.util.Objects; import java.util.UUID; import javax.measure.Quantity; import javax.measure.quantity.Energy; import javax.measure.quantity.Power; -/** Describes a load */ + +/** + * Describes a load + */ public class LoadInput extends SystemParticipantInput { - /** - * Reference to a standard load profile to use for the model. If you intend to assign specific - * values, create an {@link edu.ie3.datamodel.models.timeseries.IndividualTimeSeries} or {@link - * edu.ie3.datamodel.models.timeseries.RepetitiveTimeSeries} and assign it via an external mapping - * (e.g. by providing a global time series for a specific load profile) to this model - */ - private final StandardLoadProfile standardLoadProfile; - /** True, if demand side management is activated for this load */ - private final boolean dsm; - /** Annually consumed energy (typically in kWh) */ - private final Quantity eConsAnnual; - /** Active Power (typically in kVA) */ - private final Quantity sRated; - /** Rated power factor */ - private final double cosphiRated; - /** - * Constructor for an operated load - * - * @param uuid of the input entity - * @param operationTime Time for which the entity is operated - * @param operator of the asset - * @param id of the asset - * @param node the asset is connected to - * @param qCharacteristics Description of a reactive power characteristic - * @param standardLoadProfile Standard load profile to use for this model - * @param dsm True, if demand side management is activated for this load - * @param eConsAnnual Annually consumed energy (typically in kWh) - * @param sRated Rated apparent power (in kVA) - * @param cosphiRated Rated power factor - */ - public LoadInput( - UUID uuid, - OperationTime operationTime, - OperatorInput operator, - String id, - NodeInput node, - String qCharacteristics, - StandardLoadProfile standardLoadProfile, - boolean dsm, - Quantity eConsAnnual, - Quantity sRated, - double cosphiRated) { - super(uuid, operationTime, operator, id, node, qCharacteristics); - this.standardLoadProfile = standardLoadProfile; - this.dsm = dsm; - this.eConsAnnual = eConsAnnual.to(StandardUnits.ENERGY_IN); - this.sRated = sRated.to(StandardUnits.S_RATED); - this.cosphiRated = cosphiRated; - } - - /** - * Constructor for a non-operated load - * - * @param uuid of the input entity - * @param id of the asset - * @param node the asset is connected to - * @param qCharacteristics Description of a reactive power characteristic - * @param standardLoadProfile Standard load profile to use for this model - * @param dsm True, if demand side management is activated for this load - * @param eConsAnnual Annually consumed energy (typically in kWh) - * @param sRated Rated apparent power (in kVA) - */ - public LoadInput( - UUID uuid, - String id, - NodeInput node, - String qCharacteristics, - StandardLoadProfile standardLoadProfile, - boolean dsm, - Quantity eConsAnnual, - Quantity sRated, - double cosphiRated) { - super(uuid, id, node, qCharacteristics); - this.standardLoadProfile = standardLoadProfile; - this.dsm = dsm; - this.eConsAnnual = eConsAnnual.to(StandardUnits.ENERGY_IN); - this.sRated = sRated.to(StandardUnits.S_RATED); - this.cosphiRated = cosphiRated; - } - - public StandardLoadProfile getStandardLoadProfile() { - return standardLoadProfile; - } - - public boolean isDsm() { - return dsm; - } - - public Quantity geteConsAnnual() { - return eConsAnnual; - } - - public Quantity getsRated() { - return sRated; - } - - public double getCosphiRated() { - return cosphiRated; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - if (!super.equals(o)) return false; - LoadInput loadInput = (LoadInput) o; - return dsm == loadInput.dsm - && Double.compare(loadInput.cosphiRated, cosphiRated) == 0 - && eConsAnnual.equals(loadInput.eConsAnnual) - && sRated.equals(loadInput.sRated); - } - - @Override - public int hashCode() { - return Objects.hash(super.hashCode(), dsm, eConsAnnual, sRated, cosphiRated); - } - - @Override - public String toString() { - return "LoadInput{" - + "dsm=" - + dsm - + ", eConsAnnual=" - + eConsAnnual - + ", sRated=" - + sRated - + ", cosphiRated=" - + cosphiRated - + '}'; - } + /** + * Reference to a standard load profile to use for the model. If you intend to assign specific + * values, create an {@link edu.ie3.datamodel.models.timeseries.IndividualTimeSeries} or {@link + * edu.ie3.datamodel.models.timeseries.RepetitiveTimeSeries} and assign it via an external mapping + * (e.g. by providing a global time series for a specific load profile) to this model + */ + private final StandardLoadProfile standardLoadProfile; + /** + * True, if demand side management is activated for this load + */ + private final boolean dsm; + /** + * Annually consumed energy (typically in kWh) + */ + private final Quantity eConsAnnual; + /** + * Active Power (typically in kVA) + */ + private final Quantity sRated; + /** + * Rated power factor + */ + private final double cosphiRated; + + /** + * Constructor for an operated load + * + * @param uuid of the input entity + * @param operationTime Time for which the entity is operated + * @param operator of the asset + * @param id of the asset + * @param node the asset is connected to + * @param qCharacteristics Description of a reactive power characteristic + * @param standardLoadProfile Standard load profile to use for this model + * @param dsm True, if demand side management is activated for this load + * @param eConsAnnual Annually consumed energy (typically in kWh) + * @param sRated Rated apparent power (in kVA) + * @param cosphiRated Rated power factor + */ + public LoadInput(UUID uuid, + OperationTime operationTime, + OperatorInput operator, + String id, + NodeInput node, + String qCharacteristics, + StandardLoadProfile standardLoadProfile, + boolean dsm, + Quantity eConsAnnual, + Quantity sRated, + double cosphiRated) { + super(uuid, operationTime, operator, id, node, qCharacteristics); + this.standardLoadProfile = standardLoadProfile; + this.dsm = dsm; + this.eConsAnnual = eConsAnnual.to(StandardUnits.ENERGY_IN); + this.sRated = sRated.to(StandardUnits.S_RATED); + this.cosphiRated = cosphiRated; + } + + /** + * Constructor for an operated load + * + * @param uuid of the input entity + * @param operationTime Time for which the entity is operated + * @param operator of the asset + * @param id of the asset + * @param node the asset is connected to + * @param qCharacteristics Description of a reactive power characteristic + * @param bdewStandardLoadProfile {@link edu.ie3.datamodel.models.BdewLoadProfile} load profile key + * @param dsm True, if demand side management is activated for this load + * @param eConsAnnual Annually consumed energy (typically in kWh) + * @param sRated Rated apparent power (in kVA) + * @param cosphiRated Rated power factor + */ + public LoadInput(UUID uuid, + OperationTime operationTime, + OperatorInput operator, + String id, + NodeInput node, + String qCharacteristics, + String bdewStandardLoadProfile, + boolean dsm, + Quantity eConsAnnual, + Quantity sRated, + double cosphiRated) { + this(uuid, operationTime, operator, id, node, qCharacteristics, BdewLoadProfile.get(bdewStandardLoadProfile), + dsm, eConsAnnual, sRated, cosphiRated); + } + + /** + * Constructor for a non-operated load + * + * @param uuid of the input entity + * @param id of the asset + * @param node the asset is connected to + * @param qCharacteristics Description of a reactive power characteristic + * @param standardLoadProfile Standard load profile to use for this model + * @param dsm True, if demand side management is activated for this load + * @param eConsAnnual Annually consumed energy (typically in kWh) + * @param sRated Rated apparent power (in kVA) + */ + public LoadInput(UUID uuid, + String id, + NodeInput node, + String qCharacteristics, + StandardLoadProfile standardLoadProfile, + boolean dsm, + Quantity eConsAnnual, + Quantity sRated, + double cosphiRated) { + super(uuid, id, node, qCharacteristics); + this.standardLoadProfile = standardLoadProfile; + this.dsm = dsm; + this.eConsAnnual = eConsAnnual.to(StandardUnits.ENERGY_IN); + this.sRated = sRated.to(StandardUnits.S_RATED); + this.cosphiRated = cosphiRated; + } + + /** + * Constructor for a non-operated load + * + * @param uuid of the input entity + * @param id of the asset + * @param node the asset is connected to + * @param qCharacteristics Description of a reactive power characteristic + * @param bdewStandardLoadProfile {@link edu.ie3.datamodel.models.BdewLoadProfile} load profile key + * @param dsm True, if demand side management is activated for this load + * @param eConsAnnual Annually consumed energy (typically in kWh) + * @param sRated Rated apparent power (in kVA) + */ + public LoadInput(UUID uuid, + String id, + NodeInput node, + String qCharacteristics, + String bdewStandardLoadProfile, + boolean dsm, + Quantity eConsAnnual, + Quantity sRated, + double cosphiRated) { + this(uuid, id, node, qCharacteristics, BdewLoadProfile.get(bdewStandardLoadProfile), dsm, eConsAnnual, sRated, + cosphiRated); + } + + public StandardLoadProfile getStandardLoadProfile() { + return standardLoadProfile; + } + + public boolean isDsm() { + return dsm; + } + + public Quantity geteConsAnnual() { + return eConsAnnual; + } + + public Quantity getsRated() { + return sRated; + } + + public double getCosphiRated() { + return cosphiRated; + } + + @Override + public boolean equals(Object o) { + if(this == o) + return true; + if(o == null || getClass() != o.getClass()) + return false; + if(!super.equals(o)) + return false; + LoadInput loadInput = (LoadInput) o; + return dsm == loadInput.dsm && Double.compare(loadInput.cosphiRated, cosphiRated) == 0 && + eConsAnnual.equals(loadInput.eConsAnnual) && sRated.equals(loadInput.sRated); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), dsm, eConsAnnual, sRated, cosphiRated); + } + + @Override + public String toString() { + return "LoadInput{" + "dsm=" + dsm + ", eConsAnnual=" + eConsAnnual + ", sRated=" + sRated + ", cosphiRated=" + + cosphiRated + '}'; + } } From a827cce684a9d2135f2b679b78deea67c33ba962 Mon Sep 17 00:00:00 2001 From: Johannes Hiry Date: Wed, 25 Mar 2020 13:56:23 +0100 Subject: [PATCH 10/21] finished SystemParticipantTestData + fmt --- .../ie3/datamodel/models/BdewLoadProfile.java | 87 ++-- .../models/input/system/BmInput.java | 4 +- .../models/input/system/ChpInput.java | 6 +- .../models/input/system/LoadInput.java | 401 +++++++++--------- .../models/input/system/StorageStrategy.java | 98 ++--- .../models/input/system/type/BmTypeInput.java | 2 +- .../input/AssetInputProcessorTest.groovy | 54 ++- .../common/SystemParticipantTestData.groovy | 165 +++++++ 8 files changed, 522 insertions(+), 295 deletions(-) create mode 100644 src/test/groovy/edu/ie3/test/common/SystemParticipantTestData.groovy diff --git a/src/main/java/edu/ie3/datamodel/models/BdewLoadProfile.java b/src/main/java/edu/ie3/datamodel/models/BdewLoadProfile.java index 8963568e2..2b17796b9 100644 --- a/src/main/java/edu/ie3/datamodel/models/BdewLoadProfile.java +++ b/src/main/java/edu/ie3/datamodel/models/BdewLoadProfile.java @@ -2,62 +2,65 @@ * © 2020. TU Dortmund University, * Institute of Energy Systems, Energy Efficiency and Energy Economics, * Research group Distribution grid planning and operation - */ +*/ package edu.ie3.datamodel.models; -import edu.ie3.datamodel.models.input.system.StorageStrategy; - import java.util.Arrays; import java.util.stream.Collectors; - /** * German standard electricity load profiles, defined by the bdew (Bundesverband der Energie- und * Wasserwirtschaft; engl.Federal Association of the Energy and Water Industry). For more details * see https://www.bdew.de/energie/standardlastprofile-strom/ */ public enum BdewLoadProfile implements StandardLoadProfile { - H0("h0"), // Households - L0("l0"), // Agricultural enterprises without further differentiation - L1("l1"), // Agricultural enterprises with dairy sector - L2("l2"), // Agricultural enterprises without dairy sector - G0("g0"), // Businesses without further differentiation - G1("g1"), // Workday businesses from 8 a.m. to 6 p.m. - G2("g2"), // Businesses with high consumption in evening hours - G3("g3"), // Businesses with enduring consumption - G4("g4"), // Vendor or barber shop - G5("g5"), // Bakery - G6("g6"); // Business with main consumption on weekends + H0("h0"), // Households + L0("l0"), // Agricultural enterprises without further differentiation + L1("l1"), // Agricultural enterprises with dairy sector + L2("l2"), // Agricultural enterprises without dairy sector + G0("g0"), // Businesses without further differentiation + G1("g1"), // Workday businesses from 8 a.m. to 6 p.m. + G2("g2"), // Businesses with high consumption in evening hours + G3("g3"), // Businesses with enduring consumption + G4("g4"), // Vendor or barber shop + G5("g5"), // Bakery + G6("g6"); // Business with main consumption on weekends - private final String key; + private final String key; - BdewLoadProfile(String key) { - this.key = key.toLowerCase(); - } + BdewLoadProfile(String key) { + this.key = key.toLowerCase(); + } - /** - * Get the predefined bdew load profile based on the given key - * - * @param key key to check for - * @return The corresponding bdew load profile or throw {@link IllegalArgumentException}, if no - * matching load profile can be found - */ - public static BdewLoadProfile get(String key) { - return Arrays.stream(BdewLoadProfile.values()).filter(loadProfile -> loadProfile.key.equalsIgnoreCase(key)) - .findFirst().orElseThrow(() -> new IllegalArgumentException( - "No predefined bdew load profile with key '" + key + - "' found. Please provide one of the following keys:" + - Arrays.stream(BdewLoadProfile.values()).map(BdewLoadProfile::getKey) - .collect(Collectors.joining(", ")))); - } + /** + * Get the predefined bdew load profile based on the given key + * + * @param key key to check for + * @return The corresponding bdew load profile or throw {@link IllegalArgumentException}, if no + * matching load profile can be found + */ + public static BdewLoadProfile get(String key) { + return Arrays.stream(BdewLoadProfile.values()) + .filter(loadProfile -> loadProfile.key.equalsIgnoreCase(key)) + .findFirst() + .orElseThrow( + () -> + new IllegalArgumentException( + "No predefined bdew load profile with key '" + + key + + "' found. Please provide one of the following keys:" + + Arrays.stream(BdewLoadProfile.values()) + .map(BdewLoadProfile::getKey) + .collect(Collectors.joining(", ")))); + } - @Override - public String getKey() { - return key; - } + @Override + public String getKey() { + return key; + } - @Override - public String toString() { - return "BdewLoadProfile{" + "key='" + key + '\'' + '}'; - } + @Override + public String toString() { + return "BdewLoadProfile{" + "key='" + key + '\'' + '}'; + } } diff --git a/src/main/java/edu/ie3/datamodel/models/input/system/BmInput.java b/src/main/java/edu/ie3/datamodel/models/input/system/BmInput.java index e365916d1..0a8163946 100644 --- a/src/main/java/edu/ie3/datamodel/models/input/system/BmInput.java +++ b/src/main/java/edu/ie3/datamodel/models/input/system/BmInput.java @@ -41,7 +41,7 @@ public class BmInput extends SystemParticipantInput { * @param marketReaction Is this asset market oriented? * @param costControlled Does this plant increase the output power if the revenues exceed the * energy generation costs? - * @param feedInTariff Granted feed in tariff (typically in €/kWh) + * @param feedInTariff Granted feed in tariff (typically in €/MWh) */ public BmInput( UUID uuid, @@ -72,7 +72,7 @@ public BmInput( * @param marketReaction Is this asset market oriented? * @param costControlled Does this plant increase the output power if the revenues exceed the * energy generation costs? - * @param feedInTariff Granted feed in tariff (typically in €/kWh) + * @param feedInTariff Granted feed in tariff (typically in €/MWh) */ public BmInput( UUID uuid, diff --git a/src/main/java/edu/ie3/datamodel/models/input/system/ChpInput.java b/src/main/java/edu/ie3/datamodel/models/input/system/ChpInput.java index 1fea395ed..e54dab409 100644 --- a/src/main/java/edu/ie3/datamodel/models/input/system/ChpInput.java +++ b/src/main/java/edu/ie3/datamodel/models/input/system/ChpInput.java @@ -33,7 +33,8 @@ public class ChpInput extends SystemParticipantInput { * @param operator of the asset * @param id of the asset * @param node the asset is connected to - * @param thermalBus The thermal bus, this model is connected to (normally equal to the thermal bus of the provided thermal storage!) + * @param thermalBus The thermal bus, this model is connected to (normally equal to the thermal + * bus of the provided thermal storage!) * @param qCharacteristics Description of a reactive power characteristic * @param type of CHP * @param thermalStorage Thermal storage model @@ -63,7 +64,8 @@ public ChpInput( * @param uuid of the input entity * @param id of the asset * @param node the asset is connected to - * @param thermalBus The thermal bus, this model is connected to (normally equal to the thermal bus of the provided thermal storage!) + * @param thermalBus The thermal bus, this model is connected to (normally equal to the thermal + * bus of the provided thermal storage!) * @param qCharacteristics Description of a reactive power characteristic * @param type of CHP * @param thermalStorage Thermal storage model diff --git a/src/main/java/edu/ie3/datamodel/models/input/system/LoadInput.java b/src/main/java/edu/ie3/datamodel/models/input/system/LoadInput.java index fe269183b..ef5dd6852 100644 --- a/src/main/java/edu/ie3/datamodel/models/input/system/LoadInput.java +++ b/src/main/java/edu/ie3/datamodel/models/input/system/LoadInput.java @@ -2,7 +2,7 @@ * © 2020. TU Dortmund University, * Institute of Energy Systems, Energy Efficiency and Energy Economics, * Research group Distribution grid planning and operation - */ +*/ package edu.ie3.datamodel.models.input.system; import edu.ie3.datamodel.models.BdewLoadProfile; @@ -11,201 +11,220 @@ import edu.ie3.datamodel.models.StandardUnits; import edu.ie3.datamodel.models.input.NodeInput; import edu.ie3.datamodel.models.input.OperatorInput; - import java.util.Objects; import java.util.UUID; import javax.measure.Quantity; import javax.measure.quantity.Energy; import javax.measure.quantity.Power; - -/** - * Describes a load - */ +/** Describes a load */ public class LoadInput extends SystemParticipantInput { - /** - * Reference to a standard load profile to use for the model. If you intend to assign specific - * values, create an {@link edu.ie3.datamodel.models.timeseries.IndividualTimeSeries} or {@link - * edu.ie3.datamodel.models.timeseries.RepetitiveTimeSeries} and assign it via an external mapping - * (e.g. by providing a global time series for a specific load profile) to this model - */ - private final StandardLoadProfile standardLoadProfile; - /** - * True, if demand side management is activated for this load - */ - private final boolean dsm; - /** - * Annually consumed energy (typically in kWh) - */ - private final Quantity eConsAnnual; - /** - * Active Power (typically in kVA) - */ - private final Quantity sRated; - /** - * Rated power factor - */ - private final double cosphiRated; - - /** - * Constructor for an operated load - * - * @param uuid of the input entity - * @param operationTime Time for which the entity is operated - * @param operator of the asset - * @param id of the asset - * @param node the asset is connected to - * @param qCharacteristics Description of a reactive power characteristic - * @param standardLoadProfile Standard load profile to use for this model - * @param dsm True, if demand side management is activated for this load - * @param eConsAnnual Annually consumed energy (typically in kWh) - * @param sRated Rated apparent power (in kVA) - * @param cosphiRated Rated power factor - */ - public LoadInput(UUID uuid, - OperationTime operationTime, - OperatorInput operator, - String id, - NodeInput node, - String qCharacteristics, - StandardLoadProfile standardLoadProfile, - boolean dsm, - Quantity eConsAnnual, - Quantity sRated, - double cosphiRated) { - super(uuid, operationTime, operator, id, node, qCharacteristics); - this.standardLoadProfile = standardLoadProfile; - this.dsm = dsm; - this.eConsAnnual = eConsAnnual.to(StandardUnits.ENERGY_IN); - this.sRated = sRated.to(StandardUnits.S_RATED); - this.cosphiRated = cosphiRated; - } - - /** - * Constructor for an operated load - * - * @param uuid of the input entity - * @param operationTime Time for which the entity is operated - * @param operator of the asset - * @param id of the asset - * @param node the asset is connected to - * @param qCharacteristics Description of a reactive power characteristic - * @param bdewStandardLoadProfile {@link edu.ie3.datamodel.models.BdewLoadProfile} load profile key - * @param dsm True, if demand side management is activated for this load - * @param eConsAnnual Annually consumed energy (typically in kWh) - * @param sRated Rated apparent power (in kVA) - * @param cosphiRated Rated power factor - */ - public LoadInput(UUID uuid, - OperationTime operationTime, - OperatorInput operator, - String id, - NodeInput node, - String qCharacteristics, - String bdewStandardLoadProfile, - boolean dsm, - Quantity eConsAnnual, - Quantity sRated, - double cosphiRated) { - this(uuid, operationTime, operator, id, node, qCharacteristics, BdewLoadProfile.get(bdewStandardLoadProfile), - dsm, eConsAnnual, sRated, cosphiRated); - } - - /** - * Constructor for a non-operated load - * - * @param uuid of the input entity - * @param id of the asset - * @param node the asset is connected to - * @param qCharacteristics Description of a reactive power characteristic - * @param standardLoadProfile Standard load profile to use for this model - * @param dsm True, if demand side management is activated for this load - * @param eConsAnnual Annually consumed energy (typically in kWh) - * @param sRated Rated apparent power (in kVA) - */ - public LoadInput(UUID uuid, - String id, - NodeInput node, - String qCharacteristics, - StandardLoadProfile standardLoadProfile, - boolean dsm, - Quantity eConsAnnual, - Quantity sRated, - double cosphiRated) { - super(uuid, id, node, qCharacteristics); - this.standardLoadProfile = standardLoadProfile; - this.dsm = dsm; - this.eConsAnnual = eConsAnnual.to(StandardUnits.ENERGY_IN); - this.sRated = sRated.to(StandardUnits.S_RATED); - this.cosphiRated = cosphiRated; - } - - /** - * Constructor for a non-operated load - * - * @param uuid of the input entity - * @param id of the asset - * @param node the asset is connected to - * @param qCharacteristics Description of a reactive power characteristic - * @param bdewStandardLoadProfile {@link edu.ie3.datamodel.models.BdewLoadProfile} load profile key - * @param dsm True, if demand side management is activated for this load - * @param eConsAnnual Annually consumed energy (typically in kWh) - * @param sRated Rated apparent power (in kVA) - */ - public LoadInput(UUID uuid, - String id, - NodeInput node, - String qCharacteristics, - String bdewStandardLoadProfile, - boolean dsm, - Quantity eConsAnnual, - Quantity sRated, - double cosphiRated) { - this(uuid, id, node, qCharacteristics, BdewLoadProfile.get(bdewStandardLoadProfile), dsm, eConsAnnual, sRated, - cosphiRated); - } - - public StandardLoadProfile getStandardLoadProfile() { - return standardLoadProfile; - } - - public boolean isDsm() { - return dsm; - } - - public Quantity geteConsAnnual() { - return eConsAnnual; - } - - public Quantity getsRated() { - return sRated; - } - - public double getCosphiRated() { - return cosphiRated; - } - - @Override - public boolean equals(Object o) { - if(this == o) - return true; - if(o == null || getClass() != o.getClass()) - return false; - if(!super.equals(o)) - return false; - LoadInput loadInput = (LoadInput) o; - return dsm == loadInput.dsm && Double.compare(loadInput.cosphiRated, cosphiRated) == 0 && - eConsAnnual.equals(loadInput.eConsAnnual) && sRated.equals(loadInput.sRated); - } - - @Override - public int hashCode() { - return Objects.hash(super.hashCode(), dsm, eConsAnnual, sRated, cosphiRated); - } - - @Override - public String toString() { - return "LoadInput{" + "dsm=" + dsm + ", eConsAnnual=" + eConsAnnual + ", sRated=" + sRated + ", cosphiRated=" + - cosphiRated + '}'; - } + /** + * Reference to a standard load profile to use for the model. If you intend to assign specific + * values, create an {@link edu.ie3.datamodel.models.timeseries.IndividualTimeSeries} or {@link + * edu.ie3.datamodel.models.timeseries.RepetitiveTimeSeries} and assign it via an external mapping + * (e.g. by providing a global time series for a specific load profile) to this model + */ + private final StandardLoadProfile standardLoadProfile; + /** True, if demand side management is activated for this load */ + private final boolean dsm; + /** Annually consumed energy (typically in kWh) */ + private final Quantity eConsAnnual; + /** Active Power (typically in kVA) */ + private final Quantity sRated; + /** Rated power factor */ + private final double cosphiRated; + + /** + * Constructor for an operated load + * + * @param uuid of the input entity + * @param operationTime Time for which the entity is operated + * @param operator of the asset + * @param id of the asset + * @param node the asset is connected to + * @param qCharacteristics Description of a reactive power characteristic + * @param standardLoadProfile Standard load profile to use for this model + * @param dsm True, if demand side management is activated for this load + * @param eConsAnnual Annually consumed energy (typically in kWh) + * @param sRated Rated apparent power (in kVA) + * @param cosphiRated Rated power factor + */ + public LoadInput( + UUID uuid, + OperationTime operationTime, + OperatorInput operator, + String id, + NodeInput node, + String qCharacteristics, + StandardLoadProfile standardLoadProfile, + boolean dsm, + Quantity eConsAnnual, + Quantity sRated, + double cosphiRated) { + super(uuid, operationTime, operator, id, node, qCharacteristics); + this.standardLoadProfile = standardLoadProfile; + this.dsm = dsm; + this.eConsAnnual = eConsAnnual.to(StandardUnits.ENERGY_IN); + this.sRated = sRated.to(StandardUnits.S_RATED); + this.cosphiRated = cosphiRated; + } + + /** + * Constructor for an operated load + * + * @param uuid of the input entity + * @param operationTime Time for which the entity is operated + * @param operator of the asset + * @param id of the asset + * @param node the asset is connected to + * @param qCharacteristics Description of a reactive power characteristic + * @param bdewStandardLoadProfile {@link edu.ie3.datamodel.models.BdewLoadProfile} load profile + * key + * @param dsm True, if demand side management is activated for this load + * @param eConsAnnual Annually consumed energy (typically in kWh) + * @param sRated Rated apparent power (in kVA) + * @param cosphiRated Rated power factor + */ + public LoadInput( + UUID uuid, + OperationTime operationTime, + OperatorInput operator, + String id, + NodeInput node, + String qCharacteristics, + String bdewStandardLoadProfile, + boolean dsm, + Quantity eConsAnnual, + Quantity sRated, + double cosphiRated) { + this( + uuid, + operationTime, + operator, + id, + node, + qCharacteristics, + BdewLoadProfile.get(bdewStandardLoadProfile), + dsm, + eConsAnnual, + sRated, + cosphiRated); + } + + /** + * Constructor for a non-operated load + * + * @param uuid of the input entity + * @param id of the asset + * @param node the asset is connected to + * @param qCharacteristics Description of a reactive power characteristic + * @param standardLoadProfile Standard load profile to use for this model + * @param dsm True, if demand side management is activated for this load + * @param eConsAnnual Annually consumed energy (typically in kWh) + * @param sRated Rated apparent power (in kVA) + */ + public LoadInput( + UUID uuid, + String id, + NodeInput node, + String qCharacteristics, + StandardLoadProfile standardLoadProfile, + boolean dsm, + Quantity eConsAnnual, + Quantity sRated, + double cosphiRated) { + super(uuid, id, node, qCharacteristics); + this.standardLoadProfile = standardLoadProfile; + this.dsm = dsm; + this.eConsAnnual = eConsAnnual.to(StandardUnits.ENERGY_IN); + this.sRated = sRated.to(StandardUnits.S_RATED); + this.cosphiRated = cosphiRated; + } + + /** + * Constructor for a non-operated load + * + * @param uuid of the input entity + * @param id of the asset + * @param node the asset is connected to + * @param qCharacteristics Description of a reactive power characteristic + * @param bdewStandardLoadProfile {@link edu.ie3.datamodel.models.BdewLoadProfile} load profile + * key + * @param dsm True, if demand side management is activated for this load + * @param eConsAnnual Annually consumed energy (typically in kWh) + * @param sRated Rated apparent power (in kVA) + */ + public LoadInput( + UUID uuid, + String id, + NodeInput node, + String qCharacteristics, + String bdewStandardLoadProfile, + boolean dsm, + Quantity eConsAnnual, + Quantity sRated, + double cosphiRated) { + this( + uuid, + id, + node, + qCharacteristics, + BdewLoadProfile.get(bdewStandardLoadProfile), + dsm, + eConsAnnual, + sRated, + cosphiRated); + } + + public StandardLoadProfile getStandardLoadProfile() { + return standardLoadProfile; + } + + public boolean isDsm() { + return dsm; + } + + public Quantity geteConsAnnual() { + return eConsAnnual; + } + + public Quantity getsRated() { + return sRated; + } + + public double getCosphiRated() { + return cosphiRated; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + LoadInput loadInput = (LoadInput) o; + return dsm == loadInput.dsm + && Double.compare(loadInput.cosphiRated, cosphiRated) == 0 + && eConsAnnual.equals(loadInput.eConsAnnual) + && sRated.equals(loadInput.sRated); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), dsm, eConsAnnual, sRated, cosphiRated); + } + + @Override + public String toString() { + return "LoadInput{" + + "dsm=" + + dsm + + ", eConsAnnual=" + + eConsAnnual + + ", sRated=" + + sRated + + ", cosphiRated=" + + cosphiRated + + '}'; + } } diff --git a/src/main/java/edu/ie3/datamodel/models/input/system/StorageStrategy.java b/src/main/java/edu/ie3/datamodel/models/input/system/StorageStrategy.java index da8f86fee..252424add 100644 --- a/src/main/java/edu/ie3/datamodel/models/input/system/StorageStrategy.java +++ b/src/main/java/edu/ie3/datamodel/models/input/system/StorageStrategy.java @@ -2,62 +2,56 @@ * © 2020. TU Dortmund University, * Institute of Energy Systems, Energy Efficiency and Energy Economics, * Research group Distribution grid planning and operation - */ +*/ package edu.ie3.datamodel.models.input.system; import java.util.Arrays; import java.util.stream.Collectors; - -/** - * Enum listing different pre-defined storage operation strategies - */ +/** Enum listing different pre-defined storage operation strategies */ public enum StorageStrategy { - /** - * Storage behaves market oriented - */ - MARKET_ORIENTED("market"), - /** - * Storage behaves grid oriented - */ - GRID_ORIENTED("grid"), - /** - * Storage tries to maximize self consumption at the grid node - */ - SELF_CONSUMPTION("self"); - - /** - * Token to recognize strategy from text based input - */ - public final String token; - - StorageStrategy(String token) { - this.token = token; - } - - /** - * Get the predefined storage strategy based on the given token - * - * @param token Token to check for - * @return The corresponding storage strategy or throw {@link IllegalArgumentException}, if no - * matching strategy is found - */ - public static StorageStrategy get(String token) { - return Arrays.stream(StorageStrategy.values()) - .filter(storageStrategy -> storageStrategy.token.equalsIgnoreCase(token)).findFirst() - .orElseThrow(() -> new IllegalArgumentException( - "No predefined storage strategy with token '" + token + - "' found. Please provide one of the followign tokens: " + - Arrays.stream(StorageStrategy.values()).map(StorageStrategy::getToken) - .collect(Collectors.joining(", ")))); - } - - public String getToken() { - return token; - } - - @Override - public String toString() { - return "StorageStrategy{" + "token='" + token + '\'' + '}'; - } + /** Storage behaves market oriented */ + MARKET_ORIENTED("market"), + /** Storage behaves grid oriented */ + GRID_ORIENTED("grid"), + /** Storage tries to maximize self consumption at the grid node */ + SELF_CONSUMPTION("self"); + + /** Token to recognize strategy from text based input */ + public final String token; + + StorageStrategy(String token) { + this.token = token; + } + + /** + * Get the predefined storage strategy based on the given token + * + * @param token Token to check for + * @return The corresponding storage strategy or throw {@link IllegalArgumentException}, if no + * matching strategy is found + */ + public static StorageStrategy get(String token) { + return Arrays.stream(StorageStrategy.values()) + .filter(storageStrategy -> storageStrategy.token.equalsIgnoreCase(token)) + .findFirst() + .orElseThrow( + () -> + new IllegalArgumentException( + "No predefined storage strategy with token '" + + token + + "' found. Please provide one of the followign tokens: " + + Arrays.stream(StorageStrategy.values()) + .map(StorageStrategy::getToken) + .collect(Collectors.joining(", ")))); + } + + public String getToken() { + return token; + } + + @Override + public String toString() { + return "StorageStrategy{" + "token='" + token + '\'' + '}'; + } } diff --git a/src/main/java/edu/ie3/datamodel/models/input/system/type/BmTypeInput.java b/src/main/java/edu/ie3/datamodel/models/input/system/type/BmTypeInput.java index f11d87067..2fd66bf58 100644 --- a/src/main/java/edu/ie3/datamodel/models/input/system/type/BmTypeInput.java +++ b/src/main/java/edu/ie3/datamodel/models/input/system/type/BmTypeInput.java @@ -26,7 +26,7 @@ public class BmTypeInput extends SystemParticipantTypeInput { /** * @param uuid of the input entity * @param id of this type of BM - * @param capex Captial expense for this type of BM (typically in €) + * @param capex Capital expense for this type of BM (typically in €) * @param opex Operating expense for this type of BM (typically in €) * @param cosphiRated Power factor for this type of BM * @param loadGradient Permissible load gradient diff --git a/src/test/groovy/edu/ie3/datamodel/io/processor/input/AssetInputProcessorTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/processor/input/AssetInputProcessorTest.groovy index 5beeaf524..a50846895 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/processor/input/AssetInputProcessorTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/processor/input/AssetInputProcessorTest.groovy @@ -5,7 +5,17 @@ import edu.ie3.datamodel.models.input.connector.LineInput import edu.ie3.datamodel.models.input.connector.SwitchInput import edu.ie3.datamodel.models.input.connector.Transformer2WInput import edu.ie3.datamodel.models.input.connector.Transformer3WInput +import edu.ie3.datamodel.models.input.system.BmInput +import edu.ie3.datamodel.models.input.system.ChpInput +import edu.ie3.datamodel.models.input.system.EvInput +import edu.ie3.datamodel.models.input.system.FixedFeedInInput +import edu.ie3.datamodel.models.input.system.HpInput +import edu.ie3.datamodel.models.input.system.LoadInput +import edu.ie3.datamodel.models.input.system.PvInput +import edu.ie3.datamodel.models.input.system.StorageInput +import edu.ie3.datamodel.models.input.system.WecInput import edu.ie3.test.common.GridTestData +import edu.ie3.test.common.SystemParticipantTestData import edu.ie3.util.TimeTools import spock.lang.Specification @@ -18,11 +28,6 @@ import java.time.ZoneId */ class AssetInputProcessorTest extends Specification { - def "A ResultEntityProcessor should de-serialize a provided SystemParticipantInput correctly"() { - - - } - def "A ResultEntityProcessor should de-serialize a provided NodeInput correctly"() { given: TimeTools.initialize(ZoneId.of("UTC"), Locale.GERMANY, "yyyy-MM-dd HH:mm:ss") @@ -136,5 +141,44 @@ class AssetInputProcessorTest extends Specification { } + def "A ResultEntityProcessor should de-serialize a provided SystemParticipantInput correctly"() { + + given: + TimeTools.initialize(ZoneId.of("UTC"), Locale.GERMANY, "yyyy-MM-dd HH:mm:ss") + def sysPartResProcessor = new AssetInputProcessor(modelClass) + def validInput = modelInstance + + when: "the entity is passed to the processor" + def processingResult = sysPartResProcessor.handleEntity(validInput) + + + then: "make sure that the result is as expected " + processingResult.present + + println "[" + processingResult.get().each { k, v -> println "\"${k}\":\"${v.replaceAll("\"", "\"")}\"," } + println "]" + + processingResult.get().forEach { k, v -> + if (k != "nodeInternal") // the internal 3w node is always randomly generated, hence we can skip to test on this + assert (v == expectedResult.get(k)) + } + + + where: + modelClass | modelInstance || expectedResult + FixedFeedInInput | SystemParticipantTestData.fixedFeedInInput || [:] + PvInput | SystemParticipantTestData.pvInput || [:] + WecInput | SystemParticipantTestData.wecInput || [:] +// ChpInput | || +// BmInput | || +// EvInput | || +// LoadInput | || +// StorageInput | || +// HpInput | || + + + } + } diff --git a/src/test/groovy/edu/ie3/test/common/SystemParticipantTestData.groovy b/src/test/groovy/edu/ie3/test/common/SystemParticipantTestData.groovy new file mode 100644 index 000000000..7cd3e7584 --- /dev/null +++ b/src/test/groovy/edu/ie3/test/common/SystemParticipantTestData.groovy @@ -0,0 +1,165 @@ +package edu.ie3.test.common + +import edu.ie3.datamodel.models.BdewLoadProfile +import edu.ie3.datamodel.models.OperationTime +import edu.ie3.datamodel.models.StandardLoadProfile +import edu.ie3.datamodel.models.StandardUnits +import edu.ie3.datamodel.models.input.NodeInput +import edu.ie3.datamodel.models.input.OperatorInput +import edu.ie3.datamodel.models.input.system.BmInput +import edu.ie3.datamodel.models.input.system.ChpInput +import edu.ie3.datamodel.models.input.system.EvInput +import edu.ie3.datamodel.models.input.system.FixedFeedInInput +import edu.ie3.datamodel.models.input.system.HpInput +import edu.ie3.datamodel.models.input.system.LoadInput +import edu.ie3.datamodel.models.input.system.PvInput +import edu.ie3.datamodel.models.input.system.StorageInput +import edu.ie3.datamodel.models.input.system.WecInput +import edu.ie3.datamodel.models.input.system.type.BmTypeInput +import edu.ie3.datamodel.models.input.system.type.ChpTypeInput +import edu.ie3.datamodel.models.input.system.type.EvTypeInput +import edu.ie3.datamodel.models.input.system.type.HpTypeInput +import edu.ie3.datamodel.models.input.system.type.StorageTypeInput +import edu.ie3.datamodel.models.input.system.type.WecTypeInput +import edu.ie3.datamodel.models.input.thermal.CylindricalStorageInput +import edu.ie3.datamodel.models.input.thermal.ThermalBusInput +import edu.ie3.datamodel.models.input.thermal.ThermalStorageInput +import edu.ie3.util.TimeTools +import edu.ie3.util.quantities.PowerSystemUnits +import edu.ie3.util.quantities.interfaces.Currency +import edu.ie3.util.quantities.interfaces.DimensionlessRate +import edu.ie3.util.quantities.interfaces.EnergyPrice +import edu.ie3.util.quantities.interfaces.SpecificEnergy +import edu.ie3.util.quantities.interfaces.SpecificHeatCapacity +import tec.uom.se.quantity.Quantities +import tec.uom.se.unit.Units + +import javax.measure.Quantity +import javax.measure.quantity.Angle +import javax.measure.quantity.Area +import javax.measure.quantity.Dimensionless +import javax.measure.quantity.Energy +import javax.measure.quantity.Length +import javax.measure.quantity.Power +import javax.measure.quantity.Temperature +import javax.measure.quantity.Time +import javax.measure.quantity.Volume + +import static edu.ie3.util.quantities.PowerSystemUnits.* + + +class SystemParticipantTestData { + + // general participant data + private static final UUID participantUuid = UUID.fromString("717af017-cc69-406f-b452-e022d7fb516a") + private static final OperationTime operationTime = OperationTime.builder() + .withStart(TimeTools.toZonedDateTime("2020-03-24 15:11:31")) + .withEnd(TimeTools.toZonedDateTime("2020-03-25 15:11:31")).build() + private static final OperatorInput operator = new OperatorInput( + UUID.fromString("8f9682df-0744-4b58-a122-f0dc730f6510"), "SystemParticipantOperator") + private static final NodeInput participantNode = GridTestData.nodeA + + // general type data + private static final String qCharacteristics = "" // todo JH valid characteristic + private static final Quantity sRated = Quantities.getQuantity(25, KILOVOLTAMPERE) + private static final double cosPhiRated = 0.95 + private static final UUID typeUuid = UUID.fromString("5ebd8f7e-dedb-4017-bb86-6373c4b68eb8") + private static final Quantity capex = Quantities.getQuantity(100, EURO) + private static final Quantity opex = Quantities.getQuantity(50, EURO_PER_MEGAWATTHOUR) + private static final Quantity etaConv = Quantities.getQuantity(98, PERCENT) + + + // FixedFeedInput + public static final FixedFeedInInput fixedFeedInInput = new FixedFeedInInput(participantUuid, + operationTime, operator, "test_fixedFeedInInput", participantNode, qCharacteristics, + sRated, cosPhiRated) + + // PV + private static final double albedo = 0.20000000298023224 + private static final Quantity azimuth = Quantities.getQuantity(-8.926613807678223, DEGREE_GEOM) + private static final Quantity height = Quantities.getQuantity(41.01871871948242, DEGREE_GEOM) + private static double kT = 1 + private static double kG = 0.8999999761581421 + public static final PvInput pvInput = new PvInput(participantUuid, operationTime, operator, "test_pvInput", + participantNode, qCharacteristics, albedo, azimuth, + etaConv, height, kG, kT, false, sRated, cosPhiRated) + + + // WEC + private static final Quantity rotorArea = Quantities.getQuantity(20, SQUARE_METRE) + private static final Quantity hubHeight = Quantities.getQuantity(200, METRE) + public static final WecTypeInput wecType = new WecTypeInput(typeUuid, "test_wecType", capex, opex, + cosPhiRated, etaConv, sRated, rotorArea, hubHeight) + + public static final WecInput wecInput = new WecInput(participantUuid, + operationTime, operator, "test_wecInput", participantNode, qCharacteristics, + wecType, false) + + // CHP + private static final Quantity etaEl = Quantities.getQuantity(19, PERCENT) + private static final Quantity etaThermal = Quantities.getQuantity(76, PERCENT) + private static final Quantity pOwn = Quantities.getQuantity(0, KILOWATT) + private static final Quantity pThermal = Quantities.getQuantity(9, KILOWATT) + public static final ChpTypeInput chpTypeInput = new ChpTypeInput(typeUuid, "test_chpType", capex, opex, + etaEl, etaThermal, sRated, cosPhiRated, pThermal, pOwn) + + private static final ThermalBusInput thermalBus = new ThermalBusInput(participantUuid, operationTime, operator, + "test_thermalBusInput") + private static final Quantity storageVolumeLvl = Quantities.getQuantity(1.039154027, CUBIC_METRE) + private static final Quantity storageVolumeLvlMin = Quantities.getQuantity(0.3, CUBIC_METRE) + private static final Quantity inletTemp = Quantities.getQuantity(110, CELSIUS) + private static final Quantity returnTemp = Quantities.getQuantity(80, CELSIUS) + private static final Quantity c = Quantities.getQuantity( + 1, KILOWATTHOUR_PER_KELVIN_TIMES_CUBICMETRE) + private static final ThermalStorageInput thermalStorage = new CylindricalStorageInput(participantUuid, + "test_cylindricThermalStorage", thermalBus, storageVolumeLvl, storageVolumeLvlMin, + inletTemp, returnTemp, c) + + public static final ChpInput chpInput = new ChpInput(participantUuid, operationTime, operator, "test_chpInput", + participantNode, thermalBus, qCharacteristics, chpTypeInput, thermalStorage, false) + + + // BM + private static final Quantity loadGradient = Quantities.getQuantity(25, PERCENT_PER_HOUR) + public static final BmTypeInput bmTypeInput = new BmTypeInput(typeUuid, "test_bmTypeInput", capex, opex, + loadGradient, sRated, cosPhiRated, etaConv) + + private static final Quantity feedInTarif = Quantities.getQuantity(10, EURO_PER_MEGAWATTHOUR) + public static final BmInput bmInput = new BmInput(participantUuid, operationTime, operator, "test_bmInput", + participantNode, qCharacteristics, bmTypeInput, false, false, feedInTarif) + + // EV + private static final Quantity eStorage = Quantities.getQuantity(100, KILOWATTHOUR) + private static final Quantity eCons = Quantities.getQuantity(5, KILOWATTHOUR_PER_KILOMETRE) + public static final EvTypeInput evTypeInput = new EvTypeInput(typeUuid, "test_evTypeInput", capex, opex, + eStorage, eCons, sRated, cosPhiRated) + public static final EvInput evInput = new EvInput(participantUuid, operationTime, operator, "test_evInput", + participantNode, qCharacteristics, evTypeInput) + + // Load + private static final Quantity eConsAnnual = Quantities.getQuantity(4000, KILOWATTHOUR) + private static final StandardLoadProfile standardLoadProfile = BdewLoadProfile.H0 + public static final LoadInput loadInput = new LoadInput(participantUuid, operationTime, operator, "test_loadInput", + participantNode, qCharacteristics, standardLoadProfile, false, eConsAnnual, sRated, cosPhiRated) + + // Storage + private static final Quantity pMin = Quantities.getQuantity(10, KILOWATT) + private static final Quantity pMax = Quantities.getQuantity(15, KILOWATT) + private static final Quantity eta = Quantities.getQuantity(95, PERCENT) + private static final Quantity dod = Quantities.getQuantity(10, PERCENT) + private static final Quantity