CO₂ capture retrofit

A specific CO₂ source node is required as the default implementation of a RefSource does not allow for the CO₂ instance to be an output, as declared in the function constraints_flow_out. This is due to the implementation using CaptureData in which the CO₂ oulet flow is calculated through the implementation of the capture rate.

Hence, it is necessary to implement a CO₂ source node if one wants to model only a CO₂ source.

Introduced type and its field

CO₂ capture retrofit requires the implementation of two additional node types, RefNetworkNodeRetrofit and CCSRetroFit both nodes are quite similar to a RefNetworkNode although their application differs:

Implementation of retrofit

It is necessary to include both RefNetworkNodeRetrofit and CCSRetroFit if one wants to implement the additional installation of CO₂ capture. It is not possible to only use one of them.

If you want to include several retrofit options, it is of absolute importance that you:

  1. directly couple the RefNetworkNodeRetrofit and CCSRetroFit nodes through a Link and
  2. do not include the CO₂ proxy resource (see below) as a product in the Availability node.

It would be otherwise possible to use a single CO₂ capture unit for all process with the option for retrofit, neglecting potential peak capacity requirements and economies of scale.

Standard fields

Both introduced nodes use the same fields, although their meaning may potentially differ. The standard fields are given as:

  • id:
    The field id is only used for providing a name to the node. This is similar to the approach utilized in EnergyModelsBase.
  • cap::TimeProfile:
    The installed capacity corresponds to the potential usage of the node.
    If the node should contain investments through the application of EnergyModelsInvestments, it is important to note that you can only use FixedProfile or StrategicProfile for the capacity, but not RepresentativeProfile or OperationalProfile. In addition, all values have to be non-negative.
    Meaning in boths nodes
    • RefNetworkNodeRetrofit:
      The capacity corresponds to the production capacity of a process.
    • CCSRetroFit:
      The capacity corresponds to the CO₂ flow rate handling capacity, not the CO₂ capture capacity
  • opex_var::TimeProfile:
    The variable operational expenses are based on the capacity utilization through the variable :cap_use. Hence, it is directly related to the specified output ratios. The variable operating expenses can be provided as OperationalProfile as well.
  • opex_fixed::TimeProfile:
    The fixed operating expenses are relative to the installed capacity (through the field cap) and the chosen duration of a strategic period as outlined on Utilize TimeStruct.
    It is important to note that you can only use FixedProfile or StrategicProfile for the fixed OPEX, but not RepresentativeProfile or OperationalProfile. In addition, all values have to be non-negative.
    Meaning in boths nodes
    • RefNetworkNodeRetrofit:
      The variable OPEX is relative to the production of the main product.
    • CCSRetroFit:
      The variable OPEX is relative to the amount of flue gas handled, that is not the amount of CO₂ captured.
  • input::Dict{<:Resource, <:Real} and output::Dict{<:Resource, <:Real}:
    Both fields describe the input and output Resources with their corresponding conversion factors as dictionaries.
    All values have to be non-negative.
    Meaning in boths nodes
    • RefNetworkNodeRetrofit:
      No special meaning. The CO₂ proxy resource is automatically included in the output dictionary through providing additional methods to EMB.outputs.
    • CCSRetroFit:
      The CO₂ proxy resource is automatically included in the input dictionary through providing additional methods to EMB.inputs. Requires the incorporation of the CO₂ resource in the output dictionary, although the exact value is not relevant. It is furthermore possible to specify additional reenergy required for capturing CO₂ using a conversion factor (e.g., MWh/t CO₂).
  • data::Vector{Data}:
    An entry for providing additional data to the model. The data vector must include CaptureData for both RefNetworkNodeRetrofit and CCSRetroFit. It can include additional investment data when EnergyModelsInvestments is used.
    Meaning of the capture rate in both nodes
    • RefNetworkNodeRetrofit:
      The capture rate corresponds to the fraction of the flue gas which is sent to the CCSRetroFit node. Hence, if the value is below 1, only a fraction of the flue gas can be captured.
    • CCSRetroFit:
      The capture rate corresponds to
      1. the fraction captured from the flue gas (CaptureFlueGas),
      2. the fraction captured from the flue gas and the energy input to the unit (CaptureEnergyEmissions),
      3. the fraction captured from the flue gas and the process emissions (CaptureProcessEmissions), or
      4. the fraction captured from the flue gas, the energy input to the unit, and the process emissions (CaptureProcessEnergyEmissions)

