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(#413): RSR-1049 LDEPF Post processing - unused CHANNEL assignment #417

Merged
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 @@ -7,6 +7,8 @@
import lombok.RequiredArgsConstructor;
import org.lfenergy.compas.scl2007b4.model.*;
import org.lfenergy.compas.sct.commons.api.ExtRefEditor;
import org.lfenergy.compas.sct.commons.api.LnEditor;
import org.lfenergy.compas.sct.commons.domain.*;
import org.lfenergy.compas.sct.commons.dto.*;
import org.lfenergy.compas.sct.commons.exception.ScdException;
import org.lfenergy.compas.sct.commons.model.epf.EPF;
Expand Down Expand Up @@ -46,6 +48,7 @@ public class ExtRefEditorService implements ExtRefEditor {

private final IedService iedService;
private final LdeviceService ldeviceService;
private final LnEditor lnEditor;
samirromdhani marked this conversation as resolved.
Show resolved Hide resolved
private final ExtRefService extRefService;
private final DataTypeTemplatesService dataTypeTemplatesService;

Expand Down Expand Up @@ -323,6 +326,41 @@ public List<SclReportItem> manageBindingForLDEPF(SCL scd, EPF epf) {
return sclReportItems;
}

@Override
public void epfPostProcessing(SCL scd) {
iedService.getFilteredIeds(scd, ied -> !ied.getName().contains("TEST"))
.forEach(tied -> ldeviceService.findLdevice(tied, tlDevice -> LDEVICE_LDEPF.equals(tlDevice.getInst()))
.ifPresent(tlDevice -> tlDevice.getLN0().getDOI()
.stream().filter(tdoi -> tdoi.getName().startsWith(INREF_PREFIX))
.forEach(tdoi -> {
DoLinkedToDaFilter doLinkedToSetSrcRef = new DoLinkedToDaFilter(tdoi.getName(), List.of(), SETSRCREF_DA_NAME, List.of());
Optional<TDAI> setSrcRefDAI = lnEditor.getDOAndDAInstances(tlDevice.getLN0(), doLinkedToSetSrcRef);
DoLinkedToDaFilter doLinkedPurPose = new DoLinkedToDaFilter(tdoi.getName(), List.of(), PURPOSE_DA_NAME, List.of());
Optional<TDAI> purPoseDAI = lnEditor.getDOAndDAInstances(tlDevice.getLN0(), doLinkedPurPose);

boolean isSetSrcRefExistAndEmpty = setSrcRefDAI.isPresent()
&& (!setSrcRefDAI.get().isSetVal()
|| (setSrcRefDAI.get().isSetVal()
&& setSrcRefDAI.get().getVal().getFirst().getValue().isEmpty()));
boolean isPurposeExistAndMatchChannel = purPoseDAI.isPresent()
&& purPoseDAI.get().isSetVal()
&& (purPoseDAI.get().getVal().getFirst().getValue().startsWith("DYN_LDEPF_DIGITAL CHANNEL")
|| purPoseDAI.get().getVal().getFirst().getValue().startsWith("DYN_LDEPF_ANALOG CHANNEL"));
if(isSetSrcRefExistAndEmpty && isPurposeExistAndMatchChannel) {

DoLinkedToDa doLinkedToDa = new DoLinkedToDa();
DataObject dataObject = new DataObject();
dataObject.setDoName(tdoi.getName());
doLinkedToDa.setDataObject(dataObject);
DataAttribute dataAttribute = new DataAttribute();
dataAttribute.setDaName(SETSRCREF_DA_NAME);
dataAttribute.setDaiValues(List.of(new DaVal(null, tied.getName()+tlDevice.getInst()+"/LPHD0.Proxy")));
doLinkedToDa.setDataAttribute(dataAttribute);
lnEditor.updateOrCreateDOAndDAInstances(tlDevice.getLN0(), doLinkedToDa);
}
})));
}

private List<SclReportItem> validateIed(SclRootAdapter sclRootAdapter) {
List<SclReportItem> iedErrors = new ArrayList<>(checkIedCompasIcdHeaderAttributes(sclRootAdapter));
iedErrors.addAll(checkIedUnityOfIcdSystemVersionUuid(sclRootAdapter));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,14 @@ public interface ExtRefEditor {
*/
List<SclReportItem> manageBindingForLDEPF(SCL scd, EPF epf);

/**
* Pointing an unused channel to an existing object LPHD0.Proxy of the concerned IED.
* An unused channel is characterized by the value DAI name ="setSrcRef"/Val (should be empty) in InRef**
* that have a purpose beginning by DYN_LDEPF_DIGITAL CHANNEL or DYN_LDEPF_ANALOG CHANNEL
* @param scd SCL
*/
void epfPostProcessing(SCL scd);

/**
* Debinding of Private CompasFlows and ExtRef signals based on voltageLevel
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static org.lfenergy.compas.sct.commons.util.CommonConstants.BEHAVIOUR_DO_NAME;
import static org.lfenergy.compas.sct.commons.util.CommonConstants.STVAL_DA_NAME;
import static org.lfenergy.compas.sct.commons.util.CommonConstants.*;

/**
* A representation of the model object
Expand Down Expand Up @@ -71,8 +70,6 @@ public class LN0Adapter extends AbstractLNAdapter<LN0> {

public static final DoTypeName BEHAVIOUR_DO_TYPE_NAME = new DoTypeName(BEHAVIOUR_DO_NAME);
public static final DaTypeName BEHAVIOUR_DA_TYPE_NAME = getDaTypeNameForBeh();
private static final String DAI_NAME_PURPOSE = "purpose";
private static final String INREF_PREFIX = "InRef";
private static final Pattern LDEFP_DIGITAL_CHANNEL_PATTERN = Pattern.compile("DYN_LDEPF_DIGITAL CHANNEL \\d+_\\d+_BOOLEAN");

/**
Expand Down Expand Up @@ -233,8 +230,8 @@ public List<SclReportItem> updateDoInRef() {
return getDOIAdapters().stream()
.filter(doiAdapter -> doiAdapter.getCurrentElem().isSetName()
&& doiAdapter.getCurrentElem().getName().startsWith(INREF_PREFIX)
&& doiAdapter.findDataAdapterByName(DAI_NAME_PURPOSE).isPresent())
.map(doiAdapter -> doiAdapter.getDataAdapterByName(DAI_NAME_PURPOSE).getCurrentElem().getVal().stream()
&& doiAdapter.findDataAdapterByName(PURPOSE_DA_NAME).isPresent())
.map(doiAdapter -> doiAdapter.getDataAdapterByName(PURPOSE_DA_NAME).getCurrentElem().getVal().stream()
.findFirst()
.map(tVal -> doiAdapter.updateDaiFromExtRef(getExtRefsBoundToInRef(tVal.getValue())))
.orElse(List.of(SclReportItem.warning(getXPath(), "The DOI %s can't be bound with an ExtRef".formatted(getXPath()))))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,10 @@ public final class CommonConstants {
public static final String SETSRCCB_DA_NAME = "setSrcCB";
public static final String SETTSTREF_DA_NAME = "setTstRef";
public static final String SETTSTCB_DA_NAME = "setTstCB";
public static final String PURPOSE_DA_NAME = "purpose";
public static final String Q_DA_NAME = "q";
public static final String IED_TEST_NAME = "IEDTEST";
public static final String INREF_PREFIX = "InRef";

/**
* Private Controlller, should not be instanced
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package org.lfenergy.compas.sct.commons;

import org.assertj.core.api.Assertions;
import org.assertj.core.api.SoftAssertions;
import org.assertj.core.groups.Tuple;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Tag;
Expand Down Expand Up @@ -39,7 +40,7 @@ class ExtRefEditorServiceTest {

@BeforeEach
void init() {
extRefEditorService = new ExtRefEditorService(new IedService(), new LdeviceService(), new ExtRefService(), new DataTypeTemplatesService());
extRefEditorService = new ExtRefEditorService(new IedService(), new LdeviceService(), new LnService(), new ExtRefService(), new DataTypeTemplatesService());
}

@Test
Expand Down Expand Up @@ -955,4 +956,44 @@ void updateIedNameBasedOnLnode_when_no_Compas_ICD_Header_should_return_an_error(
.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"));
}

@Test
void epfPostProcessing_when_exist_unused_channel_should_update_setSrcRef() {
// Given
SCL scd = SclTestMarshaller.getSCLFromFile("/scd-ldepf/scd_ldepf_postProcessing.xml");
// When
extRefEditorService.epfPostProcessing(scd);
// Then
SoftAssertions softly = new SoftAssertions();

Optional<TDAI> setSrcRefInInRef1 = findDai(scd, "IED_NAME1", "LDEPF", "InRef1", "setSrcRef");
Optional<TDAI> purposeInInRef1 = findDai(scd, "IED_NAME1", "LDEPF", "InRef1", "purpose");
assertThat(purposeInInRef1).isPresent();
softly.assertThat(purposeInInRef1.get().getVal().getFirst().getValue()).doesNotStartWith("DYN_LDEPF_DIGITAL CHANNEL");
softly.assertThat(purposeInInRef1.get().getVal().getFirst().getValue()).doesNotStartWith("DYN_LDEPF_ANALOG CHANNEL");
assertThat(setSrcRefInInRef1).isPresent();
softly.assertThat(setSrcRefInInRef1.get().isSetVal()).isFalse();

Optional<TDAI> setSrcRefInInRef2 = findDai(scd, "IED_NAME1", "LDEPF", "InRef2", "setSrcRef");
Optional<TDAI> purposeInInRef2 = findDai(scd, "IED_NAME1", "LDEPF", "InRef2", "purpose");
assertThat(purposeInInRef2).isPresent();
softly.assertThat(purposeInInRef2.get().getVal().getFirst().getValue()).startsWith("DYN_LDEPF_DIGITAL CHANNEL");
assertThat(setSrcRefInInRef2).isPresent();
softly.assertThat(setSrcRefInInRef2.get().getVal().getFirst().getValue()).isEqualTo("IED_NAME1LDEPF/LPHD0.Proxy");

Optional<TDAI> setSrcRefInInRef3 = findDai(scd, "IED_NAME1", "LDEPF", "InRef3", "setSrcRef");
Optional<TDAI> purposeInInRef3 = findDai(scd, "IED_NAME1", "LDEPF", "InRef3", "purpose");
assertThat(purposeInInRef3).isPresent();
softly.assertThat(purposeInInRef3.get().getVal().getFirst().getValue()).startsWith("DYN_LDEPF_DIGITAL CHANNEL");
samirromdhani marked this conversation as resolved.
Show resolved Hide resolved
assertThat(setSrcRefInInRef3).isPresent();
softly.assertThat(setSrcRefInInRef3.get().getVal().getFirst().getValue()).isEqualTo("IED_NAME1LDEPF/LPHD0.Proxy");

Optional<TDAI> setSrcRefInInRef4 = findDai(scd, "IED_NAME1", "LDEPF", "InRef4", "setSrcRef");
Optional<TDAI> purposeInInRef4 = findDai(scd, "IED_NAME1", "LDEPF", "InRef4", "purpose");
assertThat(purposeInInRef4).isPresent();
softly.assertThat(purposeInInRef4.get().getVal().getFirst().getValue()).startsWith("DYN_LDEPF_ANALOG CHANNEL");
assertThat(setSrcRefInInRef4).isPresent();
softly.assertThat(setSrcRefInInRef4.get().getVal().getFirst().getValue()).isEqualTo("IED_NAME1LDEPF/LPHD0.Proxy");
softly.assertAll();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;

import static org.assertj.core.api.Assertions.assertThat;
Expand Down Expand Up @@ -118,6 +119,18 @@ public static IDataParentAdapter findDoiOrSdi(AbstractLNAdapter<?> lnAdapter, St
return parentAdapter;
}

public static Optional<TDAI> findDai(SCL scl, String iedName, String ldInst, String doiName, String daiName) {
return scl.getIED().stream().filter(tied -> tied.getName().equals(iedName))
.flatMap(tied -> tied.getAccessPoint().stream())
.flatMap(tAccessPoint -> tAccessPoint.getServer().getLDevice().stream())
.filter(tlDevice -> tlDevice.getInst().equals(ldInst))
.flatMap(tlDevice -> tlDevice.getLN0().getDOI().stream())
.filter(tdoi -> tdoi.getName().equals(doiName))
.flatMap(tdoi -> tdoi.getSDIOrDAI().stream().map(tUnNaming -> (TDAI)tUnNaming))
.filter(tdai -> tdai.getName().equals(daiName))
.findFirst();
}

public static AbstractDAIAdapter<?> findDai(AbstractLNAdapter<?> lnAdapter, String dataTypeRef) {
String[] names = dataTypeRef.split("\\.");
if (names.length < 2) {
Expand Down
104 changes: 104 additions & 0 deletions sct-commons/src/test/resources/scd-ldepf/scd_ldepf_postProcessing.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!-- SPDX-FileCopyrightText: 2023 2024 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">
<Private type="COMPAS-SclFileType">
<compas:SclFileType>SCD</compas:SclFileType>
</Private>
<Header id="hId" version="2007" revision="B" toolID="COMPAS"/>
<IED name="IEDTEST">
<AccessPoint name="AP_NAME"/>
</IED>
<IED name="IED_NAME1">
<Private type="COMPAS-Bay">
<compas:Bay UUID="bayUUID" BayCodif="CB00001101" NumBay="1" BayCount="1" MainShortLabel="aa"/>
</Private>
<Private type="COMPAS-ICDHeader">
<compas:ICDHeader IEDType="BCU" IEDSubstationinstance="11" IEDSystemVersioninstance="1" BayLabel="3THEIX1" IEDName="PLOE53THEIX1BCU1" ICDSystemVersionUUID="IED3e4c26f08244476f890fe38f62609a56" VendorName="Efacec" IEDredundancy="None" IEDmodel="TPU L500-3-1-F-3-C-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="2.06.000" headerId="TEMPLATE" headerVersion="1.515" headerRevision="1"/>
</Private>
<AccessPoint name="AP_NAME">
<Server>
<Authentication/>
<LDevice inst="LDEPF" ldName="IED_NAME1LDEPF">
<LN0 lnClass="LLN0" inst="" lnType="LLN0_ID1">
<DOI name="Mod">
<DAI name="stVal" valImport="true">
<Val>on</Val>
</DAI>
</DOI>
<DOI name="InRef1">
<DAI name="purpose" valKind="RO" valImport="false">
<Val>DYN_LDAGSA2_Circuit I phase A amplitude_1_Vector</Val>
</DAI>
<DAI name="setSrcRef" valKind="RO" valImport="false"/>
</DOI>
<DOI name="InRef2">
<DAI name="purpose" valKind="RO" valImport="false">
<Val>DYN_LDEPF_DIGITAL CHANNEL 11 ADF</Val>
</DAI>
<DAI name="setSrcRef" valKind="RO" valImport="false"/>
</DOI>
<DOI name="InRef3">
<DAI name="purpose" valKind="RO" valImport="false">
<Val>DYN_LDEPF_DIGITAL CHANNEL 12 ADF</Val>
</DAI>
<DAI name="setSrcRef" valKind="RO" valImport="false">
<Val/>
</DAI>
</DOI>
<DOI name="InRef4">
<DAI name="purpose" valKind="RO" valImport="false">
<Val>DYN_LDEPF_ANALOG CHANNEL 11 ADF</Val>
</DAI>
<DAI name="setSrcRef" valKind="RO" valImport="false"/>
</DOI>
<Inputs>
<ExtRef ldInst="LD_INST_1" lnClass="ANCR" lnInst="1" doName="DoName1" daName="daName1" intAddr="INT_ADDR11" desc="STAT_LDSUIED_LPDO 1 Sortie_13_BOOLEAN_18_stVal_1"/>
</Inputs>
</LN0>
</LDevice>
<LDevice inst="LD_INST_1" ldName="IED_NAME1LD_INST_1">
<LN0 lnClass="LLN0" inst="" lnType="LLN0_ID1">
<DOI name="Mod">
<DAI name="stVal">
<Val>on</Val>
</DAI>
</DOI>
<DOI name="InRef1">
<DAI name="purpose" valKind="RO" valImport="false">
<Val>DYN_LDAGSA2_Circuit I phase A amplitude_1_Vector</Val>
</DAI>
<DAI name="setSrcRef" valKind="RO" valImport="false">
</DAI>
</DOI>
</LN0>
</LDevice>
</Server>
</AccessPoint>
</IED>
<DataTypeTemplates>
<LNodeType lnClass="LLN0" id="LLN0_ID1">
<DO name="Mod" type="DO2" transient="false" />
<DO name="InRef1" type="InRefType"/>
<DO name="InRef2" type="InRefType"/>
<DO name="InRef3" type="InRefType"/>
<DO name="InRef4" type="InRefType"/>
</LNodeType>
<DOType cdc="ENC" id="DO2">
<DA fc="ST" dchg="true" qchg="false" dupd="false" name="stVal" bType="Enum" type="BehaviourModeKind" valImport="true" />
<DA fc="BL" name="daName1" bType="BOOLEAN"/>
</DOType>
<DOType cdc="ORG" id="InRefType">
<DA fc="SP" dchg="true" qchg="false" dupd="false" name="setSrcRef" bType="ObjRef"/>
<DA fc="DC" dchg="false" qchg="false" dupd="false" name="purpose" bType="VisString255" valKind="RO" valImport="false"/>
</DOType>
<EnumType id="BehaviourModeKind">
<EnumVal ord="1">on</EnumVal>
<EnumVal ord="2">off</EnumVal>
<EnumVal ord="3">blocked</EnumVal>
<EnumVal ord="4">test</EnumVal>
<EnumVal ord="5">test/blocked</EnumVal>
</EnumType>
</DataTypeTemplates>
</SCL>
Loading