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

feat(404 - rsr-1004): Add constraints to update compas flow bindings #407

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
package org.lfenergy.compas.sct.commons;

import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.lfenergy.compas.scl2007b4.model.*;
import org.lfenergy.compas.sct.commons.api.ExtRefEditor;
import org.lfenergy.compas.sct.commons.dto.*;
Expand All @@ -27,6 +26,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 +90,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 +405,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 +463,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 +474,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 +488,21 @@ 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 -> {
GuillaumeJAFFRE marked this conversation as resolved.
Show resolved Hide resolved
Optional<TCompasICDHeader> tCompasICDHeader = PrivateUtils.extractCompasPrivate(tlNode, TCompasICDHeader.class);
if (tCompasICDHeader.isPresent()) {
return Objects.equals(tCompasFlow.getFlowSourceIEDType(), tCompasICDHeader.get().getIEDType())
&& Objects.equals(tCompasFlow.getFlowIEDSystemVersioninstance(), tCompasICDHeader.get().getIEDSystemVersioninstance())
&& Objects.equals(tCompasFlow.getFlowSourceIEDredundancy(), tCompasICDHeader.get().getIEDredundancy());
} else {
sclReportItems.add(SclReportItem.error("", ("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 false;
}
})
.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 +515,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,31 @@ 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() {
GuillaumeJAFFRE marked this conversation as resolved.
Show resolved Hide resolved
// Given
SCL scd = SclTestMarshaller.getSCLFromFile("/scd-extref-iedname/scd_set_extref_iedname_based_on_lnode_several_ied_matching_compasFlow.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'"));
}

@Test
void updateIedNameBasedOnLnode_when_no_Compas_ICD_Header_should_return_an_error() {
// Given
SCL scd = SclTestMarshaller.getSCLFromFile("/scd-extref-iedname/scd_set_extref_iedname_fails_no_Compas_ICDHeader.xml");
// When
List<SclReportItem> result = extRefEditorService.updateIedNameBasedOnLnode(scd);
// Then
assertThat(result)
.extracting(SclReportItem::isError, SclReportItem::message)
.containsExactly(Tuple.tuple(true,
"The substation LNode with following attributes : IedName:IED_NAME2 / LdInst:LD_INST21 / LnClass:ANCR / LnInst:1 does not contain the needed (COMPAS - ICDHeader) private"));
}
}
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
Loading