Additional fields

Both introduced nodes have one additional field:

  • co2_proxy::Resource:
    The CO₂ proxy resource is introduced to simplify the analyses and seperate all streams corresponding to CO₂ from the CO₂ streams considered in CO₂ capture retrofit. It should be specified as ResourceCarrier with a CO₂ intensity of 0.

Mathematical description

In the following mathematical equations, we use the name for variables and functions used in the model. Variables are in general represented as

$\texttt{var\_example}[index_1, index_2]$

with square brackets, while functions are represented as

$func\_example(index_1, index_2)$

with paranthesis.

Variables

Standard variables

Both introduced nodes utilize all standard variables from the RefNetworkNode, as described on the page Optimization variables. The variables include:

Additional variables

Both introduced nodes do not add additional variables.

Constraints

The following sections omit the direct inclusion of the vector of any node. Instead, it is implicitly assumed that the constraints are valid $\forall n ∈ N$ for all RefNetworkNodeRetrofit or CCSRetroFit types if not stated differently. In addition, all constraints are valid $\forall t \in T$ (that is in all operational periods) or $\forall t_{inv} \in T^{Inv}$ (that is in all strategic periods).

Standard constraints

Both introduced nodes utilize in general the standard constraints described on Constraint functions. These standard constraints are:

  • constraints_capacity:

    \[\texttt{cap\_use}[n, t] \leq \texttt{cap\_inst}[n, t]\]

  • constraints_capacity_installed:

    \[\texttt{cap\_inst}[n, t] = capacity(n, t)\]

    Using investments

    The function constraints_capacity_installed is also used in EnergyModelsInvestments to incorporate the potential for investment. Nodes with investments are then no longer constrained by the parameter capacity.

  • constraints_flow_in:

    \[\texttt{flow\_in}[n, t, p] = inputs(n, p) \times \texttt{cap\_use}[n, t] \qquad \forall p \in inputs(n)\]

    This standard constraint is only included for `RefNetworkNodeRetrofit`.
  • constraints_flow_out:

    \[\texttt{flow\_out}[n, t, p] = outputs(n, p) \times \texttt{cap\_use}[n, t] \qquad \forall p \in outputs(n) \setminus \{\text{CO}_2\}\]

    This standard constraint is only included for `CCSRetroFit`.
  • constraints_opex_fixed:

    \[\texttt{opex\_fixed}[n, t_{inv}] = opex\_fixed(n, t_{inv}) \times \texttt{cap\_inst}[n, first(t_{inv})]\]

    Why do we use `first()`

    The variable $\texttt{cap\_inst}$ is declared over all operational periods (see the section on Capacity variables for further explanations). Hence, we use the function $first(t_{inv})$ to retrieve the installed capacity in the first operational period of a given strategic period $t_{inv}$ in the function constraints_opex_fixed.

  • constraints_opex_var:

    \[\texttt{opex\_var}[n, t_{inv}] = \sum_{t \in t_{inv}} opex_var(n, t) \times \texttt{cap\_use}[n, t] \times scale\_op\_sp(t_{inv}, t)\]

    The function `scale_op_sp`

    The function $scale\_op\_sp(t_{inv}, t)$ calculates the scaling factor between operational and strategic periods. It also takes into account potential operational scenarios and their probability as well as representative periods.

  • constraints_data:
    This function is only called for specified data of the nodes, see above. This function is extended with multiple methods for both CCSRetroFit and RefNetworkNodeRetrofit. The individual methods are explained below.

The outlet flow constraint for a RefNetworkNodeRetrofit node is requires introducing new methods for the function constraints_flow_out as the outlet flow of the CO₂ proxy is calculated in the function constraints_data as outlined in Standard constraints. This constraint is given by:

\[\texttt{flow\_out}[n, t, p] = outputs(n, p) \times \texttt{cap\_use}[n, t] \qquad \forall p \in outputs(n) \setminus \{co2\_proxy(n)\}\]

