From 956d81a785b919f5b5237201c2b53b1fbfd08e6e Mon Sep 17 00:00:00 2001 From: staudtMarius Date: Tue, 6 Aug 2024 10:54:25 +0200 Subject: [PATCH 1/6] Adding a timeseries for voltage values. --- CHANGELOG.md | 1 + .../exceptions/EntityProcessorException.java | 2 +- .../TimeBasedSimpleValueFactory.java | 20 ++++- .../timeseries/TimeSeriesMappingFactory.java | 16 +++- .../io/naming/timeseries/ColumnScheme.java | 4 +- .../io/processor/EntityProcessor.java | 2 +- .../io/source/TimeSeriesMappingSource.java | 65 +++++++++++--- .../datamodel/models/value/VoltageValue.java | 89 +++++++++++++++++++ .../ie3/datamodel/utils/TimeSeriesUtils.java | 3 +- .../validation/UniquenessValidationUtils.java | 2 +- .../input/InputEntityProcessorTest.groovy | 4 +- .../csv/CsvTimeSeriesMappingSourceIT.groovy | 3 +- ...svTimeSeriesMetaInformationSourceIT.groovy | 6 +- .../source/csv/CsvTimeSeriesSourceTest.groovy | 1 + .../models/value/VoltageValueTest.groovy | 46 ++++++++++ .../UniquenessValidationUtilsTest.groovy | 50 +++++++---- ...v_eeccbe3c-a47e-448e-8eca-1f369d3c24e6.csv | 3 + .../csv/_timeseries/time_series_mapping.csv | 9 +- 18 files changed, 278 insertions(+), 48 deletions(-) create mode 100644 src/main/java/edu/ie3/datamodel/models/value/VoltageValue.java create mode 100644 src/test/groovy/edu/ie3/datamodel/models/value/VoltageValueTest.groovy create mode 100644 src/test/resources/edu/ie3/datamodel/io/source/csv/_timeseries/its_v_eeccbe3c-a47e-448e-8eca-1f369d3c24e6.csv diff --git a/CHANGELOG.md b/CHANGELOG.md index 083590698..25209bb22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased/Snapshot] ### Added +- Adding timeseries for voltage values [#1128](https://github.com/ie3-institute/PowerSystemDataModel/issues/1128) ### Fixed diff --git a/src/main/java/edu/ie3/datamodel/exceptions/EntityProcessorException.java b/src/main/java/edu/ie3/datamodel/exceptions/EntityProcessorException.java index 37736b231..749b190d8 100644 --- a/src/main/java/edu/ie3/datamodel/exceptions/EntityProcessorException.java +++ b/src/main/java/edu/ie3/datamodel/exceptions/EntityProcessorException.java @@ -6,7 +6,7 @@ package edu.ie3.datamodel.exceptions; /** - * Is thrown, when an something went wrong during entity field mapping creation in a {@link + * Is thrown, when something went wrong during entity field mapping creation in a {@link * edu.ie3.datamodel.io.processor.EntityProcessor} */ public class EntityProcessorException extends Exception { diff --git a/src/main/java/edu/ie3/datamodel/io/factory/timeseries/TimeBasedSimpleValueFactory.java b/src/main/java/edu/ie3/datamodel/io/factory/timeseries/TimeBasedSimpleValueFactory.java index ecbc89dd5..839df2705 100644 --- a/src/main/java/edu/ie3/datamodel/io/factory/timeseries/TimeBasedSimpleValueFactory.java +++ b/src/main/java/edu/ie3/datamodel/io/factory/timeseries/TimeBasedSimpleValueFactory.java @@ -14,7 +14,10 @@ import edu.ie3.util.TimeUtil; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; -import java.util.*; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Set; public class TimeBasedSimpleValueFactory extends TimeBasedValueFactory, V> { @@ -26,6 +29,10 @@ public class TimeBasedSimpleValueFactory private static final String REACTIVE_POWER = "q"; private static final String HEAT_DEMAND = "heatDemand"; + /* voltage */ + private static final String VMAG = "vMag"; + private static final String VANG = "VAng"; + private final TimeUtil timeUtil; public TimeBasedSimpleValueFactory(Class valueClasses) { @@ -78,6 +85,17 @@ protected TimeBasedValue buildModel(SimpleTimeBasedValueData data) { data.getQuantity(REACTIVE_POWER, REACTIVE_POWER_IN)); } else if (PValue.class.isAssignableFrom(data.getTargetClass())) { value = (V) new PValue(data.getQuantity(ACTIVE_POWER, ACTIVE_POWER_IN)); + } else if (VoltageValue.class.isAssignableFrom(data.getTargetClass())) { + + try { + value = + (V) + new VoltageValue( + data.getQuantity(VMAG, VOLTAGE_MAGNITUDE), + data.getQuantity(VANG, VOLTAGE_ANGLE)); + } catch (FactoryException e) { + value = (V) new VoltageValue(data.getQuantity(VMAG, VOLTAGE_MAGNITUDE)); + } } else { throw new FactoryException( "The given factory cannot handle target class '" + data.getTargetClass() + "'."); diff --git a/src/main/java/edu/ie3/datamodel/io/factory/timeseries/TimeSeriesMappingFactory.java b/src/main/java/edu/ie3/datamodel/io/factory/timeseries/TimeSeriesMappingFactory.java index 2009435cc..3ef9d60c1 100644 --- a/src/main/java/edu/ie3/datamodel/io/factory/timeseries/TimeSeriesMappingFactory.java +++ b/src/main/java/edu/ie3/datamodel/io/factory/timeseries/TimeSeriesMappingFactory.java @@ -5,10 +5,10 @@ */ package edu.ie3.datamodel.io.factory.timeseries; +import edu.ie3.datamodel.exceptions.FactoryException; import edu.ie3.datamodel.io.factory.EntityData; import edu.ie3.datamodel.io.factory.EntityFactory; import edu.ie3.datamodel.io.source.TimeSeriesMappingSource; -import java.util.Collections; import java.util.List; import java.util.Set; import java.util.UUID; @@ -17,6 +17,7 @@ public class TimeSeriesMappingFactory extends EntityFactory { + private static final String ENTITY = "entity"; private static final String PARTICIPANT = "participant"; private static final String TIME_SERIES = "timeSeries"; @@ -26,14 +27,21 @@ public TimeSeriesMappingFactory() { @Override protected List> getFields(Class entityClass) { - return Collections.singletonList( + return List.of( + Stream.of(ENTITY, TIME_SERIES).collect(Collectors.toSet()), Stream.of(PARTICIPANT, TIME_SERIES).collect(Collectors.toSet())); } @Override protected TimeSeriesMappingSource.MappingEntry buildModel(EntityData data) { - UUID participant = data.getUUID(PARTICIPANT); UUID timeSeries = data.getUUID(TIME_SERIES); - return new TimeSeriesMappingSource.MappingEntry(participant, timeSeries); + + try { + UUID entity = data.getUUID(ENTITY); + return new TimeSeriesMappingSource.EntityMappingEntry(entity, timeSeries); + } catch (FactoryException e) { + UUID participant = data.getUUID(PARTICIPANT); + return new TimeSeriesMappingSource.ParticipantMappingEntry(participant, timeSeries); + } } } diff --git a/src/main/java/edu/ie3/datamodel/io/naming/timeseries/ColumnScheme.java b/src/main/java/edu/ie3/datamodel/io/naming/timeseries/ColumnScheme.java index 44359e34b..6ea64b458 100644 --- a/src/main/java/edu/ie3/datamodel/io/naming/timeseries/ColumnScheme.java +++ b/src/main/java/edu/ie3/datamodel/io/naming/timeseries/ColumnScheme.java @@ -19,7 +19,8 @@ public enum ColumnScheme { HEAT_DEMAND("h", HeatDemandValue.class), ACTIVE_POWER_AND_HEAT_DEMAND("ph", HeatAndPValue.class), APPARENT_POWER_AND_HEAT_DEMAND("pqh", HeatAndSValue.class), - WEATHER("weather", WeatherValue.class); + WEATHER("weather", WeatherValue.class), + VOLTAGE("v", VoltageValue.class); private final String scheme; private final Class valueClass; @@ -57,6 +58,7 @@ public static Optional parse(Class valueClass if (PValue.class.isAssignableFrom(valueClass)) return Optional.of(ACTIVE_POWER); if (HeatDemandValue.class.isAssignableFrom(valueClass)) return Optional.of(HEAT_DEMAND); if (WeatherValue.class.isAssignableFrom(valueClass)) return Optional.of(WEATHER); + if (VoltageValue.class.isAssignableFrom(valueClass)) return Optional.of(VOLTAGE); return Optional.empty(); } } 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 d756c00cf..ac7380793 100644 --- a/src/main/java/edu/ie3/datamodel/io/processor/EntityProcessor.java +++ b/src/main/java/edu/ie3/datamodel/io/processor/EntityProcessor.java @@ -55,7 +55,7 @@ protected EntityProcessor(Class registeredClass) throws EntityProce * during processing */ public LinkedHashMap handleEntity(T entity) throws EntityProcessorException { - if (!registeredClass.equals(entity.getClass())) + if (!registeredClass.isAssignableFrom(entity.getClass())) throw new EntityProcessorException( "Cannot process " + entity.getClass().getSimpleName() diff --git a/src/main/java/edu/ie3/datamodel/io/source/TimeSeriesMappingSource.java b/src/main/java/edu/ie3/datamodel/io/source/TimeSeriesMappingSource.java index 75a1802c6..81c382f9e 100644 --- a/src/main/java/edu/ie3/datamodel/io/source/TimeSeriesMappingSource.java +++ b/src/main/java/edu/ie3/datamodel/io/source/TimeSeriesMappingSource.java @@ -11,7 +11,6 @@ import edu.ie3.datamodel.io.factory.EntityData; import edu.ie3.datamodel.io.factory.timeseries.TimeSeriesMappingFactory; import edu.ie3.datamodel.models.input.InputEntity; -import edu.ie3.datamodel.models.input.system.SystemParticipantInput; import edu.ie3.datamodel.models.timeseries.TimeSeries; import edu.ie3.datamodel.utils.Try; import edu.ie3.datamodel.utils.Try.*; @@ -47,7 +46,7 @@ public Map getMapping() throws SourceException { .filter(Try::isSuccess) .map(t -> (Success) t) .map(Success::get) - .collect(Collectors.toMap(MappingEntry::participant, MappingEntry::timeSeries)); + .collect(Collectors.toMap(MappingEntry::getEntity, MappingEntry::getTimeSeries)); } /** @@ -80,12 +79,19 @@ private Try createMappingEntry( // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - /** Class to represent one entry within the participant to time series mapping */ - public record MappingEntry(UUID participant, UUID timeSeries) implements InputEntity { + /** Class to represent one entry within the entity to time series mapping */ + public abstract static class MappingEntry implements InputEntity { + protected final UUID entity; + private final UUID timeSeries; - /** Returns the {@link UUID} of the {@link SystemParticipantInput}. */ - public UUID getParticipant() { - return participant; + public MappingEntry(UUID entity, UUID timeSeries) { + this.entity = entity; + this.timeSeries = timeSeries; + } + + /** Returns the {@link UUID} of the {@link edu.ie3.datamodel.models.UniqueEntity}. */ + public UUID getEntity() { + return entity; } /** Returns the {@link UUID} of the {@link TimeSeries}. */ @@ -97,17 +103,56 @@ public UUID getTimeSeries() { public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof MappingEntry that)) return false; - return participant.equals(that.participant) && timeSeries.equals(that.timeSeries); + return entity.equals(that.entity) && timeSeries.equals(that.timeSeries); } @Override public int hashCode() { - return Objects.hash(participant, timeSeries); + return Objects.hash(entity, timeSeries); + } + + @Override + public String toString() { + return "MappingEntry{" + "entity=" + entity + ", timeSeries=" + timeSeries + '}'; + } + } + + /** Class to represent one entry within the entity to time series mapping */ + public static class EntityMappingEntry extends MappingEntry { + + public EntityMappingEntry(UUID entity, UUID timeSeries) { + super(entity, timeSeries); + } + + @Override + public String toString() { + return "EntityMappingEntry{" + "entity=" + entity + ", timeSeries=" + getTimeSeries() + '}'; + } + } + + /** Class to represent one entry within the participant to time series mapping */ + public static class ParticipantMappingEntry extends MappingEntry { + + public ParticipantMappingEntry(UUID participant, UUID timeSeries) { + super(participant, timeSeries); + } + + /** + * Returns the {@link UUID} of the {@link + * edu.ie3.datamodel.models.input.system.SystemParticipantInput}. + */ + public UUID getParticipant() { + return entity; } @Override public String toString() { - return "MappingEntry{" + "participant=" + participant + ", timeSeries=" + timeSeries + '}'; + return "ParticipantMappingEntry{" + + "participant=" + + entity + + ", timeSeries=" + + getTimeSeries() + + '}'; } } } diff --git a/src/main/java/edu/ie3/datamodel/models/value/VoltageValue.java b/src/main/java/edu/ie3/datamodel/models/value/VoltageValue.java new file mode 100644 index 000000000..3a77055e9 --- /dev/null +++ b/src/main/java/edu/ie3/datamodel/models/value/VoltageValue.java @@ -0,0 +1,89 @@ +/* + * © 2024. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation +*/ +package edu.ie3.datamodel.models.value; + +import static edu.ie3.datamodel.models.StandardUnits.VOLTAGE_ANGLE; +import static edu.ie3.util.quantities.PowerSystemUnits.DEGREE_GEOM; +import static edu.ie3.util.quantities.PowerSystemUnits.PU; +import static java.lang.Math.*; + +import java.util.Objects; +import java.util.Optional; +import javax.measure.quantity.Angle; +import javax.measure.quantity.Dimensionless; +import tech.units.indriya.ComparableQuantity; +import tech.units.indriya.quantity.Quantities; + +/** Describes a voltage value as a pair of magnitude and angle */ +public class VoltageValue implements Value { + + /** Magnitude of the voltage in p.u. */ + private final ComparableQuantity magnitude; + /** Angle of the voltage in degree */ + private final ComparableQuantity angle; + + /** + * @param magnitude of the voltage in p.u. + * @param angle of the voltage in degree + */ + public VoltageValue( + ComparableQuantity magnitude, ComparableQuantity angle) { + this.magnitude = magnitude; + this.angle = angle; + } + + /** + * This constructor will set the angle to 0° + * + * @param magnitude of the voltage in p.u. + */ + public VoltageValue(ComparableQuantity magnitude) { + this.magnitude = magnitude; + this.angle = Quantities.getQuantity(0.0, VOLTAGE_ANGLE); + } + + public Optional> getMagnitude() { + return Optional.ofNullable(magnitude); + } + + public Optional> getAngle() { + return Optional.ofNullable(angle); + } + + public Optional> getRealPart() { + double mag = magnitude.to(PU).getValue().doubleValue(); + double ang = angle.to(DEGREE_GEOM).getValue().doubleValue(); + + double eInPu = mag * cos(toRadians(ang)); + return Optional.of(Quantities.getQuantity(eInPu, PU)); + } + + public Optional> getImagPart() { + double mag = magnitude.to(PU).getValue().doubleValue(); + double ang = angle.to(DEGREE_GEOM).getValue().doubleValue(); + + double eInPu = mag * sin(toRadians(ang)); + return Optional.of(Quantities.getQuantity(eInPu, PU)); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + VoltageValue that = (VoltageValue) o; + return Objects.equals(magnitude, that.magnitude) && Objects.equals(angle, that.angle); + } + + @Override + public int hashCode() { + return Objects.hash(magnitude, angle); + } + + @Override + public String toString() { + return "VoltageValue{" + "magnitude=" + magnitude + ", angle=" + angle + '}'; + } +} diff --git a/src/main/java/edu/ie3/datamodel/utils/TimeSeriesUtils.java b/src/main/java/edu/ie3/datamodel/utils/TimeSeriesUtils.java index d6ce28049..16fdcb24f 100644 --- a/src/main/java/edu/ie3/datamodel/utils/TimeSeriesUtils.java +++ b/src/main/java/edu/ie3/datamodel/utils/TimeSeriesUtils.java @@ -25,7 +25,8 @@ public class TimeSeriesUtils { ENERGY_PRICE, APPARENT_POWER_AND_HEAT_DEMAND, ACTIVE_POWER_AND_HEAT_DEMAND, - HEAT_DEMAND); + HEAT_DEMAND, + VOLTAGE); /** Private Constructor as this class is not meant to be instantiated */ private TimeSeriesUtils() { diff --git a/src/main/java/edu/ie3/datamodel/utils/validation/UniquenessValidationUtils.java b/src/main/java/edu/ie3/datamodel/utils/validation/UniquenessValidationUtils.java index 86be3c060..a1576dfaa 100644 --- a/src/main/java/edu/ie3/datamodel/utils/validation/UniquenessValidationUtils.java +++ b/src/main/java/edu/ie3/datamodel/utils/validation/UniquenessValidationUtils.java @@ -33,7 +33,7 @@ public class UniquenessValidationUtils extends ValidationUtils { protected static final FieldSetSupplier congestionResultFieldSupplier = entity -> Set.of(entity.getTime(), entity.getSubgrid()); protected static final FieldSetSupplier mappingFieldSupplier = - entity -> Set.of(entity.participant()); + entity -> Set.of(entity.getEntity()); protected static final FieldSetSupplier idCoordinateSupplier = entity -> Set.of(entity.id(), entity.point()); protected static final FieldSetSupplier> weatherValueFieldSupplier = 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 24b1a8198..b0fd79168 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 @@ -627,10 +627,10 @@ class InputEntityProcessorTest extends Specification { def "The InputEntityProcessor should serialize a provided MappingEntry correctly"() { given: def processor = new InputEntityProcessor(TimeSeriesMappingSource.MappingEntry) - def validResult = new TimeSeriesMappingSource.MappingEntry(UUID.fromString("7eb7b296-f4c4-4020-acf3-e865453b5dbd"), UUID.fromString("bc581c6c-3044-48a1-aea1-5b2cb1370356")) + def validResult = new TimeSeriesMappingSource.ParticipantMappingEntry(UUID.fromString("7eb7b296-f4c4-4020-acf3-e865453b5dbd"), UUID.fromString("bc581c6c-3044-48a1-aea1-5b2cb1370356")) Map expectedResults = [ - "participant": "7eb7b296-f4c4-4020-acf3-e865453b5dbd", + "entity": "7eb7b296-f4c4-4020-acf3-e865453b5dbd", "timeSeries": "bc581c6c-3044-48a1-aea1-5b2cb1370356" ] diff --git a/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesMappingSourceIT.groovy b/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesMappingSourceIT.groovy index 91ff12295..2abcc918c 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesMappingSourceIT.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesMappingSourceIT.groovy @@ -23,7 +23,8 @@ class CsvTimeSeriesMappingSourceIT extends Specification implements CsvTestDataM def expectedMapping = [ (UUID.fromString("b86e95b0-e579-4a80-a534-37c7a470a409")) : UUID.fromString("9185b8c1-86ba-4a16-8dea-5ac898e8caa5"), (UUID.fromString("c7ebcc6c-55fc-479b-aa6b-6fa82ccac6b8")) : UUID.fromString("3fbfaa97-cff4-46d4-95ba-a95665e87c26"), - (UUID.fromString("90a96daa-012b-4fea-82dc-24ba7a7ab81c")) : UUID.fromString("3fbfaa97-cff4-46d4-95ba-a95665e87c26") + (UUID.fromString("90a96daa-012b-4fea-82dc-24ba7a7ab81c")) : UUID.fromString("3fbfaa97-cff4-46d4-95ba-a95665e87c26"), + (UUID.fromString("7bed7760-c220-4fe6-88b3-47b246f6ef3f")) : UUID.fromString("eeccbe3c-a47e-448e-8eca-1f369d3c24e6") ] when: diff --git a/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesMetaInformationSourceIT.groovy b/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesMetaInformationSourceIT.groovy index 2fa70a2f6..6623e76ca 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesMetaInformationSourceIT.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesMetaInformationSourceIT.groovy @@ -30,14 +30,15 @@ class CsvTimeSeriesMetaInformationSourceIT extends Specification implements CsvT new CsvIndividualTimeSeriesMetaInformation(UUID.fromString("9185b8c1-86ba-4a16-8dea-5ac898e8caa5"), ColumnScheme.ACTIVE_POWER, Path.of('its_p_9185b8c1-86ba-4a16-8dea-5ac898e8caa5')), new CsvIndividualTimeSeriesMetaInformation(UUID.fromString("3fbfaa97-cff4-46d4-95ba-a95665e87c26"), ColumnScheme.APPARENT_POWER, Path.of('its_pq_3fbfaa97-cff4-46d4-95ba-a95665e87c26')), new CsvIndividualTimeSeriesMetaInformation(UUID.fromString("46be1e57-e4ed-4ef7-95f1-b2b321cb2047"), ColumnScheme.APPARENT_POWER_AND_HEAT_DEMAND, Path.of('its_pqh_46be1e57-e4ed-4ef7-95f1-b2b321cb2047')), - new CsvIndividualTimeSeriesMetaInformation(UUID.fromString("1061af70-1c03-46e1-b960-940b956c429f"), ColumnScheme.APPARENT_POWER, Path.of('its_pq_1061af70-1c03-46e1-b960-940b956c429f')) + new CsvIndividualTimeSeriesMetaInformation(UUID.fromString("1061af70-1c03-46e1-b960-940b956c429f"), ColumnScheme.APPARENT_POWER, Path.of('its_pq_1061af70-1c03-46e1-b960-940b956c429f')), + new CsvIndividualTimeSeriesMetaInformation(UUID.fromString("eeccbe3c-a47e-448e-8eca-1f369d3c24e6"), ColumnScheme.VOLTAGE, Path.of("its_v_eeccbe3c-a47e-448e-8eca-1f369d3c24e6")) ) when: def actual = source.timeSeriesMetaInformation then: - actual.size() == 7 + actual.size() == 8 actual.every { it.key == it.value.uuid && expectedTimeSeries.contains(it.value) @@ -62,6 +63,7 @@ class CsvTimeSeriesMetaInformationSourceIT extends Specification implements CsvT "3fbfaa97-cff4-46d4-95ba-a95665e87c26" || "pq" "46be1e57-e4ed-4ef7-95f1-b2b321cb2047" || "pqh" "1061af70-1c03-46e1-b960-940b956c429f" || "pq" + "eeccbe3c-a47e-448e-8eca-1f369d3c24e6" || "v" } def "The CSV time series meta information source returns an empty optional for an unknown time series UUID"() { diff --git a/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesSourceTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesSourceTest.groovy index c142bb414..042055b31 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesSourceTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesSourceTest.groovy @@ -78,5 +78,6 @@ class CsvTimeSeriesSourceTest extends Specification implements CsvTestDataMeta { UUID.fromString("76c9d846-797c-4f07-b7ec-2245f679f5c7") | ColumnScheme.ACTIVE_POWER_AND_HEAT_DEMAND | Path.of("its_ph_76c9d846-797c-4f07-b7ec-2245f679f5c7") || 2 | HeatAndPValue UUID.fromString("3fbfaa97-cff4-46d4-95ba-a95665e87c26") | ColumnScheme.APPARENT_POWER | Path.of("its_pq_3fbfaa97-cff4-46d4-95ba-a95665e87c26") || 2 | SValue UUID.fromString("46be1e57-e4ed-4ef7-95f1-b2b321cb2047") | ColumnScheme.APPARENT_POWER_AND_HEAT_DEMAND | Path.of("its_pqh_46be1e57-e4ed-4ef7-95f1-b2b321cb2047") || 2 | HeatAndSValue + UUID.fromString("eeccbe3c-a47e-448e-8eca-1f369d3c24e6") | ColumnScheme.VOLTAGE | Path.of("its_v_eeccbe3c-a47e-448e-8eca-1f369d3c24e6") || 2 | VoltageValue } } \ No newline at end of file diff --git a/src/test/groovy/edu/ie3/datamodel/models/value/VoltageValueTest.groovy b/src/test/groovy/edu/ie3/datamodel/models/value/VoltageValueTest.groovy new file mode 100644 index 000000000..08b264476 --- /dev/null +++ b/src/test/groovy/edu/ie3/datamodel/models/value/VoltageValueTest.groovy @@ -0,0 +1,46 @@ +/* + * © 2024. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation + */ +package edu.ie3.datamodel.models.value + +import static edu.ie3.util.quantities.PowerSystemUnits.* + +import spock.lang.Specification +import tech.units.indriya.quantity.Quantities + + +class VoltageValueTest extends Specification { + + def "A VoltageValue should return the real part correctly"() { + when: + def actual = value.realPart + + then: + actual.isPresent() + actual.get() =~ expected + + where: + value | expected + new VoltageValue(Quantities.getQuantity(1, PU), Quantities.getQuantity(0, DEGREE_GEOM)) | Quantities.getQuantity(1, PU) + new VoltageValue(Quantities.getQuantity(1, PU), Quantities.getQuantity(45, DEGREE_GEOM)) | Quantities.getQuantity(0.7071067811865476, PU) + new VoltageValue(Quantities.getQuantity(1, PU), Quantities.getQuantity(90, DEGREE_GEOM)) | Quantities.getQuantity(6.123233995736766E-17, PU) // ~0pu + } + + + def "A VoltageValue should return the imaginary part correctly"() { + when: + def actual = value.imagPart + + then: + actual.isPresent() + actual.get() =~ expected + + where: + value | expected + new VoltageValue(Quantities.getQuantity(1, PU), Quantities.getQuantity(0, DEGREE_GEOM)) | Quantities.getQuantity(0, PU) + new VoltageValue(Quantities.getQuantity(1, PU), Quantities.getQuantity(45, DEGREE_GEOM)) | Quantities.getQuantity(0.7071067811865475, PU) + new VoltageValue(Quantities.getQuantity(1, PU), Quantities.getQuantity(90, DEGREE_GEOM)) | Quantities.getQuantity(1, PU) + } +} diff --git a/src/test/groovy/edu/ie3/datamodel/utils/validation/UniquenessValidationUtilsTest.groovy b/src/test/groovy/edu/ie3/datamodel/utils/validation/UniquenessValidationUtilsTest.groovy index d33502cb1..f6124f455 100644 --- a/src/test/groovy/edu/ie3/datamodel/utils/validation/UniquenessValidationUtilsTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/utils/validation/UniquenessValidationUtilsTest.groovy @@ -12,6 +12,7 @@ import static edu.ie3.util.quantities.PowerSystemUnits.PU import static tech.units.indriya.unit.Units.METRE_PER_SECOND import edu.ie3.datamodel.exceptions.DuplicateEntitiesException +import edu.ie3.datamodel.exceptions.ValidationException import edu.ie3.datamodel.io.source.TimeSeriesMappingSource import edu.ie3.datamodel.models.StandardUnits import edu.ie3.datamodel.models.input.AssetInput @@ -23,6 +24,7 @@ import edu.ie3.datamodel.models.value.SolarIrradianceValue import edu.ie3.datamodel.models.value.TemperatureValue import edu.ie3.datamodel.models.value.WeatherValue import edu.ie3.datamodel.models.value.WindValue +import edu.ie3.datamodel.utils.Try import edu.ie3.util.geo.GeoUtils import spock.lang.Specification import tech.units.indriya.quantity.Quantities @@ -168,8 +170,8 @@ class UniquenessValidationUtilsTest extends Specification { given: UUID timeSeries = UUID.randomUUID() Set uniqueEntries = [ - new TimeSeriesMappingSource.MappingEntry(UUID.randomUUID(), timeSeries), - new TimeSeriesMappingSource.MappingEntry(UUID.randomUUID(), timeSeries), + new TimeSeriesMappingSource.ParticipantMappingEntry(UUID.randomUUID(), timeSeries), + new TimeSeriesMappingSource.ParticipantMappingEntry(UUID.randomUUID(), timeSeries), ] when: @@ -183,29 +185,39 @@ class UniquenessValidationUtilsTest extends Specification { given: UUID participant = UUID.fromString("1f25eea2-20eb-4b6b-8f05-bdbb0e851e65") - Set uniqueEntries = [ - new TimeSeriesMappingSource.MappingEntry(participant, UUID.randomUUID()), - new TimeSeriesMappingSource.MappingEntry(participant, UUID.randomUUID()), + Set uniqueParticipantEntries = [ + new TimeSeriesMappingSource.ParticipantMappingEntry(participant, UUID.randomUUID()), + new TimeSeriesMappingSource.ParticipantMappingEntry(participant, UUID.randomUUID()), + ] + + Set uniqueEntityEntries = [ + new TimeSeriesMappingSource.EntityMappingEntry(participant, UUID.randomUUID()), + new TimeSeriesMappingSource.EntityMappingEntry(participant, UUID.randomUUID()), ] when: - checkMappingEntryUniqueness(uniqueEntries) + def participantDuplicate = Try.ofVoid(() -> checkMappingEntryUniqueness(uniqueParticipantEntries), DuplicateEntitiesException) + def entityDuplicate = Try.ofVoid(() -> checkMappingEntryUniqueness(uniqueEntityEntries), DuplicateEntitiesException) then: - DuplicateEntitiesException de = thrown() - de.message == "'MappingEntry' entities with duplicated UUID key, but different field values found! " + - "Affected primary keys: [1f25eea2-20eb-4b6b-8f05-bdbb0e851e65]" + participantDuplicate.failure + participantDuplicate.exception.get().message == "'ParticipantMappingEntry' entities with duplicated UUID key, but different field values found! " + + "Affected primary keys: [1f25eea2-20eb-4b6b-8f05-bdbb0e851e65]" + + entityDuplicate.failure + entityDuplicate.exception.get().message == "'EntityMappingEntry' entities with duplicated UUID key, but different field values found! " + + "Affected primary keys: [1f25eea2-20eb-4b6b-8f05-bdbb0e851e65]" } def "Checking if time based weather values are unique"() { given: ZonedDateTime time = ZonedDateTime.now() WeatherValue value = new WeatherValue( - GeoUtils.buildPoint(50d, 7d), - new SolarIrradianceValue(Quantities.getQuantity(10d, StandardUnits.SOLAR_IRRADIANCE), Quantities.getQuantity(10d, StandardUnits.SOLAR_IRRADIANCE)), - new TemperatureValue(Quantities.getQuantity(5d, Units.CELSIUS)), - new WindValue(Quantities.getQuantity(5d, DEGREE_GEOM), Quantities.getQuantity(10d, METRE_PER_SECOND)) - ) + GeoUtils.buildPoint(50d, 7d), + new SolarIrradianceValue(Quantities.getQuantity(10d, StandardUnits.SOLAR_IRRADIANCE), Quantities.getQuantity(10d, StandardUnits.SOLAR_IRRADIANCE)), + new TemperatureValue(Quantities.getQuantity(5d, Units.CELSIUS)), + new WindValue(Quantities.getQuantity(5d, DEGREE_GEOM), Quantities.getQuantity(10d, METRE_PER_SECOND)) + ) Set> uniqueValues = [ new TimeBasedValue(time, value), @@ -223,11 +235,11 @@ class UniquenessValidationUtilsTest extends Specification { given: ZonedDateTime time = ZonedDateTime.now() WeatherValue value = new WeatherValue( - GeoUtils.buildPoint(50d, 7d), - new SolarIrradianceValue(Quantities.getQuantity(10d, StandardUnits.SOLAR_IRRADIANCE), Quantities.getQuantity(10d, StandardUnits.SOLAR_IRRADIANCE)), - new TemperatureValue(Quantities.getQuantity(5d, Units.CELSIUS)), - new WindValue(Quantities.getQuantity(5d, DEGREE_GEOM), Quantities.getQuantity(10d, METRE_PER_SECOND)) - ) + GeoUtils.buildPoint(50d, 7d), + new SolarIrradianceValue(Quantities.getQuantity(10d, StandardUnits.SOLAR_IRRADIANCE), Quantities.getQuantity(10d, StandardUnits.SOLAR_IRRADIANCE)), + new TemperatureValue(Quantities.getQuantity(5d, Units.CELSIUS)), + new WindValue(Quantities.getQuantity(5d, DEGREE_GEOM), Quantities.getQuantity(10d, METRE_PER_SECOND)) + ) Set> notUniqueValues = [ new TimeBasedValue(time, value), new TimeBasedValue(time, value) diff --git a/src/test/resources/edu/ie3/datamodel/io/source/csv/_timeseries/its_v_eeccbe3c-a47e-448e-8eca-1f369d3c24e6.csv b/src/test/resources/edu/ie3/datamodel/io/source/csv/_timeseries/its_v_eeccbe3c-a47e-448e-8eca-1f369d3c24e6.csv new file mode 100644 index 000000000..1d776f689 --- /dev/null +++ b/src/test/resources/edu/ie3/datamodel/io/source/csv/_timeseries/its_v_eeccbe3c-a47e-448e-8eca-1f369d3c24e6.csv @@ -0,0 +1,3 @@ +"time";"vMag";"vAng" +2020-01-01T00:00:00Z;1.0;45.0 +2020-01-01T00:15:00Z;0.9; \ No newline at end of file diff --git a/src/test/resources/edu/ie3/datamodel/io/source/csv/_timeseries/time_series_mapping.csv b/src/test/resources/edu/ie3/datamodel/io/source/csv/_timeseries/time_series_mapping.csv index d0130d232..2e1897b2a 100644 --- a/src/test/resources/edu/ie3/datamodel/io/source/csv/_timeseries/time_series_mapping.csv +++ b/src/test/resources/edu/ie3/datamodel/io/source/csv/_timeseries/time_series_mapping.csv @@ -1,4 +1,5 @@ -"uuid";"participant";"time_series" -"58167015-d760-4f90-8109-f2ebd94cda91";"b86e95b0-e579-4a80-a534-37c7a470a409";"9185b8c1-86ba-4a16-8dea-5ac898e8caa5" -"9a9ebfda-dc26-4a40-b9ca-25cd42f6cc3f";"c7ebcc6c-55fc-479b-aa6b-6fa82ccac6b8";"3fbfaa97-cff4-46d4-95ba-a95665e87c26" -"9c1c53ea-e575-41a2-a373-a8b2d3ed2c39";"90a96daa-012b-4fea-82dc-24ba7a7ab81c";"3fbfaa97-cff4-46d4-95ba-a95665e87c26" \ No newline at end of file +"entity";"time_series" +"b86e95b0-e579-4a80-a534-37c7a470a409";"9185b8c1-86ba-4a16-8dea-5ac898e8caa5" +"c7ebcc6c-55fc-479b-aa6b-6fa82ccac6b8";"3fbfaa97-cff4-46d4-95ba-a95665e87c26" +"90a96daa-012b-4fea-82dc-24ba7a7ab81c";"3fbfaa97-cff4-46d4-95ba-a95665e87c26" +"7bed7760-c220-4fe6-88b3-47b246f6ef3f";"eeccbe3c-a47e-448e-8eca-1f369d3c24e6" \ No newline at end of file From 3d30927dc5bab3cb85b23459539f6d0e0db8a0b0 Mon Sep 17 00:00:00 2001 From: staudtMarius Date: Tue, 6 Aug 2024 12:45:41 +0200 Subject: [PATCH 2/6] Adding information to docs. --- docs/readthedocs/io/csvfiles.md | 3 +++ .../models/input/additionaldata/timeseries.md | 11 ++++++++--- .../validation/UniquenessValidationUtilsTest.groovy | 1 - 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/docs/readthedocs/io/csvfiles.md b/docs/readthedocs/io/csvfiles.md index 54a6b7369..cb01a42e4 100644 --- a/docs/readthedocs/io/csvfiles.md +++ b/docs/readthedocs/io/csvfiles.md @@ -148,6 +148,9 @@ The following keys are supported until now: * - pqh - | Active, reactive and heat power | Permissible head line: ``time,p,q,h`` + * - v + - | Voltage mangnitude in pu and angle in ° + | Permissible head line: ``time,vMag,vAng`` * - weather - | Weather information | Permissible head line: ``time,coordinate,direct_irradiation,diffuse_irradiation,temperature,wind_velocity,wind_direction`` diff --git a/docs/readthedocs/models/input/additionaldata/timeseries.md b/docs/readthedocs/models/input/additionaldata/timeseries.md index d486f78ca..f5830c83b 100644 --- a/docs/readthedocs/models/input/additionaldata/timeseries.md +++ b/docs/readthedocs/models/input/additionaldata/timeseries.md @@ -32,10 +32,12 @@ The following different values are available: - Electrical active and reactive power * - `HeatAndPValue` - - Combination of thermal power (e.g. in kW)
and electrical active power (e.g. in kW) + - | Combination of thermal power (e.g. in kW) + | and electrical active power (e.g. in kW) * - `HeatAndSValue` - - Combination of thermal power (e.g. in kW)
and electrical active and reactive power (e.g. in kW and kVAr) + - | Combination of thermal power (e.g. in kW) + | and electrical active and reactive power (e.g. in kW and kVAr) * - `EnergyPriceValue` - Wholesale market price (e.g. in € / MWh) @@ -48,7 +50,10 @@ The following different values are available: * - `WindValue` - Combination of wind direction and wind velocity - + + * - `VoltageValue` + - Combination of voltage magnitude in pu and angle in ° + * - `WeatherValue` - Combination of irradiance, temperature and wind information diff --git a/src/test/groovy/edu/ie3/datamodel/utils/validation/UniquenessValidationUtilsTest.groovy b/src/test/groovy/edu/ie3/datamodel/utils/validation/UniquenessValidationUtilsTest.groovy index f6124f455..ef5027514 100644 --- a/src/test/groovy/edu/ie3/datamodel/utils/validation/UniquenessValidationUtilsTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/utils/validation/UniquenessValidationUtilsTest.groovy @@ -12,7 +12,6 @@ import static edu.ie3.util.quantities.PowerSystemUnits.PU import static tech.units.indriya.unit.Units.METRE_PER_SECOND import edu.ie3.datamodel.exceptions.DuplicateEntitiesException -import edu.ie3.datamodel.exceptions.ValidationException import edu.ie3.datamodel.io.source.TimeSeriesMappingSource import edu.ie3.datamodel.models.StandardUnits import edu.ie3.datamodel.models.input.AssetInput From 61b9b7a97d344ab190e7f97436abac6c5d10d028 Mon Sep 17 00:00:00 2001 From: staudtMarius Date: Thu, 14 Nov 2024 12:38:00 +0100 Subject: [PATCH 3/6] Simplifying code. --- .../timeseries/TimeSeriesMappingFactory.java | 18 ++------ .../io/source/TimeSeriesMappingSource.java | 43 +------------------ .../input/InputEntityProcessorTest.groovy | 2 +- .../UniquenessValidationUtilsTest.groovy | 19 +++----- .../sql/_timeseries/time_series_mapping.sql | 11 +++-- 5 files changed, 16 insertions(+), 77 deletions(-) diff --git a/src/main/java/edu/ie3/datamodel/io/factory/timeseries/TimeSeriesMappingFactory.java b/src/main/java/edu/ie3/datamodel/io/factory/timeseries/TimeSeriesMappingFactory.java index 3ef9d60c1..b39a1fdc5 100644 --- a/src/main/java/edu/ie3/datamodel/io/factory/timeseries/TimeSeriesMappingFactory.java +++ b/src/main/java/edu/ie3/datamodel/io/factory/timeseries/TimeSeriesMappingFactory.java @@ -5,20 +5,16 @@ */ package edu.ie3.datamodel.io.factory.timeseries; -import edu.ie3.datamodel.exceptions.FactoryException; import edu.ie3.datamodel.io.factory.EntityData; import edu.ie3.datamodel.io.factory.EntityFactory; import edu.ie3.datamodel.io.source.TimeSeriesMappingSource; import java.util.List; import java.util.Set; import java.util.UUID; -import java.util.stream.Collectors; -import java.util.stream.Stream; public class TimeSeriesMappingFactory extends EntityFactory { private static final String ENTITY = "entity"; - private static final String PARTICIPANT = "participant"; private static final String TIME_SERIES = "timeSeries"; public TimeSeriesMappingFactory() { @@ -27,21 +23,13 @@ public TimeSeriesMappingFactory() { @Override protected List> getFields(Class entityClass) { - return List.of( - Stream.of(ENTITY, TIME_SERIES).collect(Collectors.toSet()), - Stream.of(PARTICIPANT, TIME_SERIES).collect(Collectors.toSet())); + return List.of(newSet(ENTITY, TIME_SERIES)); } @Override protected TimeSeriesMappingSource.MappingEntry buildModel(EntityData data) { + UUID entity = data.getUUID(ENTITY); UUID timeSeries = data.getUUID(TIME_SERIES); - - try { - UUID entity = data.getUUID(ENTITY); - return new TimeSeriesMappingSource.EntityMappingEntry(entity, timeSeries); - } catch (FactoryException e) { - UUID participant = data.getUUID(PARTICIPANT); - return new TimeSeriesMappingSource.ParticipantMappingEntry(participant, timeSeries); - } + return new TimeSeriesMappingSource.MappingEntry(entity, timeSeries); } } diff --git a/src/main/java/edu/ie3/datamodel/io/source/TimeSeriesMappingSource.java b/src/main/java/edu/ie3/datamodel/io/source/TimeSeriesMappingSource.java index 81c382f9e..da5e7b9fc 100644 --- a/src/main/java/edu/ie3/datamodel/io/source/TimeSeriesMappingSource.java +++ b/src/main/java/edu/ie3/datamodel/io/source/TimeSeriesMappingSource.java @@ -80,8 +80,8 @@ private Try createMappingEntry( // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- /** Class to represent one entry within the entity to time series mapping */ - public abstract static class MappingEntry implements InputEntity { - protected final UUID entity; + public static class MappingEntry implements InputEntity { + private final UUID entity; private final UUID timeSeries; public MappingEntry(UUID entity, UUID timeSeries) { @@ -116,43 +116,4 @@ public String toString() { return "MappingEntry{" + "entity=" + entity + ", timeSeries=" + timeSeries + '}'; } } - - /** Class to represent one entry within the entity to time series mapping */ - public static class EntityMappingEntry extends MappingEntry { - - public EntityMappingEntry(UUID entity, UUID timeSeries) { - super(entity, timeSeries); - } - - @Override - public String toString() { - return "EntityMappingEntry{" + "entity=" + entity + ", timeSeries=" + getTimeSeries() + '}'; - } - } - - /** Class to represent one entry within the participant to time series mapping */ - public static class ParticipantMappingEntry extends MappingEntry { - - public ParticipantMappingEntry(UUID participant, UUID timeSeries) { - super(participant, timeSeries); - } - - /** - * Returns the {@link UUID} of the {@link - * edu.ie3.datamodel.models.input.system.SystemParticipantInput}. - */ - public UUID getParticipant() { - return entity; - } - - @Override - public String toString() { - return "ParticipantMappingEntry{" - + "participant=" - + entity - + ", timeSeries=" - + getTimeSeries() - + '}'; - } - } } 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 b0fd79168..de99a0067 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 @@ -627,7 +627,7 @@ class InputEntityProcessorTest extends Specification { def "The InputEntityProcessor should serialize a provided MappingEntry correctly"() { given: def processor = new InputEntityProcessor(TimeSeriesMappingSource.MappingEntry) - def validResult = new TimeSeriesMappingSource.ParticipantMappingEntry(UUID.fromString("7eb7b296-f4c4-4020-acf3-e865453b5dbd"), UUID.fromString("bc581c6c-3044-48a1-aea1-5b2cb1370356")) + def validResult = new TimeSeriesMappingSource.MappingEntry(UUID.fromString("7eb7b296-f4c4-4020-acf3-e865453b5dbd"), UUID.fromString("bc581c6c-3044-48a1-aea1-5b2cb1370356")) Map expectedResults = [ "entity": "7eb7b296-f4c4-4020-acf3-e865453b5dbd", diff --git a/src/test/groovy/edu/ie3/datamodel/utils/validation/UniquenessValidationUtilsTest.groovy b/src/test/groovy/edu/ie3/datamodel/utils/validation/UniquenessValidationUtilsTest.groovy index ef5027514..95b2f0472 100644 --- a/src/test/groovy/edu/ie3/datamodel/utils/validation/UniquenessValidationUtilsTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/utils/validation/UniquenessValidationUtilsTest.groovy @@ -169,8 +169,8 @@ class UniquenessValidationUtilsTest extends Specification { given: UUID timeSeries = UUID.randomUUID() Set uniqueEntries = [ - new TimeSeriesMappingSource.ParticipantMappingEntry(UUID.randomUUID(), timeSeries), - new TimeSeriesMappingSource.ParticipantMappingEntry(UUID.randomUUID(), timeSeries), + new TimeSeriesMappingSource.MappingEntry(UUID.randomUUID(), timeSeries), + new TimeSeriesMappingSource.MappingEntry(UUID.randomUUID(), timeSeries), ] when: @@ -184,27 +184,18 @@ class UniquenessValidationUtilsTest extends Specification { given: UUID participant = UUID.fromString("1f25eea2-20eb-4b6b-8f05-bdbb0e851e65") - Set uniqueParticipantEntries = [ - new TimeSeriesMappingSource.ParticipantMappingEntry(participant, UUID.randomUUID()), - new TimeSeriesMappingSource.ParticipantMappingEntry(participant, UUID.randomUUID()), - ] - Set uniqueEntityEntries = [ - new TimeSeriesMappingSource.EntityMappingEntry(participant, UUID.randomUUID()), - new TimeSeriesMappingSource.EntityMappingEntry(participant, UUID.randomUUID()), + new TimeSeriesMappingSource.MappingEntry(participant, UUID.randomUUID()), + new TimeSeriesMappingSource.MappingEntry(participant, UUID.randomUUID()), ] when: - def participantDuplicate = Try.ofVoid(() -> checkMappingEntryUniqueness(uniqueParticipantEntries), DuplicateEntitiesException) def entityDuplicate = Try.ofVoid(() -> checkMappingEntryUniqueness(uniqueEntityEntries), DuplicateEntitiesException) then: - participantDuplicate.failure - participantDuplicate.exception.get().message == "'ParticipantMappingEntry' entities with duplicated UUID key, but different field values found! " + - "Affected primary keys: [1f25eea2-20eb-4b6b-8f05-bdbb0e851e65]" entityDuplicate.failure - entityDuplicate.exception.get().message == "'EntityMappingEntry' entities with duplicated UUID key, but different field values found! " + + entityDuplicate.exception.get().message == "'MappingEntry' entities with duplicated UUID key, but different field values found! " + "Affected primary keys: [1f25eea2-20eb-4b6b-8f05-bdbb0e851e65]" } diff --git a/src/test/resources/edu/ie3/datamodel/io/source/sql/_timeseries/time_series_mapping.sql b/src/test/resources/edu/ie3/datamodel/io/source/sql/_timeseries/time_series_mapping.sql index b3921f442..260fa5224 100644 --- a/src/test/resources/edu/ie3/datamodel/io/source/sql/_timeseries/time_series_mapping.sql +++ b/src/test/resources/edu/ie3/datamodel/io/source/sql/_timeseries/time_series_mapping.sql @@ -1,15 +1,14 @@ CREATE TABLE public.time_series_mapping ( - uuid uuid PRIMARY KEY, - participant uuid, + entity uuid PRIMARY KEY, time_series uuid ) WITHOUT OIDS TABLESPACE pg_default; INSERT INTO - public.time_series_mapping (uuid, participant, time_series) + public.time_series_mapping (entity, time_series) VALUES -('58167015-d760-4f90-8109-f2ebd94cda91', 'b86e95b0-e579-4a80-a534-37c7a470a409', '9185b8c1-86ba-4a16-8dea-5ac898e8caa5'), -('9a9ebfda-dc26-4a40-b9ca-25cd42f6cc3f', 'c7ebcc6c-55fc-479b-aa6b-6fa82ccac6b8', '3fbfaa97-cff4-46d4-95ba-a95665e87c26'), -('9c1c53ea-e575-41a2-a373-a8b2d3ed2c39', '90a96daa-012b-4fea-82dc-24ba7a7ab81c', '3fbfaa97-cff4-46d4-95ba-a95665e87c26'); +('b86e95b0-e579-4a80-a534-37c7a470a409', '9185b8c1-86ba-4a16-8dea-5ac898e8caa5'), +('c7ebcc6c-55fc-479b-aa6b-6fa82ccac6b8', '3fbfaa97-cff4-46d4-95ba-a95665e87c26'), +('90a96daa-012b-4fea-82dc-24ba7a7ab81c', '3fbfaa97-cff4-46d4-95ba-a95665e87c26'); From f4a042aa5a109427f3ad9c277081d9b44dd8a708 Mon Sep 17 00:00:00 2001 From: staudtMarius Date: Fri, 29 Nov 2024 12:35:40 +0100 Subject: [PATCH 4/6] Removing column renaming. --- .../timeseries/TimeSeriesMappingFactory.java | 12 ++++++--- .../io/source/TimeSeriesMappingSource.java | 26 +++++++------------ .../validation/UniquenessValidationUtils.java | 2 +- .../input/InputEntityProcessorTest.groovy | 2 +- .../csv/_timeseries/time_series_mapping.csv | 2 +- .../sql/_timeseries/time_series_mapping.sql | 4 +-- 6 files changed, 23 insertions(+), 25 deletions(-) diff --git a/src/main/java/edu/ie3/datamodel/io/factory/timeseries/TimeSeriesMappingFactory.java b/src/main/java/edu/ie3/datamodel/io/factory/timeseries/TimeSeriesMappingFactory.java index b39a1fdc5..2009435cc 100644 --- a/src/main/java/edu/ie3/datamodel/io/factory/timeseries/TimeSeriesMappingFactory.java +++ b/src/main/java/edu/ie3/datamodel/io/factory/timeseries/TimeSeriesMappingFactory.java @@ -8,13 +8,16 @@ import edu.ie3.datamodel.io.factory.EntityData; import edu.ie3.datamodel.io.factory.EntityFactory; import edu.ie3.datamodel.io.source.TimeSeriesMappingSource; +import java.util.Collections; import java.util.List; import java.util.Set; import java.util.UUID; +import java.util.stream.Collectors; +import java.util.stream.Stream; public class TimeSeriesMappingFactory extends EntityFactory { - private static final String ENTITY = "entity"; + private static final String PARTICIPANT = "participant"; private static final String TIME_SERIES = "timeSeries"; public TimeSeriesMappingFactory() { @@ -23,13 +26,14 @@ public TimeSeriesMappingFactory() { @Override protected List> getFields(Class entityClass) { - return List.of(newSet(ENTITY, TIME_SERIES)); + return Collections.singletonList( + Stream.of(PARTICIPANT, TIME_SERIES).collect(Collectors.toSet())); } @Override protected TimeSeriesMappingSource.MappingEntry buildModel(EntityData data) { - UUID entity = data.getUUID(ENTITY); + UUID participant = data.getUUID(PARTICIPANT); UUID timeSeries = data.getUUID(TIME_SERIES); - return new TimeSeriesMappingSource.MappingEntry(entity, timeSeries); + return new TimeSeriesMappingSource.MappingEntry(participant, timeSeries); } } diff --git a/src/main/java/edu/ie3/datamodel/io/source/TimeSeriesMappingSource.java b/src/main/java/edu/ie3/datamodel/io/source/TimeSeriesMappingSource.java index da5e7b9fc..75a1802c6 100644 --- a/src/main/java/edu/ie3/datamodel/io/source/TimeSeriesMappingSource.java +++ b/src/main/java/edu/ie3/datamodel/io/source/TimeSeriesMappingSource.java @@ -11,6 +11,7 @@ import edu.ie3.datamodel.io.factory.EntityData; import edu.ie3.datamodel.io.factory.timeseries.TimeSeriesMappingFactory; import edu.ie3.datamodel.models.input.InputEntity; +import edu.ie3.datamodel.models.input.system.SystemParticipantInput; import edu.ie3.datamodel.models.timeseries.TimeSeries; import edu.ie3.datamodel.utils.Try; import edu.ie3.datamodel.utils.Try.*; @@ -46,7 +47,7 @@ public Map getMapping() throws SourceException { .filter(Try::isSuccess) .map(t -> (Success) t) .map(Success::get) - .collect(Collectors.toMap(MappingEntry::getEntity, MappingEntry::getTimeSeries)); + .collect(Collectors.toMap(MappingEntry::participant, MappingEntry::timeSeries)); } /** @@ -79,19 +80,12 @@ private Try createMappingEntry( // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - /** Class to represent one entry within the entity to time series mapping */ - public static class MappingEntry implements InputEntity { - private final UUID entity; - private final UUID timeSeries; + /** Class to represent one entry within the participant to time series mapping */ + public record MappingEntry(UUID participant, UUID timeSeries) implements InputEntity { - public MappingEntry(UUID entity, UUID timeSeries) { - this.entity = entity; - this.timeSeries = timeSeries; - } - - /** Returns the {@link UUID} of the {@link edu.ie3.datamodel.models.UniqueEntity}. */ - public UUID getEntity() { - return entity; + /** Returns the {@link UUID} of the {@link SystemParticipantInput}. */ + public UUID getParticipant() { + return participant; } /** Returns the {@link UUID} of the {@link TimeSeries}. */ @@ -103,17 +97,17 @@ public UUID getTimeSeries() { public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof MappingEntry that)) return false; - return entity.equals(that.entity) && timeSeries.equals(that.timeSeries); + return participant.equals(that.participant) && timeSeries.equals(that.timeSeries); } @Override public int hashCode() { - return Objects.hash(entity, timeSeries); + return Objects.hash(participant, timeSeries); } @Override public String toString() { - return "MappingEntry{" + "entity=" + entity + ", timeSeries=" + timeSeries + '}'; + return "MappingEntry{" + "participant=" + participant + ", timeSeries=" + timeSeries + '}'; } } } diff --git a/src/main/java/edu/ie3/datamodel/utils/validation/UniquenessValidationUtils.java b/src/main/java/edu/ie3/datamodel/utils/validation/UniquenessValidationUtils.java index a1576dfaa..86be3c060 100644 --- a/src/main/java/edu/ie3/datamodel/utils/validation/UniquenessValidationUtils.java +++ b/src/main/java/edu/ie3/datamodel/utils/validation/UniquenessValidationUtils.java @@ -33,7 +33,7 @@ public class UniquenessValidationUtils extends ValidationUtils { protected static final FieldSetSupplier congestionResultFieldSupplier = entity -> Set.of(entity.getTime(), entity.getSubgrid()); protected static final FieldSetSupplier mappingFieldSupplier = - entity -> Set.of(entity.getEntity()); + entity -> Set.of(entity.participant()); protected static final FieldSetSupplier idCoordinateSupplier = entity -> Set.of(entity.id(), entity.point()); protected static final FieldSetSupplier> weatherValueFieldSupplier = 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 de99a0067..24b1a8198 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 @@ -630,7 +630,7 @@ class InputEntityProcessorTest extends Specification { def validResult = new TimeSeriesMappingSource.MappingEntry(UUID.fromString("7eb7b296-f4c4-4020-acf3-e865453b5dbd"), UUID.fromString("bc581c6c-3044-48a1-aea1-5b2cb1370356")) Map expectedResults = [ - "entity": "7eb7b296-f4c4-4020-acf3-e865453b5dbd", + "participant": "7eb7b296-f4c4-4020-acf3-e865453b5dbd", "timeSeries": "bc581c6c-3044-48a1-aea1-5b2cb1370356" ] diff --git a/src/test/resources/edu/ie3/datamodel/io/source/csv/_timeseries/time_series_mapping.csv b/src/test/resources/edu/ie3/datamodel/io/source/csv/_timeseries/time_series_mapping.csv index 2e1897b2a..f5d866f73 100644 --- a/src/test/resources/edu/ie3/datamodel/io/source/csv/_timeseries/time_series_mapping.csv +++ b/src/test/resources/edu/ie3/datamodel/io/source/csv/_timeseries/time_series_mapping.csv @@ -1,4 +1,4 @@ -"entity";"time_series" +"participant";"time_series" "b86e95b0-e579-4a80-a534-37c7a470a409";"9185b8c1-86ba-4a16-8dea-5ac898e8caa5" "c7ebcc6c-55fc-479b-aa6b-6fa82ccac6b8";"3fbfaa97-cff4-46d4-95ba-a95665e87c26" "90a96daa-012b-4fea-82dc-24ba7a7ab81c";"3fbfaa97-cff4-46d4-95ba-a95665e87c26" diff --git a/src/test/resources/edu/ie3/datamodel/io/source/sql/_timeseries/time_series_mapping.sql b/src/test/resources/edu/ie3/datamodel/io/source/sql/_timeseries/time_series_mapping.sql index 260fa5224..90575de9f 100644 --- a/src/test/resources/edu/ie3/datamodel/io/source/sql/_timeseries/time_series_mapping.sql +++ b/src/test/resources/edu/ie3/datamodel/io/source/sql/_timeseries/time_series_mapping.sql @@ -1,13 +1,13 @@ CREATE TABLE public.time_series_mapping ( - entity uuid PRIMARY KEY, + participant uuid PRIMARY KEY, time_series uuid ) WITHOUT OIDS TABLESPACE pg_default; INSERT INTO - public.time_series_mapping (entity, time_series) + public.time_series_mapping (participant, time_series) VALUES ('b86e95b0-e579-4a80-a534-37c7a470a409', '9185b8c1-86ba-4a16-8dea-5ac898e8caa5'), ('c7ebcc6c-55fc-479b-aa6b-6fa82ccac6b8', '3fbfaa97-cff4-46d4-95ba-a95665e87c26'), From f88d124ecc51eb06d45c67aba3a9de4d5073c36c Mon Sep 17 00:00:00 2001 From: staudtMarius Date: Tue, 3 Dec 2024 10:42:07 +0100 Subject: [PATCH 5/6] Implementing reviewer's requests. --- docs/readthedocs/io/csvfiles.md | 17 +++++++------- .../models/input/additionaldata/timeseries.md | 8 +++---- .../TimeBasedSimpleValueFactory.java | 22 ++++++++----------- .../datamodel/models/value/VoltageValue.java | 19 ++++++++-------- .../models/value/VoltageValueTest.groovy | 8 +++---- 5 files changed, 35 insertions(+), 39 deletions(-) diff --git a/docs/readthedocs/io/csvfiles.md b/docs/readthedocs/io/csvfiles.md index 2cb522fa6..3e96eb59d 100644 --- a/docs/readthedocs/io/csvfiles.md +++ b/docs/readthedocs/io/csvfiles.md @@ -122,33 +122,34 @@ This is the UUID from the example above `2fcb3e53-b94a-4b96-bea4-c469e499f1a1`. The following keys are supported until now: ```{list-table} :widths: auto + :class: wrapping :header-rows: 1 * - Key - - Information and supported head line + - Information and supported head line. * - c - An energy price (e.g. in €/MWh; c stands for charge). Permissible head line: ``time,price`` * - p - - Active power + - Active power. Permissible head line: ``time,p`` * - pq - - Active and reactive power + - Active and reactive power. Permissible head line: ``time,p,q`` * - h - - Heat power demand + - Heat power demand. Permissible head line: ``time,h`` * - ph - - Active and heat power + - Active and heat power. Permissible head line: ``time,p,h`` * - pqh - - Active, reactive and heat power + - Active, reactive and heat power. Permissible head line: ``time,p,q,h`` * - v - - Voltage mangnitude in pu and angle in ° + - Voltage mangnitude in pu and angle in °. Permissible head line: ``time,vMag,vAng`` * - weather - - Weather information + - Weather information. Permissible head line: ``time,coordinate,direct_irradiation,diffuse_irradiation,temperature,wind_velocity,wind_direction`` ``` diff --git a/docs/readthedocs/models/input/additionaldata/timeseries.md b/docs/readthedocs/models/input/additionaldata/timeseries.md index c243c9430..991568b4b 100644 --- a/docs/readthedocs/models/input/additionaldata/timeseries.md +++ b/docs/readthedocs/models/input/additionaldata/timeseries.md @@ -32,12 +32,10 @@ The following different values are available: - Electrical active and reactive power * - `HeatAndPValue` - - | Combination of thermal power (e.g. in kW) - | and electrical active power (e.g. in kW) + - Combination of thermal power (e.g. in kW)
and electrical active power (e.g. in kW) * - `HeatAndSValue` - - | Combination of thermal power (e.g. in kW) - | and electrical active and reactive power (e.g. in kW and kVAr) + - Combination of thermal power (e.g. in kW)
and electrical active and reactive power (e.g. in kW and kVAr) * - `EnergyPriceValue` - Wholesale market price (e.g. in € / MWh) @@ -52,7 +50,7 @@ The following different values are available: - Combination of wind direction and wind velocity * - `VoltageValue` - - Combination of voltage magnitude in pu and angle in ° + - Combination of voltage magnitude in p.u. and angle in ° * - `WeatherValue` - Combination of irradiance, temperature and wind information diff --git a/src/main/java/edu/ie3/datamodel/io/factory/timeseries/TimeBasedSimpleValueFactory.java b/src/main/java/edu/ie3/datamodel/io/factory/timeseries/TimeBasedSimpleValueFactory.java index ee8dd059d..05f6e2b32 100644 --- a/src/main/java/edu/ie3/datamodel/io/factory/timeseries/TimeBasedSimpleValueFactory.java +++ b/src/main/java/edu/ie3/datamodel/io/factory/timeseries/TimeBasedSimpleValueFactory.java @@ -11,12 +11,12 @@ import edu.ie3.datamodel.models.StandardUnits; import edu.ie3.datamodel.models.timeseries.individual.TimeBasedValue; import edu.ie3.datamodel.models.value.*; +import edu.ie3.datamodel.utils.Try; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Set; +import java.util.*; +import javax.measure.quantity.Angle; +import tech.units.indriya.ComparableQuantity; public class TimeBasedSimpleValueFactory extends TimeBasedValueFactory, V> { @@ -72,16 +72,10 @@ protected TimeBasedValue buildModel(SimpleTimeBasedValueData data) { } else if (PValue.class.isAssignableFrom(data.getTargetClass())) { value = (V) new PValue(data.getQuantity(ACTIVE_POWER, ACTIVE_POWER_IN)); } else if (VoltageValue.class.isAssignableFrom(data.getTargetClass())) { + Optional> angleOption = + Try.of(() -> data.getQuantity(VANG, VOLTAGE_ANGLE), FactoryException.class).getData(); - try { - value = - (V) - new VoltageValue( - data.getQuantity(VMAG, VOLTAGE_MAGNITUDE), - data.getQuantity(VANG, VOLTAGE_ANGLE)); - } catch (FactoryException e) { - value = (V) new VoltageValue(data.getQuantity(VMAG, VOLTAGE_MAGNITUDE)); - } + value = (V) new VoltageValue(data.getQuantity(VMAG, VOLTAGE_MAGNITUDE), angleOption); } else { throw new FactoryException( "The given factory cannot handle target class '" + data.getTargetClass() + "'."); @@ -106,6 +100,8 @@ protected List> getFields(Class entityClass) { minConstructorParams.addAll(Arrays.asList(ACTIVE_POWER, REACTIVE_POWER)); } else if (PValue.class.isAssignableFrom(entityClass)) { minConstructorParams.add(ACTIVE_POWER); + } else if (VoltageValue.class.isAssignableFrom(entityClass)) { + minConstructorParams.addAll(List.of(VMAG, VANG)); } else { throw new FactoryException( "The given factory cannot handle target class '" + entityClass + "'."); diff --git a/src/main/java/edu/ie3/datamodel/models/value/VoltageValue.java b/src/main/java/edu/ie3/datamodel/models/value/VoltageValue.java index 3a77055e9..d66420756 100644 --- a/src/main/java/edu/ie3/datamodel/models/value/VoltageValue.java +++ b/src/main/java/edu/ie3/datamodel/models/value/VoltageValue.java @@ -27,22 +27,23 @@ public class VoltageValue implements Value { /** * @param magnitude of the voltage in p.u. - * @param angle of the voltage in degree + * @param angleOption option for the angle of this voltage in degree */ public VoltageValue( - ComparableQuantity magnitude, ComparableQuantity angle) { + ComparableQuantity magnitude, + Optional> angleOption) { this.magnitude = magnitude; - this.angle = angle; + this.angle = angleOption.orElse(Quantities.getQuantity(0.0, VOLTAGE_ANGLE)); } /** - * This constructor will set the angle to 0° - * * @param magnitude of the voltage in p.u. + * @param angle of the voltage in degree */ - public VoltageValue(ComparableQuantity magnitude) { + public VoltageValue( + ComparableQuantity magnitude, ComparableQuantity angle) { this.magnitude = magnitude; - this.angle = Quantities.getQuantity(0.0, VOLTAGE_ANGLE); + this.angle = angle; } public Optional> getMagnitude() { @@ -65,8 +66,8 @@ public Optional> getImagPart() { double mag = magnitude.to(PU).getValue().doubleValue(); double ang = angle.to(DEGREE_GEOM).getValue().doubleValue(); - double eInPu = mag * sin(toRadians(ang)); - return Optional.of(Quantities.getQuantity(eInPu, PU)); + double fInPu = mag * sin(toRadians(ang)); + return Optional.of(Quantities.getQuantity(fInPu, PU)); } @Override diff --git a/src/test/groovy/edu/ie3/datamodel/models/value/VoltageValueTest.groovy b/src/test/groovy/edu/ie3/datamodel/models/value/VoltageValueTest.groovy index 08b264476..592f820ee 100644 --- a/src/test/groovy/edu/ie3/datamodel/models/value/VoltageValueTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/models/value/VoltageValueTest.groovy @@ -7,10 +7,10 @@ package edu.ie3.datamodel.models.value import static edu.ie3.util.quantities.PowerSystemUnits.* +import edu.ie3.util.quantities.QuantityUtil import spock.lang.Specification import tech.units.indriya.quantity.Quantities - class VoltageValueTest extends Specification { def "A VoltageValue should return the real part correctly"() { @@ -19,13 +19,13 @@ class VoltageValueTest extends Specification { then: actual.isPresent() - actual.get() =~ expected + QuantityUtil.isEquivalentAbs(actual.get(), expected, 1e-3) where: value | expected new VoltageValue(Quantities.getQuantity(1, PU), Quantities.getQuantity(0, DEGREE_GEOM)) | Quantities.getQuantity(1, PU) new VoltageValue(Quantities.getQuantity(1, PU), Quantities.getQuantity(45, DEGREE_GEOM)) | Quantities.getQuantity(0.7071067811865476, PU) - new VoltageValue(Quantities.getQuantity(1, PU), Quantities.getQuantity(90, DEGREE_GEOM)) | Quantities.getQuantity(6.123233995736766E-17, PU) // ~0pu + new VoltageValue(Quantities.getQuantity(1, PU), Quantities.getQuantity(90, DEGREE_GEOM)) | Quantities.getQuantity(0, PU) } @@ -35,7 +35,7 @@ class VoltageValueTest extends Specification { then: actual.isPresent() - actual.get() =~ expected + QuantityUtil.isEquivalentAbs(actual.get(), expected, 1e-3) where: value | expected From 99312f747635c99ce7230b8c3ef34bdd58d18b17 Mon Sep 17 00:00:00 2001 From: staudtMarius Date: Tue, 3 Dec 2024 14:28:49 +0100 Subject: [PATCH 6/6] Implementing reviewer's requests. --- .../ie3/datamodel/io/factory/FactoryData.java | 16 ++++++++++++++++ .../timeseries/TimeBasedSimpleValueFactory.java | 13 ++++++------- .../models/value/VoltageValueTest.groovy | 8 ++++++-- 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/src/main/java/edu/ie3/datamodel/io/factory/FactoryData.java b/src/main/java/edu/ie3/datamodel/io/factory/FactoryData.java index 6ed7dcb7e..cc0cdd357 100644 --- a/src/main/java/edu/ie3/datamodel/io/factory/FactoryData.java +++ b/src/main/java/edu/ie3/datamodel/io/factory/FactoryData.java @@ -78,6 +78,22 @@ public > ComparableQuantity getQuantity(String field, U return Quantities.getQuantity(getDouble(field), unit); } + /** + * Returns field value for given field name, or empty Optional if field does not exist. + * + * @param field field name + * @param unit unit of Quantity + * @param unit type parameter + * @return field value + */ + public > Optional> getQuantityOptional( + String field, Unit unit) { + return Optional.ofNullable(fieldsToAttributes.get(field)) + .filter(str -> !str.isEmpty()) + .map(Double::parseDouble) + .map(value -> Quantities.getQuantity(value, unit)); + } + /** * Returns int value for given field name. Throws {@link FactoryException} if field does not exist * or parsing fails. diff --git a/src/main/java/edu/ie3/datamodel/io/factory/timeseries/TimeBasedSimpleValueFactory.java b/src/main/java/edu/ie3/datamodel/io/factory/timeseries/TimeBasedSimpleValueFactory.java index 05f6e2b32..52b39e2d7 100644 --- a/src/main/java/edu/ie3/datamodel/io/factory/timeseries/TimeBasedSimpleValueFactory.java +++ b/src/main/java/edu/ie3/datamodel/io/factory/timeseries/TimeBasedSimpleValueFactory.java @@ -11,12 +11,9 @@ import edu.ie3.datamodel.models.StandardUnits; import edu.ie3.datamodel.models.timeseries.individual.TimeBasedValue; import edu.ie3.datamodel.models.value.*; -import edu.ie3.datamodel.utils.Try; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.*; -import javax.measure.quantity.Angle; -import tech.units.indriya.ComparableQuantity; public class TimeBasedSimpleValueFactory extends TimeBasedValueFactory, V> { @@ -42,6 +39,7 @@ public TimeBasedSimpleValueFactory( } @Override + @SuppressWarnings("unchecked") protected TimeBasedValue buildModel(SimpleTimeBasedValueData data) { ZonedDateTime time = timeUtil.toZonedDateTime(data.getField(TIME)); V value; @@ -72,10 +70,11 @@ protected TimeBasedValue buildModel(SimpleTimeBasedValueData data) { } else if (PValue.class.isAssignableFrom(data.getTargetClass())) { value = (V) new PValue(data.getQuantity(ACTIVE_POWER, ACTIVE_POWER_IN)); } else if (VoltageValue.class.isAssignableFrom(data.getTargetClass())) { - Optional> angleOption = - Try.of(() -> data.getQuantity(VANG, VOLTAGE_ANGLE), FactoryException.class).getData(); - - value = (V) new VoltageValue(data.getQuantity(VMAG, VOLTAGE_MAGNITUDE), angleOption); + value = + (V) + new VoltageValue( + data.getQuantity(VMAG, VOLTAGE_MAGNITUDE), + data.getQuantityOptional(VANG, VOLTAGE_ANGLE)); } else { throw new FactoryException( "The given factory cannot handle target class '" + data.getTargetClass() + "'."); diff --git a/src/test/groovy/edu/ie3/datamodel/models/value/VoltageValueTest.groovy b/src/test/groovy/edu/ie3/datamodel/models/value/VoltageValueTest.groovy index 592f820ee..471bc8891 100644 --- a/src/test/groovy/edu/ie3/datamodel/models/value/VoltageValueTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/models/value/VoltageValueTest.groovy @@ -8,18 +8,22 @@ package edu.ie3.datamodel.models.value import static edu.ie3.util.quantities.PowerSystemUnits.* import edu.ie3.util.quantities.QuantityUtil +import spock.lang.Shared import spock.lang.Specification import tech.units.indriya.quantity.Quantities class VoltageValueTest extends Specification { + @Shared + double tolerance = 1e-10 + def "A VoltageValue should return the real part correctly"() { when: def actual = value.realPart then: actual.isPresent() - QuantityUtil.isEquivalentAbs(actual.get(), expected, 1e-3) + QuantityUtil.isEquivalentAbs(actual.get(), expected, tolerance) where: value | expected @@ -35,7 +39,7 @@ class VoltageValueTest extends Specification { then: actual.isPresent() - QuantityUtil.isEquivalentAbs(actual.get(), expected, 1e-3) + QuantityUtil.isEquivalentAbs(actual.get(), expected, tolerance) where: value | expected