Technologies
The technology class is a subclass of the ModelComponent class. In the model, we further distinguish between generic technologies and specific technologies. Generic technologies offer a framework that can be adjusted for multiple technologies: only the performance parameters, and the input and output carriers change, while the equations remain the same.
Technology types, divided by generic and specific technologies:
Generic technologies:
RES
CONV1
CONV2
CONV3
CONV4
STOR
Specific technologies:
DAC adsorption
Gas turbine
Heat pump
Hydro open
Combined Cycle with fixed size (cannot be sized)
- Add-ons
Carbon Capture
All technology types listed above are modelled as subclasses of the Technology class. An overview of all
technologies that are currently modelled, and the technology classes / types used to model them, can be found
here.
Additionally, you can attach a post combustion CCS to any technology (see here)
Technology Class
As mentioned, the technology class is a subclass of the ModelComponent class. In general, all technology subclasses share the equations of this class, though some exceptions are there for specific technologies (the subclass then overwrites the class method).
- class Technology(tec_data: dict)
Class to read and manage data for technologies
This class is parent class to all generic and specific technologies. It creates the variables, parameters, constraints and sets of a technology.
This function is extented in the generic/specific technology classes. It adds Sets, Parameters, Variables and Constraints that are common for all technologies. The following description is true for new technologies. For existing technologies a few adaptions are made (see below). When CCS is available, we add heat and electricity to the input carriers Set and CO2captured to the output carriers Set. Moreover, we create extra Parameters and Variables equivalent to the ones created for the technology, but specific for CCS. In addition, we create Variables that are the sum of the input, output, CAPEX and OPEX of the technology and of CCS. We calculate the emissions of the technology discounting already what is being captured by the CCS.
Set declarations:
set_input_carriers: Set of input carriers
set_output_carriers: Set of output carriers
If ccs is possible:
set_input_carriers_ccs: Set of CCS input carriers
set_output_carriers_ccs: Set of CCS output carriers
** Set declarations for time aggregation:**
Three sets are declared for each technology. These are required for time averaging algorithms:
set_t_full: set of all time steps before clustering
set_t_performance: set of time steps, on which the technology performance is based on
set_t_global: set of time steps, on which the energy balance is based on
Parameter declarations:
The following is a list of declared pyomo parameters.
para_size_min: minimal possible size
para_size_max: maximal possible size
para_unit_capex: investment costs per unit
para_unit_capex_annual: Unit CAPEX annualized (annualized from given data on up-front CAPEX, lifetime and discount rate)
para_fix_capex: fixed costs independent of size
para_fix_capex_annual: Fixed CAPEX annualized (annualized from given data on up-front CAPEX, lifetime and discount rate)
para_opex_variable: operational cost EUR/output or input
para_opex_fixed: fixed opex as fraction of up-front capex
para_tec_emissionfactor: emission factor per output or input
If ccs is possible:
para_size_min_ccs: minimal possible size
para_size_max_ccs: maximal possible size
para_unit_capex_annual_ccs: investment costs per unit (annualized from given data on up-front CAPEX, lifetime and discount rate)
para_fix_capex_annual_ccs: Fixed CAPEX annualized (annualized from given data on up-front CAPEX, lifetime and discount rate)
para_opex_variable_ccs: operational cost EUR/output or input
para_opex_fixed_ccs: fixed opex as fraction of up-front capex
For existing technologies:
para_size_initial: initial size
para_decommissioning_cost_annual: Decommissioning cost
Variable declarations:
var_size: Size of the technology, can be integer or continuous
var_input: input to the technology, defined for each input carrier and time slice
var_output: output of the technology, defined for each output carrier and time slice
var_input_tot: input aggregation of technology and CCS input
var_output_tot: output aggregation of technology and CCS output
var_capex: annualized investment of the technology
var_opex_variable: variable operation costs, defined for each time slice
var_opex_fixed: fixed operational costs as fraction of up-front CAPEX
var_capex_tot: aggregation of technology and CCS capex
var_capex_aux: auxiliary variable to calculate the fixed opex of existing technologies
var_opex_variable_tot: aggregation of technology and CCS opex variable, defined for each time slice
var_opex_fixed_tot: aggregation of technology and CCS opex fixed
var_tec_emissions_pos: positive emissions, defined per time slice
var_tec_emissions_neg: negative emissions, defined per time slice
If ccs is possible:
var_size_ccs: Size of CCS (in CO2 captured terms)
var_input_ccs: input to the CCS component, defined for each CCS input carrier and time slice
var_output_ccs: output from the CCS component, defined for each CCS output carrier and time slice
var_capex_ccs: annualized investment of CCS
var_capex_aux_ccs: auxiliary variable to calculate the fixed opex of existing CCS
var_opex_variable_ccs: variable operation costs, defined for each time slice
var_opex_fixed_ccs: fixed operational costs
Constraint declarations
For new technologies, CAPEX, can be linear (for
capex_model == 1), piecewise linear (forcapex_model == 2) or linear with a fixed cost when the technology is installed (forcapex_model == 3). The capex model can also be overwritten in the children technology classes (forcapex_model == 4). Linear is defined as:\[capex_{aux} = size * capex_{unitannual}\]while linear with fixed installation costs is defined as. Note that capex_aux is zero if the technology is not installed:
\[capex_{aux} = size * capex_{unitannual} + capex_{fixed}\]Existing technologies, i.e. existing = 1, can be decommissioned (decommission = ‘continuous’ or decommission = ‘only_complete’) or not (decommission = ‘impossible’). For technologies that cannot be decommissioned, the size is fixed to the initial size given in the technology data. For technologies that can be decommissioned, the size can be smaller or equal to the initial size. When decommission = ‘continuous’ the size can take any value between the minimum and initial size. When decommission = ‘only_complete’ the size is either 0 or the initial size. Reducing the size comes at the decommissioning costs or benefits specified in the economics of the technology. The fixed opex is calculated by determining the capex that the technology would have costed if newly build and then taking the respective opex_fixed share of this. This is done with the auxiliary variable capex_aux.
For existing technologies that can be decommissioned, the CAPEX equal to the decommissioning costs:
\[capex = (size_{initial} - size) * decommissioningcost\]Variable OPEX: variable opex is defined in terms of the input, with the exception of DAC_Adsorption, RES and CONV4, where it is defined per unit of output:
\[opexvar_{t} = Input_{t, maincarrier} * opex_{var}\]Fixed OPEX: defined as a fraction of annual CAPEX:
\[opexfix = capex * opex_{fix}\]Input aggregation: aggregates total input from technology and CCS. In case there is no CCS, input_ccs is zero:
\[input_{t, car} + input_{CCS, t, car} = input_{tot, t, car}\]Output aggregation: aggregates total output from technology and CCS. In case there is no CCS, output_ccs is zero:
\[output_{t, car} + output_{CCS, t, car} = output_{tot, t, car}\]Capex aggregation: aggregates capex of technology and CCS. In case there is no CCS, capex_ccs is zero:
\[capex + capex_{CCS} = capex_{tot}\]Opex variable aggregation: aggregates opex variable of technology and CCS. In case there is no CCS, var_opex_variable_ccs is zero:
\[opex_{variable, t} + opex_{variable,CCS, t} = opex_{variable,tot, t}\]Opex fixed aggregation: aggregates opex fixed of technology and CCS. In case there is no CCS, opex_fixed_ccs is zero:
\[opex_{fixed} + opex_{fixed,CCS} = opex_{fixed,tot}\]Emissions: depending if they are based on input or output and depending if emission factor is negative or positive
\[emissions_{pos/neg,t} = output_{maincarrier, t} * emissionfactor_{pos}\]
If CCS is possible the following constraints apply:
Input carriers are given by:
\[input_{CCS, car} <= inputRatio_{carrier} * output_{CCS}/captureRate\]\[input_{tot, car} = inputTec_{car} + input_{CCS, car}\]CO2 captured output is constrained by:
\[output_{CCS} <= input(output)_{tec} * emissionFactor * captureRate\]The total output are given by:
\[output_{tot, car} = outputTec_{car} + output_{CCS, car}\]Emissions of the technology are:
\[emissions_{tec} = input(output)_{tec} * emissionFactor - output_{CCS}\]CAPEX is given by
\[CAPEX_{CCS} = Size_{CCS} * UnitCost_{CCS} + FixCost_{CCS}\]\[CAPEX_{tot} = CAPEX_{CCS} + CAPEX_{tec}\]Fixed OPEX: defined as a fraction of annual CAPEX:
\[OPEXfix_{CCS} = CAPEX_{CCS} * opex_{CCS}\]\[OPEX_{tot} = OPEX_{CCS} + OPEX_{tec}\]- construct_tech_model(b_tec, data: dict, set_t_full, set_t_clustered)
Construct the technology model with all required parameters, variable, sets,…
- Parameters:
b_tec – pyomo block with technology model
data (dict) – data containing model configuration
set_t_full – pyomo set containing timesteps
set_t_clustered – pyomo set containing clustered timesteps
- Returns:
pyomo block with technology model
- fit_technology_performance(climate_data: DataFrame, location: dict)
Fits technology performance (bounds and coefficients).
- Parameters:
climate_data (pd.Dataframe) – dataframe containing climate data
location (dict) – dict containing location details
- scale_model(b_tec, model, config)
Scales technology model
- Parameters:
b_tec – pyomo network block
model – pyomo model
config (dict) – config dict containing scaling factors
- Returns:
pyomo model
- write_results_tec_design(h5_group, model_block)
Function to report technology design
- Parameters:
model_block – pyomo network block
h5_group – h5 group to write to
- write_results_tec_operation(h5_group, model_block)
Function to report technology operation
- Parameters:
model_block – pyomo network block
h5_group – h5 group to write to
Generic Technologies
- class Res(tec_data: dict)
Renewable technology with capacity factor (has no input)
Resembles a renewable technology with no input. The capacity factors of the technology are determined for each individual technology type.
So far the following renewable technologies are possible:
Photovoltaic (based on irradiance in climate data and PV lib)
Wind turbines (based on wind speed and power curves provided)
Constraint declarations:
Output of technology. The output can be curtailed in three different ways. For
curtailment == 0, there is no curtailment possible. Forcurtailment == 1, the curtailment is continuous. Forcurtailment == 2, the size needs to be an integer, and the technology can only be curtailed discretely, i.e. by turning full modules off. Forcurtailment == 0(default), it holds:
\[Output_{t, car} = CapFactor_t * Size\]- construct_tech_model(b_tec, data: dict, set_t_full, set_t_clustered)
Adds constraints to technology blocks for tec_type RES (renewable technology)
- Parameters:
b_tec – pyomo block with technology model
data (dict) – data containing model configuration
set_t_full – pyomo set containing timesteps
set_t_clustered – pyomo set containing clustered timesteps
- Returns:
pyomo block with technology model
- fit_technology_performance(climate_data: DataFrame, location: dict)
Fits technology performance
- Parameters:
climate_data (pd.Dataframe) – dataframe containing climate data
location (dict) – dict containing location details
- write_results_tec_design(h5_group, model_block)
Function to report technology design
- Parameters:
model_block – pyomo network block
h5_group – h5 group to write to
- write_results_tec_operation(h5_group, model_block)
Function to report technology operation
- Parameters:
model_block – pyomo network block
h5_group – h5 group to write to
- class Conv1(tec_data: dict)
Technology with full input an output substitution
This technology type resembles a technology with full input and output substitution, i.e. \(\sum(output) = f(\sum(inputs))\) Three different performance function fits are possible.
Constraint declarations:
Size constraints can be formulated on the input or output. For size_based_on == ‘input’ it holds:
\[\sum(Input_{t, car}) \leq S\]For size_based_on == ‘output’ it holds:
\[\sum(Output_{t, car}) \leq S\]It is possible to limit the maximum input of a carrier. This needs to be specified in the technology JSON files. Then it holds:
\[Input_{t, car} <= max_in_{car} * \sum(Input_{t, car})\]performance_function_type == 1: Linear through origin. Note that if min_part_load is larger than 0, the technology cannot be turned off.\[\sum(Output_{t, car}) == {\alpha}_1 \sum(Input_{t, car})\]\[min_part_load * S \leq {\alpha}_1 \sum(Input_{t, car})\]performance_function_type == 2: Linear with minimal partload (makes big-m transformation required). If the technology is in on, it holds:\[\sum(Output_{t, car}) = {\alpha}_1 \sum(Input_{t, car}) + {\alpha}_2\]\[\sum(Input_{car}) \geq Input_{min} * S\]If the technology is off, input and output is set to 0:
\[\sum(Output_{t, car}) = 0\]\[\sum(Input_{t, car}) = 0\]If the technology has a standby-power, the input of the standy-by power carrier is:
\[Input_{t, standby-carrier} = standbypower * S\]performance_function_type == 3: Piecewise linear performance function ( makes big-m transformation required). The same constraints as forperformance_function_type == 2with the exception that the performance function is defined piecewise for the respective number of pieces.performance_function_type == 4:Piece-wise linear, minimal partload. Enables the modeling of technologies with slow (>1h) startup and shutdown trajectories. For more information please refer to dynamics under advanced topics. Based on Equations 9-11, 13 and 15 in Morales-España, G., Ramírez-Elizondo, L., & Hobbs, B. F. (2017). Hidden power system inflexibilities imposed by traditional unit commitment formulations. Applied Energy, 191, 223–238. https://doi.org/10.1016/J.APENERGY.2017.01.089Additionally, ramping rates of the technology can be constrained.
\[-rampingrate \leq \sum(Input_{t, car}) - \sum(Input_{t-1, car}) \leq rampingrate\]
- construct_tech_model(b_tec, data: dict, set_t_full, set_t_clustered)
Adds constraints to technology blocks for tec_type CONV1
- Parameters:
b_tec – pyomo block with technology model
data (dict) – data containing model configuration
set_t_full – pyomo set containing timesteps
set_t_clustered – pyomo set containing clustered timesteps
- Returns:
pyomo block with technology model
- fit_technology_performance(climate_data: DataFrame, location: dict)
Fits conversion technology type 1
- Parameters:
climate_data (pd.Dataframe) – dataframe containing climate data
location (dict) – dict containing location details
- class Conv2(tec_data: dict)
Technology with full input substitution
This technology type resembles a technology with full input substitution, but different performance functions for the respective output carriers, i.e. \(output_{car} = f_{car}(\sum(inputs))\). Three different performance function fits are possible.
Constraint declarations:
Size constraints are formulated on the input.
\[\sum(Input_{t, car}) \leq S\]It is possible to limit the maximum input of a carrier. This needs to be specified in the technology JSON files. Then it holds:
\[Input_{t, car} <= max_in_{car} * \sum(Input_{t, car})\]performance_function_type == 1: Linear through origin, i.e.:\[Output_{t, car} == {\alpha}_{1, car} \sum(Input_{t, car})\]\[min_part_load * S \leq {\alpha}_1 \sum(Input_{t, car})\]performance_function_type == 2: Linear with minimal partload (makes big-m transformation required). If the technology is in on, it holds:\[Output_{t, car} = {\alpha}_{1, car} \sum(Input_{t, car}) + {\alpha}_{2, car}\]\[\sum(Input_{car}) \geq Input_{min} * S\]If the technology is off, input and output is set to 0:
\[Output_{t, car} = 0\]\[\sum(Input_{t, car}) = 0\]If the technology has a standby-power, the input of the standy-by power carrier is:
\[Input_{t, standby-carrier} = standbypower * S\]performance_function_type == 3: Piecewise linear performance function ( makes big-m transformation required). The same constraints as forperformance_function_type == 2with the exception that the performance function is defined piecewise for the respective number of pieces.performance_function_type == 4:Piece-wise linear, minimal partload. Enables the modeling of technologies with slow (>1h) startup and shutdown trajectories. For more information please refer to dynamics under advanced topics. Based on Equations 9-11, 13 and 15 in Morales-España, G., Ramírez-Elizondo, L., & Hobbs, B. F. (2017). Hidden power system inflexibilities imposed by traditional unit commitment formulations. Applied Energy, 191, 223–238. https://doi.org/10.1016/J.APENERGY.2017.01.089Additionally, ramping rates of the technology can be constrained.
\[-rampingrate \leq \sum(Input_{t, car}) - \sum(Input_{t-1, car}) \leq rampingrate\]
- construct_tech_model(b_tec, data: dict, set_t_full, set_t_clustered)
Adds constraints to technology blocks for tec_type CONV2
- Parameters:
b_tec – pyomo block with technology model
data (dict) – data containing model configuration
set_t_full – pyomo set containing timesteps
set_t_clustered – pyomo set containing clustered timesteps
- Returns:
pyomo block with technology model
- fit_technology_performance(climate_data: DataFrame, location: dict)
Fits conversion technology type 2
- Parameters:
climate_data (pd.Dataframe) – dataframe containing climate data
location (dict) – dict containing location details
- class Conv3(tec_data: dict)
Technology with no input/output substitution
This technology type resembles a technology for which the output can be written as a function of the input, according to different performance functions that can be specified in the JSON files (
performance_function_type). Four different performance function fits of the technology data (again specified in the JSON file) are possible, and for all the function is based on the input of the main carrier , i.e.,: \(output_{car} = f_{car}(input_{maincarrier})\). Note that the ratio between all input carriers is fixed.Constraint declarations:
For all technologies modelled with CONV3 (regardless of performance function type): - Size constraints are formulated on the input.
\[Input_{t, maincarrier} \leq S\]The ratios of inputs are fixed and given as:
\[Input_{t, car} = {\phi}_{car} * Input_{t, maincarrier}\]If the technology is turned off, all inputs are set to zero.
performance_function_type == 1: Linear through origin. Note that if min_part_load is larger 0, the technology cannot be turned off.\[Output_{t, car} = {\alpha}_{1, car} Input_{t, maincarrier}\]\[min_part_load * S \leq {\alpha}_1 Input_{t, maincarrier}\]performance_function_type == 2: Linear with minimal partload. If the technology is in on, it holds:If the technology is in on, it holds:
\[Output_{t, car} = {\alpha}_{1, car} Input_{t, maincarrier} + {\alpha}_{2, car}\]\[Input_{maincarrier} \geq Input_{min} * S\]If the technology is off, input and output are set to 0:
\[Output_{t, car} = 0\]\[Input_{t, maincarrier} = 0\]performance_function_type == 3: Piecewise linear performance function ( makes big-m transformation required). The same constraints as forperformance_function_type == 2with the exception that the performance function is defined piecewise for the respective number of pieces.performance_function_type == 4:Piece-wise linear, minimal partload. Enables the modeling of technologies with slow (>1h) startup and shutdown trajectories. For more information please refer to dynamics under advanced topics. Based on Equations 9-11, 13 and 15 in Morales-España, G., Ramírez-Elizondo, L., & Hobbs, B. F. (2017). Hidden power system inflexibilities imposed by traditional unit commitment formulations. Applied Energy, 191, 223–238. https://doi.org/10.1016/J.APENERGY.2017.01.089Additionally, ramping rates of the technology can be constrained.
\[-rampingrate \leq Input_{t, main-car} - Input_{t-1, car} \leq rampingrate\]
- construct_tech_model(b_tec, data: dict, set_t_full, set_t_clustered)
Adds constraints to technology blocks for tec_type CONV3
- Parameters:
b_tec – pyomo block with technology model
data (dict) – data containing model configuration
set_t_full – pyomo set containing timesteps
set_t_clustered – pyomo set containing clustered timesteps
- Returns:
pyomo block with technology model
- fit_technology_performance(climate_data: DataFrame, location: dict)
Fits conversion technology type 3
- Parameters:
climate_data (pd.Dataframe) – dataframe containing climate data
location (dict) – dict containing location details
- class Conv4(tec_data: dict)
Technology with no inputs
This technology type resembles a technology with fixed output ratios and no inputs, i.e., \(output_{car} \leq S\). This technology is useful for modelling a technology for which you do not care about the inputs, i.e., you do not wish to construct and solve an energy balance for the input carriers. Two different performance function fits are possible.
Constraint declarations:
For all performance function types, the following constraints hold:
Size constraints are formulated on the output.
\[Output_{t, maincarrier} \leq S\]The ratios of outputs are fixed and given as:
\[Output_{t, car} = {\phi}_{car} * Output_{t, maincarrier}\]performance_function_type == 1: No further constraints on the performance of the technology.performance_function_type == 2: A minimum part load can be specified ( requiring a big-m transformation for the solving). The following constraints hold:When the technology is on:
\[Output_{maincarrier} \geq Output_{min} * S\]When the technology is off, output is set to 0:
\[Output_{t, car} = 0\]
- construct_tech_model(b_tec, data: dict, set_t_full, set_t_clustered)
Adds constraints to technology blocks for tec_type CONV4
- Parameters:
b_tec – pyomo block with technology model
data (dict) – data containing model configuration
set_t_full – pyomo set containing timesteps
set_t_clustered – pyomo set containing clustered timesteps
- Returns:
pyomo block with technology model
- fit_technology_performance(climate_data: DataFrame, location: dict)
Fits conversion technology type 4
- Parameters:
climate_data (pd.Dataframe) – dataframe containing climate data
location (dict) – dict containing location details
- class Stor(tec_data: dict)
Storage Technology
This model resembles a storage technology. Note that this technology only works for one carrier, and thus the carrier index is dropped in the below notation.
Variable declarations:
var_storage_level: Storage level in \(t\): \(E_t\)var_capacity_charge: Charging capacityvar_capacity_discharge: Discharging capacity
Constraint declarations:
The following constants are used:
\({\eta}_{in}\): Charging efficiency
\({\eta}_{out}\): Discharging efficiency
\({\lambda_1}\): Self-Discharging coefficient (independent of environment)
\({\lambda_2(\Theta)}\): Self-Discharging coefficient (dependent on environment)
\(Input_{max}\): Maximal charging capacity
\(Output_{max}\): Maximal discharging capacity
Size constraint:
\[E_{t} \leq S\]Maximal charging and discharging:
\[Input_{t} \leq Input_{max}\]\[Output_{t} \leq Output_{max}\]Storage level calculation:
\[E_{t} = E_{t-1} * (1 - \lambda_1) - \lambda_2(\Theta) * E_{t-1} + {\eta}_{in} * Input_{t} - 1 / {\eta}_{out} * Output_{t}\]If
allow_only_one_direction == 1, simultaneous charging and discharging is limited using Equation 24 from Morales-España, Germán & Hernandez, Ricardo & Helistö, Niina & Kiviluoma, Juha. (2022). LP Formulation for Optimal Investment and Operation of Storage Including Reserves. 10.13140/RG.2.2.27048.03840.If
allow_only_one_direction_precise == 1, then only input or output can be unequal to zero in each respective time step (otherwise, simultaneous charging and discharging can lead to unwanted ‘waste’ of energy/material).
If in
Flexibilitythepower_energy_ratio == fixed, then the capacity of the charging and discharging power is fixed as a ratio of the energy capacity. Thus:\[Input_{max} = \gamma_{charging} * S\]
If in ‘Flexibility’ the “power_energy_ratio == flexratio”, then the capacity of the charging and discharging power is a variable in the optimization. In this case, the charging and discharging rates specified in the json file are the maximum installed capacities as a ratio of the energy capacity. The model will optimize the charging and discharging capacities, based on the incorporation of these components in the CAPEX function.
If in ‘Flexibility’ the “power_energy_ratio == fixedratio”, then the capacity of the charging and discharging power is a fraction of the installed capacity. In this case, the charging and discharging rates specified in the json file are a ratio of the energy capacity.
If in ‘Flexibility’ the “power_energy_ratio == fixedcapacity”, then the capacity of the charging and discharging power is a fixed input parameter. In this case, the charging and discharging rates specified in the json file in the same unit as the input and output.
If an energy consumption for charging or dis-charging process is given, the respective carrier input is:
\[Input_{t, car} = cons_{car, in} Input_{t}\]\[Input_{t, car} = cons_{car, out} Output_{t}\]CAPEX is given by three contributions, the CAPEX of the charging capacity, the CAPEX of the discharging capacity, and the CAPEX of the energy capacity (i.e., the size of the storage).
\[CAPEX_{chargeCapacity} = chargeCapacity * unitCost_{chargeCapacity}\]\[CAPEX_{dischargeCapacity} = dischargeCapacity * unitCost_{dischargeCapacity}\]\[CAPEX_{storSize} = storSize * unitCost_{storSize}\]Additionally, ramping rates of the technology can be constraint (for input and output).
\[-rampingrate \leq Input_{t, maincar} - Input_{t-1, maincar} \leq rampingrate\]\[-rampingrate \leq \sum(Output_{t, car}) - \sum(Output_{t-1, car}) \leq rampingrate\]
- construct_tech_model(b_tec, data: dict, set_t_full, set_t_clustered)
Adds constraints to technology blocks for tec_type STOR, resembling a storage technology
- Parameters:
b_tec – pyomo block with technology model
data (dict) – data containing model configuration
set_t_full – pyomo set containing timesteps
set_t_clustered – pyomo set containing clustered timesteps
- Returns:
pyomo block with technology model
- fit_technology_performance(climate_data: DataFrame, location: dict)
Fits conversion technology type STOR and fills in the fitted parameters in a dict
- Parameters:
climate_data (pd.Dataframe) – dataframe containing climate data
location (dict) – dict containing location details
- write_results_tec_design(h5_group, model_block)
Function to report technology design
- Parameters:
model_block – pyomo network block
h5_group – h5 group to write to
- write_results_tec_operation(h5_group, model_block)
Function to report technology operation
- Parameters:
model_block – pyomo network block
h5_group – h5 group to write to
Specific Technologies
Solid Sorbent Direct Air Capture
- class DacAdsorption(tec_data: dict)
Direct Air Capture technology (adsorption)
The model resembles as Direct Air Capture technology with a modular setup. It has a heat and electricity input and CO2 as an output. The performance is based on data for a generic solid sorbent, as described in the article (see below). The performance data is fitted to the ambient temperature and humidity at the respective node.
The model is based on Wiegner et al. (2022). Optimal Design and Operation of Solid Sorbent Direct Air Capture Processes at Varying Ambient Conditions. Industrial and Engineering Chemistry Research, 2022, 12649–12667. https://doi.org/10.1021/acs.iecr.2c00681. It resembles operation configuration 1 without water spraying.
- construct_tech_model(b_tec, data: dict, set_t_full, set_t_clustered)
Adds constraints to technology blocks for tec_type DAC_adsorption
- Parameters:
b_tec – pyomo block with technology model
data (dict) – data containing model configuration
set_t_full – pyomo set containing timesteps
set_t_clustered – pyomo set containing clustered timesteps
- Returns:
pyomo block with technology model
- fit_technology_performance(climate_data: DataFrame, location: dict)
Fits the technology performance
- Parameters:
climate_data (pd.Dataframe) – dataframe containing climate data
location (dict) – dict containing location details
- write_results_tec_operation(h5_group, model_block)
Function to report technology operation
- Parameters:
model_block – pyomo network block
h5_group – h5 group to write to
Heat Pump
- class HeatPump(tec_data: dict)
Heat pump
Resembles a heat pump Three different types of heat pumps are possible: air sourced ( ‘HeatPump_AirSourced’), ground sourced (‘HeatPump_GroundSourced’) and water sourced (‘HeatPump_WaterSourced’). Additionally, a heating curve is determined for heating for buildings. Then, the application needs to be set to either ‘floor_heating’ or ‘radiator_heating’ in the data file. Otherwise, the output temperature of the heat pump can also be set to a given temperature. The coefficient of performance at full load is calculated in the respective fitting function with the equations provided in Ruhnau, O., Hirth, L., & Praktiknjo, A. (2019). Time series of heat demand and heat pump efficiency for energy system modeling. Scientific Data, 6(1). https://doi.org/10.1038/s41597-019-0199-y
The part load behavior is modelled after equation (3) in Xu, Z., Li, H., Xu, W., Shao, S., Wang, Z., Gou, X., Zhao, M., & Li, J. (2022). Investigation on the efficiency degradation characterization of low ambient temperature air source heat pump under partial load operation. International Journal of Refrigeration, 133, 99–110. https://doi.org/10.1016/J.IJREFRIG.2021.10.002
Essentially, the equations for the heat pump model are the same as for generic conversion technology type 1 (with time-dependent performance parameter).
Ramping rates of the technology can be constraint.
\[-rampingrate \leq \sum(Input_{t, car}) - \sum(Input_{t-1, car}) \leq rampingrate\]- construct_tech_model(b_tec, data: dict, set_t_full, set_t_clustered)
Adds constraints to technology blocks for tec_type HP (Heat Pump)
- Parameters:
b_tec – pyomo block with technology model
data (dict) – data containing model configuration
set_t_full – pyomo set containing timesteps
set_t_clustered – pyomo set containing clustered timesteps
- Returns:
pyomo block with technology model
- fit_technology_performance(climate_data: DataFrame, location: dict)
Performs fitting for technology type HeatPump
- Parameters:
tec_data – technology data
climate_data – climate data
- Returns:
Gas Turbine
- class GasTurbine(tec_data: dict)
Gas turbine
Resembles gas turbines of different sizes. Hydrogen and Natural Gas Turbines are possible at four different sizes, as indicated by the file names of the data. Performance data and the model is taken from Weimann, L., Ellerker, M., Kramer, G. J., & Gazzani, M. (2019). Modeling gas turbines in multi-energy systems: A linear model accounting for part-load operation, fuel, temperature, and sizing effects. International Conference on Applied Energy. https://doi.org/10.46855/energy-proceedings-5280
A small adaption is made: Natural gas turbines can co-fire hydrogen up to 5% of the energy content
Variable declarations:
Total fuel input in \(t\): \(Input_{tot, t}\)
Number of turbines on in \(t\): \(N_{on,t}\)
Constraint declarations:
The following constants are used:
\(Input_{min}\): Minimal input per turbine
\(Input_{max}\): Maximal input per turbine
\(in_{H2max}\): Maximal H2 admixture to fuel (only for natural gas turbines, default is 0.05)
\({\alpha}\): Performance parameter for electricity output
\({\beta}\): Performance parameter for electricity output
\({\epsilon}\): Performance parameter for heat output
\(f({\Theta})\): Ambient temperature correction factor
Input calculation (For hydrogen turbines, \(Input_{NG, t}\) is zero, and the second constraint is removed):
\[Input_{H2, t} + Input_{NG, t} = Input_{tot, t}\]\[Input_{H2, t} \leq in_{H2max} Input_{tot, t}\]Turbines on:
\[N_{on, t} \leq S\]If technology is on:
\[Output_{el,t} = ({\alpha} Input_{tot, t} + {\beta} * N_{on, t}) *f({\Theta})\]\[Output_{th,t} = {\epsilon} Input_{tot, t} - Output_{el,t}\]\[Input_{min} * N_{on, t} \leq Input_{tot, t} \leq Input_{max} * N_{on, t}\]If the technology is off, input and output is set to 0:
\[\sum(Output_{t, car}) = 0\]\[\sum(Input_{t, car}) = 0\]Additionally, ramping rates of the technology can be constraint.
\[-rampingrate \leq \sum(Input_{t, car}) - \sum(Input_{t-1, car}) \leq rampingrate\]
- construct_tech_model(b_tec, data: dict, set_t_full, set_t_clustered)
Adds constraints to technology blocks for gas turbines
- Parameters:
b_tec – pyomo block with technology model
data (dict) – data containing model configuration
set_t_full – pyomo set containing timesteps
set_t_clustered – pyomo set containing clustered timesteps
- Returns:
pyomo block with technology model
- fit_technology_performance(climate_data: DataFrame, location: dict)
Performs fitting for technology type GasTurbine
- Parameters:
tec_data – technology data
climate_data – climate data
- Returns:
- write_results_tec_operation(h5_group, model_block)
Function to report results of technologies after optimization
- Parameters:
b_tec – technology model block
- Returns:
dict results: holds results
Hydro Open
- class HydroOpen(tec_data: dict)
Open pumped hydro technology
Resembles a pumped hydro plant with additional natural inflows (defined in climate data). Note that this technology only works for one carrier, and thus the carrier index is dropped in the below notation.
Variable declarations:
Storage level in \(t\): \(E_t\)
Charging in \(t\): \(Input_{t}\)
Discharging in \(t\): \(Output_{t}\)
Constraint declarations:
The following constants are used:
\({\eta}_{in}\): Charging efficiency
\({\eta}_{out}\): Discharging efficiency
\({\lambda}\): Self-Discharging coefficient
\(Input_{max}\): Maximal charging capacity in one time-slice
\(Output_{max}\): Maximal discharging capacity in one time-slice
\(Natural_Inflow{t}\): Natural water inflow in time slice (can be negative, i.e. being an outflow)
Maximal charging and discharging:
\[Input_{t} \leq Input_{max}\]\[Output_{t} \leq Output_{max}\]Size constraint:
\[E_{t} \leq S\]Storage level calculation:
\[E_{t} = E_{t-1} * (1 - \lambda) + {\eta}_{in} * Input_{t} - 1 / {\eta}_{out} * Output_{t} + Natural_Inflow_{t}\]If
allow_only_one_direction == 1, then only input or output can be unequal to zero in each respective time step (otherwise, simultanous charging and discharging can lead to unwanted ‘waste’ of energy/material).Additionally, ramping rates of the technology can be constraint (for input and output).
\[-rampingrate \leq Input_{t, maincar} - Input_{t-1, maincar} \leq rampingrate\]\[-rampingrate \leq \sum(Input_{t, car}) - \sum(Input_{t-1, car}) \leq rampingrate\]
- construct_tech_model(b_tec, data: dict, set_t_full, set_t_clustered)
Adds constraints to technology blocks for tec_type Hydro_Open
- Parameters:
b_tec – pyomo block with technology model
data (dict) – data containing model configuration
set_t_full – pyomo set containing timesteps
set_t_clustered – pyomo set containing clustered timesteps
- Returns:
pyomo block with technology model
- fit_technology_performance(climate_data: DataFrame, location: dict)
Fits technology performance
- Parameters:
climate_data (pd.Dataframe) – dataframe containing climate data
location (dict) – dict containing location details
- write_results_tec_operation(h5_group, model_block)
Function to report technology operation
- Parameters:
model_block – pyomo network block
h5_group – h5 group to write to
Combined Cycle with fixed size
- class CCPP(tec_data: dict)
Combined Cycle Power Plant with Steam Production
Resembles Combined Cycle Power Plant with Steam Production. The size of the power plant it fixed and it only possible to model the plant as an existing technology (i.e. it cannot be sized). The model is based on Wiegner et al. (2024). Optimizing the Use of Limited Amounts of Hydrogen in Existing Combined Heat and Power Plants https://www.sciencedirect.com/science/article/pii/S2667095X24000199.
It is possible in the JSON file to specify the following options:
size_ohb: Size of an Oxy-fuel hydrogen burner
size_db: Size of a duct burner that can burn hydrogen or natural gas
max_h2_in_gt: Max share (energy-based) of hydrogen combustion in the gas turbine (“max_input”)
max_h2_in: Maximum of hydrogen input to plant
How to treat steam production (“steam_production”):
“ignore”: technology has no additional output other than electricity
“as heat”: technology has heat output, equivalent to the sum of HP/MP generation
“as steam”: technology has steam output, equivalent to the sum of HP/MP generation
“as hp/mp steam”: technology has HP and MP steam output
What additional components in the plant should be considered. Possible options are:
“None”: only CCPP
“DB”: Duct burner
“OHB”: Oxyfuel-hydrogen burner
Number of segments to use for performance function (“nr_segments”). Recommended: 2
Variable declarations:
Total fuel input in \(t\): \(Input_{tot, t}\)
Fuel input to duct burner/ OHB \(Input_{OHB/DB, t}\)
Constraint declarations:
The following constants are used:
\(Input_{min}\): Minimal input per turbine
\(Input_{max}\): Maximal input per turbine
\(in_{H2max}\): Maximal H2 admixture to fuel (only for natural gas turbines, default is 0.05)
\({\alpha}\): Performance parameter for electricity output
\({\beta}\): Performance parameter for electricity output
\({\epsilon}\): Performance parameter for heat output
\(f({\Theta})\): Ambient temperature correction factor
Input calculation (For hydrogen turbines, \(Input_{NG, t}\) is zero, and the second constraint is removed):
\[Input_{H2, t} + Input_{NG, t} = Input_{tot, t}\]\[Input_{H2, t} \leq in_{H2max} Input_{tot, t}\]Turbines on:
\[N_{on, t} \leq S\]If technology is on:
\[Output_{el,t} = ({\alpha} Input_{tot, t} + {\beta} * N_{on, t}) *f({\Theta})\]\[Output_{th,t} = {\epsilon} Input_{tot, t} - Output_{el,t}\]\[Input_{min} * N_{on, t} \leq Input_{tot, t} \leq Input_{max} * N_{on, t}\]If the technology is off, input and output is set to 0:
\[\sum(Output_{t, car}) = 0\]\[\sum(Input_{t, car}) = 0\]Additionally, ramping rates of the technology can be constraint.
\[-rampingrate \leq\sum(Input_{t, car}) -\sum(Input_{t-1, car}) \leq rampingrate\]
- construct_tech_model(b_tec, data: dict, set_t_full, set_t_clustered)
Adds constraints to technology blocks for gas turbines
- Parameters:
b_tec – pyomo block with technology model
data (dict) – data containing model configuration
set_t_full – pyomo set containing timesteps
set_t_clustered – pyomo set containing clustered timesteps
- Returns:
pyomo block with technology model
- fit_technology_performance(climate_data: DataFrame, location: dict)
Performs fitting for technology type CCPP
- Parameters:
tec_data – technology data
climate_data – climate data
- Returns:
- write_results_tec_operation(h5_group, model_block)
Function to report results of technologies after optimization
- Parameters:
b_tec – technology model block
- Returns:
dict results: holds results
Carbon Capture
The carbon capture object (CCS, even though it refers just to the capture technology), which does not constitute an independent technology itself, can be attached to any technology with a positive emission factor. To do this, you need to add (if not already present) the following lines of code to the json file under the “Performance” section of the technology you wish to equip with CCS:
- “ccs”: {
“possible”: 1, “co2_concentration” : 0.08, “ccs_type”: “MEA_medium”
},
To see an example of how this is done, you can look at the json file of the GasTurbine_simple_CCS technology. When you want to have the possibility of installing CCS, you need to set the “possible” option to 1. Moreover, you can specify the CO2 concentration in the flue gas of your emitting technology; this will influence the costs and energy performance of the CCS. With “ccs_type” you can specify the specific capture technology you wish to use. So far, only post combustion capture with MEA is modelled (following the work of Weimann et Al. 2023 https://doi.org/10.1016/j.apenergy.2023.120738), and you can choose the between small, medium and large according to the size range that you expect for the capture plant (the range of the sizes – based on the flue gas flow in t/h – can be found in each json file of the CCS object, e.g. “MEA_medium.json”).
The CCS needs heat and electricity as input to run. Therefore, you have to make sure to have those carriers available. Moreover, the CCS will produce an extra carrier as output of the emitting technology called “CO2captured” in amount equal to the CO2 captured from the flue gas. The CO2captured needs to be sent to a storage site or exported. In AdOpT-NET0 a storage site is represented with the SINK class of technologies. So far, only the “PermanentStorage_CO2_simple” SINK technology is available. This storage takes CO2captured and electricity (for compression and injection) as inputs and it has no output. The costs of this sink are given only by the amount of CO2 stored times a fixed cost per ton of CO2 (no capital costs).
To account for the capture of CO2 in the emissions balance, when the CC is implemented the amount of CO2 that is captured is subtracted from the emissions of the technology.
To summarize, if you want to add the CCS option to a technology you have to: - Add “ccs” section in the “Performance” of the json file as above and adjust the settings to your case study (concentration and CC technology type and size) - Have electricity, heat (with import possibility if required) and CO2captured as carriers - Have a technology type SINK or CO2captured export option - Add CO2 transport option if sink and capture are in different nodes