Skip to content
Merged
Show file tree
Hide file tree
Changes from 21 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
20 changes: 20 additions & 0 deletions src/main/java/edu/ie3/datamodel/io/factory/FactoryData.java
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,26 @@ field, getField(field)),
}
}

/**
* Parses and returns an array of UUIDs from field value of given field name. Throws {@link
* FactoryException} if field does not exist or parsing fails.
*
* @param field field name
* @return UUID
*/
public UUID[] getUUIDs(String field) {
try {
String[] uuidFields = field.split(" ");
return Arrays.stream(uuidFields).map(UUID::fromString).toArray(UUID[]::new);
} catch (IllegalArgumentException iae) {
throw new FactoryException(
String.format(
"Exception while trying to parse UUIDs of field \"%s\" with value \"%s\"",
field, getField(field)),
iae);
}
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* © 2022. TU Dortmund University,
* Institute of Energy Systems, Energy Efficiency and Energy Economics,
* Research group Distribution grid planning and operation
*/
package edu.ie3.datamodel.io.factory.input.participant;

import edu.ie3.datamodel.exceptions.ParsingException;
import edu.ie3.datamodel.io.factory.input.NodeAssetInputEntityData;
import edu.ie3.datamodel.models.ControlStrategy;
import edu.ie3.datamodel.models.OperationTime;
import edu.ie3.datamodel.models.input.NodeInput;
import edu.ie3.datamodel.models.input.OperatorInput;
import edu.ie3.datamodel.models.input.system.EmInput;
import edu.ie3.datamodel.models.input.system.characteristic.ReactivePowerCharacteristic;
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class EmInputFactory
extends SystemParticipantInputEntityFactory<EmInput, NodeAssetInputEntityData> {
private static final Logger logger = LoggerFactory.getLogger(EmInputFactory.class);

private static final String CONNECTED_ASSETS = "connectedassets";

private static final String CONTROL_STRATEGY = "controlstrategy";

public EmInputFactory() {
super(EmInput.class);
}

@Override
protected String[] getAdditionalFields() {
return new String[] {CONNECTED_ASSETS, CONTROL_STRATEGY};
}

@Override
protected EmInput buildModel(
NodeAssetInputEntityData data,
UUID uuid,
String id,
NodeInput node,
ReactivePowerCharacteristic qCharacteristics,
OperatorInput operator,
OperationTime operationTime) {
ControlStrategy controlStrategy;
try {
controlStrategy = ControlStrategy.parse(data.getField(CONTROL_STRATEGY));
} catch (ParsingException e) {
logger.warn(
"Cannot parse control strategy \"{}\" of energy management system \"{}\". Assign no control strategy instead.",
data.getField(CONTROL_STRATEGY),
id);
controlStrategy = ControlStrategy.DefaultControlStrategies.NO_CONTROL_STRATEGY;
}
final UUID[] connectedAssets = data.getUUIDs(data.getField(CONNECTED_ASSETS));
return new EmInput(
uuid,
id,
operator,
operationTime,
node,
qCharacteristics,
connectedAssets,
controlStrategy);
}
}
42 changes: 26 additions & 16 deletions src/main/java/edu/ie3/datamodel/io/processor/Processor.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import edu.ie3.datamodel.exceptions.EntityProcessorException;
import edu.ie3.datamodel.io.factory.input.NodeInputFactory;
import edu.ie3.datamodel.io.processor.result.ResultEntityProcessor;
import edu.ie3.datamodel.models.ControlStrategy;
import edu.ie3.datamodel.models.OperationTime;
import edu.ie3.datamodel.models.StandardUnits;
import edu.ie3.datamodel.models.UniqueEntity;
Expand Down Expand Up @@ -272,6 +273,9 @@ protected String processMethodResult(Object methodReturnObject, Method method, S
"ReactivePowerCharacteristic",
"CharacteristicInput" -> resultStringBuilder.append(
((CharacteristicInput<?, ?>) methodReturnObject).deSerialize());
case "UUID[]" -> resultStringBuilder.append(processUUIDArray((UUID[]) methodReturnObject));
case "ControlStrategy" -> resultStringBuilder.append(
((ControlStrategy) methodReturnObject).getKey());
default -> throw new EntityProcessorException(
"Unable to process value for attribute/field '"
+ fieldName
Expand Down Expand Up @@ -330,6 +334,28 @@ protected String handleQuantity(Quantity<?> quantity, String fieldName) {
+ ".class."));
}

/**
* This method should handle all quantities that are model processor specific e.g. we need to
* handle active power p different for {@link edu.ie3.datamodel.models.result.ResultEntity}s and
* {@link edu.ie3.datamodel.models.input.system.SystemParticipantInput}s Hence from the
* generalized method {@link #handleQuantity(Quantity, String)}, this allows for the specific
* handling of child implementations. See the implementation @ {@link ResultEntityProcessor} for
* details.
*
* @param quantity the quantity that should be processed
* @param fieldName the field name the quantity is set to
* @return an optional string with the normalized to {@link StandardUnits} value of the quantity
* or empty if an error occurred during processing
*/
protected abstract Optional<String> handleProcessorSpecificQuantity(
Quantity<?> quantity, String fieldName);

protected String processUUIDArray(UUID[] uuids) {
StringBuilder strb = new StringBuilder();
for (UUID uuid : uuids) strb.append(uuid.toString()).append(" ");
return strb.toString().strip();
}

/**
* Handling of elements of type {@link OperationTime}
*
Expand Down Expand Up @@ -366,22 +392,6 @@ protected String processZonedDateTime(ZonedDateTime zonedDateTime) {
return zonedDateTime.toString();
}

/**
* This method should handle all quantities that are model processor specific e.g. we need to
* handle active power p different for {@link edu.ie3.datamodel.models.result.ResultEntity}s and
* {@link edu.ie3.datamodel.models.input.system.SystemParticipantInput}s Hence from the
* generalized method {@link #handleQuantity(Quantity, String)}, this allows for the specific
* handling of child implementations. See the implementation @ {@link ResultEntityProcessor} for
* details.
*
* @param quantity the quantity that should be processed
* @param fieldName the field name the quantity is set to
* @return an optional string with the normalized to {@link StandardUnits} value of the quantity
* or empty if an error occurred during processing
*/
protected abstract Optional<String> handleProcessorSpecificQuantity(
Quantity<?> quantity, String fieldName);

/**
* Converts a given quantity to String by extracting the value and applying the toString method to
* it
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ public class InputEntityProcessor extends EntityProcessor<InputEntity> {
PvInput.class,
StorageInput.class,
WecInput.class,
EmInput.class,
/* -- ThermalUnitInput */
ThermalHouseInput.class,
CylindricalStorageInput.class,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -390,4 +390,8 @@ Set<HpInput> getHeatPumps(
Set<OperatorInput> operators,
Set<HpTypeInput> types,
Set<ThermalBusInput> thermalBuses);

Set<EmInput> getEmSystems();

Set<EmInput> getEmSystems(Set<NodeInput> nodes, Set<OperatorInput> operators);
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public class CsvSystemParticipantSource extends CsvDataSource implements SystemP
private final StorageInputFactory storageInputFactory;
private final WecInputFactory wecInputFactory;
private final EvcsInputFactory evcsInputFactory;
private final EmInputFactory emInputFactory;

public CsvSystemParticipantSource(
String csvSep,
Expand All @@ -87,6 +88,7 @@ public CsvSystemParticipantSource(
this.storageInputFactory = new StorageInputFactory();
this.wecInputFactory = new WecInputFactory();
this.evcsInputFactory = new EvcsInputFactory();
this.emInputFactory = new EmInputFactory();
}

/** {@inheritDoc} */
Expand Down Expand Up @@ -168,6 +170,11 @@ public Optional<SystemParticipants> getSystemParticipants() {
.filter(isPresentCollectIfNot(HpInput.class, nonBuildEntities))
.map(Optional::get)
.collect(Collectors.toSet());
Set<EmInput> emInputs =
nodeAssetEntityStream(EmInput.class, emInputFactory, nodes, operators)
.filter(isPresentCollectIfNot(EmInput.class, nonBuildEntities))
.map(Optional::get)
.collect(Collectors.toSet());

// if we found invalid elements return an empty optional and log the problems
if (!nonBuildEntities.isEmpty()) {
Expand All @@ -187,7 +194,8 @@ public Optional<SystemParticipants> getSystemParticipants() {
loads,
pvInputs,
storages,
wecInputs));
wecInputs,
emInputs));
}

