Storage

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

We has already seen Consumption, Production and Link to attach on node. Hadar has also a Stockage element. We will work on a simple network with two nodes : one with two producitons (stochastic and constant) other with consumption and stockage

img

img

import numpy as np
import hadar as hd

Create data

np.random.seed(12684681)
eolien = np.random.rand(168) * 500 + 200 # random from 200 to 700
load = np.sin(np.linspace(-1, -1+np.pi*14, 168)) * 250 + 750 # sinus moving 500 to 1000

Adequacy without storage

Start storage by remove storage !

study = hd.Study(horizon=eolien.size)\
    .network()\
        .node('a')\
            .production(name='gas', cost=100, quantity=200)\
            .production(name='nulcear', cost=50, quantity=300)\
            .production(name='eolien', cost=10, quantity=eolien)\
        .node('b')\
            .consumption(name='load', cost=10 ** 6, quantity=load)\
        .link(src='a', dest='b', cost=1, quantity=2000)\
    .build()

optim = hd.LPOptimizer()
res = optim.solve(study)

plot_without = hd.HTMLPlotting(agg=hd.ResultAnalyzer(study=study, result=res), unit_symbol='MW')
plot_without.network().node('b').stack()

Node B has a lot of lost of load. Network has not enough power to sustain consumption during peak.

plot_without.network().node('a').stack()

Productions are used immediately just to match load

Use storage

Now we add a storage. In our case cell efficiency is 80%, efficient must be < 1, Hadar use eff=0.99 as default. Other important parameter is cost it represents cost of storage per quantity during on time-step. cost at 0 or positive mean we want to minimize storage used. By default Hadar use cost=0.

So in the configuration, cost=0and eff=0.80. Therefore, a quantity stored costs 25% (\(\frac{1}{0.8} = 1.25\)) higher than same production without stored before. At any time Hadar has choice between these productions and cost.

Prod

use cost

stored before use cost

eolien

10

12,5

nuclear

50

62,75

gas

100

125

Moreover than just fix lost of load, storage can also optimize productions. Looks, a stored nuclear or eolien production is cheaper than a direct gas production. Hadar knows it and will use it !

study = hd.Study(horizon=eolien.size)\
    .network()\
        .node('a')\
            .production(name='gas', cost=100, quantity=200)\
            .production(name='nulcear', cost=50, quantity=300)\
            .production(name='eolien', cost=10, quantity=eolien)\
        .node('b')\
            .consumption(name='load', cost=10 ** 6, quantity=load)\
            .storage(name='cell', init_capacity=200, capacity=800, flow_in=400, flow_out=400, eff=.8)\
        .link(src='a', dest='b', cost=1, quantity=2000)\
    .build()

res = optim.solve(study)
plot = hd.HTMLPlotting(agg=hd.ResultAnalyzer(study=study, result=res), unit_symbol='MW')
plot.network().node('b').stack()

Yeah ! We avoid network shutdown !

plot.network().node('b').storage('cell').candles()

Hadar fills cell before each peaks.

plot.network().node('a').stack()

And yes, Hadars starts nuclear before peak, and use less gas during peak.

Use storage with negative cost

What happen, if we use negative cost ?

In this case, storage has some interest. If interest is higher than gain from optimizing productions. Hadar will automatically fill cell.

study = hd.Study(horizon=eolien.size)\
    .network()\
        .node('a')\
            .production(name='gas', cost=100, quantity=200)\
            .production(name='nulcear', cost=50, quantity=300)\
            .production(name='eolien', cost=10, quantity=eolien)\
        .node('b')\
            .consumption(name='load', cost=10 ** 6, quantity=load)\
            .storage(name='cell', init_capacity=200, capacity=800, flow_in=400, flow_out=400, eff=.8, cost=-10)\
        .link(src='a', dest='b', cost=1, quantity=2000)\
    .build()

res = optim.solve(study)
plot_cost_neg = hd.HTMLPlotting(agg=hd.ResultAnalyzer(study=study, result=res), unit_symbol='MW')
plot_cost_neg.network().node('b').storage('cell').candles()

Hadar doesn’t try to optimize import, now it saves into storage to earn interest.