com.farao_community.farao.data.crac_impl.CracImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of farao-crac-impl Show documentation
Show all versions of farao-crac-impl Show documentation
Object model for CRAC implementation
/*
* Copyright (c) 2019, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package com.farao_community.farao.data.crac_impl;
import com.farao_community.farao.commons.FaraoException;
import com.farao_community.farao.data.crac_api.*;
import com.farao_community.farao.data.crac_api.cnec.*;
import com.farao_community.farao.data.crac_api.network_action.NetworkAction;
import com.farao_community.farao.data.crac_api.network_action.NetworkActionAdder;
import com.farao_community.farao.data.crac_api.range_action.*;
import com.farao_community.farao.data.crac_api.usage_rule.OnContingencyState;
import com.farao_community.farao.data.crac_api.usage_rule.UsageMethod;
import java.util.*;
import java.util.stream.Collectors;
import static java.lang.String.format;
/**
* Business object of the CRAC file.
*
* @author Viktor Terrier {@literal }
*/
public class CracImpl extends AbstractIdentifiable implements Crac {
private static final String ADD_ELEMENT_TO_CRAC_ERROR_MESSAGE = "Please add %s to crac first.";
private static final String SAME_ELEMENT_ID_DIFFERENT_NAME_ERROR_MESSAGE = "A network element with the same ID (%s) but a different name already exists.";
private final Map networkElements = new HashMap<>();
private final Map contingencies = new HashMap<>();
private final Map states = new HashMap<>();
private final Map flowCnecs = new HashMap<>();
private final Map angleCnecs = new HashMap<>();
private final Map voltageCnecs = new HashMap<>();
private final Map pstRangeActions = new HashMap<>();
private final Map hvdcRangeActions = new HashMap<>();
private final Map injectionRangeActions = new HashMap<>();
private final Map networkActions = new HashMap<>();
public CracImpl(String id, String name) {
super(id, name);
}
public CracImpl(String id) {
this(id, id);
}
// ========================================
// region NetworkElements management
// ========================================
Set getNetworkElements() {
return new HashSet<>(networkElements.values());
}
NetworkElement getNetworkElement(String id) {
return networkElements.getOrDefault(id, null);
}
/**
* Removes NetworkElement objects from the Crac, if they are not used within other objects of the Crac.
* Only NetworkElement objects that are not referenced are removed.
* @param networkElementIds: IDs of the network elements to remove
*/
void safeRemoveNetworkElements(Set networkElementIds) {
networkElementIds.stream()
.filter(networkElementId -> !isNetworkElementUsedWithinCrac(networkElementId))
.forEach(networkElements::remove);
}
/**
* Check if a NetworkElement is referenced in the CRAC (ie in a Contingency, a Cnec or a RemedialAction)
* @param networkElementId: ID of the NetworkElement
* @return true if the NetworkElement is referenced in a Contingency, a Cnec or a RemedialAction
*/
private boolean isNetworkElementUsedWithinCrac(String networkElementId) {
return getContingencies().stream()
.flatMap(co -> co.getNetworkElements().stream())
.anyMatch(ne -> ne.getId().equals(networkElementId))
|| getCnecs().stream()
.map(Cnec::getNetworkElements)
.flatMap(Set::stream)
.anyMatch(ne -> ((NetworkElement) ne).getId().equals(networkElementId))
|| getRemedialActions().stream()
.map(RemedialAction::getNetworkElements)
.flatMap(Set::stream)
.anyMatch(ne -> ne.getId().equals(networkElementId));
}
/**
* This method add a network element to the crac internal set and returns a network element of this set.
* If an element with the same data is already added, the element of the internal set will be returned,
* otherwise it is created and then returned. An error is thrown when an element with an already
* existing ID is added with a different name.
*
* @param networkElementId: network element ID as in network files
* @param networkElementName: network element name for more human readable name
* @return a network element object that is already defined in the crac
*/
NetworkElement addNetworkElement(String networkElementId, String networkElementName) {
String name = (networkElementName != null) ? networkElementName : networkElementId;
NetworkElement cracNetworkElement = getNetworkElement(networkElementId);
if (cracNetworkElement == null) {
cracNetworkElement = new NetworkElementImpl(networkElementId, name);
} else if (!cracNetworkElement.getName().equals(name)) {
throw new FaraoException(format(SAME_ELEMENT_ID_DIFFERENT_NAME_ERROR_MESSAGE, networkElementId));
}
networkElements.put(networkElementId, cracNetworkElement);
return cracNetworkElement;
}
//endregion
// ========================================
// region Contingencies management
// ========================================
@Override
public ContingencyAdder newContingency() {
return new ContingencyAdderImpl(this);
}
@Override
public Set getContingencies() {
return new HashSet<>(contingencies.values());
}
@Override
public Contingency getContingency(String id) {
return contingencies.get(id);
}
@Override
public void removeContingency(String id) {
if (isContingencyUsedWithinCrac(id)) {
throw new FaraoException(format("Contingency %s is used within a CNEC or an OnContingencyState UsageRule. Please remove all references to the contingency first.", id));
} else {
Contingency contingency = contingencies.get(id);
if (contingency != null) {
contingencies.remove(id);
safeRemoveNetworkElements(contingency.getNetworkElements().stream().map(NetworkElement::getId).collect(Collectors.toSet()));
safeRemoveStates(getStates(contingency).stream().map(State::getId).collect(Collectors.toSet()));
}
}
}
void addContingency(Contingency contingency) {
contingencies.put(contingency.getId(), contingency);
}
/**
* Check if a Contingency is referenced in the CRAC (ie in a Cnec or in a RemedialAction's UsageRule)
* @param contingencyId: ID of the Contingency
* @return true if the Contingency is referenced in a Cnec or in a RemedialAction's UsageRule
*/
private boolean isContingencyUsedWithinCrac(String contingencyId) {
return getCnecs().stream().anyMatch(cnec -> cnec.getState().getContingency().isPresent()
&& cnec.getState().getContingency().get().getId().equals(contingencyId))
|| getRemedialActions().stream().map(RemedialAction::getUsageRules).flatMap(List::stream)
.anyMatch(usageMethod -> (usageMethod instanceof OnContingencyStateImpl)
&& ((OnContingencyStateImpl) usageMethod).getContingency().getId().equals(contingencyId));
}
//endregion
// ========================================
// region States management
// ========================================
@Override
public final Set getStates() {
return new HashSet<>(states.values());
}
@Override
public State getPreventiveState() {
return states.get("preventive");
}
@Override
public SortedSet getStates(Contingency contingency) {
Objects.requireNonNull(contingency, "Contingency must not be null when getting states.");
return states.values().stream()
.filter(state -> state.getContingency().isPresent() && state.getContingency().get().getId().equals(contingency.getId()))
.collect(Collectors.toCollection(TreeSet::new));
}
@Override
public Set getStates(Instant instant) {
return states.values().stream()
.filter(state -> state.getInstant().equals(instant))
.collect(Collectors.toSet());
}
@Override
public State getState(Contingency contingency, Instant instant) {
Objects.requireNonNull(contingency, "Contingency must not be null when getting a state.");
return states.get(contingency.getId() + " - " + instant.toString());
}
State addPreventiveState() {
if (getPreventiveState() != null) {
return getPreventiveState();
} else {
State state = new PreventiveState();
states.put(state.getId(), state);
return state;
}
}
State addState(Contingency contingency, Instant instant) {
Objects.requireNonNull(contingency, "Contingency must not be null when adding a state.");
if (instant.equals(Instant.PREVENTIVE)) {
throw new FaraoException("Impossible to add a preventive state with a contingency.");
}
if (getState(contingency, instant) != null) {
return getState(contingency, instant);
} else {
if (!contingencies.containsKey(contingency.getId())) {
throw new FaraoException(format(ADD_ELEMENT_TO_CRAC_ERROR_MESSAGE, contingency.getId()));
}
State state = new PostContingencyState(getContingency(contingency.getId()), instant);
states.put(state.getId(), state);
return state;
}
}
/**
* Removes State objects from the Crac, if they are not used within other objects of the Crac
* Only State objects that are not referenced are removed.
* @param stateIds: IDs of the States to remove
*/
void safeRemoveStates(Set stateIds) {
stateIds.stream()
.filter(stateId -> !isStateUsedWithinCrac(stateId))
.forEach(states::remove);
}
/**
* Check if a State is referenced in the CRAC (ie in a Cnec or a RemedialAction's UsageRule)
* @param stateId: ID of the State
* @return true if the State is referenced in a Cnec or a RemedialAction's UsageRule
*/
private boolean isStateUsedWithinCrac(String stateId) {
return getCnecs().stream()
.anyMatch(cnec -> cnec.getState().getId().equals(stateId))
|| getRemedialActions().stream()
.map(RemedialAction::getUsageRules)
.flatMap(List::stream)
.anyMatch(ur -> ur instanceof OnContingencyState && ((OnContingencyState) ur).getState().getId().equals(stateId));
}
//endregion
// ========================================
// region Cnec management
// ========================================
@Override
public FlowCnecAdder newFlowCnec() {
return new FlowCnecAdderImpl(this);
}
@Override
public AngleCnecAdder newAngleCnec() {
return new AngleCnecAdderImpl(this);
}
@Override
public VoltageCnecAdder newVoltageCnec() {
return new VoltageCnecAdderImpl(this);
}
@Override
public Set getCnecs() {
Set cnecs = new HashSet<>();
cnecs.addAll(getFlowCnecs());
cnecs.addAll(getAngleCnecs());
cnecs.addAll(getVoltageCnecs());
return cnecs;
}
@Override
public Set getCnecs(State state) {
Set cnecs = new HashSet<>();
cnecs.addAll(getFlowCnecs(state));
cnecs.addAll(getAngleCnecs(state));
cnecs.addAll(getVoltageCnecs(state));
return cnecs;
}
@Override
public Cnec getCnec(String cnecId) {
if (flowCnecs.containsKey(cnecId)) {
return getFlowCnec(cnecId);
} else if (angleCnecs.containsKey(cnecId)) {
return getAngleCnec(cnecId);
} else if (voltageCnecs.containsKey(cnecId)) {
return getVoltageCnec(cnecId);
}
return null;
}
/**
* Find a BranchCnec by its id, returns null if the BranchCnec does not exists
*
* @deprecated consider using getCnec() or getFlowCnec() instead
*/
@Override
@Deprecated (since = "3.0.0")
public BranchCnec getBranchCnec(String id) {
return getFlowCnec(id);
}
/**
* Gather all the BranchCnecs present in the Crac. It returns a set because Cnecs
* must not be duplicated and there is no defined order for Cnecs.
*
* @deprecated consider using getCnecs() or getFlowCnecs() instead
*/
@Override
@Deprecated (since = "3.0.0")
public Set getBranchCnecs() {
return new HashSet<>(flowCnecs.values());
}
/**
* Gather all the BranchCnecs of a specified State. It returns a set because Cnecs
* must not be duplicated and there is no defined order for Cnecs.
*
* @deprecated consider using getCnecs() or getFlowCnecs() instead
*/
@Override
@Deprecated (since = "3.0.0")
public Set getBranchCnecs(State state) {
return new HashSet<>(getFlowCnecs(state));
}
@Override
public FlowCnec getFlowCnec(String flowCnecId) {
return flowCnecs.get(flowCnecId);
}
@Override
public Set getFlowCnecs() {
return new HashSet<>(flowCnecs.values());
}
@Override
public Set getFlowCnecs(State state) {
return flowCnecs.values().stream()
.filter(cnec -> cnec.getState().equals(state))
.collect(Collectors.toSet());
}
@Override
public AngleCnec getAngleCnec(String angleCnecId) {
return angleCnecs.get(angleCnecId);
}
@Override
public Set getAngleCnecs() {
return new HashSet<>(angleCnecs.values());
}
@Override
public Set getAngleCnecs(State state) {
return angleCnecs.values().stream()
.filter(cnec -> cnec.getState().equals(state))
.collect(Collectors.toSet());
}
@Override
public VoltageCnec getVoltageCnec(String voltageCnecId) {
return voltageCnecs.get(voltageCnecId);
}
@Override
public Set getVoltageCnecs() {
return new HashSet<>(voltageCnecs.values());
}
@Override
public Set getVoltageCnecs(State state) {
return voltageCnecs.values().stream()
.filter(cnec -> cnec.getState().equals(state))
.collect(Collectors.toSet());
}
@Override
public void removeCnec(String cnecId) {
removeFlowCnec(cnecId);
removeAngleCnec(cnecId);
removeVoltageCnec(cnecId);
}
@Override
public void removeFlowCnec(String flowCnecId) {
removeFlowCnecs(Collections.singleton(flowCnecId));
}
@Override
public void removeFlowCnecs(Set flowCnecsIds) {
Set flowCnecsToRemove = flowCnecsIds.stream().map(flowCnecs::get).filter(Objects::nonNull).collect(Collectors.toSet());
Set networkElementsToRemove = flowCnecsToRemove.stream().map(cnec -> cnec.getNetworkElement().getId()).collect(Collectors.toSet());
Set statesToRemove = flowCnecsToRemove.stream().map(Cnec::getState).map(State::getId).collect(Collectors.toSet());
flowCnecsToRemove.forEach(flowCnecToRemove ->
flowCnecs.remove(flowCnecToRemove.getId())
);
safeRemoveNetworkElements(networkElementsToRemove);
safeRemoveStates(statesToRemove);
}
@Override
public void removeAngleCnec(String angleCnecId) {
removeAngleCnecs(Collections.singleton(angleCnecId));
}
@Override
public void removeAngleCnecs(Set angleCnecsIds) {
Set angleCnecsToRemove = angleCnecsIds.stream().map(angleCnecs::get).filter(Objects::nonNull).collect(Collectors.toSet());
Set networkElementsToRemove = angleCnecsToRemove.stream().map(Cnec::getNetworkElements)
.flatMap(Set::stream).map(Identifiable::getId).collect(Collectors.toSet());
Set statesToRemove = angleCnecsToRemove.stream().map(Cnec::getState).map(State::getId).collect(Collectors.toSet());
angleCnecsToRemove.forEach(angleCnecToRemove ->
angleCnecs.remove(angleCnecToRemove.getId())
);
safeRemoveNetworkElements(networkElementsToRemove);
safeRemoveStates(statesToRemove);
}
@Override
public void removeVoltageCnec(String voltageCnecId) {
removeVoltageCnecs(Collections.singleton(voltageCnecId));
}
@Override
public void removeVoltageCnecs(Set voltageCnecsIds) {
Set voltageCnecsToRemove = voltageCnecsIds.stream().map(voltageCnecs::get).filter(Objects::nonNull).collect(Collectors.toSet());
Set networkElementsToRemove = voltageCnecsToRemove.stream().map(cnec -> cnec.getNetworkElement().getId()).collect(Collectors.toSet());
Set statesToRemove = voltageCnecsToRemove.stream().map(Cnec::getState).map(State::getId).collect(Collectors.toSet());
voltageCnecsToRemove.forEach(voltageCnecToRemove ->
voltageCnecs.remove(voltageCnecToRemove.getId())
);
safeRemoveNetworkElements(networkElementsToRemove);
safeRemoveStates(statesToRemove);
}
void addFlowCnec(FlowCnec flowCnec) {
flowCnecs.put(flowCnec.getId(), flowCnec);
}
void addAngleCnec(AngleCnec angleCnec) {
angleCnecs.put(angleCnec.getId(), angleCnec);
}
void addVoltageCnec(VoltageCnec voltageCnec) {
voltageCnecs.put(voltageCnec.getId(), voltageCnec);
}
// endregion
// ========================================
// region RemedialActions management
// ========================================
@Override
public Set> getRemedialActions() {
Set> remedialActions = new HashSet<>();
remedialActions.addAll(pstRangeActions.values());
remedialActions.addAll(hvdcRangeActions.values());
remedialActions.addAll(injectionRangeActions.values());
remedialActions.addAll(networkActions.values());
return remedialActions;
}
@Override
public RemedialAction> getRemedialAction(String remedialActionId) {
RemedialAction> remedialAction = getNetworkAction(remedialActionId);
if (!Objects.isNull(remedialAction)) {
return remedialAction;
} else {
return getRangeAction(remedialActionId);
}
}
@Override
public void removeRemedialAction(String remedialActionId) {
removeRangeAction(remedialActionId);
removeNetworkAction(remedialActionId);
}
private Set getAssociatedStates(RemedialAction> remedialAction) {
return remedialAction.getUsageRules().stream()
.filter(OnContingencyState.class::isInstance)
.map(ur -> ((OnContingencyState) ur).getState())
.collect(Collectors.toSet());
}
// endregion
// ========================================
// region RangeAction management
// ========================================
@Override
public PstRangeActionAdder newPstRangeAction() {
return new PstRangeActionAdderImpl(this);
}
@Override
public HvdcRangeActionAdder newHvdcRangeAction() {
return new HvdcRangeActionAdderImpl(this);
}
@Override
public InjectionRangeActionAdder newInjectionRangeAction() {
return new InjectionRangeActionAdderImpl(this);
}
@Override
public Set getPstRangeActions() {
return new HashSet<>(pstRangeActions.values());
}
@Override
public Set getHvdcRangeActions() {
return new HashSet<>(hvdcRangeActions.values());
}
@Override
public Set getInjectionRangeActions() {
return new HashSet<>(injectionRangeActions.values());
}
@Override
public PstRangeAction getPstRangeAction(String pstRangeActionId) {
return pstRangeActions.get(pstRangeActionId);
}
@Override
public HvdcRangeAction getHvdcRangeAction(String hvdcRangeActionId) {
return hvdcRangeActions.get(hvdcRangeActionId);
}
@Override
public InjectionRangeAction getInjectionRangeAction(String injectionRangActionId) {
return injectionRangeActions.get(injectionRangActionId);
}
@Override
public Set> getRangeActions() {
Set> rangeActionsSet = new HashSet<>(pstRangeActions.values());
rangeActionsSet.addAll(hvdcRangeActions.values());
rangeActionsSet.addAll(injectionRangeActions.values());
return rangeActionsSet;
}
@Override
public Set> getRangeActions(State state, UsageMethod... usageMethods) {
Set> pstRangeActionsSet = pstRangeActions.values().stream()
.filter(rangeAction -> Arrays.stream(usageMethods).anyMatch(usageMethod -> rangeAction.getUsageMethod(state).equals(usageMethod)))
.collect(Collectors.toSet());
Set> hvdcRangeActionsSet = hvdcRangeActions.values().stream()
.filter(rangeAction -> Arrays.stream(usageMethods).anyMatch(usageMethod -> rangeAction.getUsageMethod(state).equals(usageMethod)))
.collect(Collectors.toSet());
Set> injectionRangeActionSet = injectionRangeActions.values().stream()
.filter(rangeAction -> Arrays.stream(usageMethods).anyMatch(usageMethod -> rangeAction.getUsageMethod(state).equals(usageMethod)))
.collect(Collectors.toSet());
Set> rangeActionsSet = new HashSet<>(pstRangeActionsSet);
rangeActionsSet.addAll(hvdcRangeActionsSet);
rangeActionsSet.addAll(injectionRangeActionSet);
return rangeActionsSet;
}
@Override
public Set> getPotentiallyAvailableRangeActions(State state) {
return getRangeActions(state, UsageMethod.AVAILABLE, UsageMethod.FORCED, UsageMethod.TO_BE_EVALUATED);
}
@Override
public RangeAction> getRangeAction(String id) {
if (pstRangeActions.get(id) != null) {
return pstRangeActions.get(id);
} else if (hvdcRangeActions.get(id) != null) {
return hvdcRangeActions.get(id);
} else {
return injectionRangeActions.get(id);
}
}
public void removeRangeAction(String id) {
if (pstRangeActions.get(id) != null) {
removePstRangeAction(id);
} else if (hvdcRangeActions.get(id) != null) {
removeHvdcRangeAction(id);
} else {
removeInjectionRangeAction(id);
}
}
@Override
public void removePstRangeAction(String id) {
PstRangeAction rangeActionToRemove = pstRangeActions.get(id);
if (Objects.isNull(rangeActionToRemove)) {
return;
}
Set associatedNetworkElementsIds = rangeActionToRemove.getNetworkElements().stream().map(NetworkElement::getId).collect(Collectors.toSet());
Set associatedStatesIds = getAssociatedStates(rangeActionToRemove).stream().map(State::getId).collect(Collectors.toSet());
pstRangeActions.remove(id);
safeRemoveNetworkElements(associatedNetworkElementsIds);
safeRemoveStates(associatedStatesIds);
}
@Override
public void removeHvdcRangeAction(String id) {
HvdcRangeAction rangeActionToRemove = hvdcRangeActions.get(id);
if (Objects.isNull(rangeActionToRemove)) {
return;
}
Set associatedNetworkElementsIds = rangeActionToRemove.getNetworkElements().stream().map(NetworkElement::getId).collect(Collectors.toSet());
Set associatedStatesIds = getAssociatedStates(rangeActionToRemove).stream().map(State::getId).collect(Collectors.toSet());
hvdcRangeActions.remove(id);
safeRemoveNetworkElements(associatedNetworkElementsIds);
safeRemoveStates(associatedStatesIds);
}
@Override
public void removeInjectionRangeAction(String id) {
InjectionRangeAction rangeActionToRemove = injectionRangeActions.get(id);
if (Objects.isNull(rangeActionToRemove)) {
return;
}
Set associatedNetworkElementsIds = rangeActionToRemove.getNetworkElements().stream().map(NetworkElement::getId).collect(Collectors.toSet());
Set associatedStatesIds = getAssociatedStates(rangeActionToRemove).stream().map(State::getId).collect(Collectors.toSet());
injectionRangeActions.remove(id);
safeRemoveNetworkElements(associatedNetworkElementsIds);
safeRemoveStates(associatedStatesIds);
}
void addPstRangeAction(PstRangeAction pstRangeAction) {
pstRangeActions.put(pstRangeAction.getId(), pstRangeAction);
}
void addHvdcRangeAction(HvdcRangeAction hvdcRangeAction) {
hvdcRangeActions.put(hvdcRangeAction.getId(), hvdcRangeAction);
}
void addInjectionRangeAction(InjectionRangeAction injectionRangeAction) {
injectionRangeActions.put(injectionRangeAction.getId(), injectionRangeAction);
}
// endregion
// ========================================
// region NetworkAction management
// ========================================
@Override
public Set getNetworkActions() {
return new HashSet<>(networkActions.values());
}
@Override
public Set getNetworkActions(State state, UsageMethod... usageMethods) {
return networkActions.values().stream()
.filter(networkAction -> Arrays.stream(usageMethods).anyMatch(usageMethod -> networkAction.getUsageMethod(state).equals(usageMethod)))
.collect(Collectors.toSet());
}
@Override
public Set getPotentiallyAvailableNetworkActions(State state) {
return getNetworkActions(state, UsageMethod.AVAILABLE, UsageMethod.FORCED, UsageMethod.TO_BE_EVALUATED);
}
@Override
public NetworkAction getNetworkAction(String id) {
return networkActions.get(id);
}
@Override
public NetworkActionAdder newNetworkAction() {
return new NetworkActionAdderImpl(this);
}
@Override
public void removeNetworkAction(String id) {
NetworkAction networkActionToRemove = networkActions.get(id);
if (Objects.isNull(networkActionToRemove)) {
return;
}
Set associatedNetworkElementsIds = networkActionToRemove.getNetworkElements().stream().map(NetworkElement::getId).collect(Collectors.toSet());
Set associatedStatesIds = getAssociatedStates(networkActionToRemove).stream().map(State::getId).collect(Collectors.toSet());
networkActions.remove(id);
safeRemoveNetworkElements(associatedNetworkElementsIds);
safeRemoveStates(associatedStatesIds);
}
void addNetworkAction(NetworkAction networkAction) {
networkActions.put(networkAction.getId(), networkAction);
}
// endregion
}