NcCrac.java
/*
* Copyright (c) 2023, 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.nc;
import com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider;
import com.powsybl.openrao.data.crac.io.nc.craccreator.NcCracUtils;
import com.powsybl.openrao.data.crac.io.nc.craccreator.constants.NcKeyword;
import com.powsybl.openrao.data.crac.io.nc.objects.AssessedElement;
import com.powsybl.openrao.data.crac.io.nc.objects.AssessedElementWithContingency;
import com.powsybl.openrao.data.crac.io.nc.objects.AssessedElementWithRemedialAction;
import com.powsybl.openrao.data.crac.io.nc.objects.Contingency;
import com.powsybl.openrao.data.crac.io.nc.objects.ContingencyEquipment;
import com.powsybl.openrao.data.crac.io.nc.objects.ContingencyWithRemedialAction;
import com.powsybl.openrao.data.crac.io.nc.objects.CurrentLimit;
import com.powsybl.openrao.data.crac.io.nc.objects.GridStateAlterationRemedialAction;
import com.powsybl.openrao.data.crac.io.nc.objects.RemedialActionDependency;
import com.powsybl.openrao.data.crac.io.nc.objects.RemedialActionGroup;
import com.powsybl.openrao.data.crac.io.nc.objects.RotatingMachineAction;
import com.powsybl.openrao.data.crac.io.nc.objects.ShuntCompensatorModification;
import com.powsybl.openrao.data.crac.io.nc.objects.StaticPropertyRange;
import com.powsybl.openrao.data.crac.io.nc.objects.TapChanger;
import com.powsybl.openrao.data.crac.io.nc.objects.TapPositionAction;
import com.powsybl.openrao.data.crac.io.nc.objects.TopologyAction;
import com.powsybl.openrao.data.crac.io.nc.objects.VoltageAngleLimit;
import com.powsybl.openrao.data.crac.io.nc.craccreator.NcPropertyBagsConverter;
import com.powsybl.openrao.data.crac.io.nc.craccreator.constants.NcConstants;
import com.powsybl.openrao.data.crac.io.nc.craccreator.constants.HeaderType;
import com.powsybl.openrao.data.crac.io.nc.craccreator.constants.OverridingObjectsFields;
import com.powsybl.openrao.data.crac.io.nc.objects.VoltageLimit;
import com.powsybl.triplestore.api.PropertyBag;
import com.powsybl.triplestore.api.PropertyBags;
import com.powsybl.triplestore.api.QueryCatalog;
import com.powsybl.triplestore.api.TripleStore;
import java.time.OffsetDateTime;
import java.util.*;
/**
* @author Jean-Pierre Arnould {@literal <jean-pierre.arnould at rte-france.com>}
*/
public class NcCrac {
private final TripleStore tripleStoreNcCrac;
private final QueryCatalog queryCatalogNcCrac;
private final Map<String, Set<String>> keywordMap;
private Map<String, String> overridingData;
public NcCrac(TripleStore tripleStoreNcCrac, Map<String, Set<String>> keywordMap) {
this.tripleStoreNcCrac = tripleStoreNcCrac;
this.queryCatalogNcCrac = new QueryCatalog(NcConstants.SPARQL_FILE_NC_PROFILE);
this.keywordMap = keywordMap;
this.overridingData = new HashMap<>();
}
public void clearContext(String context) {
tripleStoreNcCrac.clear(context);
}
public void clearKeywordMap(String context) {
for (Map.Entry<String, Set<String>> entry : keywordMap.entrySet()) {
String keyword = entry.getKey();
Set<String> contextNames = entry.getValue();
if (contextNames.contains(context)) {
contextNames.remove(context);
keywordMap.put(keyword, contextNames);
break;
}
}
}
private Set<String> getContextNamesToRequest(NcKeyword keyword) {
return keywordMap.getOrDefault(keyword.toString(), Collections.emptySet());
}
public Map<String, PropertyBags> getHeaders() {
Map<String, PropertyBags> returnMap = new HashMap<>();
tripleStoreNcCrac.contextNames().forEach(context -> returnMap.put(context, queryTripleStore(NcConstants.REQUEST_HEADER, Set.of(context))));
return returnMap;
}
public PropertyBags getPropertyBags(NcKeyword keyword, String... queries) {
Set<String> namesToRequest = getContextNamesToRequest(keyword);
if (namesToRequest.isEmpty()) {
return new PropertyBags();
}
return this.queryTripleStore(List.of(queries), namesToRequest);
}
public PropertyBags getPropertyBags(NcKeyword keyword, OverridingObjectsFields withOverride, String... queries) {
return withOverride == null ? getPropertyBags(keyword, queries) : NcCracUtils.overrideData(getPropertyBags(keyword, queries), overridingData, withOverride);
}
public Set<Contingency> getContingencies() {
return new NcPropertyBagsConverter<>(Contingency::fromPropertyBag).convert(getPropertyBags(NcKeyword.CONTINGENCY, OverridingObjectsFields.CONTINGENCY, NcConstants.REQUEST_ORDINARY_CONTINGENCY, NcConstants.REQUEST_EXCEPTIONAL_CONTINGENCY, NcConstants.REQUEST_OUT_OF_RANGE_CONTINGENCY));
}
public Set<ContingencyEquipment> getContingencyEquipments() {
return new NcPropertyBagsConverter<>(ContingencyEquipment::fromPropertyBag).convert(getPropertyBags(NcKeyword.CONTINGENCY, NcConstants.REQUEST_CONTINGENCY_EQUIPMENT));
}
public Set<AssessedElement> getAssessedElements() {
return new NcPropertyBagsConverter<>(AssessedElement::fromPropertyBag).convert(getPropertyBags(NcKeyword.ASSESSED_ELEMENT, OverridingObjectsFields.ASSESSED_ELEMENT, NcConstants.REQUEST_ASSESSED_ELEMENT));
}
public Set<AssessedElementWithContingency> getAssessedElementWithContingencies() {
return new NcPropertyBagsConverter<>(AssessedElementWithContingency::fromPropertyBag).convert(getPropertyBags(NcKeyword.ASSESSED_ELEMENT, OverridingObjectsFields.ASSESSED_ELEMENT_WITH_CONTINGENCY, NcConstants.REQUEST_ASSESSED_ELEMENT_WITH_CONTINGENCY));
}
public Set<AssessedElementWithRemedialAction> getAssessedElementWithRemedialActions() {
return new NcPropertyBagsConverter<>(AssessedElementWithRemedialAction::fromPropertyBag).convert(getPropertyBags(NcKeyword.ASSESSED_ELEMENT, OverridingObjectsFields.ASSESSED_ELEMENT_WITH_REMEDIAL_ACTION, NcConstants.REQUEST_ASSESSED_ELEMENT_WITH_REMEDIAL_ACTION));
}
public Set<CurrentLimit> getCurrentLimits() {
return new NcPropertyBagsConverter<>(CurrentLimit::fromPropertyBag).convert(getPropertyBags(NcKeyword.CGMES, OverridingObjectsFields.CURRENT_LIMIT, NcConstants.REQUEST_CURRENT_LIMIT));
}
public Set<VoltageLimit> getVoltageLimits() {
return new NcPropertyBagsConverter<>(VoltageLimit::fromPropertyBag).convert(getPropertyBags(NcKeyword.CGMES, OverridingObjectsFields.VOLTAGE_LIMIT, NcConstants.REQUEST_VOLTAGE_LIMIT));
}
public Set<VoltageAngleLimit> getVoltageAngleLimits() {
return new NcPropertyBagsConverter<>(VoltageAngleLimit::fromPropertyBag).convert(getPropertyBags(NcKeyword.EQUIPMENT_RELIABILITY, OverridingObjectsFields.VOLTAGE_ANGLE_LIMIT, NcConstants.REQUEST_VOLTAGE_ANGLE_LIMIT));
}
public Set<GridStateAlterationRemedialAction> getGridStateAlterationRemedialActions() {
return new NcPropertyBagsConverter<>(GridStateAlterationRemedialAction::fromPropertyBag).convert(getPropertyBags(NcKeyword.REMEDIAL_ACTION, OverridingObjectsFields.GRID_STATE_ALTERATION_REMEDIAL_ACTION, NcConstants.GRID_STATE_ALTERATION_REMEDIAL_ACTION));
}
public Set<TopologyAction> getTopologyActions() {
return new NcPropertyBagsConverter<>(TopologyAction::fromPropertyBag).convert(getPropertyBags(NcKeyword.REMEDIAL_ACTION, OverridingObjectsFields.TOPOLOGY_ACTION, NcConstants.TOPOLOGY_ACTION));
}
public Set<RotatingMachineAction> getRotatingMachineActions() {
return new NcPropertyBagsConverter<>(RotatingMachineAction::fromPropertyBag).convert(getPropertyBags(NcKeyword.REMEDIAL_ACTION, OverridingObjectsFields.ROTATING_MACHINE_ACTION, NcConstants.ROTATING_MACHINE_ACTION));
}
public Set<ShuntCompensatorModification> getShuntCompensatorModifications() {
return new NcPropertyBagsConverter<>(ShuntCompensatorModification::fromPropertyBag).convert(getPropertyBags(NcKeyword.REMEDIAL_ACTION, OverridingObjectsFields.SHUNT_COMPENSATOR_MODIFICATION, NcConstants.SHUNT_COMPENSATOR_MODIFICATION));
}
public Set<TapPositionAction> getTapPositionActions() {
return new NcPropertyBagsConverter<>(TapPositionAction::fromPropertyBag).convert(getPropertyBags(NcKeyword.REMEDIAL_ACTION, OverridingObjectsFields.TAP_POSITION_ACTION, NcConstants.TAP_POSITION_ACTION));
}
public Set<StaticPropertyRange> getStaticPropertyRanges() {
return new NcPropertyBagsConverter<>(StaticPropertyRange::fromPropertyBag).convert(getPropertyBags(NcKeyword.REMEDIAL_ACTION, OverridingObjectsFields.STATIC_PROPERTY_RANGE, NcConstants.STATIC_PROPERTY_RANGE));
}
public Set<ContingencyWithRemedialAction> getContingencyWithRemedialActions() {
return new NcPropertyBagsConverter<>(ContingencyWithRemedialAction::fromPropertyBag).convert(getPropertyBags(NcKeyword.REMEDIAL_ACTION, OverridingObjectsFields.CONTINGENCY_WITH_REMEDIAL_ACTION, NcConstants.REQUEST_CONTINGENCY_WITH_REMEDIAL_ACTION));
}
public Set<RemedialActionGroup> getRemedialActionGroups() {
return new NcPropertyBagsConverter<>(RemedialActionGroup::fromPropertyBag).convert(getPropertyBags(NcKeyword.REMEDIAL_ACTION, NcConstants.REQUEST_REMEDIAL_ACTION_GROUP));
}
public Set<RemedialActionDependency> getRemedialActionDependencies() {
return new NcPropertyBagsConverter<>(RemedialActionDependency::fromPropertyBag).convert(getPropertyBags(NcKeyword.REMEDIAL_ACTION, OverridingObjectsFields.SCHEME_REMEDIAL_ACTION_DEPENDENCY, NcConstants.REQUEST_REMEDIAL_ACTION_DEPENDENCY));
}
public Set<TapChanger> getTapChangers() {
return new NcPropertyBagsConverter<>(TapChanger::fromPropertyBag).convert(getPropertyBags(NcKeyword.CGMES, NcConstants.REQUEST_TAP_CHANGER));
}
private void setOverridingData(OffsetDateTime importTimestamp) {
overridingData = new HashMap<>();
for (OverridingObjectsFields overridingObject : OverridingObjectsFields.values()) {
addDataFromTripleStoreToMap(overridingData, overridingObject.getRequestName(), overridingObject.getObjectName(), overridingObject.getOverridedFieldName(), overridingObject.getHeaderType(), importTimestamp);
}
}
private void addDataFromTripleStoreToMap(Map<String, String> dataMap, String queryName, String queryObjectName, String queryFieldName, HeaderType headerType, OffsetDateTime importTimestamp) {
PropertyBags propertyBagsResult = queryTripleStore(queryName, tripleStoreNcCrac.contextNames());
for (PropertyBag propertyBag : propertyBagsResult) {
if (HeaderType.START_END_DATE.equals(headerType)) {
if (NcCracUtils.checkProfileKeyword(propertyBag, NcKeyword.STEADY_STATE_INSTRUCTION) && NcCracUtils.checkProfileValidityInterval(propertyBag, importTimestamp)) {
String id = propertyBag.getId(queryObjectName);
String overridedValue = propertyBag.get(queryFieldName);
dataMap.put(id, overridedValue);
}
} else {
if (NcCracUtils.checkProfileKeyword(propertyBag, NcKeyword.STEADY_STATE_HYPOTHESIS)) {
OffsetDateTime scenarioTime = OffsetDateTime.parse(propertyBag.get(NcConstants.SCENARIO_TIME));
if (importTimestamp.isEqual(scenarioTime)) {
String id = propertyBag.getId(queryObjectName);
String overridedValue = propertyBag.get(queryFieldName);
dataMap.put(id, overridedValue);
}
}
}
}
}
private PropertyBags queryTripleStore(List<String> queryKeys, Set<String> contexts) {
PropertyBags mergedPropertyBags = new PropertyBags();
for (String queryKey : queryKeys) {
mergedPropertyBags.addAll(queryTripleStore(queryKey, contexts));
}
return mergedPropertyBags;
}
/**
* execute query on the whole tripleStore or on each context included in the set
*
* @param queryKey : query name in the sparql file
* @param contexts : list of contexts where the query will be executed (if empty, the query is executed on the whole tripleStore
*/
private PropertyBags queryTripleStore(String queryKey, Set<String> contexts) {
String query = queryCatalogNcCrac.get(queryKey);
if (query == null) {
OpenRaoLoggerProvider.TECHNICAL_LOGS.warn("Query [{}] not found in catalog", queryKey);
return new PropertyBags();
}
if (contexts.isEmpty()) {
return tripleStoreNcCrac.query(query);
}
PropertyBags multiContextsPropertyBags = new PropertyBags();
for (String context : contexts) {
String contextQuery = String.format(query, context);
multiContextsPropertyBags.addAll(tripleStoreNcCrac.query(contextQuery));
}
return multiContextsPropertyBags;
}
public void setForTimestamp(OffsetDateTime offsetDateTime) {
clearTimewiseIrrelevantContexts(offsetDateTime);
setOverridingData(offsetDateTime);
}
private void clearTimewiseIrrelevantContexts(OffsetDateTime offsetDateTime) {
getHeaders().forEach((contextName, properties) -> {
if (!properties.isEmpty()) {
PropertyBag property = properties.get(0);
if (!checkTimeCoherence(property, offsetDateTime)) {
OpenRaoLoggerProvider.BUSINESS_WARNS.warn(String.format("[REMOVED] The file : %s will be ignored. Its dates are not consistent with the import date : %s", contextName, offsetDateTime));
clearContext(contextName);
clearKeywordMap(contextName);
}
}
});
}
private static boolean checkTimeCoherence(PropertyBag header, OffsetDateTime offsetDateTime) {
String startTime = header.getId(NcConstants.REQUEST_HEADER_START_DATE);
String endTime = header.getId(NcConstants.REQUEST_HEADER_END_DATE);
return NcCracUtils.isValidInterval(offsetDateTime, startTime, endTime);
}
}