com.powsybl.metrix.mapping.TimeSeriesDslLoader.groovy Maven / Gradle / Ivy
/*
* 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/.
* SPDX-License-Identifier: MPL-2.0
*/
package com.powsybl.metrix.mapping
import com.powsybl.iidm.network.Bus
import com.powsybl.iidm.network.Injection
import com.powsybl.iidm.network.Network
import com.powsybl.iidm.network.TwoWindingsTransformer
import com.powsybl.timeseries.ReadOnlyTimeSeriesStore
import com.powsybl.timeseries.TimeSeriesFilter
import com.powsybl.timeseries.ast.NodeCalc
import com.powsybl.timeseries.dsl.CalculatedTimeSeriesGroovyDslLoader
import org.apache.commons.lang3.StringUtils
import org.codehaus.groovy.control.CompilerConfiguration
import org.codehaus.groovy.control.customizers.ImportCustomizer
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.nio.file.Files
import java.nio.file.Path
import static com.powsybl.metrix.mapping.EquipmentMappingData.mapToEquipments
import static com.powsybl.metrix.mapping.EquipmentTsData.equipmentTimeSeries
import static com.powsybl.metrix.mapping.FilteredData.unmappedEquipments
import static com.powsybl.metrix.mapping.GeneratorGroupTsData.generatorGroupTimeSeries
import static com.powsybl.metrix.mapping.IgnoreLimitsData.ignoreLimits
import static com.powsybl.metrix.mapping.LoadGroupTsData.loadGroupTimeSeries
import static com.powsybl.metrix.mapping.ParametersData.parametersData
import static com.powsybl.metrix.mapping.PlannedOutagesData.mapPlannedOutages
import static com.powsybl.metrix.mapping.SimpleMappingData.mapToBreakers
import static com.powsybl.metrix.mapping.SimpleVariableMappingData.mapToSimpleVariableEquipments
/**
* @author Paul Bui-Quang {@literal }
*/
class TimeSeriesDslLoader {
private static final Logger LOGGER = LoggerFactory.getLogger(TimeSeriesDslLoader.class)
private static final String MAPPING_SCRIPT_SECTION = "Mapping script"
protected static final String DEFAULT_MAPPING_SCRIPT_NAME = "mapping.groovy"
protected final GroovyCodeSource dslSrc
protected String equipmentGroupTypes = "com.powsybl.metrix.mapping.SimpleEquipmentGroupType"
TimeSeriesDslLoader(GroovyCodeSource dslSrc) {
this.dslSrc = Objects.requireNonNull(dslSrc)
}
TimeSeriesDslLoader(File dslFile) {
this(new GroovyCodeSource(dslFile))
}
TimeSeriesDslLoader(String script) {
this(new GroovyCodeSource(script, "script", GroovyShell.DEFAULT_CODE_BASE))
}
TimeSeriesDslLoader(Reader reader) {
this(new GroovyCodeSource(reader, DEFAULT_MAPPING_SCRIPT_NAME, GroovyShell.DEFAULT_CODE_BASE))
}
TimeSeriesDslLoader(Reader reader, String fileName) {
this(new GroovyCodeSource(reader, fileName, GroovyShell.DEFAULT_CODE_BASE))
}
TimeSeriesDslLoader(Path path) {
this(Files.newBufferedReader(path), path.getFileName().toString())
}
private static logWarn(LogDslLoader logDslLoader, String message) {
if (logDslLoader == null) {
return
}
logDslLoader.logWarn(message)
}
protected List getStaticStars() {
List staticStars = new ArrayList<>()
staticStars.add(equipmentGroupTypes)
return staticStars
}
private CompilerConfiguration createCompilerConfig() {
def imports = new ImportCustomizer()
imports.addStaticStars("com.powsybl.iidm.network.EnergySource")
imports.addStaticStars("com.powsybl.iidm.network.Country")
imports.addStaticStars("com.powsybl.metrix.mapping.EquipmentVariable")
getStaticStars().forEach(staticStars -> imports.addStaticStars(staticStars))
def config = CalculatedTimeSeriesGroovyDslLoader.createCompilerConfig()
config.addCompilationCustomizers(imports)
}
static void bind(Binding binding, Network network, ReadOnlyTimeSeriesStore store, DataTableStore dataTableStore, MappingParameters parameters, TimeSeriesMappingConfig config, TimeSeriesMappingConfigLoader loader, LogDslLoader logDslLoader, ComputationRange computationRange) {
ComputationRange checkedComputationRange = ComputationRange.check(computationRange, store)
ComputationRange fullComputationRange = ComputationRange.check(store)
CalculatedTimeSeriesGroovyDslLoader.bind(binding, store, config.getTimeSeriesNodes())
DataTableDslLoader.bind(binding, dataTableStore)
TimeSeriesMappingConfigStats stats = new TimeSeriesMappingConfigStats(store, checkedComputationRange)
// map the base case to network variable
binding.network = network
def mappeable = { injection ->
Bus bus = injection.getTerminal().getBusView().getBus()
bus != null && bus.isInMainConnectedComponent()
}
def generatorsFilteringContext = network.getGenerators().findAll(mappeable).collect { injection -> new FilteringContext((Injection) injection) }
def loadsFilteringContext = network.getLoads().findAll(mappeable).collect { injection -> new FilteringContext((Injection) injection) }
def danglingLinesFilteringContext = network.getDanglingLines().findAll(mappeable).collect { injection -> new FilteringContext((Injection) injection) }
def hvdcLinesFilteringContext = network.getHvdcLines().collect { hvdcLine -> new FilteringContext(hvdcLine) }
def lccConverterStationsFilteringContext = network.getLccConverterStations().collect { converter -> new FilteringContext(converter) }
def vscConverterStationsFilteringContext = network.getVscConverterStations().collect { converter -> new FilteringContext(converter) }
def transformersFilteringContext = network.getTwoWindingsTransformers().collect { transformer -> new FilteringContext(transformer) }
def linesFilteringContext = network.getLines().collect { line -> new FilteringContext(line) }
def phaseTapChangersFilteringContext = network.getTwoWindingsTransformers().findAll {transformer -> transformer.hasPhaseTapChanger() }
.collect { transformer -> new FilteringContext((TwoWindingsTransformer) transformer) }
def ratioTapChangersFilteringContext = network.getTwoWindingsTransformers().findAll {transformer -> transformer.hasRatioTapChanger() }
.collect { transformer -> new FilteringContext((TwoWindingsTransformer) transformer) }
def switchesFilteringContext = network.getSwitchStream().collect { s -> new FilteringContext(s) }
// parameters
binding.parameters = { Closure closure ->
parametersData(closure, parameters)
}
// mapping
binding.mapToGenerators = { Closure closure ->
mapToEquipments(binding, loader, closure, generatorsFilteringContext, MappableEquipmentType.GENERATOR)
}
binding.mapToLoads = { Closure closure ->
mapToEquipments(binding, loader, closure, loadsFilteringContext, MappableEquipmentType.LOAD)
}
binding.mapToBoundaryLines = { Closure closure ->
mapToEquipments(binding, loader, closure, danglingLinesFilteringContext, MappableEquipmentType.BOUNDARY_LINE)
}
binding.mapToHvdcLines = { Closure closure ->
mapToEquipments(binding, loader, closure, hvdcLinesFilteringContext, MappableEquipmentType.HVDC_LINE)
}
binding.mapToTransformers = { Closure closure ->
mapToEquipments(binding, loader, closure, transformersFilteringContext, MappableEquipmentType.TRANSFORMER)
}
binding.mapToLines = { Closure closure ->
mapToEquipments(binding, loader, closure, linesFilteringContext, MappableEquipmentType.LINE)
}
binding.mapToPhaseTapChangers = { Closure closure ->
mapToSimpleVariableEquipments(binding, loader, closure, phaseTapChangersFilteringContext, MappableEquipmentType.PHASE_TAP_CHANGER)
}
binding.mapToRatioTapChangers = { Closure closure ->
mapToSimpleVariableEquipments(binding, loader, closure, ratioTapChangersFilteringContext, MappableEquipmentType.RATIO_TAP_CHANGER)
}
binding.mapToLccConverterStations = { Closure closure ->
mapToSimpleVariableEquipments(binding, loader, closure, lccConverterStationsFilteringContext, MappableEquipmentType.LCC_CONVERTER_STATION)
}
binding.mapToVscConverterStations = { Closure closure ->
mapToSimpleVariableEquipments(binding, loader, closure, vscConverterStationsFilteringContext, MappableEquipmentType.VSC_CONVERTER_STATION)
}
binding.mapToBreakers = { Closure closure ->
mapToBreakers(binding, loader, closure, switchesFilteringContext)
}
binding.mapPlannedOutages = { Closure closure ->
mapPlannedOutages(binding, store, loader, closure, transformersFilteringContext, linesFilteringContext, generatorsFilteringContext, checkedComputationRange.getVersions())
}
// unmapped
binding.unmappedGenerators = { Closure closure ->
unmappedEquipments(binding, loader, closure, generatorsFilteringContext, MappableEquipmentType.GENERATOR)
}
binding.unmappedLoads = { Closure closure ->
unmappedEquipments(binding, loader, closure, loadsFilteringContext, MappableEquipmentType.LOAD)
}
binding.unmappedBoundaryLines = { Closure closure ->
unmappedEquipments(binding, loader, closure, danglingLinesFilteringContext, MappableEquipmentType.BOUNDARY_LINE)
}
binding.unmappedHvdcLines = { Closure closure ->
unmappedEquipments(binding, loader, closure, hvdcLinesFilteringContext, MappableEquipmentType.HVDC_LINE)
}
binding.unmappedPhaseTapChangers = { Closure closure ->
unmappedEquipments(binding, loader, closure, phaseTapChangersFilteringContext, MappableEquipmentType.PHASE_TAP_CHANGER)
}
// time series with specific ignore limits
binding.ignoreLimits = { Closure closure ->
ignoreLimits(loader, closure)
}
// equipments for which time series must be provided
binding.provideTsGenerators = { Closure closure ->
equipmentTimeSeries(binding, loader, closure, generatorsFilteringContext, MappableEquipmentType.GENERATOR, logDslLoader)
}
binding.provideTsLoads = { Closure closure ->
equipmentTimeSeries(binding, loader, closure, loadsFilteringContext, MappableEquipmentType.LOAD, logDslLoader)
}
binding.provideTsHvdcLines = { Closure closure ->
equipmentTimeSeries(binding, loader, closure, hvdcLinesFilteringContext, MappableEquipmentType.HVDC_LINE, logDslLoader)
}
binding.provideTsTransformers = { Closure closure ->
equipmentTimeSeries(binding, loader, closure, transformersFilteringContext, MappableEquipmentType.TRANSFORMER, logDslLoader)
}
binding.provideTsLines = { Closure closure ->
equipmentTimeSeries(binding, loader, closure, linesFilteringContext, MappableEquipmentType.LINE, logDslLoader)
}
binding.provideTsBoundaryLines = { Closure closure ->
equipmentTimeSeries(binding, loader, closure, danglingLinesFilteringContext, MappableEquipmentType.BOUNDARY_LINE, logDslLoader)
}
binding.provideTsPhaseTapChangers = { Closure closure ->
equipmentTimeSeries(binding, loader, closure, phaseTapChangersFilteringContext, MappableEquipmentType.PHASE_TAP_CHANGER, logDslLoader)
}
binding.provideTsRatioTapChangers = { Closure closure ->
equipmentTimeSeries(binding, loader, closure, ratioTapChangersFilteringContext, MappableEquipmentType.RATIO_TAP_CHANGER, logDslLoader)
}
binding.provideTsBreakers = { Closure closure ->
equipmentTimeSeries(binding, loader, closure, switchesFilteringContext, MappableEquipmentType.SWITCH, logDslLoader)
}
binding.provideTsLccConverterStations = { Closure closure ->
equipmentTimeSeries(binding, loader, closure, lccConverterStationsFilteringContext, MappableEquipmentType.LCC_CONVERTER_STATION, logDslLoader)
}
binding.provideTsVscConverterStations = { Closure closure ->
equipmentTimeSeries(binding, loader, closure, vscConverterStationsFilteringContext, MappableEquipmentType.VSC_CONVERTER_STATION, logDslLoader)
}
binding.provideGroupTsGenerators = { Closure closure ->
generatorGroupTimeSeries(binding, loader, closure, generatorsFilteringContext, MappableEquipmentType.GENERATOR, logDslLoader)
}
binding.provideGroupTsLoads = { Closure closure ->
loadGroupTimeSeries(binding, loader, closure, loadsFilteringContext, MappableEquipmentType.LOAD, logDslLoader)
}
// metadatas
binding.stringMetadatas = { Closure closure ->
loader.stringMetadatas(store)
}
binding.doubleMetadatas = { Closure closure ->
loader.doubleMetadatas(store)
}
binding.intMetadatas = { Closure closure ->
loader.intMetadatas(store)
}
binding.booleanMetadatas = { Closure closure ->
loader.booleanMetadatas(store)
}
binding.getMetadataTags = { NodeCalc tsNode ->
loader.tsMetadata(tsNode, store)
}
binding.tag = { NodeCalc tsNode, String tag, String parameter = StringUtils.EMPTY ->
loader.tag(tsNode, tag, parameter)
}
// statistics
binding.sum = { NodeCalc tsNode, Boolean all_versions = true ->
stats.getTimeSeriesSum(tsNode, all_versions ? fullComputationRange : checkedComputationRange)
}
binding.min = { NodeCalc tsNode, Boolean all_versions = true ->
stats.getTimeSeriesMin(tsNode, all_versions ? fullComputationRange : checkedComputationRange)
}
binding.max = { NodeCalc tsNode, Boolean all_versions = true ->
stats.getTimeSeriesMax(tsNode, all_versions ? fullComputationRange : checkedComputationRange)
}
binding.avg = { NodeCalc tsNode, Boolean all_versions = true ->
stats.getTimeSeriesAvg(tsNode, all_versions ? fullComputationRange : checkedComputationRange)
}
binding.median = { NodeCalc tsNode, Boolean all_versions = true ->
stats.getTimeSeriesMedian(tsNode, all_versions ? fullComputationRange : checkedComputationRange)
}
// Since the values of EquipmentVariable were previously written in camelCase, we need to add them again for
// backward compatibility
EquipmentVariable.values().toList().forEach {value -> binding[value.getVariableName()] = value}
}
protected evaluate(TimeSeriesMappingConfig config, TimeSeriesMappingConfigLoader loader, Network network, MappingParameters parameters, ReadOnlyTimeSeriesStore store, DataTableStore dataTableStore, Writer out, ComputationRange computationRange) {
Binding binding = new Binding()
LogDslLoader logDslLoader = LogDslLoader.create(binding, out, MAPPING_SCRIPT_SECTION)
bind(binding, network, store, dataTableStore, parameters, config, loader, logDslLoader, computationRange)
if (out != null) {
binding.out = out
}
def shell = new GroovyShell(binding, createCompilerConfig())
shell.evaluate(dslSrc)
TimeSeriesMappingConfigChecker configChecker = new TimeSeriesMappingConfigChecker(config)
configChecker.checkMappedVariables()
Set keys = configChecker.getNotMappedEquipmentTimeSeriesKeys()
keys.forEach({ key ->
logWarn(logDslLoader, "provideTs - Time series can not be provided for id " + key.getId() + " because id is not mapped on " + key.getMappingVariable().getVariableName())
})
}
TimeSeriesMappingConfig load(Network network, MappingParameters parameters, ReadOnlyTimeSeriesStore store, DataTableStore dataTableStore, ComputationRange computationRange) {
load(network, parameters, store, dataTableStore, null, computationRange)
}
TimeSeriesMappingConfig load(Network network, MappingParameters parameters, ReadOnlyTimeSeriesStore store, DataTableStore dataTableStore, Writer out, ComputationRange computationRange) {
long start = System.currentTimeMillis()
TimeSeriesMappingConfig config = new TimeSeriesMappingConfig(network)
TimeSeriesMappingConfigLoader loader = new TimeSeriesMappingConfigLoader(config, store.getTimeSeriesNames(new TimeSeriesFilter()))
evaluate(config, loader, network, parameters, store, dataTableStore, out, computationRange)
LOGGER.trace("Dsl Loading done in {} ms", (System.currentTimeMillis() - start))
config
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy