Skip to content

Commit

Permalink
feat(#413): LDEPF Post processing - unused CHANNEL assignment
Browse files Browse the repository at this point in the history
LDEPF Post processing -  reviews

Signed-off-by: Samir Romdhani <[email protected]>
  • Loading branch information
samirromdhani committed Aug 23, 2024
1 parent 354b68d commit d4d5674
Show file tree
Hide file tree
Showing 7 changed files with 210 additions and 7 deletions.
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;
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");
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>

0 comments on commit d4d5674

Please sign in to comment.