diff --git a/CHANGELOG.md b/CHANGELOG.md index 5416aa3b7..3b60eaa43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Added weathersource documentation [#1390](https://github.com/ie3-institute/PowerSystemDataModel/issues/1390) - Added standard asset parameter for `3wTransformer` in `ReadTheDocs` [#1417](https://github.com/ie3-institute/PowerSystemDataModel/issues/1417) +- Create data model for air condition [#1396](https://github.com/ie3-institute/PowerSystemDataModel/issues/1396) ### Fixed - Fixed small issues in tests [#1400](https://github.com/ie3-institute/PowerSystemDataModel/issues/1400) diff --git a/docs/readthedocs/io/ValidationUtils.md b/docs/readthedocs/io/ValidationUtils.md index 4c2bf9194..c31bc6362 100644 --- a/docs/readthedocs/io/ValidationUtils.md +++ b/docs/readthedocs/io/ValidationUtils.md @@ -57,6 +57,7 @@ The ValidationUtils include validation checks for... - MeasurementUnitInput - SystemParticipantValidationUtils - SystemParticipantInput + - AcInput - BmInput - ChpInput - EvInput @@ -67,7 +68,8 @@ The ValidationUtils include validation checks for... - StorageInput - WecInput - EvcsInput (also checks ChargingPointType) - - SystemParticipantTypeInput + - SystemParticipantTypeInput + - AcTypeInput - BmTypeInput - ChpTypeInput - EvTypeInput diff --git a/docs/readthedocs/models/input/participant/ac.md b/docs/readthedocs/models/input/participant/ac.md new file mode 100644 index 000000000..a2814569e --- /dev/null +++ b/docs/readthedocs/models/input/participant/ac.md @@ -0,0 +1,108 @@ +(aircon-model)= + +# Air Condition + +Model of a heat pump. + +## Attributes, Units and Remarks + +### Type Model + +```{list-table} + :widths: auto + :class: wrapping + :header-rows: 1 + + + * - Attribute + - Unit + - Remarks + + * - uuid + - + - + + * - id + - + - Human readable identifier + + * - capex + - € + - Capital expenditure to purchase one entity of this type + + * - opex + - € / MWh + - Operational expenditure to operate one entity of + this type + + * - sRated + - kVA + - Rated apparent power + + * - cosPhiRated + - + - Rated power factor + + * - pThermal + - kW + - Rated thermal power (at rated electrical power) + +``` + +### Entity Model + +```{list-table} + :widths: auto + :class: wrapping + :header-rows: 1 + + + * - Attribute + - Unit + - Remarks + + * - uuid + - + - + + * - id + - + - Human readable identifier + + * - operator + - + - + + * - operationTime + - + - Timely restriction of operation + + * - node + - + - + + * - thermalBus + - + - Connection point to the thermal system + + * - qCharacteristics + - + - [Reactive power characteristic](#participant-general-q-characteristic) to follow + + * - type + - + - + + * - controllingEm + - + - UUID reference to an [Energy Management Unit](#em_model) that is controlling + this system participant. Field can be empty or missing, if this participant + is not controlled. + + +``` + +## Caveats + +Nothing - at least not known. +If you found something, please contact us! diff --git a/docs/readthedocs/models/models.md b/docs/readthedocs/models/models.md index 0803c7777..74d06e624 100644 --- a/docs/readthedocs/models/models.md +++ b/docs/readthedocs/models/models.md @@ -139,6 +139,7 @@ input/thermal/domestichotwaterstorage maxdepth: 1 --- input/participant/general +input/participant/ac input/participant/bm input/participant/chp input/participant/ev @@ -196,6 +197,7 @@ result/grid/congestion --- maxdepth: 1 --- +result/participant/ac result/participant/bm result/participant/chp result/participant/ev diff --git a/docs/readthedocs/models/result/participant/ac.md b/docs/readthedocs/models/result/participant/ac.md new file mode 100644 index 000000000..e7ba629cc --- /dev/null +++ b/docs/readthedocs/models/result/participant/ac.md @@ -0,0 +1,43 @@ +(ac-result)= + +# Air Condition + +Result of an air condition. + +## Attributes, Units and Remarks + +```{list-table} + :widths: 33 33 33 + :header-rows: 1 + + + * - Attribute + - Unit + - Remarks + + * - time + - + - date and time for the produced result + + * - inputModel + - + - uuid for the associated input model + + * - p + - MW + - + + * - q + - MVAr + - + + * - qDot + - MW + - Thermal power + +``` + +## Caveats + +Nothing - at least not known. +If you found something, please contact us! diff --git a/docs/uml/main/EntitySourceClassDiagram.puml b/docs/uml/main/EntitySourceClassDiagram.puml index d7c0de723..621ab52f9 100644 --- a/docs/uml/main/EntitySourceClassDiagram.puml +++ b/docs/uml/main/EntitySourceClassDiagram.puml @@ -129,6 +129,7 @@ class ResultEntitySource { + Set getEvcsResults() throws SourceException + Set getEvResults() throws SourceException + Set getHpResults() throws SourceException + + Set getAcResults() throws SourceException + Set getCylindricalStorageResult() throws SourceException + Set getDomesticHotWaterStorageResult() throws SourceException + Set getThermalHouseResults() throws SourceException @@ -141,6 +142,7 @@ class SystemParticipantSource{ - RawGridSource rawGridSource - ThermalSource thermalSource - EnergyManagementSource energyManagementSource + - AcInputFactory acInputFactory - BmInputFactory bmInputFactory - ChpInputFactory chpInputFactory - EvInputFactory evInputFactory @@ -154,6 +156,8 @@ class SystemParticipantSource{ + SystemParticipantSource(TypeSource, ThermalSource, RawGridSource, EnergyManagementSource, DataSource) + SystemParticipants getSystemParticipants() throws SourceException + SystemParticipants getSystemParticipants(Map, Map) throws SourceException + + Set getAirConditions() throws SourceException + + Set getAirConditions(Map, Map, Set) throws SourceException + Set getBmPlants() throws SourceException + Set getBmPlants(Map, Map, Set) throws SourceException + Set getChpPlants() throws SourceException diff --git a/docs/uml/main/OutputDatamodelConcept.puml b/docs/uml/main/OutputDatamodelConcept.puml index 5af946551..033c285cf 100644 --- a/docs/uml/main/OutputDatamodelConcept.puml +++ b/docs/uml/main/OutputDatamodelConcept.puml @@ -93,6 +93,9 @@ package models { class HpResult SystemParticipantWithHeatResult <|-- HpResult + class AcResult + SystemParticipantWithHeatResult <|-- AcResult + class WecResult SystemParticipantResult <|-- WecResult diff --git a/docs/uml/main/input/ModelContainerConcept.puml b/docs/uml/main/input/ModelContainerConcept.puml index 2583a8fc9..a42ac602c 100644 --- a/docs/uml/main/input/ModelContainerConcept.puml +++ b/docs/uml/main/input/ModelContainerConcept.puml @@ -40,6 +40,7 @@ package models.input.container { RawGridElements ..|> InputContainer class SystemParticipants { + - airConditions: Set - bmPlants: Set - chpPlants: Set - evcs: Set diff --git a/docs/uml/main/input/SystemDatamodelConcept.puml b/docs/uml/main/input/SystemDatamodelConcept.puml index 7f86d7623..01bf89740 100644 --- a/docs/uml/main/input/SystemDatamodelConcept.puml +++ b/docs/uml/main/input/SystemDatamodelConcept.puml @@ -173,6 +173,15 @@ package models { SystemParticipantInput ..|> HasNodes SystemParticipantInput ..|> NodeInput + class AcInput { + - type: AcTypeInput + - thermalBus: ThermalBusInput + } + AcInput --|> SystemParticipantInput + AcInput ..|> HasType + AcInput ..|> HasThermalBus + AcInput *-- ThermalBusInput + class BmInput { - type: BmTypeInput - marketReaction: Boolean @@ -214,7 +223,7 @@ package models { HpInput --|> SystemParticipantInput HpInput ..|> HasType HpInput ..|> HasThermalBus - ChpInput *-- ThermalBusInput + HpInput *-- ThermalBusInput class LoadInput { - standardLoadProfile: StandardLoadProfile diff --git a/src/main/java/edu/ie3/datamodel/io/factory/input/participant/AcInputEntityData.java b/src/main/java/edu/ie3/datamodel/io/factory/input/participant/AcInputEntityData.java new file mode 100644 index 000000000..97d01613f --- /dev/null +++ b/src/main/java/edu/ie3/datamodel/io/factory/input/participant/AcInputEntityData.java @@ -0,0 +1,53 @@ +/* + * © 2021. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation +*/ +package edu.ie3.datamodel.io.factory.input.participant; + +import edu.ie3.datamodel.models.input.EmInput; +import edu.ie3.datamodel.models.input.NodeInput; +import edu.ie3.datamodel.models.input.OperatorInput; +import edu.ie3.datamodel.models.input.system.AcInput; +import edu.ie3.datamodel.models.input.system.type.AcTypeInput; +import edu.ie3.datamodel.models.input.thermal.ThermalBusInput; +import java.util.Map; + +public class AcInputEntityData extends ThermalSystemParticipantEntityData { + + public AcInputEntityData( + Map fieldsToAttributes, + NodeInput node, + EmInput em, + AcTypeInput typeInput, + ThermalBusInput thermalBusInput) { + super(fieldsToAttributes, AcInput.class, node, em, typeInput, thermalBusInput); + } + + public AcInputEntityData( + Map fieldsToAttributes, + OperatorInput operator, + NodeInput node, + EmInput em, + AcTypeInput typeInput, + ThermalBusInput thermalBusInput) { + super(fieldsToAttributes, AcInput.class, operator, node, em, typeInput, thermalBusInput); + } + + /** + * Creates a new AcInputEntityData object based on a given {@link + * SystemParticipantTypedEntityData} object and given thermal bus input + * + * @param entityData The SystemParticipantTypedEntityData object to enhance + * @param thermalBusInput The thermal bus input + */ + public AcInputEntityData( + SystemParticipantTypedEntityData entityData, ThermalBusInput thermalBusInput) { + super(entityData, thermalBusInput); + } + + @Override + public String toString() { + return buildToStringContent("AcInputEntityData"); + } +} diff --git a/src/main/java/edu/ie3/datamodel/io/factory/input/participant/AcInputFactory.java b/src/main/java/edu/ie3/datamodel/io/factory/input/participant/AcInputFactory.java new file mode 100644 index 000000000..77607d277 --- /dev/null +++ b/src/main/java/edu/ie3/datamodel/io/factory/input/participant/AcInputFactory.java @@ -0,0 +1,48 @@ +/* + * © 2021. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation +*/ +package edu.ie3.datamodel.io.factory.input.participant; + +import edu.ie3.datamodel.models.OperationTime; +import edu.ie3.datamodel.models.input.EmInput; +import edu.ie3.datamodel.models.input.NodeInput; +import edu.ie3.datamodel.models.input.OperatorInput; +import edu.ie3.datamodel.models.input.system.AcInput; +import edu.ie3.datamodel.models.input.system.characteristic.ReactivePowerCharacteristic; +import edu.ie3.datamodel.models.input.system.type.AcTypeInput; +import edu.ie3.datamodel.models.input.thermal.ThermalBusInput; +import java.util.UUID; + +public class AcInputFactory + extends ThermalSystemParticipantInputFactory { + + public AcInputFactory() { + super(AcInput.class); + } + + @Override + protected AcInput createThermalSystemModel( + UUID uuid, + String id, + OperatorInput operator, + OperationTime operationTime, + NodeInput node, + ThermalBusInput thermalBusInput, + ReactivePowerCharacteristic qCharacteristics, + EmInput em, + Object typeInput) { + + return new AcInput( + uuid, + id, + operator, + operationTime, + node, + thermalBusInput, + qCharacteristics, + em, + (AcTypeInput) typeInput); + } +} diff --git a/src/main/java/edu/ie3/datamodel/io/factory/input/participant/HpInputEntityData.java b/src/main/java/edu/ie3/datamodel/io/factory/input/participant/HpInputEntityData.java index 83f01970f..e081a75fd 100644 --- a/src/main/java/edu/ie3/datamodel/io/factory/input/participant/HpInputEntityData.java +++ b/src/main/java/edu/ie3/datamodel/io/factory/input/participant/HpInputEntityData.java @@ -12,10 +12,8 @@ import edu.ie3.datamodel.models.input.system.type.HpTypeInput; import edu.ie3.datamodel.models.input.thermal.ThermalBusInput; import java.util.Map; -import java.util.Objects; -public class HpInputEntityData extends SystemParticipantTypedEntityData { - private final ThermalBusInput thermalBusInput; +public class HpInputEntityData extends ThermalSystemParticipantEntityData { public HpInputEntityData( Map fieldsToAttributes, @@ -23,8 +21,7 @@ public HpInputEntityData( EmInput em, HpTypeInput typeInput, ThermalBusInput thermalBusInput) { - super(fieldsToAttributes, HpInput.class, node, em, typeInput); - this.thermalBusInput = thermalBusInput; + super(fieldsToAttributes, HpInput.class, node, em, typeInput, thermalBusInput); } public HpInputEntityData( @@ -34,8 +31,7 @@ public HpInputEntityData( EmInput em, HpTypeInput typeInput, ThermalBusInput thermalBusInput) { - super(fieldsToAttributes, HpInput.class, operator, node, em, typeInput); - this.thermalBusInput = thermalBusInput; + super(fieldsToAttributes, HpInput.class, operator, node, em, typeInput, thermalBusInput); } /** @@ -47,42 +43,11 @@ public HpInputEntityData( */ public HpInputEntityData( SystemParticipantTypedEntityData entityData, ThermalBusInput thermalBusInput) { - super(entityData, entityData.getTypeInput()); - this.thermalBusInput = thermalBusInput; - } - - public ThermalBusInput getThermalBusInput() { - return thermalBusInput; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof HpInputEntityData that)) return false; - if (!super.equals(o)) return false; - return thermalBusInput.equals(that.thermalBusInput); - } - - @Override - public int hashCode() { - return Objects.hash(super.hashCode(), thermalBusInput); + super(entityData, thermalBusInput); } @Override public String toString() { - return "HpInputEntityData{" - + "thermalBusInput=" - + thermalBusInput.getUuid() - + ", typeInput=" - + getTypeInput().getUuid() - + ", node=" - + getNode().getUuid() - + ", operatorInput=" - + getOperatorInput().getUuid() - + ", fieldsToValues=" - + getFieldsToValues() - + ", targetClass=" - + getTargetClass() - + '}'; + return buildToStringContent("HpInputEntityData"); } } diff --git a/src/main/java/edu/ie3/datamodel/io/factory/input/participant/HpInputFactory.java b/src/main/java/edu/ie3/datamodel/io/factory/input/participant/HpInputFactory.java index 27943ee29..f5de578be 100644 --- a/src/main/java/edu/ie3/datamodel/io/factory/input/participant/HpInputFactory.java +++ b/src/main/java/edu/ie3/datamodel/io/factory/input/participant/HpInputFactory.java @@ -11,32 +11,28 @@ import edu.ie3.datamodel.models.input.OperatorInput; import edu.ie3.datamodel.models.input.system.HpInput; import edu.ie3.datamodel.models.input.system.characteristic.ReactivePowerCharacteristic; +import edu.ie3.datamodel.models.input.system.type.HpTypeInput; +import edu.ie3.datamodel.models.input.thermal.ThermalBusInput; import java.util.UUID; public class HpInputFactory - extends SystemParticipantInputEntityFactory { - private static final String TYPE = "type"; - private static final String THERMAL_BUS = "thermalBus"; + extends ThermalSystemParticipantInputFactory { public HpInputFactory() { super(HpInput.class); } @Override - protected String[] getAdditionalFields() { - return new String[] {TYPE, THERMAL_BUS}; - } - - @Override - protected HpInput buildModel( - HpInputEntityData data, + protected HpInput createThermalSystemModel( UUID uuid, String id, + OperatorInput operator, + OperationTime operationTime, NodeInput node, + ThermalBusInput thermalBusInput, ReactivePowerCharacteristic qCharacteristics, - OperatorInput operator, - OperationTime operationTime) { - final EmInput em = data.getControllingEm().orElse(null); + EmInput em, + Object typeInput) { return new HpInput( uuid, @@ -44,9 +40,9 @@ protected HpInput buildModel( operator, operationTime, node, - data.getThermalBusInput(), + thermalBusInput, qCharacteristics, em, - data.getTypeInput()); + (HpTypeInput) typeInput); } } diff --git a/src/main/java/edu/ie3/datamodel/io/factory/input/participant/ThermalSystemParticipantEntityData.java b/src/main/java/edu/ie3/datamodel/io/factory/input/participant/ThermalSystemParticipantEntityData.java new file mode 100644 index 000000000..c96871082 --- /dev/null +++ b/src/main/java/edu/ie3/datamodel/io/factory/input/participant/ThermalSystemParticipantEntityData.java @@ -0,0 +1,97 @@ +/* + * © 2021. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation +*/ +package edu.ie3.datamodel.io.factory.input.participant; + +import edu.ie3.datamodel.models.UniqueEntity; +import edu.ie3.datamodel.models.input.EmInput; +import edu.ie3.datamodel.models.input.NodeInput; +import edu.ie3.datamodel.models.input.OperatorInput; +import edu.ie3.datamodel.models.input.system.type.SystemParticipantTypeInput; +import edu.ie3.datamodel.models.input.thermal.ThermalBusInput; +import java.util.Map; +import java.util.Objects; + +/** + * Abstract base class for system participants that connect to thermal buses + * + * @param The specific type input for the thermal system participant + */ +public abstract class ThermalSystemParticipantEntityData + extends SystemParticipantTypedEntityData { + + private final ThermalBusInput thermalBusInput; + + protected ThermalSystemParticipantEntityData( + Map fieldsToAttributes, + Class targetClass, + NodeInput node, + EmInput em, + T typeInput, + ThermalBusInput thermalBusInput) { + super(fieldsToAttributes, targetClass, node, em, typeInput); + this.thermalBusInput = thermalBusInput; + } + + protected ThermalSystemParticipantEntityData( + Map fieldsToAttributes, + Class targetClass, + OperatorInput operator, + NodeInput node, + EmInput em, + T typeInput, + ThermalBusInput thermalBusInput) { + super(fieldsToAttributes, targetClass, operator, node, em, typeInput); + this.thermalBusInput = thermalBusInput; + } + + /** + * Creates a new ThermalSystemParticipantEntityData object based on a given {@link + * SystemParticipantTypedEntityData} object and given thermal bus input + * + * @param entityData The SystemParticipantTypedEntityData object to enhance + * @param thermalBusInput The thermal bus input + */ + protected ThermalSystemParticipantEntityData( + SystemParticipantTypedEntityData entityData, ThermalBusInput thermalBusInput) { + super(entityData, entityData.getTypeInput()); + this.thermalBusInput = thermalBusInput; + } + + public ThermalBusInput getThermalBusInput() { + return thermalBusInput; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ThermalSystemParticipantEntityData that)) return false; + if (!super.equals(o)) return false; + return Objects.equals(thermalBusInput, that.thermalBusInput); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), thermalBusInput); + } + + protected String buildToStringContent(String className) { + return className + + "{" + + "thermalBusInput=" + + thermalBusInput.getUuid() + + ", typeInput=" + + getTypeInput().getUuid() + + ", node=" + + getNode().getUuid() + + ", operatorInput=" + + getOperatorInput().getUuid() + + ", fieldsToValues=" + + getFieldsToValues() + + ", targetClass=" + + getTargetClass() + + '}'; + } +} diff --git a/src/main/java/edu/ie3/datamodel/io/factory/input/participant/ThermalSystemParticipantInputFactory.java b/src/main/java/edu/ie3/datamodel/io/factory/input/participant/ThermalSystemParticipantInputFactory.java new file mode 100644 index 000000000..551a7788c --- /dev/null +++ b/src/main/java/edu/ie3/datamodel/io/factory/input/participant/ThermalSystemParticipantInputFactory.java @@ -0,0 +1,87 @@ +/* + * © 2021. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation +*/ +package edu.ie3.datamodel.io.factory.input.participant; + +import edu.ie3.datamodel.models.OperationTime; +import edu.ie3.datamodel.models.input.EmInput; +import edu.ie3.datamodel.models.input.NodeInput; +import edu.ie3.datamodel.models.input.OperatorInput; +import edu.ie3.datamodel.models.input.system.SystemParticipantInput; +import edu.ie3.datamodel.models.input.system.characteristic.ReactivePowerCharacteristic; +import edu.ie3.datamodel.models.input.thermal.ThermalBusInput; +import java.util.UUID; + +/** + * Abstract factory for thermal system participants that share common construction patterns + * + * @param The model type (AcInput, HpInput, etc.) + * @param The entity data type + */ +public abstract class ThermalSystemParticipantInputFactory< + M extends SystemParticipantInput, D extends ThermalSystemParticipantEntityData> + extends SystemParticipantInputEntityFactory { + + protected static final String TYPE = "type"; + protected static final String THERMAL_BUS = "thermalBus"; + + protected ThermalSystemParticipantInputFactory(Class modelClass) { + super(modelClass); + } + + @Override + protected String[] getAdditionalFields() { + return new String[] {TYPE, THERMAL_BUS}; + } + + @Override + protected final M buildModel( + D data, + UUID uuid, + String id, + NodeInput node, + ReactivePowerCharacteristic qCharacteristics, + OperatorInput operator, + OperationTime operationTime) { + + final EmInput em = data.getControllingEm().orElse(null); + + return createThermalSystemModel( + uuid, + id, + operator, + operationTime, + node, + data.getThermalBusInput(), + qCharacteristics, + em, + data.getTypeInput()); + } + + /** + * Creates the specific thermal system model instance + * + * @param uuid The UUID of the system participant + * @param id The ID of the system participant + * @param operator The operator input + * @param operationTime The operation time + * @param node The node input + * @param thermalBusInput The thermal bus input + * @param qCharacteristics The reactive power characteristics + * @param em The energy management input (can be null) + * @param typeInput The type input for the specific system participant + * @return The created thermal system model + */ + protected abstract M createThermalSystemModel( + UUID uuid, + String id, + OperatorInput operator, + OperationTime operationTime, + NodeInput node, + ThermalBusInput thermalBusInput, + ReactivePowerCharacteristic qCharacteristics, + EmInput em, + Object typeInput); +} diff --git a/src/main/java/edu/ie3/datamodel/io/factory/result/SystemParticipantResultFactory.java b/src/main/java/edu/ie3/datamodel/io/factory/result/SystemParticipantResultFactory.java index 150709946..afae9021b 100644 --- a/src/main/java/edu/ie3/datamodel/io/factory/result/SystemParticipantResultFactory.java +++ b/src/main/java/edu/ie3/datamodel/io/factory/result/SystemParticipantResultFactory.java @@ -34,6 +34,7 @@ public SystemParticipantResultFactory() { super( LoadResult.class, FixedFeedInResult.class, + AcResult.class, BmResult.class, PvResult.class, ChpResult.class, @@ -56,6 +57,7 @@ public SystemParticipantResultFactory(DateTimeFormatter dateTimeFormatter) { dateTimeFormatter, LoadResult.class, FixedFeedInResult.class, + AcResult.class, BmResult.class, PvResult.class, ChpResult.class, @@ -113,6 +115,8 @@ protected SystemParticipantResult buildModel(EntityData data) { return new ChpResult(zdtTime, inputModelUuid, p, q, qDot); } else if (entityClass.equals(HpResult.class)) { return new HpResult(zdtTime, inputModelUuid, p, q, qDot); + } else if (entityClass.equals(AcResult.class)) { + return new AcResult(zdtTime, inputModelUuid, p, q, qDot); } else { throw new FactoryException("Cannot process " + entityClass.getSimpleName() + ".class."); } diff --git a/src/main/java/edu/ie3/datamodel/io/factory/typeinput/SystemParticipantTypeInputFactory.java b/src/main/java/edu/ie3/datamodel/io/factory/typeinput/SystemParticipantTypeInputFactory.java index 29a9e15e3..260019091 100644 --- a/src/main/java/edu/ie3/datamodel/io/factory/typeinput/SystemParticipantTypeInputFactory.java +++ b/src/main/java/edu/ie3/datamodel/io/factory/typeinput/SystemParticipantTypeInputFactory.java @@ -59,6 +59,7 @@ public class SystemParticipantTypeInputFactory public SystemParticipantTypeInputFactory() { super( + AcTypeInput.class, EvTypeInput.class, HpTypeInput.class, BmTypeInput.class, @@ -76,6 +77,8 @@ protected List> getFields(Class entityClass) { constructorParameters = expandSet(standardConstructorParams, E_STORAGE, E_CONS, S_RATED_DC); } else if (entityClass.equals(HpTypeInput.class)) { constructorParameters = expandSet(standardConstructorParams, P_THERMAL); + } else if (entityClass.equals(AcTypeInput.class)) { + constructorParameters = expandSet(standardConstructorParams, P_THERMAL); } else if (entityClass.equals(BmTypeInput.class)) { constructorParameters = expandSet(standardConstructorParams, ACTIVE_POWER_GRADIENT, ETA_CONV); } else if (entityClass.equals(WecTypeInput.class)) { @@ -105,6 +108,8 @@ protected SystemParticipantTypeInput buildModel(EntityData data) { return buildEvTypeInput(data, uuid, id, capEx, opEx, sRated, cosPhi); else if (data.getTargetClass().equals(HpTypeInput.class)) return buildHpTypeInput(data, uuid, id, capEx, opEx, sRated, cosPhi); + else if (data.getTargetClass().equals(AcTypeInput.class)) + return buildAcTypeInput(data, uuid, id, capEx, opEx, sRated, cosPhi); else if (data.getTargetClass().equals(BmTypeInput.class)) return buildBmTypeInput(data, uuid, id, capEx, opEx, sRated, cosPhi); else if (data.getTargetClass().equals(WecTypeInput.class)) @@ -151,6 +156,19 @@ private SystemParticipantTypeInput buildHpTypeInput( return new HpTypeInput(uuid, id, capEx, opEx, sRated, cosPhi, pThermal); } + private SystemParticipantTypeInput buildAcTypeInput( + EntityData data, + UUID uuid, + String id, + ComparableQuantity capEx, + ComparableQuantity opEx, + ComparableQuantity sRated, + double cosPhi) { + ComparableQuantity pThermal = data.getQuantity(P_THERMAL, StandardUnits.ACTIVE_POWER_IN); + + return new AcTypeInput(uuid, id, capEx, opEx, sRated, cosPhi, pThermal); + } + private SystemParticipantTypeInput buildBmTypeInput( EntityData data, UUID uuid, diff --git a/src/main/java/edu/ie3/datamodel/io/naming/DefaultDirectoryHierarchy.java b/src/main/java/edu/ie3/datamodel/io/naming/DefaultDirectoryHierarchy.java index 78d1cbf43..8968bf609 100644 --- a/src/main/java/edu/ie3/datamodel/io/naming/DefaultDirectoryHierarchy.java +++ b/src/main/java/edu/ie3/datamodel/io/naming/DefaultDirectoryHierarchy.java @@ -243,6 +243,7 @@ private enum SubDirectories { Constants.INPUT_SUB_TREE.resolve("participants"), true, Stream.of( + AcInput.class, BmInput.class, ChpInput.class, EvInput.class, @@ -258,6 +259,7 @@ private enum SubDirectories { Constants.RESULT_SUB_TREE.resolve("participants"), false, Stream.of( + AcResult.class, BmResult.class, ChpResult.class, EvResult.class, diff --git a/src/main/java/edu/ie3/datamodel/io/processor/Processor.java b/src/main/java/edu/ie3/datamodel/io/processor/Processor.java index d232dbf27..e31a57e6a 100644 --- a/src/main/java/edu/ie3/datamodel/io/processor/Processor.java +++ b/src/main/java/edu/ie3/datamodel/io/processor/Processor.java @@ -271,6 +271,7 @@ protected String processMethodResult( case "LoadProfile", "BdewStandardLoadProfile", "RandomLoadProfile" -> resultStringBuilder.append(((LoadProfile) methodReturnObject).getKey()); case "AssetTypeInput", + "AcTypeInput", "BmTypeInput", "ChpTypeInput", "EvTypeInput", diff --git a/src/main/java/edu/ie3/datamodel/io/processor/input/InputEntityProcessor.java b/src/main/java/edu/ie3/datamodel/io/processor/input/InputEntityProcessor.java index 6986361ee..e8a96984d 100644 --- a/src/main/java/edu/ie3/datamodel/io/processor/input/InputEntityProcessor.java +++ b/src/main/java/edu/ie3/datamodel/io/processor/input/InputEntityProcessor.java @@ -47,6 +47,7 @@ public class InputEntityProcessor extends EntityProcessor { MeasurementUnitInput.class, ThermalBusInput.class, /* -- SystemParticipantInput */ + AcInput.class, ChpInput.class, BmInput.class, EvInput.class, @@ -67,6 +68,7 @@ public class InputEntityProcessor extends EntityProcessor { NodeGraphicInput.class, LineGraphicInput.class, /* - AssetTypeInput */ + AcTypeInput.class, BmTypeInput.class, ChpTypeInput.class, EvTypeInput.class, 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 224b75850..1e5044280 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 @@ -52,6 +52,7 @@ public class ResultEntityProcessor extends EntityProcessor { EvcsResult.class, EvResult.class, HpResult.class, + AcResult.class, Transformer2WResult.class, Transformer3WResult.class, LineResult.class, diff --git a/src/main/java/edu/ie3/datamodel/io/sink/CsvFileSink.java b/src/main/java/edu/ie3/datamodel/io/sink/CsvFileSink.java index 4b08d00f6..9588dabe2 100644 --- a/src/main/java/edu/ie3/datamodel/io/sink/CsvFileSink.java +++ b/src/main/java/edu/ie3/datamodel/io/sink/CsvFileSink.java @@ -170,6 +170,7 @@ public void persistJointGrid(JointGridContainer jointGridContainer) { // get system participants with types or operators SystemParticipants systemParticipants = jointGridContainer.getSystemParticipants(); + Set airConditions = systemParticipants.getAirConditions(); Set bmPlants = systemParticipants.getBmPlants(); Set chpPlants = systemParticipants.getChpPlants(); Set evcs = systemParticipants.getEvcs(); @@ -195,6 +196,7 @@ public void persistJointGrid(JointGridContainer jointGridContainer) { chpPlants, evs, heatPumps, + airConditions, storages, wecPlants) .flatMap(Collection::stream) @@ -216,6 +218,7 @@ public void persistJointGrid(JointGridContainer jointGridContainer) { evs, fixedFeedIns, heatPumps, + airConditions, loads, pvPlants, storages, diff --git a/src/main/java/edu/ie3/datamodel/io/source/ResultEntitySource.java b/src/main/java/edu/ie3/datamodel/io/source/ResultEntitySource.java index 1e555cc56..3d01842da 100644 --- a/src/main/java/edu/ie3/datamodel/io/source/ResultEntitySource.java +++ b/src/main/java/edu/ie3/datamodel/io/source/ResultEntitySource.java @@ -80,6 +80,7 @@ public void validate() throws ValidationException { Stream.of( LoadResult.class, FixedFeedInResult.class, + AcResult.class, BmResult.class, PvResult.class, ChpResult.class, @@ -309,6 +310,19 @@ public Set getEvResults() throws SourceException { return getResultEntities(EvResult.class, systemParticipantResultFactory); } + /** + * Returns a unique set of {@link AcResult} instances. + * + *

This set has to be unique in the sense of object uniqueness but also in the sense of {@link + * java.util.UUID} uniqueness of the provided {@link AcResult} which has to be checked manually, + * as {@link AcResult#equals(Object)} is NOT restricted by the uuid of {@link AcResult}. + * + * @return a set of object and uuid unique {@link AcResult} entities + */ + public Set getAcResults() throws SourceException { + return getResultEntities(AcResult.class, systemParticipantResultFactory); + } + /** * Returns a unique set of {@link HpResult} instances. * diff --git a/src/main/java/edu/ie3/datamodel/io/source/SystemParticipantSource.java b/src/main/java/edu/ie3/datamodel/io/source/SystemParticipantSource.java index fd4c0f2cc..2631f0b18 100644 --- a/src/main/java/edu/ie3/datamodel/io/source/SystemParticipantSource.java +++ b/src/main/java/edu/ie3/datamodel/io/source/SystemParticipantSource.java @@ -44,6 +44,7 @@ public class SystemParticipantSource extends AssetEntitySource { private final EnergyManagementSource energyManagementSource; // factories + private final AcInputFactory acInputFactory; private final BmInputFactory bmInputFactory; private final ChpInputFactory chpInputFactory; private final EvInputFactory evInputFactory; @@ -84,6 +85,7 @@ public SystemParticipantSource( this.energyManagementSource = energyManagementSource; // init factories + this.acInputFactory = new AcInputFactory(); this.bmInputFactory = new BmInputFactory(); this.chpInputFactory = new ChpInputFactory(); this.evInputFactory = new EvInputFactory(); @@ -100,6 +102,7 @@ public SystemParticipantSource( public void validate() throws ValidationException { Try.scanStream( Stream.of( + validate(AcInput.class, dataSource, acInputFactory), validate(BmInput.class, dataSource, bmInputFactory), validate(ChpInput.class, dataSource, chpInputFactory), validate(EvInput.class, dataSource, evInputFactory), @@ -176,6 +179,7 @@ public SystemParticipants getSystemParticipants( Map chpTypes = typeSource.getChpTypes(); Map evTypes = typeSource.getEvTypes(); Map hpTypes = typeSource.getHpTypes(); + Map acTypes = typeSource.getAcTypes(); Map storageTypes = typeSource.getStorageTypes(); Map wecTypes = typeSource.getWecTypes(); Map emUnits = energyManagementSource.getEmUnits(); @@ -209,6 +213,10 @@ public SystemParticipants getSystemParticipants( Try.of( () -> getHeatPumps(operators, nodes, emUnits, hpTypes, thermalBuses), SourceException.class); + Try, SourceException> acInputs = + Try.of( + () -> getAirConditions(operators, nodes, emUnits, acTypes, thermalBuses), + SourceException.class); List exceptions = Try.getExceptions( @@ -221,7 +229,8 @@ public SystemParticipants getSystemParticipants( evs, evcs, chpInputs, - hpInputs); + hpInputs, + acInputs); if (!exceptions.isEmpty()) { throw new SystemParticipantsException( @@ -240,6 +249,7 @@ public SystemParticipants getSystemParticipants( evs.getOrThrow(), fixedFeedInInputs.getOrThrow(), hpInputs.getOrThrow(), + acInputs.getOrThrow(), loads.getOrThrow(), pvInputs.getOrThrow(), storages.getOrThrow(), @@ -743,6 +753,40 @@ public Set getHeatPumps( return getEntities(HpInput.class, dataSource, hpInputFactory, builder).collect(toSet()); } + /** + * If one of the sets of {@link NodeInput}, {@link ThermalBusInput} or {@link AcTypeInput} + * entities is not exhaustive for all available {@link AcInput} entities (e.g. a {@link NodeInput} + * or {@link AcTypeInput} entity is missing) or if an error during the building process occurs a + * {@link SourceException} is thrown, else all entities that are able to be built will be + * returned. + * + *

If the set with {@link OperatorInput} is not exhaustive, the corresponding operator is set + * to {@link OperatorInput#NO_OPERATOR_ASSIGNED} + * + * @param operators a map of UUID to object- and uuid-unique {@link OperatorInput} entities + * @param nodes a map of UUID to object- and uuid-unique {@link NodeInput} entities + * @param emUnits a map of UUID to object- and uuid-unique {@link EmInput} entities + * @param types a map of UUID to object- and uuid-unique {@link AcTypeInput} entities + * @param thermalBuses a map of UUID to object- and uuid-unique {@link ThermalBusInput} entities + * @return a set of object- and uuid-unique {@link AcInput} entities + */ + public Set getAirConditions( + Map operators, + Map nodes, + Map emUnits, + Map types, + Map thermalBuses) + throws SourceException { + + WrappedFunction builder = + data -> + participantEnricher + .andThen(enrichTypes(types)) + .andThen(enrich(THERMAL_BUS, thermalBuses, AcInputEntityData::new)) + .apply(data, operators, nodes, emUnits); + return getEntities(AcInput.class, dataSource, acInputFactory, builder).collect(toSet()); + } + // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- /** diff --git a/src/main/java/edu/ie3/datamodel/io/source/TypeSource.java b/src/main/java/edu/ie3/datamodel/io/source/TypeSource.java index 67f3ecd0b..78a7c2cca 100644 --- a/src/main/java/edu/ie3/datamodel/io/source/TypeSource.java +++ b/src/main/java/edu/ie3/datamodel/io/source/TypeSource.java @@ -60,6 +60,7 @@ public void validate() throws ValidationException { Stream.of( EvTypeInput.class, HpTypeInput.class, + AcTypeInput.class, BmTypeInput.class, WecTypeInput.class, ChpTypeInput.class, @@ -170,6 +171,19 @@ public Map getHpTypes() throws SourceException { return getEntities(HpTypeInput.class, dataSource, systemParticipantTypeInputFactory); } + /** + * Returns a set of {@link AcTypeInput} instances within a map by UUID. + * + *

This set has to be unique in the sense of object uniqueness but also in the sense of {@link + * UUID} uniqueness of the provided {@link AcTypeInput} which has to be checked manually, as + * {@link AcTypeInput#equals(Object)} is NOT restricted on the uuid of {@link AcTypeInput}. + * + * @return a map of UUID to object- and uuid-unique {@link AcTypeInput} entities + */ + public Map getAcTypes() throws SourceException { + return getEntities(AcTypeInput.class, dataSource, systemParticipantTypeInputFactory); + } + /** * Returns a set of {@link StorageTypeInput} instances within a map by UUID. * diff --git a/src/main/java/edu/ie3/datamodel/models/input/container/SystemParticipants.java b/src/main/java/edu/ie3/datamodel/models/input/container/SystemParticipants.java index fa81ea0fd..2b9c716ae 100644 --- a/src/main/java/edu/ie3/datamodel/models/input/container/SystemParticipants.java +++ b/src/main/java/edu/ie3/datamodel/models/input/container/SystemParticipants.java @@ -20,6 +20,7 @@ public class SystemParticipants implements InputContainer evs; private final Set fixedFeedIns; private final Set heatPumps; + private final Set airConditions; private final Set loads; private final Set pvPlants; private final Set storages; @@ -32,6 +33,7 @@ public SystemParticipants( Set evs, Set fixedFeedIns, Set heatPumps, + Set airConditions, Set loads, Set pvPlants, Set storages, @@ -42,6 +44,7 @@ public SystemParticipants( this.evs = evs; this.fixedFeedIns = fixedFeedIns; this.heatPumps = heatPumps; + this.airConditions = airConditions; this.loads = loads; this.pvPlants = pvPlants; this.storages = storages; @@ -78,6 +81,10 @@ public SystemParticipants(Collection systemParticipants) { systemParticipants.stream() .flatMap(participants -> participants.heatPumps.stream()) .collect(Collectors.toSet()); + this.airConditions = + systemParticipants.stream() + .flatMap(participants -> participants.airConditions.stream()) + .collect(Collectors.toSet()); this.loads = systemParticipants.stream() .flatMap(participants -> participants.loads.stream()) @@ -135,6 +142,11 @@ public SystemParticipants(List systemParticipants) { .filter(HpInput.class::isInstance) .map(HpInput.class::cast) .collect(Collectors.toSet()); + this.airConditions = + systemParticipants.parallelStream() + .filter(AcInput.class::isInstance) + .map(AcInput.class::cast) + .collect(Collectors.toSet()); this.loads = systemParticipants.parallelStream() .filter(LoadInput.class::isInstance) @@ -166,6 +178,7 @@ public final List allEntitiesAsList() { allEntities.addAll(evs); allEntities.addAll(fixedFeedIns); allEntities.addAll(heatPumps); + allEntities.addAll(airConditions); allEntities.addAll(loads); allEntities.addAll(pvPlants); allEntities.addAll(storages); @@ -219,6 +232,13 @@ public Set getHeatPumps() { return Collections.unmodifiableSet(heatPumps); } + /** + * @return unmodifiable Set of all air conditions in this grid + */ + public Set getAirConditions() { + return Collections.unmodifiableSet(airConditions); + } + /** * @return unmodifiable Set of all loads in this grid */ @@ -257,6 +277,7 @@ public boolean equals(Object o) { && Objects.equals(evs, that.evs) && Objects.equals(fixedFeedIns, that.fixedFeedIns) && Objects.equals(heatPumps, that.heatPumps) + && Objects.equals(airConditions, that.airConditions) && Objects.equals(loads, that.loads) && Objects.equals(pvPlants, that.pvPlants) && Objects.equals(storages, that.storages) @@ -272,6 +293,7 @@ public int hashCode() { evs, fixedFeedIns, heatPumps, + airConditions, loads, pvPlants, storages, @@ -294,6 +316,7 @@ public static class SystemParticipantsCopyBuilder private Set evs; private Set fixedFeedIns; private Set heatPumps; + private Set airConditions; private Set loads; private Set pvPlants; private Set storages; @@ -311,6 +334,7 @@ protected SystemParticipantsCopyBuilder(SystemParticipants systemParticipants) { this.evs = systemParticipants.evs; this.fixedFeedIns = systemParticipants.fixedFeedIns; this.heatPumps = systemParticipants.heatPumps; + this.airConditions = systemParticipants.airConditions; this.loads = systemParticipants.loads; this.pvPlants = systemParticipants.pvPlants; this.storages = systemParticipants.storages; @@ -383,6 +407,17 @@ public SystemParticipantsCopyBuilder heatPumps(Set heatPumps) { return thisInstance(); } + /** + * Method to alter {@link AcInput} + * + * @param airConditions set of altered air conditions + * @return this instance of {@link SystemParticipantsCopyBuilder} + */ + public SystemParticipantsCopyBuilder airConditions(Set airConditions) { + this.airConditions = airConditions; + return thisInstance(); + } + /** * Method to alter {@link LoadInput} * @@ -441,6 +476,7 @@ public SystemParticipants build() { evs, fixedFeedIns, heatPumps, + airConditions, loads, pvPlants, storages, diff --git a/src/main/java/edu/ie3/datamodel/models/input/system/AcInput.java b/src/main/java/edu/ie3/datamodel/models/input/system/AcInput.java new file mode 100644 index 000000000..6f3673b8b --- /dev/null +++ b/src/main/java/edu/ie3/datamodel/models/input/system/AcInput.java @@ -0,0 +1,185 @@ +/* + * © 2021. 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.io.extractor.HasThermalBus; +import edu.ie3.datamodel.io.extractor.HasType; +import edu.ie3.datamodel.models.OperationTime; +import edu.ie3.datamodel.models.input.EmInput; +import edu.ie3.datamodel.models.input.NodeInput; +import edu.ie3.datamodel.models.input.OperatorInput; +import edu.ie3.datamodel.models.input.system.characteristic.ReactivePowerCharacteristic; +import edu.ie3.datamodel.models.input.system.type.AcTypeInput; +import edu.ie3.datamodel.models.input.thermal.ThermalBusInput; +import java.util.Objects; +import java.util.UUID; + +/** Describes an air condition */ +public class AcInput extends SystemParticipantInput implements HasType, HasThermalBus { + /** Type of this air condition, containing default values for air condition of this kind */ + private final AcTypeInput type; + + /** The thermal bus, this model is connected to */ + private final ThermalBusInput thermalBus; + + /** + * Constructor for an operated air condition + * + * @param uuid of the input entity + * @param id of the asset + * @param operator of the asset + * @param operationTime Time for which the entity is operated + * @param node the asset is connected to + * @param thermalBus The thermal bus, this model is connected to + * @param qCharacteristics Description of a reactive power characteristic + * @param em The {@link EmInput} controlling this system participant. Null, if not applicable. + * @param type of AC + */ + public AcInput( + UUID uuid, + String id, + OperatorInput operator, + OperationTime operationTime, + NodeInput node, + ThermalBusInput thermalBus, + ReactivePowerCharacteristic qCharacteristics, + EmInput em, + AcTypeInput type) { + super(uuid, id, operator, operationTime, node, qCharacteristics, em); + this.thermalBus = thermalBus; + this.type = type; + } + + /** + * Constructor for an operated, always on air condition + * + * @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 qCharacteristics Description of a reactive power characteristic + * @param em The {@link EmInput} controlling this system participant. Null, if not applicable. + * @param type of AC + */ + public AcInput( + UUID uuid, + String id, + NodeInput node, + ThermalBusInput thermalBus, + ReactivePowerCharacteristic qCharacteristics, + EmInput em, + AcTypeInput type) { + super(uuid, id, node, qCharacteristics, em); + this.thermalBus = thermalBus; + this.type = type; + } + + @Override + public AcTypeInput getType() { + return type; + } + + @Override + public ThermalBusInput getThermalBus() { + return thermalBus; + } + + public AcInputCopyBuilder copy() { + return new AcInputCopyBuilder(this); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof AcInput acInput)) return false; + if (!super.equals(o)) return false; + return type.equals(acInput.type) && thermalBus.equals(acInput.thermalBus); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), type, thermalBus); + } + + @Override + public String toString() { + return "AcInput{" + + "uuid=" + + getUuid() + + ", id=" + + getId() + + ", operator=" + + getOperator().getUuid() + + ", operationTime=" + + getOperationTime() + + ", node=" + + getNode().getUuid() + + ", qCharacteristics='" + + getqCharacteristics() + + "', em=" + + getControllingEm() + + ", type=" + + type.getUuid() + + ", thermalBus=" + + thermalBus.getUuid() + + '}'; + } + + /** + * A builder pattern based approach to create copies of {@link AcInput} entities with altered + * field values. For detailed field descriptions refer to java docs of {@link AcInput} + * + * @version 0.1 + * @since 05.06.20 + */ + public static class AcInputCopyBuilder + extends SystemParticipantInputCopyBuilder { + + private AcTypeInput type; + private ThermalBusInput thermalBus; + + private AcInputCopyBuilder(AcInput entity) { + super(entity); + this.type = entity.getType(); + this.thermalBus = entity.getThermalBus(); + } + + public AcInputCopyBuilder type(AcTypeInput type) { + this.type = type; + return thisInstance(); + } + + public AcInputCopyBuilder thermalBus(ThermalBusInput thermalBus) { + this.thermalBus = thermalBus; + return thisInstance(); + } + + @Override + public AcInputCopyBuilder scale(Double factor) { + type(type.copy().scale(factor).build()); + return thisInstance(); + } + + @Override + public AcInput build() { + return new AcInput( + getUuid(), + getId(), + getOperator(), + getOperationTime(), + getNode(), + thermalBus, + getqCharacteristics(), + getEm(), + type); + } + + @Override + protected AcInputCopyBuilder thisInstance() { + return this; + } + } +} diff --git a/src/main/java/edu/ie3/datamodel/models/input/system/type/AcTypeInput.java b/src/main/java/edu/ie3/datamodel/models/input/system/type/AcTypeInput.java new file mode 100644 index 000000000..fca80b1bf --- /dev/null +++ b/src/main/java/edu/ie3/datamodel/models/input/system/type/AcTypeInput.java @@ -0,0 +1,129 @@ +/* + * © 2021. 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.type; + +import edu.ie3.datamodel.models.StandardUnits; +import edu.ie3.util.quantities.interfaces.Currency; +import edu.ie3.util.quantities.interfaces.EnergyPrice; +import java.util.Objects; +import java.util.UUID; +import javax.measure.quantity.Power; +import tech.units.indriya.ComparableQuantity; + +/** Describes the type of a {@link edu.ie3.datamodel.models.input.system.AcInput} */ +public class AcTypeInput extends SystemParticipantTypeInput { + /** + * Thermal output of the air condition (typically in kW), when sRated * cosphi_rated is consumed + */ + private final ComparableQuantity pThermal; + + /** + * @param uuid of the input entity + * @param id of this type of AC + * @param capex Captial expense for this type of AC (typically in €) + * @param opex Operating expense for this type of AC (typically in €) + * @param cosphiRated Power factor for this type of AC + * @param sRated Rated apparent power + * @param pThermal Thermal output of the air condition, when sRated * cosphi_rated is consumed + * electrically + */ + public AcTypeInput( + UUID uuid, + String id, + ComparableQuantity capex, + ComparableQuantity opex, + ComparableQuantity sRated, + double cosphiRated, + ComparableQuantity pThermal) { + super(uuid, id, capex, opex, sRated.to(StandardUnits.S_RATED), cosphiRated); + this.pThermal = pThermal.to(StandardUnits.ACTIVE_POWER_IN); + } + + public ComparableQuantity getpThermal() { + return pThermal; + } + + @Override + public AcTypeInputCopyBuilder copy() { + return new AcTypeInputCopyBuilder(this); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof AcTypeInput that)) return false; + if (!super.equals(o)) return false; + return pThermal.equals(that.pThermal); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), pThermal); + } + + @Override + public String toString() { + return "AcTypeInput{" + + "uuid=" + + getUuid() + + ", id=" + + getId() + + "capex=" + + getCapex() + + ", opex=" + + getOpex() + + ", sRated=" + + getsRated() + + ", cosphiRated=" + + getCosPhiRated() + + "pThermal=" + + pThermal + + '}'; + } + + /** + * A builder pattern based approach to create copies of {@link AcTypeInput} entities with altered + * field values. For detailed field descriptions refer to java docs of {@link AcTypeInput} + */ + public static class AcTypeInputCopyBuilder + extends SystemParticipantTypeInputCopyBuilder { + + private ComparableQuantity pThermal; + + private AcTypeInputCopyBuilder(AcTypeInput entity) { + super(entity); + this.pThermal = entity.getpThermal(); + } + + public AcTypeInputCopyBuilder pThermal(ComparableQuantity pThermal) { + this.pThermal = pThermal; + return thisInstance(); + } + + public ComparableQuantity getpThermal() { + return pThermal; + } + + @Override + public AcTypeInput.AcTypeInputCopyBuilder scale(Double factor) { + capex(getCapex().multiply(factor)); + sRated(getsRated().multiply(factor)); + pThermal(getpThermal().multiply(factor)); + return thisInstance(); + } + + @Override + public AcTypeInput build() { + return new AcTypeInput( + getUuid(), getId(), getCapex(), getOpex(), getsRated(), getCosPhiRated(), pThermal); + } + + @Override + protected AcTypeInput.AcTypeInputCopyBuilder thisInstance() { + return this; + } + } +} diff --git a/src/main/java/edu/ie3/datamodel/models/result/system/AcResult.java b/src/main/java/edu/ie3/datamodel/models/result/system/AcResult.java new file mode 100644 index 000000000..cd19f620a --- /dev/null +++ b/src/main/java/edu/ie3/datamodel/models/result/system/AcResult.java @@ -0,0 +1,49 @@ +/* + * © 2021. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation +*/ +package edu.ie3.datamodel.models.result.system; + +import java.time.ZonedDateTime; +import java.util.UUID; +import javax.measure.quantity.Power; +import tech.units.indriya.ComparableQuantity; + +/** Represents calculation results of a {@link edu.ie3.datamodel.models.input.system.AcInput} */ +public class AcResult extends SystemParticipantWithHeatResult { + + /** + * Standard constructor with automatic uuid generation. + * + * @param time date and time when the result is produced + * @param inputModel uuid of the input model that produces the result + * @param p active power output normally provided in MW + * @param q reactive power output normally provided in MVAr + * @param qDot provided heat energy + */ + public AcResult( + ZonedDateTime time, + UUID inputModel, + ComparableQuantity p, + ComparableQuantity q, + ComparableQuantity qDot) { + super(time, inputModel, p, q, qDot); + } + + @Override + public String toString() { + return "AcResult{" + + "time=" + + getTime() + + ", inputModel=" + + getInputModel() + + ", p=" + + getP() + + ", q=" + + getQ() + + ", qDot=" + + getqDot() + + '}'; + } +} diff --git a/src/main/java/edu/ie3/datamodel/utils/ContainerUtils.java b/src/main/java/edu/ie3/datamodel/utils/ContainerUtils.java index 522dfeaa4..82f54cda2 100644 --- a/src/main/java/edu/ie3/datamodel/utils/ContainerUtils.java +++ b/src/main/java/edu/ie3/datamodel/utils/ContainerUtils.java @@ -362,6 +362,7 @@ public static SystemParticipants filterForSubnet(SystemParticipants input, int s Set evs = filterParticipants(input.getEvs(), subnet); Set fixedFeedIns = filterParticipants(input.getFixedFeedIns(), subnet); Set heatpumps = filterParticipants(input.getHeatPumps(), subnet); + Set airConditions = filterParticipants(input.getAirConditions(), subnet); Set loads = filterParticipants(input.getLoads(), subnet); Set pvs = filterParticipants(input.getPvPlants(), subnet); Set storages = filterParticipants(input.getStorages(), subnet); @@ -374,6 +375,7 @@ public static SystemParticipants filterForSubnet(SystemParticipants input, int s evs, fixedFeedIns, heatpumps, + airConditions, loads, pvs, storages, diff --git a/src/main/java/edu/ie3/datamodel/utils/validation/GridContainerValidationUtils.java b/src/main/java/edu/ie3/datamodel/utils/validation/GridContainerValidationUtils.java index 0c4ecac7a..31e51a8a2 100644 --- a/src/main/java/edu/ie3/datamodel/utils/validation/GridContainerValidationUtils.java +++ b/src/main/java/edu/ie3/datamodel/utils/validation/GridContainerValidationUtils.java @@ -277,6 +277,7 @@ protected static Try checkConnectivity( /* sanity check to ensure uniqueness */ List> exceptions = new ArrayList<>(); + exceptions.addAll(checkSystemParticipants(systemParticipants.getAirConditions(), nodes)); exceptions.addAll(checkSystemParticipants(systemParticipants.getBmPlants(), nodes)); exceptions.addAll(checkSystemParticipants(systemParticipants.getChpPlants(), nodes)); exceptions.addAll(checkSystemParticipants(systemParticipants.getEvcs(), nodes)); diff --git a/src/main/java/edu/ie3/datamodel/utils/validation/SystemParticipantValidationUtils.java b/src/main/java/edu/ie3/datamodel/utils/validation/SystemParticipantValidationUtils.java index 6a14d0775..3c11205f1 100644 --- a/src/main/java/edu/ie3/datamodel/utils/validation/SystemParticipantValidationUtils.java +++ b/src/main/java/edu/ie3/datamodel/utils/validation/SystemParticipantValidationUtils.java @@ -69,6 +69,8 @@ protected static List> check( // Further checks for subclasses if (BmInput.class.isAssignableFrom(systemParticipant.getClass())) { exceptions.addAll(checkBm((BmInput) systemParticipant)); + } else if (AcInput.class.isAssignableFrom(systemParticipant.getClass())) { + exceptions.addAll(checkAc((AcInput) systemParticipant)); } else if (ChpInput.class.isAssignableFrom(systemParticipant.getClass())) { exceptions.addAll(checkChp((ChpInput) systemParticipant)); } else if (EvInput.class.isAssignableFrom(systemParticipant.getClass())) { @@ -165,6 +167,8 @@ protected static List> checkType( exceptions.add(checkEvType((EvTypeInput) systemParticipantTypeInput)); } else if (HpTypeInput.class.isAssignableFrom(systemParticipantTypeInput.getClass())) { exceptions.add(checkHpType((HpTypeInput) systemParticipantTypeInput)); + } else if (AcTypeInput.class.isAssignableFrom(systemParticipantTypeInput.getClass())) { + exceptions.add(checkAcType((AcTypeInput) systemParticipantTypeInput)); } else if (StorageTypeInput.class.isAssignableFrom(systemParticipantTypeInput.getClass())) { exceptions.addAll(checkStorageType((StorageTypeInput) systemParticipantTypeInput)); } else if (WecTypeInput.class.isAssignableFrom(systemParticipantTypeInput.getClass())) { @@ -358,6 +362,44 @@ private static Try checkHpType(HpTypeInput hpTypeI InvalidEntityException.class); } + /** + * Validates a AcInput if: + * + *

    + *
  • {@link SystemParticipantValidationUtils#checkAcType(AcTypeInput)} confirms a valid type + * properties + *
+ * + * @param acInput AcInput to validate + * @return a list of try objects either containing an {@link InvalidEntityException} or an empty + * Success + */ + private static List> checkAc(AcInput acInput) { + return checkType(acInput.getType()); + } + + /** + * Validates a AcTypeInput if: + * + *
    + *
  • its rated power is positive + *
  • its rated thermal power is positive + *
+ * + * @param acTypeInput AcTypeInput to validate + * @return a try object either containing an {@link InvalidEntityException} or an empty Success + */ + private static Try checkAcType(AcTypeInput acTypeInput) { + return Try.ofVoid( + () -> + detectZeroOrNegativeQuantities( + new Quantity[] { + acTypeInput.getsRated(), acTypeInput.getpThermal(), + }, + acTypeInput), + InvalidEntityException.class); + } + /** * Validates a LoadInput if: * diff --git a/src/test/groovy/edu/ie3/datamodel/io/extractor/ExtractorTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/extractor/ExtractorTest.groovy index 8e8096879..1828d2df6 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/extractor/ExtractorTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/extractor/ExtractorTest.groovy @@ -114,6 +114,16 @@ class ExtractorTest extends Specification { sptd.hpInput.controllingEm.get(), sptd.hpInput.controllingEm.get().controllingEm.get() ] + sptd.acInput || [ + sptd.acInput.node, + sptd.acInput.type, + sptd.acInput.operator, + sptd.acInput.thermalBus, + sptd.acInput.thermalBus.operator, + sptd.acInput.node.operator, + sptd.acInput.controllingEm.get(), + sptd.acInput.controllingEm.get().controllingEm.get() + ] gtd.lineGraphicCtoD || [ gtd.lineGraphicCtoD.line, diff --git a/src/test/groovy/edu/ie3/datamodel/io/factory/input/participant/AcInputFactoryTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/factory/input/participant/AcInputFactoryTest.groovy new file mode 100644 index 000000000..2127d0058 --- /dev/null +++ b/src/test/groovy/edu/ie3/datamodel/io/factory/input/participant/AcInputFactoryTest.groovy @@ -0,0 +1,81 @@ +/* + * © 2025. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation + */ +package edu.ie3.datamodel.io.factory.input.participant + +import static edu.ie3.util.quantities.PowerSystemUnits.PU + +import edu.ie3.datamodel.exceptions.FactoryException +import edu.ie3.datamodel.models.input.EmInput +import edu.ie3.datamodel.models.input.NodeInput +import edu.ie3.datamodel.models.input.OperatorInput +import edu.ie3.datamodel.models.input.system.AcInput +import edu.ie3.datamodel.models.input.system.characteristic.CharacteristicPoint +import edu.ie3.datamodel.models.input.system.type.AcTypeInput +import edu.ie3.datamodel.models.input.system.type.HpTypeInput +import edu.ie3.datamodel.models.input.thermal.ThermalBusInput +import edu.ie3.datamodel.utils.Try +import edu.ie3.test.helper.FactoryTestHelper +import spock.lang.Specification +import tech.units.indriya.quantity.Quantities + +import java.time.ZonedDateTime +import javax.measure.quantity.Dimensionless + +class AcInputFactoryTest extends Specification implements FactoryTestHelper { + def "A AcInputFactory should contain exactly the expected class for parsing"() { + given: + def inputFactory = new AcInputFactory() + def expectedClasses = [AcInput] + + expect: + inputFactory.supportedClasses == Arrays.asList(expectedClasses.toArray()) + } + + def "A AcInputFactory should parse a valid AcInput correctly"() { + given: "a system participant input type factory and model data" + def inputFactory = new AcInputFactory() + Map parameter = [ + "uuid" : "91ec3bcf-1777-4d38-af67-0bf7c9fa73c7", + "operatesfrom" : "2019-01-01T00:00:00+01:00[Europe/Berlin]", + "operatesuntil" : "2019-12-31T23:59:00+01:00[Europe/Berlin]", + "id" : "TestID", + "qcharacteristics": "cosPhiFixed:{(0.0,1.0)}" + ] + def inputClass = AcInput + def nodeInput = Mock(NodeInput) + def operatorInput = Mock(OperatorInput) + def emUnit = Mock(EmInput) + def typeInput = Mock(AcTypeInput) + def thermalBusInput = Mock(ThermalBusInput) + + when: + Try input = inputFactory.get( + new AcInputEntityData(parameter, operatorInput, nodeInput, emUnit, typeInput, thermalBusInput)) + + then: + input.success + input.data.get().getClass() == inputClass + input.data.get().with { + assert uuid == UUID.fromString(parameter["uuid"]) + assert operationTime.startDate.present + assert operationTime.startDate.get() == ZonedDateTime.parse(parameter["operatesfrom"]) + assert operationTime.endDate.present + assert operationTime.endDate.get() == ZonedDateTime.parse(parameter["operatesuntil"]) + assert operator == operatorInput + assert id == parameter["id"] + assert node == nodeInput + assert qCharacteristics.with { + assert uuid != null + assert points == Collections.unmodifiableSortedSet([ + new CharacteristicPoint(Quantities.getQuantity(0d, PU), Quantities.getQuantity(1d, PU)) + ] as TreeSet) + } + assert controllingEm == Optional.of(emUnit) + assert type == typeInput + assert thermalBus == thermalBusInput + } + } +} diff --git a/src/test/groovy/edu/ie3/datamodel/io/factory/result/SystemParticipantResultFactoryTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/factory/result/SystemParticipantResultFactoryTest.groovy index 31399a1a5..57cc800fb 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/factory/result/SystemParticipantResultFactoryTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/factory/result/SystemParticipantResultFactoryTest.groovy @@ -22,6 +22,7 @@ class SystemParticipantResultFactoryTest extends Specification implements Factor def expectedClasses = [ LoadResult, FixedFeedInResult, + AcResult, BmResult, PvResult, ChpResult, @@ -51,7 +52,7 @@ class SystemParticipantResultFactoryTest extends Specification implements Factor parameter["soc"] = "10" } - if (modelClass == HpResult || modelClass == ChpResult) { + if (modelClass == HpResult || modelClass == ChpResult || modelClass == AcResult) { parameter["qDot"] = "1" } @@ -80,6 +81,10 @@ class SystemParticipantResultFactoryTest extends Specification implements Factor assert(((HpResult) result.data.get()).getqDot() == getQuant(parameter["qDot"], StandardUnits.Q_DOT_RESULT)) } + if (modelClass == AcResult) { + assert(((AcResult) result.data.get()).getqDot() == getQuant(parameter["qDot"], StandardUnits.Q_DOT_RESULT)) + } + if (modelClass == ChpResult) { assert(((ChpResult) result.data.get()).getqDot() == getQuant(parameter["qDot"], StandardUnits.Q_DOT_RESULT)) } @@ -95,6 +100,7 @@ class SystemParticipantResultFactoryTest extends Specification implements Factor ChpResult || ChpResult WecResult || WecResult HpResult || HpResult + AcResult || AcResult StorageResult || StorageResult EmResult || EmResult } diff --git a/src/test/groovy/edu/ie3/datamodel/io/factory/typeinput/SystemParticipantTypeInputFactoryTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/factory/typeinput/SystemParticipantTypeInputFactoryTest.groovy index 95e44f71e..1042a3665 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/factory/typeinput/SystemParticipantTypeInputFactoryTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/factory/typeinput/SystemParticipantTypeInputFactoryTest.groovy @@ -27,6 +27,7 @@ class SystemParticipantTypeInputFactoryTest extends Specification implements Fac given: def typeInputFactory = new SystemParticipantTypeInputFactory() def expectedClasses = [ + AcTypeInput, EvTypeInput, HpTypeInput, BmTypeInput, diff --git a/src/test/groovy/edu/ie3/datamodel/io/naming/EntityPersistenceNamingStrategyTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/naming/EntityPersistenceNamingStrategyTest.groovy index 8688aced0..97fb289b2 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/naming/EntityPersistenceNamingStrategyTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/naming/EntityPersistenceNamingStrategyTest.groovy @@ -244,6 +244,7 @@ class EntityPersistenceNamingStrategyTest extends Specification { PvResult || "prefix_pv_res_suffix" ChpResult || "prefix_chp_res_suffix" HpResult || "prefix_hp_res_suffix" + AcResult || "prefix_ac_res_suffix" WecResult || "prefix_wec_res_suffix" StorageResult || "prefix_storage_res_suffix" EvcsResult || "prefix_evcs_res_suffix" @@ -281,6 +282,7 @@ class EntityPersistenceNamingStrategyTest extends Specification { LoadInput || "load_input" StorageInput || "storage_input" HpInput || "hp_input" + AcInput || "ac_input" LineInput || "line_input" SwitchInput || "switch_input" NodeInput || "node_input" diff --git a/src/test/groovy/edu/ie3/datamodel/io/naming/FileNamingStrategyTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/naming/FileNamingStrategyTest.groovy index 3b12faef4..e584e43c7 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/naming/FileNamingStrategyTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/naming/FileNamingStrategyTest.groovy @@ -5,6 +5,7 @@ */ package edu.ie3.datamodel.io.naming +import edu.ie3.datamodel.io.factory.input.participant.AcInputFactoryTest import edu.ie3.datamodel.io.naming.timeseries.ColumnScheme import edu.ie3.datamodel.io.naming.timeseries.IndividualTimeSeriesMetaInformation import edu.ie3.datamodel.io.naming.timeseries.LoadProfileMetaInformation @@ -21,6 +22,7 @@ import edu.ie3.datamodel.models.input.connector.type.Transformer2WTypeInput import edu.ie3.datamodel.models.input.connector.type.Transformer3WTypeInput import edu.ie3.datamodel.models.input.graphics.LineGraphicInput import edu.ie3.datamodel.models.input.graphics.NodeGraphicInput +import edu.ie3.datamodel.models.input.system.AcInput import edu.ie3.datamodel.models.input.system.BmInput import edu.ie3.datamodel.models.input.system.ChpInput import edu.ie3.datamodel.models.input.system.EvInput @@ -45,6 +47,7 @@ import edu.ie3.datamodel.models.result.connector.LineResult import edu.ie3.datamodel.models.result.connector.SwitchResult import edu.ie3.datamodel.models.result.connector.Transformer2WResult import edu.ie3.datamodel.models.result.connector.Transformer3WResult +import edu.ie3.datamodel.models.result.system.AcResult import edu.ie3.datamodel.models.result.system.BmResult import edu.ie3.datamodel.models.result.system.ChpResult import edu.ie3.datamodel.models.result.system.EmResult @@ -100,6 +103,7 @@ class FileNamingStrategyTest extends Specification { res.present res.get() == expectedPath + where: modelClass || expectedPath LoadResult || Path.of("test_grid", "results", "participants") @@ -108,6 +112,8 @@ class FileNamingStrategyTest extends Specification { PvResult || Path.of("test_grid", "results", "participants") HpResult || Path.of("test_grid", "results", "participants") ChpResult || Path.of("test_grid", "results", "participants") + HpResult || Path.of("test_grid", "results", "participants") + AcResult || Path.of("test_grid", "results", "participants") WecResult || Path.of("test_grid", "results", "participants") StorageResult || Path.of("test_grid", "results", "participants") EvcsResult || Path.of("test_grid", "results", "participants") @@ -146,6 +152,7 @@ class FileNamingStrategyTest extends Specification { LoadInput || Path.of("test_grid", "input", "participants") StorageInput || Path.of("test_grid", "input", "participants") HpInput || Path.of("test_grid", "input", "participants") + AcInput || Path.of("test_grid", "input", "participants") LineInput || Path.of("test_grid", "input", "grid") SwitchInput || Path.of("test_grid", "input", "grid") NodeInput || Path.of("test_grid", "input", "grid") @@ -250,6 +257,7 @@ class FileNamingStrategyTest extends Specification { PvResult || Path.of("test_grid", "results", "participants", "pv_res") ChpResult || Path.of("test_grid", "results", "participants", "chp_res") HpResult || Path.of("test_grid", "results", "participants", "hp_res") + AcResult || Path.of("test_grid", "results", "participants", "ac_res") WecResult || Path.of("test_grid", "results", "participants", "wec_res") StorageResult || Path.of("test_grid", "results", "participants", "storage_res") EvcsResult || Path.of("test_grid", "results", "participants", "evcs_res") @@ -310,6 +318,7 @@ class FileNamingStrategyTest extends Specification { LoadInput || Path.of("test_grid", "input", "participants", "load_input") StorageInput || Path.of("test_grid", "input", "participants", "storage_input") HpInput || Path.of("test_grid", "input", "participants", "hp_input") + AcInput || Path.of("test_grid", "input", "participants", "ac_input") EvcsInput || Path.of("test_grid", "input", "participants", "evcs_input") } @@ -510,6 +519,7 @@ class FileNamingStrategyTest extends Specification { LoadInput || Optional.empty() StorageInput || Optional.empty() HpInput || Optional.empty() + AcInput || Optional.empty() LineInput || Optional.empty() SwitchInput || Optional.empty() NodeInput || Optional.empty() @@ -617,6 +627,7 @@ class FileNamingStrategyTest extends Specification { PvResult || Path.of("pv_res") ChpResult || Path.of("chp_res") HpResult || Path.of("hp_res") + AcResult || Path.of("ac_res") WecResult || Path.of("wec_res") StorageResult || Path.of("storage_res") EvcsResult || Path.of("evcs_res") @@ -655,6 +666,7 @@ class FileNamingStrategyTest extends Specification { LoadInput || Path.of("load_input") StorageInput || Path.of("storage_input") HpInput || Path.of("hp_input") + AcInput || Path.of("ac_input") LineInput || Path.of("line_input") SwitchInput || Path.of("switch_input") NodeInput || Path.of("node_input") diff --git a/src/test/groovy/edu/ie3/datamodel/io/processor/ProcessorProviderTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/processor/ProcessorProviderTest.groovy index fde342dee..5a776218d 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/processor/ProcessorProviderTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/processor/ProcessorProviderTest.groovy @@ -76,8 +76,9 @@ class ProcessorProviderTest extends Specification implements TimeSeriesTestData MeasurementUnitInput, ThermalBusInput, /* -- SystemParticipantInput */ - ChpInput, + AcInput, BmInput, + ChpInput, EvInput, EvcsInput, FixedFeedInInput, @@ -98,6 +99,7 @@ class ProcessorProviderTest extends Specification implements TimeSeriesTestData BmTypeInput, ChpTypeInput, EvTypeInput, + AcTypeInput, HpTypeInput, LineTypeInput, Transformer2WTypeInput, @@ -107,6 +109,7 @@ class ProcessorProviderTest extends Specification implements TimeSeriesTestData /* ResultEntity */ FixedFeedInResult, HpResult, + AcResult, BmResult, PvResult, ChpResult, diff --git a/src/test/groovy/edu/ie3/datamodel/io/processor/input/InputEntityProcessorTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/processor/input/InputEntityProcessorTest.groovy index e22ff1a99..61878144c 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/processor/input/InputEntityProcessorTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/processor/input/InputEntityProcessorTest.groovy @@ -152,6 +152,18 @@ class InputEntityProcessorTest extends Specification { where: modelClass | modelInstance || expectedResult + AcInput | SystemParticipantTestData.acInput || [ + "uuid" : SystemParticipantTestData.acInput.uuid.toString(), + "id" : SystemParticipantTestData.acInput.id, + "node" : SystemParticipantTestData.acInput.node.uuid.toString(), + "operatesUntil" : SystemParticipantTestData.acInput.operationTime.endDate.orElse(ZonedDateTime.now()).toString(), + "operatesFrom" : SystemParticipantTestData.acInput.operationTime.startDate.orElse(ZonedDateTime.now()).toString(), + "operator" : SystemParticipantTestData.acInput.operator.uuid.toString(), + "qCharacteristics": SystemParticipantTestData.cosPhiFixedSerialized, + "thermalBus" : SystemParticipantTestData.acInput.thermalBus.uuid.toString(), + "type" : SystemParticipantTestData.acInput.type.uuid.toString(), + "controllingEm" : SystemParticipantTestData.acInput.controllingEm.map((UniqueEntity::getUuid).andThen(UUID::toString)).orElse("") + ] FixedFeedInInput | SystemParticipantTestData.fixedFeedInInput || [ "uuid" : SystemParticipantTestData.fixedFeedInInput.uuid.toString(), "cosPhiRated" : SystemParticipantTestData.fixedFeedInInput.cosPhiRated.toString(), @@ -234,7 +246,6 @@ class InputEntityProcessorTest extends Specification { "type" : SystemParticipantTestData.evInput.type.getUuid().toString(), "controllingEm" : SystemParticipantTestData.evInput.controllingEm.map((UniqueEntity::getUuid).andThen(UUID::toString)).orElse("") ] - LoadInput | SystemParticipantTestData.loadInput || [ "uuid" : SystemParticipantTestData.loadInput.uuid.toString(), "cosPhiRated" : SystemParticipantTestData.loadInput.cosPhiRated.toString(), diff --git a/src/test/groovy/edu/ie3/datamodel/io/processor/result/ResultEntityProcessorTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/processor/result/ResultEntityProcessorTest.groovy index 7a8dbf297..206c2474a 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/processor/result/ResultEntityProcessorTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/processor/result/ResultEntityProcessorTest.groovy @@ -89,6 +89,7 @@ class ResultEntityProcessorTest extends Specification { WecResult | new WecResult(ZonedDateTime.parse("2020-01-30T17:26:44Z"), inputModel, p, q) || expectedStandardResults StorageResult | new StorageResult(ZonedDateTime.parse("2020-01-30T17:26:44Z"), inputModel, p, q, soc) || expectedSocResults HpResult | new HpResult(ZonedDateTime.parse("2020-01-30T17:26:44Z"), inputModel, p, q, qDot) || expectedQDotResults + AcResult | new AcResult(ZonedDateTime.parse("2020-01-30T17:26:44Z"), inputModel, p, q, qDot) || expectedQDotResults EmResult | new EmResult(ZonedDateTime.parse("2020-01-30T17:26:44Z"), inputModel, p, q) || expectedStandardResults } @@ -327,7 +328,7 @@ class ResultEntityProcessorTest extends Specification { def "The list of eligible entity classes for a ResultEntityProcessor should be valid"() { given: - int noOfElements = 21 // number of all currently implemented entity results + int noOfElements = 22 // number of all currently implemented entity results expect: ResultEntityProcessor.eligibleEntityClasses.size() == noOfElements diff --git a/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvResultEntitySourceTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvResultEntitySourceTest.groovy index c8c74c4ad..8607bc7b0 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvResultEntitySourceTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvResultEntitySourceTest.groovy @@ -25,6 +25,7 @@ class CsvResultEntitySourceTest extends Specification implements CsvTestDataMeta // non-existent (empty) def chpResults = csvResultEntitySource.chpResults def hpResults = csvResultEntitySource.hpResults + def acResults = csvResultEntitySource.acResults def evResults = csvResultEntitySource.evResults def evcsResults = csvResultEntitySource.evcsResults def loadResults = csvResultEntitySource.loadResults @@ -38,7 +39,7 @@ class CsvResultEntitySourceTest extends Specification implements CsvTestDataMeta bmResults.size() == retd.BM_RESULT_SIZE fixedFeedInResults.size() == retd.FIXED_FEED_IN_RESULT_SIZE emResults.size() == retd.EM_RESULT_SIZE - chpResults.empty && hpResults.empty && evResults.empty && evcsResults.empty && + chpResults.empty && hpResults.empty && acResults.empty && evResults.empty && evcsResults.empty && loadResults.empty && storageResults.empty && thermalHouseResults.empty && flexOptionsResults.empty bmResults.first().inputModel == retd.BM_INPUT_MODEL diff --git a/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvSystemParticipantSourceTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvSystemParticipantSourceTest.groovy index 293ae514b..edb8fafbc 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvSystemParticipantSourceTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvSystemParticipantSourceTest.groovy @@ -33,13 +33,14 @@ class CsvSystemParticipantSourceTest extends Specification implements CsvTestDat def systemParticipants = csvSystemParticipantSource.systemParticipants then: - systemParticipants.allEntitiesAsList().size() == 10 + systemParticipants.allEntitiesAsList().size() == 11 systemParticipants.pvPlants.first().uuid == sptd.pvInput.uuid systemParticipants.bmPlants.first().uuid == sptd.bmInput.uuid systemParticipants.chpPlants.first().uuid == sptd.chpInput.uuid systemParticipants.evs.first().uuid == sptd.evInput.uuid systemParticipants.fixedFeedIns.first().uuid == sptd.fixedFeedInInput.uuid systemParticipants.heatPumps.first().uuid == sptd.hpInput.uuid + systemParticipants.airConditions.first().uuid == sptd.acInput.uuid systemParticipants.loads.first().uuid == sptd.loadInput.uuid systemParticipants.wecPlants.first().uuid == sptd.wecInput.uuid systemParticipants.storages.first().uuid == sptd.storageInput.uuid @@ -76,7 +77,7 @@ class CsvSystemParticipantSourceTest extends Specification implements CsvTestDat Exception ex = systemParticipants.exception.get() ex.class == SystemParticipantsException - ex.message == "Exception(s) occurred in 10 input file(s) while initializing system participants.\n" + + ex.message == "Exception(s) occurred in 11 input file(s) while initializing system participants.\n" + " 1 exception(s) occurred within \"FixedFeedInInput\" data: \n" + " Extracting UUID for field 'node' failed. Caused by: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided.\n" + " 1 exception(s) occurred within \"PvInput\" data: \n" + @@ -96,6 +97,8 @@ class CsvSystemParticipantSourceTest extends Specification implements CsvTestDat " 1 exception(s) occurred within \"ChpInput\" data: \n" + " Extracting UUID for field 'node' failed. Caused by: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided.\n" + " 1 exception(s) occurred within \"HpInput\" data: \n" + + " Extracting UUID for field 'node' failed. Caused by: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided.\n" + + " 1 exception(s) occurred within \"AcInput\" data: \n" + " Extracting UUID for field 'node' failed. Caused by: Entity with uuid 4ca90220-74c2-4369-9afa-a18bf068840d was not provided." } @@ -118,6 +121,10 @@ class CsvSystemParticipantSourceTest extends Specification implements CsvTestDat heatPumps.success heatPumps.data.get() == [sptd.hpInput] as Set + def airConditions = Try.of(() -> csvSystemParticipantSource.getAirConditions(operatorMap, nodeMap, emUnitsMap, map([sptd.acTypeInput]), thermalBusMap), SourceException) + airConditions.success + airConditions.data.get() == [sptd.acInput] as Set + def chpUnits = Try.of(() -> csvSystemParticipantSource.getChpPlants(operatorMap, nodeMap, emUnitsMap, map([sptd.chpTypeInput]), thermalBusMap, thermalStorageMap), SourceException) chpUnits.success chpUnits.data.get() == [sptd.chpInput] as Set @@ -179,6 +186,30 @@ class CsvSystemParticipantSourceTest extends Specification implements CsvTestDat [sptd.hpInput.operator] | [sptd.hpInput.type] | [] } + def "A SystemParticipantSource with csv input should throw an exception from an invalid air condition input file as expected"() { + given: + def csvSystemParticipantSource = new SystemParticipantSource( + Mock(TypeSource), + Mock(ThermalSource), + Mock(RawGridSource), + Mock(EnergyManagementSource), + new CsvDataSource(csvSep, participantsFolderPath, fileNamingStrategy)) + def nodeMap = map([sptd.participantNode]) + def emUnitsMap = map([sptd.emInput]) + + expect: + def airConditions = Try.of(() -> csvSystemParticipantSource.getHeatPumps(map(operators), nodeMap, emUnitsMap, map(types), map(thermalBuses)), SourceException) + + airConditions.failure + airConditions.exception.get().class == SourceException + + where: + operators | types | thermalBuses + [] | [] | [] + [sptd.acInput.operator] | [] | [] + [sptd.acInput.operator] | [sptd.acInput.type] | [] + } + def "A SystemParticipantSource with csv input should throw an exception from a invalid chp input file as expected"() { given: def csvSystemParticipantSource = new SystemParticipantSource( diff --git a/src/test/groovy/edu/ie3/datamodel/models/input/container/SystemParticipantsTest.groovy b/src/test/groovy/edu/ie3/datamodel/models/input/container/SystemParticipantsTest.groovy index e75cf6526..b9f32a0e8 100644 --- a/src/test/groovy/edu/ie3/datamodel/models/input/container/SystemParticipantsTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/models/input/container/SystemParticipantsTest.groovy @@ -19,6 +19,7 @@ class SystemParticipantsTest extends Specification { Collections.singleton(SystemParticipantTestData.evInput), Collections.singleton(SystemParticipantTestData.fixedFeedInInput), Collections.singleton(SystemParticipantTestData.hpInput), + Collections.singleton(SystemParticipantTestData.acInput), Collections.singleton(SystemParticipantTestData.loadInput), Collections.singleton(SystemParticipantTestData.pvInput), Collections.singleton(SystemParticipantTestData.storageInput), @@ -41,6 +42,7 @@ class SystemParticipantsTest extends Specification { Collections.singleton(SystemParticipantTestData.evInput), Collections.singleton(SystemParticipantTestData.fixedFeedInInput), Collections.singleton(SystemParticipantTestData.hpInput), + Collections.singleton(SystemParticipantTestData.acInput), Collections.singleton(SystemParticipantTestData.loadInput), Collections.singleton(SystemParticipantTestData.pvInput), Collections.singleton(SystemParticipantTestData.storageInput), @@ -53,6 +55,7 @@ class SystemParticipantsTest extends Specification { def modifiedEvInput = SystemParticipantTestData.evInput.copy().id("modified").build() def modifiedFixedFeedInInput = SystemParticipantTestData.fixedFeedInInput.copy().id("modified").build() def modifiedHpInput = SystemParticipantTestData.hpInput.copy().id("modified").build() + def modifiedAcInput = SystemParticipantTestData.acInput.copy().id("modified").build() def modifiedLoadInput = SystemParticipantTestData.loadInput.copy().id("modified").build() def modifiedPvInput = SystemParticipantTestData.pvInput.copy().id("modified").build() def modifiedStorageInput = SystemParticipantTestData.storageInput.copy().id("modified").build() @@ -66,6 +69,7 @@ class SystemParticipantsTest extends Specification { .evs(Set.of(modifiedEvInput)) .fixedFeedIn(Set.of(modifiedFixedFeedInInput)) .heatPumps(Set.of(modifiedHpInput)) + .airConditions(Set.of(modifiedAcInput)) .loads(Set.of(modifiedLoadInput)) .pvPlants(Set.of(modifiedPvInput)) .storages(Set.of(modifiedStorageInput)) @@ -79,6 +83,7 @@ class SystemParticipantsTest extends Specification { modifiedSystemParticipants.evs.first() == modifiedEvInput modifiedSystemParticipants.fixedFeedIns.first() == modifiedFixedFeedInInput modifiedSystemParticipants.heatPumps.first() == modifiedHpInput + modifiedSystemParticipants.airConditions.first() == modifiedAcInput modifiedSystemParticipants.loads.first() == modifiedLoadInput modifiedSystemParticipants.pvPlants.first() == modifiedPvInput modifiedSystemParticipants.storages.first() == modifiedStorageInput diff --git a/src/test/groovy/edu/ie3/datamodel/models/input/system/AcInputTest.groovy b/src/test/groovy/edu/ie3/datamodel/models/input/system/AcInputTest.groovy new file mode 100644 index 000000000..4072f5b86 --- /dev/null +++ b/src/test/groovy/edu/ie3/datamodel/models/input/system/AcInputTest.groovy @@ -0,0 +1,55 @@ +/* + * © 2021. 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.test.common.SystemParticipantTestData +import spock.lang.Specification + + +class AcInputTest extends Specification { + + def "A AcInput copy method should work as expected"() { + given: + def acInput = SystemParticipantTestData.acInput + + when: + def alteredUnit = acInput.copy().thermalBus(SystemParticipantTestData.thermalBus) + .type(SystemParticipantTestData.acTypeInput).build() + + then: + alteredUnit.with { + assert uuid == acInput.uuid + assert operationTime == acInput.operationTime + assert operator == acInput.operator + assert id == acInput.id + assert qCharacteristics == acInput.qCharacteristics + assert thermalBus == SystemParticipantTestData.thermalBus + assert type == SystemParticipantTestData.acTypeInput + assert controllingEm == Optional.of(SystemParticipantTestData.emInput) + } + } + + def "Scaling a AcInput via builder should work as expected"() { + given: + def acInput = SystemParticipantTestData.acInput + + when: + def alteredUnit = acInput.copy().scale(2d).build() + + then: + alteredUnit.with { + assert uuid == acInput.uuid + assert operationTime == acInput.operationTime + assert operator == acInput.operator + assert id == acInput.id + assert qCharacteristics == acInput.qCharacteristics + assert thermalBus == acInput.thermalBus + assert type.sRated == acInput.type.sRated * 2d + assert type.pThermal == acInput.type.pThermal * 2d + assert controllingEm == Optional.of(SystemParticipantTestData.emInput) + } + } +} diff --git a/src/test/groovy/edu/ie3/datamodel/utils/validation/SystemParticipantValidationUtilsTest.groovy b/src/test/groovy/edu/ie3/datamodel/utils/validation/SystemParticipantValidationUtilsTest.groovy index ffd5a19f9..2e51bdf04 100644 --- a/src/test/groovy/edu/ie3/datamodel/utils/validation/SystemParticipantValidationUtilsTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/utils/validation/SystemParticipantValidationUtilsTest.groovy @@ -77,7 +77,7 @@ class SystemParticipantValidationUtilsTest extends Specification { // Specific data for bm type private static final ComparableQuantity activePowerGradient = Quantities.getQuantity(25, ACTIVE_POWER_GRADIENT) - // Specific data for CHP type (and HP type) + // Specific data for CHP type (and HP type and AC type) private static final ComparableQuantity etaEl = Quantities.getQuantity(19, EFFICIENCY) private static final ComparableQuantity etaThermal = Quantities.getQuantity(76, EFFICIENCY) private static final ComparableQuantity pOwn = Quantities.getQuantity(0, ACTIVE_POWER_IN) @@ -295,11 +295,52 @@ class SystemParticipantValidationUtilsTest extends Specification { ex.message.contains(expectedException.message) where: - invalidHpType || expectedException - new HpTypeInput(uuid, id, capex, opex, Quantities.getQuantity(0, S_RATED), cosPhiRated, pThermal) || new InvalidEntityException("The following quantities have to be positive: 0 kVA", invalidHpType) - new HpTypeInput(uuid, id, capex, opex, sRated, cosPhiRated, Quantities.getQuantity(0, ACTIVE_POWER_IN)) || new InvalidEntityException("The following quantities have to be positive: 0 kW", invalidHpType) + invalidHpType || expectedException + new HpTypeInput(uuid, id, capex, opex, Quantities.getQuantity(0, S_RATED), cosPhiRated, pThermal) || new InvalidEntityException("The following quantities have to be positive: 0 kVA", invalidHpType) + new HpTypeInput(uuid, id, capex, opex, sRated, cosPhiRated, Quantities.getQuantity(0, ACTIVE_POWER_IN)) || new InvalidEntityException("The following quantities have to be positive: 0 kW", invalidHpType) } + // AC + + def "Smoke Test: Correct AC throws no exception"() { + given: + def acInput = SystemParticipantTestData.acInput + + when: + ValidationUtils.check(acInput) + + then: + noExceptionThrown() + } + + // No tests for "SystemParticipantValidationUtils.checkAc() recognizes all potential errors for an AC" + + def "Smoke Test: Correct AC type throws no exception"() { + given: + def acType = SystemParticipantTestData.acTypeInput + + when: + ValidationUtils.check(acType) + + then: + noExceptionThrown() + } + + def "SystemParticipantValidationUtils.checkAcType() recognizes all potential errors for an AC type"() { + when: + SystemParticipantValidationUtils.check(invalidAcType) + + then: + Throwable ex = thrown() + ex.message.contains(expectedException.message) + + where: + invalidAcType || expectedException + new AcTypeInput(uuid, id, capex, opex, Quantities.getQuantity(0, S_RATED), cosPhiRated, pThermal) || new InvalidEntityException("The following quantities have to be positive: 0 kVA", invalidAcType) + new AcTypeInput(uuid, id, capex, opex, sRated, cosPhiRated, Quantities.getQuantity(0, ACTIVE_POWER_IN)) || new InvalidEntityException("The following quantities have to be positive: 0 kW", invalidAcType) + } + + // Load def "Smoke Test: Correct load throws no exception"() { diff --git a/src/test/groovy/edu/ie3/test/common/SampleJointGrid.groovy b/src/test/groovy/edu/ie3/test/common/SampleJointGrid.groovy index f3d87989d..1b7273e37 100644 --- a/src/test/groovy/edu/ie3/test/common/SampleJointGrid.groovy +++ b/src/test/groovy/edu/ie3/test/common/SampleJointGrid.groovy @@ -129,6 +129,7 @@ class SampleJointGrid extends SystemParticipantTestData { Collections.emptySet(), Collections.emptySet(), Collections.emptySet(), + Collections.emptySet(), Set.of(loadInput, loadInput1), Collections.singleton(pvInput), Collections.singleton(storageInput), diff --git a/src/test/groovy/edu/ie3/test/common/SystemParticipantTestData.groovy b/src/test/groovy/edu/ie3/test/common/SystemParticipantTestData.groovy index 7611b78bc..79f72f086 100644 --- a/src/test/groovy/edu/ie3/test/common/SystemParticipantTestData.groovy +++ b/src/test/groovy/edu/ie3/test/common/SystemParticipantTestData.groovy @@ -323,6 +323,28 @@ class SystemParticipantTestData { hpTypeInput ) + public static final AcTypeInput acTypeInput = new AcTypeInput( + typeUuid, + "test_acTypeInput", + capex, + opex, + sRated, + cosPhiRated, + pThermal + ) + + public static final AcInput acInput = new AcInput( + UUID.fromString("42e538e7-f29d-48ad-b376-277f24200ae0"), + "test_acInput", + operator, + operationTime, + participantNode, + thermalBus, + cosPhiFixed, + emInput, + acTypeInput + ) + // charging station public static final boolean v2gSupport = false public static final evcsInput = new EvcsInput( @@ -351,5 +373,6 @@ class SystemParticipantTestData { [] as Set, [] as Set, [] as Set, + [] as Set, [] as Set) } diff --git a/src/test/resources/edu/ie3/datamodel/io/source/csv/_participants/ac_input.csv b/src/test/resources/edu/ie3/datamodel/io/source/csv/_participants/ac_input.csv new file mode 100644 index 000000000..9d3f88c35 --- /dev/null +++ b/src/test/resources/edu/ie3/datamodel/io/source/csv/_participants/ac_input.csv @@ -0,0 +1,2 @@ +uuid,id,node,operates_from,operates_until,operator,q_characteristics,thermal_bus,type,controlling_em +42e538e7-f29d-48ad-b376-277f24200ae0,test_acInput,4ca90220-74c2-4369-9afa-a18bf068840d,2020-03-24T15:11:31Z,2020-03-25T15:11:31Z,8f9682df-0744-4b58-a122-f0dc730f6510,"cosPhiFixed:{(0.00,0.95)}",0d95d7f2-49fb-4d49-8636-383a5220384e,5ebd8f7e-dedb-4017-bb86-6373c4b68eb8,977157f4-25e5-4c72-bf34-440edc778792 \ No newline at end of file diff --git a/src/test/resources/edu/ie3/datamodel/io/source/csv/_results/ac_res.csv b/src/test/resources/edu/ie3/datamodel/io/source/csv/_results/ac_res.csv new file mode 100644 index 000000000..15888891b --- /dev/null +++ b/src/test/resources/edu/ie3/datamodel/io/source/csv/_results/ac_res.csv @@ -0,0 +1 @@ +inputModel,p,q,qDot,time \ No newline at end of file diff --git a/src/test/resources/edu/ie3/datamodel/io/source/csv/_types/ac_type_input.csv b/src/test/resources/edu/ie3/datamodel/io/source/csv/_types/ac_type_input.csv new file mode 100644 index 000000000..91f0a2745 --- /dev/null +++ b/src/test/resources/edu/ie3/datamodel/io/source/csv/_types/ac_type_input.csv @@ -0,0 +1,2 @@ +uuid,capex,cos_phi_rated,id,opex,p_thermal,s_rated +5ebd8f7e-dedb-4017-bb86-6373c4b68eb8,100.0,0.95,test_acTypeInput,50.0,9.0,25.0 \ No newline at end of file