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
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=0
and 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.