CimCracUtils.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.openrao.commons.OpenRaoException;
import com.powsybl.contingency.Contingency;
import com.powsybl.openrao.data.crac.io.cim.xsd.ContingencySeries;
import com.powsybl.openrao.data.crac.io.cim.xsd.MonitoredSeries;
import com.powsybl.openrao.data.crac.io.cim.xsd.Point;
import com.powsybl.openrao.data.crac.io.cim.xsd.SeriesPeriod;
import com.powsybl.openrao.data.crac.io.cim.xsd.TimeSeries;
import com.powsybl.openrao.data.crac.api.cnec.FlowCnec;
import com.powsybl.openrao.data.crac.io.commons.api.ElementaryCreationContext;
import org.apache.commons.lang3.StringUtils;

import java.time.Duration;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * @author Godelaine de Montmorillon {@literal <godelaine.demontmorillon at rte-france.com>}
 */
public final class CimCracUtils {

    private static final DateTimeFormatter CRAC_DATE_TIME_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mmX");

    private static final Comparator<Point> REVERSE_POINT_COMPARATOR = (new PointPositionComparator()).reversed();

    private CimCracUtils() { }

    public static Contingency getContingencyFromCrac(ContingencySeries cimContingency, CimCracCreationContext cracCreationContext) {
        ElementaryCreationContext context = cracCreationContext.getContingencyCreationContextById(cimContingency.getMRID());
        if (context == null || !context.isImported()) {
            return null;
        }
        return cracCreationContext.getCrac().getContingency(context.getCreatedObjectId());
    }

    public static Set<FlowCnec> getFlowCnecsFromCrac(MonitoredSeries monitoredSeries, CimCracCreationContext cracCreationContext) {
        MonitoredSeriesCreationContext mscc = cracCreationContext.getMonitoredSeriesCreationContext(monitoredSeries.getMRID());
        if (mscc == null) {
            return new HashSet<>();
        }
        return mscc.getCreatedCnecIds().stream().map(cnecId -> cracCreationContext.getCrac().getFlowCnec(cnecId)).collect(Collectors.toSet());
    }

    public static void applyActionToEveryPoint(List<TimeSeries> cimTimeSeries, java.time.Instant timestamp, Consumer<? super Point> action) {
        cimTimeSeries.forEach(
            timeSerie -> timeSerie.getPeriod().forEach(
                period -> {
                    List<Point> points = period.getPoint();
                    points.sort(REVERSE_POINT_COMPARATOR);
                    Optional<Integer> previousPosition = Optional.empty();
                    for (Point point : points) {
                        final int currentPosition = point.getPosition();
                        if (isTimestampInPeriod(timestamp, timeSerie, period, currentPosition, previousPosition)) {
                            action.accept(point);
                        }
                        previousPosition = Optional.of(currentPosition);
                    }
                }
            )
        );
    }

    private static String getCurveTypeFromTimeSeries(TimeSeries cimTimeSerie) {
        String curveType = cimTimeSerie.getCurveType();
        if (StringUtils.isBlank(curveType)) {
            curveType = CimConstants.VARIABLE_SIZED_BLOCK_CURVE;
        }
        if (!curveType.equals(CimConstants.VARIABLE_SIZED_BLOCK_CURVE)
                && !curveType.equals(CimConstants.SEQUENTIAL_FIXED_SIZE_BLOCKS_CURVE_TYPE)) {
            throw new OpenRaoException("CurveType not supported: " + curveType);
        }
        return curveType;
    }

    private static boolean isTimestampInPeriod(Instant timestamp, TimeSeries timeSerie, SeriesPeriod period, int position, Optional<Integer> endPosition) {
        final String curveType = CimCracUtils.getCurveTypeFromTimeSeries(timeSerie);
        final Duration periodResolution = Duration.parse(period.getResolution().toString());
        final Instant periodStart = CimCracUtils.parseDateTime(period.getTimeInterval().getStart());
        final Instant periodEnd = CimCracUtils.parseDateTime(period.getTimeInterval().getEnd());

        Instant pointStart = periodStart.plus(periodResolution.multipliedBy(position - 1L));
        // default "A03"
        Instant pointEnd = periodEnd;
        if (curveType.equals(CimConstants.SEQUENTIAL_FIXED_SIZE_BLOCKS_CURVE_TYPE)) {
            pointEnd = periodStart.plus(periodResolution.multipliedBy(position));
        } else {
            if (endPosition.isPresent()) {
                pointEnd = periodStart.plus(periodResolution.multipliedBy(endPosition.get() - 1L));
            }
        }

        return pointStart.compareTo(timestamp) <= 0 && pointEnd.isAfter(timestamp);
    }

    private static Instant parseDateTime(String dateTimeStringFromCrac) {
        return OffsetDateTime.parse(dateTimeStringFromCrac, CRAC_DATE_TIME_FORMAT).toInstant();
    }
}