The introduction of the CO₂ capture unit as retrofit option requires introducing new methods for the function constraints_data for all CaptureData as described on Data functions. In all methods, the process emissions of the other ResourceEmits, that is all emissions resources except for CO₂, are calculated as

\[\begin{aligned} \texttt{emissions\_node}&[n, t, p_{em}] = \\ & \texttt{cap\_use}[n, t] \times process\_emissions(data, p_{em}, t) \qquad \forall p_{em} \in P^{em} \setminus \{\text{CO}_2\} \end{aligned}\]

RefNetworkNodeRetrofit introduces methods for CaptureProcessEmissions, CaptureEnergyEmissions, and CaptureProcessEnergyEmissions.

data::CaptureProcessEmissions

The total produced CO₂ is calculated through an auxiliary expression as

\[ CO2\_tot[n, t] = \texttt{cap\_use}[n, t] \times process\_emissions(data, \text{CO}_2, t)\]

This auxiliary variable is subsequently used to calculate the CO₂ emissions of the node as

\[\begin{aligned} \texttt{emissions\_node}&[n, t, \text{CO}_2] = \\ & (1-co2\_capture(data)) \times CO2\_tot[n, t] + \\ & \sum_{p_{in} \in P^{in}} co2\_int(p_{in}) \times \texttt{flow\_in}[n, t, p_{in}] \end{aligned}\]

data::CaptureEnergyEmissions

The total produced CO₂ is calculated through an auxiliary expression as

\[ CO2\_tot[n, t] = \sum_{p_{in} \in P^{in}} co2\_int(p_{in}) \times \texttt{flow\_in}[n, t, p_{in}]\]

This auxiliary variable is subsequently used to calculate the CO₂ emissions of the node as

\[\begin{aligned} \texttt{emissions\_node}&[n, t, \text{CO}_2] = \\ & (1-co2\_capture(data)) \times CO2\_tot[n, t] + \\ & \texttt{cap\_use}[n, t] \times process\_emissions(data, \text{CO}_2, t) \end{aligned}\]

data::CaptureProcessEnergyEmissions

The total produced CO₂ is calculated through an auxiliary expression as

\[\begin{aligned} CO2\_tot&[n, t] = \\ & \texttt{cap\_use}[n, t] \times process\_emissions(data, \text{CO}_2, t) + \\ & \sum_{p_{in} \in P^{in}} co2\_int(p_{in}) \times \texttt{flow\_in}[n, t, p_{in}] \end{aligned}\]

This auxiliary variable is subsequently used to calculate the CO₂ emissions of the node as

\[\begin{aligned} \texttt{emissions\_node}&[n, t, \text{CO}_2] = \\ & (1-co2\_capture(data)) \times CO2\_tot[n, t] + \\ & \end{aligned}\]

These constraints are the same as it is the case for other nodes. The only difference is the calculation of the the outlet flow of the CO₂ proxy resource. It is for all CaptureData calculated as

\[ \texttt{flow\_out}[n, t, co2\_proxy(n)] = CO2\_tot[n, t] * co2\_capture(data)\]

CCSRetroFit introduces methods for CaptureFlueGas, CaptureProcessEmissions, CaptureEnergyEmissions, and CaptureProcessEnergyEmissions.

All types utilize similar functions although there is a variation in the individual calculations. The model introduces two auxiliaty expressiones, $CO2\_tot_[n, t]$ and $CO2\_captured[n, t]$. $CO2\_tot_[n, t]$ representes the total produced CO₂ (flue gas from the RefNetworkNodeRetrofit and potentially energy usage related emissions and/or process emissions) in the capture unit. Hence, its calculation differes depending on the CaptureData. $CO2\_captured[n, t]$ is calculated as:

\[ CO2\_captured[n, t] = co2\_capture(data) \times CO2\_tot[n, t]\]

The CO₂ emissions are calculated for all types using the auxiliary variable $CO2\_captured[n, t]$ as

\[\begin{aligned} \texttt{emissions\_node}&[n, t, \text{CO}_2] = \\ & \texttt{flow\_in}[n, t, co2\_proxy(n)] + \\ & \texttt{cap\_use}[n, t] \times process\_emissions(data, \text{CO}_2, t) + \\ & \sum_{p_{in} \in P^{in}} co2\_int(p_{in}) \times \texttt{flow\_in}[n, t, p_{in}] - \\ & CO2\_captured[n, t] \end{aligned}\]

