Sets¶
Since urbs is a linear optimization model with many objects (e.g. variables, parameters), it is reasonable to use sets to define the groups of objects. With the usage of sets, many facilities are provided, such as understanding the main concepts of the model. Many objects are represented by various sets, therefore sets can be easily used to check whether some object has a specific characteristic or not. Additionally sets are useful to define a hierarchy of objects. Mathematical notation of sets are expressed with uppercase letters, and their members are usually expressed with the same lowercase letters. Main sets, tuple sets and subsets will be introduced in this respective order.
Elementary Sets¶
Set | Description |
---|---|
\(t \in T\) | Timesteps |
\(t \in T_\text{m}\) | Modelled Timesteps |
\(y \in Y\) | Support Timeframes |
\(v \in V\) | Sites |
\(c \in C\) | Commodities |
\(q \in Q\) | Commodity Types |
\(p \in P\) | Processes |
\(s \in S\) | Storages |
\(f \in F\) | Transmissions |
\(r \in R\) | Cost Types |
Timesteps¶
The model urbs is considered to observe a energy system model and calculate the
optimal solution within a limited span of time. This limited span of time is
viewed as a discrete variable, which means values of variables are viewed as
occurring only at distinct timesteps. The set of timesteps
\(T = \{t_0,\dots,t_N\}\) for \(N\) in \(\mathbb{N}\) represents
time. This set contains \(N+1\) sequential time steps with equal spaces.
Each time step represents another point in time. At the initialization of the
model this set is fixed by the user by setting the variable timesteps
in
script runme.py
. Duration of space between timesteps
\(\Delta t = t_{x+1} - t_x\), length of simulation \(\Delta t \cdot N\)
and time interval \([t_0,t_N]\) can be fixed to satisfy the needs of the
user. In code this set is defined by the set t
and initialized by the
section:
m.t = pyomo.Set(
initialize=m.timesteps,
ordered=True,
doc='Set of timesteps')
Where:
- Initialize: A function that receives the set indices and model to return the value of that set element, initializes the set with data.
- Ordered: A boolean value that indicates whether the set is ordered.
- Doc: A string describing the set.
Modelled Timesteps¶
The set, modelled timesteps, is a subset of the timesteps set. The only
difference between modelled timesteps set and the timesteps set is that the
initial timestep \(t_0\) is not included. All other features of the set
time steps also apply to the set of modelled timesteps. This set is the main
time set used in the model. The distinction with the set timesteps is only
required to facilitate the definition of the storage state equation. In script
model.py
this set is defined by the set tm
and initialized by the code
fragment:
m.tm = pyomo.Set(
within=m.t,
initialize=m.timesteps[1:],
ordered=True,
doc='Set of modelled timesteps')
Where:
- Within: The option that supports the validation of a set array.
m.timesteps[1:]
represents the timesteps set starting from the second element, excluding the first timestep \(t_0\)
Support Timeframes¶
Support timeframes are represented by the set \(Y\). They represent the
explicitly modeled support timeframes, e.g., years, for intertemporal models.
In script model.py
the set is defined as:
# support timeframes (e.g. 2020, 2030...)
indexlist = set()
for key in m.commodity_dict["price"]:
indexlist.add(tuple(key)[0])
m.stf = pyomo.Set(
initialize=indexlist,
doc='Set of modeled support timeframes (e.g. years)')
where:
- The
commodity_dict["price"]
is a dictionary in which prices of commodities in the sites are noted for each support timeframe (i.e. year). The dictionary’s keys have the elements: (Year, Site, Commodity Name, Commodity Type).
Sites¶
Sites are represented by the set \(V\). A site \(v\) can be any
distinct location, a place of settlement or activity (e.g. process,
transmission, storage). A site is for example an individual building,
region, country or even continent. Sites can be imagined as nodes (vertices) on
a graph of locations, connected by edges. Index of this set are the
descriptions of the sites (e.g. north, middle, south). In script model.py
this set is defined by sit
and initialized by the code fragment:
# site (e.g. north, middle, south...)
indexlist = set()
for key in m.commodity_dict["price"]:
indexlist.add(tuple(key)[1])
m.sit = pyomo.Set(
initialize=indexlist,
doc='Set of sites')
Commodities¶
As explained in the overview section, commodities are goods that can be
generated, stored, transmitted or consumed. The set of commodities represents
all goods that are relevant to the modelled energy system, such as all energy
carriers, inputs, outputs, intermediate substances. (e.g. Coal, CO2, Electric,
Wind) By default, commodities are given by their energy content (MWh). Usage of
some commodities are limited by a maximum value or maximum value per timestep
due to their availability or restrictions, also some commodities have a price
that needs to be compensated..(e.g. coal, wind, solar). In script model.py
this set is defined by com
and initialized by the code fragment:
# commodity (e.g. solar, wind, coal...)
indexlist = set()
for key in m.commodity_dict["price"]:
indexlist.add(tuple(key)[2])
m.com = pyomo.Set(
initialize=indexlist,
doc='Set of commodities')
Commodity Types¶
Commodities differ in their usage purposes, consequently commodity types
are introduced to subdivide commodities by their features. These types are hard
coded as SupIm
, Stock
, Demand
, Env
, Buy
, Sell
. In
script model.py
this set is defined as com_type
and initialized by the
code fragment:
# commodity type (i.e. SupIm, Demand, Stock, Env)
indexlist = set()
for key in m.commodity_dict["price"]:
indexlist.add(tuple(key)[3])
m.com_type = pyomo.Set(
initialize=indexlist,
doc='Set of commodity types')
Processes¶
One of the most important elements of an energy system is the process. A
process \(p\) can be defined by the action of changing one or more forms of
energy, i.e. commodities, to others. In our modelled energy system, processes
convert input commodities into output commodities. Process technologies are
represented by the set processes \(P\). Different processes technologies
have fixed input and output commodities. These input and output commodities can
be either single or multiple regardless of each other. Some example members of
this set can be: Wind Turbine, Gas Plant, Photovoltaics. In script
model.py
this set is defined as pro
and initialized by the code
fragment:
# process (e.g. Wind turbine, Gas plant, Photovoltaics...)
indexlist = set()
for key in m.process_dict["inv-cost"]:
indexlist.add(tuple(key)[2])
m.pro = pyomo.Set(
initialize=indexlist,
doc='Set of conversion processes')
where:
- The
m.process_dict["inv-cost"]
is again a dictionary whose key has the elements: (Year, Site, Process). An example key would look like as follows: (2020, ‘Mid’, ‘Biomass plant’).
Storages¶
Energy storage is provided by technical facilities that store energy to
generate a commodity at a later time for the purpose of meeting the demand.
Occasionally, on-hand commodities may not be able to satisfy the required
amount of energy to meet the demand, or the available amount of energy may be
much more than required. Storage technologies play a major role in such
circumstances. The Set \(S\) represents all storage technologies (e.g.
Pump storage). In script features\storage.py
this set is defined as sto
and
initialized by the code fragment:
# storage (e.g. hydrogen, pump storage)
indexlist = set()
for key in m.storage_dict["eff-in"]:
indexlist.add(tuple(key)[2])
m.sto = pyomo.Set(
initialize=indexlist,
doc='Set of storage technologies')
where:
- The
m.storage_dict["eff-in"]
is a dictionary whose key has the elements: (Year, Site, Storage, Commodity). An example key would look like as follows: (2020, ‘Mid’, ‘Hydrogen’, ‘Elec’).
Transmissions¶
Transmissions \(f \in F\) represent possible conveyances of commodities
between sites. Transmission process technologies can vary between different
commodities, due to distinct physical attributes and forms of commodities. Some
examples for transmission technologies are: HVAC (High Voltage AC), HVDC, pipeline. In
script features\transmission.py
this set is defined as tra
and initialized by the code
fragment:
# tranmission (e.g. hvac, hvdc, pipeline...)
indexlist = set()
for key in m.transmission_dict["eff"]:
indexlist.add(tuple(key)[3])
m.tra = pyomo.Set(
initialize=indexlist,
doc='Set of transmission technologies')
where:
- The
m.transmission_dict["eff"]
is a dictionary whose key has the elements: Year, Site In, Site Out, Transmission, Commodity.
Cost Types¶
One of the major goals of the model is to calculate the costs of a simulated
energy system. There are 7 different types of costs. Each one has different
features and are defined for different instances. Set of cost types is
hardcoded, which means they are not considered to be fixed or changed by the
user. The set \(R\) defines the cost types, each member \(r\) of this
set \(R\) represents a unique cost type name. In script model.py
this
set is defined as cost_type
and initialized by the code fragment:
m.cost_type = pyomo.Set(
initialize=m.cost_type_list,
doc='Set of cost types (hard-coded)')
The cost types are hard coded and taken from a list with following structure:
[Invest
, Fixed
, Variable
, Fuel
, Environmental
, Revenue
, Purchase
].
Tuple Sets¶
A tuple is finite, ordered collection of elements. For example, the tuple
(hat,red,large)
consists of 3 ordered elements and defines another element
itself. Tuples are needed in this model to define the combinations of elements
from different sets. Defining a tuple lets us assemble related elements and use
them as a single element. These tuples are then collected into tuple sets.
These tuple sets are then immensely useful for efficient indexing of model
variables and parameters and for defining the constraint rules.
Commodity Tuples¶
Commodity tuples represent combinations of defined commodities.
These are represented by the set \(C_{yvq}\). A member \(c_{yvq}\) in
set \(C_{yvq}\) is a commodity \(c\) of commodity type \(q\) in
support timeframe \(y\) and site \(v\). This set is defined as
com_tuples
and given by the code fragment under model.py
:
m.com_tuples = pyomo.Set(
within=m.stf * m.sit * m.com * m.com_type,
initialize=tuple(m.commodity_dict["price"].keys()),
doc='Combinations of defined commodities, e.g. (2018,Mid,Elec,Demand)')
where:
- The keys of
commodity_dict["price"]
has the following elements: (Year, Site, Commodity, Commodity Type). For example, (2020, Mid, Elec, Demand) and it is interpreted as commodity Elec of commodity type Demand in the year 2020 in site Mid.
Process Tuples¶
Process tuples represent possible placements of processes within the model.
These are represented by the set \(P_{yv}\). A member \(p_{yv}\) in set
\(P_{yv}\) is a process \(p\) in support timeframe \(y\) and site
\(v\). This set is defined as pro_tuples
and given by the code fragment:
m.pro_tuples = pyomo.Set(
within=m.stf * m.sit * m.pro,
initialize=tuple(m.process_dict["inv-cost"].keys()),
doc='Combinations of possible processes, e.g. (2018,North,Coal plant)')
where:
- The key of
process_dict["inv-cost"]
has the following elements: (Year, Site, Process). For example, (2020, ‘North’, ‘Coal Plant’) and it is interpreted as process Coal Plant in site North in the year 2020.
There are three subsets defined for process tuples, which each activate a different set of modeling constraints.
The first subset of the process tuples pro_partial_tuples
\(P_{yv}^\text{partial}\) is formed in order to identify processes that
have partial operation properties. Programmatically, they are identified by
those processes, which have the parameter ratio-min
set for one of their
input commodities in table Process-Commodity. The tuple set is defined as:
m.pro_partial_tuples = pyomo.Set(
within=m.stf * m.sit * m.pro,
initialize=[(stf, site, process)
for (stf, site, process) in m.pro_tuples
for (s, pro, _) in tuple(m.r_in_min_fraction_dict.keys())
if process == pro and s == stf],
doc='Processes with partial input')
where:
- The keys of dictionary
r_in_min_fraction_dict
contain the data: Year, Process, Commodity. For example (2020, ‘Coal Plant’, ‘Coal’).
The second subset is formed in order to capture all processes that take up a
certain area and are thus subject to the area constraint at the given site.
These processes are identified by the parameter area-per-cap
set in table
Process, if at the same time a value for area
is set in table Site. The
tuple set is defined as:
# process tuples for area rule
m.pro_area_tuples = pyomo.Set(
within=m.stf * m.sit * m.pro,
initialize=tuple(m.proc_area_dict.keys()),
doc='Processes and Sites with area Restriction')
where:
- The key of dictionary
proc_area_dict
has the form: Year, Site, Process. For example (2020, ‘Mid’, ‘Photovoltaics’).
Finally, processes that are subject to restrictions in the change of
operational state are captured with the pro_maxgrad_tuples
. This subset is
defined as:
# process tuples for maximum gradient feature
m.pro_maxgrad_tuples = pyomo.Set(
within=m.stf * m.sit * m.pro,
initialize=[(stf, sit, pro)
for (stf, sit, pro) in m.pro_tuples
if m.process_dict['max-grad'][stf, sit, pro] < 1.0 / dt],
doc='Processes with maximum gradient smaller than timestep length')
where:
- The
process_dict['max-grad'][stf, sit, pro]
returns the values from max-grad column in the process sheet of input excel files. In the dictionary, the keys that correspond to the values are tuples in form Stf, sit, pro and they are to interpreted as year, site, process.
Transmission Tuples¶
Transmission tuples represent possible transmissions. These are represented by
the set \(F_{yc{v_\text{out}}{v_\text{in}}}\). A member
\(f_{yc{v_\text{out}}{v_\text{in}}}\) in set
\(F_{yc{v_\text{out}}{v_\text{in}}}\) is a transmission \(f\), that is
directed from an origin site \(v_\text{out}\) to a destination site
\(v_{in}\) and carrying the commodity \(c\) in support timeframe
\(y\). The term “directed from an origin site \(v_\text{out}\)
to a destination site \(v_\text{in}\)” can also be defined as an arc
\(a\) . For example, (2020, South, Mid, hvac, Elec) is interpreted as
transmission hvac that is directed from origin site South to destination
site Mid carrying commodity Elec in year 2020. This set is defined as
tra_tuples
and given by the code fragment:
m.tra_tuples = pyomo.Set(
within=m.stf * m.sit * m.sit * m.tra * m.com,
initialize=tuple(m.transmission_dict["eff"].keys()),
doc='Combinations of possible transmissions, e.g. '
'(2020,South,Mid,hvac,Elec)')
DCPF Transmission Tuples¶
If the DC Power Flow Model feature is activated in the model, three different transmission tuple sets are defined in the model.
The set \(F_{yc{v_\text{out}}{v_\text{in}}^{TP}}\) includes every transport model transmission lines and
is defined as tra_tuples_tp
and given by the code fragment:
m.tra_tuples_tp = pyomo.Set(
within=m.stf * m.sit * m.sit * m.tra * m.com,
initialize=tuple(tra_tuples_tp),
doc='Combinations of possible transport transmissions,'
'e.g. (2020,South,Mid,hvac,Elec)')
The set \(F_{yc{v_\text{out}}{v_\text{in}}^{DCPF}}\) includes every transmission
line, which should be modelled with DCPF. If the complementary arcs are included in
the input for DCPF transmission lines, these will be excluded from this set with
remove_duplicate_transmission()
. This set is defined as tra_tuples_dc
and given by the code fragment:
m.tra_tuples_dc = pyomo.Set(
within=m.stf * m.sit * m.sit * m.tra * m.com,
initialize=tuple(tra_tuples_dc),
doc='Combinations of possible bidirectional dc'
'transmissions, e.g. (2020,South,Mid,hvac,Elec)')
If the DCPF is activated, the set \(F_{yc{v_\text{out}}{v_\text{in}}}\) is defined by the unification of the sets
\(F_{yc{v_\text{out}}{v_\text{in}}^{DCPF}}\) and \(F_{yc{v_\text{out}}{v_\text{in}}^{TP}}\). This set is defined
as tra_tuples
in the same fashion as the default transmission model.
Storage Tuples¶
Storage tuples label storages. They are represented by the set \(S_{yvc}\).
A member \(s_{yvc}\) in set \(S_{yvc}\) is a storage \(s\) of
commodity \(c\) in site \(v\) and support timeframe \(y\). For
example, (2020, Mid, Bat, Elec) is interpreted as storage Bat for commodity
Elec in site Mid in the year 2020. This set is defined as sto_tuples
and given by the code fragment:
m.sto_tuples = pyomo.Set(
within=m.stf * m.sit * m.sto * m.com,
initialize=tuple(m.storage_dict["eff-in"].keys()),
doc='Combinations of possible storage by site,'
'e.g. (2020,Mid,Bat,Elec)')
There are two subsets of storage tuples.
In a first subset of the storage tuples are all storages that have a user defined fixed value for the initial state are collected.
m.sto_init_bound_tuples = pyomo.Set(
within=m.stf * m.sit * m.sto * m.com,
initialize=tuple(m.stor_init_bound_dict.keys()),
doc='storages with fixed initial state')
A second subset is defined for all storages that have a fixed ratio between charging/discharging power and storage content.
m.sto_ep_ratio_tuples = pyomo.Set(
within=m.stf*m.sit*m.sto*m.com,
initialize=tuple(m.sto_ep_ratio_dict.keys()),
doc='storages with given energy to power ratio')
Process Input Tuples¶
Process input tuples represent commodities consumed by processes. These are
represented by the set \(C_{yvp}^\text{in}\). A member
\(c_{yvp}^\text{in}\) in set \(C_{yvp}^\text{in}\) is a commodity
\(c\) consumed by the process \(p\) in site \(v\) in support
timeframe \(y\). For example, (2020, Mid, PV, Solar) is interpreted as
commodity Solar consumed by the process PV in the site Mid in the year
2020. This set is defined as pro_input_tuples
and given by the code
fragment:
m.pro_input_tuples = pyomo.Set(
within=m.stf * m.sit * m.pro * m.com,
initialize=[(stf, site, process, commodity)
for (stf, site, process) in m.pro_tuples
for (s, pro, commodity) in tuple(m.r_in_dict.keys())
if process == pro and s == stf],
doc='Commodities consumed by process by site,'
'e.g. (2020,Mid,PV,Solar)')
Where: r_in_dict
represents the process input ratio as set in the input.
For processes in the tuple set pro_partial_tuples
, the following tuple set
pro_partial_input_tuples
enumerates their input commodities. It is used to
index the constraints that modifies a process’ input commodity flow with
respect to the standard case without partial operation. It is defined by the
following code fragment:
m.pro_partial_input_tuples = pyomo.Set(
within=m.stf * m.sit * m.pro * m.com,
initialize=[(stf, site, process, commodity)
for (stf, site, process) in m.pro_partial_tuples
for (s, pro, commodity) in tuple(m.r_in_min_fraction_dict
.keys())
if process == pro and s == stf],
doc='Commodities with partial input ratio,'
'e.g. (2020,Mid,Coal PP,Coal)')
Process Output Tuples¶
Process output tuples represent commodities generated by processes. These are
represented by the set \(C_{yvp}^\text{out}\). A member
\(c_{yvp}^\text{out}\) in set \(C_{yvp}^\text{out}\) is a commodity
\(c\) generated by the process \(p\) in site \(v\) and support
timeframe \(y\). For example, (2020, Mid,PV,Elec) is interpreted as the
commodity Elec is generated by the process PV in the site Mid in the year
2020. This set is defined as pro_output_tuples
and given by the code
fragment:
m.pro_output_tuples = pyomo.Set(
within=m.stf * m.sit * m.pro * m.com,
initialize=[(stf, site, process, commodity)
for (stf, site, process) in m.pro_tuples
for (s, pro, commodity) in tuple(m.r_out_dict.keys())
if process == pro and s == stf],
doc='Commodities produced by process by site, e.g. (2020,Mid,PV,Elec)')
Where: r_out_dict
represents the process output ratio as set in the input.
There are two alternative tuple sets that are active whenever their respective features are set in the input.
First, for processes in the tuple set pro_partial_tuples
, the tuple set
pro_partial_output_tuples
enumerates their output commodities. It is used
to index the constraints that modifies a process’ output commodity flow with
respect to the standard case without partial operation. It is defined by the
following code fragment:
m.pro_partial_output_tuples = pyomo.Set(
within=m.stf * m.sit * m.pro * m.com,
initialize=[(stf, site, process, commodity)
for (stf, site, process) in m.pro_partial_tuples
for (s, pro, commodity) in tuple(m.r_out_min_fraction_dict
.keys())
if process == pro and s == stf],
doc='Commodities with partial input ratio, e.g. (Mid,Coal PP,CO2)')
Second, the output of all processes that have a time dependent efficiency are
collected in an additional tuple set. The set contains all outputs
corresponding to processes that are specified as column indices in the input
file worksheet TimeVarEff
. The code is implemented in features\TimeVarEff.py
as:
m.pro_timevar_output_tuples = pyomo.Set(
within=m.stf * m.sit * m.pro * m.com,
initialize=[(stf, site, process, commodity)
for stf in tve_stflist
for (site, process) in tuple(m.eff_factor_dict.keys())
for (st, pro, commodity) in tuple(m.r_out_dict.keys())
if process == pro and st == stf and commodity not in
m.com_env],
doc='Outputs of processes with time dependent efficiency')
Demand Side Management Tuples¶
There are two kinds of demand side management (DSM) tuples in the model: DSM site tuples \(D_{yvc}\) and DSM down tuples \(D_{yvct,tt}^\text{down}\). The first kind \(D_{yvc}\) represents all possible combinations of support timeframe \(y\), site \(v\) and commodity \(c\) of the DSM sheet. It is given by the code fragment:
m.dsm_site_tuples = pyomo.Set(
within=m.stf*m.sit*m.com,
initialize=tuple(m.dsm_dict["delay"].keys()),
doc='Combinations of possible dsm by site, e.g. '
'(2020, Mid, Elec)')
The second kind \(D_{t,tt,yvc}^\text{down}\) refers to all possible DSM downshift possibilities. It is defined to overcome the difficulty caused by the two time indices of the DSM downshift variable. Dependend on support timeframe \(y\), site \(v\) and commodity \(c\) the tuples contain two time indices. For example, (5001, 5003, 2020, Mid, Elec) is intepreted as the downshift in timestep 5003, which was caused by the upshift of timestep 5001 in year 2020 at site Mid for commodity Elec. The tuples are given by the following code fragment:
m.dsm_down_tuples = pyomo.Set(
within=m.tm*m.tm*m.stf*m.sit*m.com,
initialize=[(t, tt, stf, site, commodity)
for (t, tt, stf, site, commodity)
in dsm_down_time_tuples(m.timesteps[1:],
m.dsm_site_tuples,
m)],
doc='Combinations of possible dsm_down combinations, e.g. '
'(5001,5003,2020,Mid,Elec)')
where the following function is utilized:
def dsm_down_time_tuples(time, sit_com_tuple, m):
""" Dictionary for the two time instances of DSM_down
Args:
time: list with time indices
sit_com_tuple: a list of (site, commodity) tuples
m: model instance
Returns:
A list of possible time tuples depending on site and commodity
"""
delay = m.dsm_dict['delay']
ub = max(time)
lb = min(time)
time_list = []
for (stf, site, commodity) in sit_com_tuple:
for step1 in time:
for step2 in range(step1 -
max(int(delay[stf, site, commodity] /
m.dt.value), 1),
step1 +
max(int(delay[stf, site, commodity] /
m.dt.value), 1) + 1):
if lb <= step2 <= ub:
time_list.append((step1, step2, stf, site, commodity))
return time_list
Commodity Type Subsets¶
Commodity type subsets represent the commodity tuples only from a given commodity type. Commodity type subsets are subsets of the sets commodity tuples. These subsets can be obtained by fixing the commodity type \(q\) to a desired commodity type (e.g. SupIm, Stock) in the set commodity tuples \(C_{vq}\). Since there are 6 types of commodity types, there are also 6 commodity type subsets. Commodity type subsets are:
Supply Intermittent Commodities (SupIm
): The set \(C_\text{sup}\)
represents all commodities \(c\) of commodity type SupIm
. Commodities
of this type have intermittent timeseries, in other words, availability of
these commodities are not constant. These commodities might have various energy
content for every timestep \(t\). For example, solar radiation is contingent
on many factors such as sun position, weather and varies permanently.
Stock Commodities (Stock
): The set \(C_\text{st}\) represents all
commodities \(c\) of commodity type Stock
. Commodities of this type can
be purchased at any time for a given price (\(k_{vc}^\text{fuel}\)).
Sell Commodities (Sell
): The set \(C_\text{sell}\) represents all
commodities \(c\) of commodity type Sell
. Commodities that can be sold.
These commodities have a sell price ( \(k_{vct}^\text{s}\) ) that may vary
with the given timestep \(t\).
Buy Commodities (Buy
): The set \(C_\text{buy}\) represents all
commodities \(c\) of commodity type Buy
. Commodities that can be
purchased. These commodities have a buy price ( \(k_{vc}^\text{b}\) ) that
may vary with the given timestep \(t\).
Demand Commodities (Demand
): The set \(C_\text{dem}\) represents
all commodities \(c\) of commodity type Demand
. Commodities of this
type are the requested commodities of the energy system. They are usually the
end product of the model (e.g. Electricity:Elec).
Environmental Commodities (Env
): The set \(C_\text{env}\)
represents all commodities \(c\) of commodity type Env
. Commodities of
this type are usually the undesired byproducts of processes that might be
harmful for environment, optional maximum creation limits can be set to control
the generation of these commodities
(e.g. Greenhouse Gas Emissions: \(\text{CO}_2\)).
Commodity type subsets are given by the code fragment:
m.com_supim = pyomo.Set(
within=m.com,
initialize=commodity_subset(m.com_tuples, 'SupIm'),
doc='Commodities that have intermittent (timeseries) input')
m.com_stock = pyomo.Set(
within=m.com,
initialize=commodity_subset(m.com_tuples, 'Stock'),
doc='Commodities that can be purchased at some site(s)')
m.com_sell = pyomo.Set(
within=m.com,
initialize=commodity_subset(m.com_tuples, 'Sell'),
doc='Commodities that can be sold')
m.com_buy = pyomo.Set(
within=m.com,
initialize=commodity_subset(m.com_tuples, 'Buy'),
doc='Commodities that can be purchased')
m.com_demand = pyomo.Set(
within=m.com,
initialize=commodity_subset(m.com_tuples, 'Demand'),
doc='Commodities that have a demand (implies timeseries)')
m.com_env = pyomo.Set(
within=m.com,
initialize=commodity_subset(m.com_tuples, 'Env'),
doc='Commodities that (might) have a maximum creation limit')
Where:
-
urbs.
commodity_subset
(com_tuples, type_name)¶ Returns the commodity names(\(c\)) of the given commodity type(\(q\)).
Parameters: - com_tuples – A list of tuples (site, commodity, commodity type)
- type_name – A commodity type or a list of commodity types
Returns: The set (unique elements/list) of commodity names of the desired commodity type.
Operational State Tuples¶
For intertemporal optimization the operational state of units in a support timeframe y has to be calculated from both the initially installed units and their remaining lifetime and the units installed in a previous support timeframe which are still operational in y. This is achieved via 6 tuple sets two each for processes, transmissions and storages. For the mathematical description please refer to Unit Expansion Constraints.
Initially Installed Units¶
Processes which are already installed at the beginning of the modeled time horizon and still operational in support timeframe stf are collected in the following tuple set:
m.inst_pro_tuples = pyomo.Set(
within=m.sit*m.pro*m.stf,
initialize=[(sit, pro, stf)
for (sit, pro, stf)
in inst_pro_tuples(m)],
doc=' Installed processes that are still operational through stf')
where the following function is utilized:
def inst_pro_tuples(m):
""" Tuples for operational status of already installed units
(processes, transmissions, storages) for intertemporal planning.
Only such tuples where the unit is still operational until the next
support time frame are valid.
"""
inst_pro = []
sorted_stf = sorted(list(m.stf))
for (stf, sit, pro) in m.inst_pro.index:
for stf_later in sorted_stf:
index_helper = sorted_stf.index(stf_later)
if stf_later == max(m.stf):
if (stf_later +
m.global_prop.loc[(max(sorted_stf), 'Weight'), 'value'] -
1 < min(m.stf) + m.process_dict['lifetime'][
(stf, sit, pro)]):
inst_pro.append((sit, pro, stf_later))
elif (stf_later + sorted_stf[index_helper + 1])/2 <= (min(m.stf)
+ m.process_dict['lifetime'][(stf, sit, pro)]):
inst_pro.append((sit, pro, stf_later))
return inst_pro
Transmissions which are already installed at the beginning of the modeled time horizon and still operational in support timeframe stf are collected in the following tuple set:
m.inst_tra_tuples = pyomo.Set(
within=m.sit*m.sit*m.tra*m.com*m.stf,
initialize=[(sit, sit_, tra, com, stf)
for (sit, sit_, tra, com, stf)
in inst_tra_tuples(m)],
doc='Installed transmissions that are still operational through stf')
where the following function is utilized:
def inst_tra_tuples(m):
""" s.a. inst_pro_tuples
"""
inst_tra = []
sorted_stf = sorted(list(m.stf))
for (stf, sit1, sit2, tra, com) in m.inst_tra.index:
for stf_later in sorted_stf:
index_helper = sorted_stf.index(stf_later)
if stf_later == max(m.stf):
if (stf_later +
m.global_prop_dict['value'][(max(sorted_stf), 'Weight')] -
1 < min(m.stf) + m.transmission_dict['lifetime'][
(stf, sit1, sit2, tra, com)]):
inst_tra.append((sit1, sit2, tra, com, stf_later))
elif (sorted_stf[index_helper + 1] <= min(m.stf) +
m.transmission_dict['lifetime'][
(stf, sit1, sit2, tra, com)]):
inst_tra.append((sit1, sit2, tra, com, stf_later))
return inst_tra
Storages which are already installed at the beginning of the modeled time horizon and still operational in support timeframe stf are collected in the following tuple set:
m.inst_sto_tuples = pyomo.Set(
within=m.sit*m.sto*m.com*m.stf,
initialize=[(sit, sto, com, stf)
for (sit, sto, com, stf)
in inst_sto_tuples(m)],
doc='Installed storages that are still operational through stf')
where the following function is utilized:
def inst_sto_tuples(m):
""" s.a. inst_pro_tuples
"""
inst_sto = []
sorted_stf = sorted(list(m.stf))
for (stf, sit, sto, com) in m.inst_sto.index:
for stf_later in sorted_stf:
index_helper = sorted_stf.index(stf_later)
if stf_later == max(m.stf):
if (stf_later +
m.global_prop_dict['value'][(max(sorted_stf), 'Weight')] -
1 < min(m.stf) +
m.storage_dict['lifetime'][(stf, sit, sto, com)]):
inst_sto.append((sit, sto, com, stf_later))
elif (sorted_stf[index_helper + 1] <=
min(m.stf) + m.storage_dict['lifetime'][
(stf, sit, sto, com)]):
inst_sto.append((sit, sto, com, stf_later))
return inst_sto
Installation in Earlier Support Timeframe¶
Processes installed in an earlier support timeframe stf and still usable in support timeframe stf_later are collected in the following tuple set:
m.operational_pro_tuples = pyomo.Set(
within=m.sit*m.pro*m.stf*m.stf,
initialize=[(sit, pro, stf, stf_later)
for (sit, pro, stf, stf_later)
in op_pro_tuples(m.pro_tuples, m)],
doc='Processes that are still operational through stf_later'
'(and the relevant years following), if built in stf'
'in stf.')
where the following function is utilized:
def op_pro_tuples(pro_tuple, m):
""" Tuples for operational status of units (processes, transmissions,
storages) for intertemporal planning.
Only such tuples where the unit is still operational until the next
support time frame are valid.
"""
op_pro = []
sorted_stf = sorted(list(m.stf))
for (stf, sit, pro) in pro_tuple:
for stf_later in sorted_stf:
index_helper = sorted_stf.index(stf_later)
if stf_later == max(sorted_stf):
if (stf_later +
m.global_prop.loc[(max(sorted_stf), 'Weight'), 'value'] -
1 <= stf + m.process_dict['depreciation'][
(stf, sit, pro)]):
op_pro.append((sit, pro, stf, stf_later))
elif ((stf_later + sorted_stf[index_helper + 1])/2 <= stf + m.process_dict['depreciation'][(stf, sit, pro)]
and stf <= stf_later):
op_pro.append((sit, pro, stf, stf_later))
else:
pass
return op_pro
Transmissions installed in an earlier support timeframe stf and still usable in support timeframe stf_later are collected in the following tuple set:
m.operational_tra_tuples = pyomo.Set(
within=m.sit*m.sit*m.tra*m.com*m.stf*m.stf,
initialize=[(sit, sit_, tra, com, stf, stf_later)
for (sit, sit_, tra, com, stf, stf_later)
in op_tra_tuples(m.tra_tuples, m)],
doc='Transmissions that are still operational through stf_later'
'(and the relevant years following), if built in stf'
'in stf.')
where the following function is utilized:
def op_tra_tuples(tra_tuple, m):
""" s.a. op_pro_tuples
"""
op_tra = []
sorted_stf = sorted(list(m.stf))
for (stf, sit1, sit2, tra, com) in tra_tuple:
for stf_later in sorted_stf:
index_helper = sorted_stf.index(stf_later)
if stf_later == max(sorted_stf):
if (stf_later +
m.global_prop_dict['value'][(max(sorted_stf), 'Weight')] -
1 <= stf + m.transmission_dict['depreciation'][
(stf, sit1, sit2, tra, com)]):
op_tra.append((sit1, sit2, tra, com, stf, stf_later))
elif (sorted_stf[index_helper + 1] <=
stf + m.transmission_dict['depreciation'][
(stf, sit1, sit2, tra, com)] and stf <= stf_later):
op_tra.append((sit1, sit2, tra, com, stf, stf_later))
else:
pass
return op_tra
Storages installed in an earlier support timeframe stf and still usable in support timeframe stf_later are collected in the following tuple set:
m.operational_sto_tuples = pyomo.Set(
within=m.sit*m.sto*m.com*m.stf*m.stf,
initialize=[(sit, sto, com, stf, stf_later)
for (sit, sto, com, stf, stf_later)
in op_sto_tuples(m.sto_tuples, m)],
doc='Processes that are still operational through stf_later'
'(and the relevant years following), if built in stf'
'in stf.')
where the following function is utilized:
def op_sto_tuples(sto_tuple, m):
""" s.a. op_pro_tuples
"""
op_sto = []
sorted_stf = sorted(list(m.stf))
for (stf, sit, sto, com) in sto_tuple:
for stf_later in sorted_stf:
index_helper = sorted_stf.index(stf_later)
if stf_later == max(sorted_stf):
if (stf_later +
m.global_prop_dict['value'][(max(sorted_stf), 'Weight')] -
1 <= stf +
m.storage_dict['depreciation'][(stf, sit, sto, com)]):
op_sto.append((sit, sto, com, stf, stf_later))
elif (sorted_stf[index_helper + 1] <=
stf +
m.storage_dict['depreciation'][(stf, sit, sto, com)] and
stf <= stf_later):
op_sto.append((sit, sto, com, stf, stf_later))
else:
pass
return op_sto