/** {@inheritDoc} */
Expand Down Expand Up @@ -732,4 +740,30 @@ private Optional<ChpInputEntityData> buildChpEntityData(
thermalBus.get(),
thermalStorage.get()));
}

/** {@inheritDoc} */
@Override
public Set<EmInput> getEmSystems() {
Set<OperatorInput> operators = typeSource.getOperators();
return getEmSystems(rawGridSource.getNodes(operators), operators);
}

/**
* {@inheritDoc}
*
* <p>If the set of {@link NodeInput} entities is not exhaustive for all available {@link
* LoadInput} entities (e.g. a {@link NodeInput} entity is missing) or if an error during the
* building process occurs, the entity that misses something will be skipped (which can be seen as
* a filtering functionality), but all entities that are able to be built will be returned anyway
* and the elements that couldn't have been built are logged.
*
* <p>If the set with {@link OperatorInput} is not exhaustive, the corresponding operator is set
* to {@link OperatorInput#NO_OPERATOR_ASSIGNED}
*/
@Override
public Set<EmInput> getEmSystems(Set<NodeInput> nodes, Set<OperatorInput> operators) {
return filterEmptyOptionals(
nodeAssetEntityStream(EmInput.class, emInputFactory, nodes, operators))
.collect(Collectors.toSet());
}
}
35 changes: 35 additions & 0 deletions src/main/java/edu/ie3/datamodel/models/ControlStrategy.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* © 2022. TU Dortmund University,
* Institute of Energy Systems, Energy Efficiency and Energy Economics,
* Research group Distribution grid planning and operation
*/
package edu.ie3.datamodel.models;