while the CO₂ outlet flow is given as:

\[ \texttt{flow\_out}[n, t, \text{CO}_2] = CO2\_captured[n, t]\]

data::CaptureFlueGas

The total produced CO₂ is calculated as

\[ CO2\_tot[n, t] = \texttt{cap\_use}[n, t]\]

In addition, we have to provide an upper limit on the outlet CO₂ flow to avoid achieving a higher capture rate than specified when the capture unit is dimensioned for a larger CO₂ proxy inlet flow rate:

\[\begin{aligned} \texttt{flow\_out}&[n, t, \text{CO}_2] \leq \\ & co2\_capture(data) \times \\ & \texttt{flow\_in}[n, t, co2\_proxy(n)] \end{aligned}\]

data::CaptureProcessEmissions

The total produced CO₂ is calculated as

\[\begin{aligned} CO2\_tot&[n, t] = \\ & \texttt{cap\_use}[n, t] \times (1 + process\_emissions(data, \text{CO}_2, t)) \end{aligned}\]

In addition, we have to provide an upper limit on the outlet CO₂ flow to avoid achieving a higher capture rate than specified when the capture unit is dimensioned for a larger CO₂ proxy inlet flow rate:

\[\begin{aligned} \texttt{flow\_out}&[n, t, \text{CO}_2] \leq \\ & co2\_capture(data) \times \\ & (\texttt{flow\_in}[n, t, co2\_proxy(n)] + \\ & \texttt{cap\_use}[n, t] \times process\_emissions(data, \text{CO}_2, t)) \end{aligned}\]

data::CaptureEnergyEmissions

The total produced CO₂ is calculated as

\[\begin{aligned} CO2\_tot&[n, t] = \\ & \texttt{cap\_use}[n, t] + \\ & \sum_{p_{in} \in P^{in}} co2\_int(p_{in}) \times \texttt{flow\_in}[n, t, p_{in}] \end{aligned}\]

In addition, we have to provide an upper limit on the outlet CO₂ flow to avoid achieving a higher capture rate than specified when the capture unit is dimensioned for a larger CO₂ proxy inlet flow rate:

\[\begin{aligned} \texttt{flow\_out}&[n, t, \text{CO}_2] \leq \\ & co2\_capture(data) \times \\ & (\texttt{flow\_in}[n, t, co2\_proxy(n)] + \\ & \sum_{p_{in} \in P^{in}} co2\_int(p_{in}) \times \texttt{flow\_in}[n, t, p_{in}]) \end{aligned}\]

data::CaptureProcessEnergyEmissions

The total produced CO₂ is calculated through an auxiliary expression as

\[\begin{aligned} CO2\_tot&[n, t] = \\ & \texttt{cap\_use}[n, t] \times (1 + process\_emissions(data, \text{CO}_2, t)) + \\ & \sum_{p_{in} \in P^{in}} co2\_int(p_{in}) \times \texttt{flow\_in}[n, t, p_{in}] \end{aligned}\]

This auxiliary variable is subsequently used to calculate the CO₂ emissions of the node as

\[\begin{aligned} \texttt{flow\_out}&[n, t, \text{CO}_2] \leq \\ & co2\_capture(data) \times \\ & (\texttt{flow\_in}[n, t, co2\_proxy(n)] + \\ & \texttt{cap\_use}[n, t] \times process\_emissions(data, \text{CO}_2, t) + \\ & \sum_{p_{in} \in P^{in}} co2\_int(p_{in}) \times \texttt{flow\_in}[n, t, p_{in}]) \end{aligned}\]

Additional constraints

Constraints calculated in create_node

The inlet flow constraint for a CCSRetroFit node is calculated separately as the inlet flow of the CO₂ proxy is calculated in the function constraints_data as outlined in Standard constraints. This constraint is given by:

\[\texttt{flow\_in}[n, t, p] = inputs(n, p) \times \texttt{cap\_use}[n, t] \qquad \forall p \in inputs(n) \setminus \{co2\_proxy(n)\}\]

Constraints through separate functions

Neither RefNetworkNodeRetrofit nor CCSRetroFit nodes introduce new functions.