RemedialActionSeriesCreator.java
/*
* Copyright (c) 2022, 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.powsybl.openrao.data.crac.io.cim.craccreator;
import com.powsybl.contingency.Contingency;
import com.powsybl.openrao.data.crac.api.Crac;
import com.powsybl.openrao.data.crac.api.Instant;
import com.powsybl.openrao.data.crac.api.InstantKind;
import com.powsybl.openrao.data.crac.api.RemedialActionAdder;
import com.powsybl.openrao.data.crac.io.cim.xsd.MonitoredSeries;
import com.powsybl.openrao.data.crac.api.cnec.Cnec;
import com.powsybl.openrao.data.crac.api.cnec.FlowCnec;
import com.powsybl.openrao.data.crac.api.usagerule.OnFlowConstraintInCountryAdder;
import com.powsybl.openrao.data.crac.api.usagerule.UsageMethod;
import com.powsybl.openrao.data.crac.io.commons.api.ImportStatus;
import com.powsybl.openrao.data.crac.io.cim.parameters.CimCracCreationParameters;
import com.powsybl.openrao.data.crac.io.commons.OpenRaoImportException;
import com.powsybl.glsk.commons.CountryEICode;
import com.powsybl.iidm.network.Country;
import com.powsybl.iidm.network.Network;
import com.powsybl.openrao.data.crac.io.cim.xsd.RemedialActionRegisteredResource;
import com.powsybl.openrao.data.crac.io.cim.xsd.RemedialActionSeries;
import com.powsybl.openrao.data.crac.io.cim.xsd.Series;
import com.powsybl.openrao.data.crac.io.cim.xsd.TimeSeries;
import org.apache.commons.lang3.StringUtils;
import java.util.*;
import java.util.stream.Collectors;
import static com.powsybl.openrao.data.crac.io.cim.craccreator.CimConstants.*;
import static com.powsybl.openrao.data.crac.io.cim.craccreator.CimCracUtils.getContingencyFromCrac;
import static com.powsybl.openrao.data.crac.io.cim.craccreator.CimCracUtils.getFlowCnecsFromCrac;
/**
* @author Godelaine de Montmorillon {@literal <godelaine.demontmorillon at rte-france.com>}
*/
public class RemedialActionSeriesCreator {
private final Crac crac;
private final Network network;
private final List<TimeSeries> cimTimeSeries;
private Set<RemedialActionSeriesCreationContext> remedialActionSeriesCreationContexts;
private final CimCracCreationContext cracCreationContext;
private List<Contingency> contingencies;
private List<String> invalidContingencies;
private HvdcRangeActionCreator hvdcRangeActionCreator = null;
private Set<Cnec<?>> cnecs;
private final CimCracCreationParameters cimCracCreationParameters;
private final Map<String, PstRangeActionCreator> pstRangeActionCreators = new HashMap<>();
private final Map<String, NetworkActionCreator> networkActionCreators = new HashMap<>();
private final Set<HvdcRangeActionCreator> hvdcRangeActionCreators = new HashSet<>();
private Country sharedDomain;
public RemedialActionSeriesCreator(List<TimeSeries> cimTimeSeries, Crac crac, Network network, CimCracCreationContext cracCreationContext, CimCracCreationParameters cimCracCreationParameters) {
this.cimTimeSeries = cimTimeSeries;
this.crac = crac;
this.network = network;
this.cracCreationContext = cracCreationContext;
this.cimCracCreationParameters = cimCracCreationParameters;
}
private Set<Series> getRaSeries() {
Set<Series> raSeries = new HashSet<>();
CimCracUtils.applyActionToEveryPoint(
cimTimeSeries,
cracCreationContext.getTimeStamp().toInstant(),
point -> point.getSeries().stream()
.filter(this::describesRemedialActionsToImport)
.filter(this::checkRemedialActionSeries)
.forEach(raSeries::add)
);
return raSeries;
}
public void createAndAddRemedialActionSeries() {
this.remedialActionSeriesCreationContexts = new HashSet<>();
this.contingencies = new ArrayList<>();
this.invalidContingencies = new ArrayList<>();
for (Series cimSerie : getRaSeries()) {
resetSeriesContingencies();
// Read and store contingencies
cimSerie.getContingencySeries().forEach(cimContingency -> {
Contingency contingency = getContingencyFromCrac(cimContingency, cracCreationContext);
if (Objects.nonNull(contingency)) {
contingencies.add(contingency);
} else {
invalidContingencies.add(cimContingency.getMRID());
}
});
// Read and store Monitored Series
this.cnecs = getFlowCnecsFromMonitoredAndContingencySeries(cimSerie);
// Read and store AdditionalConstraint Series
if (doNotImportRaSeries(cimSerie)) {
continue;
}
// Read and create / modify RA creators
boolean shouldReadSharedDomain = cimSerie.getMonitoredSeries().isEmpty();
for (RemedialActionSeries remedialActionSeries : cimSerie.getRemedialActionSeries()) {
readRemedialAction(remedialActionSeries, shouldReadSharedDomain);
}
if (hvdcRangeActionCreator != null) {
this.hvdcRangeActionCreators.add(hvdcRangeActionCreator);
hvdcRangeActionCreator = null;
}
}
// Add all RAs from creators to CRAC
addAllRemedialActionsToCrac();
this.cracCreationContext.setRemedialActionSeriesCreationContexts(remedialActionSeriesCreationContexts);
}
private boolean doNotImportRaSeries(Series cimSerie) {
// Do not import a series with only ill-defined contingencies
boolean illDefinedContingencies = contingencies.isEmpty() && !invalidContingencies.isEmpty();
// Do not import a series with an ill-defined additional constraint series
boolean illDefinedAdditionalConstraintSeries = readAdditionalConstraintSeries(cimSerie);
if (illDefinedContingencies) {
cimSerie.getRemedialActionSeries().forEach(remedialActionSeries -> this.remedialActionSeriesCreationContexts.add(RemedialActionSeriesCreationContext.notImported(remedialActionSeries.getMRID(), ImportStatus.INCONSISTENCY_IN_DATA, String.format("This RA is not imported because it is only associated to invalid contingencies %s", invalidContingencies))));
return true;
}
return !illDefinedAdditionalConstraintSeries;
}
/**
* Reads AdditionalConstraint_Series of a Series and potentially creates associated angleCnec
* If an angle cnec has been correctly defined, return true to import cimSerie's remedial actions.
*/
private boolean readAdditionalConstraintSeries(Series cimSerie) {
if (!cimSerie.getAdditionalConstraintSeries().isEmpty()) {
if (isAValidAngleCnecSeries(cimSerie)) {
AdditionalConstraintSeriesCreator additionalConstraintSeriesCreator = new AdditionalConstraintSeriesCreator(crac, network, cimSerie.getAdditionalConstraintSeries().get(0), contingencies.get(0).getId(), cimSerie.getMRID(), cracCreationContext);
this.cnecs.add(additionalConstraintSeriesCreator.createAndAddAdditionalConstraintSeries());
// If angle cnec import has failed, create failed RemedialActionSeriesCreationContexts for associated remedial actions.
if (cracCreationContext.getAngleCnecCreationContexts().stream().anyMatch(context -> context.getSerieId().equals(cimSerie.getMRID()) && !context.isImported())) {
for (RemedialActionSeries remedialActionSeries : cimSerie.getRemedialActionSeries()) {
remedialActionSeriesCreationContexts.add(RemedialActionSeriesCreationContext.notImported(remedialActionSeries.getMRID(), ImportStatus.INCONSISTENCY_IN_DATA, "Associated angle cnec could not be imported"));
}
return false;
}
} else {
return false;
}
}
return true;
}
/**
* A valid angle cnec series contains :
* -- exactly 1 additional constraint series
* -- exactly 1 valid contingency
*/
private boolean isAValidAngleCnecSeries(Series cimSerie) {
if (cimSerie.getAdditionalConstraintSeries().size() == 1
&& contingencies.size() == 1 && invalidContingencies.isEmpty()) {
return true;
} else if (cimSerie.getAdditionalConstraintSeries().size() > 1) {
remedialActionSeriesCreationContexts.add(RemedialActionSeriesCreationContext.notImported(cimSerie.getMRID(), ImportStatus.INCONSISTENCY_IN_DATA, String.format("Angle cnec series has too many (%s) additional constraint series", cimSerie.getAdditionalConstraintSeries().size())));
return false;
} else {
remedialActionSeriesCreationContexts.add(RemedialActionSeriesCreationContext.notImported(cimSerie.getMRID(), ImportStatus.INCONSISTENCY_IN_DATA, "Angle cnec series has an ill defined contingency series"));
return false;
}
}
/**
* Reads Monitored_Series of a Series and maps them to flow cnecs
* If Contingency_Series exist in the Series, then the flow cnecs that do not correspond to these contingencies are filtered out
*/
private Set<Cnec<?>> getFlowCnecsFromMonitoredAndContingencySeries(Series cimSerie) {
Set<Cnec<?>> flowCnecsFromMsAndCs = new HashSet<>();
for (MonitoredSeries monitoredSeries : cimSerie.getMonitoredSeries()) {
Set<FlowCnec> flowCnecsForMs = getFlowCnecsFromCrac(monitoredSeries, cracCreationContext);
if (!cimSerie.getContingencySeries().isEmpty()) {
flowCnecsForMs = flowCnecsForMs.stream().filter(
flowCnec -> flowCnec.getState().getContingency().isPresent()
&& contingencies.contains(flowCnec.getState().getContingency().get())
).collect(Collectors.toSet());
}
flowCnecsFromMsAndCs.addAll(flowCnecsForMs);
}
return flowCnecsFromMsAndCs;
}
private void addAllRemedialActionsToCrac() {
pstRangeActionCreators.values().forEach(
creator -> {
creator.addPstRangeAction();
this.remedialActionSeriesCreationContexts.add(creator.getPstRangeActionCreationContext());
}
);
networkActionCreators.values().forEach(
creator -> {
creator.addNetworkAction();
this.remedialActionSeriesCreationContexts.add(creator.getNetworkActionCreationContext());
}
);
hvdcRangeActionCreators.forEach(
creator -> this.remedialActionSeriesCreationContexts.addAll(creator.add())
);
}
private void readRemedialAction(RemedialActionSeries remedialActionSeries, boolean shouldReadSharedDomain) {
String createdRemedialActionId = remedialActionSeries.getMRID();
// --- BusinessType
String businessType = remedialActionSeries.getBusinessType();
if (!checkBusinessType(createdRemedialActionId, businessType)) {
return;
}
// --- ApplicationModeMarketObjectStatus
String applicationModeMarketObjectStatus = remedialActionSeries.getApplicationModeMarketObjectStatusStatus();
if (!checkApplicationModeMarketObjectStatus(createdRemedialActionId, applicationModeMarketObjectStatus)) {
return;
}
// --- Availability_MarketObjectStatus
String availabilityMarketObjectStatus = remedialActionSeries.getAvailabilityMarketObjectStatusStatus();
if (!checkAvailabilityMarketObjectStatus(createdRemedialActionId, availabilityMarketObjectStatus)) {
return;
}
// --- Shared domain
sharedDomain = null;
if (shouldReadSharedDomain && !remedialActionSeries.getSharedDomain().isEmpty()) {
if (remedialActionSeries.getSharedDomain().size() > 1) {
remedialActionSeriesCreationContexts.add(RemedialActionSeriesCreationContext.notImported(createdRemedialActionId, ImportStatus.NOT_YET_HANDLED_BY_OPEN_RAO, "RemedialActionSeries with multiple SharedDomain are not supported"));
return;
}
sharedDomain = new CountryEICode(remedialActionSeries.getSharedDomain().get(0).getMRID().getValue()).getCountry();
}
// --- Registered Resources
List<RemedialActionRegisteredResource> remedialActionRegisteredResources = remedialActionSeries.getRegisteredResource();
if (remedialActionRegisteredResources.isEmpty()) {
remedialActionSeriesCreationContexts.add(RemedialActionSeriesCreationContext.notImported(createdRemedialActionId, ImportStatus.INCOMPLETE_DATA, "Missing registered resource"));
return;
}
// -- Read remedial action, and store or modify its creator
readRemedialAction(remedialActionSeries);
}
private void readRemedialAction(RemedialActionSeries remedialActionSeries) {
// 1) Check if Remedial Action is a Pst Range Action :
if (identifyAndReadPstRangeAction(remedialActionSeries)) {
return;
}
// 2) Check if Remedial Action is part of a HVDC Range Action :
if (identifyAndReadHvdcRangeAction(remedialActionSeries)) {
return;
}
// 3) Suppose that Remedial Action is a Network Action :
readNetworkAction(remedialActionSeries);
}
// Return true if PST range action has been read.
private boolean identifyAndReadPstRangeAction(RemedialActionSeries remedialActionSeries) {
String createdRemedialActionId = remedialActionSeries.getMRID();
List<RemedialActionRegisteredResource> remedialActionRegisteredResources = remedialActionSeries.getRegisteredResource();
for (RemedialActionRegisteredResource remedialActionRegisteredResource : remedialActionRegisteredResources) {
String psrType = remedialActionRegisteredResource.getPSRTypePsrType();
if (Objects.isNull(psrType)) {
remedialActionSeriesCreationContexts.add(PstRangeActionSeriesCreationContext.notImported(createdRemedialActionId, ImportStatus.INCOMPLETE_DATA, "Missing psrType"));
return true;
}
// ------ PST Range Action
if (psrType.equals(PsrType.PST.getStatus()) && Objects.isNull(remedialActionRegisteredResource.getResourceCapacityDefaultCapacity())) {
if (remedialActionRegisteredResources.size() > 1) {
remedialActionSeriesCreationContexts.add(PstRangeActionSeriesCreationContext.notImported(createdRemedialActionId, ImportStatus.INCONSISTENCY_IN_DATA, String.format("> 1 registered resources (%s) with at least one PST Range Action defined", remedialActionRegisteredResources.size())));
return true;
}
if (!pstRangeActionCreators.containsKey(createdRemedialActionId)
|| !pstRangeActionCreators.get(createdRemedialActionId).getPstRangeActionCreationContext().isImported()) {
PstRangeActionCreator pstRangeActionCreator = new PstRangeActionCreator(remedialActionSeries, contingencies, invalidContingencies, cnecs, sharedDomain);
pstRangeActionCreator.createPstRangeActionAdder(crac, network, cimCracCreationParameters);
pstRangeActionCreators.put(createdRemedialActionId, pstRangeActionCreator);
} else {
// Some remedial actions can be defined in multiple Series in order to define multiple usage rules (eg on flow constraint on different CNECs)
// In this case, only import extra usage rules
addExtraUsageRules(remedialActionSeries.getApplicationModeMarketObjectStatusStatus(), createdRemedialActionId, pstRangeActionCreators.get(createdRemedialActionId).getPstRangeActionAdder());
}
return true;
}
}
return false;
}
private void addExtraUsageRules(String applicationModeMarketObjectStatus, String remedialActionId, RemedialActionAdder<?> adder) {
try {
RemedialActionSeriesCreator.addUsageRules(
crac, applicationModeMarketObjectStatus, adder, contingencies, invalidContingencies, cnecs, sharedDomain
);
} catch (OpenRaoImportException e) {
cracCreationContext.getCreationReport().warn(String.format("Extra usage rules for RA %s could not be imported: %s", remedialActionId, e.getMessage()));
}
}
// Indicates whether an hvdc range action is present amidst the registered resources
private boolean identifyAndReadHvdcRangeAction(RemedialActionSeries remedialActionSeries) {
List<RemedialActionRegisteredResource> remedialActionRegisteredResources = remedialActionSeries.getRegisteredResource();
String applicationModeMarketObjectStatus = remedialActionSeries.getApplicationModeMarketObjectStatusStatus();
for (RemedialActionRegisteredResource remedialActionRegisteredResource : remedialActionRegisteredResources) {
if (remedialActionRegisteredResource.getPSRTypePsrType().equals(PsrType.HVDC.getStatus())) {
if (!applicationModeMarketObjectStatus.equals(ApplicationModeMarketObjectStatus.AUTO.getStatus())) {
remedialActionSeriesCreationContexts.add(RemedialActionSeriesCreationContext.notImported(remedialActionSeries.getMRID(), ImportStatus.INCONSISTENCY_IN_DATA, String.format("HVDC cannot be imported at instant %s", applicationModeMarketObjectStatus)));
return true;
}
if (Objects.isNull(hvdcRangeActionCreator)) {
hvdcRangeActionCreator = new HvdcRangeActionCreator(
crac, network,
contingencies, invalidContingencies, cnecs, sharedDomain, cimCracCreationParameters);
}
hvdcRangeActionCreator.addDirection(remedialActionSeries);
return true;
}
}
return false;
}
private void readNetworkAction(RemedialActionSeries remedialActionSeries) {
String createdRemedialActionId = remedialActionSeries.getMRID();
if (!networkActionCreators.containsKey(createdRemedialActionId)
|| !networkActionCreators.get(createdRemedialActionId).getNetworkActionCreationContext().isImported()) {
NetworkActionCreator networkActionCreator = new NetworkActionCreator(crac, network, remedialActionSeries,
contingencies, invalidContingencies, cnecs, sharedDomain);
networkActionCreator.createNetworkActionAdder();
networkActionCreators.put(createdRemedialActionId, networkActionCreator);
} else {
// Some remedial actions can be defined in multiple Series in order to define multiple usage rules (eg on flow constraint on different CNECs)
// In this case, only import extra usage rules
addExtraUsageRules(remedialActionSeries.getApplicationModeMarketObjectStatusStatus(), createdRemedialActionId, networkActionCreators.get(createdRemedialActionId).getNetworkActionAdder());
}
}
/*---------------- STATIC METHODS ----------------------*/
public static RemedialActionSeriesCreationContext importWithContingencies(String createdRemedialActionId, List<String> invalidContingencies) {
if (invalidContingencies.isEmpty()) {
return RemedialActionSeriesCreationContext.imported(createdRemedialActionId, false, "");
} else {
String contingencyList = StringUtils.join(invalidContingencies, ", ");
return RemedialActionSeriesCreationContext.imported(createdRemedialActionId, true, String.format("Contingencies %s were not imported", contingencyList));
}
}
public static RemedialActionSeriesCreationContext importPstRaWithContingencies(String createdRemedialActionId, String networkElementNativeMrid, String networkElementNativeName, List<String> invalidContingencies) {
if (invalidContingencies.isEmpty()) {
return PstRangeActionSeriesCreationContext.imported(createdRemedialActionId, false, "", networkElementNativeMrid, networkElementNativeName);
} else {
String contingencyList = StringUtils.join(invalidContingencies, ", ");
return PstRangeActionSeriesCreationContext.imported(createdRemedialActionId, true, String.format("Contingencies %s were not imported", contingencyList), networkElementNativeMrid, networkElementNativeName);
}
}
public static void checkPstUnit(String unitSymbol) {
if (Objects.isNull(unitSymbol)) {
throw new OpenRaoImportException(ImportStatus.INCOMPLETE_DATA, "Missing unit symbol");
}
if (!unitSymbol.equals(PST_CAPACITY_UNIT_SYMBOL)) {
throw new OpenRaoImportException(ImportStatus.INCONSISTENCY_IN_DATA, String.format("Wrong unit symbol in its registered resource: %s", unitSymbol));
}
}
public static void addUsageRules(Crac crac, String applicationModeMarketObjectStatus,
RemedialActionAdder<?> remedialActionAdder,
List<Contingency> contingencies,
List<String> invalidContingencies,
Set<Cnec<?>> cnecs,
Country sharedDomain) {
if (applicationModeMarketObjectStatus.equals(ApplicationModeMarketObjectStatus.PRA.getStatus())) {
addUsageRulesAtInstant(remedialActionAdder, contingencies, invalidContingencies, cnecs, sharedDomain, crac.getPreventiveInstant());
}
if (applicationModeMarketObjectStatus.equals(ApplicationModeMarketObjectStatus.CRA.getStatus())) {
addUsageRulesAtInstant(remedialActionAdder, contingencies, invalidContingencies, cnecs, sharedDomain, crac.getInstant(InstantKind.CURATIVE));
}
if (applicationModeMarketObjectStatus.equals(ApplicationModeMarketObjectStatus.PRA_AND_CRA.getStatus())) {
addUsageRulesAtInstant(remedialActionAdder, null, null, cnecs, sharedDomain, crac.getPreventiveInstant());
addUsageRulesAtInstant(remedialActionAdder, contingencies, invalidContingencies, cnecs, sharedDomain, crac.getInstant(InstantKind.CURATIVE));
}
if (applicationModeMarketObjectStatus.equals(ApplicationModeMarketObjectStatus.AUTO.getStatus())) {
addUsageRulesAtInstant(remedialActionAdder, contingencies, invalidContingencies, cnecs, sharedDomain, crac.getInstant(InstantKind.AUTO));
}
}
private static void addUsageRulesAtInstant(RemedialActionAdder<?> remedialActionAdder,
List<Contingency> contingencies,
List<String> invalidContingencies,
Set<Cnec<?>> cnecs,
Country sharedDomain,
Instant instant) {
if (!cnecs.isEmpty()) {
cnecs.forEach(cnec -> addOnConstraintUsageRule(remedialActionAdder, cnec, instant));
return;
}
UsageMethod usageMethod = instant.isAuto() ? UsageMethod.FORCED : UsageMethod.AVAILABLE;
if (!Objects.isNull(sharedDomain)) {
addOnFlowConstraintInCountryUsageRule(remedialActionAdder, contingencies, sharedDomain, instant, usageMethod);
return;
}
checkUsageRulesContingencies(instant, contingencies, invalidContingencies);
if (instant.isPreventive() ||
instant.isCurative() && (contingencies == null || contingencies.isEmpty())) {
addOnInstantUsageRules(remedialActionAdder, instant);
} else {
RemedialActionSeriesCreator.addOnStateUsageRules(remedialActionAdder, instant, usageMethod, contingencies);
}
}
private static void checkUsageRulesContingencies(Instant instant, List<Contingency> contingencies, List<String> invalidContingencies) {
switch (instant.getKind()) {
case PREVENTIVE:
if (Objects.nonNull(contingencies) && !contingencies.isEmpty()
|| Objects.nonNull(invalidContingencies) && !invalidContingencies.isEmpty()) {
throw new OpenRaoImportException(ImportStatus.INCONSISTENCY_IN_DATA, "Cannot create a preventive remedial action associated to a contingency");
}
break;
case AUTO:
if (contingencies.isEmpty() && invalidContingencies.isEmpty()) {
throw new OpenRaoImportException(ImportStatus.INCONSISTENCY_IN_DATA, String.format("Cannot create a free-to-use remedial action at instant '%s'", instant));
}
if (contingencies.isEmpty()) {
throw new OpenRaoImportException(ImportStatus.INCONSISTENCY_IN_DATA, String.format("Contingencies are all invalid, and usage rule is on instant '%s'", instant));
}
break;
case CURATIVE:
if (contingencies.isEmpty() && !invalidContingencies.isEmpty()) {
throw new OpenRaoImportException(ImportStatus.INCONSISTENCY_IN_DATA, String.format("Contingencies are all invalid, and usage rule is on instant '%s'", instant));
}
break;
default:
throw new OpenRaoImportException(ImportStatus.INCONSISTENCY_IN_DATA, String.format("Cannot add usage rule on instant '%s'", instant));
}
}
private static void addOnInstantUsageRules(RemedialActionAdder<?> adder, Instant raApplicationInstant) {
adder.newOnInstantUsageRule()
.withInstant(raApplicationInstant.getId())
.withUsageMethod(UsageMethod.AVAILABLE)
.add();
}
private static void addOnStateUsageRules(RemedialActionAdder<?> adder, Instant raApplicationInstant, UsageMethod usageMethod, List<Contingency> contingencies) {
contingencies.forEach(contingency ->
adder.newOnContingencyStateUsageRule()
.withInstant(raApplicationInstant.getId())
.withUsageMethod(usageMethod)
.withContingency(contingency.getId())
.add());
}
private static void addOnConstraintUsageRule(RemedialActionAdder<?> adder, Cnec<?> cnec, Instant instant) {
// Only allow PRAs with usage method OnFlowConstraint/OnAngleConstraint, for CNECs of instants PREVENTIVE & OUTAGE & CURATIVE
// Only allow ARAs with usage method OnFlowConstraint/OnAngleConstraint, for CNECs of instant AUTO
// Only allow CRAs with usage method OnFlowConstraint/OnAngleConstraint, for CNECs of instant CURATIVE
if (cnec.getState().getInstant().comesBefore(instant)) {
return;
}
adder.newOnConstraintUsageRule()
.withCnec(cnec.getId())
.withUsageMethod(instant.isAuto() ? UsageMethod.FORCED : UsageMethod.AVAILABLE)
.withInstant(instant.getId())
.add();
}
private static void addOnFlowConstraintInCountryUsageRule(RemedialActionAdder<?> remedialActionAdder, List<Contingency> contingencies, Country sharedDomain, Instant instant, UsageMethod usageMethod) {
OnFlowConstraintInCountryAdder<?> onFlowConstraintInCountryAdder = remedialActionAdder
.newOnFlowConstraintInCountryUsageRule()
.withInstant(instant.getId())
.withCountry(sharedDomain)
.withUsageMethod(usageMethod);
if (!Objects.isNull(contingencies) && !contingencies.isEmpty()) {
contingencies.forEach(
contingency -> onFlowConstraintInCountryAdder.withContingency(contingency.getId()).add());
} else {
onFlowConstraintInCountryAdder.add();
}
}
/*-------------- SERIES CHECKS ------------------------------*/
private boolean checkRemedialActionSeries(Series cimSerie) {
// --- Check optimizationStatus
String optimizationStatus = cimSerie.getOptimizationMarketObjectStatusStatus();
if (Objects.nonNull(optimizationStatus)) {
boolean statusOk = false;
for (String status : REMEDIAL_ACTION_OPTIMIZATION_STATUS) {
if (optimizationStatus.equals(status)) {
statusOk = true;
break;
}
}
if (!statusOk) {
remedialActionSeriesCreationContexts.add(RemedialActionSeriesCreationContext.notImported(cimSerie.getMRID(), ImportStatus.INCONSISTENCY_IN_DATA, String.format("Wrong optimization status: %s", optimizationStatus)));
return false;
}
}
return true;
}
private boolean checkBusinessType(String createdRemedialActionId, String businessType) {
if (Objects.isNull(businessType) || !businessType.equals(BUSINESS_TYPE_IN_REMEDIALACTION_SERIES)) {
remedialActionSeriesCreationContexts.add(RemedialActionSeriesCreationContext.notImported(createdRemedialActionId, ImportStatus.INCONSISTENCY_IN_DATA, String.format("Wrong businessType: %s", businessType)));
return false;
}
return true;
}
private boolean checkApplicationModeMarketObjectStatus(String createdRemedialActionId, String applicationModeMarketObjectStatus) {
if (Objects.isNull(applicationModeMarketObjectStatus)) {
remedialActionSeriesCreationContexts.add(RemedialActionSeriesCreationContext.notImported(createdRemedialActionId, ImportStatus.INCOMPLETE_DATA, "Missing applicationMode MarketObjectStatus"));
return false;
}
for (ApplicationModeMarketObjectStatus value : ApplicationModeMarketObjectStatus.values()) {
if (applicationModeMarketObjectStatus.equals(value.getStatus())) {
return true;
}
}
remedialActionSeriesCreationContexts.add(RemedialActionSeriesCreationContext.notImported(createdRemedialActionId, ImportStatus.INCONSISTENCY_IN_DATA, String.format("Wrong applicationMode_MarketObjectStatus: %s", applicationModeMarketObjectStatus)));
return false;
}
private boolean checkAvailabilityMarketObjectStatus(String createdRemedialActionId, String availabilityMarketObjectStatus) {
if (Objects.isNull(availabilityMarketObjectStatus)) {
remedialActionSeriesCreationContexts.add(RemedialActionSeriesCreationContext.notImported(createdRemedialActionId, ImportStatus.INCOMPLETE_DATA, "Missing availabilityMarketObjectStatus"));
return false;
}
// A38 not handled by Open RAO.
if (availabilityMarketObjectStatus.equals(AvailabilityMarketObjectStatus.SHALL_BE_USED.getStatus())) {
remedialActionSeriesCreationContexts.add(RemedialActionSeriesCreationContext.notImported(createdRemedialActionId, ImportStatus.NOT_YET_HANDLED_BY_OPEN_RAO, String.format("Wrong availabilityMarketObjectStatus: %s", availabilityMarketObjectStatus)));
return false;
}
if (!availabilityMarketObjectStatus.equals(AvailabilityMarketObjectStatus.MIGHT_BE_USED.getStatus())) {
remedialActionSeriesCreationContexts.add(RemedialActionSeriesCreationContext.notImported(createdRemedialActionId, ImportStatus.INCONSISTENCY_IN_DATA, String.format("Wrong availabilityMarketObjectStatus: %s", availabilityMarketObjectStatus)));
return false;
}
return true;
}
private void resetSeriesContingencies() {
this.contingencies = new ArrayList<>();
this.invalidContingencies = new ArrayList<>();
}
private boolean describesRemedialActionsToImport(Series series) {
return series.getBusinessType().equals(REMEDIAL_ACTIONS_SERIES_BUSINESS_TYPE);
}
}