TulipaEnergy / TulipaEnergyModel.jl

An energy system optimization model that is flexible, computationally efficient, and academically robust.
Apache License 2.0
27 stars 18 forks source link

Add basic version of unit commitment and ramping constraints #581

Closed datejada closed 1 month ago

datejada commented 6 months ago

Description

Create methods to have two levels of detail for the unit commitment:

NOTE: The more complex version of the unit commitment (i.e., tight and compact) will be implemented in 2025!

Also, we need to create methods to have the possibility of having ramping constraints or not.

Use the formulation here as a reference:

https://www.overleaf.com/project/6454fde7fdf7f1c73ceeb2a0

Sub issues (edit and create relevant issues as they are needed)

datejada commented 6 months ago

Starting in July

datejada commented 6 months ago

Take @gzclarence formulation from the "Fully Flexible Temporal Resolution for Energy System Optimization Using Index Aggregation" paper for the unit commitment and ramping constraints using flexible temporal resolution. By July, a pre-print should be publicly available; in the meantime, ask Zhi for details.

datejada commented 4 months ago

Unit commitment method (basic version)

The basic unit commitment constraints will only consider the commitment variable and the minimum operating point for the constraints. In addition, the ramping constraints will consider the ramping up and down rates.

The unit commitment method will only apply to production and conversion assets.

New variables

$v^{\text{on}}_{a,k,b_k}$: Number of units ON of asset $a$ in representative period $k$ and timestep block $b_k$ [N]

New parameters

$p^{\text{min operating point}}_{a}$: Minimum operating point or minimum stable generation level defined as a portion of the capacity of asset $a$ [p.u.]

$p^{\text{max ramp up}}_{a}$: Maximum ramping up rate as a portion of the capacity of asset $a$ [p.u.]

$p^{\text{max ramp down}}_{a}$: Maximum ramping down rate as a portion of the capacity of asset $a$ [p.u.]

$p^{\text{init units}}_{a}$: Initial number of units (double-check if it is better as a new parameter or if it is a calculation from existing input data)

New method

Name Description Elements Superset Notes
$\mathcal{A}^{\text{uc}}$ Energy assets with unit commitment method $\mathcal{A}^{\text{uc}} \subseteq \mathcal{A}^{\text{cv}} \cup \mathcal{A}^{\text{p}}$ This set contains conversion and production assets that have a unit commitment method (unit_commitment_method in the file assets-data.csv) different from none.
$\mathcal{A}^{\text{uc basic}}$ Energy assets with a basic unit commitment method $\mathcal{A}^{\text{uc basic}} \subseteq \mathcal{A}^{\text{uc}}$ This set contains the assets that have a basic unit commitment method (unit_commitment_method = basic in the file assets-data.csv).

New expressions

For the unit commitment method, we define the following expression for the flow that is above the minimum operating point of the asset:

e^{\text{flow above min}}_{a,k,b_k} = \sum_{f \in \mathcal{F}^{\text{out}}_a} v^{\text{flow}}_{f,k,b_k} - p^{\text{availability profile}}_{a,k,b_k} \cdot p^{\text{capacity}}_{a} \cdot p^{\text{min operating point}}_{a} \cdot v^{\text{on}}_{a,k,b_k}  \quad
\\ \\ \forall a \in \mathcal{A}^{\text{uc}}, \forall k \in \mathcal{K},\forall b_k \in \mathcal{B_k}

New constraints

Limit to the units on (i.e., commitment) variable:

v^{\text{on}}_{a,k,b_k} \leq p^{\text{init units}}_{a} + v^{\text{inv}}_{a}  \quad
\\ \\ \forall a \in \mathcal{A}^{\text{uc}}, \forall k \in \mathcal{K},\forall b_k \in \mathcal{B_k}

Maximum output flow above the minimum operating point:

e^{\text{flow above min}}_{a,k,b_k} \leq p^{\text{availability profile}}_{a,k,b_k} \cdot p^{\text{capacity}}_{a} \cdot \left(1 - p^{\text{min operating point}}_{a} \right) \cdot v^{\text{on}}_{a,k,b_k}  \quad
\\ \\ \forall a \in \mathcal{A}^{\text{uc basic}}, \forall k \in \mathcal{K},\forall b_k \in \mathcal{B_k}

Minimum output flow above the minimum operating point:

e^{\text{flow above min}}_{a,k,b_k} \geq 0  \quad
\\ \\ \forall a \in \mathcal{A}^{\text{uc basic}}, \forall k \in \mathcal{K},\forall b_k \in \mathcal{B_k}

Maximum ramp-up rate limit to the flow above the operating point:

