Except where otherwise noted, this content is Copyright (c) 2020, RTE and licensed under a CC-BY-4.0 license.

Workflow

What is Worflow ?

When you want to simulate adequacy in a network for the next weeks or month, you need to create stochastic study, and generate scenarios (c.f. Begin Stochastic)

Workflow is the preprocessing module for Hadar. Workflow will help user to generate scenarios and sample them to create a stochastic study. It’s a toolbox to create pipelines to transform data for optimizer.

With workflow, you will plug stage themself to create pipeline. Stages can already be developed or you can develop your own Stage.

Recreate data used in Begin Stochastic

To understand workflow power we will generate data previously used in Begin Stochastic

Build fault pipelines

Let’s begin by constant production like nuclear and gas. These productions are not stochastic by default. However fault can occur and it’s what we will generate. For this example all stages belongs to hadar ready-to-use library.

import hadar as hd
import numpy as np
import pandas as pd
import plotly.graph_objects as go
# We generate 5 fault scenarios where a fault remove 100 MW with an odd of 1% by timestep,
# minimum downtime are one step (one hour) and maximum downtime are 12 step.
fault_pipe = hd.RepeatScenario(n=5) + hd.Fault(loss=300, occur_freq=0.01, downtime_min=1, downtime_max=12) + hd.ToShuffler('quantity')

Build stochastic pipelines

In this case, we have to develop our own stage. Let’s begin with wind. We know max wind power, we will apply a linear random between 0 to max for each timestep

class WindRandom(hd.Stage):
    def __init__(self):
        hd.Stage.__init__(self, plug=hd.FreePlug()) # We will see in other example what is FreePlug

    # Method to implement from Stage to create your own Stage with its behaviour
    def _process_timeline(self, timeline: pd.DataFrame) -> pd.DataFrame:
        return timeline * np.random.rand(*timeline.shape)
wind_pipe = hd.RepeatScenario(n=3) + WindRandom() + hd.ToShuffler('quantity')

Then we generate load. For load we will apply a cumulative normal distribution with given value as mean.

class LoadRandom(hd.Stage):
    def __init__(self):
        hd.Stage.__init__(self, plug=hd.FreePlug()) # We will see in other example what is FreePlug

    # Method to implement from Stage to create your own Stage with its behaviour
    def _process_timeline(self, timeline: pd.DataFrame) -> pd.DataFrame:
        return timeline + np.cumsum(np.random.randn(*timeline.shape) * 10, axis=0)
load_pipe = hd.RepeatScenario(n=3) + LoadRandom() + hd.ToShuffler('quantity')

Generate and sample

We use Shuffler object to generate data by pipeline and then sample 10 scenarios

ones = pd.DataFrame({'quantity': np.ones(168)})
# Load are simply a sinus shape
sinus = pd.DataFrame({'quantity': np.sin(np.linspace(-1, -1+np.pi*14, 168))*.2 + .8})

shuffler = hd.Shuffler()
shuffler.add_pipeline(name='gas', data=ones * 1000, pipeline=fault_pipe)
shuffler.add_pipeline(name='nuclear', data=ones * 5000, pipeline=fault_pipe)
shuffler.add_pipeline(name='eolien', data=ones * 1000, pipeline=wind_pipe)
shuffler.add_pipeline(name='load_A', data=sinus * 2000, pipeline=load_pipe)
shuffler.add_pipeline(name='load_B', data=sinus * 3000, pipeline=load_pipe)
shuffler.add_pipeline(name='load_D', data=sinus * 1000, pipeline=load_pipe)
sampling = shuffler.shuffle(nb_scn=10)
def input_plot(title, raw, generate):
    x = np.arange(raw.size)
    fig = go.Figure()
    for i, scn in enumerate(generate):
        fig.add_trace(go.Scatter(x=x, y=scn, name='scn %d' % i, line=dict(color='rgba(100, 100, 100, 0.2)')))

    fig.add_traces(go.Scatter(x=x, y=raw.values.T[0], name='raw'))

    fig.update_layout(title_text=title)
    return fig
input_plot('Gas', ones * 1000, sampling['gas'])
input_plot('Nuclear', ones * 5000, sampling['nuclear'])
input_plot('eolien', ones * 1000, sampling['eolien'])
input_plot('load_A', sinus * 2000, sampling['load_A'])
# for name, values in sampling.items():
#    np.savetxt('../Begin Stochastic/%s.csv' % name, values.T, delimiter=' ', fmt='%04.2f')