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

Release 0.2.28 #419

Merged
merged 6 commits into from
Aug 26, 2024
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;
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 @@ -66,6 +66,7 @@ public class LDeviceAdapter extends SclElementAdapter<IEDAdapter, TLDevice> {
private static final long INTG_PD_VALUE_FOR_FC_MX = 2000L;

private static final String DA_SETSRCREF = "setSrcRef";
private static final String CYC_REPORT_TYPE = "CYC";

/**
* Constructor
Expand Down Expand Up @@ -94,19 +95,19 @@ public void createHmiReportControlBlocks(PO po) {
findLnAdapter(tfcdaFilter.getLnClass(), tfcdaFilter.getLnInst(), tfcdaFilter.getPrefix()).filter(lnAdapter -> lnAdapter.getDaiModStValValue().map(ActiveStatus::fromValue).map(ActiveStatus.ON::equals).orElse(true)))
.map(sourceLn -> sourceLn.getDAI(new DataAttributeRef(toFCDA(tfcdaFilter)), false))
.filter(das -> das.stream().anyMatch(da -> TFCEnum.fromValue(tfcdaFilter.getFc().value()) == da.getFc())) // getDAI does not filter on DA.
.ifPresent(dataAttributeRefs -> createHmiReportCB(ln0, toFCDA(tfcdaFilter))));
.ifPresent(dataAttributeRefs -> createHmiReportCB(ln0, tfcdaFilter)));
}

private void createHmiReportCB(LN0Adapter ln0, TFCDA fcda) {
boolean isFcMx = fcda.getFc() == TFCEnum.MX;
String dataSetSuffix = getInst().toUpperCase(Locale.ENGLISH) + ATTRIBUTE_VALUE_SEPARATOR + (isFcMx ? "CYPO" : "DQPO");
private void createHmiReportCB(LN0Adapter ln0, TFCDAFilter tfcdaFilter) {
TFCDA fcda = toFCDA(tfcdaFilter);
String dataSetSuffix = getInst().toUpperCase(Locale.ENGLISH) + ATTRIBUTE_VALUE_SEPARATOR + tfcdaFilter.getReportType().substring(0, 2) + "PO";
String dataSetName = DATASET_NAME_PREFIX + dataSetSuffix;
DataSetAdapter dataSet = ln0.createDataSetIfNotExists(dataSetName, ControlBlockEnum.REPORT);
dataSet.createFCDAIfNotExists(fcda.getLdInst(), fcda.getPrefix(), fcda.getLnClass().get(0), fcda.getLnInst(), fcda.getDoName(), fcda.getDaName(), fcda.getFc());
dataSet.createFCDAIfNotExists(fcda.getLdInst(), fcda.getPrefix(), fcda.getLnClass().getFirst(), fcda.getLnInst(), fcda.getDoName(), fcda.getDaName(), fcda.getFc());
String cbName = CONTROLBLOCK_NAME_PREFIX + dataSetSuffix;
String cbId = ln0.generateControlBlockId(getLdName(), cbName);
ControlBlockAdapter controlBlockAdapter = ln0.createControlBlockIfNotExists(cbName, cbId, dataSetName, ControlBlockEnum.REPORT);
if (isFcMx) {
if (tfcdaFilter.getReportType().equals(CYC_REPORT_TYPE)) {
TReportControl tReportControl = (TReportControl) controlBlockAdapter.getCurrentElem();
tReportControl.setIntgPd(INTG_PD_VALUE_FOR_FC_MX);
tReportControl.getTrgOps().setDchg(false);
Expand Down Expand Up @@ -478,7 +479,7 @@ private void updateNewCreatedLnDaiValue(TLN tln, TExtRef tExtRef, String lnInst,
private String createVal(TExtRef tExtRef) {
String sourceLdName = getParentAdapter().getParentAdapter().getIEDAdapterByName(tExtRef.getIedName())
.getLDeviceAdapterByLdInst(tExtRef.getSrcLDInst()).getLdName();
String lnClass = !tExtRef.isSetSrcLNClass() ? TLLN0Enum.LLN_0.value() : tExtRef.getSrcLNClass().get(0);
String lnClass = !tExtRef.isSetSrcLNClass() ? TLLN0Enum.LLN_0.value() : tExtRef.getSrcLNClass().getFirst();
return sourceLdName + "/" + lnClass + "." + tExtRef.getSrcCBName();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@
import org.apache.commons.lang3.tuple.Pair;
import org.lfenergy.compas.scl2007b4.model.*;
import org.lfenergy.compas.sct.commons.dto.*;
import org.lfenergy.compas.sct.commons.scl.ldevice.LDeviceActivation;
import org.lfenergy.compas.sct.commons.scl.ObjectReference;
import org.lfenergy.compas.sct.commons.scl.ied.InputsAdapter;
import org.lfenergy.compas.sct.commons.scl.ldevice.LDeviceActivation;
import org.lfenergy.compas.sct.commons.scl.ldevice.LDeviceAdapter;
import org.lfenergy.compas.sct.commons.util.PrivateUtils;

import java.util.List;
import java.util.Optional;
import java.util.Set;
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 All @@ -47,9 +47,6 @@
* <li>{@link LN0Adapter#getDAI <em>Returns the value of the <b>DataAttributeRef </b> containment reference By filter</em>}</li>
* <li>{@link LN0Adapter#getDAIValues(DataAttributeRef) <em>Returns <b>DAI (sGroup, value) </b> containment reference list By <b>DataAttributeRef </b> filter</em>}</li>
*
* <li>{@link LN0Adapter#getDataSetByName(String) <em>Returns the value of the <b>TDataSet </b>object reference By the value of the <b>name </b>attribute </em>}</li>
*
* <li>{@link LN0Adapter#getControlBlocks(List, TServiceType) <em>Returns the value of the <b>ControlBlock </b>containment reference list that match <b>datSet </b> value of given <b>TDataSet</b> </em>}</li>
* <li>{@link LN0Adapter#addPrivate <em>Add <b>TPrivate </b>under this object</em>}</li>
* <li>{@link LN0Adapter#removeAllControlBlocksAndDatasets() <em>Remove all <b>ControlBlock</b></em>}</li>
* </ul>
Expand All @@ -73,8 +70,7 @@ 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");

/**
* Constructor
Expand Down Expand Up @@ -188,7 +184,7 @@ public Optional<SclReportItem> updateLDeviceStatus(List<Pair<String, String>> ie
if (daiBehList.isEmpty()) {
return Optional.of(buildFatalReportItem("The LDevice doesn't have a DO @name='Beh' OR its associated DA@fc='ST' AND DA@name='stVal'"));
}
Set<String> enumValues = getEnumValues(daiBehList.get(0).getDaName().getType());
Set<String> enumValues = getEnumValues(daiBehList.getFirst().getDaName().getType());
Optional<TCompasLDevice> optionalTCompasLDevice = PrivateUtils.extractCompasPrivate(getParentAdapter().getCurrentElem(), TCompasLDevice.class);
if (optionalTCompasLDevice.isEmpty()) {
return Optional.of(buildFatalReportItem("The LDevice doesn't have a Private compas:LDevice."));
Expand Down Expand Up @@ -234,16 +230,26 @@ 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(getBoundExtRefsByDesc(tVal.getValue())))
.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()))))
)
.flatMap(List::stream)
.collect(Collectors.toList());
}

private List<TExtRef> getExtRefsBoundToInRef(String desc) {
List<TExtRef> boundExtRefs = getBoundExtRefsByDesc(desc);
// Special case for LDEPF DIGITAL CHANNEL of type BOOLEAN RSR-1048
if (boundExtRefs.isEmpty() && LDEFP_DIGITAL_CHANNEL_PATTERN.matcher(desc).matches()) {
String descWithoutType = desc.substring(0, desc.lastIndexOf("_"));
return getBoundExtRefsByDesc(descWithoutType);
}
return boundExtRefs;
}

private List<TExtRef> getBoundExtRefsByDesc(String desc) {
return getExtRefs().stream()
.filter(tExtRef -> tExtRef.isSetIedName() && tExtRef.isSetLdInst() && tExtRef.isSetLnClass() && tExtRef.isSetDoName() &&
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 @@ -60,6 +60,7 @@ SPDX-License-Identifier: Apache-2.0
<xs:attribute name="lnInst" type="xs:string" use="required"/>
<xs:attribute name="doName" type="xs:string" use="required"/>
<xs:attribute name="fc" type="tfc" use="required"/>
<xs:attribute name="reportType" type="xs:string" use="required"/>
</xs:complexType>

<xs:simpleType name="tfc">
Expand All @@ -69,4 +70,4 @@ SPDX-License-Identifier: Apache-2.0
</xs:restriction>
</xs:simpleType>

</xs:schema>
</xs:schema>
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();
}
}
Loading
Loading