import edu.ie3.datamodel.exceptions.ParsingException;
import java.io.Serializable;
import java.util.Arrays;

public interface ControlStrategy extends Serializable {
String getKey();

static ControlStrategy parse(String key) throws ParsingException {
if (key == null || key.isEmpty())
return ControlStrategy.DefaultControlStrategies.NO_CONTROL_STRATEGY;

String filterKey = key.toLowerCase().replace("-", "_");
return Arrays.stream(EmControlStrategy.values())
.filter(profile -> profile.getKey().equals(filterKey))
.findFirst()
.orElseThrow(
() -> new ParsingException("Cannot parse \"" + key + "\" to a valid control strategy"));
}

enum DefaultControlStrategies implements ControlStrategy {
NO_CONTROL_STRATEGY;

@Override
public String getKey() {
return "No control strategy assigned";
}
}
}
45 changes: 45 additions & 0 deletions src/main/java/edu/ie3/datamodel/models/EmControlStrategy.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* © 2022. TU Dortmund University,
* Institute of Energy Systems, Energy Efficiency and Energy Economics,
* Research group Distribution grid planning and operation
*/
package edu.ie3.datamodel.models;

import java.util.Arrays;
import java.util.Locale;
import java.util.stream.Collectors;

public enum EmControlStrategy implements ControlStrategy {
SELF_OPTIMIZATION("self_optimization");

private final String key;

EmControlStrategy(String key) {
this.key = key.toLowerCase(Locale.ROOT);
}

public static EmControlStrategy get(String key) {
return Arrays.stream(EmControlStrategy.values())
.filter(controlStrategy -> controlStrategy.key.equalsIgnoreCase(key))
.findFirst()
.orElseThrow(
() ->
new IllegalArgumentException(
"No predefined energy management control strategy '"
+ key
+ "' found. Please provide one of the following keys: "
+ Arrays.stream(EmControlStrategy.values())
.map(EmControlStrategy::getKey)
.collect(Collectors.joining(", "))));
}

@Override
public String getKey() {
return key;
}

@Override
public String toString() {
return "EmControlStrategy{" + "key='" + key + '\'' + '}';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public class SystemParticipants implements InputContainer<SystemParticipantInput
private final Set<PvInput> pvPlants;
private final Set<StorageInput> storages;
private final Set<WecInput> wecPlants;
private final Set<EmInput> emSystems;

public SystemParticipants(
Set<BmInput> bmPlants,
Expand All @@ -35,7 +36,8 @@ public SystemParticipants(
Set<LoadInput> loads,
Set<PvInput> pvPlants,
Set<StorageInput> storages,
Set<WecInput> wecPlants) {
Set<WecInput> wecPlants,
Set<EmInput> emSystems) {
this.bmPlants = bmPlants;
this.chpPlants = chpPlants;
this.evCS = evCS;
Expand All @@ -46,6 +48,7 @@ public SystemParticipants(
this.pvPlants = pvPlants;
this.storages = storages;
this.wecPlants = wecPlants;
this.emSystems = emSystems;
}

/**
Expand Down Expand Up @@ -94,6 +97,10 @@ public SystemParticipants(Collection<SystemParticipants> systemParticipants) {
systemParticipants.stream()
.flatMap(participants -> participants.wecPlants.stream())
.collect(Collectors.toSet());
this.emSystems =
systemParticipants.stream()
.flatMap(participants -> participants.emSystems.stream())
.collect(Collectors.toSet());
}

/**
Expand Down Expand Up @@ -155,6 +162,11 @@ public SystemParticipants(List<SystemParticipantInput> systemParticipants) {
.filter(WecInput.class::isInstance)
.map(WecInput.class::cast)
.collect(Collectors.toSet());
this.emSystems =
systemParticipants.parallelStream()
.filter(EmInput.class::isInstance)
.map(EmInput.class::cast)
.collect(Collectors.toSet());
}

@Override
Expand Down Expand Up @@ -223,6 +235,10 @@ public Set<WecInput> getWecPlants() {
return Collections.unmodifiableSet(wecPlants);
}

public Set<EmInput> getEmSystems() {
return Collections.unmodifiableSet(emSystems);
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
Expand Down
Loading