drawing


Welcome to the showcase!


Navigation:
Step forward: SPACE | Step backward: SHIFT+SPACE
Chapters: / | Subslides: /
Overview: Esc

drawing

About Draf

What is Draf?

Draf stands for "Demand Response Analysis Framework" and is an easy-to-use open source decision support tool that enables the economic and ecological evaluation of industrial demand response potential. It is devoloped in Python and uses the power of Gurobi to build and solve multi-objective optimization models of industrial energy systems and production processes to quantify the cost and green-house-gas saving potentials of price based demand response. Target groups are researchers, engineers, and decision-makers of companies in industrial or commercial sectors with some basic knowledge of the Python programming language.

Draf is developed by Markus Fleschutz in a cooperative PhD between Cork Institute of Technology and the Karlsruhe University of Applied Sciences and under the supervision of Dr. Michael D. Murphy and Dr.-Ing Marco Braun. More information can be found on the website.

Venn-Diagramm

Why Draf?

  • The core-idea of demand response is to shift electric demand to hours with cheap electricity prices e.g. when shares of renewable energy sources are high.
  • For industrial companies, price-based demand response is an essential and promising approach to reduce both electricity costs and – with increasing relevance – carbon emissions.
  • The problem with the quantification of demand response potential is that it requires the modeling of the inventives (here: day ahead market prices and carbon dynamic emission factors) and the flexible entities (batteries, heatpumps etc.) with its most relevant constraints which can be very complex and time consuming.
  • Draf solves this problem by making the quantification process of demand response potentials automated and easy-to-use. It provides market data, predefined models, modeling assistance, and visualization tools and helps the user to focus on the important aspects.

Core areas

Draf combines several task areas that are important for the quantification of demand response potentials. The most important ones are:

  1. Easy access to electricity market data.
    E.g. if a case study is configured with a specific year and country, Draf downloads the according day-ahead market prices and historic national electricity generation data, preprocesses it, and prepares the real-time prices and carbon emission factors that are needed for the analysis.
  2. Several predefined models.
    ... of typical industrial energy systems that can easily be parameterized.
  3. Fully automated scenario generation.
    In a scenario, only a few parameters are changed.
  4. Several built-in analysis and visualisation tools.
    Venn-Diagramm

Input/Output example

This graph gives you a feeling of typical inputs and outputs:

Venn-Diagramm
drawing

A quick-start showcase

We start with a straightforward model. Let's say we have a 100 kWpeak Photovoltaic System (PV), a 1 MWhel Battery Energy System (BES), and given electricity demand and want to know the cost and carbon reduction potential for price based demand response considering a 50 €/kW peak-load price and a day-ahead market price. We can use the "PV_BES"-model of draf:

drawingSchematic depiction of model "PV_BES" with its parameters and variables.

Case study setup & scenario generation

