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 / deconstructing compas-flow #442

Merged
merged 2 commits into from
Dec 9, 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
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2023 RTE FRANCE
// SPDX-FileCopyrightText: 2023 2024 RTE FRANCE
//
// SPDX-License-Identifier: Apache-2.0

Expand All @@ -15,41 +15,26 @@
import org.lfenergy.compas.sct.commons.model.epf.TCBScopeType;
import org.lfenergy.compas.sct.commons.model.epf.TChannel;
import org.lfenergy.compas.sct.commons.model.epf.TChannelType;
import org.lfenergy.compas.sct.commons.scl.ExtRefService;
import org.lfenergy.compas.sct.commons.scl.SclRootAdapter;
import org.lfenergy.compas.sct.commons.scl.ied.IEDAdapter;
import org.lfenergy.compas.sct.commons.scl.ldevice.LDeviceAdapter;
import org.lfenergy.compas.sct.commons.scl.ln.AbstractLNAdapter;
import org.lfenergy.compas.sct.commons.scl.ln.LN0Adapter;
import org.lfenergy.compas.sct.commons.util.ActiveStatus;
import org.lfenergy.compas.sct.commons.util.PrivateEnum;
import org.lfenergy.compas.sct.commons.util.PrivateUtils;
import org.lfenergy.compas.sct.commons.util.Utils;

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

import static org.apache.commons.lang3.StringUtils.*;
import static org.lfenergy.compas.sct.commons.util.CommonConstants.*;

