diff --git a/cta-optimizer/Readme.md b/cta-optimizer/Readme.md new file mode 100644 index 00000000..3bcc3d25 --- /dev/null +++ b/cta-optimizer/Readme.md @@ -0,0 +1,31 @@ + README for Corrective Topological Actions optimizer + + +CTA version 1.0, June 8, 2016 +Copyright (C) 2016, Tractebel Engineering SA +All rights reserved + + +The Corrective Topological Actions optimizer (CTA) is a proprietary software of TRACTEBEL ENGINEERING S.A. + + +It is integrated into the iTesla Power System Tool through the “CTA-integration” module. +The CTA-integration module is subject to the terms of the Mozilla Public License, v. 2.0. +If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/ + +The use of the Corrective Topological Actions optimizer (CTA) requires : + +1. A license agreement duly signed with TRACTEBEL ENGINEERING S.A. + + TRACTEBEL freely allows the use of CTA for research projects. + Detailed conditions may be obtained on request to support-eurostag@tractebel.engie.com + +2. A set of configuration files for the module + + They will be delivered by TRACTEBEL after the signature of the license agreement. + +3. The XPRESS solver with support of AMPL + + The CTA optimizer is based on AMPL anonymized scripts. + Those scripts are using the XPRESS solver. + The XPRESS solver must therefore be installed and configured on the hosting computer. diff --git a/cta-optimizer/pom.xml b/cta-optimizer/pom.xml new file mode 100644 index 00000000..aebb7051 --- /dev/null +++ b/cta-optimizer/pom.xml @@ -0,0 +1,193 @@ + + + 4.0.0 + + + eu.itesla_project + itesla-parent + 0.1-SNAPSHOT + + + cta-optimizer + + Corrective Topological Actions optimizer + classes to build optimization problem with cta opitmizer + + + UTF-8 + **/*ITest.java + ${user.home}/share/ipso + /opt/xpressmp + /opt/ampl-9.1 + ${user.home}/Documents/solverResources + ${user.home}/Documents/action-ctg_France_V0.4.xml + ${user.home}/Documents/20130115_1845_SN2_FR0 + 20130115_1845_SN2_FR0 + + + + + ipso-integration-test + + nothingToExclude + + + + + + + junit + junit + + + + org.slf4j + slf4j-api + + + + ch.qos.logback + logback-classic + + + + ${project.groupId} + case-repository + ${project.version} + + + + ${project.groupId} + iidm-network-api + ${project.version} + + + + ${project.groupId} + iidm-network-impl + ${project.version} + + + + ${project.groupId} + iidm-actions-contingencies-xml-client + ${project.version} + + + + ${project.groupId} + iidm-import-export-api + ${project.version} + jar + + + + ${project.groupId} + iidm-xml-import-export + ${project.version} + + + com.google.guava + guava + + + + org.apache.velocity + velocity + 1.7 + + + + + ${project.groupId} + cim1-import + ${project.version} + + + + net.sf.supercsv + super-csv + + + + ${project.groupId} + eurostag-ech-export + ${project.version} + test + + + ${project.groupId} + eurostag-step-up-transformer + ${project.version} + test + + + ${project.groupId} + ucte-import + ${project.version} + test + + + org.apache.commons + commons-lang3 + + + + ${project.groupId} + computation + ${project.version} + + + + ${project.groupId} + modules + ${project.version} + + + + ${project.groupId} + computation-local + ${project.version} + + + + org.mockito + mockito-all + test + + + + + + + + + **/*.properties + + src/test/resources + true + + + + **/*.properties + + src/test/resources + false + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + ${tests.to.exclude} + + + + + + + diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/AbstractBranchModelConverter.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/AbstractBranchModelConverter.java new file mode 100644 index 00000000..a10e04b0 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/AbstractBranchModelConverter.java @@ -0,0 +1,54 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.converter; + +import eu.itesla_project.cta.model.IpsoEquipment; +import eu.itesla_project.iidm.network.CurrentLimits; +import eu.itesla_project.iidm.network.Identifiable; +import eu.itesla_project.iidm.network.TwoTerminalsConnectable; + +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * @author Yannick Pihan + */ + +abstract class AbstractBranchModelConverter extends AbstractModelConverter{ + + protected AbstractBranchModelConverter(ConversionContext context) { + super(context); + } + + protected float findMaxCurrentPermanentLimitFor(TwoTerminalsConnectable connectable) { + checkArgument(connectable != null, "connectable must not be null"); + Optional currentLimits1 = Optional.ofNullable(connectable.getCurrentLimits1()); + Optional currentLimits2 = Optional.ofNullable(connectable.getCurrentLimits2()); + + if (currentLimits1.isPresent() && currentLimits2.isPresent()) { + float perm1 = currentLimits1.get().getPermanentLimit(); + float perm2 = currentLimits2.get().getPermanentLimit(); + + if (!Float.isNaN(perm1) && !Float.isNaN(perm2)) { + return Math.max(perm1,perm2); + } + else if (!Float.isNaN(perm1)) { + return perm1; + }else if(!Float.isNaN(perm2)) { + return perm2; + }else { + return Float.NaN; + } + }else if (currentLimits1.isPresent()) { + return currentLimits1.get().getPermanentLimit(); + } else if (currentLimits2.isPresent()) { + return currentLimits2.get().getPermanentLimit(); + } else { + return Float.NaN; + } + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/AbstractLoadModelConverter.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/AbstractLoadModelConverter.java new file mode 100644 index 00000000..2d3b6066 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/AbstractLoadModelConverter.java @@ -0,0 +1,45 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.converter; + +import eu.itesla_project.cta.model.IpsoLoad; +import eu.itesla_project.cta.model.IpsoNode; +import eu.itesla_project.iidm.network.Bus; +import eu.itesla_project.iidm.network.Equipments; +import eu.itesla_project.iidm.network.Identifiable; +import eu.itesla_project.iidm.network.Load; + +/** + * @author Yannick Pihan + */ +abstract class AbstractLoadModelConverter extends AbstractModelConverter{ + + AbstractLoadModelConverter(ConversionContext context) { + super(context); + } + + protected IpsoLoad convertLoad(Load load) { + + String id = createIpsoId(); + + Equipments.ConnectionInfo info = Equipments.getConnectionInfoInBusBreakerView(load.getTerminal()); + Bus bus = info.getConnectionBus(); + + final IpsoNode ipsoNode = getContext().getMappingBetweenIidmIdAndIpsoEquipment().getIpsoNodeFor(bus).get(); + + final float activePower = load.getTerminal().getP(); + final float reactivePower = load.getTerminal().getQ(); + + return new IpsoLoad( + id, + load.getId(), + ipsoNode, + info.isConnected(), + activePower, + reactivePower, + getContext().getWorld()); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/AbstractModelConverter.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/AbstractModelConverter.java new file mode 100644 index 00000000..4809fdab --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/AbstractModelConverter.java @@ -0,0 +1,121 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.converter; + +import com.google.common.base.Preconditions; +import eu.itesla_project.cta.model.IpsoEquipment; +import eu.itesla_project.iidm.network.Identifiable; +import eu.itesla_project.iidm.network.Network; +import eu.itesla_project.iidm.network.util.Identifiables; +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Yannick Pihan + * + * @param (From) iidm component + * @param (To) ipso component + */ +abstract class AbstractModelConverter implements ModelConverter { + private static final float SNREF = 100.f; + private static final float RATE = 100.f; + private static final int ID_LENGTH_FOR_ONE_CONNECTION_COMPONENT = 8; + private static final int ID_LENGTH_FOR_TWO_CONNECTIONS_COMPONENT = 20; + private final ConversionContext context; + + protected AbstractModelConverter(ConversionContext context) { + Preconditions.checkArgument(context != null, "context cannot be null"); + this.context = context; + } + + @Override + public List convert(Network network) { + List result = new ArrayList<>(); + for (F toConvert : Identifiables.sort(gatherDataToConvertFrom(network))) { + T converted = doConvert(toConvert); + if (converted != null) { + result.add(converted); + addToDictionary(toConvert, converted); + } + } + return result; + } + + @Override + public abstract Iterable gatherDataToConvertFrom(Network network); + + @Override + public String createIpsoId() { + return context.createId(getComponentType(), ID_LENGTH_FOR_ONE_CONNECTION_COMPONENT); + } + + /** + * @return a new Ipso branch id from Ipso nodes ids. + * If the id is already existing in the dictionary then + * the parrallele index of the line is increased. + */ + @Override + public String createIdFrom(String nodeId1, String nodeId2) { + String id12, id21; + int index = 1; + do { + char paralleleIndex = Character.forDigit(index, Character.MAX_RADIX); + id12 = nodeId1 + "-" + nodeId2 + "-" + paralleleIndex; + id21 = nodeId2 + "-" + nodeId1 + "-" + paralleleIndex; + id12 = StringUtils.rightPad(id12, ID_LENGTH_FOR_TWO_CONNECTIONS_COMPONENT); + id21 = StringUtils.rightPad(id21, ID_LENGTH_FOR_TWO_CONNECTIONS_COMPONENT); + index++; + } + while(getContext().getMappingBetweenIidmIdAndIpsoEquipment().containsIpsoId(id12) || + getContext().getMappingBetweenIidmIdAndIpsoEquipment().containsIpsoId(id21)); + + return id12; + } + + @Override + public final ConversionContext getContext() { + return context; + } + + /** + * @return the Ipso compoenent Type + */ + protected abstract ComponentType getComponentType(); + + /** + * Performs the unitary conversion of iidm component to ipso component + * @param toConvert + * @return + */ + protected abstract T doConvert(F toConvert); + + public void addToDictionary(F fromConvert, T toConvert ) { + context.getMappingBetweenIidmIdAndIpsoEquipment().add(getIdOf(fromConvert), toConvert); + } + + protected String getIdOf(F fromConvert) { + return fromConvert.getId(); + } + + /** + * Base power as reference for the ipso network + * @return snref + */ + public static float snref() { + return SNREF; + } + + /** + * Base rate as reference for the ipso network + * @return rate + */ + public static float rate() { + return RATE; + } + +} \ No newline at end of file diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/AbstractNodeModelConverter.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/AbstractNodeModelConverter.java new file mode 100644 index 00000000..d5838203 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/AbstractNodeModelConverter.java @@ -0,0 +1,127 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.converter; + +import eu.itesla_project.cta.model.DataUtil; +import eu.itesla_project.cta.model.IpsoNode; +import eu.itesla_project.cta.model.IpsoNodeType; +import eu.itesla_project.iidm.network.Bus; +import eu.itesla_project.iidm.network.Identifiable; +import eu.itesla_project.iidm.network.VoltageLevel; +import org.apache.commons.lang3.StringUtils; + +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkArgument; +import static java.lang.Float.isNaN; +import static java.util.Optional.of; +/** + * @author Yannick Pihan + * + * Abstract class to createAmplModelFrom iidm identifiable to ipso node + */ +abstract class AbstractNodeModelConverter extends AbstractModelConverter { + + protected static final String EXTERNAL = "EXTERNAL"; + protected static final float DEFAULT_LOW_VOLTAGE_LEVEL = 0.5f; + protected static final float DEFAULT_HIGH_VOLTAGE_LEVEL = 1.5f; + + protected String getIidmId(F identifiable) { + return identifiable.getId(); + } + + /** + * constructor + * @param context of the conversion + */ + protected AbstractNodeModelConverter(ConversionContext context) { + super(context); + } + + protected IpsoNode convertBus(String iidmId, Bus bus) { + + String id = createIpsoId(); + + // getValue area as the id of enumeration constant (EXTERNAL: "FR") + String area = findAreaFor(bus); + // complete area with blank in order to have for 8 characters for macro-region + String area8 = StringUtils.rightPad(area, 8); + + final float baseVoltage = findBaseVoltage(bus); + final float minVoltageLimit = findLowVoltageLevel(bus, baseVoltage); // pu + final float maxVoltageLimit = findHighVoltageLevel(bus, baseVoltage); // pu + + // Set PQ by default (PV or SB nodes will be determined latter) + IpsoNodeType nodeType = IpsoNodeType.PQ; + + return new IpsoNode( + id, + iidmId, + area, + area8, + baseVoltage, + bus == null ? 0.f : bus.getV(), + bus == null ? 0.f : bus.getAngle(), + nodeType, + bus == null ? 0.f : bus.getP(), + bus == null ? 0.f : bus.getQ(), + minVoltageLimit, + maxVoltageLimit, + getContext().getWorld()); + } + + protected String findAreaFor(Bus bus) { + return of(bus) + .map(b -> b.getVoltageLevel().getSubstation().getCountry().name()) + .orElse(EXTERNAL); + } + + protected float findBaseVoltage(Bus bus) { + checkArgument(bus != null, "bus must not be null"); + Optional voltageLevel = getVoltageLevelOf(bus); + if (voltageLevel.isPresent()) { + return voltageLevel.get().getNominalV(); + } + else { + return Float.NaN; + } + } + + private Optional getVoltageLevelOf(Bus bus) { + checkArgument(bus != null, "bus must not be null"); + return Optional.ofNullable(bus.getVoltageLevel()); + } + + protected float findLowVoltageLevel(Bus bus, float baseVoltage) { + checkArgument(bus != null, "bus must not be null"); + if (isNaN(baseVoltage)) { + return DEFAULT_LOW_VOLTAGE_LEVEL; + } else { + Optional voltageLevel = getVoltageLevelOf(bus); + if (voltageLevel.isPresent()){ + return DataUtil.getSafeValueOf(voltageLevel.get().getLowVoltageLimit() / baseVoltage, DEFAULT_LOW_VOLTAGE_LEVEL); + } + else { + return DEFAULT_LOW_VOLTAGE_LEVEL; + } + } + } + + protected float findHighVoltageLevel(Bus bus, float baseVoltage) { + checkArgument(bus != null, "bus must not be null"); + if (isNaN(baseVoltage)) { + return DEFAULT_HIGH_VOLTAGE_LEVEL; + } else { + Optional voltageLevel = getVoltageLevelOf(bus); + if (voltageLevel.isPresent()){ + return DataUtil.getSafeValueOf(voltageLevel.get().getHighVoltageLimit() / baseVoltage, DEFAULT_HIGH_VOLTAGE_LEVEL); + } + else { + return DEFAULT_HIGH_VOLTAGE_LEVEL; + } + } + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/AmplModelFactory.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/AmplModelFactory.java new file mode 100644 index 00000000..40a74c7b --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/AmplModelFactory.java @@ -0,0 +1,586 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.converter; + +import eu.itesla_project.cta.model.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.FileWriter; +import java.io.IOException; +import java.io.Writer; +import java.nio.file.Path; +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import static com.google.common.base.Preconditions.checkArgument; +import static java.lang.Math.*; +import static java.util.stream.Collectors.toList; + +/** + * @author Yannick Pihan + */ +public class AmplModelFactory { + private static final Logger LOG = LoggerFactory.getLogger(AmplModelFactory.class); + protected static final String LINESEPARATOR = System.getProperty("line.separator"); + protected static final String TABSEPARATOR = "\t"; + + + public AmplModel createAmplModelFrom(IpsoNetworkState completeNetworkState, IpsoProblemDefinition ipsoProblemDefinition, List topologicalActions, Path unpluggedLogFile) { + + IpsoNetworkState ipsoNetworkState = completeNetworkState.getInterconnectedVersion(topologicalActions); + logDisconnectedEquipment(completeNetworkState, ipsoNetworkState, unpluggedLogFile); + + AmplModel amplModel = new AmplModel( + // Sets + createAmplGenerators(ipsoNetworkState), + createAmplLoads(ipsoNetworkState), + createAmplCapacitors(ipsoNetworkState), + createAmplNodes(ipsoNetworkState), + createAmplSlackBuses(ipsoNetworkState), + // Branches + createAmplTransfBranches(ipsoNetworkState), + createAmplSimpleBranches(ipsoNetworkState), + createAmplCouplages(ipsoNetworkState), + // Parameters + createAmplNodeParameters(ipsoNetworkState, ipsoProblemDefinition), + createAmplSlackBusesParameters(ipsoNetworkState), + createAmplGeneratorParameters(ipsoNetworkState, ipsoProblemDefinition, topologicalActions), + createAmplLoadParameters(ipsoNetworkState, topologicalActions), + createAmplCapacitorParameters(ipsoNetworkState, topologicalActions), + createAmplBranchParameters(ipsoNetworkState, ipsoProblemDefinition, topologicalActions), + createAmplTransformerParameters(ipsoNetworkState), + createAmplCouplingParameters(ipsoNetworkState, topologicalActions) + ); + + return amplModel; + } + + private void logDisconnectedEquipment(IpsoNetworkState completeNetworkState, IpsoNetworkState filteredNetworkState, Path toPath) { + + try { + + Writer writer = new FileWriter(toPath.toFile()); + + writeToLog(writer, + completeNetworkState.getIpsoNodes().stream() + .filter(node -> !filteredNetworkState.getIpsoNodes().contains(node)) + .collect(toList()), + IpsoNode.class); + + writeToLog(writer, + completeNetworkState.getIpsoBanks().stream() + .filter(node -> !filteredNetworkState.getIpsoBanks().contains(node)) + .collect(toList()), + IpsoBank.class); + + writeToLog(writer, + completeNetworkState.getIpsoLoads().stream() + .filter(node -> !filteredNetworkState.getIpsoLoads().contains(node)) + .collect(toList()), + IpsoLoad.class); + + writeToLog(writer, + completeNetworkState.getIpsoGenerators().stream() + .filter(node -> !filteredNetworkState.getIpsoGenerators().contains(node)) + .collect(toList()), + IpsoGenerator.class); + + writeToLog(writer, + completeNetworkState.getIpsoTwoWindingsTransformers().stream() + .filter(node -> !filteredNetworkState.getIpsoTwoWindingsTransformers().contains(node)) + .collect(toList()), + IpsoTwoWindingsTransformer.class); + + writeToLog(writer, + completeNetworkState.getIpsoLines().stream() + .filter(node -> !filteredNetworkState.getIpsoLines().contains(node)) + .collect(toList()), + IpsoLine.class); + + writeToLog(writer, + completeNetworkState.getIpsoCouplings().stream() + .filter(node -> !filteredNetworkState.getIpsoCouplings().contains(node)) + .collect(toList()), + IpsoCoupling.class); + + writer.close(); + + + } catch (IOException e) { + LOG.error("Cannot write log for disconnected equipments",e); + } + } + + private void writeToLog(Writer writer, Collection equipmentsToLog, Class classOfEquipmentsToLog) throws IOException { + StringBuilder builder = new StringBuilder(LINESEPARATOR); + builder.append(classOfEquipmentsToLog.getSimpleName()); + builder.append(": "); + builder.append(LINESEPARATOR); + + equipmentsToLog.stream() + .forEach(equipment -> builder.append(TABSEPARATOR) + .append(equipment.getId()) + .append(LINESEPARATOR)); + + writer.write(builder.toString()); + } + + private List createAmplCapacitorParameters(IpsoNetworkState ipsoNetworkState, List topologicalActions) { + return ipsoNetworkState.getIpsoBanks().stream() + .map(bank -> createAmplCapacitorParameter(bank, topologicalActions)) + .collect(Collectors.toList()); + } + + private AmplCapacitorParameters createAmplCapacitorParameter(IpsoBank bank, List topologicalActions) { + return new AmplCapacitorParameters( + bank.getId(), + bank.getConnectedNode().getId(), + bank.isConnected(), + findReconfigurationState(bank, topologicalActions), + 0, + bank.getMaxSteps(), + bank.getSelectedSteps(), + bank.getActivePöwerByStep()/100, + bank.getReactivePowerByStep()/100 + ); + } + + + private List createAmplCapacitors(IpsoNetworkState ipsoNetworkState) { + return ipsoNetworkState.getIpsoBanks().stream() + .map(IpsoBank::getId) + .map(AmplCapacitor::new) + .collect(Collectors.toList()); + } + + + /* + * Sets creation + **/ + // Generators set + private List createAmplGenerators(IpsoNetworkState networkState) { + return networkState.getIpsoGenerators().stream() + .map(IpsoGenerator::getId) + .map(AmplGenerator::new) + .collect(toList()); + } + + // Loads set + private List createAmplLoads(IpsoNetworkState networkState) { + return networkState.getIpsoLoads().stream() + .map(IpsoLoad::getId) + .map(AmplLoad::new) + .collect(toList()); + } + + // Nodes Set + private List createAmplNodes(IpsoNetworkState networkState) { + return networkState.getIpsoNodes().stream() + .map(node -> new AmplSimpleNode(node.getId())) + .collect(toList()); + } + + // Slackbus set + private List createAmplSlackBuses(IpsoNetworkState networkState) { + return networkState.getIpsoNodes().stream() + .filter(IpsoNode::isSlackBus) + .distinct() + .map(IpsoNode::getId) + .map(AmplSlackBus::new) + .collect(toList()); + } + + /** + * Branches sets + */ + + // Transformer branches + private List createAmplTransfBranches(IpsoNetworkState ipsoNetworkState) { + return ipsoNetworkState.getIpsoTwoWindingsTransformers().stream() + .map(IpsoTwoWindingsTransformer::getId) + .distinct() + .map(AmplTransformerBranch::new) + .collect(toList()); + } + + // Couplages + private List createAmplSimpleBranches(IpsoNetworkState ipsoNetworkState) { + return ipsoNetworkState.getIpsoLines().stream() + .map(IpsoLine::getId) + .distinct() + .map(AmplSimpleBranch::new) + .collect(toList()); + } + + // Slackbuses + private List createAmplCouplages(IpsoNetworkState ipsoNetworkState) { + return ipsoNetworkState.getIpsoCouplings().stream() + .map(IpsoCoupling::getId) + .distinct() + .map(AmplCouplage::new) + .collect(toList()); + } + + // Nodes Parameters + private List createAmplNodeParameters(IpsoNetworkState ipsoNetworkState, IpsoProblemDefinition ipsoProblemDefinition) { + return ipsoNetworkState.getIpsoNodes() + .stream() + .distinct() + .map(ipsoNode -> createAmplNodeParameter(ipsoNode, ipsoProblemDefinition)) + .collect(toList()); + } + + private AmplNodeParameter createAmplNodeParameter(IpsoNode ipsoNode, IpsoProblemDefinition ipsoProblemDefinition) { + Optional constraint = ipsoProblemDefinition.getConstraintNodeAcVoltageBounds().stream() + .filter(containsConstraintOn(ipsoNode)) + .findFirst(); + + final float vMin = getBoundMinFor(constraint); + + final float vInit = DataUtil.getSafeValueOf(ipsoNode.getVoltage() / ipsoNode.getBaseVoltage(), 0f); + + final float vMax = getBoundMaxFor(constraint); + + final float vNom = DataUtil.getSafeValueOf(ipsoNode.getBaseVoltage(), 0f); + + final float initialTH = (float)(DataUtil.getSafeValueOf(ipsoNode.getAngle(), 0f) * PI / 180); + + + return new AmplNodeParameter(ipsoNode.getId(), vMin, vInit, vMax, vNom, initialTH); + } + + // Slack Buses Parameters + private List createAmplSlackBusesParameters(IpsoNetworkState ipsoNetworkState) { + return ipsoNetworkState.getIpsoNodes().stream() + .filter(IpsoNode::isSlackBus) + .distinct() + .map(this::createAmplSlackBusParameter) + .collect(Collectors.toList()); + } + + + private AmplSlackBusParameters createAmplSlackBusParameter(IpsoNode sb) { + return new AmplSlackBusParameters(sb.getId(), (float)(sb.getAngle() * PI / 180), (float)(sb.getAngle() * PI / 180)); + } + + // Generators Parameters + private List createAmplGeneratorParameters(IpsoNetworkState ipsoNetworkState, IpsoProblemDefinition ipsoProblemDefinition, List topologicalActions) { + return ipsoNetworkState.getIpsoGenerators().stream() + .distinct() + .map(generator -> createAmplGeneratorParameter(generator, ipsoProblemDefinition, topologicalActions)) + .collect(Collectors.toList()); + + } + + private AmplGeneratorParameters createAmplGeneratorParameter(IpsoGenerator generator, IpsoProblemDefinition ipsoProblemDefinition, List topologicalActions) { + + Optional reactivePowerConstraint = ipsoProblemDefinition.getConstraintGeneratorQBounds().stream() + .filter(containsConstraintOn(generator)) + .findFirst(); + + final IpsoNode connectedNode = generator.getConnectedNode(); + + final float pgMin = connectedNode.isSlackBus() ? + Float.NEGATIVE_INFINITY : + generator.getActivePower() / 100f; + + final float pgMax = connectedNode.isSlackBus() ? + Float.POSITIVE_INFINITY : + generator.getActivePower() / 100f; + + final float qgMin = connectedNode.isSlackBus() ? + Float.NEGATIVE_INFINITY : + (reactivePowerConstraint.isPresent() ? + reactivePowerConstraint.get().getBoundsMin()/100f : + generator.getReactivePower() / 100f); + + final float qgMax = connectedNode.isSlackBus() ? + Float.POSITIVE_INFINITY : + (reactivePowerConstraint.isPresent() ? + reactivePowerConstraint.get().getBoundsMax()/100f : + generator.getReactivePower() / 100f); + + return new AmplGeneratorParameters( + generator.getId(), + connectedNode.getId(), + pgMin, // PGmin + generator.getActivePower()/100f, // Initial_P + pgMax, // PGmax + qgMin, + generator.getReactivePower()/100f, + qgMax, + generator.isConnected(), + findReconfigurationState(generator, topologicalActions), + 1.0f, + 1000f + ); + } + + // Loads Parameters + private List createAmplLoadParameters(IpsoNetworkState ipsoNetworkState, List topologicalActions) { + return ipsoNetworkState.getIpsoLoads().stream() + .distinct() + .map(load -> createAmplLoadParameter(load, topologicalActions)) + .collect(Collectors.toList()); + + } + + private AmplLoadParameters createAmplLoadParameter(IpsoLoad load, List topologicalActions) { + final IpsoNode connectedNode = load.getConnectedNode(); + + final float initialDL = 0f; + + final float dlMax = 1.0f; + + final float wDL = 100f; + + return new AmplLoadParameters( + load.getId(), + connectedNode.getId(), + load.isConnected(), + findReconfigurationState(load, topologicalActions), + load.getActivePower() / 100, + load.getReactivePower() / 100, + initialDL, + dlMax, + wDL + ); + } + + /* + * Branch Parameters + */ + private List createAmplBranchParameters(IpsoNetworkState ipsoNetworkState, IpsoProblemDefinition ipsoProblemDefinition, List topologicalActions) { + List result = createAmplBranchParametersFromLines(ipsoNetworkState, ipsoProblemDefinition, topologicalActions); + result.addAll( + createAmplBranchParametersFromTransformers(ipsoNetworkState, ipsoProblemDefinition, topologicalActions) + ); + + return result; + } + + private List createAmplBranchParametersFromTransformers(IpsoNetworkState networkState, IpsoProblemDefinition problemDefinition, List topologicalActions) { + return networkState.getIpsoTwoWindingsTransformers().stream() + .distinct() + .map(transfo -> createAmplBranchParametersFromTransformer(problemDefinition, transfo, topologicalActions)) + .collect(Collectors.toList()); + } + + private AmplBranchParameters createAmplBranchParametersFromTransformer(IpsoProblemDefinition problemDefinition, IpsoTwoWindingsTransformer transformer, List topologicalActions) { + Optional constraint = problemDefinition.getConstraint2WTransformerFlows().stream() + .filter(containsConstraintOn(transformer)) + .findFirst(); + + int initialTapIndex = transformer.getIndexes().indexOf(transformer.getInitialTap()); + + float uccForInitialTap = transformer.getUccs().get(initialTapIndex); + + float y = abs(100f/uccForInitialTap ); + + float zeta = uccForInitialTap > 0 ? + getZetaFromTransformer(uccForInitialTap, transformer.getCuLosses()) + : (float)-(PI/2); + + return new AmplBranchParameters( + transformer.getId(), + transformer.getIpsoNode1().getId(), + transformer.getIpsoNode2().getId(), + y, + zeta, + transformer.getFeLosses() / 100f, // g_sh + getBShFromTransformer(transformer.getFeLosses(), transformer.getMagnetizingCurrent()), // b_sh + transformer.isConnected(), // InitConfig + findReconfigurationState(transformer, topologicalActions), // CanReconfig + 9999f, // P_MaxFlow + 9999f, // Q_MaxFlow + 9999f, // S_MaxFlow + getMaxFlow(transformer.getIpsoNode1(), constraint), // I_MaxFlow_OR + getMaxFlow(transformer.getIpsoNode2(), constraint) // I_MaxFlow_DE + ); + } + + private List createAmplBranchParametersFromLines(IpsoNetworkState ipsoNetworkState, IpsoProblemDefinition ipsoProblemDefinition, List topologicalActions) { + return ipsoNetworkState.getIpsoLines().stream() + .distinct() + .map(line -> createAmplBranchParametersFromLine(ipsoProblemDefinition, line, topologicalActions)) + .collect(Collectors.toList()); + } + + private AmplBranchParameters createAmplBranchParametersFromLine(IpsoProblemDefinition ipsoProblemDefinition, IpsoLine line, List topologicalActions) { + Optional constraint = ipsoProblemDefinition.getConstraintLineFlows().stream() + .filter(containsConstraintOn(line)) + .findFirst(); + + final float y = 100f / (float) sqrt( + pow((double) line.getResistance(), 2d) + + pow((double) line.getReactance(), 2d)); + + final float zeta = (float) atan(line.getReactance() / line.getResistance()); + + return new AmplBranchParameters( + line.getId(), + line.getIpsoNode1().getId(), + line.getIpsoNode2().getId(), + y, + zeta, + line.getSemiConductance() / 100f, // g_sh + line.getSemiSusceptance() / 100f, // b_sh + line.isConnected(), + findReconfigurationState(line, topologicalActions), + 9999f, + 9999f, + 9999f, + getMaxFlow(line.getIpsoNode1(), constraint), // I_MaxFlow_OR + getMaxFlow(line.getIpsoNode2(), constraint) // I_MaxFlow_DE + ); + } + + // Transformers parameters + private List createAmplTransformerParameters(IpsoNetworkState networkState) { + return networkState.getIpsoTwoWindingsTransformers().stream() + .distinct() + .map(this::createAmplTransformerParameter) + .collect(Collectors.toList()); + } + + private AmplTransformerParameters createAmplTransformerParameter(IpsoTwoWindingsTransformer transformer) { + + final float r = getInitialRForTransformer(transformer) * (transformer.getIpsoNode1().getBaseVoltage() / transformer.getIpsoNode2().getBaseVoltage()); + final float phaseMin = getPhaseMinForTransformer(transformer); + final float tapMin = transformer.getLowStep(); + final float tapMax = transformer.getHighStep(); + final float phaseByTap = getPhaseByTapForTransformer(transformer); + + return new AmplTransformerParameters( + transformer.getId(), + r, + r, + r, + transformer.getInitialTap(), + tapMin, + tapMax, + phaseMin, + phaseByTap + ); + } + + // Coupling parameters + private List createAmplCouplingParameters(IpsoNetworkState ipsoNetworkState, List topologicalActions) { + return ipsoNetworkState.getIpsoCouplings().stream() + .distinct() + .map(couplage -> createAmplCouplingParameter(couplage, topologicalActions)) + .collect(Collectors.toList()); + } + + private AmplCouplingParameters createAmplCouplingParameter(IpsoCoupling couplage, List topologicalActions) { + return new AmplCouplingParameters( + couplage.getId(), + couplage.getIpsoNode1().getId(), + couplage.getIpsoNode2().getId(), + couplage.isConnected(), + findReconfigurationState(couplage, topologicalActions) + ); + } + + /** + **Auxialiary Methods + **/ + + private float getMaxFlow(IpsoNode node, Optional constraint) { + if ( constraint.isPresent()) { + return constraint.get().getMaxFlow() * + (float) sqrt(3d) * + DataUtil.getSafeValueOf(node.getBaseVoltage(), 0f) + / 100000f; + } + else { + return 0f; // If not present, Vnom = 0f (default value)AbstractIpsoConstraintLineFlow.DEFAULT_BOUND_MAX + } + + } + + private float getBoundMinFor(Optional constraint) { + if ( constraint.isPresent()) { + return constraint.get().getBoundsMin(); + } + else { + return IpsoConstraintNodeAcVoltageBounds.DEFAULT_BOUND_MIN; + } + } + + private float getBoundMaxFor(Optional constraint) { + if (constraint.isPresent()) { + return constraint.get().getBoundsMax(); + } else { + return IpsoConstraintNodeAcVoltageBounds.DEFAULT_BOUND_MAX; + } + } + + private Predicate containsConstraintOn(IpsoEquipment equipment) { + return constraint -> constraint.getRelatedIpsoEquipment().equals(equipment); + } + + private Predicate notIn(List generatorNodes) { + return ipsoNode -> !generatorNodes.contains(ipsoNode); + } + + private float getZetaFromTransformer(Float uccForInitialTap, float cuLosses) { + return (float) atan(sqrt(pow(uccForInitialTap, 2) - (pow(cuLosses, 2)))/ cuLosses); + } + + + private float getBShFromTransformer(float feLosses, float magnetizingCurrent) { + return magnetizingCurrent >= feLosses ? + (float) sqrt(pow(magnetizingCurrent, 2) - pow(feLosses, 2)) / 100f: + 0f; + } + + private float getPhaseMinForTransformer(IpsoTwoWindingsTransformer transformer) { + return transformer.getPhases().size() > 0 ? + (float)(transformer.getPhases().get(0) * PI / 180): + 0f; + } + + private float getPhaseByTapForTransformer(IpsoTwoWindingsTransformer transformer) { + return transformer.getPhases().size() > 1 ? + (float)((transformer.getPhases().get(1) - transformer.getPhases().get(0)) * PI / 180): + 0f; + } + + private float getInitialRForTransformer(IpsoTwoWindingsTransformer transformer) { + try { + int initialTapIndex = transformer.getIndexes().indexOf(transformer.getInitialTap()); + return transformer.getVoltages_side2().get(initialTapIndex) / + transformer.getVoltages_side1().get(initialTapIndex); + } + catch(Exception e) { + return 0f; + } + } + + private boolean findReconfigurationState(AbstractIpsoBranch branch, List topologicalActions) { + checkArgument(branch != null, "branch must not be null"); + return topologicalActions.stream() + .filter(action -> action.getEquipmentId() == branch.getId()) + .anyMatch(isOppositeTo(branch.isConnected())); + } + + private boolean findReconfigurationState(IpsoOneConnectionEquipment connection, List topologicalActions) { + checkArgument(connection != null, "connection must not be null"); + return topologicalActions.stream() + .filter(action -> action.getEquipmentId() == connection.getId()) + .anyMatch(isOppositeTo(connection.isConnected())); + } + + private Predicate isOppositeTo(boolean connected) { + return topologicalAction -> topologicalAction.getSwitchAction().isOppositeTo(connected); + } + +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/BankModelConverter.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/BankModelConverter.java new file mode 100644 index 00000000..5cb9b3dd --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/BankModelConverter.java @@ -0,0 +1,69 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.converter; + +import eu.itesla_project.cta.model.IpsoBank; +import eu.itesla_project.cta.model.IpsoNode; +import eu.itesla_project.iidm.network.Bus; +import eu.itesla_project.iidm.network.Equipments; +import eu.itesla_project.iidm.network.Network; +import eu.itesla_project.iidm.network.ShuntCompensator; + +/** + * @author Yannick Pihan + * + * Bank (ShuntCompensator) converter + */ +class BankModelConverter extends AbstractModelConverter{ + + BankModelConverter(ConversionContext context) { + super(context); + } + + @Override + protected IpsoBank doConvert(ShuntCompensator shunt) { + + String id = createIpsoId(); + + Equipments.ConnectionInfo info = + Equipments.getConnectionInfoInBusBreakerView(shunt.getTerminal()); + Bus bus = info.getConnectionBus(); + boolean connected = info.isConnected(); + final IpsoNode ipsoNode = getContext().getMappingBetweenIidmIdAndIpsoEquipment().getIpsoNodeFor(bus).get(); + + int maxSteps = shunt.getMaximumSectionCount(); + //...number of steps in service + int selectedSteps = shunt.getCurrentSectionCount(); + + //...no active lost in the iidm shunt compensator + float activePöwerByStep = 0.f; + //...getValue vnom on the connected node + float vnom = shunt.getTerminal().getVoltageLevel().getNominalV(); + //...reactive power of each step [Mvar] + float reactivePowerByStep = vnom*vnom * shunt.getMaximumB() + / shunt.getMaximumSectionCount(); + + return new IpsoBank(id, + shunt.getId(), + ipsoNode, + connected, + maxSteps, + selectedSteps, + activePöwerByStep, + reactivePowerByStep, + getContext().getWorld()); + } + + @Override + public Iterable gatherDataToConvertFrom(Network network) { + return network.getShunts(); + } + + @Override + protected ComponentType getComponentType() { + return ComponentType.BANK; + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/ComponentType.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/ComponentType.java new file mode 100644 index 00000000..2da26802 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/ComponentType.java @@ -0,0 +1,34 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.converter; + +/** + * @author Yannick Pihan + */ +public enum ComponentType { + NETWORK('A'), + NODE('N'), + XNODE('X'), + LINE('-'), + DANGLING_LINE('-'), + TWO_WINDINGS_TRANSFORMER('-'), + THREE_WINDINGS_TRANSFORMER('-'), + COUPLING('-'), + GENERATOR('G'), + LOAD('L'), + XLOAD('Z'), + BANK('B'); + + private char type; + + ComponentType(char type) { + this.type = type; + } + + public char getChar() { + return type; + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/ConversionContext.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/ConversionContext.java new file mode 100644 index 00000000..7cd6f885 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/ConversionContext.java @@ -0,0 +1,84 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.converter; + +import com.google.common.base.Preconditions; + +import java.util.HashMap; +import java.util.Map; +/** + * @author Yannick Pihan + */ +public class ConversionContext { + + private MappingBetweenIidmIdAndIpsoEquipment mappingBetweenIidmIdAndIpsoEquipment; + + private Map indexByPrefix = new HashMap<>(); + private String caseName; + + /** + * constructor + */ + public ConversionContext(String caseName) { + Preconditions.checkArgument(caseName != null, "caseName cannot be null"); + this.mappingBetweenIidmIdAndIpsoEquipment = new MappingBetweenIidmIdAndIpsoEquipment(); + this.caseName = caseName; + } + + /** + * Create a unique name by Ipso component types + * @param componentType, an enumeration to identify NODE, LINE, ... + * @param nameMaxLength, the max length of the generated name + * @return the generated name + */ + public String createId(ComponentType componentType, int nameMaxLength) { + // increase the index associeted to the component (through its prefix) + char prefix = componentType.getChar(); + int increasedIndex = increaseIndexFor(prefix); + // compute the length of the name + int nameLength = nameMaxLength - 1; + return String.format("%s%0" + nameLength + "d" , + prefix, + increasedIndex); + } + + /** + * Increase index value associated to a prefix + * @param prefix + * @return increased index + */ + private int increaseIndexFor(char prefix) { + int index = 0; + if ( indexByPrefix.containsKey(prefix)) { + index = indexByPrefix.get(prefix) + 1; + indexByPrefix.put(prefix, index); + } + else { + indexByPrefix.put(prefix, index); + } + return index; + } + + public MappingBetweenIidmIdAndIpsoEquipment getMappingBetweenIidmIdAndIpsoEquipment() { + return mappingBetweenIidmIdAndIpsoEquipment; + } + + int getWorld() { + return 0; + } + + /** + * Should be a ressource such as Eurostag export + * @return flase by default + */ + public boolean isNoGeneratorMinMaxQ() { + return false; + } + + String getCaseName() { + return caseName; + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/CouplingDeviceModelConverter.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/CouplingDeviceModelConverter.java new file mode 100644 index 00000000..481c17b4 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/CouplingDeviceModelConverter.java @@ -0,0 +1,81 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.converter; + +import eu.itesla_project.commons.ITeslaException; +import eu.itesla_project.cta.model.IpsoCoupling; +import eu.itesla_project.cta.model.IpsoNode; +import eu.itesla_project.iidm.network.Bus; +import eu.itesla_project.iidm.network.Network; +import eu.itesla_project.iidm.network.Switch; +import eu.itesla_project.iidm.network.VoltageLevel; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +/** + * @author Yannick Pihan + */ +public class CouplingDeviceModelConverter extends AbstractModelConverter{ + + final class ConnectionBuses { + private Bus from; + private Bus to; + public ConnectionBuses(Bus from, Bus to) { + this.from = from; + this.to = to; + } + + public Bus getFrom() { + return from; + } + + public Bus getTo() { + return to; + } + } + + private Map swtichConnectivities = new HashMap<>(); + + CouplingDeviceModelConverter(ConversionContext context) { + super(context); + } + + @Override + public Iterable gatherDataToConvertFrom(Network network) { + List switches = new ArrayList<>(); + for (VoltageLevel vl : network.getVoltageLevels()) { + for (Switch s : vl.getBusBreakerView().getSwitches()) { + Bus b1 = vl.getBusBreakerView().getBus1(s.getId()); + Bus b2 = vl.getBusBreakerView().getBus2(s.getId()); + swtichConnectivities.put(s.getId(), new ConnectionBuses(b1, b2)); + switches.add(s); + } + } + return switches; + } + + @Override + protected ComponentType getComponentType() { + return ComponentType.COUPLING; + } + + @Override + protected IpsoCoupling doConvert(Switch iidmSwitch) { + // getValue connection buses + ConnectionBuses buses = swtichConnectivities.get(iidmSwitch.getId()); + if (buses == null) throw new ITeslaException(String.format("No connectivies found for %s", iidmSwitch.getId())); + + final IpsoNode ipsoNode1 = getContext().getMappingBetweenIidmIdAndIpsoEquipment().getIpsoNodeFor(buses.getFrom()).get(); + final IpsoNode ipsoNode2 = getContext().getMappingBetweenIidmIdAndIpsoEquipment().getIpsoNodeFor(buses.getTo()).get(); + String id = createIdFrom(ipsoNode1.getId(), ipsoNode2.getId()); + + final boolean connected = !iidmSwitch.isOpen(); + return new IpsoCoupling(id, iidmSwitch.getId(), ipsoNode1, ipsoNode2, connected, getContext().getWorld()); + } + +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/DanglingLineModelConverter.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/DanglingLineModelConverter.java new file mode 100644 index 00000000..f3c1ace5 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/DanglingLineModelConverter.java @@ -0,0 +1,122 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.converter; + +import com.google.common.collect.Iterables; +import eu.itesla_project.commons.ITeslaException; +import eu.itesla_project.cta.model.DataUtil; +import eu.itesla_project.cta.model.IpsoLine; +import eu.itesla_project.cta.model.IpsoNode; +import eu.itesla_project.iidm.network.Bus; +import eu.itesla_project.iidm.network.DanglingLine; +import eu.itesla_project.iidm.network.Equipments; +import eu.itesla_project.iidm.network.Network; + +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkArgument; +/** + * @author Yannick Pihan + */ +class DanglingLineModelConverter extends AbstractModelConverter { + + protected DanglingLineModelConverter(ConversionContext context) { + super(context); + } + + /** + * @return ipso danglingLine + */ + @Override + public IpsoLine doConvert(DanglingLine danglingLine) { + checkArgument(danglingLine != null, "danglingLine must not be null"); + checkArgument(danglingLine.getTerminal() != null, "danglingLine.getTerminal() must not be null"); + + Equipments.ConnectionInfo info1 = Equipments.getConnectionInfoInBusBreakerView(danglingLine.getTerminal()); + + Bus bus1 = info1.getConnectionBus(); + + Optional ipsoNodeFrom = getMapping().getIpsoNodeFor(bus1); + Optional ipsoNodeTo = getMapping().getIpsoNodeFor(getFictiveBusIdFor(danglingLine)); + + if (ipsoNodeFrom.isPresent() && ipsoNodeTo.isPresent()) { + IpsoNode ipsoNode1 = ipsoNodeFrom.get(); + IpsoNode ipsoNode2 = ipsoNodeTo.get(); + + String id = createIdFrom(ipsoNode1.getId(), ipsoNode2.getId()); + + float vnom = getVnom(danglingLine); + final float vnomPow2 = (float) Math.pow(vnom, 2); + float Rpu = (danglingLine.getR() * snref()) / vnomPow2; //...total danglingLine resistance [p.u.] + float Xpu = (danglingLine.getX() * snref()) / vnomPow2; //...total danglingLine reactance [p.u.] + float Gpu = (danglingLine.getG() / snref()) * vnomPow2; //...semi shunt conductance [p.u.] + float Bpu = (danglingLine.getB() / snref()) * vnomPow2; //...semi shunt susceptance [p.u.] + + // x 100 to createAmplModelFrom pu to percent of pu, in order to be compliant with PSA format (used by IPSO) + Rpu = Rpu * 100.0f; + Xpu = Xpu * 100.0f; + Gpu = Gpu * 100.0f; + Bpu = Bpu * 100.0f; + + final int world = getContext().getWorld(); + final float currentFlow = danglingLine.getTerminal().getI(); + return new IpsoLine( + id, + danglingLine.getId(), + ipsoNode1, + ipsoNode2, + info1.isConnected(), + true, + Rpu, + Xpu, + Gpu, + Bpu, + findMaxCurrentPermanentLimitFor(danglingLine), + currentFlow, + currentFlow, + world); + } else { + return null; + } + } + + private float findMaxCurrentPermanentLimitFor(DanglingLine danglingLine) { + if (danglingLine.getCurrentLimits() != null) { + return danglingLine.getCurrentLimits().getPermanentLimit(); + } + else { + return Float.NaN; + } + } + + /** + * @return Nominal Voltage [Kv] + */ + private static float getVnom( DanglingLine danglingLine ) { + Iterable buses = danglingLine.getTerminal().getVoltageLevel().getBusBreakerView().getBuses(); + final Bus bus = Iterables.getFirst(buses, null); + if ( bus == null ) throw new ITeslaException("getVnom cannot get bus of the same voltage level"); + return DataUtil.getSafeValueOf(bus.getVoltageLevel().getNominalV()); + } + + @Override + protected ComponentType getComponentType() { + return ComponentType.DANGLING_LINE; + } + + @Override + public Iterable gatherDataToConvertFrom(Network network) { + return network.getDanglingLines(); + } + + private String getFictiveBusIdFor(DanglingLine danglingLine) { + return IpsoConverterUtil.getFictiveBusIdFor(danglingLine); + } + + private MappingBetweenIidmIdAndIpsoEquipment getMapping() { + return getContext().getMappingBetweenIidmIdAndIpsoEquipment(); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/GeneratorConverter.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/GeneratorConverter.java new file mode 100644 index 00000000..b2c50e6a --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/GeneratorConverter.java @@ -0,0 +1,133 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.converter; + +import eu.itesla_project.cta.model.DataUtil; +import eu.itesla_project.cta.model.IpsoGenerator; +import eu.itesla_project.cta.model.IpsoNode; +import eu.itesla_project.iidm.network.*; +import eu.itesla_project.iidm.network.util.Identifiables; + +import java.util.ArrayList; +import java.util.List; + +import static com.google.common.base.Preconditions.checkArgument; +/** + * @author Yannick Pihan + */ +class GeneratorConverter extends AbstractModelConverter{ + private static final int REACTIVE_POWER_LOWER_LIMIT = -9999; + private static final int REACTIVE_POWER_UPPER_LIMIT = 9999; + + private int generatorCounter = 0; + private int biggestGeneratorIndex = 0; + private float biggestActivePower = 0f; + + GeneratorConverter(ConversionContext context) { + super(context); + } + + /** + * Convert iidm generator to Ipso generator . + * Moreover, the conversion performs the research of + * macro region as internal or external and de type PV, SB or PQ for nodes + * + * @param network + * @return list of node for ipso + */ + @Override + public List convert(Network network) { + checkArgument(network != null, "network cannto be null"); + List ipsoGenerators = new ArrayList<>(); + + for(Generator generator : Identifiables.sort(gatherDataToConvertFrom(network)) ) { + identifyBiggestGenerator(generator); + + // createAmplModelFrom it to Ipso generator + final IpsoGenerator ipsoGenerator = this.doConvert(generator); + ipsoGenerators.add(ipsoGenerator); + addToDictionary(generator, ipsoGenerator); + + generatorCounter++; + } + + defineBiggestGenerator(ipsoGenerators); + return ipsoGenerators; + } + + private void identifyBiggestGenerator(Generator generator) { + if ( isConnected(generator)) { + if (this.biggestActivePower < DataUtil.getSafeValueOf(generator.getTargetP())) { + this.biggestActivePower = generator.getTargetP(); + this.biggestGeneratorIndex = generatorCounter; + } + } + } + + private boolean isConnected(Generator generator) { + Equipments.ConnectionInfo info = Equipments.getConnectionInfoInBusBreakerView(generator.getTerminal()); + return info.isConnected(); + } + + private void defineBiggestGenerator(List ipsoGenerators) { + ipsoGenerators.get(biggestGeneratorIndex).setBiggest(true); + } + + @Override + protected IpsoGenerator doConvert(Generator generator) { + final String id = createIpsoId(); + + Equipments.ConnectionInfo connectionInfo = + Equipments.getConnectionInfoInBusBreakerView(generator.getTerminal()); + Bus bus = connectionInfo.getConnectionBus(); + final IpsoNode ipsoNode = getContext().getMappingBetweenIidmIdAndIpsoEquipment().getIpsoNodeFor(bus).get(); + + final float activePower = -1.0f * generator.getTerminal().getP(); //...active power [MW] + final float reactivePower = -1.0f * generator.getTerminal().getQ(); //...reactive power [Mvar] + final float minActivePower = generator.getMinP(); //...minimum active power [MW] + final float maxActivePower = generator.getMaxP(); //...maximum active power [MW] + + ReactiveLimits reactiveLimits = generator.getReactiveLimits(); + //...minimum reactive power [Mvar] + final float minReactivePower = getContext().isNoGeneratorMinMaxQ() || reactiveLimits == null + ? REACTIVE_POWER_LOWER_LIMIT : reactiveLimits.getMinQ(activePower); + //...maximum reactive power [Mvar] + final float maxReactivePower = getContext().isNoGeneratorMinMaxQ() || reactiveLimits == null + ? REACTIVE_POWER_UPPER_LIMIT : reactiveLimits.getMaxQ(activePower); + + final double nominalPower = Math.sqrt(Math.pow(activePower, 2) + Math.pow(reactivePower, 2)); + final float nominalVoltage = bus.getVoltageLevel().getNominalV(); + final float setpointVoltage = generator.isVoltageRegulatorOn() ? DataUtil.getSafeValueOf(generator.getTargetV()) : 0f; + + return new IpsoGenerator( + id, + generator.getId(), + ipsoNode, + connectionInfo.isConnected(), + generator.isVoltageRegulatorOn(), + minActivePower, + maxActivePower, + minReactivePower, + maxReactivePower, + (float)nominalPower, + activePower, + reactivePower, + nominalVoltage, + setpointVoltage, + getContext().getWorld()); + } + + @Override + public Iterable gatherDataToConvertFrom(Network network) { + return network.getGenerators(); + } + + @Override + protected ComponentType getComponentType() { + return ComponentType.GENERATOR; + } + +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/IpsoConverterUtil.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/IpsoConverterUtil.java new file mode 100644 index 00000000..ec1f54e0 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/IpsoConverterUtil.java @@ -0,0 +1,28 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.converter; + +import eu.itesla_project.iidm.network.DanglingLine; +/** + * @author Yannick Pihan + */ +class IpsoConverterUtil { + + protected static final String BUS_RADIX = "_bus"; + protected static final String LOAD_RADIX = "_load"; + + private IpsoConverterUtil() { + } + + public static String getFictiveBusIdFor(DanglingLine danglingLine) { + return new StringBuilder(danglingLine.getId()).append(BUS_RADIX).toString(); + + } + + public static String getFictiveLoadIdFor(DanglingLine danglingLine) { + return new StringBuilder(danglingLine.getId()).append(LOAD_RADIX).toString(); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/IpsoTap.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/IpsoTap.java new file mode 100644 index 00000000..fcb5c12b --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/IpsoTap.java @@ -0,0 +1,59 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.converter; + +import eu.itesla_project.iidm.network.TapChanger; + +import static com.google.common.base.Preconditions.checkArgument; +/** + * @author Yannick Pihan + */ +public class IpsoTap { + private final int nominal; + private final int initial; + private final int lowstep; + private final int highstep; + + /** + * Constructor + * @param tapChanger + */ + public IpsoTap(TapChanger tapChanger) { + checkArgument(tapChanger != null, "tapChanger must not ne null" ); + this.initial = tapChanger.getTapPosition(); + this.lowstep = tapChanger.getLowTapPosition(); + this.highstep = tapChanger.getHighTapPosition(); + // Nominal tap number is not available in IIDM. + // We take th median plot by default + this.nominal = tapChanger.getStepCount() / 2 + 1; + } + + /** + * Constructor + */ + public IpsoTap() { + this.initial = 1; + this.lowstep = 1; + this.highstep = 1; + this.nominal = 1; + } + + public int getNominal() { + return nominal; + } + + public int getInitial() { + return initial; + } + + public int getLowstep() { + return lowstep; + } + + public int getHighstep() { + return highstep; + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/LineModelConverter.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/LineModelConverter.java new file mode 100644 index 00000000..da3ebd2c --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/LineModelConverter.java @@ -0,0 +1,101 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.converter; + +import eu.itesla_project.commons.ITeslaException; +import eu.itesla_project.cta.model.DataUtil; +import eu.itesla_project.cta.model.IpsoLine; +import eu.itesla_project.cta.model.IpsoNode; +import eu.itesla_project.iidm.network.*; + +/** + * @author Yannick Pihan + */ +class LineModelConverter extends AbstractBranchModelConverter { + + protected LineModelConverter(ConversionContext context) { + super(context); + } + + /** + * @return ipso line + */ + @Override + public IpsoLine doConvert(Line line) { + Equipments.ConnectionInfo info1 = Equipments.getConnectionInfoInBusBreakerView(line.getTerminal1()); + Equipments.ConnectionInfo info2 = Equipments.getConnectionInfoInBusBreakerView(line.getTerminal2()); + + Bus bus1 = info1.getConnectionBus(); + Bus bus2 = info2.getConnectionBus(); + + final IpsoNode ipsoNode1 = getContext().getMappingBetweenIidmIdAndIpsoEquipment().getIpsoNodeFor(bus1).get(); + final IpsoNode ipsoNode2 = getContext().getMappingBetweenIidmIdAndIpsoEquipment().getIpsoNodeFor(bus2).get(); + final String id = createIdFrom(ipsoNode1.getId(), ipsoNode2.getId()); + + final float vnom = getVnom(line, TwoTerminalsConnectable.Side.ONE); + final float vnomPow2 = (float) Math.pow(vnom, 2); + float Rpu = (line.getR() * snref()) / vnomPow2; //...total line resistance [p.u.] + float Xpu = (line.getX() * snref()) / vnomPow2; //...total line reactance [p.u.] + float Gpu = (line.getG1() / snref()) * vnomPow2; //...semi shunt conductance [p.u.] + float Bpu = (line.getB1() / snref()) * vnomPow2; //...semi shunt susceptance [p.u.] + + // x 100 to convert pu to percent of pu, in order to be compliant with PSA format (used by IPSO) + Rpu = Rpu * 100.0f; + Xpu = Xpu * 100.0f; + Gpu = Gpu * 100.0f; + Bpu = Bpu * 100.0f; + + final int world = getContext().getWorld(); + return new IpsoLine( + id, + line.getId(), + ipsoNode1, + ipsoNode2, + info1.isConnected(), + info2.isConnected(), + Rpu, + Xpu, + Gpu, + Bpu, + findMaxCurrentPermanentLimitFor(line), + line.getTerminal1().getI(), + line.getTerminal2().getI(), + world); + } + + /** + * Get Nominal Voltage one each side of TwoTerminalsConnectable (iidm) + * @param connectable + * @param side + * @return Nominal Voltage [Kv] + */ + private static float getVnom( TwoTerminalsConnectable connectable, TwoTerminalsConnectable.Side side ) { + Iterable buses; + if (side == TwoTerminalsConnectable.Side.ONE ) + { + buses = connectable.getTerminal1().getVoltageLevel().getBusBreakerView().getBuses(); + } + else + { + buses = connectable.getTerminal2().getVoltageLevel().getBusBreakerView().getBuses(); + } + + Bus bus = buses.iterator().next(); + if ( bus == null ) throw new ITeslaException("getVnom cannot get bus of the same voltage level"); + return DataUtil.getSafeValueOf(bus.getVoltageLevel().getNominalV()); + } + + @Override + protected ComponentType getComponentType() { + return ComponentType.LINE; + } + + @Override + public Iterable gatherDataToConvertFrom(Network network) { + return network.getLines(); + } + +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/LoadModelConverter.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/LoadModelConverter.java new file mode 100644 index 00000000..99fba5b2 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/LoadModelConverter.java @@ -0,0 +1,38 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.converter; + +import eu.itesla_project.cta.model.IpsoLoad; +import eu.itesla_project.iidm.network.Load; +import eu.itesla_project.iidm.network.Network; + +import static com.google.common.base.Preconditions.checkArgument; +/** + * @author Yannick Pihan + */ +class LoadModelConverter extends AbstractLoadModelConverter{ + + LoadModelConverter(ConversionContext context) { + super(context); + } + + + @Override + public IpsoLoad doConvert(Load load) { + checkArgument(load != null, "load must not be null"); + return convertLoad(load); + } + + @Override + public Iterable gatherDataToConvertFrom(Network network) { + return network.getLoads(); + } + + @Override + protected ComponentType getComponentType() { + return ComponentType.LOAD; + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/MappingBetweenIidmIdAndIpsoEquipment.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/MappingBetweenIidmIdAndIpsoEquipment.java new file mode 100644 index 00000000..116ee1ad --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/MappingBetweenIidmIdAndIpsoEquipment.java @@ -0,0 +1,110 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.converter; + +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; +import eu.itesla_project.cta.model.IpsoEquipment; +import eu.itesla_project.cta.model.IpsoNode; +import eu.itesla_project.iidm.network.Bus; +import eu.itesla_project.iidm.network.Identifiable; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Strings.padEnd; +import static java.util.Optional.ofNullable; +/** + * @author Yannick Pihan + */ +public class MappingBetweenIidmIdAndIpsoEquipment { + + private final BiMap iidmId2IpsoEquipment; + + /** + * default constructor + */ + public MappingBetweenIidmIdAndIpsoEquipment() { + this(new HashMap()); + } + + /** + * copy constructor + */ + public MappingBetweenIidmIdAndIpsoEquipment(Map iidmId2IpsoEquipment) { + this.iidmId2IpsoEquipment = HashBiMap.create(iidmId2IpsoEquipment); + } + + /** + * Put iidm and ipso component names to the dictionary + */ + public void add(Identifiable identifiable, IpsoEquipment ipsoComponent) { + checkArgument(identifiable != null, "identifiable must not be null"); + checkArgument(ipsoComponent != null, "ipsoComponent must not be null"); + this.add(identifiable.getId(), ipsoComponent); + } + + /** + * Put iidm and ipso id's to the dictionary + */ + public void add(String iidmId, IpsoEquipment ipsoComponent) { + checkArgument(iidmId != null, "iidmId must not be null"); + checkArgument(ipsoComponent != null, "ipsoComponent must not be null"); + if (containsIpsoEquipmentFor(iidmId)) { + throw new RuntimeException("IIDM id '" + iidmId + "' already exists in the dictionary"); + } + iidmId2IpsoEquipment.put(iidmId, ipsoComponent); + } + + /** + * @return Ipso node corresponding to the given iidm bus + */ + public Optional getIpsoNodeFor(Bus bus) { + checkArgument(bus != null, "bus must not be null"); + return getIpsoNodeFor(bus.getId()); + } + + /** + * @return Ipso node corresponding to the given iidm bus id + */ + public Optional getIpsoNodeFor(String busId) { + checkArgument(busId != null, "busId must not be null"); + return ofNullable((IpsoNode) iidmId2IpsoEquipment.get(busId)); + } + + public boolean containsIpsoEquipmentFor(String iidmId) { + return iidmId2IpsoEquipment.containsKey(iidmId); + } + + public Optional getIpsoEquipmentFor(String iidmId) { + checkArgument(iidmId != null, "iidmId must not be null"); + return ofNullable(iidmId2IpsoEquipment.get(iidmId)); + } + + /** + * @return true if ipso id is already defined in the dictionary + */ + boolean containsIpsoId(String id) { + checkArgument(id != null, "id must not be null"); + return iidmId2IpsoEquipment.values().stream() + .anyMatch(ipsoComponent -> ipsoComponent.getId().equals(id)); + } + + public String getIidmIdFor(String ipsoName) { + + return iidmId2IpsoEquipment.values().stream() + .filter(ipsoEquipment -> ipsoEquipment.getId().equals(padEnd(ipsoName, 20, ' '))) + .findFirst() + .map(IpsoEquipment::getIidmId) + .orElseThrow(() -> new IllegalArgumentException("no such Iidm equipment for Ispo name=" + ipsoName)); + } + + public BiMap getIidmId2IpsoEquipment() { + return iidmId2IpsoEquipment; + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/ModelConverter.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/ModelConverter.java new file mode 100644 index 00000000..0ee03bc6 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/ModelConverter.java @@ -0,0 +1,59 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.converter; + +import eu.itesla_project.cta.model.IpsoComponent; +import eu.itesla_project.cta.model.IpsoEquipment; +import eu.itesla_project.iidm.network.Identifiable; +import eu.itesla_project.iidm.network.Network; + +import java.util.List; +/** + * @author Yannick Pihan + */ +interface ModelConverter { + + /** + * Convert data from iidm network to a list of {@link IpsoComponent}. + * The data to createAmplModelFrom is handled in the method {@link ModelConverter#gatherDataToConvertFrom } + * All components converted are added to the dictionary + * of the {@link ConversionContext} + * @param network + * @return list of converted components to Ipso format + */ + List convert(Network network); + + /** + * Gather iidm data to createAmplModelFrom + * @param network + * @return a list of iidm components + */ + Iterable gatherDataToConvertFrom(Network network); + + /** + * Create new name for ipso component with one connection. + *

Example: C000002 (where 'C' is a prefix)

+ *

The prefix of the name is given from {@link ComponentType }

+ * @return unique name + * @see ComponentType + */ + String createIpsoId(); + + /** + * Create new name for two side connectable ipso component + *

The new name is composeb by name1-name2-x

+ *

with x as parrallele index

+ * @param nodeName1 + * @param nodeName2 + * @return unique name + */ + String createIdFrom(String nodeName1, String nodeName2); + + /** + * @return the conversion context + */ + ConversionContext getContext(); +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/NetworkModelConverter.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/NetworkModelConverter.java new file mode 100644 index 00000000..0c3db666 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/NetworkModelConverter.java @@ -0,0 +1,66 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.converter; + +import eu.itesla_project.cta.model.*; +import eu.itesla_project.iidm.network.*; + +import java.util.List; +/** + * @author Yannick Pihan + */ +public class NetworkModelConverter { + + /** + * constructor + */ + public NetworkModelConverter() { + } + + /** + * @return Ipso Network State from Iidm Network + */ + public IpsoNetworkState convert(Network network, ConversionContext context) { + + // create ipso network model + IpsoNetworkState ipsoNetwork = new IpsoNetworkState(0, context.getCaseName(), context.getMappingBetweenIidmIdAndIpsoEquipment()); + + ModelConverter nodeConverter = new NodeModelConverter(context); + List acNodes = nodeConverter.convert(network); + + ModelConverter xNodeConverter = new XnodeModelConverter(context); + acNodes.addAll(xNodeConverter.convert(network)); + ipsoNetwork.addNodes(acNodes); + + ModelConverter lineConverter = new LineModelConverter(context); + List acLines = lineConverter.convert(network); + ipsoNetwork.addLines(acLines); + + ModelConverter danglingLineConverter = new DanglingLineModelConverter(context); + ipsoNetwork.addLines(danglingLineConverter.convert(network)); + + ModelConverter generatorConverter = new GeneratorConverter(context); + ipsoNetwork.addGenerators(generatorConverter.convert(network)); + + ModelConverter loadConverter = new LoadModelConverter(context); + ipsoNetwork.addLoads(loadConverter.convert(network)); + + ModelConverter xLoadModelConverter = new XloadModelConverter(context); + ipsoNetwork.addLoads(xLoadModelConverter.convert(network)); + + ModelConverter bankConverter = new BankModelConverter(context); + ipsoNetwork.addBanks(bankConverter.convert(network)); + + ModelConverter couplingConverter = new CouplingDeviceModelConverter(context); + ipsoNetwork.addCouplings(couplingConverter.convert(network)); + + ModelConverter + transformerConverter = new TwoWindingsTransformerModelConverter(context); + ipsoNetwork.addTwoWindingsTransformers(transformerConverter.convert(network)); + + return ipsoNetwork; + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/NodeModelConverter.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/NodeModelConverter.java new file mode 100644 index 00000000..df322395 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/NodeModelConverter.java @@ -0,0 +1,160 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.converter; + +import com.google.common.base.Function; +import com.google.common.base.Preconditions; +import com.google.common.collect.Multimap; +import com.google.common.collect.Multimaps; +import com.google.gdata.util.common.base.Pair; +import eu.itesla_project.cta.model.IpsoNode; +import eu.itesla_project.cta.model.IpsoNodeType; +import eu.itesla_project.cta.model.IpsoRegionType; +import eu.itesla_project.iidm.network.Bus; +import eu.itesla_project.iidm.network.Network; +import eu.itesla_project.iidm.network.util.Identifiables; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; +/** + * @author Yannick Pihan + */ +class NodeModelConverter extends AbstractNodeModelConverter { + + private static final Logger LOG = LoggerFactory.getLogger(NodeModelConverter.class); + + public NodeModelConverter(ConversionContext context) { + super(context); + } + + /** + * Convert iidm bus to ipso node . + * Moreover, the conversion performs the research of + * macro region as internal or external and de type PV, SB or PQ for nodes + * + * @param network + * @return list of node for ipso + */ + @Override + public List convert(Network network) { + Preconditions.checkArgument(network != null, "network cannto be null"); + List nodes = new ArrayList<>(); + + SpecialNodeFinder specialNodesFinder = new SpecialNodeFinder(); + for(Bus bus : Identifiables.sort(gatherDataToConvertFrom(network)) ) { + // check if the node is special + specialNodesFinder.browse(bus); + // createAmplModelFrom it to Ipso node + final IpsoNode ipsoNode = this.doConvert(bus); + // store created ipso node + nodes.add(ipsoNode); + // add bus and node names to the dictionary + super.addToDictionary(bus, ipsoNode); + } + + // set PV node type + definePvNodesFor(nodes, specialNodesFinder); + + // set slackbus type + if (specialNodesFinder.hasSlackBusFound() ) { + defineSlackBusfor(nodes, specialNodesFinder); + } + else { + LOG.error("no slackbus found!"); + } + + // set Macro region internal or external + defineMacroRegionOf(nodes); + + return nodes; + } + + @Override + protected ComponentType getComponentType() { + return ComponentType.NODE; + } + + @Override + public Iterable gatherDataToConvertFrom(Network network) { + return network.getBusBreakerView().getBuses(); + } + + @Override + protected IpsoNode doConvert(Bus bus) { + return super.convertBus(bus.getId(), bus); + } + + /** + * Change node type to slackbus in the list of Ipso nodes + * @param nodes + * @param specialNodeFinder + */ + private void defineSlackBusfor(List nodes, SpecialNodeFinder specialNodeFinder) { + int index = specialNodeFinder.getSlackBusIndex(); + IpsoNode ipsoNode = nodes.get(index); + // set the type of node to SB + ipsoNode.setNodeType(IpsoNodeType.SB); + nodes.set(index ,ipsoNode); + } + + private void definePvNodesFor(List nodes, SpecialNodeFinder specialNodeFinder) { + for(int index : specialNodeFinder.getPvNodeIndexes()) { + IpsoNode ipsoNode = nodes.get(index); + if (!ipsoNode.isSlackBus()) { + // set the type of node to PV + ipsoNode.setNodeType(IpsoNodeType.PV); + // TODO à confirmer + //ipsoNode.setValue(NodeAttribute.ACTIVE_POWER, specialNodeFinder.getSlackBusGenerator().getTargetP() ); + nodes.set(index, ipsoNode); + } + } + } + + /** + * Defines the macroregion of node as internal or external accordingly to + * the number of node by region. The bigger number of nodes for a given region + * will be set as "Internal", others as "External" + * @param nodes + */ + private void defineMacroRegionOf(List nodes) { + Preconditions.checkArgument(!nodes.isEmpty(), "At least one node is required."); + + defineEveryNodeAsExternal(nodes); + // order IpsoNode by Country + Multimap nodesByCountry = Multimaps.index(nodes, byCountry()); + String internalCountry = findCountryThatContainsTheBiggestNumberOfNodes(nodesByCountry); + + // internal nodes + for (IpsoNode node : nodesByCountry.get(internalCountry)) { + node.setMacroRegionName(IpsoRegionType.INTERNAL.getValue()); + } + } + + private Function byCountry() { + return input -> input.getRegionName(); + } + + private String findCountryThatContainsTheBiggestNumberOfNodes(Multimap nodeByCountry) { + Pair maxLengthWithCountry = null; + for (String country : nodeByCountry.keySet()) { + int numberOfNodes = nodeByCountry.get(country).size(); + if (maxLengthWithCountry == null || maxLengthWithCountry.getSecond() < numberOfNodes) { + maxLengthWithCountry = Pair.of(country, numberOfNodes); + } + } + return maxLengthWithCountry.getFirst(); + } + + private void defineEveryNodeAsExternal(List nodes) { + // default values + for (IpsoNode node : nodes) { + node.setMacroRegionName(IpsoRegionType.EXTERNAL.getValue()); + } + } + +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/SpecialNodeFinder.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/SpecialNodeFinder.java new file mode 100644 index 00000000..c02ddbf4 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/SpecialNodeFinder.java @@ -0,0 +1,142 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.converter; + +import eu.itesla_project.iidm.network.Bus; +import eu.itesla_project.iidm.network.Equipments; +import eu.itesla_project.iidm.network.Generator; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +/** + * @author Yannick Pihan + */ +final class SpecialNodeFinder { + + private Bus slackBus; + private Generator slackBusGenerator; + private int slackBusIndex; + private int busCounter; + private Set pvNodeIndexes; + + /** + * constructor + */ + public SpecialNodeFinder() { + resetFinder(); + } + + /** + * Reinitialize finder + */ + public void resetFinder() { + slackBus = null; + slackBusGenerator = null; + slackBusIndex = -1; + busCounter = 0; + pvNodeIndexes = new HashSet<>(); + } + + /** + * Browses and determines the bus which is slackbus or PV node + */ + public void browse(Bus bus) { + + if (atLeastOneGeneratorFor(bus)) { + + for (Generator generator : bus.getGenerators()) { + + // a regulated generator + if (generator.isVoltageRegulatorOn()) { + + if (areConnected(generator, bus)) + { + storeBiggest(generator, bus); + + storePvNodesFor(generator); + } + } + } + } + busCounter++; + } + + private boolean atLeastOneGeneratorFor(Bus bus) { + return bus.getGenerators() != null; + } + + private boolean areConnected(Generator generator, Bus CandidateBus) { + Equipments.ConnectionInfo info = Equipments.getConnectionInfoInBusBreakerView(generator.getTerminal()); + // if the generator is connected to the bus + if (info.isConnected() ) { + //...Assure the candidate bus is the real bus and not an aggregated bus + return info.getConnectionBus().getId().equals(CandidateBus.getId()); + } else { + return false; + } + } + + /** + * get index of slackbus among all browsed buses + * @return + */ + public int getSlackBusIndex() { + return slackBusIndex; + } + + public boolean hasSlackBusFound() { + return slackBusIndex >= 0; + } + + /** + * get the slackbus chosen among all browsed buses + * @return + */ + public Bus getSlackBus() { + return slackBus; + } + + /** + * + * @return the bigger generator connected to the slackbus + */ + public Generator getSlackBusGenerator() { + return slackBusGenerator; + } + + /** + * Get PV node indexes among all browsed buses + * @return + */ + public Set getPvNodeIndexes() { + return Collections.unmodifiableSet(pvNodeIndexes); + } + + /** + * Store biggest generator (Pmax) and his connection bus as slackbus + */ + private void storeBiggest(Generator generator, Bus bus) { + if (slackBusGenerator == null || isBiggestGenerator(generator)) { + slackBus = bus; + slackBusGenerator = generator; + slackBusIndex = this.busCounter; + } + } + + private boolean isBiggestGenerator(Generator generator) { + return generator.getMaxP() > slackBusGenerator.getMaxP(); + } + + private void storePvNodesFor(Generator generator) { + + // at least on regulator in V Regulator is enough + // to define the connected node as PV + if (generator.isVoltageRegulatorOn()) { + pvNodeIndexes.add(this.busCounter); + } + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/TwoWindingsTransformerModelConverter.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/TwoWindingsTransformerModelConverter.java new file mode 100644 index 00000000..a8675aa5 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/TwoWindingsTransformerModelConverter.java @@ -0,0 +1,314 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.converter; + +import eu.itesla_project.commons.ITeslaException; +import eu.itesla_project.cta.model.*; +import eu.itesla_project.iidm.network.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.function.Function; + +import static com.google.common.base.Preconditions.checkArgument; +import static java.util.Optional.ofNullable; +/** + * @author Yannick Pihan + */ +class TwoWindingsTransformerModelConverter extends AbstractBranchModelConverter{ + + private static final Logger LOGGER = LoggerFactory.getLogger(TwoWindingsTransformerModelConverter.class); + protected static final String CANNOT_FIND_REGULATED_BUS = "Cannot find regulated bus for TwoWindingTransformer having the id: "; + protected static final String PHASE_TRANSFORMER_WITH_UNCONSISTENT_REGULATION_BUS = "Phase transformer %s has a regulated bus which is different of bus1 and bus2"; + protected static final String TRANSFORMER_HAS_TO_MANY_REGULATION_MODE = "Ratio transformer %s with 2 regulation modes is not supported"; + + + final class Losses { + float cu; + float fe; + float magnetizingCurrent; + float saturation_exponent; + } + + + final class IpsoStep { + float rho, alpha; + TransformerRegulationType mode; + float un01, un02, ucc, phase; + } + + /** + * Constructor + * @param context + */ + TwoWindingsTransformerModelConverter(ConversionContext context) { + super(context); + } + + @Override + protected IpsoTwoWindingsTransformer doConvert(TwoWindingsTransformer transformer) { + + Equipments.ConnectionInfo info1 = Equipments.getConnectionInfoInBusBreakerView(transformer.getTerminal1()); + Equipments.ConnectionInfo info2 = Equipments.getConnectionInfoInBusBreakerView(transformer.getTerminal2()); + Bus bus1 = info1.getConnectionBus(); + Bus bus2 = info2.getConnectionBus(); + final IpsoNode ipsoNode1 = getContext().getMappingBetweenIidmIdAndIpsoEquipment().getIpsoNodeFor(bus1).get(); + final IpsoNode ipsoNode2 = getContext().getMappingBetweenIidmIdAndIpsoEquipment().getIpsoNodeFor(bus2).get(); + + String id = createIdFrom(ipsoNode1.getId(), ipsoNode2.getId()); + + Losses losses = this.computeLosses(transformer); + IpsoTap tap = this.computeTapChangerInfo(transformer); + Map steps = computeIpsoSteps(transformer, tap); + + final TransformerRegulationParameters regulationParameters = findRegulationParametersFor(transformer, bus1, bus2); + + //...writeVariables records + List indexes = new ArrayList<>(); + List voltages_side1 = new ArrayList<>(); + List voltages_side2 = new ArrayList<>(); + List phases = new ArrayList<>(); + List uccs = new ArrayList<>(); + if (steps.size() > 0) { + + for (int index : steps.keySet()) { + IpsoStep step = steps.get(index); + indexes.add(index); + voltages_side1.add(step.un01); + voltages_side2.add(step.un02); + phases.add(step.phase); + uccs.add(step.ucc); + } + } + + return new IpsoTwoWindingsTransformer( + id, + transformer.getId(), + ipsoNode1, + ipsoNode2, + info1.isConnected(), + info2.isConnected(), + losses.cu, + losses.fe, + losses.magnetizingCurrent, + losses.saturation_exponent, + rate(), + tap.getNominal(), + tap.getInitial(), + tap.getLowstep(), + tap.getHighstep(), + steps.size(), + indexes, + voltages_side1, + voltages_side2, + phases, + uccs, + findMaxCurrentPermanentLimitFor(transformer), + findCurrentFlow(transformer, regulationParameters.getRegulationType()), + regulationParameters, + getContext().getWorld()); + } + + private float findCurrentFlow(TwoWindingsTransformer transformer, TransformerRegulationType transformerRegulationType) { + checkArgument(transformer.getTerminal1() != null, "transformer.getTerminal1() must not be null"); + checkArgument(transformer.getTerminal2() != null, "transformer.getTerminal2() must not be null"); + float flow1 = DataUtil.getSafeValueOf(transformer.getTerminal1().getI(), 0); + float flow2 = DataUtil.getSafeValueOf(transformer.getTerminal2().getI(), 0); + return Math.max(flow1, flow2); + } + + private Function getSafeI() { + return terminal -> DataUtil.getSafeValueOf(terminal.getI()); + } + + private Losses computeLosses(TwoWindingsTransformer transformer) { + Losses losses = new Losses(); + + float ratedU1 = transformer.getRatedU1(); + float ratedU2 = transformer.getRatedU2(); + float nominalU2 = transformer.getTerminal2().getVoltageLevel().getNominalV(); + + //...mTrans.getR() = Get the nominal series resistance specified in Ω at the secondary voltage side. + float Rpu2 = ( transformer.getR() * snref() ) / nominalU2 / nominalU2; //...total line resistance [p.u.](Base snref) + float Gpu2 = ( transformer.getG() / snref() ) * nominalU2 * nominalU2; //...semi shunt conductance [p.u.](Base snref) + float Bpu2 = ( transformer.getB() / snref() ) * nominalU2 * nominalU2; //...semi shunt susceptance [p.u.](Base snref) + + //...changing base snref -> base RATE to compute losses + losses.cu = Rpu2 * rate() * 100f / snref(); //...base RATE (100F -> %) + losses.fe = 10000f * ( Gpu2 / rate()) * (snref() / 100f) ; //...base RATE + float modgb = (float) Math.sqrt(Math.pow(Gpu2,2.f) + Math.pow(Bpu2, 2.f) ); + losses.magnetizingCurrent = 10000 * ( modgb / rate()) * (snref() / 100f); //...magnetizing current [% base RATE] + losses.saturation_exponent = 1.f; + + return losses; + } + + private IpsoTap computeTapChangerInfo(TwoWindingsTransformer transformer) { + if (transformer.getRatioTapChanger() != null) { + return new IpsoTap(transformer.getRatioTapChanger()); + } else if (transformer.getPhaseTapChanger() != null) { + return new IpsoTap(transformer.getPhaseTapChanger()); + } else { + return new IpsoTap(); + } + } + + private TransformerRegulationParameters findRegulationParametersFor(TwoWindingsTransformer transformer, Bus bus1, Bus bus2) { + checkArgument(transformer != null, "transformer must not be null"); + checkArgument(bus1 != null, "bus1 must not be null"); + checkArgument(bus2 != null, "bus2 must not be null"); + //...get tap changers + RatioTapChanger rtc = transformer.getRatioTapChanger(); + PhaseTapChanger ptc = transformer.getPhaseTapChanger(); + + TransformerRegulationType regulationType = TransformerRegulationType.NO; + float setpoint = 0.f; + Bus regulatedbus = null; // get bus1 as regulated bus by default + IpsoNode ipsoRegulatedBus = null; + int currentStepPosition = 0; + + // Ratio tap changer (voltage regulating) + if (isRegulationDefinedFor(rtc)) { + regulatedbus = findRegulatedBusFor(rtc).get(); + + regulationType = findVolategRegulationType(bus1, bus2, regulatedbus) + .orElseThrow(() -> new IllegalStateException(unconsistentRegulationBusFor(transformer))); + + setpoint = rtc.getTargetV() / regulatedbus.getVoltageLevel().getNominalV(); // !!! in PU + currentStepPosition = rtc.getTapPosition(); + } + + // Phase tap changer (active power regulating) + if (isRegulationDefinedFor(ptc)) { + // two regulation types cannot be defined on the same twoWindingTransformer + if (regulationType.isVoltageRegulationType()) { + throw new ITeslaException(String.format(TRANSFORMER_HAS_TO_MANY_REGULATION_MODE, transformer.getId())); + } + setpoint = ptc.getThresholdI(); // in Ampere + regulatedbus = findRegulatedBusFor(ptc).get(); + currentStepPosition = ptc.getTapPosition(); + regulationType = findFlowRegulationType(bus1, bus2, regulatedbus) + .orElseThrow(() -> new IllegalStateException(unconsistentRegulationBusFor(transformer))); + } + + if (regulationType != TransformerRegulationType.NO ) { + ipsoRegulatedBus = getContext().getMappingBetweenIidmIdAndIpsoEquipment().getIpsoNodeFor(regulatedbus).get(); + } + return new TransformerRegulationParameters(regulationType, setpoint, regulationType.getSideValue(), currentStepPosition, ipsoRegulatedBus); + } + + private String unconsistentRegulationBusFor(TwoWindingsTransformer transformer) { + return String.format(PHASE_TRANSFORMER_WITH_UNCONSISTENT_REGULATION_BUS, transformer.getId()); + } + + private Optional findRegulatedBusFor(TapChanger tapChanger) { + checkArgument(tapChanger != null, "tap changer must not be null."); + return ofNullable(tapChanger.getTerminal()) + .map(Terminal::getBusBreakerView) + .map(Terminal.BusBreakerView::getBus); + } + + private Optional findVolategRegulationType(Bus bus1, Bus bus2, Bus regulatedbus) { + checkArgument(bus1 != null, "bus1 must not be null"); + checkArgument(bus2 != null, "bus1 must not be null"); + checkArgument(regulatedbus != null, "regulatedbus must not be null"); + if (bus1.equals(regulatedbus)) { + return Optional.of(TransformerRegulationType.VOLTAGE_SIDE_1); + } else if (bus2.equals(regulatedbus)) { + return Optional.of(TransformerRegulationType.VOLTAGE_SIDE_2); + } + else { + return Optional.empty(); + } + } + + private Optional findFlowRegulationType(Bus bus1, Bus bus2, Bus regulatedbus) { + checkArgument(bus1 != null, "bus1 must not be null"); + checkArgument(bus2 != null, "bus1 must not be null"); + checkArgument(regulatedbus != null, "regulatedbus must not be null"); + if (bus1.equals(regulatedbus)) { + return Optional.of(TransformerRegulationType.ACTIVE_FLUX_1); + } else if (bus2.equals(regulatedbus)) { + return Optional.of(TransformerRegulationType.ACTIVE_FLUX_2); + } + else { + return Optional.empty(); + } + } + + private boolean isRegulationDefinedFor(TapChanger tapChanger) { + return tapChanger != null && tapChanger.isRegulating() && findRegulatedBusFor(tapChanger).isPresent(); + } + + private Map computeIpsoSteps(TwoWindingsTransformer transformer, IpsoTap tap) { + + float ratedU1 = transformer.getRatedU1(); + float ratedU2 = transformer.getRatedU2(); + float nomiU2 = transformer.getTerminal2().getVoltageLevel().getNominalV(); + + //...getValue ratio tap changer + RatioTapChanger rtc = transformer.getRatioTapChanger(); + PhaseTapChanger ptc = transformer.getPhaseTapChanger(); + + Map steps = new TreeMap<>(); + for ( int s = tap.getLowstep() ; s <= tap.getHighstep() ; s++ ) { + + IpsoStep step = new IpsoStep(); + step.un01 = ratedU1; + step.un02 = ratedU2; + + float dr = 0f, dx = 0f, ucc, phase = 0f; + if (rtc != null ) { + step.rho = rtc.getStep(s).getRho(); + step.un01 /= rtc.getStep(s).getRho() ; + step.un02 = ratedU2; + dr += rtc.getStep(s).getR(); + dx += rtc.getStep(s).getX(); + } + + if (ptc != null ) { + step.alpha = ptc.getStep(s).getAlpha(); + phase = ptc.getStep(s).getAlpha(); + step.un01 /= ptc.getStep(s).getRho(); //temporary, to be investigated for ptc + dr += ptc.getStep(s).getR(); + dx += ptc.getStep(s).getX(); + } + + //...transformer.getR() = Get the nominal series resistance specified in Ω at the secondary voltage side. + float rpu2 = ( transformer.getR() * (1 + dr/100.0f) * snref() ) / nomiU2 / nomiU2; //...total line resistance [p.u.](Base snref) + float xpu2 = ( transformer.getX() * (1 + dx/100.0f) * snref() ) / nomiU2 / nomiU2; //...total line reactance [p.u.](Base snref) + + //...leakage impedance [%] (base RATE) + if ( xpu2 < 0 ) { + ucc = xpu2 * rate() * 100f / snref(); + } + else + { + float modrx = (float) Math.sqrt(Math.pow(rpu2,2.f) + Math.pow(xpu2, 2.f) ); + ucc = modrx * rate() * 100f / snref(); + } + + step.ucc = ucc; + step.phase = phase; + steps.put(s, step); + } + + return steps; + + } + + @Override + public Iterable gatherDataToConvertFrom(Network network) { + return network.getTwoWindingsTransformers(); + } + + @Override + protected ComponentType getComponentType() { + return ComponentType.TWO_WINDINGS_TRANSFORMER; + } + +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/XloadModelConverter.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/XloadModelConverter.java new file mode 100644 index 00000000..7ec80596 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/XloadModelConverter.java @@ -0,0 +1,69 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.converter; + +import eu.itesla_project.cta.model.IpsoLoad; +import eu.itesla_project.cta.model.IpsoNode; +import eu.itesla_project.iidm.network.DanglingLine; +import eu.itesla_project.iidm.network.Network; + +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkArgument; +/** + * @author Yannick Pihan + */ +class XloadModelConverter extends AbstractLoadModelConverter{ + + XloadModelConverter(ConversionContext context) { + super(context); + } + + + @Override + public IpsoLoad doConvert(DanglingLine danglingLine) { + checkArgument(danglingLine != null, "danglingLine must not be null"); + + String id = createIpsoId(); + Optional ipsoNodeFor = getContext().getMappingBetweenIidmIdAndIpsoEquipment().getIpsoNodeFor(IpsoConverterUtil.getFictiveBusIdFor(danglingLine)); + + if(ipsoNodeFor.isPresent()) { + IpsoNode ipsoNode = ipsoNodeFor.get(); + + float activePower = danglingLine.getP0(); + float reactivePower = danglingLine.getQ0(); + return new IpsoLoad( + id, + getIdOf(danglingLine), + ipsoNode, + true, + activePower, + reactivePower, + getContext().getWorld()); + } + else { + return null; + } + } + + @Override + public Iterable gatherDataToConvertFrom(Network network) { + return network.getDanglingLines(); + } + + @Override + protected ComponentType getComponentType() { + return ComponentType.XLOAD; + } + + /** + * @return A fake id for fictive node created from danglingLine + */ + @Override + protected String getIdOf(DanglingLine danglingLine) { + return IpsoConverterUtil.getFictiveLoadIdFor(danglingLine); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/XnodeModelConverter.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/XnodeModelConverter.java new file mode 100644 index 00000000..c97ebf63 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/converter/XnodeModelConverter.java @@ -0,0 +1,88 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.converter; + +import eu.itesla_project.cta.model.IpsoNode; +import eu.itesla_project.cta.model.IpsoNodeType; +import eu.itesla_project.cta.model.IpsoRegionType; +import eu.itesla_project.iidm.network.Bus; +import eu.itesla_project.iidm.network.DanglingLine; +import eu.itesla_project.iidm.network.Network; +import eu.itesla_project.iidm.network.util.SV; + +import static com.google.common.base.Preconditions.checkArgument; +/** + * @author Yannick Pihan + */ +class XnodeModelConverter extends AbstractNodeModelConverter { + + public XnodeModelConverter(ConversionContext context) { + super(context); + } + + @Override + public IpsoNode doConvert(DanglingLine danglingLine) { + checkArgument(danglingLine != null, "danglingLine must not be null"); + checkArgument(danglingLine.getTerminal() != null, "danglingLine.getTerminal() must not be null"); + checkArgument(danglingLine.getTerminal().getBusBreakerView() != null, "danglingLine.getTerminal().getBusBreakerView() must not be null"); + + //checkArgument(danglingLine.getTerminal().getBusBreakerView().getBus()!= null, "danglingLine.getTerminal().getBusBreakerView().getBus() must not be null"); + if (danglingLine.getTerminal().getBusBreakerView().getBus() == null) { + return null; + } else { + final String id = createIpsoId(); + final Bus bus = danglingLine.getTerminal().getBusBreakerView().getBus(); + + // voltage of known bus of the dangling line + final float voltage = bus.getV(); + // angle of known bus of the dangling line + final float angle = bus.getAngle(); + + final float p = danglingLine.getTerminal().getP(); + final float q = danglingLine.getTerminal().getQ(); + + final float pn = danglingLine.getTerminal().getBusBreakerView().getBus().getP(); + final float qn = danglingLine.getTerminal().getBusBreakerView().getBus().getQ(); + + final SV known = new SV(p, q, voltage, angle); + final SV fictitious = known.otherSide(danglingLine); + final float baseVoltage = findBaseVoltage(bus); + + return new IpsoNode( + id, + getIdOf(danglingLine), + findAreaFor(bus), + IpsoRegionType.EXTERNAL.getValue(), + baseVoltage, + fictitious.getU(), + fictitious.getA(), + IpsoNodeType.PQ, + fictitious.getP(), + fictitious.getQ(), + findLowVoltageLevel(bus, baseVoltage), + findHighVoltageLevel(bus, baseVoltage), + getContext().getWorld()); + } + } + + @Override + public Iterable gatherDataToConvertFrom(Network network) { + return network.getDanglingLines(); + } + + @Override + protected ComponentType getComponentType() { + return ComponentType.XNODE; + } + + /** + * @return A fake id for fictive node created from danglingLine + */ + @Override + protected String getIdOf(DanglingLine danglingLine) { + return IpsoConverterUtil.getFictiveBusIdFor(danglingLine); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/io/AmplModelWriter.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/io/AmplModelWriter.java new file mode 100644 index 00000000..c2a09b19 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/io/AmplModelWriter.java @@ -0,0 +1,45 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.io; + +import eu.itesla_project.cta.model.AmplModel; +import eu.itesla_project.cta.service.AmplConstants; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.runtime.RuntimeConstants; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.List; +import java.util.Map; + +import static java.util.Arrays.stream; +import static java.util.stream.Collectors.toMap; +/** + * @author Yannick Pihan + */ +public class AmplModelWriter { + + public void write(AmplModel model, String toPath, String templatePath) throws IOException { + VelocityEngine templateEngine = new VelocityEngine(); + templateEngine.setProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, templatePath); + templateEngine.init(); + Template template = templateEngine.getTemplate(AmplConstants.TEMPLATE_FILE); + + VelocityContext context = new VelocityContext(formatParameters(model)); + FileWriter writer = new FileWriter(new File(toPath)); + template.merge(context, writer); + + writer.close(); + } + + private Map> formatParameters(AmplModel model) { + return stream(AmplParameters.values()) + .collect(toMap(AmplParameters::getName, parameter -> parameter.format(model))); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/io/AmplParameterFormatter.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/io/AmplParameterFormatter.java new file mode 100644 index 00000000..6b2f4c31 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/io/AmplParameterFormatter.java @@ -0,0 +1,46 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.io; + +import java.util.List; + +import static com.google.common.base.Preconditions.checkArgument; +import static java.util.stream.Collectors.joining; +/** + * Copyright (c) 2016, Tractebel (http://www.itesla-project.eu/consortium) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * @author Yannick Pihan + */ +class AmplParameterFormatter { + + private static final String DELIMITER = "\t"; + + public String format(List list) { + checkArgument(list != null, "list must not be null"); + return list.stream() + .map(e -> convertBooleanToInteger(e)) + .map(Object::toString) + .collect(joining(DELIMITER)); + } + + private Object convertBooleanToInteger(Object e) { + if(e instanceof Boolean ) { + return (boolean)e ? 1 : 0; + } + else if(e instanceof Float && (float)e == Float.NEGATIVE_INFINITY) { + return "-Infinity"; + } + else if(e instanceof Float && (float)e == Float.POSITIVE_INFINITY) { + return "Infinity"; + } + else { + return e; + } + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/io/AmplParameters.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/io/AmplParameters.java new file mode 100644 index 00000000..82061437 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/io/AmplParameters.java @@ -0,0 +1,65 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.io; + +import eu.itesla_project.cta.model.AmplModel; +import eu.itesla_project.cta.model.AmplWritable; + +import java.util.List; +import java.util.function.Function; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.collect.Lists.newArrayList; +import static java.util.stream.Collectors.toList; +/** + * @author Yannick Pihan + */ +public enum AmplParameters { + + GENERATORS("generators", AmplModel::getGenerators), + LOADS("loads", AmplModel::getLoads), + CAPACITORS("capacitors", AmplModel::getCapacitors), + NODES("nodes", AmplModel::getNodes), + TRANSFORMERS("transformers", AmplModel::getTransBranches), + SIMPLE_BRANCHES("simpleBranches", AmplModel::getSimpleBranches), + COUPLAGES("couplages", AmplModel::getCouplages), + SLACKBUSES("slackbuses", AmplModel::getSlackBuses), + + NODE_PARAMETERS("nodeParametersList", AmplModel::getNodeParameters), + SLACKBUS_PARAMETERS("slackbusParametersList", AmplModel::getSlackBusParameters), + GENERATOR_PARAMETERS("generatorParametersList", AmplModel::getGeneratorParameters), + LOAD_PARAMETERS("loadParametersList", AmplModel::getLoadParameters), + CAPACITOR_PARAMETERS("capacitorParametersList", AmplModel::getCapacitorParameters), + BRANCH_PARAMETERS("branchParametersList", AmplModel::getBranchParameters), + TRANSFORMER_PARAMETERS("transformerParametersList", AmplModel::getTransformerParameters), + COUPLING_PARAMETERS("couplingParametersList", AmplModel::getCouplingParameters), + ; + + private static List EMPTY_SET = newArrayList("{}"); + private static final AmplParameterFormatter FORMATTER = new AmplParameterFormatter(); + + private final String name; + private final Function> amplElements; + + AmplParameters(String name, + Function> amplElements) { + this.name = name; + this.amplElements = amplElements; + } + + public List format(AmplModel model) { + checkArgument(model != null, "model must not be null"); + List strings = amplElements.apply(model) + .stream() + .map(element -> FORMATTER.format(element.getOrderedValues())) + .collect(toList()); + return strings.isEmpty() ? EMPTY_SET : strings; + } + + public String getName() { + return name; + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/io/IpsoCsvWriter.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/io/IpsoCsvWriter.java new file mode 100644 index 00000000..91cc5848 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/io/IpsoCsvWriter.java @@ -0,0 +1,54 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.io; + +import com.google.common.base.Preconditions; +import com.google.common.collect.Iterables; +import eu.itesla_project.cta.model.IpsoWritable; +import org.supercsv.io.CsvListWriter; +import org.supercsv.io.ICsvListWriter; +import org.supercsv.prefs.CsvPreference; + +import java.io.FileWriter; +import java.io.IOException; +import java.io.Writer; +import java.nio.file.Path; +import java.util.List; +/** + * @author Yannick Pihan + */ +public class IpsoCsvWriter implements IpsoWriter { + + @Override + public void write(List writables, Path toPath) throws IOException { + Preconditions.checkArgument(writables != null, "writables cannot be null"); + Preconditions.checkArgument(toPath != null, "toPath cannot be null"); + + try (Writer writer = new FileWriter(toPath.toFile()); + ICsvListWriter csvWriter = new CsvListWriter(writer, CsvPreference.EXCEL_PREFERENCE)) { + writeHeader(writables, csvWriter); + writeLines(writables, csvWriter); + } + } + + private void writeLines(List writables, ICsvListWriter csvWriter) throws IOException { + for (IpsoWritable writable : writables) { + csvWriter.write(writable.getOrderedValues()); + } + } + + private void writeHeader(List writables, ICsvListWriter csvwriter) throws IOException { + IpsoWritable firstOne = Iterables.getFirst(writables, null); + if (firstOne != null) { + csvwriter.write(firstOne.getOrderedHeaders()); + } + } + + @Override + public IpsoOutputFormat getFormat() { + return IpsoOutputFormat.CSV; + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/io/IpsoOutputFormat.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/io/IpsoOutputFormat.java new file mode 100644 index 00000000..1882cc4e --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/io/IpsoOutputFormat.java @@ -0,0 +1,13 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.io; +/** + * @author Yannick Pihan + */ +public enum IpsoOutputFormat { + CSV, + XML_SOAP +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/io/IpsoWriter.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/io/IpsoWriter.java new file mode 100644 index 00000000..692135c1 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/io/IpsoWriter.java @@ -0,0 +1,22 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.io; + +import eu.itesla_project.cta.model.IpsoWritable; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.List; +/** + * @author Yannick Pihan + */ +public interface IpsoWriter { + + void write(List writables, Path toPath) throws IOException; + + IpsoOutputFormat getFormat(); + +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/io/Writers.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/io/Writers.java new file mode 100644 index 00000000..2b53da30 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/io/Writers.java @@ -0,0 +1,26 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.io; + +import java.util.ServiceLoader; +/** + * @author Yannick Pihan + */ +public final class Writers { + + private static final ServiceLoader WRITERS_LOADER = ServiceLoader.load(IpsoWriter.class); + + private Writers() {} + + public static IpsoWriter findWriterFor(IpsoOutputFormat format) { + for (IpsoWriter writer : WRITERS_LOADER) { + if (writer.getFormat() == format) { + return writer; + } + } + return null; + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AbstractFlowConstraint.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AbstractFlowConstraint.java new file mode 100644 index 00000000..9a629463 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AbstractFlowConstraint.java @@ -0,0 +1,32 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; +/** + * @author Yannick Pihan + */ +public abstract class AbstractFlowConstraint extends IpsoConstraint { + + protected static final String FLOW_MIN = "FLOW_MIN"; + protected static final String FLOW_MAX = "FLOW_MAX"; + private final FlowUnit flowUnit; + + public AbstractFlowConstraint(T equipment, FlowUnit flowUnit ,float min, float max, int world) { + super(equipment, min, max, world); + this.flowUnit = flowUnit; + } + + public float getMaxFlow() { + return getBoundsMax(); + } + + public float getMinFlow() { + return getBoundsMin(); + } + + public FlowUnit getFlowUnit() { + return flowUnit; + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AbstractIpsoBranch.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AbstractIpsoBranch.java new file mode 100644 index 00000000..a8dabf53 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AbstractIpsoBranch.java @@ -0,0 +1,42 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import java.util.List; +/** + * @author Yannick Pihan + */ +public abstract class AbstractIpsoBranch extends IpsoEquipment{ + + protected final IpsoNode ipsoNode1; + protected final IpsoNode ipsoNode2; + + public AbstractIpsoBranch(String id, String iidmId, int world, IpsoNode ipsoNode1, IpsoNode ipsoNode2) { + super(id, iidmId, world); + this.ipsoNode1 = ipsoNode1; + this.ipsoNode2 = ipsoNode2; + } + + public abstract boolean isConnected(); + + public boolean couldBeConnected(List topologicalActions) { + return this.isConnected() || topologicalActions.stream() + .filter(action -> action.getEquipmentId() == this.getId()) + .anyMatch(action -> action.getSwitchAction().isOppositeTo(this.isConnected())); + } + protected char getConnectionCodeFor(boolean connected) { + return connected ? 'Y' : 'N'; + } + + public IpsoNode getIpsoNode2() { + return ipsoNode2; + } + + public IpsoNode getIpsoNode1() { + return ipsoNode1; + } + +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AbstractIpsoConstraintLineFlow.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AbstractIpsoConstraintLineFlow.java new file mode 100644 index 00000000..cf035986 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AbstractIpsoConstraintLineFlow.java @@ -0,0 +1,37 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import com.google.common.collect.Lists; + +import java.util.List; +/** + * @author Yannick Pihan + */ +public abstract class AbstractIpsoConstraintLineFlow extends AbstractFlowConstraint { + + public AbstractIpsoConstraintLineFlow(IpsoLine line, FlowUnit unit, float min, float max, int world) { + super(line, unit, min, max, world); + } + + @Override + protected abstract float getConstrainedAttributeValueFor(IpsoLine equipment); + + @Override + public List getOrderedHeaders() { + return Lists.newArrayList( + NAME, + UNIT, + FLOW_MIN, + FLOW_MAX, + WORLD); + } + + @Override + public List getOrderedValues() { + return Lists.newArrayList(getRelatedIpsoEquipment().getId(), getFlowUnit().getUnit(), getBoundsMin(), getBoundsMax(), getWorld()); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplBranchParameters.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplBranchParameters.java new file mode 100644 index 00000000..fdbe9a37 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplBranchParameters.java @@ -0,0 +1,64 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import com.google.common.collect.Lists; + +import java.util.List; +/** + * @author Yannick Pihan + */ +public class AmplBranchParameters extends AmplElement{ + private final String id; + private final String or; + private final String de; + private final float y; + private final float zeta; + private final float gSh; + private final float bSh; + private final boolean initConfig; + private final boolean canReconfig; + private final float pMaxFlow; + private final float qMaxFlow; + private final float sMaxFlow; + private final float iMaxFlowOr; + private final float iMaxFlowDe; + + public AmplBranchParameters(String id, String or, String de, float y, float zeta, float gSh, float bSh, boolean initConfig, boolean canReconfig, float pMaxFlow, float qMaxFlow, float sMaxFlow, float iMaxFlowOr, float iMaxFlowDe) { + this.id = id; + this.or = or; + this.de = de; + this.y = y; + this.zeta = zeta; + this.gSh = gSh; + this.bSh = bSh; + this.initConfig = initConfig; + this.canReconfig = canReconfig; + this.pMaxFlow = pMaxFlow; + this.qMaxFlow = qMaxFlow; + this.sMaxFlow = sMaxFlow; + this.iMaxFlowOr = iMaxFlowOr; + this.iMaxFlowDe = iMaxFlowDe; + } + + @Override + public List getOrderedValues() { + return Lists.newArrayList(this.id, + this.or, + this.de, + this.y, + this.zeta, + this.gSh, + this.bSh, + this.initConfig, + this.canReconfig, + this.pMaxFlow, + this.qMaxFlow, + this.sMaxFlow, + this.iMaxFlowOr, + this.iMaxFlowDe); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplCapacitor.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplCapacitor.java new file mode 100644 index 00000000..63e01aa3 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplCapacitor.java @@ -0,0 +1,27 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import java.util.List; + +import static com.google.common.collect.Lists.newArrayList; +/** + * @author Yannick Pihan + */ +public class AmplCapacitor extends AmplElement{ + private final String id; + + public AmplCapacitor(String id) { + this.id = id.trim(); + } + + @Override + public List getOrderedValues() { return newArrayList(this.id); } + + public String getId() { + return id; + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplCapacitorParameters.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplCapacitorParameters.java new file mode 100644 index 00000000..a44704c9 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplCapacitorParameters.java @@ -0,0 +1,53 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import com.google.common.collect.Lists; + +import java.util.List; +/** + * @author Yannick Pihan + */ +public class AmplCapacitorParameters implements AmplWritable{ + + + private final String id; + private final String connectedNode; + private final boolean initConfig; + private final boolean canReconfig; + private final int stepMin; + private final int stepMax; + private final int initialStep; + private final float activePowerByStep; + private final float reactivePowerByStep; + + public AmplCapacitorParameters(String id, String cnode, boolean initConfig, boolean canReconfig, int stepMin, int stepMax, int initialStep, float activePowerByStep, float reactivePowerByStep) { + this.id = id; + this.connectedNode = cnode; + this.initConfig = initConfig; + this.canReconfig = canReconfig; + this.stepMin = stepMin; + this.stepMax = stepMax; + this.initialStep = initialStep; + this.activePowerByStep = activePowerByStep; + this.reactivePowerByStep = reactivePowerByStep; + } + + @Override + public List getOrderedValues() { + return Lists.newArrayList( + this.id, + this.connectedNode, + this.initConfig, + this.canReconfig, + this.stepMin, + this.stepMax, + this.initialStep, + this.activePowerByStep, + this.reactivePowerByStep + ); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplCouplage.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplCouplage.java new file mode 100644 index 00000000..e9f0cf15 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplCouplage.java @@ -0,0 +1,27 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import com.google.common.collect.Lists; + +import java.util.List; +/** + * @author Yannick Pihan + */ +public class AmplCouplage extends AmplElement{ + private final String id; + + public AmplCouplage(String id) { + this.id = id.trim(); + } + + public String getId() { + return id; + } + + @Override + public List getOrderedValues() { return Lists.newArrayList(this.id); } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplCouplingParameters.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplCouplingParameters.java new file mode 100644 index 00000000..2336a186 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplCouplingParameters.java @@ -0,0 +1,43 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import com.google.common.collect.Lists; + +import java.util.List; +/** + * @author Yannick Pihan + */ +public class AmplCouplingParameters implements AmplWritable{ + + + final String id; + final String ipsoNode1; + final String ipsoNode2; + + final boolean connected; + + final boolean canReconfig; + + public AmplCouplingParameters(String id, String ipsoNode1, String ipsoNode2, boolean connected, boolean canReconfig) { + this.id = id; + this.ipsoNode1 = ipsoNode1; + this.ipsoNode2 = ipsoNode2; + this.connected = connected; + this.canReconfig = canReconfig; + } + + @Override + public List getOrderedValues() { + return Lists.newArrayList( + this.id, + this.ipsoNode1, + this.ipsoNode2, + this.connected, + this.canReconfig + ); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplElement.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplElement.java new file mode 100644 index 00000000..7fd0ee87 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplElement.java @@ -0,0 +1,10 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; +/** + * @author Yannick Pihan + */ +public abstract class AmplElement implements AmplWritable {} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplGenerator.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplGenerator.java new file mode 100644 index 00000000..e53ccfd5 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplGenerator.java @@ -0,0 +1,35 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import java.util.List; + +import static com.google.common.collect.Lists.newArrayList; +/** + * @author Yannick Pihan + */ +public class AmplGenerator extends AmplElement { + private final String name; + + public AmplGenerator(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + @Override + public List getOrderedValues () { + return newArrayList(name); + } + + @Override + public String toString() { + return name; + } + +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplGeneratorParameters.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplGeneratorParameters.java new file mode 100644 index 00000000..168aecba --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplGeneratorParameters.java @@ -0,0 +1,60 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import com.google.common.collect.Lists; + +import java.util.List; +/** + * @author Yannick Pihan + */ +public class AmplGeneratorParameters extends AmplElement{ + private final String id; + private final String connectedNodeId; + private final float pgMin; + private final float initialP; + private final float pgMax; + private final float qgMin; + private final float intialQ; + private final float qgMax; + private final float dlgenMax; + private final float wDlgen; + private final boolean initialConfigG; + private final boolean canReconfig; + + + public AmplGeneratorParameters(String id, String connectedNodeId, float pgMin, float initialP, float pgMax, float qgMin, float intialQ, float qgMax, boolean connected, boolean canReconfig,float dlgenMax, float wDlgen) { + this.id = id; + this.connectedNodeId = connectedNodeId; + this.pgMin = pgMin; + this.initialP = initialP; + this.pgMax = pgMax; + this.qgMin = qgMin; + this.intialQ = intialQ; + this.initialConfigG = connected; + this.canReconfig = canReconfig; + this.qgMax = qgMax; + this.dlgenMax = dlgenMax; + this.wDlgen = wDlgen; + } + + @Override + public List getOrderedValues() { + return Lists.newArrayList( + this.id, + this.connectedNodeId, + this.pgMin, + this.initialP, + this.pgMax, + this.qgMin, + this.intialQ, + this.qgMax, + this.initialConfigG, + this.canReconfig, + this.dlgenMax, + this.wDlgen); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplLoad.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplLoad.java new file mode 100644 index 00000000..5c53b534 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplLoad.java @@ -0,0 +1,30 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import com.google.common.collect.Lists; + +import java.util.List; +/** + * @author Yannick Pihan + */ +public class AmplLoad extends AmplElement { + + private final String id; + + public AmplLoad(String name) { + this.id = name; + } + + @Override + public List getOrderedValues() { + return Lists.newArrayList(id); + } + + public String getId() { + return id; + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplLoadParameters.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplLoadParameters.java new file mode 100644 index 00000000..ad7eb5eb --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplLoadParameters.java @@ -0,0 +1,52 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import com.google.common.collect.Lists; + +import java.util.List; +/** + * @author Yannick Pihan + */ +public class AmplLoadParameters extends AmplElement{ + + private final String id; + private final String connectedNodeId; + private final boolean initialConfigG; + private final boolean canReconfig; + private final float pl; + private final float ql; + private final float initialDL; + private final float dlMax; + private final float wDL; + + + public AmplLoadParameters(String id, String connectedNodeId, boolean connected, boolean canReconfig,float pl, float ql, float initialDL, float dlMax, float wDL) { + this.id = id; + this.connectedNodeId = connectedNodeId; + this.initialConfigG = connected; + this.canReconfig = canReconfig; + this.pl = pl; + this.ql = ql; + this.initialDL = initialDL; + this.dlMax = dlMax; + this.wDL = wDL; + } + + @Override + public List getOrderedValues() { + return Lists.newArrayList( + this.id, + this.connectedNodeId, + this.initialConfigG, + this.canReconfig, + this.pl, + this.ql, + this.initialDL, + this.dlMax, + this.wDL); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplModel.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplModel.java new file mode 100644 index 00000000..127da0d6 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplModel.java @@ -0,0 +1,107 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import java.util.List; +/** + * @author Yannick Pihan + */ +public class AmplModel { + + private final List generators; + private final List nodes; + private final List transBranches; + private final List simpleBranches; + private final List couplages; + private final List slackBuses; + private final List nodeParameters; + private final List slackBusParameters; + private final List generatorParameters; + private final List branchParameters; + private final List transformerParameters; + private final List couplingParameters; + private final List loads; + private final List loadParameters; + private final List capacitors; + private final List capacitorParameters; + + /** + * Constructor + */ + public AmplModel(List generators, + List loads, + List capacitors, List nodes, + List slackBuses, + List transBranches, + List simpleBranches, + List couplages, + List nodeParameters, + List slackBusParameters, + List generatorParameters, + List loadParameters, + List capacitorParameters, + List branchParameters, + List transformerParameters, + List amplCouplingParameters) { + + this.generators = generators; + this.loads = loads; + this.capacitors = capacitors; + this.nodes = nodes; + this.slackBuses = slackBuses; + this.transBranches = transBranches; + this.simpleBranches = simpleBranches; + this.couplages = couplages; + this.nodeParameters = nodeParameters; + this.slackBusParameters = slackBusParameters; + this.generatorParameters = generatorParameters; + this.loadParameters = loadParameters; + this.capacitorParameters = capacitorParameters; + this.branchParameters = branchParameters; + this.transformerParameters = transformerParameters; + this.couplingParameters = amplCouplingParameters; + } + + public List getGenerators() { + return generators; + } + + public List getLoads() { return loads; } + + public List getNodes() { return nodes; } + + public List getNodeParameters() { return nodeParameters; } + + public List getTransBranches() { return transBranches; } + + public List getSimpleBranches() { return simpleBranches; } + + public List getCouplages() { return this.couplages; } + + public List getSlackBuses() { return this.slackBuses; } + + public List getSlackBusParameters() { return this.slackBusParameters; } + + public List getGeneratorParameters() { return this.generatorParameters; } + + public List getBranchParameters() { return this.branchParameters; } + + public List getTransformerParameters() { return this.transformerParameters; } + + public List getCouplingParameters() { return this.couplingParameters; } + + public List getCapacitors() { + return capacitors; + } + + public List getLoadParameters() { + return loadParameters; + } + + public List getCapacitorParameters() { + return capacitorParameters; + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplNodeParameter.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplNodeParameter.java new file mode 100644 index 00000000..fab8ef6f --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplNodeParameter.java @@ -0,0 +1,46 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import com.google.common.collect.Lists; + +import java.util.List; +/** + * @author Yannick Pihan + */ +public class AmplNodeParameter extends AmplElement { + private String id; + private float vMin ; + private float vInit; + private float vMax; + private float vNom; + private float initialTH; + + public String getId() { + return id; + } + + public AmplNodeParameter(String id, float vMin, float vInit, float vMax, float vNom, float initialTH) { + this.id = id; + this.vMin = vMin; + this.vInit = vInit; + this.vMax = vMax; + this.vNom = vNom; + this.initialTH = initialTH; + } + + @Override + public List getOrderedValues() { + return Lists.newArrayList( + this.id, + this.vMin, + this.vInit, + this.vMax, + this.vNom, + this.initialTH + ); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplSimpleBranch.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplSimpleBranch.java new file mode 100644 index 00000000..d90cc67a --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplSimpleBranch.java @@ -0,0 +1,29 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import com.google.common.collect.Lists; + +import java.util.List; +/** + * @author Yannick Pihan + */ +public class AmplSimpleBranch extends AmplElement{ + private final String id; + + public AmplSimpleBranch(String id) { + this.id = id.trim(); + } + + public String getId() { + return id; + } + + @Override + public List getOrderedValues() { + return Lists.newArrayList(this.id); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplSimpleNode.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplSimpleNode.java new file mode 100644 index 00000000..0d46d955 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplSimpleNode.java @@ -0,0 +1,33 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import com.google.common.base.Strings; +import com.google.common.collect.Lists; + +import java.util.List; + +import static com.google.common.base.Preconditions.checkArgument; +/** + * @author Yannick Pihan + */ +public class AmplSimpleNode extends AmplElement { + private String id; + + public AmplSimpleNode(String name) { + checkArgument(!Strings.isNullOrEmpty(name), "name must not be null or empty"); + this.id = name; + } + + public String getId() { + return id; + } + + @Override + public List getOrderedValues() { + return Lists.newArrayList(this.id); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplSlackBus.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplSlackBus.java new file mode 100644 index 00000000..60b2fbd3 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplSlackBus.java @@ -0,0 +1,27 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import com.google.common.collect.Lists; + +import java.util.List; +/** + * @author Yannick Pihan + */ +public class AmplSlackBus extends AmplElement { + private final String id; + + public AmplSlackBus(String id) { + this.id = id.trim(); + } + + public String getId() { + return id; + } + + @Override + public List getOrderedValues() { return Lists.newArrayList(this.id); } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplSlackBusParameters.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplSlackBusParameters.java new file mode 100644 index 00000000..f08718c0 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplSlackBusParameters.java @@ -0,0 +1,41 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import com.google.common.collect.Lists; + +import java.util.List; +/** + * @author Yannick Pihan + */ +public class AmplSlackBusParameters extends AmplElement { + private final String id; + private final float tMin; + private final float tMax; + + public AmplSlackBusParameters(String id, float tMin, float tMax) { + this.id = id; + this.tMin = tMin; + this.tMax = tMax; + } + + public String getId() { + return id; + } + + public float gettMin() { + return tMin; + } + + public float gettMax() { + return tMax; + } + + @Override + public List getOrderedValues() { + return Lists.newArrayList(this.id, this.tMin, this.tMax); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplTransformerBranch.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplTransformerBranch.java new file mode 100644 index 00000000..10aff8f2 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplTransformerBranch.java @@ -0,0 +1,29 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import com.google.common.collect.Lists; + +import java.util.List; +/** + * @author Yannick Pihan + */ +public class AmplTransformerBranch extends AmplElement{ + private String id; + + public String getId() { + return id; + } + + public AmplTransformerBranch(String id) { + this.id = id.trim(); + } + + @Override + public List getOrderedValues() { + return Lists.newArrayList(this.id); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplTransformerParameters.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplTransformerParameters.java new file mode 100644 index 00000000..360af30f --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplTransformerParameters.java @@ -0,0 +1,54 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import com.google.common.collect.Lists; + +import java.util.List; +/** + * @author Yannick Pihan + */ +public class AmplTransformerParameters implements AmplWritable { + + final String id; + final float rMin; + final float initialR; + final float rMax; + final float tapInit; + private final float tapMin; + private final float tapMax; + private final float phaseMin; + private final float phaseByTap; + + + public AmplTransformerParameters(String id, float rMin, float initialR, float rMax, float tapInit, float tapMin, float tapMax, float phaseMin, float phaseByTap) { + this.id = id; + this.rMin = rMin; + this.initialR = initialR; + this.rMax = rMax; + this.tapInit = tapInit; + this.tapMin = tapMin; + this.tapMax = tapMax; + this.phaseMin = phaseMin; + this.phaseByTap = phaseByTap; + + } + + @Override + public List getOrderedValues() { + return Lists.newArrayList( + this.id, + this.rMin, + this.initialR, + this.rMax, + this.tapInit, + this.tapMin, + this.tapMax, + this.phaseMin, + this.phaseByTap + ); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplWritable.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplWritable.java new file mode 100644 index 00000000..ee149892 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/AmplWritable.java @@ -0,0 +1,14 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import java.util.List; +/** + * @author Yannick Pihan + */ +public interface AmplWritable { + List getOrderedValues(); +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/DataUtil.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/DataUtil.java new file mode 100644 index 00000000..ec68fe9f --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/DataUtil.java @@ -0,0 +1,48 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +/** + * @author Yannick Pihan + */ +public class DataUtil { + + /** + * Give value without NaN + * @return the value or 0.f if the value is NaN + */ + public static float getSafeValueOf(float value) { + return Float.isNaN(value) ? 0f : value; + } + + public static Object replaceNanByEmpty(float value) { + return Float.isNaN(value) ? "" : value; + } + + /** + * Give value without NaN + * @return the value or the default value iff the value is NaN + */ + public static float getSafeValueOf(float value, float defaultValue) { + return Float.isNaN(value) ? defaultValue : value; + } + + /** + * Give value without NaN + * @return the value or 0.f if the value is NaN + */ + public static double getSafeValueOf(double value) { + return Double.isNaN(value) ? 0f : value; + } + + /** + * Give value without NaN + * @return the value or the default value iff the value is NaN + */ + public static double getSafeValueOf(double value, double defaultValue) { + return Double.isNaN(value) ? 0f : defaultValue; + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/FlowType.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/FlowType.java new file mode 100644 index 00000000..403ddfcd --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/FlowType.java @@ -0,0 +1,13 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; +/** + * @author Yannick Pihan + */ +public enum FlowType { + SIDE1, + SIDE2 +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/FlowUnit.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/FlowUnit.java new file mode 100644 index 00000000..563f88c8 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/FlowUnit.java @@ -0,0 +1,27 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; +/** + * @author Yannick Pihan + */ +public enum FlowUnit { + AMPERE("A"), + MVA("MVA"), + MW_S1("MW"), + MW_S2("MW"), + MVAR_S1("MVAR"), + MVAR_S2("MVAR"); + + private String unit; + + FlowUnit(String unit) { + this.unit = unit; + } + + public String getUnit() { + return unit; + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoBank.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoBank.java new file mode 100644 index 00000000..91229eb7 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoBank.java @@ -0,0 +1,81 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import com.google.common.collect.Lists; + +import java.util.List; +/** + * @author Yannick Pihan + */ +public class IpsoBank extends IpsoOneConnectionEquipment { + + private static final String INITIAL_STEP_NUMBER = "INITIAL_STEP_NUMBER"; + private static final String MAX_STEP_NUMBER = "MAX_STEP_NUMBER"; + private static final String CONNECTED = "CONNECTED"; + private static final String NODE_NAME = "NODE_NAME"; + private static final String ACTIVE_LOSSES_BY_STEP = "ACTIVE_LOSSES_BY_STEP"; + private static final String REACTIVE_LOSSES_BY_STEP = "REACTIVE_LOSSES_BY_STEP"; + private final int maxSteps; + private final int selectedSteps; + private final float activePöwerByStep; + private final float reactivePowerByStep; + + public IpsoBank(String id, String iidmId, IpsoNode connectedNode, boolean connected, int maxSteps, int selectedSteps, float activePöwerByStep, float reactivePowerByStep, int world) { + super(id, iidmId, connectedNode, world); + this.connected = connected; + this.maxSteps = maxSteps; + this.selectedSteps = selectedSteps; + this.activePöwerByStep = activePöwerByStep; + this.reactivePowerByStep = reactivePowerByStep; + } + + public int getCurrentSectionCount() { + return selectedSteps; + } + + public int getMaxSteps() { + return maxSteps; + } + + public int getSelectedSteps() { + return selectedSteps; + } + + public float getActivePöwerByStep() { + return activePöwerByStep; + } + + public float getReactivePowerByStep() { + return reactivePowerByStep; + } + + @Override + public List getOrderedHeaders() { + return Lists.newArrayList( + NAME, + NODE_NAME, + CONNECTED, + MAX_STEP_NUMBER, + INITIAL_STEP_NUMBER, + ACTIVE_LOSSES_BY_STEP, + REACTIVE_LOSSES_BY_STEP, + WORLD); + } + + @Override + public List getOrderedValues() { + return Lists.newArrayList( + getId(), + getConnectedNode().getId(), + connected, + maxSteps, + selectedSteps, + replaceNanAndLogIt(ACTIVE_LOSSES_BY_STEP, activePöwerByStep, 0f), + replaceNanAndLogIt(REACTIVE_LOSSES_BY_STEP, reactivePowerByStep, 0f), + getWorld()); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoBoundsEvaluator.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoBoundsEvaluator.java new file mode 100644 index 00000000..1d3411db --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoBoundsEvaluator.java @@ -0,0 +1,64 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import static com.google.common.base.Preconditions.checkArgument; +/** + * @author Yannick Pihan + */ +public class IpsoBoundsEvaluator { + + public static final float EPSILON_VALUE = 0.0001f; + protected static final float EPSILON_BOUNDS = 0.00001f; + + /** + * @return true if the value is out of min and max bounds + */ + public static boolean isOutOfBounds(float value, float min, float max) { + checkArgument(!Float.isNaN(min), "min value must not ne NaN"); + checkArgument(!Float.isNaN(max), "max value must not ne NaN"); + if(Float.isNaN(value)) { + return false; + } + else { + return isConfoundedBounds(min, max) ? isOutOfSetpoint(value, min, max) : isOutsideBounds(value, min, max); + } + } + + /** + * @return true if min is very close to max + */ + public static boolean isConfoundedBounds(float min, float max) { + checkArgument(!Float.isNaN(min), "min value must not ne NaN"); + checkArgument(!Float.isNaN(max), "max value must not ne NaN"); + checkArgument(max >= min, "max value must be greater then min value"); + return max-min <= EPSILON_BOUNDS; + } + + private static boolean isOutOfSetpoint(float value, float min, float max) { + if(Float.isNaN(value)) { + return false; + } + else { + return value < (min+max )/2 - EPSILON_VALUE || value > (min+max)/2 + EPSILON_VALUE; + } + } + + private static boolean isOutsideBounds(float value, float min, float max) { + checkArgument(!Float.isNaN(value), "value value must not ne NaN"); + checkArgument(!Float.isNaN(min), "min value must not ne NaN"); + checkArgument(!Float.isNaN(max), "max value must not ne NaN"); + checkArgument(max >= min, "max value must be greater then min value"); + return value < min - EPSILON_VALUE || value > max + EPSILON_VALUE; + } + public static boolean isJustOnTheBounds(float value, float min, float max) { + checkArgument(!Float.isNaN(value), "value value must not ne NaN"); + checkArgument(!Float.isNaN(min), "min value must not ne NaN"); + checkArgument(!Float.isNaN(max), "max value must not ne NaN"); + checkArgument(max >= min, "max value must be greater then min value"); + return value < min + EPSILON_VALUE || value > max - EPSILON_VALUE; + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoComponent.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoComponent.java new file mode 100644 index 00000000..f9f4012b --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoComponent.java @@ -0,0 +1,98 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; +import org.slf4j.Logger; + +import static com.google.common.base.Preconditions.checkArgument; +import static org.apache.commons.lang3.StringUtils.isNotEmpty; +import static org.slf4j.LoggerFactory.getLogger; +/** + * @author Yannick Pihan + */ +public abstract class IpsoComponent implements IpsoWritable{ + + private static final Logger LOG = getLogger(IpsoComponent.class); + + protected static final String NAME = "NAME"; + protected static final String WORLD = "WORLD"; + + private final String id; + private final int world; + public IpsoComponent(String id, int world) { + checkArgument(isNotEmpty(id), "id cannot be null or empty"); + checkArgument(world >= 0, "world must be greater or equal to zero"); + this.id = id; + this.world = world; + } + + /** + * @return id of the Ipso component + * Remark: The id is limited to a specific number of character in + * according to the type of component + */ + public String getId() { + return id; + } + + /** + * @return the network state index of the component: + *

0 - healthy state

+ *

1 - network state for the first contengy

+ *

2 - network state for the second contengy

* + *

...

+ */ + public int getWorld() { + return world; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (!(o instanceof IpsoComponent)) { + return false; + } + + IpsoComponent that = (IpsoComponent) o; + return new EqualsBuilder().append(id, that.getId()).isEquals(); + } + + @Override + public int hashCode() { + return new HashCodeBuilder().append(id).toHashCode(); + } + + /** + * @return replace NaN by a default value and log it + */ + protected float replaceNanAndLogIt(String attributeName, float value, float defaultValue) { + checkArgument(attributeName != null, "attributeName must not be null"); + if ( Float.isNaN(value)) { + logNaN(attributeName, defaultValue); + } + return DataUtil.getSafeValueOf(value, defaultValue); + } + + public void logNaN(String attributeName, float defaultValue) { + LOG.warn("The Ipos component {} {} has NaN for attibute {}. It is replaced by {}", + getClass().getSimpleName(), + getId(), + attributeName, + defaultValue); + } + + @Override + public String toString() { + return String.format("%s %s", + getClass().getSimpleName(), + getOrderedHeaders().toString()); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoConstraint.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoConstraint.java new file mode 100644 index 00000000..9b925808 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoConstraint.java @@ -0,0 +1,129 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import eu.itesla_project.cta.service.IpsoIdUtil; +import org.slf4j.Logger; + +import java.util.List; +import java.util.Set; + +import static org.slf4j.LoggerFactory.getLogger; +/** + * @author Yannick Pihan + */ +public abstract class IpsoConstraint extends IpsoComponent implements IpsoProblemDefinitionElement { + + private static final Logger LOG = getLogger(IpsoConstraint.class); + protected static final String UNIT = "UNIT"; + + private final T equipment; + + private final float boundsMin; + private final float boundsMax; + + public IpsoConstraint(T equipment, float boundsMin, float boundsMax, int world) { + super(IpsoIdUtil.getNextUniqueId(), world); + this.equipment = equipment; + this.boundsMin = replaceNanAndLogIt("MIN", boundsMin, defaultBoundsMin()); + this.boundsMax = replaceNanAndLogIt("MAX", boundsMax, defaultBoundsMax()); + } + + protected float defaultBoundsMin() { + return -9999f; + } + + protected float defaultBoundsMax() { + return 9999f; + } + + public boolean isViolated() { + return IpsoBoundsEvaluator.isOutOfBounds(getConstrainedAttributeValueFor(equipment), boundsMin, boundsMax); + } + + public boolean isNotViolated() { + return !isViolated(); + } + + @Override + public List getOrderedValues() { + return Lists.newArrayList(equipment.getId(), getBoundsMin(), getBoundsMax(), getWorld()); + } + + public float getBoundsMin() { + return boundsMin; + } + + public float getBoundsMax() { + return boundsMax; + } + + protected abstract float getConstrainedAttributeValueFor(T equipment); + + public float getConstrainedValue() { + return getConstrainedAttributeValueFor(equipment); + } + + @Override + public T getRelatedIpsoEquipment() { + return equipment; + } + + public boolean isSetpointConstraint() { + return IpsoBoundsEvaluator.isConfoundedBounds(boundsMin, boundsMax); + } + + public boolean isNotSetpointConstraint() { + return !isSetpointConstraint(); + } + + @Override + public void logNaN(String attributeName, float defaultValue) { + LOG.warn("The Ipso Constraint {} for {} ({}) has NaN for attibute {}. It is replaced by {}", + this.getClass().getSimpleName(), + equipment.getId(), + equipment.getIidmId(), + attributeName, + defaultValue); + } + + @Override + public String toString() { + return String.format("Constraint (%s) id=%s, %s=%s (%s), value=%s, min=%s, max = %s", + this.getClass().getSimpleName(), + getId(), + getRelatedIpsoEquipment().getClass().getSimpleName(), + getRelatedIpsoEquipment().getId(), + getRelatedIpsoEquipment().getIidmId(), + getConstrainedValue(), + getBoundsMin(), + getBoundsMax()); + } + + @Override + public boolean isConstraint() { + return true; + } + + @Override + public boolean isVariable() { + return false; + } + + + private static Set> flowConstraints = Sets.newHashSet( + IpsoConstraint2WTransformerFlow.class, + IpsoConstraint3WTransformerFlow.class, + IpsoConstraintLineFlowSide1.class, + IpsoConstraintLineFlowSide2.class + ); + + public boolean isCurrentViolation() { + return (flowConstraints.contains(this.getClass())); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoConstraint2WTransformerFlow.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoConstraint2WTransformerFlow.java new file mode 100644 index 00000000..7a744660 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoConstraint2WTransformerFlow.java @@ -0,0 +1,47 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import com.google.common.collect.Lists; + +import java.util.List; +/** + * @author Yannick Pihan + */ +public class IpsoConstraint2WTransformerFlow extends AbstractFlowConstraint { + + /** + * Constructor + */ + public IpsoConstraint2WTransformerFlow(IpsoTwoWindingsTransformer transformer, FlowUnit unit, float min, float max, int world) { + super(transformer, unit, min, max, world); + } + + @Override + protected float getConstrainedAttributeValueFor(IpsoTwoWindingsTransformer equipment) { + return equipment.getCurrentFlow(); + } + + @Override + public List getOrderedHeaders() { + return Lists.newArrayList( + NAME, + UNIT, + FLOW_MIN, + FLOW_MAX, + WORLD); + } + + @Override + public List getOrderedValues() { + return Lists.newArrayList( + getRelatedIpsoEquipment().getId(), + getFlowUnit().getUnit(), + getBoundsMin(), + getBoundsMax(), + getWorld()); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoConstraint2WTransformerTapBounds.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoConstraint2WTransformerTapBounds.java new file mode 100644 index 00000000..ce4b7fd7 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoConstraint2WTransformerTapBounds.java @@ -0,0 +1,39 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import com.google.common.collect.Lists; + +import java.util.List; +/** + * @author Yannick Pihan + */ +public class IpsoConstraint2WTransformerTapBounds extends IpsoConstraint { + + protected static final String TAP_MIN = "TAP_MIN"; + protected static final String TAP_MAX = "TAP_MAX"; + + /** + * Constructor + */ + public IpsoConstraint2WTransformerTapBounds(IpsoTwoWindingsTransformer transformer, int tapMin, int tapMax, int world) { + super(transformer, tapMin, tapMax, world); + } + + @Override + protected float getConstrainedAttributeValueFor(IpsoTwoWindingsTransformer equipment) { + return equipment.getRegulationParameters().getCurrentStepPosition(); + } + + @Override + public List getOrderedHeaders() { + return Lists.newArrayList( + NAME, + TAP_MIN, + TAP_MAX, + WORLD); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoConstraint3WTransformerFlow.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoConstraint3WTransformerFlow.java new file mode 100644 index 00000000..61de1921 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoConstraint3WTransformerFlow.java @@ -0,0 +1,32 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import java.util.List; +/** + * @author Yannick Pihan + */ +public class IpsoConstraint3WTransformerFlow extends IpsoConstraint { + + public IpsoConstraint3WTransformerFlow(IpsoTwoWindingsTransformer transformer, float min, float max, int world) { + super(transformer,min,max,world); + } + + @Override + protected float getConstrainedAttributeValueFor(IpsoTwoWindingsTransformer equipment) { + return 0; + } + + @Override + public List getOrderedValues() { + return null; + } + + @Override + public List getOrderedHeaders() { + return null; + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoConstraintBankStepBounds.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoConstraintBankStepBounds.java new file mode 100644 index 00000000..b280570f --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoConstraintBankStepBounds.java @@ -0,0 +1,36 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import com.google.common.collect.Lists; + +import java.util.List; +/** + * @author Yannick Pihan + */ +public class IpsoConstraintBankStepBounds extends IpsoConstraint { + + protected static final String STEP_MIN = "STEP_MIN"; + protected static final String STEP_MAX = "STEP_MAX"; + + public IpsoConstraintBankStepBounds(IpsoBank ipsoBank, int stepMin, int stepMax, int world) { + super(ipsoBank, stepMin, stepMax, world); + } + + @Override + protected float getConstrainedAttributeValueFor(IpsoBank equipment) { + return equipment.getCurrentSectionCount(); + } + + @Override + public List getOrderedHeaders() { + return Lists.newArrayList( + NAME, + STEP_MIN, + STEP_MAX, + WORLD); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoConstraintGeneratorPBounds.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoConstraintGeneratorPBounds.java new file mode 100644 index 00000000..70c79150 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoConstraintGeneratorPBounds.java @@ -0,0 +1,39 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import com.google.common.collect.Lists; + +import java.util.List; +/** + * @author Yannick Pihan + */ +public class IpsoConstraintGeneratorPBounds extends IpsoConstraint { + + protected static final String POWER_MIN = "POWER_MIN"; + protected static final String POWER_MAX = "POWER_MAX"; + + /** + * Constructor + */ + public IpsoConstraintGeneratorPBounds(IpsoGenerator generator, float minActivePower, float maxActivePower, int world) { + super(generator, minActivePower, maxActivePower, world); + } + + @Override + protected float getConstrainedAttributeValueFor(IpsoGenerator equipment) { + return equipment.getActivePower(); + } + + @Override + public List getOrderedHeaders() { + return Lists.newArrayList( + NAME, + POWER_MIN, + POWER_MAX, + WORLD); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoConstraintGeneratorQBounds.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoConstraintGeneratorQBounds.java new file mode 100644 index 00000000..5fcac7b4 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoConstraintGeneratorQBounds.java @@ -0,0 +1,39 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import com.google.common.collect.Lists; + +import java.util.List; +/** + * @author Yannick Pihan + */ +public class IpsoConstraintGeneratorQBounds extends IpsoConstraint { + + protected static final String POWER_MIN = "POWER_MIN"; + protected static final String POWER_MAX = "POWER_MAX"; + + /** + * Constructor + */ + public IpsoConstraintGeneratorQBounds(IpsoGenerator generator, float minReactivePower, float maxReactivePower, int world) { + super(generator, minReactivePower, maxReactivePower, world); + } + + @Override + protected float getConstrainedAttributeValueFor(IpsoGenerator equipment) { + return equipment.getReactivePower(); + } + + @Override + public List getOrderedHeaders() { + return Lists.newArrayList( + NAME, + POWER_MIN, + POWER_MAX, + WORLD); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoConstraintLineFlowSide1.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoConstraintLineFlowSide1.java new file mode 100644 index 00000000..0a4edd4d --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoConstraintLineFlowSide1.java @@ -0,0 +1,21 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; +/** + * @author Yannick Pihan + */ +public class IpsoConstraintLineFlowSide1 extends AbstractIpsoConstraintLineFlow { + + public IpsoConstraintLineFlowSide1(IpsoLine line, FlowUnit unit, float min, float max, int world) { + super(line, unit, min, max, world); + } + + @Override + protected float getConstrainedAttributeValueFor(IpsoLine equipment) { + return Math.max(equipment.getCurrentFlowSide1(), equipment.getCurrentFlowSide2()); + } + +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoConstraintLineFlowSide2.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoConstraintLineFlowSide2.java new file mode 100644 index 00000000..1476e007 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoConstraintLineFlowSide2.java @@ -0,0 +1,21 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; +/** + * @author Yannick Pihan + */ +public class IpsoConstraintLineFlowSide2 extends AbstractIpsoConstraintLineFlow { + + public IpsoConstraintLineFlowSide2(IpsoLine line, FlowUnit unit, float min, float max, int world) { + super(line, unit, min, max, world); + } + + @Override + protected float getConstrainedAttributeValueFor(IpsoLine equipment) { + return equipment.getCurrentFlowSide2(); + } + +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoConstraintNodeAcAngleBounds.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoConstraintNodeAcAngleBounds.java new file mode 100644 index 00000000..d67e8c90 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoConstraintNodeAcAngleBounds.java @@ -0,0 +1,49 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import com.google.common.collect.Lists; + +import java.util.List; +/** + * @author Yannick Pihan + */ +public class IpsoConstraintNodeAcAngleBounds extends IpsoConstraint { + + protected static final String ANGLE_MIN = "ANGLE_MIN"; + protected static final String ANGLE_MAX = "ANGLE_MAX"; + + /** + * Constructor + */ + public IpsoConstraintNodeAcAngleBounds(IpsoNode ipsoNode, float angleMin, float angleMax, int world) { + super(ipsoNode, angleMin, angleMax, world); + } + + @Override + protected float defaultBoundsMin() { + return -360f; + } + + @Override + protected float defaultBoundsMax() { + return 360f; + } + + @Override + protected float getConstrainedAttributeValueFor(IpsoNode equipment) { + return equipment.getAngle(); + } + + @Override + public List getOrderedHeaders() { + return Lists.newArrayList( + NAME, + ANGLE_MIN, + ANGLE_MAX, + WORLD); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoConstraintNodeAcVoltageBounds.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoConstraintNodeAcVoltageBounds.java new file mode 100644 index 00000000..09cf930f --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoConstraintNodeAcVoltageBounds.java @@ -0,0 +1,64 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import com.google.common.collect.Lists; + +import java.util.List; +/** + * @author Yannick Pihan + */ +public class IpsoConstraintNodeAcVoltageBounds extends IpsoConstraint { + + protected static final String VOLTAGE_MIN = "VOLTAGE_MIN"; + protected static final String VOLTAGE_MAX = "VOLTAGE_MAX"; + public static final float DEFAULT_BOUND_MIN = 0f; + public static final float DEFAULT_BOUND_MAX = 1.5f; + private final VoltageUnit unit; + + public IpsoConstraintNodeAcVoltageBounds(IpsoNode ipsoNode, VoltageUnit unit, float minVoltage, float maxVoltage, int world) { + super(ipsoNode, minVoltage, maxVoltage, world); + this.unit = unit; + } + + /** + * @return node voltage in pu + */ + @Override + protected float getConstrainedAttributeValueFor(IpsoNode equipment) { + return equipment.getVoltage() / equipment.getBaseVoltage(); + } + + @Override + protected float defaultBoundsMin() { + return DEFAULT_BOUND_MIN; + } + + @Override + protected float defaultBoundsMax() { + return DEFAULT_BOUND_MAX; + } + + @Override + public List getOrderedHeaders() { + return Lists.newArrayList( + NAME, + UNIT, + VOLTAGE_MIN, + VOLTAGE_MAX, + WORLD); + } + + @Override + public List getOrderedValues() { + return Lists.newArrayList( + getRelatedIpsoEquipment().getId(), + unit.getUnit(), + DataUtil.replaceNanByEmpty(getBoundsMin()), + DataUtil.replaceNanByEmpty(getBoundsMax()), + getWorld()); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoControlVariable.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoControlVariable.java new file mode 100644 index 00000000..15582196 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoControlVariable.java @@ -0,0 +1,74 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import com.google.common.collect.Lists; +import eu.itesla_project.cta.service.IpsoIdUtil; +import org.slf4j.Logger; + +import java.util.List; + +import static org.slf4j.LoggerFactory.getLogger; +/** + * @author Yannick Pihan + */ +public abstract class IpsoControlVariable extends IpsoComponent implements IpsoProblemDefinitionElement { + + private static final Logger LOG = getLogger(IpsoControlVariable.class); + + private final T equipment; + private final float controlledValue; + + public IpsoControlVariable(T equipment, float controlledValue, int world) { + super(IpsoIdUtil.getNextUniqueId(), world); + this.equipment = equipment; + this.controlledValue = controlledValue; + } + + @Override + public List getOrderedValues() { + return Lists.newArrayList(equipment.getId(), controlledValue, getWorld()); + } + + @Override + public T getRelatedIpsoEquipment() { + return equipment; + } + + public float getControlledValue() { + return controlledValue; + } + + @Override + public void logNaN(String attributeName, float defaultValue) { + LOG.warn("The Ipso control variable {} for {} ({}) has NaN for attibute {}. It is replaced by {}", + this.getClass().getSimpleName(), + equipment.getId(), + equipment.getIidmId(), + attributeName, + defaultValue); + } + + @Override + public String toString() { + return String.format("Control variable id=%s, %s=%s (%s)", + getId(), + getRelatedIpsoEquipment().getClass().getSimpleName(), + getRelatedIpsoEquipment().getId(), + getRelatedIpsoEquipment().getIidmId(), + getControlledValue()); + } + + @Override + public boolean isVariable() { + return true; + } + + @Override + public boolean isConstraint() { + return false; + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoControlVariable2WTransformerTap.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoControlVariable2WTransformerTap.java new file mode 100644 index 00000000..b06d0150 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoControlVariable2WTransformerTap.java @@ -0,0 +1,49 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import com.google.common.collect.Lists; + +import java.util.List; +/** + * @author Yannick Pihan + */ +public class IpsoControlVariable2WTransformerTap extends IpsoControlVariable { + + private final LinkOption linkOption; + private final float speed; + private final float epsilon; + + /** + * Constructor + */ + public IpsoControlVariable2WTransformerTap(IpsoTwoWindingsTransformer transformer, LinkOption linkOption, float speed, float epsilon, int world) { + super(transformer, speed, world); + this.linkOption = linkOption; + this.speed = speed; + this.epsilon = epsilon; + } + + @Override + public List getOrderedValues() { + return Lists.newArrayList( + getRelatedIpsoEquipment().getId(), + linkOption.getOption(), + speed, + epsilon, + getWorld()); + } + + @Override + public List getOrderedHeaders() { + return Lists.newArrayList( + "NAME", + "LINK_OPTION", + "SPEED", + "EPSILON", + "WORLD"); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoControlVariableBankStep.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoControlVariableBankStep.java new file mode 100644 index 00000000..45b87b68 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoControlVariableBankStep.java @@ -0,0 +1,30 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import com.google.common.collect.Lists; + +import java.util.List; +/** + * @author Yannick Pihan + */ +public class IpsoControlVariableBankStep extends IpsoControlVariable { + + /** + * Constructor + */ + public IpsoControlVariableBankStep(IpsoBank bank, float speed, int world) { + super(bank, speed, world); + } + + @Override + public List getOrderedHeaders() { + return Lists.newArrayList( + "NAME", + "SPEED", + "WORLD"); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoControlVariableGeneratorStatism.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoControlVariableGeneratorStatism.java new file mode 100644 index 00000000..17b182ad --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoControlVariableGeneratorStatism.java @@ -0,0 +1,30 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import com.google.common.collect.Lists; + +import java.util.List; +/** + * @author Yannick Pihan + */ +public class IpsoControlVariableGeneratorStatism extends IpsoControlVariable { + + /** + * Constructor + */ + public IpsoControlVariableGeneratorStatism(IpsoGenerator generator, float voltageSetpoint, int world) { + super(generator, voltageSetpoint, world); + } + + @Override + public List getOrderedHeaders() { + return Lists.newArrayList( + "NAME", + "VOLTAGE_SETPOINT", + "WORLD"); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoControlVariableProductionP.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoControlVariableProductionP.java new file mode 100644 index 00000000..dfcc7801 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoControlVariableProductionP.java @@ -0,0 +1,39 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import com.google.common.collect.Lists; + +import java.util.List; +/** + * @author Yannick Pihan + */ +public class IpsoControlVariableProductionP extends IpsoControlVariable { + + private final LinkOption option; + private final float speed; + + public IpsoControlVariableProductionP(IpsoGenerator generator, LinkOption option, float speed, int world) { + super(generator, speed, world); + this.option = option; + this.speed = speed; + } + + @Override + public List getOrderedValues() { + return Lists.newArrayList(getRelatedIpsoEquipment().getId(), option.getOption(), speed, getWorld()); + } + + @Override + public List getOrderedHeaders() { + return Lists.newArrayList( + "NAME", + "LINK_OPTION", + "SPEED", + "WORLD"); + } +} + diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoControlVariableProductionQ.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoControlVariableProductionQ.java new file mode 100644 index 00000000..03006730 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoControlVariableProductionQ.java @@ -0,0 +1,38 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import com.google.common.collect.Lists; + +import java.util.List; +/** + * @author Yannick Pihan + */ +public class IpsoControlVariableProductionQ extends IpsoControlVariable { + + private final LinkOption linkOption; + private final float speed; + + public IpsoControlVariableProductionQ(IpsoGenerator generator, LinkOption linkOption, float speed, int world) { + super(generator, speed, world); + this.linkOption = linkOption; + this.speed = speed; + } + + @Override + public List getOrderedValues() { + return Lists.newArrayList(getRelatedIpsoEquipment().getId(), linkOption.getOption(), speed, getWorld()); + } + + @Override + public List getOrderedHeaders() { + return Lists.newArrayList( + "NAME", + "LINK_OPTION", + "SPEED", + "WORLD"); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoCoupling.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoCoupling.java new file mode 100644 index 00000000..25a59680 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoCoupling.java @@ -0,0 +1,49 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import com.google.common.collect.Lists; + +import java.util.List; +/** + * @author Yannick Pihan + */ +public class IpsoCoupling extends AbstractIpsoBranch{ + + private static final String NODE_NAME_1 = "NODE_NAME_1"; + private static final String NODE_NAME_2 = "NODE_NAME_2"; + private static final String CONNECTION_STATUS = "CONNECTION_STATUS"; + private final boolean connected; + + /** + * constructor + */ + public IpsoCoupling(String id, String iidmId,IpsoNode ipsoNode1, IpsoNode ipsoNode2, boolean connected, int world) { + super(id, iidmId, world, ipsoNode1, ipsoNode2); + this.connected = connected; + } + + @Override + public List getOrderedValues() { + return Lists.newArrayList(getId(), ipsoNode1.getId(), ipsoNode2.getId(), getConnectionCodeFor(connected), getWorld()); + } + + @Override + public List getOrderedHeaders() { + return Lists.newArrayList( + NAME, + NODE_NAME_1, + NODE_NAME_2, + CONNECTION_STATUS, + WORLD); + } + + @Override + public boolean isConnected() { + return connected; + } + +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoEquipment.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoEquipment.java new file mode 100644 index 00000000..18df25d3 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoEquipment.java @@ -0,0 +1,47 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import org.slf4j.Logger; + +import static org.slf4j.LoggerFactory.getLogger; +/** + * @author Yannick Pihan + */ +public abstract class IpsoEquipment extends IpsoComponent { + + private static final Logger LOG = getLogger(IpsoEquipment.class); + + private final String iidmId; + + public IpsoEquipment(String id, String iidmId, int world) { + super(id, world); + this.iidmId = iidmId; + } + + public String getIidmId() { + return iidmId; + } + + @Override + public void logNaN(String attributeName, float defaultValue) { + LOG.warn("The Ipso equipment {} {} ({}) has NaN for attibute {}. It is replaced by {}", + this.getClass().getSimpleName(), + getId(), + iidmId, + attributeName, + defaultValue); + } + + @Override + public String toString() { + return String.format("%s, %s=%s (%s)", + getId(), + getClass().getSimpleName(), + getId(), + getIidmId()); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoGenerator.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoGenerator.java new file mode 100644 index 00000000..3698e070 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoGenerator.java @@ -0,0 +1,208 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import com.google.common.collect.Lists; + +import java.util.List; + +import static com.google.common.base.Preconditions.checkArgument; +/** + * @author Yannick Pihan + */ +public class IpsoGenerator extends IpsoOneConnectionEquipment { + protected static final float DELTA_Q_EPSILON = 0.1f; + + protected static final String NODE_NAME = "NODE_NAME"; + protected static final String CONNECTED = "CONNECTED"; + protected static final String INITIAL_ACTIVE_POWER = "INITIAL_ACTIVE_POWER"; + protected static final String INITIAL_REACTIVE_POWER = "INITIAL_REACTIVE_POWER"; + protected static final String MIN_ACTIVE_POWER = "MIN_ACTIVE_POWER"; + protected static final String MAX_ACTIVE_POWER = "MAX_ACTIVE_POWER"; + protected static final String MIN_REACTIVE_POWER = "MIN_REACTIVE_POWER"; + protected static final String MAX_REACTIVE_POWER = "MAX_REACTIVE_POWER"; + protected static final String NOMINAL_POWER = "NOMINAL_POWER"; + protected static final String NOMINAL_ACTIVE_POWER = "NOMINAL_ACTIVE_POWER"; + protected static final String NOMINAL_REACTIVE_POWER = "NOMINAL_REACTIVE_POWER"; + protected static final String NOMINAL_VOLTAGE = "NOMINAL_VOLTAGE"; + private final boolean regulating; + private final float minActivePower; + private final float maxActivePower; + private final float minReactivePower; + private final float maxReactivePower; + private final float nominalPower; + private final float activePower; + private final float reactivePower; + private final float nominalVoltage; + private final float setpointVoltage; + private final float deltaQ; + private boolean biggest; // biggest active power + + /** + * Constructor + */ + public IpsoGenerator(String id, + String iidmId, + IpsoNode connectedNode, + boolean connected, + boolean regulating, + float minActivePower, + float maxActivePower, + float minReactivePower, + float maxReactivePower, + float nominalPower, + float activePower, + float reactivePower, + float nominalVoltage, + float setpointVoltage, + int world) { + super(id, iidmId, connectedNode, world); + checkArgument(connectedNode != null, "connectedNode must not be null"); + this.regulating = regulating; + this.connected = connected; + this.minActivePower = minActivePower; + this.maxActivePower = maxActivePower; + this.minReactivePower = minReactivePower; + this.maxReactivePower = maxReactivePower; + this.nominalPower = nominalPower; + this.activePower = activePower; + this.reactivePower = reactivePower; + this.nominalVoltage = nominalVoltage; + this.setpointVoltage = setpointVoltage; + this.deltaQ = maxReactivePower - minReactivePower; + } + + public boolean isRegulating() { + return regulating; + } + + public void setBiggest(boolean biggest) { + this.biggest = biggest; + } + + /** + * + * @return true if the generator is the biggest one + * Remark: The biggest generator is always connected to a node + */ + public boolean isBiggest() { + return biggest; + } + + /** + * @return true iff Qmax-Qmin > DELTAT_Q_EPSILON + */ + public boolean isDeltaQLimitUpperThanOneMvar() { + return Math.abs(maxReactivePower - minReactivePower) > DELTA_Q_EPSILON; + } + + /** + * @return true iff Qmax-Qmin < DELTAT_Q_EPSILON + */ + public boolean isDeltaQLimitLowerThanOneMvar() { + return Math.abs(deltaQ) < DELTA_Q_EPSILON; + } + + public float getDeltaQ() { + return deltaQ; + } + + public float getMinActivePower() {return minActivePower;} + + public float getMaxActivePower() {return maxActivePower;} + + public float getMinReactivePower() {return minReactivePower;} + + public float getMaxReactivePower() {return maxReactivePower;} + + + /** + * @return the voltage setpoint in pu + */ + public float getVoltageSetpointPu() { + if (Float.isNaN(setpointVoltage) || + Float.isNaN(nominalVoltage) || + nominalVoltage == 0f) { + return Float.NaN; + } + else { + return setpointVoltage / nominalVoltage; + } + } + + + public float getActivePower() { + return activePower; + } + + public float getReactivePower() { + return reactivePower; + } + + private char connectionStatusOf(boolean connected) { + return connected ? 'Y' : 'N'; + } + + @Override + public List getOrderedHeaders() { + return Lists.newArrayList( + NAME, + NODE_NAME, + CONNECTED, + INITIAL_ACTIVE_POWER, + INITIAL_REACTIVE_POWER, + MIN_ACTIVE_POWER, + MAX_ACTIVE_POWER, + MIN_REACTIVE_POWER, + MAX_REACTIVE_POWER, + NOMINAL_POWER, + NOMINAL_ACTIVE_POWER, + NOMINAL_REACTIVE_POWER, + NOMINAL_VOLTAGE, + "BVD", // not used + "XMQ", // not used + "SETPOINT_VOLTAGE", + "CALVAER_VOLTAGE", // not used + "CAPABILITY_CURVE_QMIN_PMIN", // not used + "CAPABILITY_CURVE_QMIN_PMAX", // not used + "CAPABILITY_CURVE_XCR", // not used + "GENERATOR_TYPE", // not used + "NUMBER_OF_LINKED_GENERATORS", // not used + "NAMES_OF_LINKED_GENERATORS", // will be a string + "DROOP_COEFFICIENT", // not used + "WORLD"); + } + + @Override + public List getOrderedValues() { + return Lists.newArrayList( + getId(), + getConnectedNode().getId(), + connectionStatusOf(connected), + replaceNanAndLogIt(INITIAL_ACTIVE_POWER, activePower,0f), + replaceNanAndLogIt(INITIAL_REACTIVE_POWER, reactivePower,0f), + replaceNanAndLogIt(MIN_ACTIVE_POWER, minActivePower,0f), + replaceNanAndLogIt(MAX_ACTIVE_POWER, maxActivePower,0f), + replaceNanAndLogIt(MIN_REACTIVE_POWER, minReactivePower,0f), + replaceNanAndLogIt(MAX_REACTIVE_POWER, maxReactivePower,0f), + replaceNanAndLogIt(NOMINAL_POWER, nominalPower,0f), + replaceNanAndLogIt(NOMINAL_ACTIVE_POWER, activePower,0f), + replaceNanAndLogIt(NOMINAL_REACTIVE_POWER, reactivePower,0f), + replaceNanAndLogIt(NOMINAL_VOLTAGE, nominalVoltage,0f), + null, // BVD + null, // XMQ + DataUtil.getSafeValueOf(setpointVoltage), + null, // "CALVAER_VOLTAGE" + null, // CAPABILITY_CURVE_QMIN_PMIN" not used + null, // CAPABILITY_CURVE_QMIN_PMAX" not used + null, // CAPABILITY_CURVE_XCR" not used + null, // GENERATOR_TYPE" not used + null, // NUMBER_OF_LINKED_GENERATORS" not used + null, // NAMES_OF_LINKED_GENERATORS" will be a string + null, // DROOP_COEFFICIENT" not used + getWorld()); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoLine.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoLine.java new file mode 100644 index 00000000..f0628b0b --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoLine.java @@ -0,0 +1,110 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import com.google.common.collect.Lists; + +import java.util.List; + +import static com.google.common.base.Preconditions.checkArgument; +/** + * @author Yannick Pihan + */ +public class IpsoLine extends AbstractIpsoBranch { + + private final boolean connectedSide1; + private final boolean connectedSide2; + private final float maxCurrentPermanentLimit; + private final float currentFlowSide1; + private final float rpu; + private final float xpu; + private final float gpu; + private final float bpu; + private final float currentFlowSide2; + + public IpsoLine(String id, String iidmId, IpsoNode ipsoNode1, IpsoNode ipsoNode2, boolean connectedSide1, boolean connectedSide2, float rpu, float xpu, float gpu, float bpu, float maxCurrentPermanentLimit, float currentFlowSide1, float currentFlowSide2, int world) { + super(id, iidmId, world, ipsoNode1, ipsoNode2); + checkArgument(ipsoNode1 != null, "ipsoNode1 must not be null"); + checkArgument(ipsoNode2 != null, "ipsoNode2 must not be null"); + this.connectedSide1 = connectedSide1; + this.connectedSide2 = connectedSide2; + this.rpu = rpu; + this.xpu = xpu; + this.gpu = gpu; + this.bpu = bpu; + this.maxCurrentPermanentLimit = maxCurrentPermanentLimit; + this.currentFlowSide1 = currentFlowSide1; + this.currentFlowSide2 = currentFlowSide2; + } + + public float getMaxCurrentPermanentLimit() { + return maxCurrentPermanentLimit; + } + + public boolean hasMaxCurrentPermanentLimitDefined() { + return !Float.isNaN(maxCurrentPermanentLimit); + } + + public float getCurrentFlowSide1() { + return currentFlowSide1; + } + + public float getCurrentFlowSide2() { + return currentFlowSide2; + } + + public float getResistance() { return rpu; } + + public float getReactance() { return xpu; } + + public float getSemiConductance() { return gpu; } + + public float getSemiSusceptance() { return bpu; } + + private char connectionStatusOf(boolean connected) { + return connected ? 'Y' : 'N'; + } + + @Override + public List getOrderedHeaders() { + return Lists.newArrayList( + "NAME", + "NODE_NAME_1", + "NODE_NAME_2", + "CONNECTED_SIDE_1", + "CONNECTED_SIDE_2", + "RESISTANCE", + "REACTANCE", + "SEMI_CONDUCTANCE", + "SEMI_SUSCEPTANCE", + "WORLD"); + } + + @Override + public List getOrderedValues() { + return Lists.newArrayList( + getId(), + ipsoNode1.getId(), + ipsoNode2.getId(), + connectionStatusOf(connectedSide1), + connectionStatusOf(connectedSide2), + rpu, + xpu, + gpu, + bpu, + getWorld()); + } + + @Override + public boolean isConnected() { + return connectedSide1 && connectedSide2; + } + + @Override + protected char getConnectionCodeFor(boolean connected) { + return connected ? 'Y' : 'N'; + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoLoad.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoLoad.java new file mode 100644 index 00000000..9702e4e9 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoLoad.java @@ -0,0 +1,66 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import com.google.common.collect.Lists; + +import java.util.List; + +import static com.google.common.base.Preconditions.checkArgument; +/** + * @author Yannick Pihan + */ +public class IpsoLoad extends IpsoOneConnectionEquipment { + + protected static final String NODE_NAME = "NODE_NAME"; + protected static final String CONNECTED = "CONNECTED"; + protected static final String INITIAL_ACTIVE_POWER = "INITIAL_ACTIVE_POWER"; + protected static final String INITIAL_REACTIVE_POWER = "INITIAL_REACTIVE_POWER"; + private final float activePower; + private final float reactivePower; + + public IpsoLoad(String id, String iidmId,IpsoNode connectedNode, boolean connected, float activePower, float reactivePower, int world) { + super(id, iidmId, connectedNode, world); + checkArgument(connectedNode != null, "connectedNode must not be null"); + this.connected = connected; + this.activePower = activePower; + this.reactivePower = reactivePower; + } + + private char connectionStatusOf(boolean connected) { + return connected ? 'Y' : 'N'; + } + + @Override + public List getOrderedHeaders() { + return Lists.newArrayList( + NAME, + NODE_NAME, + CONNECTED, + INITIAL_ACTIVE_POWER, + INITIAL_REACTIVE_POWER, + WORLD); + } + + @Override + public List getOrderedValues() { + return Lists.newArrayList( + getId(), + getConnectedNode().getId(), + connectionStatusOf(connected), + replaceNanAndLogIt(INITIAL_ACTIVE_POWER, activePower, 0f), + replaceNanAndLogIt(INITIAL_REACTIVE_POWER, reactivePower, 0f), + getWorld()); + } + + public float getActivePower() { + return activePower; + } + + public float getReactivePower() { + return reactivePower; + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoNetworkState.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoNetworkState.java new file mode 100644 index 00000000..38cce152 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoNetworkState.java @@ -0,0 +1,257 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import eu.itesla_project.cta.converter.MappingBetweenIidmIdAndIpsoEquipment; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static java.util.stream.Collectors.toList; +/** + * @author Yannick Pihan + */ +public class IpsoNetworkState implements IpsoOptimizationDataInput { + + private final MappingBetweenIidmIdAndIpsoEquipment mappingBetweenIidmIdAndIpsoEquipment; + private final int world; + private String caseName; + private List ipsoNodes; + private List ipsoLines; + private List ipsoGenerators; + private List ipsoLoads; + private List ipsoBanks; + private List ipsoCouplings; + private List ipsoTwoWindingsTransformers; + + /** + * Constructor + */ + public IpsoNetworkState(int world, String caseName, MappingBetweenIidmIdAndIpsoEquipment mappingBetweenIidmIdAndIpsoEquipment) { + this.world = world; + this.caseName = caseName; + this.ipsoNodes = new ArrayList<>(); + this.ipsoLines = new ArrayList<>(); + this.ipsoGenerators = new ArrayList<>(); + this.ipsoLoads = new ArrayList<>(); + this.ipsoBanks = new ArrayList<>(); + this.ipsoCouplings = new ArrayList<>(); + this.ipsoTwoWindingsTransformers = new ArrayList<>(); + this.mappingBetweenIidmIdAndIpsoEquipment = mappingBetweenIidmIdAndIpsoEquipment; + } + + public IpsoNetworkState(IpsoNetworkState ipsoNetworkState, int contingencyIndex, MappingBetweenIidmIdAndIpsoEquipment mappingBetweenIidmIdAndIpsoEquipment) { + super(); + this.world = contingencyIndex+1; + this.caseName = ipsoNetworkState.getCaseName(); + this.ipsoNodes = new ArrayList<>(ipsoNetworkState.getIpsoNodes()); + this.ipsoLines = new ArrayList<>(ipsoNetworkState.getIpsoLines()); + this.ipsoGenerators = new ArrayList<>(ipsoNetworkState.getIpsoGenerators()); + this.ipsoLoads = new ArrayList<>(ipsoNetworkState.getIpsoLoads()); + this.ipsoBanks = new ArrayList<>(ipsoNetworkState.getIpsoBanks()); + this.ipsoCouplings = new ArrayList<>(ipsoNetworkState.getIpsoCouplings()); + this.ipsoTwoWindingsTransformers = new ArrayList<>(ipsoNetworkState.getIpsoTwoWindingsTransformers()); + this.mappingBetweenIidmIdAndIpsoEquipment = mappingBetweenIidmIdAndIpsoEquipment; + } + + + public List getIpsoNodes() { + return ipsoNodes; + } + + public List getIpsoLines() { + return ipsoLines; + } + + public List getIpsoGenerators() { + return ipsoGenerators; + } + + public List getIpsoLoads() { + return ipsoLoads; + } + + public List getIpsoBanks() { + return ipsoBanks; + } + + public List getIpsoCouplings() { + return ipsoCouplings; + } + + public List getIpsoTwoWindingsTransformers() { + return ipsoTwoWindingsTransformers; + } + + public void addNodes(List nodes) { + ipsoNodes.addAll(nodes); + } + + public void addNode(IpsoNode nodes) { ipsoNodes.add(nodes); } + + public void addLines(List lines) { + ipsoLines.addAll(lines); + } + + public void addGenerators(List generators) { + this.ipsoGenerators.addAll(generators); + } + + public void addLoads(List loads) { + this.ipsoLoads.addAll(loads); + } + + public void addBanks(List banks) { + this.ipsoBanks.addAll(banks); + } + + public void addCouplings(List couplings) { + this.ipsoCouplings.addAll(couplings); + } + + public void addTwoWindingsTransformers(List transformers) { + this.ipsoTwoWindingsTransformers.addAll(transformers); + } + + @Override + public int getWorld() { + return world; + } + + @Override + public String getCaseName() { + return caseName; + } + + public Stream getConnectedAndRegulatingGenerators() { + return getIpsoGenerators().stream() + .filter(IpsoGenerator::isConnected) + .filter(IpsoGenerator::isRegulating); + } + + public Stream getConnectedAndRegulatingRatioTapChangerTransformer() { + return getIpsoTwoWindingsTransformers().stream() + .filter(IpsoTwoWindingsTransformer::isConnectedOnBothSides) + .filter(IpsoTwoWindingsTransformer::isRegulating) + .filter(IpsoTwoWindingsTransformer::isRatioTapChanger); + } + + public Stream getConnectedAndRegulatingPhaseTapChangerTransformer() { + return getIpsoTwoWindingsTransformers().stream() + .filter(IpsoTwoWindingsTransformer::isConnectedOnBothSides) + .filter(IpsoTwoWindingsTransformer::isRegulating) + .filter(IpsoTwoWindingsTransformer::isPhaseTapChanger); + } + + public MappingBetweenIidmIdAndIpsoEquipment getMappingBetweenIidmIdAndIpsoEquipment() { + return mappingBetweenIidmIdAndIpsoEquipment; + } + + + public IpsoNetworkState getInterconnectedVersion(List topologicalActions) { + IpsoNetworkState result = new IpsoNetworkState(this.world, + this.caseName, + new MappingBetweenIidmIdAndIpsoEquipment( + this.mappingBetweenIidmIdAndIpsoEquipment.getIidmId2IpsoEquipment() + )); + ArrayList roots = new ArrayList( + this.getIpsoNodes().stream() + .filter(IpsoNode::isSlackBus) + .collect(toList())); + + for(IpsoNode root:roots) { + graphSearchFrom(root, result, topologicalActions); + } + + return result; + } + + private void graphSearchFrom(IpsoNode root, IpsoNetworkState result, List topologicalActions) { + + Stack frontier = new Stack<>(); + frontier.push(root); + + try { + Method[][] branchGetters = { + {IpsoNetworkState.class.getMethod("getIpsoLines"), IpsoNetworkState.class.getMethod("addLine", IpsoLine.class)}, + {IpsoNetworkState.class.getMethod("getIpsoCouplings"), IpsoNetworkState.class.getMethod("addCoupling", IpsoCoupling.class)}, + {IpsoNetworkState.class.getMethod("getIpsoTwoWindingsTransformers"), IpsoNetworkState.class.getMethod("addTwoWindingsTransformer", IpsoTwoWindingsTransformer.class)}, + }; + Method[][] oneConnectionElementGetters = { + {IpsoNetworkState.class.getMethod("getIpsoGenerators"), IpsoNetworkState.class.getMethod("addGenerator", IpsoGenerator.class)}, + {IpsoNetworkState.class.getMethod("getIpsoLoads"), IpsoNetworkState.class.getMethod("addLoad", IpsoLoad.class)}, + {IpsoNetworkState.class.getMethod("getIpsoBanks"), IpsoNetworkState.class.getMethod("addBank", IpsoBank.class)}, + }; + + + while (!frontier.isEmpty()) { + + IpsoNode currentNode = frontier.pop(); + + if (!result.getIpsoNodes().contains(currentNode)) { + result.addNode(currentNode); + + for (Method[] element : branchGetters) { + List thisElementList = (List)element[0].invoke(this, null); + List linkedElements = thisElementList.stream() + .filter(isLinked(currentNode)) + .collect(Collectors.toList()); + + List resultElementList = (List)element[0].invoke(result, null); + + for (AbstractIpsoBranch branch : linkedElements) { + if(branch.couldBeConnected(topologicalActions) && !resultElementList.contains(branch)) { + element[1].invoke(result, branch); + if (branch.getIpsoNode1().equals(currentNode)) { + frontier.push(branch.getIpsoNode2()); + } else { + frontier.push(branch.getIpsoNode1()); + } + } + + } + + } + + for (Method[] element : oneConnectionElementGetters) { + + List thisElementList = (List)element[0].invoke(this, null); + thisElementList.stream() + .filter(isConnected(currentNode)) + .forEach(equipment -> { + try { + if(equipment.couldBeConnected(topologicalActions)) { + element[1].invoke(result, equipment); + } + } + catch (InvocationTargetException e) {e.printStackTrace();} + catch (IllegalAccessException e) {e.printStackTrace();} + } + ); + } + } + } + } catch(NoSuchMethodException | InvocationTargetException | IllegalAccessException e){ + e.printStackTrace(); + } + } + + + private Predicate isLinked(IpsoNode node) { + return branch -> branch.getIpsoNode1() == node || branch.getIpsoNode2() == node; + } + + private Predicate isConnected(IpsoNode node) { + return ipsoOneConnectionEquipment -> ipsoOneConnectionEquipment.getConnectedNode() == node; + } + +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoNode.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoNode.java new file mode 100644 index 00000000..7acad973 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoNode.java @@ -0,0 +1,129 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import com.google.common.collect.Lists; + +import java.util.List; +/** + * @author Yannick Pihan + */ +public class IpsoNode extends IpsoEquipment { + + public static final String BASE_VOLTAGE = "BASE_VOLTAGE"; + public static final String INITIAL_VOLTAGE = "INITIAL_VOLTAGE"; + public static final String INITIAL_ANGLE = "INITIAL_ANGLE"; + public static final String ACTIVE_POWER = "ACTIVE_POWER"; + public static final String REACTIVE_POWER = "REACTIVE_POWER"; + private static final String REGION = "REGION"; + private static final String MACRO_REGION = "MACRO_REGION"; + private static final String NODE_TYPE = "NODE_TYPE"; + private final String regionName; + private String macroRegionName; + private final float baseVoltage; + private float activePower; + private final float reactivePower; + private final float minVoltageLimit; + private final float maxVoltageLimit; + private final float angle; + private final float voltage; + private IpsoNodeType nodeType; + + /** + * constructor + */ + public IpsoNode(String id, String iidmId, String regionName, String macroRegionName, float baseVoltage, float voltage, float angle, IpsoNodeType nodeType, float activePower, float reactivePower, float minVoltageLimit, float maxVoltageLimit, int world) { + super(id, iidmId, world); + this.regionName = regionName; + this.macroRegionName = macroRegionName; + this.baseVoltage = baseVoltage; + this.nodeType = nodeType; + this.activePower = activePower; + this.reactivePower = reactivePower; + this.minVoltageLimit = minVoltageLimit; + this.maxVoltageLimit = maxVoltageLimit; + this.voltage = voltage; + this.angle = angle; + } + + @Override + public List getOrderedValues() { + + return Lists.newArrayList( + getId(), + regionName, + macroRegionName, // macro-regionName ? + replaceNanAndLogIt(BASE_VOLTAGE, baseVoltage, 0f), + replaceNanAndLogIt(INITIAL_VOLTAGE, voltage, 0f), + replaceNanAndLogIt(INITIAL_ANGLE, angle, 0f), + nodeType.getValue(), + replaceNanAndLogIt(ACTIVE_POWER, activePower, 0f), + replaceNanAndLogIt(REACTIVE_POWER, reactivePower, 0f), + getWorld()); + } + + @Override + public List getOrderedHeaders() { + return Lists.newArrayList( + NAME, + REGION, + MACRO_REGION, + BASE_VOLTAGE, + INITIAL_VOLTAGE, + INITIAL_ANGLE, + NODE_TYPE, + ACTIVE_POWER, + REACTIVE_POWER, + WORLD); + } + + + public boolean isSlackBus() { + return nodeType == IpsoNodeType.SB; + } + + public float getMinVoltageLimit() { + return minVoltageLimit; + } + + public float getMaxVoltageLimit() { + return maxVoltageLimit; + } + + public float getAngle() { + return angle; + } + + public float getVoltage() { + return voltage; + } + + public void setNodeType(IpsoNodeType nodeType) { + this.nodeType = nodeType; + } + + public void setMacroRegionName(String macroRegionName) { + this.macroRegionName = macroRegionName; + } + + public String getRegionName() { + return regionName; + } + + public float getBaseVoltage() { + return baseVoltage; + } + + public float getActivePower() { + return activePower; + } + + public float getReactivePower() { + return reactivePower; + } +} + + diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoNodeType.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoNodeType.java new file mode 100644 index 00000000..1bb6dddb --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoNodeType.java @@ -0,0 +1,25 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; +/** + * @author Yannick Pihan + */ +public enum IpsoNodeType { + + PV("PV"), + PQ("PQ"), + SB("SB"); + + private String value; + + IpsoNodeType(String value) { + this.value = value; + } + + public String getValue() { + return value; + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoOneConnectionEquipment.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoOneConnectionEquipment.java new file mode 100644 index 00000000..2b19e3eb --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoOneConnectionEquipment.java @@ -0,0 +1,38 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import java.util.List; + +import static com.google.common.base.Preconditions.checkArgument; +/** + * @author Yannick Pihan + */ +public abstract class IpsoOneConnectionEquipment extends IpsoEquipment { + + private final IpsoNode connectedNode; + protected boolean connected; + + public IpsoOneConnectionEquipment(String id, String iidmId, IpsoNode connectedNode, int world) { + super(id, iidmId, world); + checkArgument(connectedNode != null, "connectedNode must not be null"); + this.connectedNode = connectedNode; + } + + public IpsoNode getConnectedNode() { + return connectedNode; + } + + public boolean isConnected() { + return connected; + } + public boolean couldBeConnected(List topologicalActions) { + return this.isConnected() || topologicalActions.stream() + .filter(action -> action.getEquipmentId() == this.getId()) + .anyMatch(action -> action.getSwitchAction().isOppositeTo(this.isConnected())); + } +} + diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoOptimizationDataInput.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoOptimizationDataInput.java new file mode 100644 index 00000000..f37fa966 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoOptimizationDataInput.java @@ -0,0 +1,22 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; +/** + * @author Yannick Pihan + */ +public interface IpsoOptimizationDataInput { + /** + * + * @return the world of the optimization + * with (w=0 healthy state, w > 0 contengencies) + */ + int getWorld(); + + /** + * @return the name of the case; cannot be empty or null + */ + String getCaseName(); +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoProblemDefinition.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoProblemDefinition.java new file mode 100644 index 00000000..0dbc58bf --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoProblemDefinition.java @@ -0,0 +1,275 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import eu.itesla_project.cta.service.CorrectiveActions; +import eu.itesla_project.cta.service.IpsoInvalidComponent; + +import java.util.List; + +import static com.google.common.base.Preconditions.checkArgument; +import static java.util.stream.Collectors.toList; +/** + * @author Yannick Pihan + */ +public class IpsoProblemDefinition implements IpsoOptimizationDataInput { + + private final List invalidComponents; + private List variableGeneratorPs; + private List variableGeneratorQs; + private List variableGeneratorStatisms; + private List variableBankSteps; + private List variable2WTransformerTaps; + + private List constraintLineFlow; + private List constraint2WTransformerFlows; + private List constraintNodeAcVoltageBounds; + private List constraintNodeAcAngleBounds; + private List constraintGeneratorPBounds; + private List constraintGeneratorQBounds; + private List constraint2WTransformerTaps; + private List constraintBankStepBounds; + + private int world; + private final String caseName; + private CorrectiveActions correctiveActions; + + /** + * Constructor + */ + public IpsoProblemDefinition(String caseName, int world, + List variableGeneratorPs, + List variableGeneratorQs, + List variableGeneratorStatisms, + List variableBankSteps, + List variable2WTransformerTaps, + List constraintLineFlow, + List constraint2WTransformerFlows, + List constraintNodeAcVoltageBoundses, + List constraintNodeAcAngleBounds, + List constraintGeneratorPBounds, + List constraintGeneratorQBounds, + List constraint2WTransformerTaps, + List constraintBankStepBoundses, + List invalidComponents) { + checkArgument(variableGeneratorPs != null, "variableGeneratorPs must not be null"); + checkArgument(variableGeneratorQs != null, "variableGeneratorQs must not be null"); + checkArgument(variableGeneratorStatisms != null, "variableGeneratorStatisms must not be null"); + checkArgument(variableBankSteps != null, "variableBankSteps must not be null"); + checkArgument(variable2WTransformerTaps != null, "variable2WTransformerTaps must not be null"); + checkArgument(constraintLineFlow != null, "variable2WTransformerTaps must not be null"); + checkArgument(constraint2WTransformerFlows != null, "constraint2WTransformerFlows must not be null"); + checkArgument(constraintNodeAcVoltageBoundses != null, "constraintNodeAcVoltageBounds must not be null"); + checkArgument(constraintNodeAcAngleBounds != null, "constraintNodeAcAngleBounds must not be null"); + checkArgument(constraintGeneratorPBounds != null, "constraintGeneratorPBounds must not be null"); + checkArgument(constraintGeneratorQBounds != null, "constraintGeneratorPBounds must not be null"); + checkArgument(constraint2WTransformerTaps != null, "constraint2WTransformerTaps must not be null"); + checkArgument(constraintBankStepBoundses != null, "constraintBankStepBounds must not be null"); + checkArgument(invalidComponents != null, "invalidComponents must not be null"); + this.caseName = caseName; + this.world = world; + this.variableGeneratorPs = variableGeneratorPs; + this.variableGeneratorQs = variableGeneratorQs; + this.variableGeneratorStatisms = variableGeneratorStatisms; + this.variableBankSteps = variableBankSteps; + this.variable2WTransformerTaps = variable2WTransformerTaps; + this.constraintLineFlow = constraintLineFlow; + this.constraint2WTransformerFlows = constraint2WTransformerFlows; + this.constraintNodeAcVoltageBounds = constraintNodeAcVoltageBoundses; + this.constraintNodeAcAngleBounds = constraintNodeAcAngleBounds; + this.constraintGeneratorPBounds = constraintGeneratorPBounds; + this.constraintGeneratorQBounds = constraintGeneratorQBounds; + this.constraint2WTransformerTaps = constraint2WTransformerTaps; + this.constraintBankStepBounds = constraintBankStepBoundses; + this.invalidComponents = invalidComponents; + + } + + public List getVariableGeneratorPs() { + return variableGeneratorPs; + } + + public List getVariableGeneratorQs() { + return variableGeneratorQs; + } + + public List getVariableBankSteps() { + return variableBankSteps; + } + + public List getVariable2WTransformerTaps() { + return variable2WTransformerTaps; + } + + public List getConstraintGeneratorPBounds() { + return constraintGeneratorPBounds; + } + + public List getConstraintGeneratorQBounds() { + return constraintGeneratorQBounds; + } + + public List getConstraintLineFlows() { + return constraintLineFlow; + } + + public List getConstraint2WTransformerFlows() {return constraint2WTransformerFlows;} + + public List getConstraintNodeAcVoltageBounds() {return constraintNodeAcVoltageBounds;} + + public List getVariableGeneratorStatisms() {return variableGeneratorStatisms;} + + public List getConstraintNodeAcAngleBounds() {return constraintNodeAcAngleBounds;} + + public List getConstraint2WTransformerTaps() {return constraint2WTransformerTaps;} + + public List getConstraintBankStepBounds() { + return constraintBankStepBounds; + } + + public List getInvalidComponents() { + return invalidComponents; + } + + @Override + public int getWorld() { + return world; + } + + @Override + public String getCaseName() { + return caseName; + } + + public void mergeControlVariables(List controlVariables) { + + final List newVariableProductionP = controlVariables.stream() + .filter(controlVariable -> controlVariable instanceof IpsoControlVariableProductionP) + .map(IpsoControlVariableProductionP.class::cast) + .collect(toList()); + + final List newVariableProductionQ = controlVariables.stream() + .filter(controlVariable -> controlVariable instanceof IpsoControlVariableProductionQ) + .map(IpsoControlVariableProductionQ.class::cast) + .collect(toList()); + + final List newVariableGeneratorStatism = controlVariables.stream() + .filter(controlVariable -> controlVariable instanceof IpsoControlVariableGeneratorStatism) + .map(IpsoControlVariableGeneratorStatism.class::cast) + .collect(toList()); + + final List newVariableBankStep = controlVariables.stream() + .filter(controlVariable -> controlVariable instanceof IpsoControlVariableBankStep) + .map(IpsoControlVariableBankStep.class::cast) + .collect(toList()); + + final List newVariable2WTransformerTap = controlVariables.stream() + .filter(controlVariable -> controlVariable instanceof IpsoControlVariable2WTransformerTap) + .map(IpsoControlVariable2WTransformerTap.class::cast) + .collect(toList()); + + mergeControlVariables(variableGeneratorPs, newVariableProductionP); + mergeControlVariables(variableGeneratorQs, newVariableProductionQ); + mergeControlVariables(variableGeneratorStatisms, newVariableGeneratorStatism); + mergeControlVariables(variableBankSteps, newVariableBankStep); + mergeControlVariables(variable2WTransformerTaps, newVariable2WTransformerTap); + } + + + public void mergeConstraints(List constraints) { + + final List newConstraintGeneratorPBounds = findSubTypeOf(IpsoConstraintGeneratorPBounds.class, constraints); + + final List newConstraintGeneratorQBounds = findSubTypeOf(IpsoConstraintGeneratorQBounds.class, constraints); + + final List newConstraintBankStep = findSubTypeOf(IpsoConstraintBankStepBounds.class, constraints); + + final List newConstraint2WTransformerTap = findSubTypeOf(IpsoConstraint2WTransformerTapBounds.class, constraints); + + final List newConstraintLineFlow = constraints.stream() + .filter(constraint -> constraint instanceof AbstractIpsoConstraintLineFlow) + .map(AbstractIpsoConstraintLineFlow.class::cast) + .collect(toList()); + + final List newConstraintTransformerFlow = constraints.stream() + .filter(constraint -> constraint instanceof IpsoConstraint2WTransformerFlow) + .map(IpsoConstraint2WTransformerFlow.class::cast) + .collect(toList()); + + final List newConstraintVoltageBounds = constraints.stream() + .filter(constraint -> constraint instanceof IpsoConstraintNodeAcVoltageBounds) + .map(IpsoConstraintNodeAcVoltageBounds.class::cast) + .collect(toList()); + + final List newConstraintAngleBounds = constraints.stream() + .filter(constraint -> constraint instanceof IpsoConstraintNodeAcAngleBounds) + .map(IpsoConstraintNodeAcAngleBounds.class::cast) + .collect(toList()); + + mergeConstraints(this.constraintLineFlow, newConstraintLineFlow); + mergeConstraints(this.constraint2WTransformerFlows, newConstraintTransformerFlow); + mergeConstraints(this.constraintNodeAcVoltageBounds, newConstraintVoltageBounds); + mergeConstraints(this.constraintNodeAcAngleBounds, newConstraintAngleBounds); + mergeConstraints(this.constraintGeneratorPBounds, newConstraintGeneratorPBounds); + mergeConstraints(this.constraintGeneratorQBounds, newConstraintGeneratorQBounds); + mergeConstraints(this.constraint2WTransformerTaps, newConstraint2WTransformerTap); + mergeConstraints(this.constraintBankStepBounds, newConstraintBankStep); + } + + List findSubTypeOf(Class constraintClass, List constraints) { + return constraints.stream() + .filter(constraint -> constraint.getClass().equals(constraintClass)) + .map(constraintClass::cast) + .collect(toList()); + } + + private void mergeControlVariables(List existingVariables, + List newVariables) { + final List equipmentIds = newVariables.stream() + .map(variable -> variable.getRelatedIpsoEquipment().getId()) + .collect(toList()); + + List variables = existingVariables.stream() + .filter(existingVariable -> thatIsNotRelatedToAnEquipmentIn(equipmentIds, existingVariable)) + .collect(toList()); + + variables.addAll(newVariables); + existingVariables.clear(); + existingVariables.addAll(variables); + } + + private void mergeConstraints(List existingConstraints, + List newConstraints) { + // get equipment id's which are handled by the new constraints + final List equipmentIds = newConstraints.stream() + .map(variable -> variable.getRelatedIpsoEquipment().getId()) + .collect(toList()); + + // keep existing constraints related to an equipment which is not in the list of equipment ids + List constraints = existingConstraints.stream() + .filter(existingConstraint -> thatIsNotRelatedToAnEquipmentIn(equipmentIds, existingConstraint)) + .collect(toList()); + + constraints.addAll(newConstraints); + existingConstraints.clear(); + existingConstraints.addAll(constraints); + } + + /** + * @return true if the existing variable is related to an equipment which is not in the list of equipement ids + */ + private boolean thatIsNotRelatedToAnEquipmentIn(List equipmentIds, IpsoControlVariable existingVariable) { + return !equipmentIds.contains(existingVariable.getRelatedIpsoEquipment().getId()); + } + + /** + * @return true if the existing variable is related to an equipment which is not in the list of equipement ids + */ + private boolean thatIsNotRelatedToAnEquipmentIn(List equipmentIds, IpsoConstraint existingConstraint) { + return !equipmentIds.contains(existingConstraint.getRelatedIpsoEquipment().getId()); + } + +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoProblemDefinitionElement.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoProblemDefinitionElement.java new file mode 100644 index 00000000..9b842b1e --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoProblemDefinitionElement.java @@ -0,0 +1,17 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; +/** + * @author Yannick Pihan + */ +public interface IpsoProblemDefinitionElement { + + T getRelatedIpsoEquipment(); + + boolean isConstraint(); + + boolean isVariable(); +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoRegionType.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoRegionType.java new file mode 100644 index 00000000..0e21268e --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoRegionType.java @@ -0,0 +1,24 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; +/** + * @author Yannick Pihan + */ +public enum IpsoRegionType { + + INTERNAL("Internal"), + EXTERNAL("External"); + + private String value; + + IpsoRegionType(String value) { + this.value = value; + } + + public String getValue() { + return value; + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoTwoWindingsTransformer.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoTwoWindingsTransformer.java new file mode 100644 index 00000000..525719b0 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoTwoWindingsTransformer.java @@ -0,0 +1,233 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import com.google.common.collect.Lists; + +import java.util.List; +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkArgument; +/** + * @author Yannick Pihan + */ +public class IpsoTwoWindingsTransformer extends AbstractIpsoBranch{ + + private final TransformerRegulationParameters regulationParameters; + private final float maxCurrentPermanentLimit; + private final float currentFlow; + private final boolean connectedSide1; + private final boolean connectedSide2; + private final float cuLosses; + private final float feLosses; + private final float magnetizingCurrent; + private final float saturationExponent; + private final float rate; + private final int nominalTap; + private final int initialTap; + private final int lowStep; + private final int highStep; + private final int stepSize; + private final List indexes; + private final List voltages_side1; + private final List voltages_side2; + private final List phases; + private final List uccs; + private int stepLowStep = 0; + private int highstep = 0; + + /** + * constructor + */ + public IpsoTwoWindingsTransformer( + String id, + String iidmId, + IpsoNode ipsoNode1, + IpsoNode ipsoNode2, + boolean connectedSide1, + boolean connectedSide2, + float cuLosses, + float feLosses, + float magnetizingCurrent, + float saturationExponent, + float rate, + int nominalTap, + int initialTap, + int lowStep, + int highStep, + int stepSize, + List indexes, + List voltages_side1, + List voltages_side2, + List phases, + List uccs, + float maxCurrentPermanentLimit, + float currentFlow, + TransformerRegulationParameters regulationParameters, + int world) { + super(id, iidmId, world, ipsoNode1, ipsoNode2); + checkArgument(regulationParameters != null, "regulationParameters must not be null"); + checkArgument(ipsoNode1 != null, "ipsoNode1 must not be null"); + checkArgument(ipsoNode2 != null, "ipsoNode2 must not be null"); + this.connectedSide1 = connectedSide1; + this.connectedSide2 = connectedSide2; + this.cuLosses = cuLosses; + this.feLosses = feLosses; + this.magnetizingCurrent = magnetizingCurrent; + this.saturationExponent = saturationExponent; + this.rate = rate; + this.nominalTap = nominalTap; + this.initialTap = initialTap; + this.lowStep = lowStep; + this.highStep = highStep; + this.stepSize = stepSize; + this.indexes = indexes; + this.voltages_side1 = voltages_side1; + this.voltages_side2 = voltages_side2; + this.phases = phases; + this.uccs = uccs; + this.maxCurrentPermanentLimit = maxCurrentPermanentLimit; + this.currentFlow = currentFlow; + this.regulationParameters = regulationParameters; + } + + public int getInitialTap() { + return initialTap; + } + + public List getUccs() { return uccs; } + + public float getCuLosses() { return cuLosses; } + + public float getFeLosses() { return feLosses; } + + public float getMagnetizingCurrent() { return magnetizingCurrent; } + + public int getLowStep() { + return lowStep; + } + + public int getHighStep() { + return highStep; + } + + public TransformerRegulationParameters getRegulationParameters() { + return regulationParameters; + } + + public boolean isRegulating() { + return regulationParameters.getRegulationType().isRegulating(); + } + + public boolean isRatioTapChanger() { + return regulationParameters.getRegulationType().isVoltageRegulationType(); + } + + public boolean isPhaseTapChanger() { + return regulationParameters.getRegulationType().isFlowRegulationType(); + } + + public boolean hasMoreThanOneStep() { + return stepSize > 1; + } + + public boolean isConnectedOnBothSides() { + return connectedSide1 && connectedSide2; + } + + public float getMaxCurrentPermanentLimit() { + return maxCurrentPermanentLimit; + } + + public float getCurrentFlow() { + return currentFlow; + } + + public List getIndexes() { + return indexes; + } + + public List getVoltages_side1() { + return voltages_side1; + } + + public List getVoltages_side2() { + return voltages_side2; + } + + public List getPhases() { + return phases; + } + + @Override + public List getOrderedHeaders() { + return Lists.newArrayList( + NAME, + "NODE_NAME_1", + "NODE_NAME_2", + "CONNECTED_SIDE_1", + "CONNECTED_SIDE_2", + "CU_LOSSES", + "FE_LOSSES", + "MAGNETIZING_CURRENT", + "SATURATION_EXPONENT", + "NOMINAL_POWER", + "NOMINAL_TAP", + "INITIAL_TAP", + "CONTROLLED_SIDE", + "VOLTAGE_SETPOINT", + WORLD, + "STEP_NUMBER", + "STEP_INDEXES", + "STEP_VOLTAGES_SIDE1", + "STEP_VOLTAGES_SIDE2", + "STEP_DEPHASES", + "STEP_UCCS" + ); + } + + @Override + public List getOrderedValues() { + return Lists.newArrayList( + getId(), + ipsoNode1.getId(), + ipsoNode2.getId(), + getConnectionCodeFor(connectedSide1), + getConnectionCodeFor(connectedSide2), + cuLosses, + feLosses, + magnetizingCurrent, + saturationExponent, + rate, + nominalTap, + initialTap, + regulationParameters.getControlledSide(), + regulationParameters.getSetpoint(), + getWorld(), + stepSize > 0 ? stepSize : null, + stepSize > 0 ? indexes : null, + stepSize > 0 ? voltages_side1 : null, + stepSize > 0 ? voltages_side2 : null, + stepSize > 0 ? phases : null, + stepSize > 0 ? uccs : null + ); + + } + + public Optional getRegulatedNode() { + return Optional.ofNullable(this.getRegulationParameters()) + .map(TransformerRegulationParameters::getRegulatedNode); + } + + public boolean hasRegulatingNode() { + return getRegulatedNode().isPresent(); + } + + @Override + public boolean isConnected() { + return connectedSide1 && connectedSide2; + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoWritable.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoWritable.java new file mode 100644 index 00000000..f86cc722 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/IpsoWritable.java @@ -0,0 +1,17 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import java.util.List; +/** + * @author Yannick Pihan + */ +public interface IpsoWritable { + + List getOrderedValues(); + + List getOrderedHeaders(); +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/LinkOption.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/LinkOption.java new file mode 100644 index 00000000..2d3266e3 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/LinkOption.java @@ -0,0 +1,24 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; +/** + * @author Yannick Pihan + */ +public enum LinkOption { + FREE(""), + VOLTAGE("Voltage"), + POWER("Power"), + TAP("Tap"); + + private String option; + LinkOption(String option) { + this.option = option; + } + + public String getOption() { + return option; + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/SwitchAction.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/SwitchAction.java new file mode 100644 index 00000000..d87efc3d --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/SwitchAction.java @@ -0,0 +1,33 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; +/** + * @author Yannick Pihan + */ +public enum SwitchAction { + OPEN("opening"), + CLOSE("closing"); + + private final String stateDescription; + SwitchAction(String stateDescription) { + this.stateDescription = stateDescription; + } + + public boolean isOppositeTo(boolean connected) { + return (this == OPEN && connected) || + (this == CLOSE && !connected); + } + + + public String getStateDescription() { + return stateDescription; + } + + @Override + public String toString() { + return String.format("Switch %s", getStateDescription()); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/TopologicalAction.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/TopologicalAction.java new file mode 100644 index 00000000..5ae803fd --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/TopologicalAction.java @@ -0,0 +1,50 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import eu.itesla_project.cta.service.AmplConstants; +import eu.itesla_project.modules.contingencies.ActionParameters; + +/** + * @author Yannick Pihan + */ +public class TopologicalAction { + + final String equipmentId; + final SwitchAction switchAction; + final String elementaryActionId; + + public TopologicalAction(String equipmentId, SwitchAction switchAction, String elementaryActionId) { + this.equipmentId = equipmentId; + this.switchAction = switchAction; + this.elementaryActionId = elementaryActionId; + } + + public String getEquipmentId() { return equipmentId; } + + public SwitchAction getSwitchAction() { return switchAction; } + + public String getElementaryActionId() { + return elementaryActionId; + } + + @Override + public String toString() { + return String.format("Equipment %s - Action: %s", + equipmentId, + switchAction.toString()); + } + + public boolean isEquivalentTo(ActionParameters action) { + return action.getNames().stream() + .filter(name -> name.equals(AmplConstants.SWITCH_TAG)) + .map(action::getValue) + .filter(value -> value instanceof Boolean) + .anyMatch(value -> !switchAction.isOppositeTo((boolean)value)); + } + + +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/TransformerRegulationParameters.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/TransformerRegulationParameters.java new file mode 100644 index 00000000..b940785f --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/TransformerRegulationParameters.java @@ -0,0 +1,53 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; +/** + * @author Yannick Pihan + */ +public final class TransformerRegulationParameters { + private final IpsoNode regulatedNode; + private final int controlledSide; + private final float setpoint; + private final TransformerRegulationType regulationType; + private float currentStepPosition; + + public TransformerRegulationParameters(TransformerRegulationType regulationType, float setpoint, int controlledSide, int currentStepPosition, IpsoNode regulatedNode) { + this.regulationType = regulationType; + this.setpoint = setpoint; + this.controlledSide = controlledSide; + this.currentStepPosition = currentStepPosition; + this.regulatedNode = regulatedNode; + } + + public int getControlledSide() { + return controlledSide; + } + + /** + * @return the value of setpoint. With: + * - value in pu if regulationType is "voltage" + * - value in Ampere if regulationType is "ACTIVE_FLUX_x" + */ + public float getSetpoint() { + return setpoint; + } + + public boolean hasSetpointDefined() { + return !Float.isNaN(setpoint); + } + + public TransformerRegulationType getRegulationType() { + return regulationType; + } + + public IpsoNode getRegulatedNode() { + return regulatedNode; + } + + public float getCurrentStepPosition() { + return currentStepPosition; + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/TransformerRegulationType.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/TransformerRegulationType.java new file mode 100644 index 00000000..db025c06 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/TransformerRegulationType.java @@ -0,0 +1,38 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; +/** + * @author Yannick Pihan + */ +public enum TransformerRegulationType { + NO(0), + VOLTAGE_SIDE_1(1), + VOLTAGE_SIDE_2(2), + ACTIVE_FLUX_1(1), + ACTIVE_FLUX_2(2); + + + private final int sideValue; + + TransformerRegulationType(int sideValue) { + this.sideValue = sideValue; + } + + public boolean isVoltageRegulationType() { + return this == VOLTAGE_SIDE_1 || this == VOLTAGE_SIDE_2; + } + public boolean isFlowRegulationType() { + return this == ACTIVE_FLUX_1 || this == ACTIVE_FLUX_2; + } + + public boolean isRegulating() { + return this != NO; + } + + public int getSideValue() { + return sideValue; + } +} \ No newline at end of file diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/ValidationType.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/ValidationType.java new file mode 100644 index 00000000..a5288372 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/ValidationType.java @@ -0,0 +1,13 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; +/** + * @author Yannick Pihan + */ +public enum ValidationType { + DELTA_Q_LIMIT_LOWER_THAN_ONE_MVAR, + DELTA_P_LIMIT_LOWER_THAN_ONE_MVAR +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/model/VoltageUnit.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/VoltageUnit.java new file mode 100644 index 00000000..9c0196b3 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/model/VoltageUnit.java @@ -0,0 +1,25 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; +/** + * @author Yannick Pihan + */ +public enum VoltageUnit { + + Voltage("kV"), + PU("pu"); + + private String unit; + + VoltageUnit(String unit) { + this.unit = unit; + } + + public String getUnit() { + return unit; + } + +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/service/AbstractIpsoProblemDefinitionFactory.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/AbstractIpsoProblemDefinitionFactory.java new file mode 100644 index 00000000..a03930e6 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/AbstractIpsoProblemDefinitionFactory.java @@ -0,0 +1,40 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.service; + +import eu.itesla_project.cta.model.IpsoNetworkState; +import eu.itesla_project.cta.model.IpsoProblemDefinition; + +/** + * @author Yannick Pihan + */ +abstract class AbstractIpsoProblemDefinitionFactory { + + public abstract IpsoProblemDefinition createProblemDefinitionFor(IpsoNetworkState ipsoNetworkState, IpsoOptions options); + + /** + * @return A problem definition from constraints and control variables + */ + protected IpsoProblemDefinition createOperationalProblemDefinitionFor(IpsoNetworkState networkState, IpsoOptions options) { + + return IpsoProblemDefinitionBuilder + .create(networkState.getCaseName(), networkState.getWorld(), options) + .addVoltageBoundsConstraints(networkState) + .addAngleBoundsConstraints(networkState) + .addActivePowerBoundsConstraints(networkState) + .addReactivePowerBoundsConstraints(networkState) + .addLineFlowConstraints(networkState) + .addBankStepBoundsConstraints(networkState) + .addTwoWindingTransformerFowConstraints(networkState) + .addTwoWindingTransformerTapBoundsConstraints(networkState) + .addTwoWindingTransformerTapVariables(networkState) + .addActiveProductionVariables(networkState) + .addReactiveProductionVariables(networkState) + .addStatismGeneratorVariables(networkState) + .addBankStepVariables(networkState) + .createIpsoProblemDefinition(); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/service/AmplConstants.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/AmplConstants.java new file mode 100644 index 00000000..e42f182b --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/AmplConstants.java @@ -0,0 +1,30 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.service; +/** + * @author Yannick Pihan + */ +public interface AmplConstants { + + String APPLICATION_NAME = "ampl"; + String DAT_FILE_NAME = "ampl.dat"; + String RUN_FILE_NAME = "amplInput.run"; + String TAB_FILE_NAME = "SolverOptions.tab"; + String TEMPLATE_FILE = "template.dat"; + + String MODELS_DIR = "amplModels"; + + // AmplResults + String RESULTS_TAG = "results"; + String ID_TAG = "id"; + String PARAMETERS_TAG = "parameters"; + String AMPL_EQUIPMENT_TAG = "equipments"; + String XML_FILE_NAME = "result.xml"; + String SWITCH_TAG = "connection_status"; + String AMPL_STATUS_TAG = "status"; + String AMPL_UNPLUGGED_EQUIPMENT_PREFIX = "disconnected_equipments_"; + String AMPL_UNPLUGGED_EQUIPMENT_SUFFIX = ".dat"; +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/service/AmplExecutionError.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/AmplExecutionError.java new file mode 100644 index 00000000..de3d361a --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/AmplExecutionError.java @@ -0,0 +1,14 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.service; +/** + * @author Yannick Pihan + */ +class AmplExecutionError extends Exception{ + public AmplExecutionError(String s) { + super(s); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/service/AmplExecutionResults.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/AmplExecutionResults.java new file mode 100644 index 00000000..242e2d36 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/AmplExecutionResults.java @@ -0,0 +1,37 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.service; + +import eu.itesla_project.modules.contingencies.ActionParameters; + +import java.util.HashMap; +import java.util.Map; +/** + * @author Yannick Pihan + */ +class AmplExecutionResults { + + private final Map actionElements; + private final AmplStatus status; + + AmplExecutionResults(Map actionElements, AmplStatus status) { + this.actionElements = actionElements; + this.status = status; + } + + public AmplExecutionResults(AmplStatus status) { + actionElements = new HashMap<>(); + this.status = status; + } + + public Map getActionElements() { + return actionElements; + } + + public AmplStatus getStatus() { + return status; + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/service/AmplOptimizationResultService.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/AmplOptimizationResultService.java new file mode 100644 index 00000000..cff27b82 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/AmplOptimizationResultService.java @@ -0,0 +1,201 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.service; + +import eu.itesla_project.computation.ExecutionError; +import eu.itesla_project.computation.ExecutionReport; +import eu.itesla_project.modules.contingencies.ActionParameterBooleanValue; +import eu.itesla_project.modules.contingencies.ActionParameters; +import org.w3c.dom.Document; +import org.w3c.dom.NodeList; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static com.google.common.base.Preconditions.checkArgument; +import static java.lang.System.getProperty; +import static java.util.stream.Collectors.joining; +import static java.util.stream.Collectors.toList; +/** + * @author Yannick Pihan + */ +class AmplOptimizationResultService { + + protected static final String SOLVED = "solved"; + protected static final String INFEASIBLE = "infeasible"; + + public static AmplExecutionResults createAmplResultFrom(Path resultPath, ExecutionReport report, IpsoOutputListing outputListing) { + + Map results = new HashMap<>(); + AmplStatus status = AmplStatus.SUCCEEDED; + + try { + if (!report.getErrors().isEmpty()) { + status = AmplStatus.EXECUTION_ERROR; + throw new AmplExecutionError("Error during Ampl process: Result file not generated." + findErrorMessageIn(report)); + + } else if (!Files.exists(resultPath)) { + status = AmplStatus.EXECUTION_ERROR; + throw new AmplExecutionError("Error during Ampl process: Result file not generated."); + + } else { + // XML parsing + DocumentBuilderFactory parserFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder parser = parserFactory.newDocumentBuilder(); + Document resultDocument = parser.parse(resultPath.toFile()); + resultDocument.normalizeDocument(); + + NodeList childNodes = resultDocument.getElementsByTagName(AmplConstants.RESULTS_TAG).item(0).getChildNodes(); + + for (int i = 0; i < childNodes.getLength(); i++) { + if (isEquipmentsTag(childNodes, i)) { + results = readResults(childNodes.item(i).getChildNodes()); + } + if (isStatusTag(childNodes, i)) { + status = readStatus(childNodes.item(i).getChildNodes(), i); + } + } + writeResultsTo(outputListing, status, results); + } + } catch (Exception e) { + e.printStackTrace(); + outputListing.addAmplError(e); + status = AmplStatus.EXECUTION_ERROR; + } + finally { + return new AmplExecutionResults(results, status); + } + } + + private static void writeResultsTo(IpsoOutputListing outputListing, AmplStatus status, Map results) { + List actions = getActionDescriptionsFrom(results); + outputListing.addAmplResult(status, actions); + } + + private static List getActionDescriptionsFrom(Map results) { + return results.entrySet().stream() + .map(entry -> formatResult(entry.getKey(), entry.getValue())) + .collect(toList()); + } + + private static AmplStatus readStatus(NodeList childNodes, int i) { + String status = childNodes.item(i).getTextContent(); + if(status.contains(SOLVED)) { + return AmplStatus.SUCCEEDED; + } + else if (status.contains(INFEASIBLE)) { + return AmplStatus.UNFEASIBLE; + } else { + return AmplStatus.ERROR; + } + } + + private static boolean isStatusTag(NodeList childNodes, int i) { + return childNodes.item(i).getNodeName().equals(AmplConstants.AMPL_STATUS_TAG); + } + + private static boolean isEquipmentsTag(NodeList childNodes, int i) { + return childNodes.item(i).getNodeName().equals(AmplConstants.AMPL_EQUIPMENT_TAG); + } + + /** + * Generate a hash map containing the equipment id as key and + * relatd ActionParameters as value + * + * @param equipments : xml data related to the equipments + * @return + */ + private static Map readResults(NodeList equipments) { + Map results = new HashMap<>(); + + for (int i = 0; i < equipments.getLength(); i++) { + addResult(equipments.item(i).getChildNodes(), results); + } + + return results; + } + + /** + * Add an entry into the results Hash Map + * @param equipmentData : data corresponding to the corrective actions of a given equipment + * @param results : hashmap containing all the results already computed + */ + private static void addResult(NodeList equipmentData, Map results) { + String name = ""; + ActionParameters parameters = null; + for(int i = 0; i < equipmentData.getLength(); i++) { + if(equipmentData.item(i).getNodeName().equals(AmplConstants.ID_TAG)) { + name = equipmentData.item(i).getTextContent(); + } + else if (equipmentData.item(i).getNodeName().equals(AmplConstants.PARAMETERS_TAG)) { + parameters = findParametersFrom(equipmentData.item(i).getChildNodes()); + } + } + + if(!name.isEmpty() && parameters != null) { + results.put(name, parameters); + } + } + + /** + * Create an ActionParameters instance corresponding to the parameters + * contained into the xml + * + * @param xmlNodes : xml data of the parameters + * @return : the parameters corresponding to the xml + */ + private static ActionParameters findParametersFrom(NodeList xmlNodes) { + + ActionParameters actionParameters = new ActionParameters(); + + for(int i = 0; i < xmlNodes.getLength(); i++) { + String parameterName = xmlNodes.item(i).getNodeName(); + String parameterValue = xmlNodes.item(i).getTextContent(); + if(!parameterName.isEmpty() && !parameterValue.isEmpty()) { + if(parameterName.equals(AmplConstants.SWITCH_TAG)) + actionParameters.addParameter(parameterName, new ActionParameterBooleanValue(parameterValue.equals("1"))); + } + } + return actionParameters; + } + + private static String findErrorMessageIn(ExecutionReport report) { + return report.getErrors().stream() + .map(ExecutionError::toString) + .collect( + joining(getProperty("line.separator")) + ); + } + + private static String formatResult(String key, ActionParameters value) { + checkArgument(value != null, "value must not be null"); + StringBuilder pararameters = new StringBuilder(); + for(String parameterName : value.getNames()) { + pararameters.append(parameterName + " : "); + Object parameterValue = value.getValue(parameterName); + if(parameterName.equals(AmplConstants.SWITCH_TAG) && parameterValue instanceof Boolean) { + pararameters.append(((boolean) parameterValue) ? "close" : "open"); + } + else { + pararameters.append(parameterValue.toString()); + } + pararameters.append(", "); + } + return new StringBuilder() + .append(" ") + .append(key) + .append(" ") + .append(pararameters.toString()) + .append(" ") + .toString(); + } + +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/service/AmplStatus.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/AmplStatus.java new file mode 100644 index 00000000..35fd6091 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/AmplStatus.java @@ -0,0 +1,25 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.service; +/** + * @author Yannick Pihan + */ +enum AmplStatus { + SUCCEEDED("SUCCEEDED"), + UNFEASIBLE("UNFEASIBLE"), + ERROR("ERROR"), + EXECUTION_ERROR("EXECUTION_ERROR"); + + private final String textDescription; + + AmplStatus(String textDescription) { + this.textDescription = textDescription; + } + + public String getTextDescription() { + return textDescription; + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/service/CorrectiveActions.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/CorrectiveActions.java new file mode 100644 index 00000000..ffbc70dc --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/CorrectiveActions.java @@ -0,0 +1,66 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.service; + +import com.google.common.collect.Lists; +import eu.itesla_project.cta.model.IpsoConstraint; +import eu.itesla_project.cta.model.IpsoControlVariable; +import eu.itesla_project.cta.model.TopologicalAction; + +import java.util.List; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkState; +/** + * @author Yannick Pihan + */ +public class CorrectiveActions { + + private final List controlVariables; + private final List constraints; + private final List topologicalActions; + private String actionPlanId = ""; + + public CorrectiveActions(List controlVariables, List constraints, List topologicalActions) { + checkArgument(controlVariables != null, "controlVariables must not be null"); + checkArgument(constraints != null, "constraints must not be null"); + checkArgument(topologicalActions != null, "topologicalActions must not be null"); + this.controlVariables = controlVariables; + this.constraints = constraints; + this.topologicalActions = topologicalActions; + } + + public CorrectiveActions() { + controlVariables = Lists.newArrayList(); + constraints = Lists.newArrayList(); + this.topologicalActions = Lists.newArrayList(); + } + + public List getControlVariables() { + return controlVariables; + } + + public List getConstraints() { + return constraints; + } + + public List getTopologicalActions() { + return topologicalActions; + } + + public boolean addTopologicalAction(TopologicalAction topologicalAction) { + return topologicalActions.add(topologicalAction); + } + + public boolean hasTopologicalActions() { + checkState(topologicalActions != null, "topologicalActions must not be null"); + return topologicalActions.size() > 0; + } + + public String getActionPlanId() { + return actionPlanId; + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/service/CorrectiveControlIpsoOptimizer.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/CorrectiveControlIpsoOptimizer.java new file mode 100644 index 00000000..0add8f21 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/CorrectiveControlIpsoOptimizer.java @@ -0,0 +1,191 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.service; + +import eu.itesla_project.computation.CommandExecutor; +import eu.itesla_project.computation.ComputationManager; +import eu.itesla_project.cta.model.AmplModel; +import eu.itesla_project.cta.model.IpsoConstraint; +import eu.itesla_project.cta.model.IpsoNetworkState; +import eu.itesla_project.cta.model.IpsoProblemDefinition; +import eu.itesla_project.modules.contingencies.ContingenciesAndActionsDatabaseClient; +import eu.itesla_project.modules.optimizer.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.List; + +import static com.google.common.base.Preconditions.checkArgument; +import static eu.itesla_project.cta.service.IpsoOptimizerConfiguration.createOptimizationConfiguration; +import static java.util.stream.Collectors.toList; +/** + * @author Yannick Pihan + */ +public class CorrectiveControlIpsoOptimizer implements CorrectiveControlOptimizer { + + Logger logger = LoggerFactory.getLogger(CorrectiveControlIpsoOptimizer.class); + + private final ContingenciesAndActionsDatabaseClient client; + private final ComputationManager computationManager; + private IpsoComputationService computationService; + private IpsoOptions options; + private IpsoOptimizerConfiguration configuration; + + public CorrectiveControlIpsoOptimizer(ContingenciesAndActionsDatabaseClient client, ComputationManager computationManager) { + this.client = client; + this.computationManager = computationManager; + } + + public void init(CorrectiveControlOptimizerParameters parameters, IpsoOptimizerConfiguration configuration) { + + this.computationService = new IpsoComputationService(); + this.options = IpsoOptions.createOptionsForScOpf(); + this.configuration = configuration; + } + + @Override + public void init(CorrectiveControlOptimizerParameters parameters) { + this.init(parameters, createOptimizationConfiguration()); + } + + @Override + public CorrectiveControlOptimizerResult run(PostContingencyState postContingencyState) throws Exception { + checkArgument(postContingencyState != null, "postContingencyState must not be null"); + checkArgument(postContingencyState.getStateId() != null, "postContingencyState.getStateId() must not be null"); + checkArgument(postContingencyState.getContingency() != null, "postContingencyState.getContingency() must not be null"); + checkArgument(postContingencyState.getNetwork() != null, "postContingencyState.getNetwork() must not be null"); + + logger.info("Running IPSO on contingency {} and state {} of {} network", + postContingencyState.getContingency().getId(), + postContingencyState.getStateId(), + postContingencyState.getNetwork().getId()); + + // Conversion from iidm network into ipso network + IpsoNetworkState ipsoNetworkState = computationService + .convertIidmNetworkToIpsoNetworkState( + postContingencyState.getNetwork().getName(), + postContingencyState.getNetwork()); + + // create the onput listing + IpsoOutputListing outputListing = createOutputListing(ipsoNetworkState); + outputListing.addContingency(postContingencyState.getContingency()); + + IpsoProblemDefinition problemDefinition = computationService.createScopfIpsoProblemDefinition( + ipsoNetworkState, + options, + outputListing); + + // Looking for violated constraints + List violatedConstraints = computationService.findViolatedConstraintsFor(problemDefinition, outputListing); + // Remove voltage constraints + violatedConstraints = violatedConstraints.stream() + .filter(IpsoConstraint::isCurrentViolation) + .collect(toList()); + + OptimizerExecutionService executionService = new OptimizerExecutionService(); + + String contingencyId = postContingencyState.getContingency().getId(); + if (!violatedConstraints.isEmpty() && options.isActionCorrectivesTakenIntoAccount()) { + logger.info("{} constraints violated for contingency {} and state {} of {} network", + violatedConstraints.size(), + contingencyId, + postContingencyState.getStateId(), + postContingencyState.getNetwork().getId()); + + // Generate corrective actions + CorrectiveActions correctiveActions = computationService.createCorrectiveActions( + postContingencyState, + violatedConstraints, + client, + ipsoNetworkState.getMappingBetweenIidmIdAndIpsoEquipment(), + outputListing); + + // Update problem definition + problemDefinition.mergeControlVariables(correctiveActions.getControlVariables()); + problemDefinition.mergeConstraints(correctiveActions.getConstraints()); + + AmplExecutionResults amplResult = null; + + try { + + if (correctiveActions.hasTopologicalActions()) { + logger.info("Running AMPL on contingency {} and state {} of {} network", + contingencyId, + postContingencyState.getStateId(), + postContingencyState.getNetwork().getId()); + AmplModel amplModel = computationService.computeNewTopologyFor( + ipsoNetworkState, + problemDefinition, + correctiveActions.getTopologicalActions(), + Files.createTempFile(computationManager.getLocalDir(), + AmplConstants.AMPL_UNPLUGGED_EQUIPMENT_PREFIX, + AmplConstants.AMPL_UNPLUGGED_EQUIPMENT_SUFFIX)); + + // run Ampl + amplResult = executionService.runAmpl(postContingencyState, amplModel, configuration, computationManager, outputListing); + if ( amplResult.getStatus().equals(AmplStatus.EXECUTION_ERROR) ) { + logger.error("Error running AMPL on contingency {} and state {} of {} network", + contingencyId, + postContingencyState.getStateId(), + postContingencyState.getNetwork().getId()); + } + } else + logger.warn("No topological actions for contingency {} and state {} of {} network", + contingencyId, + postContingencyState.getStateId(), + postContingencyState.getNetwork().getId()); + + } + catch(IllegalArgumentException e) { + outputListing.addAmplError(e); + logger.error("Error running AMPL on contingency {} and state {} of {} network: {}", + contingencyId, + postContingencyState.getStateId(), + postContingencyState.getNetwork().getId(), + e.getMessage()); + e.printStackTrace(); + } + + CorrectiveControlOptimizerResult correctiveControlOptimizerResult = executionService.createCorrectiveControlOptimizerResult(amplResult, contingencyId, ipsoNetworkState.getMappingBetweenIidmIdAndIpsoEquipment(), correctiveActions); + outputListing.addResultCode(correctiveControlOptimizerResult.getFinalStatus()); + try (CommandExecutor executor = computationManager.newCommandExecutor(new HashMap<>(), "itesla_CCO_", true)) { + final Path workingDir = executor.getWorkingDir(); + outputListing.addLoadFlowResultsFor(postContingencyState.getNetwork()); + outputListing.write(workingDir, postContingencyState.getContingency().getId() + '_' + IpsoConstants.OUTPUT_LISTING_FILENAME); + } + return correctiveControlOptimizerResult; + } + else { + logger.warn("No violated constraints for contingency {} and state {} of {} network", + contingencyId, + postContingencyState.getStateId(), + postContingencyState.getNetwork().getId()); + + final CorrectiveControlOptimizerResult result = new CorrectiveControlOptimizerResult(contingencyId, false); + result.setFinalStatus(CCOFinalStatus.NO_CONSTRAINT_VIOLATED); + outputListing.addResultCode(CCOFinalStatus.NO_CONSTRAINT_VIOLATED); + try (CommandExecutor executor = computationManager.newCommandExecutor(new HashMap<>(), "itesla_CCO_", true)) { + final Path workingDir = executor.getWorkingDir(); + outputListing.addLoadFlowResultsFor(postContingencyState.getNetwork()); + outputListing.write(workingDir, postContingencyState.getContingency().getId() + '_' + IpsoConstants.OUTPUT_LISTING_FILENAME); + } + return result; + } + } + + @Override + public void close() throws Exception { + } + + private IpsoOutputListing createOutputListing(IpsoNetworkState ipsoNetworkState) { + return new IpsoComputationService() + .createNewOutputListing(ipsoNetworkState.getMappingBetweenIidmIdAndIpsoEquipment()); + } + +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoComputationService.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoComputationService.java new file mode 100644 index 00000000..4b3835d5 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoComputationService.java @@ -0,0 +1,103 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.service; + +import eu.itesla_project.computation.ExecutionReport; +import eu.itesla_project.cta.converter.AmplModelFactory; +import eu.itesla_project.cta.converter.ConversionContext; +import eu.itesla_project.cta.converter.MappingBetweenIidmIdAndIpsoEquipment; +import eu.itesla_project.cta.converter.NetworkModelConverter; +import eu.itesla_project.cta.model.*; +import eu.itesla_project.iidm.network.Network; +import eu.itesla_project.modules.contingencies.ContingenciesAndActionsDatabaseClient; +import eu.itesla_project.modules.optimizer.PostContingencyState; +import org.slf4j.Logger; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.List; + +import static com.google.common.base.Preconditions.checkArgument; +import static eu.itesla_project.cta.service.IpsoOutputListingMessageType.INVALID_COMPONENTS; +import static eu.itesla_project.cta.service.IpsoOutputListingMessageType.VIOLATED_CONSTRAINTS; +import static org.slf4j.LoggerFactory.getLogger; +/** + * @author Yannick Pihan + */ +class IpsoComputationService { + + private static final Logger LOG = getLogger(IpsoComputationService.class); + + public IpsoComputationService() {} + + /** + * create an Scopf Ipso problem definition from post contingency iidm network and Ipso network model + * @param ipsoNetworkState + * @param option + * @return + * @throws IOException + */ + public IpsoProblemDefinition createScopfIpsoProblemDefinition(IpsoNetworkState ipsoNetworkState, IpsoOptions option, IpsoOutputListing outputListing) throws IOException { + IpsoProblemDefinition problemDefinition = createIpsoProblemDefinitionFrom(ipsoNetworkState, option); + outputListing.addToListing(INVALID_COMPONENTS, problemDefinition.getInvalidComponents()); + return problemDefinition; + } + + /** + * @return Ipso network state resulting the conversion of a iidm network + */ + public IpsoNetworkState convertIidmNetworkToIpsoNetworkState(String optimizationId, Network network) { + ConversionContext conversionContext = new ConversionContext(optimizationId); + NetworkModelConverter networkModelConverter = new NetworkModelConverter(); + return networkModelConverter.convert(network, conversionContext); + } + + /** + * + * @return Ipso problem definition for a given Ipso network state + */ + public IpsoProblemDefinition createIpsoProblemDefinitionFrom(IpsoNetworkState ipsoNetworkState, IpsoOptions option) { + IpsoProblemDefinitionFactory problemDefinitionFactory = new IpsoProblemDefinitionFactory(); + return problemDefinitionFactory.createProblemDefinitionFor(ipsoNetworkState, option); + } + + + public IpsoOutputListing createNewOutputListing(MappingBetweenIidmIdAndIpsoEquipment mappingBetweenIidmIdAndIpsoEquipment) { + return new IpsoOutputListing(mappingBetweenIidmIdAndIpsoEquipment); + + } + + public CorrectiveActions createCorrectiveActions(PostContingencyState postContingencyState, List violatedConstraints, ContingenciesAndActionsDatabaseClient client, MappingBetweenIidmIdAndIpsoEquipment mappingBetweenIidmIdAndIpsoEquipment, IpsoOutputListing outputListing) { + IpsoCorrectiveActionService correctiveActionManager = new IpsoCorrectiveActionService(postContingencyState, client, mappingBetweenIidmIdAndIpsoEquipment); + return correctiveActionManager.createCorrectiveActionsToResolve(violatedConstraints, outputListing); + } + + public IpsoOptimizationResults createOptimizationResultsFrom(ExecutionReport report, Path path) { + return new IpsoOptimizationResultsService().createIpsoOptimizationResults(report, path); + } + + public AmplModel computeNewTopologyFor(IpsoNetworkState networkState, IpsoProblemDefinition problemDefinition, List topologicalActions, Path unpluggedLogFile) { + checkArgument(networkState != null, "networkState must not be null"); + checkArgument(problemDefinition != null, "problemDefinition must not be null"); + + return new AmplModelFactory().createAmplModelFrom(networkState, problemDefinition, topologicalActions, unpluggedLogFile); + } + + public List findViolatedConstraintsFor(IpsoProblemDefinition problemDefinition, IpsoOutputListing outputListing) { + checkArgument(problemDefinition != null, "problemDefinition must not be null"); + checkArgument(outputListing != null, "outputListing must not be null"); + + List violatedConstraints = new IpsoProblemDefinitionService().findViolatedConstraintsIn(problemDefinition); + addViolatedConstraintsTo(outputListing, violatedConstraints); + + return violatedConstraints; + } + + private void addViolatedConstraintsTo(IpsoOutputListing outputListing, List violatedConstraints) { + outputListing.addToListing(VIOLATED_CONSTRAINTS, violatedConstraints); + outputListing.addSeparator(); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoConstants.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoConstants.java new file mode 100644 index 00000000..8c6f396e --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoConstants.java @@ -0,0 +1,14 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.service; +/** + * @author Yannick Pihan + */ +interface IpsoConstants { + String APPLICATION_NAME = "test_api.e"; + String SOLUTION_OUT = "OutputListingSolution.out"; + String OUTPUT_LISTING_FILENAME = "OutputListingProblemDefinition.out"; +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoConstraintFactory.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoConstraintFactory.java new file mode 100644 index 00000000..c04bd6cb --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoConstraintFactory.java @@ -0,0 +1,262 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.service; + +import com.google.common.collect.Lists; +import eu.itesla_project.cta.model.*; +import org.slf4j.Logger; + +import java.util.List; +import java.util.stream.Collectors; + +import static com.google.common.base.Preconditions.checkArgument; +import static java.util.stream.Collectors.toList; +import static org.slf4j.LoggerFactory.getLogger; +/** + * @author Yannick Pihan + */ +class IpsoConstraintFactory { + + private static final Logger LOG = getLogger(IpsoConstraintFactory.class); + + private final IpsoProblemComponentFactory ipsoProblemComponentFactory; + + public IpsoConstraintFactory(IpsoProblemComponentFactory ipsoProblemComponentFactory) { + checkArgument(ipsoProblemComponentFactory != null, "ipsoProblemComponentFactory must not be null"); + this.ipsoProblemComponentFactory = ipsoProblemComponentFactory; + } + + /** + * @return create voltage AC node constraints in according to the options + */ + public List createVoltageBoundsConstraints(IpsoNetworkState networkState, IpsoOptions option) { + checkArgument(networkState != null, "networkState must not be null"); + List constraints = Lists.newArrayList(); + + // get the list of node id that are not directly concerned by a constraint + final List nodesRegulatedByGenerators = networkState.getConnectedAndRegulatingGenerators() + .map(IpsoGenerator::getConnectedNode) + .collect(Collectors.toList()); + + final List nodesRegulatedByTransformers = networkState.getConnectedAndRegulatingRatioTapChangerTransformer() + .map(transformer -> transformer.getRegulationParameters().getRegulatedNode()) + .collect(Collectors.toList()); + + if (option.isGeneratorSetpointTakenIntoAccount()) { + + List constraintsFromGenerators = createVoltageConstraintsForNodesControlledByGenerators(networkState); + // add voltage setpoint constraints for nodes controlled by generators + constraints.addAll(constraintsFromGenerators); + + List constraintsFromTransformers = createVoltageConstraintsForNodesControlledByTransformer(networkState); + // add voltage setpoint constraints for nodes controlled by transformer + constraints.addAll(constraintsFromTransformers); + } + + if (option.isVoltageLimitsTakenIntoAccount()) { + // create voltage bound constraints for no regulated nodes + List constraintsFromNodes = createVoltageConstraintsForNotRegulatedNodes( + networkState, nodesRegulatedByGenerators, nodesRegulatedByTransformers); + // add voltage bound constraint + constraints.addAll(constraintsFromNodes); + } + + return constraints; + } + + private List createVoltageConstraintsForNotRegulatedNodes(IpsoNetworkState networkState, List nodesRegulatedByGenerators, List nodesRegulatedByTransformers) { + return networkState.getIpsoNodes() + .stream() + .filter(node -> !nodesRegulatedByGenerators.contains(node)) + .filter(node -> !nodesRegulatedByTransformers.contains(node)) + .map(node -> ipsoProblemComponentFactory.createConstraintNodeAcVoltageBounds( + node, + VoltageUnit.PU, + node.getMinVoltageLimit(), + node.getMaxVoltageLimit(), + networkState.getWorld())) + .collect(toList()); + } + + private List createVoltageConstraintsForNodesControlledByTransformer(IpsoNetworkState networkState) { + return networkState.getConnectedAndRegulatingRatioTapChangerTransformer() + .map(transformer -> ipsoProblemComponentFactory.createConstraintNodeAcVoltageBounds( + transformer.getRegulationParameters().getRegulatedNode(), + VoltageUnit.PU, + transformer.getRegulationParameters().getSetpoint(), + transformer.getRegulationParameters().getSetpoint(), + networkState.getWorld())) + .collect(toList()); + } + + private List createVoltageConstraintsForNodesControlledByGenerators(IpsoNetworkState networkState) { + return networkState.getConnectedAndRegulatingGenerators() + .map(generator -> ipsoProblemComponentFactory.createConstraintNodeAcVoltageBounds( + generator.getConnectedNode(), + VoltageUnit.PU, + generator.getVoltageSetpointPu(), + generator.getVoltageSetpointPu(), + networkState.getWorld())) + .collect(toList()); + } + + /** + * @return angle constraints on AC node + */ + public List createNodeAcAngleBoundConstraints(IpsoNetworkState networkState) { + IpsoNode sb = findSlackBusIn(networkState); + IpsoConstraintNodeAcAngleBounds constraint = ipsoProblemComponentFactory.createConstraintNodeAcAngleBounds(sb, sb.getAngle(), sb.getAngle(), networkState.getWorld()); + return Lists.newArrayList(constraint); + } + + /** + * @return Active Power constraints on generators + */ + public List createActivePowerBoundsConstraints(IpsoNetworkState networkState) { + + IpsoNode slackbusNode = findSlackBusIn(networkState); + + IpsoGenerator generatorConnectedToSlackbus = networkState.getIpsoGenerators() + .stream() + .filter(generator -> areConnected(generator, slackbusNode)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("There is no generatorConnectedToSlackbus linked to the Node [slackbus]")); + + IpsoConstraintGeneratorPBounds constraintProductionPBounds = ipsoProblemComponentFactory.createConstraintProductionPBounds( + generatorConnectedToSlackbus, + generatorConnectedToSlackbus.getMinActivePower(), + generatorConnectedToSlackbus.getMaxActivePower(), + networkState.getWorld()); + + return Lists.newArrayList(constraintProductionPBounds); + } + + /** + * @return Reactive Power constraints on generators + */ + public List createReactivePowerBoundsConstraints(IpsoNetworkState networkState) { + checkArgument(networkState != null, "networkState must not be null"); + return networkState.getConnectedAndRegulatingGenerators() + .filter(IpsoGenerator::isDeltaQLimitUpperThanOneMvar) + .map(generator -> ipsoProblemComponentFactory.createConstraintProductionQBounds( + generator, + generator.getMinReactivePower(), + generator.getMaxReactivePower(), + networkState.getWorld())) + .collect(toList()); + } + + /** + * @return Flow constraints on lines + */ + public List createLineFlowConstraints(IpsoNetworkState networkState, IpsoOptions option) { + checkArgument(networkState != null, "networkState must not be null"); + + if (option.isVoltageLimitsTakenIntoAccount()) { + return networkState.getIpsoLines().stream() + .filter(IpsoLine::hasMaxCurrentPermanentLimitDefined) + .flatMap(line -> createConstraintLineFlowOnBothSides(line, networkState.getWorld()).stream()) + .collect(toList()); + }else { + return Lists.newArrayList(); + } + } + + private List createConstraintLineFlowOnBothSides(IpsoLine line, int world) { + AbstractIpsoConstraintLineFlow constraintSide1 = ipsoProblemComponentFactory.createConstraintLineFlow(line, FlowType.SIDE1, world); + AbstractIpsoConstraintLineFlow constraintSide2 = ipsoProblemComponentFactory.createConstraintLineFlow(line, FlowType.SIDE2, world); + //return Lists.newArrayList(constraintSide1, constraintSide2); + // TODO Don't forget to restore 'constraintSide2' when Ipso API will support it + return Lists.newArrayList(constraintSide1); + } + + public List createTwoWindingTransformerTapBoundsConstraints(IpsoNetworkState networkState, IpsoOptions option) { + checkArgument(networkState != null, "networkState must not be null"); + + if (option.isTransformerRegulateTakenIntoAccount()) { + return networkState.getIpsoTwoWindingsTransformers().stream() + .filter(IpsoTwoWindingsTransformer::isConnectedOnBothSides) + .filter(IpsoTwoWindingsTransformer::isRegulating) + .filter(IpsoTwoWindingsTransformer::hasMoreThanOneStep) + .map(ipsoTransformer -> ipsoProblemComponentFactory.createConstraint2WTfoTap( + ipsoTransformer, + ipsoTransformer.getLowStep(), + ipsoTransformer.getHighStep(), + networkState.getWorld())) + .collect(toList()); + } + else { + return Lists.newArrayList(); + } + } + + public List createTwoWindingTransformerFlowConstraints(IpsoNetworkState networkState, IpsoOptions option) { + checkArgument(networkState != null, "networkState must not be null"); + List constraints = Lists.newArrayList(); + + // get all regulating phase tap transformer with setpoint defined .. + List transformerPtcWithSetpoint = networkState.getConnectedAndRegulatingPhaseTapChangerTransformer() + .filter(transformer -> transformer.getRegulationParameters().hasSetpointDefined()) + .collect(toList()); + + if (option.isTransformerSetpointTakenIntoAccount()) { + // and create a constraint for all of them + List setpointConstraints = transformerPtcWithSetpoint.stream() + .map(ipsoTransformer -> ipsoProblemComponentFactory.createConstraint2WTransformerFlow( + ipsoTransformer, + FlowUnit.AMPERE, + ipsoTransformer.getRegulationParameters().getSetpoint(), + ipsoTransformer.getRegulationParameters().getSetpoint(), + networkState.getWorld())) + .collect(toList()); + + constraints.addAll(setpointConstraints); + } + + if (option.isVoltageLimitsTakenIntoAccount()) { + // create flow limit constraint for all other transformers + List maxCurrentLimitconstraints = networkState.getIpsoTwoWindingsTransformers().stream() + .filter(IpsoTwoWindingsTransformer::isConnectedOnBothSides) + //.filter(IpsoTwoWindingsTransformer::hasMoreThanOneStep) + .filter(transformer -> !transformerPtcWithSetpoint.contains(transformer)) + .map(ipsoTransformer -> ipsoProblemComponentFactory.createConstraint2WTransformerFlow( + ipsoTransformer, + FlowUnit.AMPERE, + IpsoProblemComponentFactory.DEFAULT_BRANCH_FLOW_MIN, + ipsoTransformer.getMaxCurrentPermanentLimit(), + networkState.getWorld())) + .collect(toList()); + + constraints.addAll(maxCurrentLimitconstraints); + } + + + return constraints; + } + + public List createBankStepBoundsConstraints(IpsoNetworkState networkState) { + return Lists.newArrayList(); + } + + private IpsoNode findSlackBusIn(IpsoNetworkState networkState) { + return networkState.getIpsoNodes() + .stream() + .filter(IpsoNode::isSlackBus) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("There is no slack bus")); + } + + /** + * @return true iff the generator is connected to the node + */ + protected boolean areConnected(IpsoGenerator ipsoGenerator, IpsoNode ipsoNode) { + checkArgument(ipsoGenerator != null, "ipsoGenerator must not be null"); + checkArgument(ipsoNode != null, "ipsoNode must not be null"); + checkArgument(ipsoGenerator.getConnectedNode() != null, "ipsoGenerator.getConnectedNode() must not be null"); + return ipsoGenerator.getConnectedNode().equals(ipsoNode); + } +} + diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoConstraintFinder.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoConstraintFinder.java new file mode 100644 index 00000000..180d7167 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoConstraintFinder.java @@ -0,0 +1,105 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.service; + +import com.google.common.collect.Lists; +import eu.itesla_project.cta.model.IpsoBoundsEvaluator; +import eu.itesla_project.cta.model.IpsoConstraint; +import eu.itesla_project.cta.model.IpsoProblemDefinition; + +import java.util.Collection; +import java.util.List; + +import static com.google.common.base.Preconditions.checkArgument; +import static java.util.stream.Collectors.toList; + +/** + * @author Yannick Pihan + */ +class IpsoConstraintFinder { + + /** + * Constructor + */ + public IpsoConstraintFinder() { + } + + /** + * @return violated constraints + */ + public List findAllViolatedConstraintsIn(IpsoProblemDefinition ipsoProblemDefinition) { + checkArgument(ipsoProblemDefinition != null, "ipsoProblemDefinition must not be null"); + + // 1. find all constraints + List constraints = findAllConstraintsOf(ipsoProblemDefinition); + + // 2. filter on violated constraint + return constraints.stream() + .filter(IpsoConstraint::isViolated) + .collect(toList()); + } + + /** + * @return violated constraints from a list of constraints + */ + public > List findViolatedConstraintsIn(List constraints) { + return constraints.stream() + .filter(T::isViolated) + .collect(toList()); + } + + /** + * @return violated setpoint constraints from a list of constraints + */ + public > List findViolatedSetpointConstraintsIn(List constraints) { + return constraints.stream() + .filter(T::isViolated) + .filter(T::isSetpointConstraint) + .collect(toList()); + } + + /** + * @return violated bounds constraints from a list of constraints + */ + public > List findViolatedBoundsConstraintsIn(List constraints) { + return constraints.stream() + .filter(T::isViolated) + .filter(T::isNotSetpointConstraint) + .collect(toList()); + } + + /** + * @return not violated constraints from a list of constraints + */ + public > List findNotViolatedSetpointConstraintsIn(List constraints) { + return constraints.stream() + .filter(T::isNotViolated) + .filter(T::isSetpointConstraint) + .collect(toList()); + } + + public List findConstraintsJustOnTheBounds(Collection constraints) { + return constraints.stream() + .filter(c -> IpsoBoundsEvaluator.isJustOnTheBounds(c.getConstrainedValue(), c.getBoundsMin(), c.getBoundsMax())) + .collect(toList()); + } + + /** + * + * @return all constraints defined to the Ipso problem definition + */ + private List findAllConstraintsOf(IpsoProblemDefinition ipsoProblemDefinition) { + List ipsoConstraints = Lists.newArrayList( ipsoProblemDefinition.getConstraintNodeAcVoltageBounds()); + ipsoConstraints.addAll(ipsoProblemDefinition.getConstraintNodeAcAngleBounds()); + ipsoConstraints.addAll(ipsoProblemDefinition.getConstraintGeneratorPBounds()); + ipsoConstraints.addAll(ipsoProblemDefinition.getConstraintGeneratorQBounds()); + ipsoConstraints.addAll(ipsoProblemDefinition.getConstraint2WTransformerFlows()); + ipsoConstraints.addAll(ipsoProblemDefinition.getConstraint2WTransformerTaps()); + ipsoConstraints.addAll(ipsoProblemDefinition.getConstraintLineFlows()); + ipsoConstraints.addAll(ipsoProblemDefinition.getConstraintBankStepBounds()); + return ipsoConstraints; + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoControlVariableFactory.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoControlVariableFactory.java new file mode 100644 index 00000000..c6412dcb --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoControlVariableFactory.java @@ -0,0 +1,96 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.service; + +import com.google.common.collect.Lists; +import eu.itesla_project.cta.model.*; + +import java.util.List; + +import static com.google.common.base.Preconditions.checkArgument; +import static java.util.stream.Collectors.toList; +/** + * @author Yannick Pihan + */ +class IpsoControlVariableFactory { + + public static final float DEFAULT_SPEED_TAP = 2.f; + public static final float EPSILON = 0.00001f; + public static final float DEFAULT_SPEED_Q = 0f; + public static final float DEFAULT_SPEED_P = 9999f; + private final IpsoProblemComponentFactory ipsoProblemComponentFactory; + + public IpsoControlVariableFactory(IpsoProblemComponentFactory ipsoProblemComponentFactory) { + checkArgument(ipsoProblemComponentFactory != null, "ipsoProblemComponentFactory must not be null"); + this.ipsoProblemComponentFactory = ipsoProblemComponentFactory; + } + + /** + * + * @return the active power control variables + */ + public List createActiveProductionVariables(IpsoNetworkState networkState) { + checkArgument(networkState != null, "networkState must not be null"); + return networkState.getIpsoGenerators().stream() + .filter(IpsoGenerator::isBiggest) + .map(generator -> ipsoProblemComponentFactory.createVariableProductionP( + generator, + LinkOption.FREE, + DEFAULT_SPEED_P, + networkState.getWorld()) + ) + .collect(toList()); + } + + /** + * + * @return the reactive power control variables + */ + public List createReactiveProductionVariables(IpsoNetworkState networkState) { + checkArgument(networkState != null, "networkState must not be null"); + + List variables = networkState.getConnectedAndRegulatingGenerators() + .filter(IpsoGenerator::isDeltaQLimitUpperThanOneMvar) + .map(generator -> ipsoProblemComponentFactory.createVariableProductionQ( + generator, + LinkOption.VOLTAGE, + DEFAULT_SPEED_Q, + networkState.getWorld()) + ) + .collect(toList()); + + return variables; + } + + public List createTwoWindingTransformerTapVariables(IpsoNetworkState networkState, IpsoOptions option) { + + if ( option.isTransformerRegulateTakenIntoAccount() ) { + checkArgument(networkState != null, "networkState must not be null"); + return networkState.getIpsoTwoWindingsTransformers().stream() + .filter(IpsoTwoWindingsTransformer::isRegulating) + .filter(IpsoTwoWindingsTransformer::isConnectedOnBothSides) + .filter(IpsoTwoWindingsTransformer::hasMoreThanOneStep) + .map(transformer -> ipsoProblemComponentFactory.createVariable2WTransformerTap( + transformer, + LinkOption.TAP, + DEFAULT_SPEED_TAP, + EPSILON, + networkState.getWorld())) + .collect(toList()); + } + else { + return Lists.newArrayList(); + } + } + + public List createGeneratorStatismVariables(IpsoNetworkState networkState) { + return Lists.newArrayList(); + } + + public List createBankStepVariables(IpsoNetworkState networkState) { + return Lists.newArrayList(); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoCorrectiveActionService.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoCorrectiveActionService.java new file mode 100644 index 00000000..66903d7f --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoCorrectiveActionService.java @@ -0,0 +1,360 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.service; + +import com.google.common.base.Strings; +import eu.itesla_project.cta.converter.MappingBetweenIidmIdAndIpsoEquipment; +import eu.itesla_project.cta.model.*; +import eu.itesla_project.iidm.network.Network; +import eu.itesla_project.modules.contingencies.*; +import eu.itesla_project.modules.optimizer.PostContingencyState; + +import java.math.BigInteger; +import java.util.*; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkState; +import static com.google.common.collect.Iterables.getFirst; +import static com.google.common.collect.Lists.newArrayList; +import static eu.itesla_project.cta.service.IpsoOutputListingMessageType.*; +import static eu.itesla_project.modules.contingencies.ActionElementType.*; +import static java.util.Optional.*; +import static java.util.stream.Collectors.toList; +/** + * @author Yannick Pihan + */ +class IpsoCorrectiveActionService { + + private static final List TYPE_OF_IIDM_ACTIONS_SUPPORTED_BY_IPSO = newArrayList(SWITCH_OPEN, SWITCH_CLOSE, LINE_TRIPPING, TAP_CHANGE, GENERATION_REDISPATCHING); + private static final List> FLOW_CONSTRAINT_TYPES = newArrayList( + IpsoConstraint2WTransformerFlow.class, + IpsoConstraintLineFlowSide1.class, + IpsoConstraintLineFlowSide2.class, + AbstractIpsoConstraintLineFlow.class); + + private final ContingenciesAndActionsDatabaseClient client; + private final IpsoCorrectiveActionsFactory correctiveActionsFactory; + private final MappingBetweenIidmIdAndIpsoEquipment mappingIidmIpso; + private PostContingencyState postContingencyState; + + public IpsoCorrectiveActionService(PostContingencyState postContingencyState, ContingenciesAndActionsDatabaseClient client, + MappingBetweenIidmIdAndIpsoEquipment mappingIidmIpso) { + checkArgument(client != null, "client must not be null"); + checkArgument(postContingencyState != null, "postContingencyState must not be null"); + checkArgument(mappingIidmIpso != null, "mappingIidmIpso must not be null"); + this.client = client; + this.postContingencyState = postContingencyState; + this.mappingIidmIpso = mappingIidmIpso; + this.correctiveActionsFactory = new IpsoCorrectiveActionsFactory(); + } + + /** + * Create corrective actions to resolve violated constraints + * @return a list of corrective actions + */ + public CorrectiveActions createCorrectiveActionsToResolve(List violatedConstraints, IpsoOutputListing outputListing) { + checkArgument(violatedConstraints != null, "violatedConstraints must not be null"); + + // find associations corresponding to violated constraints + final List associations = findAssociationsWhichContain(violatedConstraints); + checkState(associations != null, "associations must not be null"); + + if (!associations.isEmpty()) { + + // For the moment we consider only one contingency and so only one assocation (fixme) + ActionsContingenciesAssociation association = getFirst(associations, null); + addAssoctiationIdsTo(outputListing, associations); + + // find action plans + List actionPlans = findActionPlansIn(association); // return always one action plan for the moment (fixme) + addActionPlanIdsTo(outputListing, actionPlans); + + String actionPlanId = getCandidateActionPlanIdFor(actionPlans); + + // find all actions from action plan or directly from the association if no action plan is defined + List actions = !actionPlans.isEmpty() + ? findLowerPriorityActionsFor(actionPlans) + : findActionFrom(association); + + addActionIdsTo(outputListing, actions); + + // create corrective actions + return createCorrectiveActionsFrom(actions, outputListing); + + } else { + outputListing.addToListing(NO_ASSOCIATION_FOUND); + return new CorrectiveActions(); + } + } + + private String getCandidateActionPlanIdFor(List actionPlans) { + return actionPlans.isEmpty() ? "" : actionPlans.stream().map(action -> action.getName()).findFirst().orElse(""); + } + + // Find action if action not in an ActionPlan + private List findActionFrom(ActionsContingenciesAssociation association) { + List actions = new ArrayList<>(); + Optional actionId = ofNullable(getFirst(association.getActionsId(), null)); + if (actionId.isPresent()) { + actions.add(client.getAction(actionId.get(), getPostContingencyNetwork())); + } + return actions; + } + + // TODO Action plan Id, List, ... + private CorrectiveActions createCorrectiveActionsFrom(List actions, IpsoOutputListing outputListing) { + List elements = createIpsoProblemDefinitionElementsFrom(actions); + + List variables = elements.stream() + .filter(IpsoProblemDefinitionElement::isVariable) + .map(IpsoControlVariable.class::cast) + .collect(toList()); + + List constraints = elements.stream() + .filter(IpsoProblemDefinitionElement::isConstraint) + .map(IpsoConstraint.class::cast) + .collect(toList()); + + List topologicalActions = + actions.stream() + .map(this::createTopologicalActionsFrom) + .flatMap(List::stream) + .collect(toList()); + + // complete output listing + addCorrectivesActionsTo(outputListing, variables, constraints, topologicalActions); + return new CorrectiveActions(variables, constraints, topologicalActions); + } + + private List findActionPlansIn(ActionsContingenciesAssociation association) { + checkArgument(association != null, "association must not be null"); + return association.getActionsId().stream() + .map(client::getActionPlan) + .filter(Objects::nonNull) + .limit(1) + .collect(toList()); + } + + private List findLowerPriorityActionsFor(List actionPlans) { + return actionPlans.stream() + .filter(Objects::nonNull) + .flatMap(actionPlan -> findLowerPriorityActionsFor(actionPlan).stream()) + .collect(toList()); + } + + + private List findLowerPriorityActionsFor(ActionPlan actionPlan) { + checkArgument(actionPlan != null, "actionPlan must not be null"); + Optional actionPlanOption = findActionPlanOptionOfLowerPriority(actionPlan); + return actionPlanOption + .map(option -> option.getActions().values() + .stream() + .map(id -> client.getAction(id, getPostContingencyNetwork())) + .collect(toList())) + .orElse(newArrayList()); + } + + private Optional findActionPlanOptionOfLowerPriority(ActionPlan actionPlan) { + checkArgument(actionPlan != null, "action plan must not be null"); + final Map actionPlanOptionMap = actionPlan.getPriorityOption(); + if ( actionPlanOptionMap.size() > 0 ) { + // get lower priority + final BigInteger key = Collections.min(actionPlanOptionMap.keySet()); + return of(actionPlanOptionMap.get(key)); + } + else { + return empty(); + } + } + + private List createIpsoProblemDefinitionElementsFrom(List actions) { + checkArgument(actions != null, "actions must not be null"); + return actions.stream() + .map(Action::getElements) + .flatMap(Collection::stream) + .map(this::createIpsoProblemDefinitionElementsFrom) + .flatMap(Collection::stream) + .collect(toList()); + } + + /** + * + * @return list of new Ipso problem definition elements (such as IpsoVariable or IpsoConstraint) + */ + private List createIpsoProblemDefinitionElementsFrom(ActionElement actionElement) { + checkArgument(actionElement != null, "actionElement must not be null"); + + if (actionElement instanceof GenerationRedispatching ) { + // potentially more than one generator are concerned + GenerationRedispatching generationRedispatching = (GenerationRedispatching) actionElement; + return generationRedispatching.getGeneratorIds().stream() + .filter(mappingIidmIpso::containsIpsoEquipmentFor) + .map(id -> mappingIidmIpso.getIpsoEquipmentFor(id).get()) + .map(correctiveActionsFactory::createProblemDefinitionElementsFor) + .flatMap(List::stream) + .collect(toList()); + } else if (actionElement instanceof TapChangeAction) { + return mappingIidmIpso.getIpsoEquipmentFor(actionElement.getEquipmentId()) + .map(correctiveActionsFactory::createProblemDefinitionElementsFor) + .orElse(newArrayList()); + } else { + // action element not supported by Ipso + return newArrayList(); + } + } + + private List createTopologicalActionsFrom(Action action) { + checkArgument(action != null, "actionElement must not be null"); + + List topologicalActions = action.getElements().stream() + .filter(this::thatCorrespondsToABranchOpeningAction) + .filter(this::thatReferencesAValidEquipment) + .map(this::findRelatedIpsoEquipmentId) + .map(id -> new TopologicalAction(id, SwitchAction.OPEN, action.getId())) + .collect(toList()); + + topologicalActions.addAll( + action.getElements().stream() + .filter(this::thatCorrespondsToABranchClosingAction) + .filter(this::thatReferencesAValidEquipment) + .map(this::findRelatedIpsoEquipmentId) + .map(id -> new TopologicalAction(id, SwitchAction.CLOSE, action.getId())) + .collect(toList()) + ); + + return topologicalActions; + } + + private boolean thatCorrespondsToABranchClosingAction(ActionElement actionElement) { + return actionElement instanceof SwitchClosingAction; + } + + private boolean thatCorrespondsToABranchOpeningAction(ActionElement actionElement) { + return actionElement instanceof SwitchOpeningAction || + actionElement instanceof LineTrippingAction; + } + + private String findRelatedIpsoEquipmentId(ActionElement actionElement) { + checkArgument(actionElement != null, "actionElement must not be null"); + checkArgument(!Strings.isNullOrEmpty(actionElement.getEquipmentId()), "actionElement.getEquipmentId() must not be null or empty"); + return mappingIidmIpso.getIpsoEquipmentFor(actionElement.getEquipmentId()) + .map(IpsoComponent::getId) + .orElse("unknownIpsoId"); + } + + /** + * @return true if the Iidm equipment id is existing in the mapping Iidm-Ipso + */ + private boolean thatReferencesAValidEquipment(ActionElement actionElement) { + return mappingIidmIpso.containsIpsoEquipmentFor(actionElement.getEquipmentId()); + } + + private void addUnsupportedActionsTo(IpsoOutputListing outputListing, List actions) { + List unSupportedElements = actions.stream() + .flatMap(action -> action.getElements().stream()) + .filter(IpsoCorrectiveActionService::isNotSupportedByIpso) + .collect(toList()); + outputListing.addToListing(UNSUPPORTED_CORRECTIVE_ACTIONS, unSupportedElements.stream().map(this::stringDescriptionOf).collect(toList())); + } + + private List findAssociationsWhichContain(List violatedConstraints) { + checkArgument(violatedConstraints != null, "violatedConstraints must not be null"); + return client.getActionsCtgAssociations().stream() + .filter(association -> thatContainsContingency(getContingency(), association)) + .filter(association -> thatMatchConstraintsWith(violatedConstraints, association)) + .collect(toList()); + } + + private Contingency getContingency() { + + return postContingencyState.getContingency(); + } + + private boolean thatContainsContingency(Contingency contingency, ActionsContingenciesAssociation actionsContingenciesAssociation) { + if (contingency != null ) { + return actionsContingenciesAssociation.getContingenciesId().stream() + .anyMatch(id -> id.equals(contingency.getId())); + } else { + return false; + } + } + + /** + * @return true if the association matches withe the violated constraints of Ipso + */ + private boolean thatMatchConstraintsWith(List violatedConstraints, ActionsContingenciesAssociation association) { + + if (association.getConstraints().size() == 0 ) { + // if no constraint defined int the association we consider the first violated flow constraint + return violatedConstraints.stream() + .anyMatch(c -> isAFlowConstraint(c)); + } + else { + // if constraints are defined in the association, we check if one of them is found in the list of ipsoConstraint + List iidmEquipmentIds = association.getConstraints().stream() + .map(Constraint::getEquipment) + .collect(toList()); + + return violatedConstraints.stream() + .anyMatch(constraint -> containsId(constraint.getRelatedIpsoEquipment().getIidmId(), iidmEquipmentIds)); + } + } + + private boolean isAFlowConstraint(final IpsoConstraint constraint) { + return FLOW_CONSTRAINT_TYPES.stream() + .anyMatch( aClass -> aClass.equals(constraint.getClass())); + } + + private boolean containsId(String iidmId, List iidmIds) { + return iidmIds.contains(iidmId); + } + + private static boolean isNotSupportedByIpso(ActionElement actionElement) { + return !TYPE_OF_IIDM_ACTIONS_SUPPORTED_BY_IPSO.contains(actionElement.getType()); + } + + private String stringDescriptionOf(ActionElement n) { + return String.format("%s - %s", n.getEquipmentId(), n.getType().name()); + } + + /*** Output listing ***/ + + private void addAssoctiationIdsTo(IpsoOutputListing outputListing, List associations) { + outputListing.addToListing(ASSOCIATION_FOUND, + associations.stream() + .map(ActionsContingenciesAssociation::getActionsId) + .collect(toList()) + ); + } + + + private void addActionPlanIdsTo(IpsoOutputListing outputListing, List actionPlans) { + outputListing.addToListing(ACTION_PLAN_FOUND, + actionPlans.stream() + .filter(Objects::nonNull) + .map(ActionPlan::getName) + .collect(toList()) + ); + } + + private void addActionIdsTo(IpsoOutputListing outputListing, List actions) { + outputListing.addToListing(ACTION_FOUND, + actions.stream() + .map(Action::getId) + .collect(toList()) + ); + } + + private void addCorrectivesActionsTo(IpsoOutputListing outputListing, List variables, List constraints, List topologicalActions) { + outputListing.addToListing(NEW_CORRECTIVE_CONTROLVARIABLES, variables); + outputListing.addToListing(NEW_CORRECTIVE_CONSTRAINTS, constraints); + outputListing.addToListing(NEW_TOPOLOGICAL_ACTIONS, topologicalActions); + } + + private Network getPostContingencyNetwork() { + return postContingencyState.getNetwork(); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoCorrectiveActionsFactory.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoCorrectiveActionsFactory.java new file mode 100644 index 00000000..7d5f7a94 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoCorrectiveActionsFactory.java @@ -0,0 +1,69 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.service; + +import com.google.common.collect.Lists; +import eu.itesla_project.cta.model.*; + +import java.util.List; + +import static com.google.common.base.Preconditions.checkArgument; +import static eu.itesla_project.cta.model.LinkOption.TAP; +import static eu.itesla_project.cta.service.IpsoControlVariableFactory.DEFAULT_SPEED_TAP; +import static eu.itesla_project.cta.service.IpsoControlVariableFactory.EPSILON; +/** + * @author Yannick Pihan + */ +class IpsoCorrectiveActionsFactory { + + private final IpsoProblemComponentFactory ipsoProblemComponentFactory; + + IpsoCorrectiveActionsFactory() { + ipsoProblemComponentFactory = new IpsoProblemComponentFactory(); + } + + public List createProblemDefinitionElementsFor(IpsoEquipment equipment) { + checkArgument(equipment != null, "equipment must be null"); + List elements = Lists.newArrayList(); + + if ( equipment instanceof IpsoTwoWindingsTransformer) { + final IpsoTwoWindingsTransformer twoWindingsTransformer = (IpsoTwoWindingsTransformer) equipment; + elements.add(createControlVariableForTapChanger(twoWindingsTransformer)); + elements.add(createConstraintForTapChanger(twoWindingsTransformer)); + } + else if (equipment instanceof IpsoGenerator) { + final IpsoGenerator generator = (IpsoGenerator)equipment; + elements.add(createControlVariableActiveProductionFor(generator)); + elements.add(createConstraintActiveProductionFor(generator)); + } + return elements; + } + + private T createConstraintActiveProductionFor(IpsoGenerator generator) { + return (T)ipsoProblemComponentFactory.createConstraintProductionPBounds(generator, generator.getMinActivePower(), generator.getMaxActivePower(),0 ); + } + + private T createControlVariableActiveProductionFor(IpsoGenerator generator) { + return (T)ipsoProblemComponentFactory.createVariableProductionP(generator, LinkOption.POWER, 0.0f, 0); + } + + private T createControlVariableForTapChanger(IpsoTwoWindingsTransformer transformer) { + return (T) ipsoProblemComponentFactory.createVariable2WTransformerTap( + transformer, + TAP, + DEFAULT_SPEED_TAP, + EPSILON, + 0); + } + + private T createConstraintForTapChanger(IpsoTwoWindingsTransformer transformer) { + return (T)ipsoProblemComponentFactory.createConstraint2WTfoTap( + transformer, + transformer.getLowStep(), + transformer.getHighStep(), + 0); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoEquipmentType.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoEquipmentType.java new file mode 100644 index 00000000..eaf66dbf --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoEquipmentType.java @@ -0,0 +1,20 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.service; +/** + * @author Yannick Pihan + */ +public enum IpsoEquipmentType { + NODE, + LINE, + TFO2W, + TFO3W, + GENERATOR, + LOAD, + BANK, + COUPLING, + UNKNOWN +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoIdUtil.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoIdUtil.java new file mode 100644 index 00000000..0b05553f --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoIdUtil.java @@ -0,0 +1,21 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.service; + +import eu.itesla_project.cta.model.IpsoEquipment; + +import java.util.concurrent.atomic.AtomicLong; +/** + * @author Yannick Pihan + */ +public class IpsoIdUtil { + + private static AtomicLong atomicLong = new AtomicLong(1); + + public static String getNextUniqueId() { + return String.valueOf(atomicLong.getAndIncrement()); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoInvalidComponent.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoInvalidComponent.java new file mode 100644 index 00000000..3688f2f4 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoInvalidComponent.java @@ -0,0 +1,84 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.service; + +import eu.itesla_project.cta.model.IpsoComponent; +import eu.itesla_project.cta.model.IpsoEquipment; +import eu.itesla_project.cta.model.IpsoOneConnectionEquipment; +import eu.itesla_project.cta.model.ValidationType; + +import java.util.List; +/** + * @author Yannick Pihan + */ +public class IpsoInvalidComponent extends IpsoComponent{ + protected static final String CONNECTED_TO = " connected to "; + protected static final String INVALID_COMPONENT = "Invalid "; + protected static final String CAUSED_BY = " caused by "; + private final Class ipsoComponentClass; + private final float unvalidatedValue; + private ValidationType validationType; + private IpsoEquipment ipsoEquipment; + private String id; + + /** + * Constructor + */ + public IpsoInvalidComponent(IpsoEquipment ipsoEquipment, ValidationType validationType, Class ipsoComponentClass, float unvalidatedValue) { + super(IpsoIdUtil.getNextUniqueId(), 0); + this.ipsoEquipment = ipsoEquipment; + this.validationType = validationType; + this.ipsoComponentClass = ipsoComponentClass; + this.unvalidatedValue = unvalidatedValue; + } + + @Override + public String toString() { + return new StringBuilder() + .append(INVALID_COMPONENT) + .append(ipsoComponentClass.getSimpleName()) + .append(getEquipmentDescription()) + .append(findConnectedEquipmentDescription()) + .append(CAUSED_BY) + .append(validationType.name()) + .append(findValidationValueDescription()) + .toString(); + } + + public String getEquipmentDescription() { + return String.format(" for %s %s%s", this.ipsoEquipment.getClass().getSimpleName(), ipsoEquipment.getId(), getIidmIdDescriptionFor(ipsoEquipment)); + } + + private String getIidmIdDescriptionFor(IpsoEquipment ipsoEquipment) { + return String.format(" (%s) ", ipsoEquipment.getIidmId()); + } + + private String findConnectedEquipmentDescription() { + if (ipsoEquipment instanceof IpsoOneConnectionEquipment) { + IpsoOneConnectionEquipment oneConnectionEquipment = (IpsoOneConnectionEquipment)ipsoEquipment; + return new StringBuilder(CONNECTED_TO) + .append(oneConnectionEquipment.getConnectedNode().getId()) + .append(getIidmIdDescriptionFor(oneConnectionEquipment.getConnectedNode())).toString(); + + } else { + return ""; + } + } + + private String findValidationValueDescription() { + return String.format(" (%f) ", unvalidatedValue); + } + + @Override + public List getOrderedValues() { + return null; + } + + @Override + public List getOrderedHeaders() { + return null; + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoInvalidIpsoComponentFactory.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoInvalidIpsoComponentFactory.java new file mode 100644 index 00000000..c38238dc --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoInvalidIpsoComponentFactory.java @@ -0,0 +1,43 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.service; + +import com.google.common.collect.Lists; +import eu.itesla_project.cta.model.IpsoComponent; +import eu.itesla_project.cta.model.IpsoGenerator; +import eu.itesla_project.cta.model.IpsoNetworkState; +import eu.itesla_project.cta.model.ValidationType; + +import java.util.List; + +import static com.google.common.base.Preconditions.checkArgument; +import static java.util.stream.Collectors.toList; +/** + * @author Yannick Pihan + */ +public class IpsoInvalidIpsoComponentFactory { + + public List createInvalidComponentsThatHave(ValidationType validationType, Class ipsoComponentClass, IpsoNetworkState networkState) { + checkArgument(networkState != null, "networkState must not be null"); + checkArgument(ipsoComponentClass != null, "ipsoComponentClass must not be null"); + + switch (validationType) { + case DELTA_P_LIMIT_LOWER_THAN_ONE_MVAR: + return Lists.newArrayList(); // not used + case DELTA_Q_LIMIT_LOWER_THAN_ONE_MVAR: + return createInvalidComponentForQLimits(validationType, ipsoComponentClass, networkState); + default: + throw new IllegalArgumentException("unsupported ValidationType"); + } + } + + private List createInvalidComponentForQLimits(ValidationType validationType, Class ipsoComponentClass, IpsoNetworkState networkState) { + return networkState.getConnectedAndRegulatingGenerators() + .filter(IpsoGenerator::isDeltaQLimitLowerThanOneMvar) + .map(generator -> new IpsoInvalidComponent(generator, validationType, ipsoComponentClass, generator.getDeltaQ())) + .collect(toList()); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoOptimizationResults.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoOptimizationResults.java new file mode 100644 index 00000000..fefacd5e --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoOptimizationResults.java @@ -0,0 +1,36 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.service; + +import java.nio.file.Path; +/** + * @author Yannick Pihan + */ +public class IpsoOptimizationResults { + private final IpsoOptimizationStatus status; + private final Path csvFile; + private final Path outFile; + private final IpsoSolution solution; + + public IpsoOptimizationResults(IpsoOptimizationStatus status, Path outFile, Path csvFile, IpsoSolution solution) { + this.status = status; + this.csvFile = csvFile; + this.outFile = outFile; + this.solution = solution; + } + + public IpsoOptimizationStatus getStatus() { + return status; + } + + public IpsoSolution getSolution() { + return solution; + } + + public boolean hasSolutionFound() { + return solution != null; + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoOptimizationResultsService.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoOptimizationResultsService.java new file mode 100644 index 00000000..651c70fb --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoOptimizationResultsService.java @@ -0,0 +1,195 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.service; + +import com.google.common.base.Splitter; +import com.google.common.collect.Lists; +import eu.itesla_project.computation.ExecutionReport; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.FilenameUtils; +import org.slf4j.Logger; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.Optional; +import java.util.function.Predicate; + +import static com.google.common.base.Preconditions.checkArgument; +import static eu.itesla_project.cta.service.IpsoEquipmentType.GENERATOR; +import static eu.itesla_project.cta.service.IpsoEquipmentType.TFO2W; +import static eu.itesla_project.cta.service.IpsoOptimizationStatus.*; +import static java.util.stream.Collectors.toList; +import static org.slf4j.LoggerFactory.getLogger; +/** + * @author Yannick Pihan + */ +final class IpsoOptimizationResultsService { + + private static final Logger LOG = getLogger(IpsoOptimizationResultsService.class); + + protected static final char SEPARATOR = ';'; + protected static final int INDEX_OF_TOLERANCE = 3; + protected static final double TOLERANCE_ERROR = 0.0001; + protected static final String CONTROL = "CONTROL"; + protected static final String TAP = "TAP"; + protected static final String GENE = "GENE"; + protected static final String TFO_2 = "TFO2"; + + public IpsoOptimizationResults createIpsoOptimizationResults(ExecutionReport executionReport, Path csvPath) { + checkArgument(csvPath != null, "csvPath must not be null"); + checkArgument(executionReport != null, "executionReport must not be null"); + + Path outPath = resolveOutPathFrom(csvPath); + + IpsoOptimizationStatus status; + IpsoSolution solution = null; + if (isExecutionFailed(executionReport)) { + status = EXECUTION_FAILED; + } + else if ( isNullOrNotExists(outPath) ) { + status = IPSO_OUT_FILE_MISSING; + } + else if ( isNullOrNotExists(csvPath)) { + status = IPSO_CSV_FILE_MISSING; + } + else { + solution = createSolutionFromFile(csvPath); + status = findStatusOf(solution); + } + + return new IpsoOptimizationResults(status, outPath, csvPath, solution); + } + + private IpsoOptimizationStatus findStatusOf(IpsoSolution solution) { + return solution.getObjectiveFunctionValue() < TOLERANCE_ERROR ? SUCCEDED : ERROR; + } + + private IpsoSolution createSolutionFromFile(Path path) { + List solutions = Lists.newArrayList(); + List lines = readLinesOf(path); + if ( lines.isEmpty()) { + return new IpsoSolution(solutions, 9999.9f); + } + else { + float tolerance = findTolerance(lines); + solutions.addAll(findGeneratorSolutions(lines)); + solutions.addAll(findTransformerSolutions(lines)); + return new IpsoSolution(solutions, tolerance); + } + } + + private boolean isExecutionFailed(ExecutionReport executionReport) { + return !executionReport.getErrors().isEmpty(); + } + + private List findTransformerSolutions(List lines) { + return lines.stream() + .filter(this::lineThatConstainsControl) + .filter(lineThatContainsTransformerDescription()) + .map(this::createSolutionForTransformer) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(toList()); + } + + private List findGeneratorSolutions(List lines) { + return lines.stream() + .filter(this::lineThatConstainsControl) + .filter(lineThatContainsGeneratorDescription()) + .map(this::createSolutionForGenerator) + .collect(toList()); + } + + private IpsoSolutionElement createSolutionForGenerator(String line) { + List lines = splitToList(line); + String name = lines.get(3); + String attribute = lines.get(4); + float setpoint = Float.parseFloat(lines.get(8)); + return new IpsoSolutionElement(GENERATOR, name, attribute, setpoint); + } + + private Optional createSolutionForTransformer(String line) { + List lines = splitToList(line); + String name = lines.get(3); + String attribute = lines.get(4); + if (attribute.contains(TAP)) { + float setpoint = Float.parseFloat(lines.get(8)); + return Optional.of(new IpsoSolutionElement(TFO2W, name, attribute, setpoint)); + } + else { + return Optional.empty(); + } + } + + private Predicate lineThatContainsGeneratorDescription() { + return line -> splitToList(line).contains(GENE); + } + + private Predicate lineThatContainsTransformerDescription() { + return line -> splitToList(line).contains(TFO_2); + } + + private boolean lineThatConstainsControl(String line) { + return splitToList(line).contains(CONTROL); + } + + float findTolerance(List lines) { + Optional lineObjFun = lines.stream() + .filter(line -> linesThatConstains("OBJFUN", line)) + .findFirst(); + + if (lineObjFun.isPresent()) { + return getFloatValueAt(INDEX_OF_TOLERANCE, lineObjFun); + } + else { + return 9999.0f; + } + } + + float getFloatValueAt(int index, Optional lineToParse) { + return getFloatValueAt(index, lineToParse.get()); + } + + float getFloatValueAt(int index, String lineToParse) { + return Float.parseFloat(splitToList(lineToParse).get(index)); + } + + boolean linesThatConstains(String match, String line) { + return splitToList(line).contains(match); + } + + private List splitToList(String line) { + return Lists.newArrayList(Splitter.on(SEPARATOR).trimResults().split(line)); + } + + private List readLinesOf(Path resultPath) { + List lines = Lists.newArrayList(); + File file = new File(resultPath.toUri()); + try { + lines.addAll(FileUtils.readLines(file, "UTF-8")); + } catch (IOException e) { + LOG.error("Cannot read Ipso result file {} - {}", resultPath, e.getMessage()); + }finally { + return lines; + } + } + + boolean isNullOrNotExists(Path path) { + return path == null || !Files.exists(path); + } + + /** + * Resolve 'ipso'.out path form 'ipso'.csv file path + * @return Ipso log path .out form Ipso CSV file path or null if the new path does not exist + */ + Path resolveOutPathFrom(Path path) { + return Paths.get(FilenameUtils.removeExtension(path.toString()) + ".out"); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoOptimizationStatus.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoOptimizationStatus.java new file mode 100644 index 00000000..1a9deeb8 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoOptimizationStatus.java @@ -0,0 +1,28 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.service; +/** + * @author Yannick Pihan + */ +public enum IpsoOptimizationStatus { + ABORTED("IPSO ABORTED"), + EXECUTION_FAILED("IPSO EXECUTION FAILED"), + IPSO_OUT_FILE_MISSING("IPSO OUT FILE MISSING"), + IPSO_CSV_FILE_MISSING("IPSO CSV FILE MISSING"), + ERROR("IPSO OPTIMIZATION HAS ENCOUNTERED ERROR(S)"), + SUCCEDED("IPSO OPTIMISATION SUCCEEDED"), + UNDEFINED("NO STATUS AVAILABLE"); + + private String message; + + IpsoOptimizationStatus(String message) { + this.message = message; + } + + public String getMessage() { + return message; + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoOptimizerConfiguration.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoOptimizerConfiguration.java new file mode 100644 index 00000000..4931d484 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoOptimizerConfiguration.java @@ -0,0 +1,76 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.service; + +import eu.itesla_project.commons.io.ModuleConfig; +import eu.itesla_project.commons.io.PlatformConfig; + +import java.nio.file.Path; +/** + * @author Yannick Pihan + */ +public class IpsoOptimizerConfiguration { + + private String ipsoWorkingDirPrefix = "itesla_ipso_"; + private String amplWorkingDirPrefix = "itesla_ampl_"; + private boolean debug = true; + private int priority = 1; + private Path solverPath; + private Path solverRessourcePath; + private Path amplPath; + private Path ipsoPath; + + public IpsoOptimizerConfiguration(Path solverPath, Path ipsoPath, Path amplDir, Path amplResourcePath) { + this.solverPath = solverPath; + this.ipsoPath = ipsoPath; + this.amplPath = amplDir; + this.solverRessourcePath = amplResourcePath; + } + + private IpsoOptimizerConfiguration() { + ModuleConfig config = PlatformConfig.defaultConfig().getModuleConfig("ipso"); + ipsoPath = config.getPathProperty("ipso", null); + amplPath = config.getPathProperty("ampl", null); + solverPath = config.getPathProperty("solver", null); + solverRessourcePath = config.getPathProperty("solverResources", null); + } + + public void setDebug(boolean debug) { + this.debug = debug; + } + + public Path getIpsoPath() { + return ipsoPath; + } + + public Path getSolverPath() { + return solverPath; + } + + public Path getAmplPath() { + return amplPath; + } + + public Path getSolverRessourcePath() { + return solverRessourcePath; + } + + public int getPriority() { + return priority; + } + + public boolean isDebug() { + return debug; + } + + public static IpsoOptimizerConfiguration createOptimizationConfiguration() { + return new IpsoOptimizerConfiguration(); + } + + public String getAmplWorkingDirPrefix() { + return amplWorkingDirPrefix; + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoOptions.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoOptions.java new file mode 100644 index 00000000..9391110f --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoOptions.java @@ -0,0 +1,115 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.service; +/** + * @author Yannick Pihan + */ +public class IpsoOptions { + + private final boolean transformerRegulateTakenIntoAccount; + private final boolean transformerSetpointTakenIntoAccount; + private final boolean generatorSetpointTakenIntoAccount; + private final boolean voltageLimitsTakenIntoAccount; + private final boolean currentLimitsTakenIntoAccount; + private final boolean actionCorrectivesTakenIntoAccount; + private final boolean continueCorrectiveActionTakenIntoAccount; + + /** + * Constructor + */ + private IpsoOptions(boolean transformerRegulateTakenIntoAccount, + boolean transformerSetpointTakenIntoAccount, + boolean generatorSetpointTakenIntoAccount, + boolean voltageLimitsTakenIntoAccount, + boolean currentLimitsTakenIntoAccount, + boolean actionCorrectivesTakenIntoAccount, + boolean continueCorrectiveActionTakenIntoAccount) { + this.transformerRegulateTakenIntoAccount = transformerRegulateTakenIntoAccount; + this.transformerSetpointTakenIntoAccount = transformerSetpointTakenIntoAccount; + this.generatorSetpointTakenIntoAccount = generatorSetpointTakenIntoAccount; + this.voltageLimitsTakenIntoAccount = voltageLimitsTakenIntoAccount; + this.currentLimitsTakenIntoAccount = currentLimitsTakenIntoAccount; + this.actionCorrectivesTakenIntoAccount = actionCorrectivesTakenIntoAccount; + this.continueCorrectiveActionTakenIntoAccount = continueCorrectiveActionTakenIntoAccount; + } + + /** + * + * @return true if the setpoint of transformer is fixed. + * If yes, a voltage setpoint constraint is mandatory on the regulated node. + */ + public boolean isTransformerSetpointTakenIntoAccount() { + return transformerSetpointTakenIntoAccount; + } + + /** + * @return true if the transformer regulates voltage without fixed setpoint. + * Ipso can then chosen the best setpoint. + * Remark: + * return true is the option setpoint transformer is already taken into account + * otherwize the regulate transformer option is considered. + */ + public boolean isTransformerRegulateTakenIntoAccount() { + if (transformerSetpointTakenIntoAccount) { + return true; + } + else { + return transformerRegulateTakenIntoAccount; + } + } + + public boolean isGeneratorSetpointTakenIntoAccount() { + return generatorSetpointTakenIntoAccount; + } + + public boolean isVoltageLimitsTakenIntoAccount() { + return voltageLimitsTakenIntoAccount; + } + + public boolean isCurrentLimitsTakenIntoAccount() { + return currentLimitsTakenIntoAccount; + } + + public boolean isActionCorrectivesTakenIntoAccount() { + return actionCorrectivesTakenIntoAccount; + } + + public boolean isContinueCorrectiveActionTakenIntoAccount() { + return continueCorrectiveActionTakenIntoAccount; + } + + /** + * Factory method + * @return opf options + */ + public static IpsoOptions createOptionsForOpf() { + return new IpsoOptions( + false, // transformerRegulateTakenIntoAccount; + false, // transformerSetpointTakenIntoAccount; + true, // generatorSetpointTakenIntoAccount; + false, // voltageLimitsTakenIntoAccount; + false, // currentLimitsTakenIntoAccount; + false, // action corrective taken into account + true // continue corrective actions taken into acount + ); + } + + /** + * Factory method + * @return scopf options + */ + public static IpsoOptions createOptionsForScOpf() { + return new IpsoOptions( + true, // transformer Regulate Taken into account; + true, // transformer Setpoint Taken into account; + true, // generator Setpoint Taken into account; + true, // voltage Limits Taken into account; + true, // current Limits Taken into account; + true, // action corrective taken into account + true // continue corrective actions taken into acount + ); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoOutputListing.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoOutputListing.java new file mode 100644 index 00000000..28742155 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoOutputListing.java @@ -0,0 +1,328 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.service; + +import com.google.common.base.Preconditions; +import com.google.common.collect.Lists; +import eu.itesla_project.computation.ComputationManager; +import eu.itesla_project.cta.converter.MappingBetweenIidmIdAndIpsoEquipment; +import eu.itesla_project.cta.model.IpsoEquipment; +import eu.itesla_project.iidm.network.*; +import eu.itesla_project.modules.contingencies.Contingency; +import eu.itesla_project.modules.optimizer.CCOFinalStatus; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Path; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Collection; +import java.util.List; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.collect.Lists.newArrayList; +import static java.util.stream.Collectors.joining; +import static java.util.stream.Collectors.toList; +import static org.apache.commons.lang3.SystemUtils.LINE_SEPARATOR; +/** + * @author Yannick Pihan + */ +public class IpsoOutputListing { + + public static final String DELIMITER = ","; + protected static final String OUTOUT_LISTING_FILENAME = "ipsoOutputListing.txt"; + protected static final String DATE_FORMAT_NOW = "yyyy-MM-dd HH:mm:ss"; + + private final MappingBetweenIidmIdAndIpsoEquipment mappingBetweenIidmIdAndIpsoEquipment; + private List listing; + private String filename; + + private ComputationManager computationManager; + + /** + * Constructor + */ + public IpsoOutputListing(MappingBetweenIidmIdAndIpsoEquipment mappingBetweenIidmIdAndIpsoEquipment) { + checkArgument(mappingBetweenIidmIdAndIpsoEquipment != null, "mappingBetweenIidmIdAndIpsoEquipment must not be null"); + this.mappingBetweenIidmIdAndIpsoEquipment = mappingBetweenIidmIdAndIpsoEquipment; + listing = newArrayList(); + filename = OUTOUT_LISTING_FILENAME; + } + + private String getIpsoId(String iidmId) { + return mappingBetweenIidmIdAndIpsoEquipment.getIpsoEquipmentFor(iidmId) + .map(IpsoEquipment::getId) + .orElse("?"); + } + + private String formatLine(Object ... elements) { + List lines = newArrayList(elements); + return lines.stream() + .map(Object::toString) + .collect(joining(DELIMITER)); + } + + private String header() { + return IpsoOutputListingMessageType.IPSO_OUTPUT_LISTING.getMessage(); + } + + private void addListHeader(int numberOfElement, String header) { + listing.add(""); + listing.add(String.format("%s %s:", numberOfElement, header)); + } + + public void addToListing(IpsoOutputListingMessageType messageType, Collection components) { + addListHeader(components.size(), messageType.getMessage()); + listing.addAll( + components + .stream() + .map(T::toString) + .collect(toList()) + ); + } + + public void addToListing(IpsoOutputListingMessageType correctiveActions, String... arguments) { + listing.add(String.format(correctiveActions.getMessage(), arguments)); + } + + public void addContingency(Contingency contingency) throws IOException { + checkArgument(contingency != null, "contingency must not have a null contingency"); + listing.add(IpsoOutputListingMessageType.CONTINGENCY_HEADER.getMessage()); // Contingency applied: + listing.add(contingency.getId()); + + listing.add(IpsoOutputListingMessageType.CONTINGENCY_ARRAY_HEADER.getMessage()); + listing.addAll(contingency.getElements().stream() + .map(element -> formatLine(getIpsoId(element.getId()), element.getId(), element.getType().name())) + .collect(toList())); + } + + public void addLoadFlowResultsFor(Network network) { + Preconditions.checkArgument(network != null, "network must be null"); + + listing.add(""); + listing.add(String.format("LOAD FLOW RESULTS FOR NETWORK: %s", network.getName())); + listing.add(""); + listing.add("GENERATORS"); + listing.add("# Names terminal P (MW) terminal Q (MVAR) "); + listing.add("#-------------------- ---------------- ---------------- "); + for (Generator gen : network.getGenerators()) { + listing.add(String.format("%s %s %15.8f %15.8f", getIpsoId(gen.getId()), gen.getId(), gen.getTerminal().getP(), gen.getTerminal().getQ())); + } + listing.add( ""); + + listing.add( "BUSES"); + listing.add("# Name V (kV) Angle (Degrees) "); + listing.add("#-------------------- --------------- --------------- "); + for (Bus bus : network.getBusBreakerView().getBuses()) { + listing.add(String.format("%s %s %15.8f %15.8f", getIpsoId(bus.getId()), bus.getId(), bus.getV(), bus.getAngle())); + } + //listing.add("END BUSES\n"); + listing.add( ""); + + listing.add( "BRANCHES"); + listing.add("# Q (MVAR) P (MW) "); + listing.add("# ------------------------------- ------------------------------- "); + listing.add("# Name From To From To "); + listing.add("#--------------------------------- --------------- --------------- --------------- --------------- "); + for (Line line : network.getLines()) { + listing.add(String.format("%s %s %15.8f %15.8f %15.8f %15.8f", getIpsoId(line.getId()), line.getId(), line.getTerminal1().getQ(), line.getTerminal2().getQ(), line.getTerminal1().getP(), line.getTerminal2().getP())); + } + listing.add( ""); + + listing.add( "DANGLINGLINES"); + listing.add("# Q (MVAR) P (MW) "); + listing.add("# ------------------------------- ------------------------------- "); + listing.add("# Name From To From To "); + listing.add("#--------------------------------- --------------- --------------- --------------- --------------- "); + for (DanglingLine danglingLine : network.getDanglingLines()) { + listing.add(String.format("%s %s %15.8f %15.8f %15.8f %15.8f", getIpsoId(danglingLine.getId()), danglingLine.getId(), danglingLine.getTerminal().getQ(), null, danglingLine.getTerminal().getP(), null)); + } + + listing.add( ""); + listing.add( "BRANCHES CURRENT"); + listing.add("# Flow (Ampere) "); + listing.add("# ------------------------------- "); + listing.add("# Name From To "); + listing.add("#--------------------------------- --------------- --------------- "); + for (Line line : network.getLines()) { + listing.add(String.format("%s %s %15.8f %15.8f", getIpsoId(line.getId()), line.getId(), line.getTerminal1().getI(), line.getTerminal2().getI())); + } + + listing.add( ""); + listing.add( "DANGLINGLINES CURRENT"); + listing.add("# Flow (Ampere) "); + listing.add("# ------------------------------- "); + listing.add("# Name From To "); + listing.add("#--------------------------------- --------------- --------------- "); + for (DanglingLine danglingLine : network.getDanglingLines()) { + listing.add(String.format("%s %s %15.8f %15.8f", getIpsoId(danglingLine.getId()), danglingLine.getId(), danglingLine.getTerminal().getI(), null)); + } + //listing.add("END DANGLINGLINES CURRENT\n"); + listing.add( ""); + listing.add("TRANSFORMERS"); + listing.add("# Q (MVAR) P (MW) "); + listing.add("# ------------------------------- ------------------------------- "); + listing.add("# Name From To From To "); + listing.add("#--------------------------------- --------------- --------------- --------------- --------------- "); + for (TwoTerminalsConnectable transfo : network.getTwoWindingsTransformers()) { + listing.add(String.format("%s %s %15.8f %15.8f %15.8f %15.8f", getIpsoId(transfo.getId()), transfo.getId(), transfo.getTerminal1().getQ(), transfo.getTerminal2().getQ(), transfo.getTerminal1().getP(), transfo.getTerminal2().getP())); + } + //listing.add("END TRANSFORMERS\n"); + listing.add(""); + //listing.add("TRANSFORMERS"); + listing.add("# Flow (Ampere) "); + listing.add("# ------------------------------- "); + listing.add("# Name From To "); + listing.add("#--------------------------------- --------------- --------------- "); + for (TwoTerminalsConnectable transfo : network.getTwoWindingsTransformers()) { + listing.add(String.format("%s %s %15.8f %15.8f", getIpsoId(transfo.getId()), transfo.getId(), transfo.getTerminal1().getI(), transfo.getTerminal2().getI())); + } + //listing.add("END TRANSFORMERS\n"); + + listing.add(""); + listing.add("COUPLING"); + listing.add("# Name Bus 1 Bus 2 V"); + listing.add("#--------------------------------------------------- ---------------- ------------------ --------------- "); + for (VoltageLevel voltageLevel : network.getVoltageLevels()) { + for(Switch s : voltageLevel.getBusBreakerView().getSwitches()) { + listing.add(String.format("%s %s %s %s %15.8f", + getIpsoId(s.getId()), + s.getId(), + voltageLevel.getBusBreakerView().getBus1(s.getId()), + voltageLevel.getBusBreakerView().getBus2(s.getId()), + voltageLevel.getNominalV())); + } + } + + listing.add(""); + listing.add("LOAD"); + listing.add("# INITIAL POWER "); + listing.add("# ------------------------------- "); + listing.add("# Name P0 Q0 "); + listing.add("#--------------------------------- --------------- --------------- "); + for (Load load : network.getLoads()) { + listing.add(String.format("%s %s %15.8f %15.8f", getIpsoId(load.getId()), load.getId(), load.getP0(), load.getQ0())); + } + listing.add(separation()); + } + + private String separation() { + return StringUtils.repeat("=", 80); + } + + @Deprecated + public void write() { + try { + try (OutputStream fileToWrite = computationManager.newCommonFile(filename)) { + List linesToWrite = Lists.newArrayList(); + linesToWrite.add(separation()); + linesToWrite.add(header()); + linesToWrite.add(now()); + linesToWrite.add(separation()); + linesToWrite.addAll(listing); + IOUtils.writeLines(linesToWrite, LINE_SEPARATOR, fileToWrite); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void write(ComputationManager computationManager, String filename) { + try { + try (OutputStream fileToWrite = computationManager.newCommonFile(filename)) { + List linesToWrite = newArrayList(); + linesToWrite.add(separation()); + linesToWrite.add(header()); + linesToWrite.add(now()); + linesToWrite.add(separation()); + linesToWrite.addAll(listing); + IOUtils.writeLines(linesToWrite, LINE_SEPARATOR, fileToWrite); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void write(Path outputPath, String filename) { + try { + try (OutputStream fileToWrite = new FileOutputStream(outputPath.resolve(filename).toFile())) { + List linesToWrite = newArrayList(); + linesToWrite.add(separation()); + linesToWrite.add(header()); + linesToWrite.add(now()); + linesToWrite.add(separation()); + linesToWrite.addAll(listing); + IOUtils.writeLines(linesToWrite, LINE_SEPARATOR, fileToWrite); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void addAmplError(Exception e) { + addSeparator(); + listing.add("ERROR during AMPL execution: "+ e.getMessage()); + addSeparator(); + } + + public void addOptimizationError(IllegalArgumentException e) { + addSeparator(); + listing.add("Optimization process error: "+ e.getMessage()); + addSeparator(); + } + + public void addResultCode(CCOFinalStatus status) { + addSeparator(); + listing.add(IpsoOutputListingMessageType.CORRECTIVE_ACTION_RESULT.getMessage()); + listing.add(status.toString()); + addSeparator(); + } + + + public void addAmplResult(AmplStatus status, Collection actions) { + addSeparator(); + listing.add(IpsoOutputListingMessageType.AMPL_SOLUTION_HEADER.getMessage()); + listing.add(status.getTextDescription()); + if(status == AmplStatus.SUCCEEDED) { + addSeparator(); + listing.add(IpsoOutputListingMessageType.AMPL_SOLUTION_FOUND.getMessage()); + actions.stream().forEach(listing::add); + } + addSeparator(); + } + + + public void addSeparator() { + listing.add(""); + } + + public static String now() { + Calendar cal = Calendar.getInstance(); + SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT_NOW); + return sdf.format(cal.getTime()); + } + + public void addToListing(IpsoOptimizationResults result) { + checkArgument(result != null, "result cannot be null"); + addStatusOf(result); + if (result.hasSolutionFound()) { + addSolutionOf(result); + } + } + + private void addSolutionOf(IpsoOptimizationResults results) { + listing.add(String.format("%s %s", IpsoOutputListingMessageType.OBJ_FUN_VALUE.getMessage(), results.getSolution().getObjectiveFunctionValue())); + listing.add(IpsoOutputListingMessageType.SOLUTION_FOUND.getMessage()); + results.getSolution().getSolutionElements().forEach(c -> listing.add(c.toString())); + } + + private void addStatusOf(IpsoOptimizationResults results) { + listing.add(results.getStatus().getMessage()); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoOutputListingMessageType.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoOutputListingMessageType.java new file mode 100644 index 00000000..cb2df035 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoOutputListingMessageType.java @@ -0,0 +1,65 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.service; +/** + * @author Yannick Pihan + */ +public enum IpsoOutputListingMessageType { + // ON_BOUND_CONSTRAINT + IPSO_OUTPUT_LISTING("IPSO OUTPUT LISTING"), + NODES_ON_BOUND_CONSTRAINT("REGULATED NODES WHERE THE VOLTAGE BOUND CONSTRAINTS ARE NOT VIOLATED"), + Q_ON_BOUND_CONSTRAINT_REMOVED("Q BOUND CONSTRAINTS AND VARIABLE REMOVED, BECAUSE THE Q VALUE IS ON THE BOUNDS"), + VOLTAGE_ON_BOUND_CONSTRAINT_REMOVED("RELATED VOLTAGE BOUND CONSTRAINTS REMOVED"), + TRANSFORMER_ON_BOUND_CONSTRAINT("REGULATED TRANSFORMER WHERE THE TAP VALUE IS ON THE BOUNDS"), + TAP_ON_BOUND_CONSTRAINT_REMOVED("TAP CONSTRAINTS AND VARIABLES REMOVED"), + VOLTAGE_ON_BOUND_CONSTRAINT_TRANSFORMER_REMOVED("RELATED VOLTAGE CONSTRAINTS REMOVED"), + // ... + VIOLATED_LINE_FLOW_CONSTRAINTS_REMOVED_WITH_MIN_MAX("VIOLATED LINE FLOW CONSTRAINTS REMOVED WITH MIN < MAX"), + VIOLATED_TRANSFORMER_FLOW_CONSTRAINTS_REMOVED_WITH_MIN_MAX("VIOLATED TRANSFORMER FLOW CONSTRAINTS REMOVED WITH MIN < MAX"), + TRANSFORMERS_REGULATING_THE_FLOW_SUBJECT_TO_VIOLATED_BOUND_CONSTRAINTS_WITH_MIN_MAX_ARE_REMOVED("TRANSFORMERS REGULATING THE FLOW SUBJECT TO VIOLATED BOUND CONSTRAINTS WITH MIN=MAX ARE REMOVED"), + RELATED_TAP_CONSTRAINTS_ARE_REMOVED("RELATED TAP CONSTRAINTS ARE REMOVED"), + RELATED_TAP_VARIABLE_ARE_REMOVED("RELATED TAP VARIABLE ARE REMOVED"), + VIOLATED_VOLTAGE_BOUND_CONSTRAINTS_REMOVED_WITH_MIN_MAX("VIOLATED VOLTAGE BOUND CONSTRAINTS REMOVED WITH MIN < MAX"), + VIOLATED_VOLTAGE_BOUND_CONSTRAINTS_REMOVED_WITH_MIN_MAX1("VIOLATED VOLTAGE BOUND CONSTRAINTS REMOVED WITH MIN≃MAX"), + CONNECTED_GENERATORS_REGULATING_THE_NODE_VOLTAGE_SUBJECT_TO_VIOLATED_BOUND_CONSTRAINTS_WITH_MIN_MAX("CONNECTED GENERATORS REGULATING THE NODE VOLTAGE SUBJECT TO VIOLATED BOUND CONSTRAINTS WITH MIN=MAX"), + Q_BOUND_CONTRAINTS_AND_VARIABLE_REMOVED("Q BOUND CONTRAINTS AND VARIABLE REMOVED"), + TRANSFORMER_REGULATING_THE_NODE_VOLTAGE_SUBJECT_TO_VIOLATED_BOUND_CONSTRAINTS_WITH_MIN_MAX("TRANSFORMER REGULATING THE NODE VOLTAGE SUBJECT TO VIOLATED BOUND CONSTRAINTS WITH MIN=MAX"), + TRANSFORMER_TAP_BOUND_CONSTRAINTS_AND_VARIABLE_REMOVED("TRANSFORMER TAP BOUND CONSTRAINTS AND VARIABLE REMOVED"), + // ... + INVALID_COMPONENTS("INVALID IPSO COMPONENTS"), + UNSUPPORTED_CORRECTIVE_ACTIONS("UNSUPPORTED CORRECTIVE ACTIONS"), + VIOLATED_CONSTRAINTS("VIOLATED CONSTRAINTS"), + CONTINGENCY_HEADER("CONTINGENCY APPLIED:"), + CONTINGENCY_ARRAY_HEADER("EQUIPMENTS LOST"), + ACTION_PLAN_FOUND("ACTION PLANS FOUND"), + ACTION_FOUND("ACTIONS FOUND"), + NEW_CORRECTIVE_CONTROLVARIABLES("CORRECTIVE CONTROL VARIABLES"), + NEW_CORRECTIVE_CONSTRAINTS("CORRECTIVE CONSTRAINTS"), + NEW_TOPOLOGICAL_ACTIONS("CORRECTIVE TOPOLOGICAL ACTIONS"), + ASSOCIATION_FOUND("ASSOCATION FOUND"), + NO_ASSOCIATION_FOUND("NO ASSOCIATION FOUND"), + OBJ_FUN_VALUE("OBJECTIVE FUNCTION VALUE:"), + SOLUTION_FOUND("SOLUTION FOUND:"), + // AMPL + AMPL_SOLUTION_HEADER("AMPL PROTOTYPE OUTPUT"), + AMPL_SOLUTION_FOUND("AMPL SOLUTION FOUND"), + AMPL_FAILED("AMPL FAILED"), + AMPL_RESULTS("AMPL RESULTS"), + + // Corrective Action result + CORRECTIVE_ACTION_RESULT("RETURNED CODE"); + + private String message; + + IpsoOutputListingMessageType(String message) { + this.message = message; + } + + public String getMessage() { + return this.message; + } + +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoProblemComponentFactory.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoProblemComponentFactory.java new file mode 100644 index 00000000..4119af14 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoProblemComponentFactory.java @@ -0,0 +1,86 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.service; + +import eu.itesla_project.cta.model.*; + +/** + * @author Yannick Pihan + */ +class IpsoProblemComponentFactory { + + public static final float DEFAULT_BRANCH_FLOW_MIN = 0.0f; + + public IpsoControlVariableProductionP createVariableProductionP(IpsoGenerator generator, LinkOption linkOption, float speed, int world) { + return new IpsoControlVariableProductionP(generator, linkOption, speed, world); + + } + + public IpsoControlVariableProductionQ createVariableProductionQ(IpsoGenerator generator, LinkOption linkOption, float speed, int world) { + return new IpsoControlVariableProductionQ(generator, linkOption, speed, world); + + } + + public IpsoControlVariableGeneratorStatism createVariableGeneratorStatism(IpsoGenerator generator, float voltageSetpoint, int world) { + return new IpsoControlVariableGeneratorStatism(generator, voltageSetpoint, world); + + } + + public IpsoControlVariableBankStep createVariableBankStep(IpsoBank bank, float speed, int world) { + return new IpsoControlVariableBankStep(bank, speed, world); + } + + public IpsoControlVariable2WTransformerTap createVariable2WTransformerTap(IpsoTwoWindingsTransformer transformer, LinkOption linkOption, float speed, float epsilon, int world) { + return new IpsoControlVariable2WTransformerTap(transformer, linkOption, speed, epsilon, world); + } + + public IpsoConstraintLineFlowSide1 createConstraintLineFlowSide1(IpsoLine line, FlowUnit unit, float flowMin, float flowMax, int world) { + return new IpsoConstraintLineFlowSide1(line, unit, flowMin, flowMax, world); + } + + public IpsoConstraintLineFlowSide2 createConstraintLineFlowSide2(IpsoLine line, FlowUnit unit, float flowMin, float flowMax, int world) { + return new IpsoConstraintLineFlowSide2(line, unit, flowMin, flowMax, world); + } + + public IpsoConstraint2WTransformerFlow createConstraint2WTransformerFlow(IpsoTwoWindingsTransformer transformer, FlowUnit unit, float flowMin, float flowMax, int world) { + return new IpsoConstraint2WTransformerFlow(transformer, unit, flowMin, flowMax, world); + } + + public IpsoConstraintNodeAcVoltageBounds createConstraintNodeAcVoltageBounds(IpsoNode ipsoNode, VoltageUnit unit, float minVoltage, float maxVoltage, int world) { + return new IpsoConstraintNodeAcVoltageBounds(ipsoNode, unit, minVoltage, maxVoltage, world); + } + + public IpsoConstraintGeneratorPBounds createConstraintProductionPBounds(IpsoGenerator generator, float minActivePower, float maxActivePower, int world) { + return new IpsoConstraintGeneratorPBounds(generator, minActivePower, maxActivePower, world); + } + + public IpsoConstraintGeneratorQBounds createConstraintProductionQBounds(IpsoGenerator generator, float minReactivePower, float maxReactivePower, int world) { + return new IpsoConstraintGeneratorQBounds(generator, minReactivePower, maxReactivePower, world); + + } + + public IpsoConstraintNodeAcAngleBounds createConstraintNodeAcAngleBounds(IpsoNode ipsoNode, float angleMin, float angleMax, int world) { + return new IpsoConstraintNodeAcAngleBounds(ipsoNode, angleMin, angleMax, world); + + } + + public IpsoConstraint2WTransformerTapBounds createConstraint2WTfoTap(IpsoTwoWindingsTransformer transformer, int tapMin, int tapMax, int world) { + return new IpsoConstraint2WTransformerTapBounds(transformer, tapMin, tapMax, world); + } + + public IpsoConstraintBankStepBounds createConstraintBankStepBounds(IpsoBank ipsoBank, int stepMin, int stepMax, int world) { + return new IpsoConstraintBankStepBounds(ipsoBank, stepMin, stepMax, world); + } + + public T createConstraintLineFlow(IpsoLine line, FlowType side1, int world) { + FlowUnit flowUnit = FlowUnit.AMPERE; + if (side1 == FlowType.SIDE1) { + return (T) new IpsoConstraintLineFlowSide1(line, flowUnit, DEFAULT_BRANCH_FLOW_MIN, line.getMaxCurrentPermanentLimit(), world); + } else { + return (T) new IpsoConstraintLineFlowSide2(line, flowUnit, DEFAULT_BRANCH_FLOW_MIN, line.getMaxCurrentPermanentLimit(), world); + } + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoProblemDefinitionBuilder.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoProblemDefinitionBuilder.java new file mode 100644 index 00000000..e59e5a9c --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoProblemDefinitionBuilder.java @@ -0,0 +1,153 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.service; + +import com.google.common.collect.Lists; +import eu.itesla_project.cta.model.*; + +import java.util.List; + +import static eu.itesla_project.cta.model.ValidationType.DELTA_Q_LIMIT_LOWER_THAN_ONE_MVAR; +/** + * @author Yannick Pihan + */ +final class IpsoProblemDefinitionBuilder { + + private final IpsoConstraintFactory ipsoConstraintFactory; + private final IpsoControlVariableFactory ipsoControlVariableFactory; + private final IpsoInvalidIpsoComponentFactory ipsoInvalidComponentFactory; + private final String name; + private final int world; + private final IpsoOptions option; + + private List constraintNodeAcVoltageBoundses; + private List constraintNodeAcAngleBounds; + private List constraintGeneratorPBounds; + private List constraintGeneratorQBounds; + private List constraintLineFlow; + private List constraint2WTransformerTaps; + private List constraint2WTransformerFlows; + private List constraintBankStepBounds; + private List variableGeneratorPs; + private List variableGeneratorQs; + private List variable2WTransformerTaps; + private List variableGeneratorStatisms; + private List variableBankSteps; + private List invalidIpsoComponents; + + /** + * @return a new IpsoProblemDefinitionBuilder + */ + private IpsoProblemDefinitionBuilder(String name, int world, IpsoConstraintFactory ipsoConstraintFactory, IpsoControlVariableFactory ipsoControlVariableFactory, IpsoInvalidIpsoComponentFactory ipsoInvalidComponentFactory, IpsoOptions option) { + this.name = name; + this.world = world; + this.ipsoConstraintFactory = ipsoConstraintFactory; + this.ipsoControlVariableFactory = ipsoControlVariableFactory; + this.ipsoInvalidComponentFactory = ipsoInvalidComponentFactory; + this.invalidIpsoComponents = Lists.newArrayList(); + this.option = option; + } + + public static IpsoProblemDefinitionBuilder create(String name, int world, IpsoOptions option) { + IpsoProblemComponentFactory ipsoProblemComponentFactory = new IpsoProblemComponentFactory(); + return new IpsoProblemDefinitionBuilder( + name, + world, + new IpsoConstraintFactory(ipsoProblemComponentFactory), + new IpsoControlVariableFactory(ipsoProblemComponentFactory), + new IpsoInvalidIpsoComponentFactory(), + option); + } + + public IpsoProblemDefinitionBuilder addVoltageBoundsConstraints(IpsoNetworkState networkState) { + constraintNodeAcVoltageBoundses = ipsoConstraintFactory.createVoltageBoundsConstraints(networkState, option); + return this; + } + + public IpsoProblemDefinitionBuilder addAngleBoundsConstraints(IpsoNetworkState networkState) { + constraintNodeAcAngleBounds = ipsoConstraintFactory.createNodeAcAngleBoundConstraints(networkState); + return this; + } + + public IpsoProblemDefinitionBuilder addActivePowerBoundsConstraints(IpsoNetworkState networkState) { + constraintGeneratorPBounds = ipsoConstraintFactory.createActivePowerBoundsConstraints(networkState); + return this; + } + + public IpsoProblemDefinitionBuilder addReactivePowerBoundsConstraints(IpsoNetworkState networkState) { + constraintGeneratorQBounds = ipsoConstraintFactory.createReactivePowerBoundsConstraints(networkState); + invalidIpsoComponents.addAll(ipsoInvalidComponentFactory.createInvalidComponentsThatHave(DELTA_Q_LIMIT_LOWER_THAN_ONE_MVAR, IpsoConstraintGeneratorQBounds.class, networkState)); + return this; + } + + public IpsoProblemDefinitionBuilder addLineFlowConstraints(IpsoNetworkState networkState) { + constraintLineFlow = ipsoConstraintFactory.createLineFlowConstraints(networkState, option); + return this; + } + + public IpsoProblemDefinitionBuilder addTwoWindingTransformerTapBoundsConstraints(IpsoNetworkState networkState) { + constraint2WTransformerTaps = ipsoConstraintFactory.createTwoWindingTransformerTapBoundsConstraints(networkState, option); + return this; + } + + public IpsoProblemDefinitionBuilder addTwoWindingTransformerFowConstraints(IpsoNetworkState networkState) { + constraint2WTransformerFlows = ipsoConstraintFactory.createTwoWindingTransformerFlowConstraints(networkState, option); + return this; + } + + public IpsoProblemDefinitionBuilder addBankStepBoundsConstraints(IpsoNetworkState networkState) { + constraintBankStepBounds = ipsoConstraintFactory.createBankStepBoundsConstraints(networkState); + return this; + } + + public IpsoProblemDefinitionBuilder addTwoWindingTransformerTapVariables(IpsoNetworkState networkState) { + variable2WTransformerTaps = ipsoControlVariableFactory.createTwoWindingTransformerTapVariables(networkState, option); + return this; + } + + public IpsoProblemDefinitionBuilder addActiveProductionVariables(IpsoNetworkState networkState) { + variableGeneratorPs = ipsoControlVariableFactory.createActiveProductionVariables(networkState); + return this; + } + + public IpsoProblemDefinitionBuilder addReactiveProductionVariables(IpsoNetworkState networkState) { + variableGeneratorQs = ipsoControlVariableFactory.createReactiveProductionVariables(networkState); + invalidIpsoComponents.addAll(ipsoInvalidComponentFactory.createInvalidComponentsThatHave(DELTA_Q_LIMIT_LOWER_THAN_ONE_MVAR, IpsoControlVariableProductionQ.class, networkState)); + return this; + } + + public IpsoProblemDefinitionBuilder addStatismGeneratorVariables(IpsoNetworkState networkState) { + variableGeneratorStatisms = ipsoControlVariableFactory.createGeneratorStatismVariables(networkState); + return this; + } + + public IpsoProblemDefinitionBuilder addBankStepVariables(IpsoNetworkState networkState) { + variableBankSteps = ipsoControlVariableFactory.createBankStepVariables(networkState); + return this; + } + + public IpsoProblemDefinition createIpsoProblemDefinition() { + return new IpsoProblemDefinition( + this.name, + this.world, + variableGeneratorPs, + variableGeneratorQs, + variableGeneratorStatisms, + variableBankSteps, + variable2WTransformerTaps, + constraintLineFlow, + constraint2WTransformerFlows, + constraintNodeAcVoltageBoundses, + constraintNodeAcAngleBounds, + constraintGeneratorPBounds, + constraintGeneratorQBounds, + constraint2WTransformerTaps, + constraintBankStepBounds, + invalidIpsoComponents); + } + +} + diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoProblemDefinitionFactory.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoProblemDefinitionFactory.java new file mode 100644 index 00000000..0c399eb1 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoProblemDefinitionFactory.java @@ -0,0 +1,30 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.service; + +import eu.itesla_project.cta.model.IpsoNetworkState; +import eu.itesla_project.cta.model.IpsoProblemDefinition; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * @author Yannick Pihan + */ +final class IpsoProblemDefinitionFactory extends AbstractIpsoProblemDefinitionFactory { + + private transient final IpsoProblemComponentFactory ipsoProblemComponentFactory; + + IpsoProblemDefinitionFactory() { + ipsoProblemComponentFactory = new IpsoProblemComponentFactory(); + } + + @Override + public IpsoProblemDefinition createProblemDefinitionFor(IpsoNetworkState ipsoNetworkState, IpsoOptions options) { + checkArgument(ipsoNetworkState != null, "configuration must not be null"); + checkArgument(options != null, "options must not be null"); + return createOperationalProblemDefinitionFor(ipsoNetworkState, options); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoProblemDefinitionService.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoProblemDefinitionService.java new file mode 100644 index 00000000..81fdf270 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoProblemDefinitionService.java @@ -0,0 +1,34 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.service; + +import eu.itesla_project.cta.model.IpsoConstraint; +import eu.itesla_project.cta.model.IpsoProblemDefinition; +import org.slf4j.Logger; + +import java.util.List; + +import static org.slf4j.LoggerFactory.getLogger; +/** + * @author Yannick Pihan + */ + class IpsoProblemDefinitionService { + + private static final Logger LOG = getLogger(IpsoProblemDefinitionService.class); + + public IpsoProblemDefinitionService() { + } + + /** + * @return violated constraints defined within a problem definition + */ + public List findViolatedConstraintsIn(IpsoProblemDefinition problemDefinition) { + IpsoConstraintFinder ipsoConstraintFinder = new IpsoConstraintFinder(); + return ipsoConstraintFinder.findAllViolatedConstraintsIn(problemDefinition); + } +} + + diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoSolution.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoSolution.java new file mode 100644 index 00000000..b350eb8b --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoSolution.java @@ -0,0 +1,32 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.service; + +import java.util.List; + +import static com.google.common.base.Preconditions.checkArgument; +/** + * @author Yannick Pihan + */ +public class IpsoSolution { + + private final List solutionElements; + private final float objectiveFunctionValue; + + public IpsoSolution(List solutionElements, float objectiveFunctionValue) { + checkArgument(solutionElements != null, "solutionElements must not be null"); + this.solutionElements = solutionElements; + this.objectiveFunctionValue = objectiveFunctionValue; + } + + public List getSolutionElements() { + return solutionElements; + } + + public float getObjectiveFunctionValue() { + return objectiveFunctionValue; + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoSolutionElement.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoSolutionElement.java new file mode 100644 index 00000000..024d03e0 --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/IpsoSolutionElement.java @@ -0,0 +1,28 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.service; +/** + * @author Yannick Pihan + */ +public class IpsoSolutionElement { + + private final IpsoEquipmentType equipmentType; + private final String name; + private final String attribute; + private final float value; + + public IpsoSolutionElement(IpsoEquipmentType equipmentType, String name, String attribute, float value) { + this.equipmentType = equipmentType; + this.name = name; + this.attribute = attribute; + this.value = value; + } + + @Override + public String toString() { + return String.format("TYPE:%s NAME:%s, ATTRIBUTE:%s VALUE:%s", equipmentType.toString(), name, attribute, value); + } +} diff --git a/cta-optimizer/src/main/java/eu/itesla_project/cta/service/OptimizerExecutionService.java b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/OptimizerExecutionService.java new file mode 100644 index 00000000..810d9f8c --- /dev/null +++ b/cta-optimizer/src/main/java/eu/itesla_project/cta/service/OptimizerExecutionService.java @@ -0,0 +1,221 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.service; + +import eu.itesla_project.computation.*; +import eu.itesla_project.cta.converter.MappingBetweenIidmIdAndIpsoEquipment; +import eu.itesla_project.cta.io.AmplModelWriter; +import eu.itesla_project.cta.model.AmplModel; +import eu.itesla_project.cta.model.TopologicalAction; +import eu.itesla_project.iidm.datasource.FileDataSource; +import eu.itesla_project.iidm.export.Exporter; +import eu.itesla_project.iidm.export.Exporters; +import eu.itesla_project.iidm.network.util.Networks; +import eu.itesla_project.modules.contingencies.ActionParameters; +import eu.itesla_project.modules.optimizer.CorrectiveControlOptimizerResult; +import eu.itesla_project.modules.optimizer.PostContingencyState; +import org.apache.commons.io.FileUtils; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; +import java.util.Map.Entry; + +import static com.google.common.base.Preconditions.checkArgument; +import static eu.itesla_project.cta.service.AmplConstants.*; +import static eu.itesla_project.modules.optimizer.CCOFinalStatus.*; +import static java.util.stream.Collectors.toList; +/** + * @author Yannick Pihan + */ +public class OptimizerExecutionService { + + /** + * Start a optimization on the given ampl model + * + * @param postContingencyState : network to optimize + * @param amplModel : model corresponding to the network + * @param configuration : configuration to use during the optimization + * @param computationManager : manage the process execution + * @param outputListing + * @return : a list of action to apply to optimize the network + * @throws Exception + */ + public AmplExecutionResults runAmpl(PostContingencyState postContingencyState, AmplModel amplModel, IpsoOptimizerConfiguration configuration, ComputationManager computationManager, IpsoOutputListing outputListing) throws Exception { + checkArgument(configuration != null, "configuration cannot be null"); + checkArgument(configuration.getAmplPath() != null && Files.exists(configuration.getAmplPath()), "'ampl.path' property is not correctly defined"); + + try (CommandExecutor executor = computationManager.newCommandExecutor(createEnvironmentVariablesFrom(configuration), + configuration.getAmplWorkingDirPrefix(), + configuration.isDebug())) { + + if (configuration.isDebug()) { + // dump state info for debugging + Networks.dumpStateId(executor.getWorkingDir(), postContingencyState.getNetwork()); + + Exporter exporter = Exporters.getExporter("XML"); + if (exporter != null) { + Properties parameters = new Properties(); + parameters.setProperty("iidm.export.xml.indent", "true"); + parameters.setProperty("iidm.export.xml.with-branch-state-variables", "true"); + parameters.setProperty("iidm.export.xml.with-breakers", "true"); + parameters.setProperty("iidm.export.xml.with-properties", "true"); + try { + exporter.export(postContingencyState.getNetwork(), parameters, new FileDataSource(executor.getWorkingDir(), "network")); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + final Path datPath = executor.getWorkingDir().resolve(AmplConstants.DAT_FILE_NAME); + AmplModelWriter datWriter = new AmplModelWriter(); + datWriter.write(amplModel, datPath.toString(), configuration.getSolverRessourcePath().toString()); + generateAmplInputFile(executor.getWorkingDir(), configuration); + + Command amplCommand = generateAmplCommand(configuration.getAmplPath()); + + ExecutionReport report = executor.start(new CommandExecution( + amplCommand, + 1, + configuration.getPriority(), + Networks.getExecutionTags(postContingencyState.getNetwork()))); + + Path outputFile = executor.getWorkingDir().resolve(AmplConstants.XML_FILE_NAME); + return AmplOptimizationResultService.createAmplResultFrom(outputFile, report, outputListing); + + } + catch (Exception e ) { + e.printStackTrace(); + outputListing.addAmplError(e); + return new AmplExecutionResults(AmplStatus.EXECUTION_ERROR); + } + } + + /** + * Copy all the files required by Ampl to the right directory + * @param workingDir : directory use during the Ampl run + * @param configuration + * @throws IOException : Can't write the files + */ + + void generateAmplInputFile(Path workingDir, IpsoOptimizerConfiguration configuration) throws IOException { + + Path runFile = configuration.getSolverRessourcePath().resolve(RUN_FILE_NAME); + Path tabFile = configuration.getSolverRessourcePath().resolve(TAB_FILE_NAME); + Path modelsDirectory = configuration.getSolverRessourcePath().resolve(MODELS_DIR); + + Files.copy(runFile, workingDir.resolve(RUN_FILE_NAME)); + Files.copy(tabFile, workingDir.resolve(TAB_FILE_NAME)); + FileUtils.copyDirectory(new File(modelsDirectory.toString()), + new File(workingDir.resolve(MODELS_DIR).toString())); + } + + private Command generateAmplCommand(Path amplPath) { + return new SimpleCommandBuilder() + .id("ampl") + .program(amplPath.resolve(AmplConstants.APPLICATION_NAME).toString()) + // DO NOT WORK ALTHOUGH THE VARIABLE $PATH CONTAINS WELL THE APPLICATION PATH + //.program(IpsoConstants.APPLICATION_NAME) + .args(RUN_FILE_NAME) + .timeout(60) + .inputFiles() + .outputFiles() + .build(); + } + + /** + * Generate a map containing the LD_LIBRARY_PATH and PATH + * environment variable + * + * @return a Map with the variable as the key to the corresponding value + */ + private Map createEnvironmentVariablesFrom(IpsoOptimizerConfiguration configuration) { + Map env = new HashMap<>(); + + env.put("LD_LIBRARY_PATH", configuration.getSolverPath().toString() + + ":" + configuration.getIpsoPath().toString() + + ":" + configuration.getSolverPath().resolve("lib").toString()); + + env.put("PATH", configuration.getIpsoPath().toString() + + ":" + configuration.getSolverPath().resolve("bin").toString()); + + env.put("XPRESS", configuration.getSolverPath().toString()); + return env; + } + + + public CorrectiveControlOptimizerResult createCorrectiveControlOptimizerResult(AmplExecutionResults amplResults, + String contingencyId, + MappingBetweenIidmIdAndIpsoEquipment dictionary, + CorrectiveActions clientCorrectiveActions) { + + if (isSuccessFor(amplResults)) { + CorrectiveControlOptimizerResult optimizerResult; + // get all the actions + List topologicalActions = amplResults.getActionElements().entrySet().stream() + .map(action -> findCorrespondingTopologicalAction(action, clientCorrectiveActions)) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(toList()); + + // check if topological actions have been found + if(topologicalActions.isEmpty()) { + optimizerResult = new CorrectiveControlOptimizerResult(contingencyId, false); + optimizerResult.setFinalStatus(AUTOMATIC_CORRECTIVE_ACTION_FOUND); + } + else { + optimizerResult = new CorrectiveControlOptimizerResult(contingencyId, true); + topologicalActions.stream() + .forEach(action -> optimizerResult.addEquipment( + action.getElementaryActionId(), + dictionary.getIidmIdFor(action.getEquipmentId()), + amplResults.getActionElements().get(action.getEquipmentId().trim()))); + optimizerResult.setFinalStatus(MANUAL_CORRECTIVE_ACTION_FOUND); + + } + optimizerResult.setActionPlan(clientCorrectiveActions.getActionPlanId()); + return optimizerResult; + + } else { + CorrectiveControlOptimizerResult controlOptimizerResult = new CorrectiveControlOptimizerResult(contingencyId, false); + if(amplResults == null) { + controlOptimizerResult.setFinalStatus(NO_SUPPORTED_CORRECTIVE_ACTION_AVAILABLE_IN_THE_DATABASE); + } + else { + switch (amplResults.getStatus()) { + case UNFEASIBLE: + controlOptimizerResult.setFinalStatus(NO_CORRECTIVE_ACTION_FOUND); + break; + case ERROR: + controlOptimizerResult.setFinalStatus(OPTIMIZER_INTERNAL_ERROR); + break; + case EXECUTION_ERROR: + controlOptimizerResult.setFinalStatus(OPTIMIZER_EXECUTION_ERROR); + break; + } + } + return controlOptimizerResult; + } + } + + private boolean isSuccessFor(AmplExecutionResults amplResults) { + return isNotNullOrEmpty(amplResults) && amplResults.getStatus() == AmplStatus.SUCCEEDED; + } + + Optional findCorrespondingTopologicalAction(Entry correction, CorrectiveActions correctiveActions) { + return correctiveActions.getTopologicalActions().stream() + .filter(topologicalAction -> topologicalAction.getEquipmentId().trim().equals(correction.getKey())) + .filter(topologicalAction -> topologicalAction.isEquivalentTo(correction.getValue())) + .findFirst(); + } + + private boolean isNotNullOrEmpty(AmplExecutionResults results) { + return results != null && !results.getActionElements().isEmpty(); + } +} diff --git a/cta-optimizer/src/main/resources/META-INF/services/eu.itesla_project.cta.io.IpsoWriter b/cta-optimizer/src/main/resources/META-INF/services/eu.itesla_project.cta.io.IpsoWriter new file mode 100644 index 00000000..1c7cd1c1 --- /dev/null +++ b/cta-optimizer/src/main/resources/META-INF/services/eu.itesla_project.cta.io.IpsoWriter @@ -0,0 +1 @@ +eu.itesla_project.cta.io.IpsoCsvWriter \ No newline at end of file diff --git a/cta-optimizer/src/main/resources/logback.xml b/cta-optimizer/src/main/resources/logback.xml new file mode 100644 index 00000000..13442897 --- /dev/null +++ b/cta-optimizer/src/main/resources/logback.xml @@ -0,0 +1,12 @@ + + + + + %d{yyyy-MM-dd_HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + diff --git a/cta-optimizer/src/test/java/eu/itesla_project/cta/converter/AbstractNodeModelConverterImplTest.java b/cta-optimizer/src/test/java/eu/itesla_project/cta/converter/AbstractNodeModelConverterImplTest.java new file mode 100644 index 00000000..34602c1d --- /dev/null +++ b/cta-optimizer/src/test/java/eu/itesla_project/cta/converter/AbstractNodeModelConverterImplTest.java @@ -0,0 +1,80 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.converter; + +import eu.itesla_project.iidm.network.Bus; +import eu.itesla_project.iidm.network.VoltageLevel; +import org.hamcrest.CoreMatchers; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +import static java.lang.Float.NaN; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; +/** + * @author Yannick Pihan + */ +public class AbstractNodeModelConverterImplTest { + + protected static final float FLOAT_VALUE = 3.3f; + protected static final float BASE_VOLTAGE_LEVEL = 2f; + private NodeModelConverter nodeModelConverter; + private Bus bus; + private VoltageLevel voltageLevel; + + @Before + public void setup() { + ConversionContext conversionContext = new ConversionContext("test"); + nodeModelConverter = new NodeModelConverter(conversionContext); + voltageLevel = Mockito.mock(VoltageLevel.class); + bus = Mockito.mock(Bus.class); + } + + @Test + public void findBaseVoltageHappyPath() { + Mockito.when(voltageLevel.getNominalV()).thenReturn(FLOAT_VALUE); + Mockito.when(bus.getVoltageLevel()).thenReturn(voltageLevel); + float baseVoltage = nodeModelConverter.findBaseVoltage(bus); + + assertThat(baseVoltage, is(FLOAT_VALUE)); + } + + @Test + public void findBaseVoltageReturnsNaNHappyPath() { + Mockito.when(bus.getVoltageLevel()).thenReturn(null); + float baseVoltage = nodeModelConverter.findBaseVoltage(bus); + + assertThat(baseVoltage, is(NaN)); + } + + @Test + public void findLowVoltageLevelHappyPath() { + Mockito.when(voltageLevel.getLowVoltageLimit()).thenReturn(FLOAT_VALUE); + Mockito.when(bus.getVoltageLevel()).thenReturn(voltageLevel); + float lowVoltageLevel = nodeModelConverter.findLowVoltageLevel(bus, BASE_VOLTAGE_LEVEL); + + assertThat(lowVoltageLevel, is(FLOAT_VALUE/BASE_VOLTAGE_LEVEL)); + } + + @Test + public void findLowVoltageLevelReturnsDefaultLowLimit() { + Mockito.when(voltageLevel.getLowVoltageLimit()).thenReturn(NaN); + float lowVoltageLevel = nodeModelConverter.findLowVoltageLevel(bus, BASE_VOLTAGE_LEVEL); + + assertThat(lowVoltageLevel, CoreMatchers.is(AbstractNodeModelConverter.DEFAULT_LOW_VOLTAGE_LEVEL)); + } + + @Test + public void findHighVoltageLevelReturnsDefaultHighLimit() { + Mockito.when(voltageLevel.getHighVoltageLimit()).thenReturn(FLOAT_VALUE); + Mockito.when(bus.getVoltageLevel()).thenReturn(voltageLevel); + float highVoltageLevel = nodeModelConverter.findHighVoltageLevel(bus, NaN); + + assertThat(highVoltageLevel, CoreMatchers.is(AbstractNodeModelConverter.DEFAULT_HIGH_VOLTAGE_LEVEL)); + } + +} diff --git a/cta-optimizer/src/test/java/eu/itesla_project/cta/converter/LineModelConverterImplTest.java b/cta-optimizer/src/test/java/eu/itesla_project/cta/converter/LineModelConverterImplTest.java new file mode 100644 index 00000000..f60d87c1 --- /dev/null +++ b/cta-optimizer/src/test/java/eu/itesla_project/cta/converter/LineModelConverterImplTest.java @@ -0,0 +1,72 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.converter; + +import eu.itesla_project.cta.model.IpsoEquipment; +import eu.itesla_project.cta.model.IpsoLine; +import eu.itesla_project.cta.model.IpsoNode; +import eu.itesla_project.cta.model.IpsoNodeType; +import eu.itesla_project.iidm.network.Line; +import eu.itesla_project.iidm.network.Network; +import org.apache.commons.lang3.StringUtils; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +/** + * @author Yannick Pihan + */ +public class LineModelConverterImplTest { + + private ConversionContext context; + private static final int TOTAL_LENGTH = 20; + + @Before + public void setup() { + context = new ConversionContext("caseName"); + MappingBetweenIidmIdAndIpsoEquipment dictionary = context.getMappingBetweenIidmIdAndIpsoEquipment(); + dictionary.add("iidm0", creatIpsoLineWithTheId("node1-node2-0")); + dictionary.add("iidm1", creatIpsoLineWithTheId("node1-node2-1")); + dictionary.add("iidm2", creatIpsoLineWithTheId("node1-node2-2")); + dictionary.add("iidm3", creatIpsoLineWithTheId("node1-node2-3")); + dictionary.add("iidm4", creatIpsoLineWithTheId("node1-node2-4")); + dictionary.add("iidm5", creatIpsoLineWithTheId("node1-node2-5")); + dictionary.add("iidm6", creatIpsoLineWithTheId("node1-node2-6")); + dictionary.add("iidm7", creatIpsoLineWithTheId("node1-node2-7")); + dictionary.add("iidm8", creatIpsoLineWithTheId("node1-node2-8")); + dictionary.add("iidm9", creatIpsoLineWithTheId("node1-node2-9")); + } + + private IpsoEquipment creatIpsoLineWithTheId(String id) { + return new IpsoLine(StringUtils.rightPad(id, TOTAL_LENGTH), "iidm id", createIpsoNode("node1"), createIpsoNode("node2"), true, true, 0f,0f, 0f, 0f, 0f, 0f, 0f, 0); + } + + private IpsoNode createIpsoNode(String node1) { + return new IpsoNode(node1, "iidm id", "", "", 0,0,0, IpsoNodeType.PQ,0,0,0,0,0); + } + + @Test + public void createIpsoNameReturnsLineWithUniqueName() { + + LineModelConverter converter = new LineModelConverter(context) { + @Override + public Iterable gatherDataToConvertFrom(Network network) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + protected ComponentType getComponentType() { + throw new UnsupportedOperationException("Not supported yet."); + }; + }; + + Assert.assertEquals(converter.createIdFrom("node1", "node2"), "node1-node2-a "); + context.getMappingBetweenIidmIdAndIpsoEquipment().add("iid10", creatIpsoLineWithTheId("node1-node2-a")); + Assert.assertEquals(converter.createIdFrom("node1", "node2"), "node1-node2-b "); + Assert.assertEquals(converter.createIdFrom("node1", "node3"), "node1-node3-1 "); + context.getMappingBetweenIidmIdAndIpsoEquipment().add("iid11", creatIpsoLineWithTheId("node1-node3-1")); + Assert.assertEquals(converter.createIdFrom("node1", "node3"), "node1-node3-2 "); + } +} diff --git a/cta-optimizer/src/test/java/eu/itesla_project/cta/model/IpsoProblemDefinitionImplTest.java b/cta-optimizer/src/test/java/eu/itesla_project/cta/model/IpsoProblemDefinitionImplTest.java new file mode 100644 index 00000000..e4c53fb7 --- /dev/null +++ b/cta-optimizer/src/test/java/eu/itesla_project/cta/model/IpsoProblemDefinitionImplTest.java @@ -0,0 +1,72 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.model; + +import com.google.common.collect.Lists; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +import java.util.List; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; +/** + * @author Yannick Pihan + */ +public class IpsoProblemDefinitionImplTest { + + private IpsoProblemDefinition ipsoProblemDefinition; + + @Before + public void setup() { + + ipsoProblemDefinition = new IpsoProblemDefinition( + "test", 0, + Lists.newArrayList(), + Lists.newArrayList(), + Lists.newArrayList(), + Lists.newArrayList(), + Lists.newArrayList(), + Lists.newArrayList(), + Lists.newArrayList(), + Lists.newArrayList(), + Lists.newArrayList(), + Lists.newArrayList(), + Lists.newArrayList(), + Lists.newArrayList(), + Lists.newArrayList(), + Lists.newArrayList()); + } + + @Test + public void findSubTypeOfHappyPath() { + + IpsoGenerator generator = Mockito.mock(IpsoGenerator.class); + IpsoTwoWindingsTransformer transformer = Mockito.mock(IpsoTwoWindingsTransformer.class); + + IpsoConstraintGeneratorQBounds constraintGeneratorQBounds1 = new IpsoConstraintGeneratorQBounds(generator, 0, 10, 0); + IpsoConstraintGeneratorQBounds constraintGeneratorQBounds2 = new IpsoConstraintGeneratorQBounds(generator, 0, 11, 0); + IpsoConstraintGeneratorPBounds constraintGeneratorPBounds1 = new IpsoConstraintGeneratorPBounds(generator, 0, 12, 0); + IpsoConstraintGeneratorPBounds constraintGeneratorPBounds2 = new IpsoConstraintGeneratorPBounds(generator, 0, 13, 0); + IpsoConstraint2WTransformerTapBounds constraint2WTransformerTapBounds1 = new IpsoConstraint2WTransformerTapBounds(transformer, 0,13,0); + IpsoConstraint2WTransformerTapBounds constraint2WTransformerTapBounds2 = new IpsoConstraint2WTransformerTapBounds(transformer, 0,13,0); + IpsoConstraint2WTransformerTapBounds constraint2WTransformerTapBounds3 = new IpsoConstraint2WTransformerTapBounds(transformer, 0,13,0); + + List constraints = Lists.newArrayList( + constraintGeneratorQBounds1, + constraintGeneratorQBounds2, + constraintGeneratorPBounds1, + constraintGeneratorPBounds2, + constraint2WTransformerTapBounds1, + constraint2WTransformerTapBounds2, + constraint2WTransformerTapBounds3); + + List expectedConstraints = ipsoProblemDefinition.findSubTypeOf(IpsoConstraint2WTransformerTapBounds.class, constraints); + assertThat(expectedConstraints.size(), is(3)); + } + +} diff --git a/cta-optimizer/src/test/java/eu/itesla_project/cta/service/TestServiceUtility.java b/cta-optimizer/src/test/java/eu/itesla_project/cta/service/TestServiceUtility.java new file mode 100644 index 00000000..caac2618 --- /dev/null +++ b/cta-optimizer/src/test/java/eu/itesla_project/cta/service/TestServiceUtility.java @@ -0,0 +1,42 @@ +/** Copyright (c) 2016, Tractebel (http://www.tractebel-engie.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + **/ +package eu.itesla_project.cta.service; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Properties; +/** + * @author Yannick Pihan + */ +public class TestServiceUtility { + + private static TestServiceUtility singleton = null; + + public static TestServiceUtility getInstance() { + if (singleton == null) { + singleton = new TestServiceUtility(); + } + return singleton; + } + + private TestServiceUtility() {} + + public Path createDirectoryInTempWithNameOf(String name) throws IOException { + Path wdir = Paths.get(System.getProperty("java.io.tmpdir"), name); + Files.createDirectories(wdir); + return wdir; + } + + public Properties loadConfigurationFor(String filename) throws IOException { + String configurationFilename = filename + ".properties"; + Path configurationFile = Paths.get(this.getClass().getResource(configurationFilename).getPath()); + Properties configuration = new Properties(); + configuration.load(Files.newInputStream(configurationFile)); + return configuration; + } +} diff --git a/cta-optimizer/src/test/resources/eu/itesla_project/cta/service/CorrectiveControlIpsoOptimizerITest.properties b/cta-optimizer/src/test/resources/eu/itesla_project/cta/service/CorrectiveControlIpsoOptimizerITest.properties new file mode 100644 index 00000000..2a28f2d3 --- /dev/null +++ b/cta-optimizer/src/test/resources/eu/itesla_project/cta/service/CorrectiveControlIpsoOptimizerITest.properties @@ -0,0 +1,10 @@ +ipso.path=${ipso.path} +solver.path=${solver.path} +ampl.path=${ampl.path} +solverResources.path=${solverResources.path} +contingencies.path=${contingencies.path} +network.folder=${network.folder} +network.prefix=${network.prefix} +network.path=${network.path} +network.config=${network.config} + diff --git a/cta-optimizer/src/test/resources/eu/itesla_project/cta/service/UctCorrectiveControlIpsoOptimizerITest.properties b/cta-optimizer/src/test/resources/eu/itesla_project/cta/service/UctCorrectiveControlIpsoOptimizerITest.properties new file mode 100644 index 00000000..d3614ffc --- /dev/null +++ b/cta-optimizer/src/test/resources/eu/itesla_project/cta/service/UctCorrectiveControlIpsoOptimizerITest.properties @@ -0,0 +1,7 @@ +ipso.path=${ipso.path} +solver.path=${solver.path} +ampl.path=${ampl.path} +solverResources.path=${solverResources.path} +network.path=${user.home}/Documents/eu_network +network.config=/home/yannickpihan/Documents/Border_FR-BE.xml + diff --git a/cta-optimizer/src/test/resources/eu/itesla_project/cta/service/XMLCorrectiveControlIpsoOptimizerITest.properties b/cta-optimizer/src/test/resources/eu/itesla_project/cta/service/XMLCorrectiveControlIpsoOptimizerITest.properties new file mode 100644 index 00000000..b8af044f --- /dev/null +++ b/cta-optimizer/src/test/resources/eu/itesla_project/cta/service/XMLCorrectiveControlIpsoOptimizerITest.properties @@ -0,0 +1,7 @@ +ipso.path=${ipso.path} +solver.path=${solver.path} +ampl.path=${ampl.path} +solverResources.path=${user.home}/Documents/solverResources_anon +network.path=${user.home}/Documents/sampled_state/post/ +network.config=/home/yannickpihan/Documents/action-ctg_France_V0.4.xml + diff --git a/cta-optimizer/src/test/resources/logback-test.xml b/cta-optimizer/src/test/resources/logback-test.xml new file mode 100644 index 00000000..ca98c07e --- /dev/null +++ b/cta-optimizer/src/test/resources/logback-test.xml @@ -0,0 +1,18 @@ + + + + + + %d{yyyy-MM-dd_HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 7d802fb7..c71f286b 100644 --- a/pom.xml +++ b/pom.xml @@ -65,6 +65,7 @@ distribution case-repository network-merge + cta-optimizer