Skip to content

Commit

Permalink
feat(404 - rsr-1004): Add constraints to update compas flow bindings
Browse files Browse the repository at this point in the history
- modification of ExtRefEditorService and add a test
- modification of ExtRefEditor interface to return List<SclReportItem> with updateIedNameBasedOnLnode()

Signed-off-by: JAFFRE Guillaume <guillaume.jaffre@rte-france.com>
  • Loading branch information
GuillaumeJAFFRE committed Jul 10, 2024
1 parent 1167ab8 commit 4734324
Show file tree
Hide file tree
Showing 5 changed files with 186 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

import java.math.BigInteger;
import java.util.*;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -90,7 +91,7 @@ private static List<TIED> getIedSources(SclRootAdapter sclRootAdapter, TCompasBa
*/
private List<ExtRefInfo.ExtRefWithBayReference> getExtRefWithBayReferenceInLDEPF(TDataTypeTemplates dataTypeTemplates, TIED tied, final TLDevice tlDevice, final List<SclReportItem> sclReportItems) {
List<ExtRefInfo.ExtRefWithBayReference> extRefBayReferenceList = new ArrayList<>();
String lDevicePath = "SCL/IED[@name=\""+ tied.getName() + "\"]/AccessPoint/Server/LDevice[@inst=\"" + tlDevice.getInst() + "\"]";
String lDevicePath = "SCL/IED[@name=\"" + tied.getName() + "\"]/AccessPoint/Server/LDevice[@inst=\"" + tlDevice.getInst() + "\"]";
Optional<TCompasBay> tCompasBay = PrivateUtils.extractCompasPrivate(tied, TCompasBay.class);
if (tCompasBay.isEmpty()) {
sclReportItems.add(SclReportItem.error(lDevicePath, "The IED has no Private Bay"));
Expand Down Expand Up @@ -405,8 +406,7 @@ private List<SclReportItem> updateLDEPFDos(LDeviceAdapter lDeviceAdapter, TExtRe
private Optional<SclReportItem> updateVal(AbstractLNAdapter<?> lnAdapter, String doName, String daName, TExtRef extRef, TChannel setting) {
String value = switch (daName) {
case DU_DA_NAME -> setting.getChannelShortLabel();
case SETVAL_DA_NAME ->
LN_PREFIX_B.equals(lnAdapter.getPrefix()) || LN_PREFIX_A.equals(lnAdapter.getPrefix()) ? setting.getChannelLevModQ().value() : setting.getChannelLevMod().value();
case SETVAL_DA_NAME -> LN_PREFIX_B.equals(lnAdapter.getPrefix()) || LN_PREFIX_A.equals(lnAdapter.getPrefix()) ? setting.getChannelLevModQ().value() : setting.getChannelLevMod().value();
case STVAL_DA_NAME -> ActiveStatus.ON.getValue();
case SETSRCREF_DA_NAME -> computeDaiValue(lnAdapter, extRef, setting.getDAName());
default -> null;
Expand Down Expand Up @@ -464,7 +464,7 @@ public void debindCompasFlowsAndExtRefsBasedOnVoltageLevel(SCL scd) {


@Override
public void updateIedNameBasedOnLnode(SCL scl) {
public List<SclReportItem> updateIedNameBasedOnLnode(SCL scl) {
Map<TopoKey, TBay> bayByTopoKey = scl.getSubstation().stream()
.flatMap(tSubstation -> tSubstation.getVoltageLevel().stream())
.flatMap(tVoltageLevel -> tVoltageLevel.getBay().stream())
Expand All @@ -475,6 +475,7 @@ public void updateIedNameBasedOnLnode(SCL scl) {
.flatMap(Optional::stream)
.collect(Collectors.toMap(BayTopoKey::topoKey, BayTopoKey::bay));

List<SclReportItem> sclReportItems = new ArrayList<>();
scl.getIED().stream()
.flatMap(ldeviceService::getLdevices)
.forEach(tlDevice ->
Expand All @@ -488,9 +489,18 @@ public void updateIedNameBasedOnLnode(SCL scl) {
&& Objects.equals(tlNode.getLnInst(), tCompasFlow.getExtReflnInst())
&& Utils.lnClassEquals(tlNode.getLnClass(), tCompasFlow.getExtReflnClass())
&& Objects.equals(tlNode.getPrefix(), tCompasFlow.getExtRefprefix()))
.filter(tlNode -> {
TCompasICDHeader tCompasICDHeader = PrivateUtils.extractCompasPrivate(tlNode, TCompasICDHeader.class)
.orElseThrow(() -> new ScdException(("The substation LNode with following attributes : IedName:%s / LdInst:%s / LnClass:%s / LnInst:%s " +
"does not contain the needed (COMPAS - ICDHeader) private")
.formatted(tlNode.getIedName(), tlNode.getLdInst(), tlNode.getLnClass().getFirst(), tlNode.getLnInst())));
return Objects.equals(tCompasFlow.getFlowSourceIEDType(), tCompasICDHeader.getIEDType())
&& Objects.equals(tCompasFlow.getFlowIEDSystemVersioninstance(), tCompasICDHeader.getIEDSystemVersioninstance())
&& Objects.equals(tCompasFlow.getFlowSourceIEDredundancy(), tCompasICDHeader.getIEDredundancy());
})
.map(TLNode::getIedName)
.filter(StringUtils::isNotBlank)
.findFirst()
.reduce(checkOnlyOneIed(tCompasFlow, tBay, sclReportItems))
)
.ifPresentOrElse(iedName -> {
extRefService.getMatchingExtRefs(tlDevice, tCompasFlow).forEach(tExtRef -> tExtRef.setIedName(iedName));
Expand All @@ -503,6 +513,17 @@ public void updateIedNameBasedOnLnode(SCL scl) {
)
)
);
return sclReportItems;
}

private static BinaryOperator<String> checkOnlyOneIed(TCompasFlow tCompasFlow, TBay tBay, List<SclReportItem> sclReportItems) {
return (iedName1, iedName2) -> {
sclReportItems.add(SclReportItem.error("",
("Several LNode@IedName ('%s', '%s') are found in the bay '%s' for the following compas-flow attributes :" +
" @FlowSourceIEDType '%s' @FlowSourceIEDredundancy '%s' @FlowIEDSystemVersioninstance '%s'").
formatted(iedName1, iedName2, tBay.getName(), tCompasFlow.getFlowSourceIEDType(), tCompasFlow.getFlowSourceIEDredundancy(), tCompasFlow.getFlowIEDSystemVersioninstance())));
return iedName1;
};
}

record TopoKey(String FlowNode, BigInteger FlowNodeOrder) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,9 @@ public interface ExtRefEditor {

/**
* Update compas:Flow.ExtRefiedName and ExtRef.iedName, based on Substation LNode iedName
* @param scd SCL
* @return list of encoutered errors
*/
void updateIedNameBasedOnLnode(SCL scd);
List<SclReportItem> updateIedNameBasedOnLnode(SCL scd);

}
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,7 @@ void manageBindingForLDEPF_when_DO_Mod_and_DA_stVal_NotFoundInDataTypeTemplate_s
.extracting(SclReportItem::message, SclReportItem::xpath)
.containsExactly(
Tuple.tuple("DO@name=Mod/DA@name=stVal not found in DataTypeTemplate",
"SCL/IED[@name=\"IED_NAME1\"]/AccessPoint/Server/LDevice[@inst=\"LDEPF\"]"),
"SCL/IED[@name=\"IED_NAME1\"]/AccessPoint/Server/LDevice[@inst=\"LDEPF\"]"),
Tuple.tuple("DO@name=Mod/DA@name=stVal not found in DataTypeTemplate",
"SCL/IED[@name=\"IED_NAME2\"]/AccessPoint/Server/LDevice[@inst=\"LDEPF\"]"),
Tuple.tuple("DO@name=Mod/DA@name=stVal not found in DataTypeTemplate",
Expand Down Expand Up @@ -865,7 +865,7 @@ void debindCompasFlowsAndExtRefsBasedOnVoltageLevel(String testCase, SCL scd, Tu
.containsExactly(flow2);
}

private static Stream<Arguments> provideFlowAndExtRefForDebinding(){
private static Stream<Arguments> provideFlowAndExtRefForDebinding() {
SCL scd = SclTestMarshaller.getSCLFromFile("/scd-extref-flow-debind/scd_extref_flow_debind_success.xml");
SCL scdVoltageLevel0 = SclTestMarshaller.getSCLFromFile("/scd-extref-flow-debind/scd_extref_flow_debind_volatagelevelname_0.xml");
SCL scdVoltageLevelUnknown = SclTestMarshaller.getSCLFromFile("/scd-extref-flow-debind/scd_extref_flow_debind_volatagelevelname_unknown.xml");
Expand Down Expand Up @@ -901,7 +901,7 @@ private TInputs findInputs(SCL scd) {
}

@Test
void updateIedNameBasedOnLnode_should_update_CompasFlow_and_ExtRef_iedName(){
void updateIedNameBasedOnLnode_should_update_CompasFlow_and_ExtRef_iedName() {
// Given
SCL scd = SclTestMarshaller.getSCLFromFile("/scd-extref-iedname/scd_set_extref_iedname_based_on_lnode_success.xml");
// When
Expand All @@ -914,7 +914,7 @@ void updateIedNameBasedOnLnode_should_update_CompasFlow_and_ExtRef_iedName(){
}

@Test
void updateIedNameBasedOnLnode_when_no_matching_lnode_should_clear_binding(){
void updateIedNameBasedOnLnode_when_no_matching_lnode_should_clear_binding() {
// Given
SCL scd = SclTestMarshaller.getSCLFromFile("/scd-extref-iedname/scd_set_extref_iedname_based_on_lnode_success.xml");
PrivateUtils.extractCompasPrivate(scd.getSubstation().get(0).getVoltageLevel().get(0).getBay().get(0), TCompasTopo.class).orElseThrow().setNode("99");
Expand All @@ -928,4 +928,18 @@ void updateIedNameBasedOnLnode_when_no_matching_lnode_should_clear_binding(){
assertExtRefIsNotBound(findExtRef(scd, "IED_NAME1", "LD_INST11", "STAT_LDSUIED_LPDO 1 Sortie_13_BOOLEAN_18_stVal_1"));

}

@Test
void updateIedNameBasedOnLnode_when_several_ied_match_compasFlow_should_return_an_error() {
// Given
SCL scd = SclTestMarshaller.getSCLFromFile("/scd-extref-iedname/scd_set_extref_iedname_based_on_lnode_several_ied_matching.xml");
// When
List<SclReportItem> result = extRefEditorService.updateIedNameBasedOnLnode(scd);
// Then
assertThat(result)
.extracting(SclReportItem::isError, SclReportItem::message)
.containsExactly(Tuple.tuple(true,
"Several LNode@IedName ('IED_NAME2', 'IED_NAME3') are found in the bay 'BAY_1' for the following compas-flow attributes " +
": @FlowSourceIEDType 'SCU' @FlowSourceIEDredundancy 'A' @FlowIEDSystemVersioninstance '1'"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!-- SPDX-FileCopyrightText: 2023 RTE FRANCE -->
<!-- -->
<!-- SPDX-License-Identifier: Apache-2.0 -->
<SCL version="2007" revision="B" release="4" xmlns="http://www.iec.ch/61850/2003/SCL" xmlns:compas="https://www.lfenergy.org/compas/extension/v1">
<Header id="hId" version="2007" revision="B" toolID="COMPAS"/>
<Substation name="SITE">
<VoltageLevel nomFreq="50" numPhases="3" name="0">
<Voltage unit="V" multiplier="k">0</Voltage>
<Bay name="BAY_1">
<Private type="COMPAS-Topo">
<compas:Topo Node="101" NodeOrder="2" Direction="Down"/>
</Private>
<Private type="COMPAS-Bay">
<compas:Bay BayCodif="TG00000001" UUID="9cd6f05b-1bbd-4ba3-86c5-41c99103e06d" Version="1"
MainShortLabel="SITE1" SecondLabel="SITE-TGENE" NumBay="7" BayCount="1"/>
</Private>
<Function name="FUNCTION_1">
<Private type="COMPAS-Function">
<compas:Function UUID="8f4cda3f-828c-4006-9b87-2af96b19304b" Label="FUNCTION_1"/>
</Private>
<LNode iedName="IED_NAME2" ldInst="LD_INST21" lnClass="ANCR" lnInst="1">
<Private type="COMPAS-ICDHeader">
<compas:ICDHeader xmlns:compas="https://www.lfenergy.org/compas/extension/v1" ICDSystemVersionUUID="IED7949eaedc51747c9947e9152eb09e9cf" IEDType="SCU" IEDSubstationinstance="12" IEDSystemVersioninstance="1" BayLabel="4CBO.1" IEDName="PUYPE4CBO1BCU1" VendorName="Efacec" IEDredundancy="A" IEDmodel="TPU L500-3-1-F-3-B-X-X-X-X-X-X-X-X-X-X-X-X-X-X-X-X-X-XXXX-6-4-8-X-CXXX-A2B1C2E3F2G1H1" hwRev="1.00" swRev="3.07.004" headerId="BCU_CBO_v2" headerVersion="1.484" headerRevision="1"/>
</Private>
<Private type="COMPAS-LNodeStatus">on</Private>
</LNode>
</Function>
<Function name="FUNCTION_2">
<Private type="COMPAS-Function">
<compas:Function UUID="8f4cda3f-828c-4006-9b87-2af96b19304b" Label="FUNCTION_2"/>
</Private>
<LNode iedName="IED_NAME3" ldInst="LD_INST21" lnClass="ANCR" lnInst="1">
<Private type="COMPAS-ICDHeader">
<compas:ICDHeader xmlns:compas="https://www.lfenergy.org/compas/extension/v1" ICDSystemVersionUUID="IED7949eaedc51747c9947e9152eb09e9cf" IEDType="SCU" IEDSubstationinstance="12" IEDSystemVersioninstance="1" BayLabel="4CBO.1" IEDName="PUYPE4CBO1BCU1" VendorName="Efacec" IEDredundancy="A" IEDmodel="TPU L500-3-1-F-3-B-X-X-X-X-X-X-X-X-X-X-X-X-X-X-X-X-X-XXXX-6-4-8-X-CXXX-A2B1C2E3F2G1H1" hwRev="1.00" swRev="3.07.004" headerId="BCU_CBO_v2" headerVersion="1.484" headerRevision="1"/>
</Private>
<Private type="COMPAS-LNodeStatus">on</Private>
</LNode>
</Function>
</Bay>
</VoltageLevel>
</Substation>
<IED name="IED_NAME1">
<Private type="COMPAS-ICDHeader">
<compas:ICDHeader ICDSystemVersionUUID="System_Version_IED_NAME1" IEDType="BCU" IEDSubstationinstance="11" IEDSystemVersioninstance="1" IEDName="IED_NAME1" VendorName="SCLE SFE" IEDmodel="ARKENS-SV1120-HGAAA-EB5" IEDredundancy="A" BayLabel="3THEIX2" hwRev="0.0.2." swRev="1.0a"
headerId="ARKENS-SV1120-HGAAA-EB5_SCU" headerVersion="1.2a" headerRevision="412995"/>
</Private>
<AccessPoint name="AP_NAME">
<Server>
<Authentication/>
<LDevice inst="LD_INST11" ldName="IED_NAME1LD_INST11">
<LN0 lnClass="LLN0" inst="" lnType="LNEX1">
<DOI name="Mod">
<DAI name="stVal">
<Val>on</Val>
</DAI>
</DOI>
<Inputs>
<Private type="COMPAS-Flow">
<compas:Flow FlowSourceBayNode="101" FlowSourceBayNodeOrder="2" dataStreamKey="STAT_LDSUIED_LPDO 1 Sortie_13_BOOLEAN_18_stVal_1" ExtRefiedName="IED_NAME_A_CHANGER" ExtRefldinst="LD_INST21" ExtRefprefix="" ExtReflnClass="ANCR" ExtReflnInst="1" FlowID="1"
FlowStatus="ACTIVE" FlowKind="BAY_INTERNAL" FlowSourceIEDType="SCU" FlowSourceIEDredundancy="A" FlowIEDSystemVersioninstance="1"/>
</Private>
<ExtRef iedName="IED_NAME_A_CHANGER" ldInst="LD_INST21" lnClass="ANCR" lnInst="1" doName="DoName1" daName="daName1" intAddr="INT_ADDR11" pDO="Do11.sdo11" pDA="da11.bda111.bda112.bda113" desc="STAT_LDSUIED_LPDO 1 Sortie_13_BOOLEAN_18_stVal_1"/>
</Inputs>
</LN0>
</LDevice>
</Server>
</AccessPoint>
</IED>
<IED name="IED_NAME2">
<Private type="COMPAS-ICDHeader">
<compas:ICDHeader ICDSystemVersionUUID="System_Version_IED_NAME2" IEDType="SCU" IEDSubstationinstance="22" IEDSystemVersioninstance="1" IEDName="IED_NAME2" VendorName="SCLE SFE" IEDmodel="ARKENS-SV1120-HGAAA-EB5" IEDredundancy="A" BayLabel="3THEIX2" hwRev="0.0.2." swRev="1.0a"
headerId="ARKENS-SV1120-HGAAA-EB5_SCU" headerVersion="1.2a" headerRevision="412995"/>
</Private>
<AccessPoint name="AP_NAME">
<Server>
<Authentication/>
<LDevice inst="LD_INST21">
<LN0 lnClass="LLN0" inst="" lnType="LNEX1">
<DOI name="Mod">
<DAI name="stVal">
<Val>on</Val>
</DAI>
</DOI>
</LN0>
<LN lnClass="ANCR" inst="1" lnType="lnType"/>
</LDevice>
</Server>
</AccessPoint>
</IED>
<IED name="IED_NAME3">
<Private type="COMPAS-ICDHeader">
<compas:ICDHeader ICDSystemVersionUUID="System_Version_IED_NAME2" IEDType="SCU" IEDSubstationinstance="22" IEDSystemVersioninstance="1" IEDName="IED_NAME2" VendorName="SCLE SFE" IEDmodel="ARKENS-SV1120-HGAAA-EB5" IEDredundancy="A" BayLabel="3THEIX2" hwRev="0.0.2." swRev="1.0a"
headerId="ARKENS-SV1120-HGAAA-EB5_SCU" headerVersion="1.2a" headerRevision="412995"/>
</Private>
<AccessPoint name="AP_NAME">
<Server>
<Authentication/>
<LDevice inst="LD_INST21">
<LN0 lnClass="LLN0" inst="" lnType="LNEX1">
<DOI name="Mod">
<DAI name="stVal">
<Val>on</Val>
</DAI>
</DOI>
</LN0>
<LN lnClass="ANCR" inst="1" lnType="lnType"/>
</LDevice>
</Server>
</AccessPoint>
</IED>
<DataTypeTemplates>
<LNodeType lnClass="LLN0" id="LNEX1">
<DO name="Mod" type="DO1"/>
</LNodeType>
<LNodeType lnClass="ANCR" id="lnType">
<DO name="DoName1" type="DO2"/>
</LNodeType>
<DOType cdc="ENC" id="DO1">
<DA fc="ST" name="stVal" bType="Enum" type="BehaviourModeKind"/>
</DOType>
<DOType cdc="ENC" id="DO2">
<DA fc="BL" name="daName1" bType="BOOLEAN"/>
</DOType>
<EnumType id="BehaviourModeKind">
<EnumVal ord="1">on</EnumVal>
<EnumVal ord="2">off</EnumVal>
<EnumVal ord="3">test</EnumVal>
</EnumType>
</DataTypeTemplates>
</SCL>
Loading

0 comments on commit 4734324

Please sign in to comment.