Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add a new identifier with wildcards support #2965

Merged
merged 10 commits into from
May 14, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,17 @@ public List<NetworkElementIdentifier> getIdentifiants() {
@Override
public List<Contingency> getContingencies(Network network) {
return networkElementIdentifiers.stream()
.filter(identifier -> !identifier.filterIdentifiable(network).isEmpty())
.map(identifier -> {
List<ContingencyElement> contingencyElements = identifier.filterIdentifiable(network)
.stream()
.map(ContingencyElement::of)
.collect(Collectors.toList());
String contingencyId = identifier.getContingencyId().orElse(getGeneratedContingencyId(contingencyElements));
return new Contingency(contingencyId, contingencyElements);
})
.filter(contingency -> contingency.isValid(network))
.collect(Collectors.toList());
.filter(identifier -> !identifier.filterIdentifiable(network).isEmpty())
.map(identifier -> {
List<ContingencyElement> contingencyElements = identifier.filterIdentifiable(network)
.stream()
.map(ContingencyElement::of)
.toList();
String contingencyId = identifier.getContingencyId().orElse(getGeneratedContingencyId(contingencyElements));
return new Contingency(contingencyId, contingencyElements);
})
.filter(contingency -> contingency.isValid(network))
.collect(Collectors.toList());
}

public Map<String, Set<String>> getNotFoundElements(Network network) {
Expand All @@ -71,8 +71,8 @@ public Map<String, Set<String>> getNotFoundElements(Network network) {
Set<String> notFoundElements = identifier.getNotFoundElements(network);
if (!notFoundElements.isEmpty()) {
String contingencyId = identifier.getContingencyId().orElse(getGeneratedContingencyId(identifier.filterIdentifiable(network)
.stream()
.map(ContingencyElement::of).toList()));
.stream()
.map(ContingencyElement::of).toList()));
notFoundElementsMap.put(contingencyId, notFoundElements);
}

Expand All @@ -82,8 +82,8 @@ public Map<String, Set<String>> getNotFoundElements(Network network) {

private String getGeneratedContingencyId(List<ContingencyElement> contingencyElements) {
return "Contingency : " + contingencyElements
.stream()
.map(ContingencyElement::getId)
.collect(Collectors.joining(" + "));
.stream()
.map(ContingencyElement::getId)
.collect(Collectors.joining(" + "));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,19 @@
*/
package com.powsybl.contingency;

import com.powsybl.commons.PowsyblException;
import com.powsybl.contingency.contingency.list.IdentifierContingencyList;
import com.powsybl.iidm.network.Identifiable;
import com.powsybl.iidm.network.identifiers.*;
import com.powsybl.iidm.network.Network;
import com.powsybl.iidm.network.test.EurostagTutorialExample1Factory;
import com.powsybl.iidm.network.test.FourSubstationsNodeBreakerFactory;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import java.util.*;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.*;

/**
* @author Etienne Lesot {@literal <etienne.lesot@rte-france.com>}
Expand Down Expand Up @@ -183,4 +186,40 @@ void testIdentifierListOfDefaultIds() {
Map<String, Set<String>> notFoundElements = contingencyList.getNotFoundElements(network);
assertEquals(0, notFoundElements.size());
}

@Test
void testUnknownCharacterIdentifierWithList() {
Network network = EurostagTutorialExample1Factory.create();
List<NetworkElementIdentifier> networkElementIdentifierListElements = new ArrayList<>();
NetworkElementIdentifier elementIdentifier = new IdWithWildcardsNetworkElementIdentifier("NHV1_NHV2_?");
networkElementIdentifierListElements.add(elementIdentifier);
IdentifierContingencyList contingencyList = new IdentifierContingencyList("list", networkElementIdentifierListElements);
List<Contingency> contingencies = contingencyList.getContingencies(network);
assertEquals(1, contingencies.size());
List<String> elementIds = contingencies.get(0).getElements().stream().map(ContingencyElement::getId).toList();
assertTrue(elementIds.containsAll(Arrays.asList("NHV1_NHV2_1", "NHV1_NHV2_2")));
}

@Test
void testUnknownCharacterIdentifier() {
EtienneLt marked this conversation as resolved.
Show resolved Hide resolved
String message = Assertions.assertThrows(PowsyblException.class, () -> new IdWithWildcardsNetworkElementIdentifier("NHV1_NHV2_?_?_?_?_?_?_?")).getMessage();
Assertions.assertEquals("There can be a maximum of 5 wildcards ('?')", message);
String message2 = Assertions.assertThrows(PowsyblException.class, () -> new IdWithWildcardsNetworkElementIdentifier("NHV1_NHV2_ç")).getMessage();
Assertions.assertEquals("Only characters allowed for this identifier are letters, numbers, '_', '-', '.' and the wildcard character '?'", message2);
NetworkElementIdentifier elementIdentifier = new IdWithWildcardsNetworkElementIdentifier("NHV1_NHV?_?");
Network network = EurostagTutorialExample1Factory.create();
List<String> identifiables = elementIdentifier.filterIdentifiable(network).stream().map(Identifiable::getId).toList();
Assertions.assertEquals(2, identifiables.size());
assertTrue(identifiables.containsAll(Arrays.asList("NHV1_NHV2_1", "NHV1_NHV2_2")));
EtienneLt marked this conversation as resolved.
Show resolved Hide resolved

network.newSubstation().setId("NHV1.NHV2-1").add();
network.newSubstation().setId("NHV10NHV2-1").add();
elementIdentifier = new IdWithWildcardsNetworkElementIdentifier("NHV1.NHV?-?");
EtienneLt marked this conversation as resolved.
Show resolved Hide resolved
identifiables = elementIdentifier.filterIdentifiable(network).stream().map(Identifiable::getId).toList();
Assertions.assertEquals(1, identifiables.size());
assertTrue(identifiables.contains("NHV1.NHV2-1"));

String message3 = assertThrows(PowsyblException.class, () -> new IdWithWildcardsNetworkElementIdentifier("TEST_WITH_NO_WILDCARDS")).getMessage();
assertEquals("There is no wildcard in your identifier, please use IdBasedNetworkElementIdentifier instead", message3);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,7 @@
import com.powsybl.commons.test.ComparisonUtils;
import com.powsybl.contingency.contingency.list.ContingencyList;
import com.powsybl.contingency.contingency.list.IdentifierContingencyList;
import com.powsybl.iidm.network.identifiers.NetworkElementIdentifier;
import com.powsybl.iidm.network.identifiers.NetworkElementIdentifierContingencyList;
import com.powsybl.iidm.network.identifiers.IdBasedNetworkElementIdentifier;
import com.powsybl.iidm.network.identifiers.VoltageLevelAndOrderNetworkElementIdentifier;
import com.powsybl.iidm.network.identifiers.*;
import org.junit.jupiter.api.Test;

import java.io.*;
Expand All @@ -44,6 +41,7 @@ private static IdentifierContingencyList create() {
"vl2", '1', "contingencyId2"));
networkElementIdentifiers.add(new NetworkElementIdentifierContingencyList(Collections.singletonList(new
IdBasedNetworkElementIdentifier("identifier")), "contingencyId3"));
networkElementIdentifiers.add(new IdWithWildcardsNetworkElementIdentifier("identifier?", "contingencyId4"));
return new IdentifierContingencyList("list1", networkElementIdentifiers);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,9 @@
"type" : "ID_BASED",
"identifier" : "identifier"
} ]
}, {
"type" : "ID_WITH_WILDCARDS",
"contingencyId" : "contingencyId4",
"identifier" : "identifier?"
} ]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/**
* Copyright (c) 2024, RTE (http://www.rte-france.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/.
* SPDX-License-Identifier: MPL-2.0
*/
package com.powsybl.iidm.network.identifiers;

import com.powsybl.commons.PowsyblException;
import com.powsybl.iidm.network.Identifiable;
import com.powsybl.iidm.network.Network;
import org.apache.commons.lang3.StringUtils;

import java.util.Collections;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import static com.powsybl.iidm.network.identifiers.NetworkElementIdentifier.IdentifierType.ID_WITH_WILDCARDS;

/**
*
* Identifier that finds a network element that have some unknown character.
* The character '?' is the wildcard that replace the unknown characters
* There can be maximum 5 wildcards in the identifier.
* For example the identifier "GEN_?" allows to find GEN_1
* the only special characters allowed for the identifier are '_', '-', '.'
*
* @author Etienne Lesot {@literal <etienne.lesot at rte-france.com>}
*
*/
olperr1 marked this conversation as resolved.
Show resolved Hide resolved
public class IdWithWildcardsNetworkElementIdentifier implements NetworkElementIdentifier {
private String identifier;
public static final char WILDCARD = '?';
public static final int ALLOWED_WILDCARDS_NUMBER = 5;
private final String contingencyId;

public IdWithWildcardsNetworkElementIdentifier(String identifier) {
this(identifier, null);
}

public IdWithWildcardsNetworkElementIdentifier(String identifier, String contingencyId) {
this.identifier = Objects.requireNonNull(identifier);
this.contingencyId = contingencyId;
initialize();
}

private void initialize() {
String allowedCharactersRegex = "^[A-Za-z0-9_?.-]*$";

if (!identifier.matches(allowedCharactersRegex)) {
throw new PowsyblException("Only characters allowed for this identifier are letters, numbers, '_', '-', '.' and the wildcard character '?'");
}
int separatorNumber = StringUtils.countMatches(identifier, WILDCARD);
if (separatorNumber > ALLOWED_WILDCARDS_NUMBER) {
throw new PowsyblException("There can be a maximum of " + ALLOWED_WILDCARDS_NUMBER + " wildcards ('?')");
}
if (separatorNumber == 0) {
throw new PowsyblException("There is no wildcard in your identifier, please use IdBasedNetworkElementIdentifier instead");
}
identifier = identifier.replace(".", "\\.").replace(WILDCARD, '.');
}

@Override
public Set<Identifiable> filterIdentifiable(Network network) {
return network.getIdentifiables()
.stream()
.filter(identifiable -> identifiable.getId().matches(identifier))
.collect(Collectors.toUnmodifiableSet());
}

@Override
public Set<String> getNotFoundElements(Network network) {
Identifiable<?> identifiable = network.getIdentifiable(identifier);
return identifiable == null ? Collections.singleton(identifier) : Collections.emptySet();
}

@Override
public IdentifierType getType() {
return ID_WITH_WILDCARDS;
}

@Override
public Optional<String> getContingencyId() {
return Optional.ofNullable(contingencyId);
}

public String getIdentifier() {
return identifier;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ public interface NetworkElementIdentifier {
enum IdentifierType {
ID_BASED,
VOLTAGE_LEVELS_AND_ORDER,
LIST
LIST,
ID_WITH_WILDCARDS
}

IdentifierType getType();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,7 @@
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.powsybl.commons.json.JsonUtil;
import com.powsybl.iidm.network.identifiers.NetworkElementIdentifierContingencyList;
import com.powsybl.iidm.network.identifiers.IdBasedNetworkElementIdentifier;
import com.powsybl.iidm.network.identifiers.NetworkElementIdentifier;
import com.powsybl.iidm.network.identifiers.VoltageLevelAndOrderNetworkElementIdentifier;
import com.powsybl.iidm.network.identifiers.*;

import java.io.IOException;
import java.util.Collections;
Expand Down Expand Up @@ -54,8 +51,7 @@ public NetworkElementIdentifier deserialize(JsonParser parser, DeserializationCo
}
case "identifierList" -> {
parser.nextToken();
networkElementIdentifierList = JsonUtil.readList(deserializationContext,
parser, NetworkElementIdentifier.class);
networkElementIdentifierList = JsonUtil.readList(deserializationContext, parser, NetworkElementIdentifier.class);
}
case "voltageLevelId1" -> voltageLevelId1 = parser.nextTextValue();
case "voltageLevelId2" -> voltageLevelId2 = parser.nextTextValue();
Expand All @@ -76,7 +72,8 @@ public NetworkElementIdentifier deserialize(JsonParser parser, DeserializationCo
case ID_BASED -> new IdBasedNetworkElementIdentifier(identifier, contingencyId);
case LIST -> new NetworkElementIdentifierContingencyList(networkElementIdentifierList, contingencyId);
case VOLTAGE_LEVELS_AND_ORDER ->
new VoltageLevelAndOrderNetworkElementIdentifier(voltageLevelId1, voltageLevelId2, order, contingencyId);
new VoltageLevelAndOrderNetworkElementIdentifier(voltageLevelId1, voltageLevelId2, order, contingencyId);
case ID_WITH_WILDCARDS -> new IdWithWildcardsNetworkElementIdentifier(identifier, contingencyId);
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,7 @@
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import com.powsybl.iidm.network.identifiers.NetworkElementIdentifierContingencyList;
import com.powsybl.iidm.network.identifiers.IdBasedNetworkElementIdentifier;
import com.powsybl.iidm.network.identifiers.NetworkElementIdentifier;
import com.powsybl.iidm.network.identifiers.VoltageLevelAndOrderNetworkElementIdentifier;
import com.powsybl.iidm.network.identifiers.*;

import java.io.IOException;
import java.util.Optional;
Expand Down Expand Up @@ -41,15 +38,18 @@ public void serialize(NetworkElementIdentifier networkElementIdentifier, JsonGen
break;
case LIST:
serializerProvider.defaultSerializeField("identifierList",
((NetworkElementIdentifierContingencyList) networkElementIdentifier).getNetworkElementIdentifiers(),
jsonGenerator);
((NetworkElementIdentifierContingencyList) networkElementIdentifier).getNetworkElementIdentifiers(),
jsonGenerator);
break;
case VOLTAGE_LEVELS_AND_ORDER:
VoltageLevelAndOrderNetworkElementIdentifier ucteIdentifier = (VoltageLevelAndOrderNetworkElementIdentifier) networkElementIdentifier;
jsonGenerator.writeStringField("voltageLevelId1", ucteIdentifier.getVoltageLevelId1());
jsonGenerator.writeStringField("voltageLevelId2", ucteIdentifier.getVoltageLevelId2());
jsonGenerator.writeStringField("order", Character.toString(ucteIdentifier.getOrder()));
break;
case ID_WITH_WILDCARDS:
jsonGenerator.writeStringField("identifier", ((IdWithWildcardsNetworkElementIdentifier) networkElementIdentifier)
.getIdentifier().replace('.', IdWithWildcardsNetworkElementIdentifier.WILDCARD));
}
jsonGenerator.writeEndObject();
}
Expand Down