com.farao_community.farao.data.crac_impl.PstRangeActionAdderImpl 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) 2020, 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.range.RangeType;
import com.farao_community.farao.data.crac_api.range.TapRange;
import com.farao_community.farao.data.crac_api.range.TapRangeAdder;
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.OnInstant;
import com.farao_community.farao.data.crac_api.usage_rule.UsageRule;
import java.util.*;
import static com.farao_community.farao.data.crac_impl.AdderUtils.assertAttributeNotNull;
import static com.farao_community.farao.commons.logs.FaraoLoggerProvider.BUSINESS_WARNS;
/**
* @author Peter Mitri {@literal }
* @author Baptiste Seguinot {@literal }
*/
public class PstRangeActionAdderImpl extends AbstractRemedialActionAdder implements PstRangeActionAdder {
public static final String PST_RANGE_ACTION = "PstRangeAction";
private String networkElementId;
private String networkElementName;
private List ranges;
private String groupId = null;
private Integer initialTap = null;
private Map tapToAngleConversionMap;
@Override
protected String getTypeDescription() {
return PST_RANGE_ACTION;
}
PstRangeActionAdderImpl(CracImpl owner) {
super(owner);
this.ranges = new ArrayList<>();
}
@Override
public PstRangeActionAdder withNetworkElement(String networkElementId) {
return withNetworkElement(networkElementId, networkElementId);
}
@Override
public PstRangeActionAdder withNetworkElement(String networkElementId, String networkElementName) {
this.networkElementId = networkElementId;
this.networkElementName = networkElementName;
return this;
}
@Override
public PstRangeActionAdder withGroupId(String groupId) {
this.groupId = groupId;
return this;
}
@Override
public PstRangeActionAdder withInitialTap(int initialTap) {
this.initialTap = initialTap;
return this;
}
@Override
public PstRangeActionAdder withTapToAngleConversionMap(Map tapToAngleConversionMap) {
this.tapToAngleConversionMap = tapToAngleConversionMap;
return this;
}
@Override
public TapRangeAdder newTapRange() {
return new TapRangeAdderImpl(this);
}
@Override
public PstRangeAction add() {
checkId();
checkAutoUsageRules();
assertAttributeNotNull(networkElementId, PST_RANGE_ACTION, "network element", "withNetworkElement()");
assertAttributeNotNull(initialTap, PST_RANGE_ACTION, "initial tap", "withInitialTap()");
assertAttributeNotNull(tapToAngleConversionMap, PST_RANGE_ACTION, "tap to angle conversion map", "withTapToAngleConversionMap()");
if (!Objects.isNull(getCrac().getRemedialAction(id))) {
throw new FaraoException(String.format("A remedial action with id %s already exists", id));
}
List validRanges = checkRanges();
checkTapToAngleConversionMap();
if (usageRules.isEmpty()) {
BUSINESS_WARNS.warn("PstRangeAction {} does not contain any usage rule, by default it will never be available", id);
}
NetworkElement networkElement = this.getCrac().addNetworkElement(networkElementId, networkElementName);
PstRangeActionImpl pstWithRange = new PstRangeActionImpl(this.id, this.name, this.operator, this.usageRules, validRanges, networkElement, groupId, initialTap, tapToAngleConversionMap, speed);
this.getCrac().addPstRangeAction(pstWithRange);
return pstWithRange;
}
void addRange(TapRange pstRange) {
ranges.add(pstRange);
}
private boolean isPreventiveUsageRule(UsageRule usageRule) {
return (usageRule instanceof OnInstant && ((OnInstant) usageRule).getInstant().equals(Instant.PREVENTIVE))
|| (usageRule instanceof OnContingencyState && ((OnContingencyState) usageRule).getInstant().equals(Instant.PREVENTIVE));
}
private List checkRanges() {
// filter RELATIVE_TO_PREVIOUS_INSTANT range if the RA is purely preventive
List validRanges = new ArrayList<>();
if (usageRules.stream().allMatch(this::isPreventiveUsageRule)) {
ranges.forEach(range -> {
if (range.getRangeType().equals(RangeType.RELATIVE_TO_PREVIOUS_INSTANT)) {
BUSINESS_WARNS.warn("RELATIVE_TO_PREVIOUS_INSTANT range has been filtered from PstRangeAction {}, as it is a preventive RA", id);
} else {
validRanges.add(range);
}
});
} else {
validRanges.addAll(ranges);
}
if (validRanges.isEmpty()) {
BUSINESS_WARNS.warn("PstRangeAction {} does not contain any valid range, by default the range of the network will be used", id);
}
return validRanges;
}
private void checkTapToAngleConversionMap() {
if (tapToAngleConversionMap.size() < 2) {
throw new FaraoException(String.format("TapToAngleConversionMap of PST %s should at least contain 2 entries.", id));
}
if (tapToAngleConversionMap.keySet().stream().anyMatch(Objects::isNull) || tapToAngleConversionMap.values().stream().anyMatch(Objects::isNull)) {
throw new FaraoException(String.format("TapToAngleConversionMap of PST %s cannot contain null values", id));
}
int minTap = Collections.min(tapToAngleConversionMap.keySet());
int maxTap = Collections.max(tapToAngleConversionMap.keySet());
boolean isInverted = tapToAngleConversionMap.get(minTap) > tapToAngleConversionMap.get(maxTap);
double previousTapAngle = tapToAngleConversionMap.get(minTap);
for (int tap = minTap + 1; tap < maxTap; tap++) {
if (!tapToAngleConversionMap.containsKey(tap)) {
throw new FaraoException(String.format("TapToAngleConversionMap of PST %s should contain all the consecutive taps between %d and %d", id, minTap, maxTap));
}
if ((!isInverted && tapToAngleConversionMap.get(tap) < previousTapAngle)
|| (isInverted && tapToAngleConversionMap.get(tap) > previousTapAngle)) {
throw new FaraoException(String.format("TapToAngleConversionMap of PST %s should be increasing or decreasing", id));
}
previousTapAngle = tapToAngleConversionMap.get(tap);
}
if (initialTap > maxTap || initialTap < minTap) {
throw new FaraoException(String.format("initialTap of PST %s must be included into its tapToAngleConversionMap", id));
}
}
void checkAutoUsageRules() {
usageRules.forEach(usageRule -> {
if (usageRule.getInstant().equals(Instant.AUTO) && Objects.isNull(speed)) {
throw new FaraoException("Cannot create an AUTO Pst range action without speed defined");
}
});
}
}