blue-marble / gridpath

A versatile simulation and optimization platform for power-system planning and operations.
https://www.gridpath.io
Apache License 2.0
88 stars 35 forks source link

Enforce shutdown trajectory when shutdown is initiated at the first timepoint of a subproblem with linked horizons #1111

Open sriharid opened 1 month ago

sriharid commented 1 month ago

When there are linked horizons, it is possible for a unit that is committed at the last timepoint of a previous subproblem to generate a shutdown event at the very first timepoint of the next subproblem without honouring any shutdown ramp rate (between these two timepoints) - even when such a shutdown ramp rate is specified.

In the worst case, the unit can directly reach zero generation at the at the very first timepoint of the next subproblem - from a committed state at the last timepoint of a previous subproblem.

The suggested fix for this issue is in power_during_shutdown_constraint_rule() in gen_commit_unit_common.py. This constraint is enforced between the current timepoint (i.e. the timepoint with which the function is called) and the next timepoint. This results in the first timepoint of every subproblem to be unconstrained (for this constraint) with respect to the last (non-lookahead) timepoint of the previous subproblem. The solution to this is to apply the constraint between the previous timepoint and the current timepoint instead.

The suggested implementation is consistent with that of decreasing_shutdown_power_constraint_rule(), which was fixed in #1070.

sriharid commented 1 month ago

@anamileva, if the proposed fix is okay, I can implement and submit a pull request.

anamileva commented 1 month ago

Sounds good to me, thanks @sriharid!

sriharid commented 1 week ago

@anamileva, we tried to fix the issue as described above. However, the fix requires adding a couple of params - PMin and PMax - to linked parameters. Following is the full explanation with the 3 possible scenarios, and what happens in those scenarios in the current implementation and in the proposed implementation. Please let us know if it is okay to add these two linked parameters.

Current Formulation:

Commit[CurrTP] * PMin[CurrTP] + PowerAbovePMin[CurrTP] + UpwardsReserves[CurrTP] - ShutdownPower[NextTP]
<=
(1 - Shutdown[NextTP]) * PMax[NextTP] + ShutDown[NextTP] * ShutDownRampRatePerTP[CurrTP]

There are 3 possible cases:

  1. When ShutDown[NextTP] = 1: Commit[CurrTP] = 1
PMin[CurrTP] + PowerAbovePMin[CurrTP] + UpwardsReserves[CurrTP] - ShutdownPower[NextTP]
  <= ShutDownRampRatePerTP[CurrTP]
  1. When ShutDown[NextTP] = 0:

    2a. When Commit[CurrTP] = 0: PowerAbovePMin[CurrTP] = 0

UpwardsReserves[CurrTP] - ShutdownPower[NextTP] <= PMax[NextTP] 2b. When Commit[CurrTP] = 1: Commit[NextTP] = 1 ShutdownPower[NextTP] = 0

    PMin[CurrTP] + PowerAbovePMin[CurrTP] + UpwardsReserves[CurrTP]
    <= 
    PMax[NextTP]

In the above case, the constraint is actually incorrect since PMax[NextTP] could be different from PMax[CurrTP].

Proposed Formulation

Commit[PrevTP] * PMin[PrevTP] + PowerAbovePMin[PrevTP] - ShutdownPower[CurrTP]
<=
(1 - Shutdown[CurrTP]) * (PMax[PrevTP] - UpwardsReserves[PrevTP]) + ShutDown[CurrTP] * ShutDownRampRatePerTP[PrevTP]

3 possible cases:

  1. When Shutdown[CurrTP] = 1: Commit[PrevTP] = 1
  PMin[PrevTP] + PowerAbovePMin[PrevTP] - ShutdownPower[CurrTP]
  <=
  ShutDownRampRatePerTP[PrevTP]

Above constraint is what this function is intended to implement.

  1. When Shutdown[CurrTP] = 0: 2a. When Commit[PrevTP] = 0: PowerAbovePMin[PrevTP] = 0

- ShutdownPower[CurrTP] <= PMax[PrevTP] - UpwardsReserves[PrevTP]

The constraint will not bind in this case, i.e., it will always hold true (LHS is always <=0 and RHS is always >= 0).

2b. When Commit[PrevTP] = 1: Commit[CurrTP] = 1 ShutdownPower[CurrTP] = 0

    PMin[PrevTP] + PowerAbovePMin[PrevTP]
    <=
    PMax[PrevTP] - UpwardsReserves[PrevTP]

This constraint is superfluous in this case since this is already enforced by max_power_constraint_rule.

In the above formulation, UpwardsReserves[PrevTP] is redundant, i.e., even if we don't include it in the formulation, there is no material difference to the final constraints. However, we retained it to be consistent with the rest of the constraints.

So we need the following values at the previous timepoint: Commit[PrevTP] ==> linked_commit PMin[PrevTP] PowerAbovePMin[PrevTP] ==> linked_provide_power_above_pmin PMax[PrevTP] UpwardsReserves[PrevTP] ==> linked_upward_reserves ShutDownRampRatePerTP[PrevTP] ==> linked_shutdown_ramp_rate_mw_per_tmp

If CurrTP is the first TP of a linked horizon, we need all the above 6 values from linked data. However, two of the above, that is PMin and PMax, are not written out in the linked results.

anamileva commented 1 week ago

@sriharid, yes, I don't see any issue with adding these two to the linked params. Thank you!