MetrixAnalysis.java
/*
* Copyright (c) 2021, 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/.
* SPDX-License-Identifier: MPL-2.0
*/
package com.powsybl.metrix.integration.metrix;
import com.google.common.base.Stopwatch;
import com.powsybl.contingency.ContingenciesProvider;
import com.powsybl.iidm.network.Network;
import com.powsybl.metrix.integration.*;
import com.powsybl.metrix.integration.exceptions.MappingScriptLoadingException;
import com.powsybl.metrix.integration.exceptions.MetrixScriptLoadingException;
import com.powsybl.metrix.integration.io.MetrixConfigResult;
import com.powsybl.metrix.integration.utils.LocalThreadExecutor;
import com.powsybl.metrix.mapping.*;
import com.powsybl.timeseries.ReadOnlyTimeSeriesStore;
import com.powsybl.timeseries.ast.NodeCalc;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
/**
* @author Valentin Berthault {@literal <valentin.berthault at rte-france.com>}
*/
public class MetrixAnalysis {
private static final Logger LOGGER = LoggerFactory.getLogger(MetrixAnalysis.class);
private static final String DEFAULT_SCHEMA_NAME = "default";
public static final String TIME_SERIES_MAPPING_LOADING = "[%s] Time series mapping loaded in %d ms";
public static final String TIME_SERIES_MAPPING_LOADING_ERROR = "[%s] Error loading Time series mapping after %d ms";
public static final String METRIX_DSL_DATA_LOADING = "[%s] Metrix dsl data loaded in %d ms";
public static final String METRIX_DSL_DATA_LOADING_ERROR = "[%s] Error loading Metrix dsl data after %d ms";
private final NetworkSource networkSource;
private final TimeSeriesDslLoader timeSeriesDslLoader;
private final Reader metrixDslReader;
private final Reader remedialActionsReader;
private final ContingenciesProvider contingenciesProvider;
private final ReadOnlyTimeSeriesStore store;
private final MetrixAppLogger appLogger;
private final ComputationRange computationRange;
private final DataTableStore dataTableStore;
private Consumer<Future<?>> updateTask;
private Writer scriptLogWriter;
private Writer inputLogWriter;
private String schemaName;
public void setUpdateTask(Consumer<Future<?>> updateTask) {
this.updateTask = updateTask;
}
public void setScriptLogWriter(Writer scriptLogWriter) {
this.scriptLogWriter = scriptLogWriter;
}
public void setInputLogWriter(Writer inputLogWriter) {
this.inputLogWriter = inputLogWriter;
}
public void setSchemaName(String schemaName) {
if (schemaName != null) {
this.schemaName = schemaName;
}
}
private void initDefaultParameters() {
this.updateTask = ignore -> {
};
this.scriptLogWriter = null;
this.inputLogWriter = null;
this.schemaName = DEFAULT_SCHEMA_NAME;
}
public MetrixAnalysis(NetworkSource networkSource, TimeSeriesDslLoader timeSeriesDslLoader, Reader metrixDslReader,
Reader remedialActionsReader, ContingenciesProvider contingenciesProvider,
ReadOnlyTimeSeriesStore store, DataTableStore dataTableStore, MetrixAppLogger appLogger,
ComputationRange computationRange) {
this.networkSource = Objects.requireNonNull(networkSource);
this.timeSeriesDslLoader = Objects.requireNonNull(timeSeriesDslLoader);
this.store = Objects.requireNonNull(store);
this.dataTableStore = Objects.requireNonNull(dataTableStore);
this.appLogger = Objects.requireNonNull(appLogger);
this.metrixDslReader = metrixDslReader;
this.remedialActionsReader = remedialActionsReader;
this.contingenciesProvider = contingenciesProvider;
this.computationRange = computationRange;
initDefaultParameters();
}
public MetrixAnalysisResult runAnalysis(String id) {
MetrixParameters metrixParameters = MetrixParameters.load();
MappingParameters mappingParameters = MappingParameters.load();
Network network = networkSource.copy();
try (BufferedWriter scriptLogBufferedWriter = scriptLogWriter != null ? new BufferedWriter(scriptLogWriter) : null;
BufferedWriter inputLogBufferedWriter = inputLogWriter != null ? new BufferedWriter(inputLogWriter) : null) {
TimeSeriesMappingConfig mappingConfig = loadMappingConfig(timeSeriesDslLoader, network, mappingParameters, scriptLogBufferedWriter, id);
Map<String, NodeCalc> timeSeriesNodesAfterMapping = new HashMap<>(mappingConfig.getTimeSeriesNodes());
MetrixDslData metrixDslData = null;
Map<String, NodeCalc> timeSeriesNodesAfterMetrix = null;
if (metrixDslReader != null) {
metrixDslData = loadMetrixDslData(metrixDslReader, network, metrixParameters, mappingConfig, scriptLogBufferedWriter, id);
timeSeriesNodesAfterMetrix = new HashMap<>(mappingConfig.getTimeSeriesNodes());
}
MetrixInputAnalysisResult inputs = new MetrixInputAnalysis(remedialActionsReader, contingenciesProvider, network, metrixDslData, dataTableStore, inputLogBufferedWriter, scriptLogBufferedWriter).runAnalysis();
MetrixConfigResult metrixConfigResult = new MetrixConfigResult(timeSeriesNodesAfterMapping, timeSeriesNodesAfterMetrix);
return new MetrixAnalysisResult(metrixDslData, mappingConfig, network, metrixParameters, mappingParameters, metrixConfigResult, inputs.getContingencies(), inputs.getRemedials());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private TimeSeriesMappingConfig loadMappingConfig(TimeSeriesDslLoader timeSeriesDslLoader, Network network, MappingParameters mappingParameters, Writer writer, String id) {
appLogger.tagged("info")
.log("[%s] Loading time series mapping...", schemaName);
Stopwatch stopwatch = Stopwatch.createStarted();
boolean inError = false;
try {
CompletableFuture<TimeSeriesMappingConfig> mappingFuture = new LocalThreadExecutor<TimeSeriesMappingConfig>("Script_TS_" + id)
.supplyAsync(() -> timeSeriesDslLoader.load(network, mappingParameters, store, dataTableStore, writer, computationRange));
updateTask.accept(mappingFuture);
return mappingFuture.get();
} catch (ExecutionException e) {
inError = true;
throw new MappingScriptLoadingException(e);
} catch (InterruptedException e) {
LOGGER.warn("Mapping has been interrupted!", e);
inError = true;
Thread.currentThread().interrupt();
throw new RuntimeException(e.getMessage());
} finally {
appLogger.tagged("performance")
.log(inError ? TIME_SERIES_MAPPING_LOADING_ERROR : TIME_SERIES_MAPPING_LOADING, schemaName, stopwatch.stop().elapsed(TimeUnit.MILLISECONDS));
updateTask.accept(null);
}
}
private MetrixDslData loadMetrixDslData(Reader metrixDslReader, Network network, MetrixParameters metrixParameters, TimeSeriesMappingConfig mappingConfig, Writer writer, String id) {
appLogger.tagged("info")
.log("[%s] Loading metrix dsl...", schemaName);
Stopwatch stopwatch = Stopwatch.createStarted();
boolean inError = false;
try {
CompletableFuture<MetrixDslData> metrixFuture = new LocalThreadExecutor<MetrixDslData>("Script_M_" + id)
.supplyAsync(() -> MetrixDslDataLoader.load(metrixDslReader, network, metrixParameters, store, dataTableStore, mappingConfig, writer));
updateTask.accept(metrixFuture);
MetrixDslData metrixDslData = metrixFuture.get();
metrixDslData.setComputationType(metrixParameters.getComputationType());
return metrixDslData;
} catch (ExecutionException e) {
inError = true;
throw new MetrixScriptLoadingException(e);
} catch (InterruptedException e) {
LOGGER.warn("Metrix dsl loading has been interrupted!", e);
inError = true;
Thread.currentThread().interrupt();
return null;
} finally {
appLogger.tagged("performance")
.log(inError ? METRIX_DSL_DATA_LOADING_ERROR : METRIX_DSL_DATA_LOADING, schemaName, stopwatch.stop().elapsed(TimeUnit.MILLISECONDS));
updateTask.accept(null);
}
}
}