e^{\text{flow above min}}_{a,k,b_k} - e^{\text{flow above min}}_{a,k,b_k-1} \leq p^{\text{availability profile}}_{a,k,b_k} \cdot p^{\text{capacity}}_{a} \cdot p^{\text{max ramp up}}_{a} \cdot v^{\text{on}}_{a,k,b_k}  \quad
\\ \\ \forall a \in \mathcal{A}^{\text{uc basic}}, \forall k \in \mathcal{K},\forall b_k \in \mathcal{B_k}

Maximum ramp-down rate limit to the flow above the operating point:

e^{\text{flow above min}}_{a,k,b_k} - e^{\text{flow above min}}_{a,k,b_k-1} \geq - p^{\text{availability profile}}_{a,k,b_k} \cdot p^{\text{capacity}}_{a} \cdot p^{\text{max ramp down}}_{a} \cdot v^{\text{on}}_{a,k,b_k}  \quad
\\ \\ \forall a \in \mathcal{A}^{\text{uc basic}}, \forall k \in \mathcal{K},\forall b_k \in \mathcal{B_k}

Change in current constraints

The "Maximum Output Flows Limit" will only apply to the conversion and producer assets that are not in the unit commitment method:

\sum_{f \in \mathcal{F}^{\text{out}}_a} v^{\text{flow}}_{f,k,b_k} \leq p^{\text{availability profile}}_{a,k,b_k} \cdot \left(p^{\text{init capacity}}_{a} + p^{\text{capacity}}_{a} \cdot v^{\text{inv}}_{a} \right)  \quad
\\ \\ \forall a \in \left(\mathcal{A}^{\text{s}} \setminus \mathcal{A}^{\text{sb}} \right) \cup \left(\left(\mathcal{A}^{\text{p}} \cup \mathcal{A}^{\text{cv}} \right) \setminus \mathcal{A}^{\text{uc}} \right), \forall k \in \mathcal{K},\forall b_k \in \mathcal{B_k}
datejada commented 4 months ago

@g-moralesespana please review the equations above for the basic/simple unit commitment method we will implement in the model. The full list of symbols and variables is available in the documentation. Notice that for the sake of simplicity, here we don't show the flexible temporal resolution stuff (although, for this case, we defined that all the constraints will be in power, so the duration of the temporal_blocks won't affect).

datejada commented 4 months ago

Comments after review with @g-moralesespana and @gnawin.

We want to use a different method for ramping. So, we can have:

Add the duration to the ramping equation.

Add to the documentation that the basic UC + ramping allows the asset to startup up to "minimum operating point" + "ramp up capability", and for shutdown "minimum operating point" + "ramp down capability"

Try to avoid redundant constraints by checking the parameter. For example, if the ramp limit is greater than the maximum capacity - minimum capacity then you don't need the constraint.

clizbe commented 2 months ago

Is there a difference between using something like this:

if row.asset ∈ Auc
    FOO
else row.asset non-Auc
    BAR

or this:

cases = [Auc, non-Auc]
for case in cases
    FOO BAR
end

Okay while writing the question I think I figured it out. The first is if you want different logic depending on the selection. The second is you want the same logic for everyone, but with different parameters/options depending on the selection.

