Stratified thermal storage¶
This module was developed to implement a simplified model of a large-scale sensible heat storage with ideal stratification for energy system optimization with oemof.solph.
A simplified 2-zone-model of a stratified thermal energy storage.
- We assume a cylindrical storage of (inner) diameter d and height h, with two temperature regions that are perfectly separated.
- The temperatures are assumed to be constant and correspond to the feed-in/return temperature of the heating system.
- Heat conductivity of the storage has to be passed as well as a timeseries of outside temperatures for the calculation of heat losses.
- There is no distinction between outside temperature and ground temperature.
- A single value for the thermal transmittance is assumed, neglecting the fact that the storage’s lateral surface is bent and thus has a higher thermal transmittance than a flat surface. The relative error introduced here gets smaller with larger storage diameters.
- Material properties are constant.
The equation describing the storage content at timestep t is the following:
which is of the form
The three terms represent:
- , constant heat losses through the top and bottom surfaces,
- , losses through the total lateral surface assuming the storage to be empty (storage is at , and is the driving temperature difference), depending on the height of the storage,
- , additional losses through lateral surface that belong to the hot part of the water body, depending on the state of charge.
In the case of investment, the diameter is given and the height can be adapted to adapt the nominal capacity of the storage. With this assumption, all relations stay linear.
Because of the space that diffuser plates for charging/discharging take up, it is assumed that the storage can neither be fully charged nor discharged, which is parametrised as a minimal/maximal storage level (indicated by the dotted lines in Fig. 1).
These parameters are part of the stratified thermal storage module:
symbol attribute type explanation
Height [m] (if not investment)
Storage surface [m2]
Storage volume [m3]
Density of storage medium [kg/m3]
Heat capacity of storage medium [J/(kg*K)]
Hot temperature level [deg C]
Cold temperature level [deg C]
Environment temperature timeseries [deg C] attribute of oemof-solph component Stored thermal energy at time t [MWh] attribute of oemof-solph component Energy flowing in at time t
Maximum amount of stored thermal energy [MWh]
Thermal transmittance [W/(m2*K)]
Thickness of isolation layer [mm]
Heat conductivity of isolation material [W/(m*K)]
Heat transfer coefficient inside [W/(m2*K)]
Heat transfer coefficient outside [W/(m2*K)]
Relative loss of storage content within one timestep [-]
Fixed losses as share of nominal storage capacity [-]
Fixed absolute losses independent of storage content or nominal storage capacity [MWh]
Charging efficiency [-]
Discharging efficiency [-]
Using the StratifiedThermalStorage facade, you can instantiate a storage like this:
from oemof.solph import Bus from oemof.thermal.facades import StratifiedThermalStorage bus_heat = Bus('heat') thermal_storage = StratifiedThermalStorage( label='thermal_storage', bus=bus_heat, diameter=2, height=5, temp_h=95, temp_c=60, temp_env=10, u_value=u_value, min_storage_level=0.05, max_storage_level=0.95, capacity=1, efficiency=0.9, marginal_cost=0.0001 )
The non-usable storage volume is represented by the parameters
To learn about all parameters that can be passed to the facades, have a look at the API documentation of the
StratifiedThermalStorage class of the facade module.
For the storage investment mode, you still need to provide
capacity open and set
There are two options to choose from:
- Invest into
capacity(charging/discharging power) with a fixed ratio. Pass
- Invest into
capacityindependently with no fixed ratio. Pass
In many practical cases, thermal storages are dimensioned using a rule of thumb: The storage should be able to provide its peak thermal power for 6-7 hours. To apply this in a model, use option 1.
thermal_storage = StratifiedThermalStorage( label='thermal_storage', bus=bus_heat, diameter=2, temp_h=95, temp_c=60, temp_env=10, u_value=u_value, expandable=True, capacity_cost=0, storage_capacity_cost=400, minimum_storage_capacity=1, invest_relation_input_capacity=1 / 6, min_storage_level=0.05, max_storage_level=0.95, efficiency=0.9, marginal_cost=0.0001 )
If you do not want to use a rule of thumb and rather let the model decide, go with option 2. Do so
by leaving out
invest_relation_input_capacity and setting
a finite value. Also have a look at the examples, where both options are shown.
A 3rd and 4th option, investing into
nominal_storage_capacity but leaving
capacity fixed or vice versa, can not be modelled with this facade (at the moment).
It seems to be a case that is not as relevant for thermal storages as the others. If you want to
model it, you can do so by performing the necessary pre-calculations and using oemof.solph’s
For this example to work as intended, please use oemof-solph v0.4.0 or higher
to ensure that the GenericStorage has the attributes
The following figure shows a comparison of results of a common storage implementation using only a loss rate vs. the stratified thermal storage implementation (source code).
In the background, the StratifiedThermalStorage class uses the following functions. They can be used independent of the facade class as well.
The thermal transmittance is pre-calculated using calculate_u_value.
The dimensions of the storage are calculated with calculate_storage_dimensions
volume, surface = calculate_storage_dimensions(height, diameter)
The nominal storage capacity is pre-calculated using calculate_capacities.
nominal_storage_capacity = calculate_capacities( volume, temp_h, temp_c, heat_capacity, density )
Loss terms are precalculated by the following function.
loss_rate, fixed_losses_relative, fixed_losses_absolute = calculate_losses( u_value, diameter, temp_h, temp_c, temp_env, time_increment, heat_capacity, density)
To calculate the thermal transmittance of the storage hull from material properties, you can use the following function.
u_value = calculate_storage_u_value(s_iso, lamb_iso, alpha_inside, alpha_outside)