@RequiredArgsConstructor
public class ExtRefEditorService implements ExtRefEditor {
private static final String INVALID_OR_MISSING_ATTRIBUTES_IN_EXT_REF_BINDING_INFO = "Invalid or missing attributes in ExtRef binding info";
samirromdhani marked this conversation as resolved.
Show resolved Hide resolved
private static final Map<String, String> voltageCodification = Map.of(
"3", "HT",
"4", "HT",
"5", "THT",
"6", "THT",
"7", "THT"
);

private final IedService iedService;
private final LdeviceService ldeviceService;
private final LnEditor lnEditor;
private final ExtRefService extRefService;
private final DataTypeTemplatesService dataTypeTemplatesService;

/**
Expand Down Expand Up @@ -274,31 +259,6 @@ public TExtRef updateExtRefSource(SCL scd, ExtRefInfo extRefInfo) throws ScdExce
return anLNAdapter.updateExtRefSource(extRefInfo);
}

@Override
public List<SclReportItem> updateAllExtRefIedNames(SCL scd) {
SclRootAdapter sclRootAdapter = new SclRootAdapter(scd);
List<SclReportItem> iedErrors = validateIed(sclRootAdapter);
if (!iedErrors.isEmpty()) {
samirromdhani marked this conversation as resolved.
Show resolved Hide resolved
return iedErrors;
}
Map<String, IEDAdapter> icdSystemVersionToIed = sclRootAdapter.streamIEDAdapters()
.collect(Collectors.toMap(
iedAdapter -> iedAdapter.getCompasICDHeader()
.map(TCompasICDHeader::getICDSystemVersionUUID)
.orElseThrow(), // Value presence is checked by method validateIed called above
Function.identity()
));

return sclRootAdapter.streamIEDAdapters()
.flatMap(IEDAdapter::streamLDeviceAdapters)
.filter(LDeviceAdapter::hasLN0)
.map(LDeviceAdapter::getLN0Adapter)
.filter(LN0Adapter::hasInputs)
.map(LN0Adapter::getInputsAdapter)
.map(inputsAdapter -> inputsAdapter.updateAllExtRefIedNames(icdSystemVersionToIed))
.flatMap(List::stream).toList();
}

@Override
public List<SclReportItem> manageBindingForLDEPF(SCL scd, EPF epf) {
List<SclReportItem> sclReportItems = new ArrayList<>();
Expand Down Expand Up @@ -361,48 +321,6 @@ public void epfPostProcessing(SCL scd) {
})));
}

private List<SclReportItem> validateIed(SclRootAdapter sclRootAdapter) {
List<SclReportItem> iedErrors = new ArrayList<>(checkIedCompasIcdHeaderAttributes(sclRootAdapter));
iedErrors.addAll(checkIedUnityOfIcdSystemVersionUuid(sclRootAdapter));
return iedErrors;
}

private List<SclReportItem> checkIedCompasIcdHeaderAttributes(SclRootAdapter sclRootAdapter) {
return sclRootAdapter.streamIEDAdapters()
.map(iedAdapter -> {
Optional<TCompasICDHeader> compasPrivate = iedAdapter.getCompasICDHeader();
if (compasPrivate.isEmpty()) {
return iedAdapter.buildFatalReportItem(String.format("IED has no Private %s element", PrivateEnum.COMPAS_ICDHEADER.getPrivateType()));
}
if (isBlank(compasPrivate.get().getICDSystemVersionUUID())
|| isBlank(compasPrivate.get().getIEDName())) {
return iedAdapter.buildFatalReportItem(String.format("IED private %s as no icdSystemVersionUUID or iedName attribute",
PrivateEnum.COMPAS_ICDHEADER.getPrivateType()));
}
return null;
}
).filter(Objects::nonNull)
.toList();
}

private List<SclReportItem> checkIedUnityOfIcdSystemVersionUuid(SclRootAdapter sclRootAdapter) {
Map<String, List<TIED>> systemVersionToIedList = sclRootAdapter.getCurrentElem().getIED().stream()
.collect(Collectors.groupingBy(ied -> PrivateUtils.extractCompasPrivate(ied, TCompasICDHeader.class)
.map(TCompasICDHeader::getICDSystemVersionUUID)
.orElse("")));

return systemVersionToIedList.entrySet().stream()
.filter(entry -> isNotBlank(entry.getKey()))
.filter(entry -> entry.getValue().size() > 1)
.map(entry -> SclReportItem.error(entry.getValue().stream()
.map(tied -> new IEDAdapter(sclRootAdapter, tied))
.map(IEDAdapter::getXPath)
.collect(Collectors.joining(", ")),
"/IED/Private/compas:ICDHeader[@ICDSystemVersionUUID] must be unique" +
" but the same ICDSystemVersionUUID was found on several IED."))
.toList();
}

private void updateLDEPFExtRefBinding(TExtRef extRef, TIED iedSource, TChannel setting) {
extRef.setIedName(iedSource.getName());
extRef.setLdInst(setting.getLDInst());
Expand Down Expand Up @@ -456,122 +374,20 @@ private String computeDaiValue(AbstractLNAdapter<?> lnAdapter, TExtRef extRef, S
return extRef.getIedName() +
extRef.getLdInst() + "/" +
trimToEmpty(extRef.getPrefix()) +
extRef.getLnClass().get(0) +
extRef.getLnClass().getFirst() +
trimToEmpty(extRef.getLnInst()) + "." +
extRef.getDoName() + "." + Q_DA_NAME;
} else {
return extRef.getIedName() +
extRef.getLdInst() + "/" +
trimToEmpty(extRef.getPrefix()) +
extRef.getLnClass().get(0) +
extRef.getLnClass().getFirst() +
trimToEmpty(extRef.getLnInst()) + "." +
extRef.getDoName() + "." +
daName;
}
}

@Override
public void debindCompasFlowsAndExtRefsBasedOnVoltageLevel(SCL scd) {
scd.getSubstation()
.stream()
.flatMap(tSubstation -> tSubstation.getVoltageLevel().stream())
.map(TVoltageLevel::getName)
.filter(tVoltageLevelName -> !"0".equals(tVoltageLevelName))
.forEach(tVoltageLevelName -> scd.getIED().stream()
.flatMap(ldeviceService::getLdevices)
.filter(TLDevice::isSetLN0)
.filter(tlDevice -> tlDevice.getLN0().isSetInputs())
.forEach(tlDevice -> {
String flowSource = voltageCodification.get(tVoltageLevelName);
extRefService.getCompasFlows(tlDevice)
.filter(TCompasFlow::isSetFlowSourceVoltageLevel)
.filter(TCompasFlow::isSetExtRefiedName)
.forEach(tCompasFlow -> {
if (!tCompasFlow.getFlowSourceVoltageLevel().equals(flowSource)) {
//debind extRefs correspondind to compas flow
extRefService.getMatchingExtRefs(tlDevice, tCompasFlow)
.forEach(extRefService::clearExtRefBinding);
//debind all compas flow
extRefService.clearCompasFlowBinding(tCompasFlow);
}
});
})
);
}


@Override
public List<SclReportItem> updateIedNameBasedOnLnode(SCL scl) {
Map<TopoKey, TBay> bayByTopoKey = scl.getSubstation().stream()
.flatMap(tSubstation -> tSubstation.getVoltageLevel().stream())
.flatMap(tVoltageLevel -> tVoltageLevel.getBay().stream())
.map(tBay -> PrivateUtils.extractCompasPrivate(tBay, TCompasTopo.class)
.filter(tCompasTopo -> isNotBlank(tCompasTopo.getNode()) && Objects.nonNull(tCompasTopo.getNodeOrder()))
.map(tCompasTopo -> new BayTopoKey(tBay, new TopoKey(tCompasTopo.getNode(), tCompasTopo.getNodeOrder())))
)
samirromdhani marked this conversation as resolved.
Show resolved Hide resolved
.flatMap(Optional::stream)
.collect(Collectors.toMap(BayTopoKey::topoKey, BayTopoKey::bay));

List<SclReportItem> sclReportItems = new ArrayList<>();
scl.getIED().stream()
.flatMap(ldeviceService::getLdevices)
.forEach(tlDevice ->
extRefService.getCompasFlows(tlDevice)
.filter(tCompasFlow -> Objects.nonNull(tCompasFlow.getFlowSourceBayNode()) && Objects.nonNull(tCompasFlow.getFlowSourceBayNodeOrder()))
.forEach(tCompasFlow ->
Optional.ofNullable(bayByTopoKey.get(new TopoKey(tCompasFlow.getFlowSourceBayNode().toString(), tCompasFlow.getFlowSourceBayNodeOrder())))
.flatMap(tBay -> tBay.getFunction().stream()
.flatMap(tFunction -> tFunction.getLNode().stream())
.filter(tlNode -> Objects.equals(tlNode.getLdInst(), tCompasFlow.getExtRefldinst())
&& Objects.equals(tlNode.getLnInst(), tCompasFlow.getExtReflnInst())
&& Utils.lnClassEquals(tlNode.getLnClass(), tCompasFlow.getExtReflnClass())
&& Objects.equals(tlNode.getPrefix(), tCompasFlow.getExtRefprefix()))
.filter(tlNode -> {
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)
.reduce(checkOnlyOneIed(tCompasFlow, tBay, sclReportItems))
)
.ifPresentOrElse(iedName -> {
extRefService.getMatchingExtRefs(tlDevice, tCompasFlow).forEach(tExtRef -> tExtRef.setIedName(iedName));
tCompasFlow.setExtRefiedName(iedName);
},
() -> {
extRefService.getMatchingExtRefs(tlDevice, tCompasFlow).forEach(extRefService::clearExtRefBinding);
extRefService.clearCompasFlowBinding(tCompasFlow);
}
)
)
);
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) {
}

record BayTopoKey(TBay bay, TopoKey topoKey) {
}

private record DoNameAndDaName(String doName, String daName) {
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
* <ol>
* <li>{@link ExtRefEditor#updateExtRefBinders <em>Update the <b>TExtRef </b> reference object for given <b>ExtRefBindingInfo </b> model</em>}</li>
* <li>{@link ExtRefEditor#updateExtRefSource <em>Update the <b>TExtRef </b> reference object for given <b>ExtRefSourceInfo </b> model</em>}</li>
* <li>{@link ExtRefEditor#updateAllExtRefIedNames <em>Update the iedName attribute in all <b>TExtRef</b></em>}</li>
* <li>{@link ExtRefEditor#manageBindingForLDEPF <em>Manage <b>TExtRef</b> Binding For LDevice (inst=LDEPF) within LDEPF configuration</em>}</li>
* </ol>
* </ul>
Expand All @@ -47,13 +46,6 @@ public interface ExtRefEditor {
*/
TExtRef updateExtRefSource(SCL scd, ExtRefInfo extRefInfo) throws ScdException;

/**
* Updates iedName attribute of all ExtRefs in the Scd.
*
* @return list of encountered errors
*/
List<SclReportItem> updateAllExtRefIedNames(SCL scd);

/**
* ExtRef Binding For LDevice (inst=LDEPF) that matching EPF configuration
*
Expand All @@ -71,18 +63,4 @@ public interface ExtRefEditor {
*/
void epfPostProcessing(SCL scd);

/**
* Debinding of Private CompasFlows and ExtRef signals based on voltageLevel
*
* @param scd SCL file in which ExtRef and Private CompasFlow should be debind
*/
void debindCompasFlowsAndExtRefsBasedOnVoltageLevel(SCL scd);

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

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* // SPDX-FileCopyrightText: 2023 RTE FRANCE
* // SPDX-FileCopyrightText: 2023 2024 RTE FRANCE
* //
* // SPDX-License-Identifier: Apache-2.0
*/
Expand Down Expand Up @@ -52,18 +52,6 @@ public Stream<TCompasFlow> getMatchingCompasFlows(TInputs inputs, TExtRef tExtRe
.filter(compasFlow -> isMatchingExtRef(compasFlow, tExtRef));
}

/**
* Retrieves ExtRefs corresponding to given CompasFlow
*
* @param tlDevice LDevice containing CompasFlows and ExtRefs
* @param tCompasFlow corresponding to Extrefs we are searching
* @return stream of matching ExtRefs
*/
public Stream<TExtRef> getMatchingExtRefs(TLDevice tlDevice, TCompasFlow tCompasFlow) {
return getExtRefs(tlDevice)
.filter(tExtRef -> isMatchingExtRef(tCompasFlow, tExtRef));
}

/**
* Debind ExtRef
*
Expand All @@ -85,18 +73,6 @@ public void clearExtRefBinding(TExtRef extRef) {
extRef.unsetSrcLNClass();
}

/**
* Debind CompasFlow
*
* @param tCompasFlow to debind
*/
public void clearCompasFlowBinding(TCompasFlow tCompasFlow) {
tCompasFlow.setExtRefiedName(null);
tCompasFlow.setExtRefldinst(null);
tCompasFlow.setExtReflnClass(null);
tCompasFlow.setExtReflnInst(null);
tCompasFlow.setExtRefprefix(null);
}

/**
* Check if extRef matches CompasFlow
Expand Down
Loading
Loading