@abelsiqueira Is that right? (Dunno if the question even makes sense. I ran into "cases" in the intra_rp_constraints in create_model and thought maybe it could be used to apply constraints to specific assets (where we currently use a subset such as Ft or Auc).

abelsiqueira commented 2 months ago

@clizbe, yes the second snippet is the same logic for everyone.

clizbe commented 2 months ago

@datejada Is the "Limit to the units on (i.e., commitment) variable:" constraint supposed to have p_init_units or is it actually p_init_capacity?

clizbe commented 2 months ago

@datejada To use e flow above min for timeblock -1 (second term in max ramp-up rate limit) - should I create a second expression to calc this as needed or should e flow above min be stored somewhere that I can access the previous timeblock?

clizbe commented 2 months ago

We want to use a different method for ramping. So, we can have:

  • No UC, No ramping
  • No UC, Yes ramping
  • Yes UC, No ramping
  • Yes UC, Yes ramping

@datejada Does this mean I also need to add a method for ramping (not listed above)?

datejada commented 2 months ago

We want to use a different method for ramping. So, we can have:

  • No UC, No ramping
  • No UC, Yes ramping
  • Yes UC, No ramping
  • Yes UC, Yes ramping

@datejada Does this mean I also need to add a method for ramping (not listed above)?

@clizbe Correct!, it is not updated in the first part of this issue. We need something like $A^{ramp}$ for the assets with a ramp method. Then, the formulation should be updated to apply only the assets in each case. Give it a try to update the formulation, and I can review it afterwards 😉

datejada commented 2 months ago

@datejada To use e flow above min for timeblock -1 (second term in max ramp-up rate limit) - should I create a second expression to calc this as needed or should e flow above min be stored somewhere that I can access the previous timeblock?

@clizbe For the first implementation, let's assume we apply the constraint for timeblock > 1 (so we don't deal with that situation now). There are fancy ways to deal with that (e.g., cycling constraints), but the easy is to start creating the constraint after the first timeblock (so you don't have the problem of the previous one) @g-moralesespana, Do you have any extra thoughts?

datejada commented 2 months ago

@datejada Is the "Limit to the units on (i.e., commitment) variable:" constraint supposed to have p_init_units or is it actually p_init_capacity?

@clizbe Nice catch! we need to add the bound for the units on. It should be <= existing units + investment variable

where: existing units => can be determined from the parameters capacity and initial_capacity investment variable => assets_investment[a]

There are a couple of things to consider here, but we can comment on later. This is the general idea

clizbe commented 2 months ago

@datejada To use e flow above min for timeblock -1 (second term in max ramp-up rate limit) - should I create a second expression to calc this as needed or should e flow above min be stored somewhere that I can access the previous timeblock?

@clizbe For the first implementation, let's assume we apply the constraint for timeblock > 1 (so we don't deal with that situation now). There are fancy ways to deal with that (e.g., cycling constraints), but the easy is to start creating the constraint after the first timeblock (so you don't have the problem of the previous one) @g-moralesespana, Do you have any extra thoughts?

Okay! But that doesn't answer my question. Should I be calculating two parameters (t and t-1) or just one (all t) and referencing t-1? Because I think with my current implementation it's easier to calculate them separately, but maybe that's inefficient.

clizbe commented 2 months ago

@datejada Is the "Limit to the units on (i.e., commitment) variable:" constraint supposed to have p_init_units or is it actually p_init_capacity?

@clizbe Nice catch! we need to add the bound for the units on. It should be <= existing units + investment variable

where: existing units => can be determined from the parameters capacity and initial_capacity investment variable => assets_investment[a]

There are a couple of things to consider here, but we can comment on later. This is the general idea

I'm still not sure what you mean. Do we consider Units to be a subdivision of Capacity? Like there are 2 Units with 10 Capacity each so we have 20 Capacity?

datejada commented 2 months ago

@datejada To use e flow above min for timeblock -1 (second term in max ramp-up rate limit) - should I create a second expression to calc this as needed or should e flow above min be stored somewhere that I can access the previous timeblock?

@clizbe For the first implementation, let's assume we apply the constraint for timeblock > 1 (so we don't deal with that situation now). There are fancy ways to deal with that (e.g., cycling constraints), but the easy is to start creating the constraint after the first timeblock (so you don't have the problem of the previous one) @g-moralesespana, Do you have any extra thoughts?

Okay! But that doesn't answer my question. Should I be calculating two parameters (t and t-1) or just one (all t) and referencing t-1? Because I think with my current implementation it's easier to calculate them separately, but maybe that's inefficient.

So, two things here. First, you don't need a second expression, please take a look to the first constraint in the storage file https://github.com/TulipaEnergy/TulipaEnergyModel.jl/blob/main/src/constraints/storage.jl It has the structure of t-1 in the storage level. Second, to avoid and error for the first timeblock (because timeblock before t=1 does not exist) you need to write the constraint starting from the second timeblock (then the previous one, i.e., t=1, exists).

The first thing is the answer to your question; the second thing is what I thought you were asking at the beginning 😝

datejada commented 2 months ago

@datejada Is the "Limit to the units on (i.e., commitment) variable:" constraint supposed to have p_init_units or is it actually p_init_capacity?

@clizbe Nice catch! we need to add the bound for the units on. It should be <= existing units + investment variable where: existing units => can be determined from the parameters capacity and initial_capacity investment variable => assets_investment[a] There are a couple of things to consider here, but we can comment on later. This is the general idea

I'm still not sure what you mean. Do we consider Units to be a subdivision of Capacity? Like there are 2 Units with 10 Capacity each so we have 20 Capacity?

Yes, but after reading your question and looking at the input data, maybe we can change it a bit the input data to make it clearer and easier for the users. Please take a look on how is the input data for the units in INES specification. What we need is either initial units and some capacity to determine the initial capacity or some initial capacity and a capacity per unit, and then we can calculate the initial number of units. We should look at the proposal in INES and also what makes more sense for the users. I added the parameter init units in the list to check how we will define it (either calculated or direct input).

clizbe commented 2 months ago

@datejada The "flow above min operating point >= 0" constraint is for the subset Auc_basic. Does that mean the constraint only applies to Auc_basic and not (in the future) to Auc_advanced?

datejada commented 2 months ago

@datejada The "flow above min operating point >= 0" constraint is for the subset Auc_basic. Does that mean the constraint only applies to Auc_basic and not (in the future) to Auc_advanced?

We will use it in the future for the Auc_advanced, but since it is not in place yet, it is OK that it only applies to the Auc_basic for now. In the future, it will apply if any Auc method is selected.

datejada commented 1 month ago

All tasks have been completed 🚀