diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c6c590e8..2b724d870 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 - Enhance `TimeSeriesSource` with method to retrieve all time keys after a given key [#543](https://github.com/ie3-institute/PowerSystemDataModel/issues/543) - Enhance `WeatherSource` with method to retrieve all time keys after a given key [#572](https://github.com/ie3-institute/PowerSystemDataModel/issues/572) +- Adding timeseries for voltage values [#1128](https://github.com/ie3-institute/PowerSystemDataModel/issues/1128) ### Fixed diff --git a/docs/readthedocs/io/csvfiles.md b/docs/readthedocs/io/csvfiles.md index afeb737d8..2cb522fa6 100644 --- a/docs/readthedocs/io/csvfiles.md +++ b/docs/readthedocs/io/csvfiles.md @@ -144,6 +144,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 a082ba2fb..c243c9430 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/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 ab128d1e6..ee8dd059d 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 @@ -13,7 +13,10 @@ import edu.ie3.datamodel.models.value.*; 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> { @@ -25,6 +28,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"; + public TimeBasedSimpleValueFactory(Class valueClasses) { super(valueClasses); } @@ -64,6 +71,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..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 @@ -8,16 +8,13 @@ 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 PARTICIPANT = "participant"; + private static final String ENTITY = "entity"; private static final String TIME_SERIES = "timeSeries"; public TimeSeriesMappingFactory() { @@ -26,14 +23,13 @@ public TimeSeriesMappingFactory() { @Override protected List> getFields(Class entityClass) { - return Collections.singletonList( - Stream.of(PARTICIPANT, TIME_SERIES).collect(Collectors.toSet())); + return List.of(newSet(ENTITY, TIME_SERIES)); } @Override protected TimeSeriesMappingSource.MappingEntry buildModel(EntityData data) { - UUID participant = data.getUUID(PARTICIPANT); + UUID entity = data.getUUID(ENTITY); UUID timeSeries = data.getUUID(TIME_SERIES); - return new TimeSeriesMappingSource.MappingEntry(participant, timeSeries); + return new TimeSeriesMappingSource.MappingEntry(entity, 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..da5e7b9fc 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 static class MappingEntry implements InputEntity { + private 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,17 @@ 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{" + "participant=" + participant + ", timeSeries=" + timeSeries + '}'; + return "MappingEntry{" + "entity=" + entity + ", timeSeries=" + timeSeries + '}'; } } } 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..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 @@ -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 = [ - "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 445ddc403..47d662b9a 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 @@ -94,5 +94,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..95b2f0472 100644 --- a/src/test/groovy/edu/ie3/datamodel/utils/validation/UniquenessValidationUtilsTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/utils/validation/UniquenessValidationUtilsTest.groovy @@ -23,6 +23,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 @@ -183,29 +184,30 @@ class UniquenessValidationUtilsTest extends Specification { given: UUID participant = UUID.fromString("1f25eea2-20eb-4b6b-8f05-bdbb0e851e65") - Set uniqueEntries = [ + Set uniqueEntityEntries = [ new TimeSeriesMappingSource.MappingEntry(participant, UUID.randomUUID()), new TimeSeriesMappingSource.MappingEntry(participant, UUID.randomUUID()), ] when: - checkMappingEntryUniqueness(uniqueEntries) + 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]" + + entityDuplicate.failure + entityDuplicate.exception.get().message == "'MappingEntry' 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 +225,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 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');