Skip to content

address #264 correctly #322

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Apr 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
[![codecov](https://codecov.io/gh/ie3-institute/PowerSystemDataModel/branch/master/graph/badge.svg)](https://codecov.io/gh/ie3-institute/PowerSystemDataModel)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/d1d73fb87e084904993f968178274835)](https://www.codacy.com/gh/ie3-institute/PowerSystemDataModel?utm_source=github.com&utm_medium=referral&utm_content=ie3-institute/PowerSystemDatamodel&utm_campaign=Badge_Grade)
[![License](https://img.shields.io/github/license/ie3-institute/powersystemdatamodel)](https://github.com/ie3-institute/powersystemdatamodel/blob/master/LICENSE)
[![Maven Central](https://img.shields.io/maven-central/v/com.github.ie3-institute/PowerSystemDataModel.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22com.github.ie3-institute%22%20AND%20a:%22PowerSystemDataModel%22)

Provides an extensive data model capable of modelling energy systems with high granularity e.g. for bottom-up simulations. Additionally, useful functions to process, augment and furnish model i/o information is provided. Effective handling of geographic information related to power grids is also possible. Currently, i/o processing capabilities are provided for *.csv* files.

Expand Down
2 changes: 1 addition & 1 deletion src/main/java/edu/ie3/datamodel/io/factory/Factory.java
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ protected int validateParameters(D data, Set<String>... fieldSets) {
+ "}"
+ " are invalid for instance of "
+ data.getTargetClass().getSimpleName()
+ ". \nThe following fields (without complex objects e.g. nodes) to be passed to a constructor of '"
+ ". \nThe following fields (without complex objects e.g. nodes, operators, ...) to be passed to a constructor of '"
+ data.getTargetClass().getSimpleName()
+ "' are possible (NOT case-sensitive!):\n"
+ possibleOptions);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
/**
* Data used for the construction of {@link edu.ie3.datamodel.models.input.AssetInput} entities.
* This data object can include additional information about the {@link OperatorInput}, which cannot
* be provided through the attribute map.
* be provided through the attribute map as it is a complex shared entity.
*/
public class AssetInputEntityData extends EntityData {
private final OperatorInput operator;
Expand Down
37 changes: 21 additions & 16 deletions src/main/java/edu/ie3/datamodel/io/source/csv/CsvDataSource.java
Original file line number Diff line number Diff line change
Expand Up @@ -242,18 +242,27 @@ private OperatorInput getFirstOrDefaultOperator(
String operatorUuid,
String entityClassName,
String requestEntityUuid) {
return operatorUuid.trim().isEmpty()
? OperatorInput.NO_OPERATOR_ASSIGNED
: findFirstEntityByUuid(operatorUuid, operators)
.orElseGet(
() -> {
log.debug(
"Cannot find operator with uuid '{}' for element '{}' and uuid '{}'. Defaulting to 'NO OPERATOR ASSIGNED'.",
operatorUuid,
entityClassName,
requestEntityUuid);
return OperatorInput.NO_OPERATOR_ASSIGNED;
});
if (operatorUuid == null) {
log.warn(
"Input file for class '{}' is missing the 'operator' field. "
+ "This is okay, but you should consider fixing the file by adding the field. "
+ "Defaulting to 'NO OPERATOR ASSIGNED'",
entityClassName);
return OperatorInput.NO_OPERATOR_ASSIGNED;
} else {
return operatorUuid.trim().isEmpty()
? OperatorInput.NO_OPERATOR_ASSIGNED
: findFirstEntityByUuid(operatorUuid, operators)
.orElseGet(
() -> {
log.debug(
"Cannot find operator with uuid '{}' for element '{}' and uuid '{}'. Defaulting to 'NO OPERATOR ASSIGNED'.",
operatorUuid,
entityClassName,
requestEntityUuid);
return OperatorInput.NO_OPERATOR_ASSIGNED;
});
}
}

/**
Expand All @@ -263,11 +272,8 @@ private OperatorInput getFirstOrDefaultOperator(
*
* <pre>{@code
* Collection.stream().filter(isPresentCollectIfNot(NodeInput.class, new ConcurrentHashMap<>()))
*
* }</pre>
*
* ...
*
* @param entityClass entity class that should be used as they key in the provided counter map
* @param invalidElementsCounterMap a map that counts the number of empty optionals and maps it to
* the provided entity clas
Expand Down Expand Up @@ -332,7 +338,6 @@ protected <T extends UniqueEntity> Stream<T> filterEmptyOptionals(Stream<Optiona
*/
protected <T extends UniqueEntity> Optional<T> findFirstEntityByUuid(
String entityUuid, Collection<T> entities) {
if (entities == null) return Optional.empty();
return entities.stream()
.parallel()
.filter(uniqueEntity -> uniqueEntity.getUuid().toString().equalsIgnoreCase(entityUuid))
Expand Down
4 changes: 3 additions & 1 deletion src/main/java/edu/ie3/datamodel/models/value/Value.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,7 @@
*/
package edu.ie3.datamodel.models.value;

import java.io.Serializable;

/** Describes any class that represents a value */
public interface Value {}
public interface Value extends Serializable {}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import edu.ie3.datamodel.models.input.connector.type.LineTypeInput;
import edu.ie3.datamodel.models.input.connector.type.Transformer2WTypeInput;
import edu.ie3.datamodel.models.input.connector.type.Transformer3WTypeInput;
import edu.ie3.datamodel.utils.GridAndGeoUtils;
import edu.ie3.util.geo.GeoUtils;
import edu.ie3.util.quantities.QuantityUtil;
import javax.measure.Quantity;
import tech.units.indriya.quantity.Quantities;
Expand Down Expand Up @@ -338,7 +338,7 @@ private static void lineLengthMatchesDistancesBetweenPointsOfLineString(LineInpu
|| line.getNodeB().getGeoPosition() != NodeInput.DEFAULT_GEO_POSITION)
&& !QuantityUtil.isEquivalentAbs(
line.getLength(),
GridAndGeoUtils.totalLengthOfLineString(line.getGeoPosition()),
GeoUtils.totalLengthOfLineString(line.getGeoPosition()),
allowedLengthError))
throw new InvalidEntityException(
"Line length does not equal calculated distances between points building the line", line);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ class AssetInputEntityFactoryTest extends Specification implements FactoryTestHe
"{operatesfrom -> 2019-01-01T00:00:00+01:00[Europe/Berlin],\n" +
"operatesuntil -> 2019-12-31T00:00:00+01:00[Europe/Berlin],\n" +
"uuid -> 91ec3bcf-1777-4d38-af67-0bf7c9fa73c7} are invalid for instance of TestAssetInput. \n" +
"The following fields (without complex objects e.g. nodes) to be passed to a constructor of 'TestAssetInput' are possible (NOT case-sensitive!):\n" +
"The following fields (without complex objects e.g. nodes, operators, ...) to be passed to a constructor of 'TestAssetInput' are possible (NOT case-sensitive!):\n" +
"0: [id, uuid]\n" +
"1: [id, operatesfrom, uuid]\n" +
"2: [id, operatesuntil, uuid]\n" +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ class FixedFeedInInputFactoryTest extends Specification implements FactoryTestHe
"id -> TestID,\n" +
"srated -> 3,\n" +
"uuid -> 91ec3bcf-1777-4d38-af67-0bf7c9fa73c7} are invalid for instance of FixedFeedInInput. \n" +
"The following fields (without complex objects e.g. nodes) to be passed to a constructor of 'FixedFeedInInput' are possible (NOT case-sensitive!):\n" +
"The following fields (without complex objects e.g. nodes, operators, ...) to be passed to a constructor of 'FixedFeedInInput' are possible (NOT case-sensitive!):\n" +
"0: [cosphirated, id, qcharacteristics, srated, uuid]\n" +
"1: [cosphirated, id, operatesfrom, qcharacteristics, srated, uuid]\n" +
"2: [cosphirated, id, operatesuntil, qcharacteristics, srated, uuid]\n" +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class NodeResultFactoryTest extends Specification implements FactoryTestHelper {
"{inputModel -> 91ec3bcf-1897-4d38-af67-0bf7c9fa73c7,\n" +
"time -> 2020-01-30 17:26:44,\n" +
"vmag -> 2} are invalid for instance of NodeResult. \n" +
"The following fields (without complex objects e.g. nodes) to be passed to a constructor of 'NodeResult' are possible (NOT case-sensitive!):\n" +
"The following fields (without complex objects e.g. nodes, operators, ...) to be passed to a constructor of 'NodeResult' are possible (NOT case-sensitive!):\n" +
"0: [inputModel, time, vang, vmag]\n" +
"1: [inputModel, time, uuid, vang, vmag]\n"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ class SystemParticipantResultFactoryTest extends Specification implements Factor
"{inputModel -> 91ec3bcf-1777-4d38-af67-0bf7c9fa73c7,\n" +
"q -> 2,\n" +
"time -> 2020-01-30 17:26:44} are invalid for instance of WecResult. \n" +
"The following fields (without complex objects e.g. nodes) to be passed to a constructor of 'WecResult' are possible (NOT case-sensitive!):\n" +
"The following fields (without complex objects e.g. nodes, operators, ...) to be passed to a constructor of 'WecResult' are possible (NOT case-sensitive!):\n" +
"0: [inputModel, p, q, time]\n" +
"1: [inputModel, p, q, time, uuid]\n"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ class SystemParticipantTypeInputFactoryTest extends Specification implements Fac
"pmin -> 7,\n" +
"srated -> 5,\n" +
"uuid -> 91ec3bcf-1777-4d38-af67-0bf7c9fa73c7} are invalid for instance of StorageTypeInput. \n" +
"The following fields (without complex objects e.g. nodes) to be passed to a constructor of 'StorageTypeInput' are possible (NOT case-sensitive!):\n" +
"The following fields (without complex objects e.g. nodes, operators, ...) to be passed to a constructor of 'StorageTypeInput' are possible (NOT case-sensitive!):\n" +
"0: [activepowergradient, capex, cosphirated, dod, estorage, eta, id, lifecycle, lifetime, opex, pmax, srated, uuid]\n"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
*/
package edu.ie3.datamodel.io.source.csv

import edu.ie3.datamodel.io.factory.input.ThermalBusInputFactory
import edu.ie3.datamodel.io.naming.EntityPersistenceNamingStrategy
import edu.ie3.datamodel.models.UniqueEntity
import edu.ie3.datamodel.models.input.NodeInput
import edu.ie3.datamodel.models.input.OperatorInput
import edu.ie3.datamodel.models.input.thermal.ThermalBusInput
import edu.ie3.test.common.GridTestData as gtd
import edu.ie3.test.common.SystemParticipantTestData as sptd
import spock.lang.Shared
Expand Down Expand Up @@ -49,7 +51,7 @@ class CsvDataSourceTest extends Specification {
}

String[] parseCsvRow(
String csvRow,String csvSep) {
String csvRow, String csvSep) {
return super.parseCsvRow(csvRow, csvSep)
}

Expand All @@ -66,18 +68,6 @@ class CsvDataSourceTest extends Specification {

DummyCsvSource dummyCsvSource = new DummyCsvSource(csvSep, testBaseFolderPath, entityPersistenceNamingStrategy)

def "A csv data source returns empty optional, when looking for a specific uuid"() {
given:
def entities = null
def uuid = UUID.randomUUID().toString()

when:
def actual = dummyCsvSource.findFirstEntityByUuid(uuid, entities)

then:
!actual.present
}

def "A csv data source is able to find the correct first entity by uuid"() {
given:
def uuid = UUID.randomUUID()
Expand Down Expand Up @@ -287,43 +277,43 @@ class CsvDataSourceTest extends Specification {
"6.0",
"thats \"good\""
]
"," | "1,abc,def,\"He said \"\"test, test\"\" and was happy\", 5.0" || [
"," | "1,abc,def,\"He said \"\"test, test\"\" and was happy\", 5.0" || [
"1",
"abc",
"def",
"He said \"test, test\" and was happy",
"5.0"
]
"," | "1,abc,def,\"He said \"\"test, test\"\" and was happy\",\"obviously, yet.\", 5.0" || [
"," | "1,abc,def,\"He said \"\"test, test\"\" and was happy\",\"obviously, yet.\", 5.0" || [
"1",
"abc",
"def",
"He said \"test, test\" and was happy",
"obviously, yet.",
"5.0"
]
"," | "1,abc,def,\"He said \"\"test, test\"\"\", 5.0" || [
"," | "1,abc,def,\"He said \"\"test, test\"\"\", 5.0" || [
"1",
"abc",
"def",
"He said \"test, test\"",
"5.0"
]
"," | "1,abc,def,\"He said \"\"test, test\"\"\"" || [
"," | "1,abc,def,\"He said \"\"test, test\"\"\"" || [
"1",
"abc",
"def",
"He said \"test, test\""
]
"," | "1,abc,def,\"He said \"\"test, test\"\" and was happy\", 5.0, \"... and felt like a \"\"genius\"\" with this.\"" || [
"," | "1,abc,def,\"He said \"\"test, test\"\" and was happy\", 5.0, \"... and felt like a \"\"genius\"\" with this.\"" || [
"1",
"abc",
"def",
"He said \"test, test\" and was happy",
"5.0",
"... and felt like a \"genius\" with this."
]
"," | "1,abc,def,\"He said \"\"test, test\"\" and was happy\", 5.0, \"... and felt like a \"\"genius\"\" with this.\"," || [
"," | "1,abc,def,\"He said \"\"test, test\"\" and was happy\", 5.0, \"... and felt like a \"\"genius\"\" with this.\"," || [
"1",
"abc",
"def",
Expand Down Expand Up @@ -452,8 +442,8 @@ class CsvDataSourceTest extends Specification {
where:
noOfEntities || distinctSize || firstElement
0 || 0 || null
10 || 1 || ["uuid" : "4ca90220-74c2-4369-9afa-a18bf068840d",
"geo_position": "{\"type\":\"Point\",\"coordinates\":[7.411111,51.492528],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}}}",
10 || 1 || ["uuid" : "4ca90220-74c2-4369-9afa-a18bf068840d",
"geo_position" : "{\"type\":\"Point\",\"coordinates\":[7.411111,51.492528],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}}}",
"id" : "node_a",
"operates_until": "2020-03-25T15:11:31Z[UTC]",
"operates_from" : "2020-03-24T15:11:31Z[UTC]",
Expand Down Expand Up @@ -497,7 +487,7 @@ class CsvDataSourceTest extends Specification {
]

when:
def allRows = [nodeInputRow1, nodeInputRow2]*10
def allRows = [nodeInputRow1, nodeInputRow2]* 10
def distinctRows = dummyCsvSource.distinctRowsWithLog(allRows, uuidExtractor, NodeInput.simpleName, "UUID")

then:
Expand All @@ -523,4 +513,23 @@ class CsvDataSourceTest extends Specification {
[sptd.chpTypeInput]| ["type": "5ebd8f7e-dedb-4017-bb86-6373c4b68eb8"] || true || sptd.chpTypeInput
}

def "A CsvDataSource should not throw an exception but assume NO_OPERATOR_ASSIGNED if the operator field is missing in the headline"() {

given:
def thermalBusInputFieldsToAttributesMap = [
"uuid" : "0d95d7f2-49fb-4d49-8636-383a5220384e",
"id" : "test_thermalBusInput",
"operatesuntil": "2020-03-25T15:11:31Z[UTC]",
"operatesfrom" : "2020-03-24T15:11:31Z[UTC]"
]

when:
def thermalBusInputEntity = new ThermalBusInputFactory().get(dummyCsvSource.assetInputEntityDataStream(ThermalBusInput, thermalBusInputFieldsToAttributesMap, Collections.emptyList()))

then:
noExceptionThrown() // no NPE should be thrown
thermalBusInputEntity.present
thermalBusInputEntity.get().operator.id == OperatorInput.NO_OPERATOR_ASSIGNED.id // operator id should be set accordingly
}

}