These few lines of codes import the model PV_BES, initializes a case study, adds a reference scenario, sets the default parameters from the PV_BES-model, changes the user-defined parameters P_PV_CAPx_(existing 'PV power) and c_GRID_peak_(electricity peak price), builds 8 scenarios (2 pricing tariffs with 4 pareto points each), improves the pareto weighting factors so that the pareto points are more equally distributed, sets the model, optimizes it and saves the whole case study.

In [4]:
import draf
from models import PV_BES as mod

cs = draf.CaseStudy(name="ShowCase", year=2017, freq="60min", country="DE")

cs.add_REF_scen(doc="no BES").set_params(mod.params_func).update_params(
    P_PV_CAPx_=100, c_GRID_peak_=50)

cs.add_scens([("c_GRID_T", "t", ["c_GRID_RTP_T", "c_GRID_TOU_T"]),
              ("E_BES_CAPx_", "b", [1000])], nParetoPoints=4)

cs.improve_pareto_and_set_model(mod.model_func).optimize(mod.postprocess_func).save();
Using license file D:\Programme\Anaconda3\gurobi.lic
Academic license - for non-commercial use only
Successfully solved 9 scenarios with an average solving time of 0.793 seconds.
CaseStudy saved to D:/mf/draf/results/ShowCase/2019-12-10_143654_.p ( 24.3 MB)

Results

The pareto curve is the main resulting diagram of the draf-analysis. It plots the total costs versus the total carbon emissions for all scenarios. Scenarios can be grouped according to key-words in order to help identify individual pareto fronts. Here, the pareto-weighting factors are denoted with α.

In [5]:
cs.plot.pareto_curves(groups=["REF", "TOU", "RTP"], label_verbosity=4)

More plotting

Parameter (input)

Parameter scalars for all scenarios

This table shows all parameters of all scenarios with its values, unit and description.

In [66]:
cs.plot.table("p")
Note: Bold font indicate deviation from first/reference scenario.
Out[66]:
REF sc1 sc2 sc3 sc4 sc5 sc6 sc7 sc8 unit doc
p
alpha_ 0 0 0.333333 0.666667 1 0 0.333333 0.666667 1 pareto weighting factor
n_C_ 1.38897e-05 1.38897e-05 1.38897e-05 1.38897e-05 1.38897e-05 1.38897e-05 1.38897e-05 1.38897e-05 1.38897e-05 normalization factor
n_CE_ 4.31839e-09 4.31839e-09 4.31839e-09 4.31839e-09 4.31839e-09 4.31839e-09 4.31839e-09 4.31839e-09 4.31839e-09 normalization factor
c_GRID_peak_ 50 50 50 50 50 50 50 50 50 €/kW_el peak price
P_PV_CAPx_ 100 100 100 100 100 100 100 100 100 kW_peak existing capacity PV
E_BES_CAPx_ 0 1000 1000 1000 1000 1000 1000 1000 1000 kW_el existing capacity BES
eta_BES_time_ 0.999 0.999 0.999 0.999 0.999 0.999 0.999 0.999 0.999 storing efficiency
eta_BES_in_ 0.999 0.999 0.999 0.999 0.999 0.999 0.999 0.999 0.999 loading efficiency
k_BES_in_per_capa_ 1 1 1 1 1 1 1 1 1 ratio of charging power / capacity
k_BES_out_per_capa_ 1 1 1 1 1 1 1 1 1 ratio of discharging power / capacity (aka C rate)
timelog_params_ 0.838508 0 0 0 0 0 0 0 0 seconds time for building the params
timelog_model_ 2.79629 2.08576 2.0242 2.09764 2.09404 2.35387 2.24089 2.36363 2.07149 seconds time for building the model
mipGap_ 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 % Gap to relaxed solution
timelog_solve_ 0.324877 1.15911 1.09521 1.14603 0.508448 0.905575 0.906073 0.782783 0.310037 seconds time for solving the model

For all non-scalars entities, the describe function gives an overview of one ore many scenarios:

In [67]:
cs.plot
Out[67]:
<draf.plotting.cs_plotting.CsPlotter at 0x26543d2a308>
In [68]:
sc = cs.scens.sc1
sc.plot.describe(include_vars=False)
================================================================================
tc_GRID_RTP_T_b1000_a0.0: Parameters
  doc = c_GRID_T=c_GRID_RTP_T; E_BES_CAPx_=1000; alpha_=0.0
================================================================================

 ---------
alpha_                 0.00000 
n_C_                   0.00001 
n_CE_                  0.00000 
c_GRID_peak_          50.00000 €/kW_el
P_PV_CAPx_           100.00000 kW_peak
E_BES_CAPx_            1.00000 MW_el
eta_BES_time_          0.99900 
eta_BES_in_            0.99900 
k_BES_in_per_capa_        1.00000 
k_BES_out_per_capa_        1.00000 
timelog_params_        0.00000 seconds
timelog_model_         2.08576 seconds
mipGap_                0.10000 %
timelog_solve_         1.15911 seconds

T ---------
                         sum        mean         min         max  \
ce_GRID_T       4.835891e+06  552.042355  168.163680  846.098705   
E_dem_T         5.000000e+05   57.077626   40.242549   76.965997   
c_GRID_addon_T  1.148261e+03    0.131080    0.131080    0.131080   
E_PV_profile_T  9.415523e+02    0.107483    0.000000    0.814534   
c_GRID_TOU_T    2.994915e+02    0.034189    0.029372    0.043550   
c_GRID_RTP_T    2.994915e+02    0.034189   -0.083060    0.163520   
c_GRID_T        2.994915e+02    0.034189   -0.083060    0.163520   

                               
ce_GRID_T       gCO2eq/kWh_el  
E_dem_T                kWh_el  
c_GRID_addon_T       €/kWh_el  
E_PV_profile_T  kW_el/kW_peak  
c_GRID_TOU_T         €/kWh_el  
c_GRID_RTP_T         €/kWh_el  
c_GRID_T             €/kWh_el  

Heatmaps

Heatmaps are the perfect plot type to see seasonal and daily patterns of a whole year's timeseries.

In [70]:
sc.plot.heatmap(ent_name="E_dem_T")
In [71]:
sc.plot.heatmap(ent_name="E_PV_T")
In [72]:
sc.plot.heatmap(ent_name="c_GRID_RTP_T")
In [73]:
sc.plot.heatmap(ent_name="ce_GRID_T")
In [74]:
sc.plot.heatmap(ent_name="E_BES_in_T")
In [75]:
sc.plot.heatmap(ent_name="E_BES_out_T")

Variables / Results (output)

Scalars for all scenarios

This code produces a table of all scalar variables of the model with its resulting values, units, and descriptions.

In [76]:
cs.plot.table("v")
Note: Bold font indicate deviation from first/reference scenario.
Out[76]:
REF sc1 sc2 sc3 sc4 sc5 sc6 sc7 sc8 unit doc
v
C_ 71995.9 69008.8 69770 72336.9 118511 69541.1 70940 75039.7 121804 €/a total costs
C_inv_ 0 0 0 0 0 0 0 0 0 investment costs
C_op_ 71995.9 69008.8 69770 72336.9 118511 69541.1 70940 75039.7 121804 €/a operating costs
CE_ 2.31568e+08 2.14108e+08 2.01786e+08 1.93712e+08 1.89929e+08 2.28803e+08 2.07706e+08 1.94421e+08 1.90349e+08 gCO2eq/a total emissions
C_GRID_peak_ 3799.13 3732.58 4930.15 7867.6 53522.1 2943.47 3843.64 7214.17 53553.6 €/a costs for peak price
P_GRID_peak_ 75.9826 74.6517 98.603 157.352 1070.44 58.8694 76.8728 144.283 1071.07 kW_el peak electricity
C_GRID_buy_ 68210.1 65276.2 64839.8 64469.3 64988.9 66597.6 67096.4 67825.5 68250.3 €/a cost for bought electricity
C_GRID_sell_ 13.4039 0 0 0 0 0 0 0 0 €/a earnings for bought electricity

Variables Summary for scenario "sc1"

In [77]:
cs.scens.sc1.plot.describe(include_pars=False)
================================================================================
tc_GRID_RTP_T_b1000_a0.0: Variables
  doc = c_GRID_T=c_GRID_RTP_T; E_BES_CAPx_=1000; alpha_=0.0
================================================================================

 ---------
C_                    69.00879 Thousand €/a
C_inv_                 0.00000 €
C_op_                 69.00879 Thousand €/a
CE_                  214.10811 tCO2eq/a
C_GRID_peak_           3.73258 Thousand €/a
P_GRID_peak_          74.65168 kW_el
C_GRID_buy_           65.27621 Thousand €/a
C_GRID_sell_           0.00000 €/a

T ---------
                        sum        mean  min          max        
E_BES_T        2.548201e+06  290.890549  0.0  1000.000000  kWh_el
E_GRID_buy_T   4.083512e+05   46.615433  0.0    74.651680  kWh_el
E_BES_in_T     1.523552e+05   17.392150  0.0   101.877687  kWh_el
E_BES_out_T    1.498488e+05   17.106028 -0.0    75.982645  kWh_el
E_PV_T         9.415523e+04   10.748314  0.0    81.453351  kWh_el
E_PV_OC_T      9.415523e+04   10.748314  0.0    81.453351  kWh_el
E_GRID_sell_T  0.000000e+00    0.000000  0.0     0.000000  kWh_el
E_PV_FI_T      0.000000e+00    0.000000  0.0     0.000000  kWh_el

Pareto front

In [16]:
cs.plot.pareto_curves(groups=["REF", "TOU", "RTP"])

Sankey

The sankey plot shows the yearly energy sums of key energy flows from left (source) to right (cradle). You can hover over to see the numbers:

In [19]:
cs.scens.sc1.plot.sankey(mod.sankey_func)

Features / modules

Saving & Loading of case studies

At any time, you can save the case study to hard disk like so:

In [20]:
cs.save("test");
CaseStudy saved to D:/mf/draf/results/ShowCase/2019-12-10_143657_test.p ( 33.7 MB)

... and open it later again:

In [39]:
import draf
cs = draf.CaseStudy(fp="D:/mf/draf/results/ShowCase/2019-12-10_143657_test.p")

Data export

Draf is compatible with the powerful xarray-module. Here, parameters and results are comined into one big dataset:

In [40]:
cs.scens.REF.get_xarray_dataset()
Out[40]:
<xarray.Dataset>
Dimensions:         (T: 8760)
Coordinates:
  * T               (T) int64 0 1 2 3 4 5 6 ... 8754 8755 8756 8757 8758 8759
Data variables:
    E_GRID_buy_T    (T) float64 44.33 46.08 43.76 41.85 ... 47.83 45.88 43.15
    E_GRID_sell_T   (T) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0
    E_PV_T          (T) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0
    E_PV_OC_T       (T) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0
    E_PV_FI_T       (T) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0
    E_BES_T         (T) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0
    E_BES_in_T      (T) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0
    E_BES_out_T     (T) float64 -0.0 -0.0 -0.0 -0.0 -0.0 ... -0.0 -0.0 -0.0 -0.0
    ce_GRID_T       (T) float64 507.9 518.0 514.5 525.0 ... 241.2 253.3 241.1
    c_GRID_RTP_T    (T) float64 0.02096 0.0209 0.01813 ... 0.00186 -0.00092
    c_GRID_TOU_T    (T) float64 0.02937 0.02937 0.02937 ... 0.02937 0.02937
    c_GRID_T        (T) float64 0.02096 0.0209 0.01813 ... 0.00186 -0.00092
    c_GRID_addon_T  (T) float64 0.1311 0.1311 0.1311 ... 0.1311 0.1311 0.1311
    E_dem_T         (T) float64 44.33 46.08 43.76 41.85 ... 47.83 45.88 43.15
    E_PV_profile_T  (T) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0

Spot market prices

Draf provides day ahead spot market prices for several European countries and years.

In [81]:
sc = cs.scens.REF
sc.plot.fig_size = (12,1)

sc.prep.add_c_GRID_RTP_T()
sc.plot.heatmap(ent_name="c_GRID_RTP_T")

Carbon emission factors

Draf provides dynamic carbon emission factors for several European countries and years.

In [82]:
sc.prep.add_ce_GRID_T(name="ce_GRID_avg_T", method="average")
sc.plot.heatmap(ent_name="ce_GRID_avg_T")
In [83]:
sc.prep.add_ce_GRID_T(name="ce_GRID_mar_T", method="marginal")
sc.plot.heatmap(ent_name="ce_GRID_mar_T")

Timeseries Preparation

Draf provides some useful tools for demand estimation. These are especially useful when only aggregated values are availible.

First, we prepare an electricity demand from a industrial standard load profile "G1" which stands for Business on weekdays 08:00 - 18:00 and an given annual energy demand of 5 GWh/a.

In [84]:
sc = draf.CaseStudy(year=2017).add_REF_scen()
sc.prep.add_E_dem_T(profile="G1", annual_energy=5e6, holidays_province="BY")
sc.plot.fig_size = (12,1)
sc.plot.heatmap(ent_name="E_dem_T")
In [85]:
sc.params.E_dem_T.sum()
Out[85]:
5000000.0

Now let's create an heat demand timeseries from the annual energy, the target_temperatur, the heating threshold and the location where the ambient temperature is taken.

In [86]:
sc.prep.add_H_dem_T(annual_energy=5e6, target_temp=20.0, threshold_temp=10.0, location='Rheinstetten')
sc.plot.heatmap(ent_name="H_dem_T")

This is the ambient temperature that was used as basis:

In [87]:
sc.plot.heatmap(timeseries=draf.prep.io.get_amb_temp(year=cs.year, freq=cs.freq, location="Rheinstetten"))

Model templates

Draf comes with some out-of-the-box models for different relevant aggregates in the industrial environment that can easily be parameterized. One of the models is "DER_HUT" - Distribted Energy Ressources(DER) and Heat upgrading Technologies (HUT). Here is a schematic:

drawing

By the way:

The PV_BES from the quickstart showcase: drawing
is a submodel of the DER_HUT: drawing

Access to Draf-objects

In the following, access and preview of draf-objects (CaseStudy, Scenario, etc.) is demonstrated.

Case Study

In [88]:
cs
Out[88]:
<CaseStudy object>
• name: ShowCase
• doc: No doc available.
• freq: 60min
• country: DE
• is_dry_run: False
• scens: [...]
• plot: <draf.plotting.cs_plotting.CsPlotter object at 0x0000026543D2A308>
• dims: <Dimensions object> (empty)
• params: <Params object> (empty)
• obj_vars: ['C_', 'CE_']
• year: 2017
• dtindex: [...]
• dtindex_custom: [...]
• steps_per_day: 24
• scen_vars: [('c_GRID_T', 't', ['c_GRID_RTP_T', 'c_GRID_TOU_T']), ('E_BES_CAPx_', 'b', [1000]), ('alpha_', 'a', array([0.        , 0.33333333, 0.66666667, 1.        ]))]
• scen_df: [...]
• dt_info:
  ⤷ t1 = 0     (Sunday, 2017-01-01 00:00:00),
  ⤷ t2 = 8759  (Sunday, 2017-12-31 23:00:00)
  ⤷ Length = 8760

Scenarios

In [89]:
cs.scens
Out[89]:
<Scenarios object>
   name         doc
  ⤷ REF        | no BES
  ⤷ sc1        | c_GRID_T=c_GRID_RTP_T; E_BES_CAPx_=1000; alpha_=0.0
  ⤷ sc2        | c_GRID_T=c_GRID_RTP_T; E_BES_CAPx_=1000; alpha_=0.3333333333333333
  ⤷ sc3        | c_GRID_T=c_GRID_RTP_T; E_BES_CAPx_=1000; alpha_=0.6666666666666666
  ⤷ sc4        | c_GRID_T=c_GRID_RTP_T; E_BES_CAPx_=1000; alpha_=1.0
  ⤷ sc5        | c_GRID_T=c_GRID_TOU_T; E_BES_CAPx_=1000; alpha_=0.0
  ⤷ sc6        | c_GRID_T=c_GRID_TOU_T; E_BES_CAPx_=1000; alpha_=0.3333333333333333
  ⤷ sc7        | c_GRID_T=c_GRID_TOU_T; E_BES_CAPx_=1000; alpha_=0.6666666666666666
  ⤷ sc8        | c_GRID_T=c_GRID_TOU_T; E_BES_CAPx_=1000; alpha_=1.0

Scenario

In [90]:
cs.scens.REF
Out[90]:
<Scenario object>
• id: REF
• name: REF
• doc: no BES
• is_dry_run: False
• dims: [...]
• params: [...]
• plot: <draf.plotting.scen_plotting.ScenPlotter object at 0x0000026543E0E4C8>
• prep: <draf.prep.params_prepping.Prepper object at 0x0000026543E0EF08>
• vars: [...]
• dtindex: [...]
• dtindex_custom: [...]
• res: [...]

Params

In [91]:
cs.scens.REF.params
Out[91]:
<Params object>
   name                 dims       unit doc
  ⤷ alpha_                   |          |pareto weighting factor
  ⤷ n_C_                     |          |normalization factor
  ⤷ n_CE_                    |          |normalization factor
  ⤷ ce_GRID_T               T|gCO2eq/kWh_el|Average carbon emission factors for 2017, 60min, DE. Source:entsoe
  ⤷ c_GRID_peak_             |   €/kW_el|peak price
  ⤷ c_GRID_RTP_T            T|  €/kWh_el|Day-ahead-market-prices 2017, 60min, DE
  ⤷ c_GRID_TOU_T            T|  €/kWh_el|Time-Of-Use-tariff with the prices 0.029€ and 0.044€
  ⤷ c_GRID_T                T|  €/kWh_el|chosen electricity tariff
  ⤷ c_GRID_addon_T          T|  €/kWh_el|add-on electricity price component
  ⤷ E_dem_T                 T|    kWh_el|electricity demand from standard load profile G3
  ⤷ P_PV_CAPx_               |   kW_peak|existing capacity PV
  ⤷ E_PV_profile_T          T|kW_el/kW_peak|produced PV-power for 1 kW_peak
  ⤷ E_BES_CAPx_              |     kW_el|existing capacity BES
  ⤷ eta_BES_time_            |          |storing efficiency
  ⤷ eta_BES_in_              |          |loading efficiency
  ⤷ k_BES_in_per_capa_       |          |ratio of charging power / capacity
  ⤷ k_BES_out_per_capa_      |          |ratio of discharging power / capacity (aka C rate)
  ⤷ timelog_params_          |   seconds|time for building the params
  ⤷ timelog_model_           |   seconds|time for building the model
  ⤷ mipGap_                  |         %|Gap to relaxed solution
  ⤷ timelog_solve_           |   seconds|time for solving the model
  ⤷ ce_GRID_avg_T           T|gCO2eq/kWh_el|Average carbon emission factors for 2017, 60min, DE. Source:entsoe
  ⤷ ce_GRID_mar_T           T|gCO2eq/kWh_el|Marginal carbon emission factors for 2017, 60min, DE. Source:entsoe

choose one of them, e.g. P_PV_CAPx_:

In [92]:
cs.scens.REF.params.P_PV_CAPx_
Out[92]:
100

Results

In [93]:
cs.scens.REF.res
Out[93]:
<Results object>
   name                 dims       unit doc
  ⤷ C_                       |       €/a|total costs
  ⤷ C_inv_                   |         €|investment costs
  ⤷ C_op_                    |       €/a|operating costs
  ⤷ CE_                      |  gCO2eq/a|total emissions
  ⤷ C_GRID_peak_             |       €/a|costs for peak price
  ⤷ E_GRID_buy_T            T|    kWh_el|bought el. from the grid
  ⤷ E_GRID_sell_T           T|    kWh_el|sold el. to the grid
  ⤷ P_GRID_peak_             |     kW_el|peak electricity
  ⤷ C_GRID_buy_              |       €/a|cost for bought electricity
  ⤷ C_GRID_sell_             |       €/a|earnings for bought electricity
  ⤷ E_PV_T                  T|    kWh_el|produced electricity
  ⤷ E_PV_OC_T               T|    kWh_el|own consumption
  ⤷ E_PV_FI_T               T|    kWh_el|feed-in
  ⤷ E_BES_T                 T|    kWh_el|electricity stored
  ⤷ E_BES_in_T              T|    kWh_el|electricity charged
  ⤷ E_BES_out_T             T|    kWh_el|electricity uncharged

choose one of them, e.g. C_:

In [94]:
cs.scens.REF.res.C_
Out[94]:
71995.86036638569