updated the doc with LMP and AELMP

pull/27/head
Jun He 3 years ago
parent 5c91dc2ac9
commit 415732f0ec

@ -139,3 +139,107 @@ solution = JSON.parsefile("solution.json")
# Validate solution and print validation errors
UnitCommitment.validate(instance, solution)
```
### Computing Locational Marginal Prices (LMPs)
### Conventional LMPs
The locational marginal price (LMP) refers to the cost of withdrawing one additional unit of energy at a bus. UC.jl computes the LMPs of a system using a three-step approach: (1) solving the UC model as usual, (2) fixing the values for all binary variables, and (3) re-solving the model. The LMPs are the dual variables' values associated with the net injection constraints. Step (1) is considered the pre-stage and the model must be solved before calling the `compute_lmp` method, in which Step (2) and (3) take place.
The `compute_lmp` method calculates the locational marginal prices of the given unit commitment instance. The method accepts 3 arguments, which are(1) a solved UC model, (2) an LMP method object, and (3) a linear optimizer. Note that the LMP method is a struct that inherits the abstract type `PricingMethod`. For conventional (vanilla) LMP, the method is defined under the `LMP` module and contains no fields. Thus, one only needs to specify `LMP.Method()` for the second argument. This particular method style is designed to provide users with more flexibility to design their own pricing calculation methods (see [Approximate Extended LMPs](#approximate-extended-lmps) for more details.) Finally, the last argument requires a linear optimizer. Open-source optimizers such as `Clp` and `HiGHS` can be used here, but solvers such as `Cbc` do not support dual value evaluations and should be avoided in this method. The method returns a dictionary of LMPs. Each key is usually a tuple of "Bus name" and time index. It returns nothing if there is an error in solving the LMPs. Example usage can be found below.
```julia
using UnitCommitment
using Cbc
using HiGHS
import UnitCommitment:
LMP
# Read benchmark instance
instance = UnitCommitment.read("instance.json")
# Construct model (using state-of-the-art defaults)
model = UnitCommitment.build_model(
instance = instance,
optimizer = Cbc.Optimizer,
)
# Get the LMPs before solving the UC model
# Error messages will be displayed and the returned value is nothing.
# lmp = UnitCommitment.compute_lmp(model, LMP.Method(), optimizer = HiGHS.Optimizer) # DO NOT RUN
UnitCommitment.optimize!(model)
# Get the LMPs after solving the UC model (the correct way)
# DO NOT use Cbc as the optimizer here. Cbc does not support dual values.
# Compute regular LMP
my_lmp = UnitCommitment.compute_lmp(
model,
LMP.Method(),
optimizer = HiGHS.Optimizer,
)
# Accessing the 'my_lmp' dictionary
# Example: "b1" is the bus name, 1 is the first time slot
@show my_lmp["b1", 1]
```
### Approximate Extended LMPs
UC.jl also provides an alternative method to calculate the approximate extended LMPs (AELMPs). The method is the same as the conventional name `compute_lmp` with the exception that the second argument takes the struct from the `AELMP` module. Similar to the conventional LMP, the AELMP method is a struct that inherits the abstract type `PricingMethod`. The AELMP method is defined under the `AELMP` module and contains two boolean fields: `allow_offline_participation` and `consider_startup_costs`. If `allow_offline_participation = true`, then offline generators are allowed to participate in the pricing. If instead `allow_offline_participation = false`, offline generators are not allowed and therefore are excluded from the system. A solved UC model is optional if offline participation is allowed, but is required if not allowed. The method forces offline participation to be allowed if the UC model supplied by the user is not solved. For the second field, If `consider_startup_costs = true`, then start-up costs are integrated and averaged over each unit production; otherwise the production costs stay the same. By default, both fields are set to `true`. The AELMP method can be used as an example for users to define their own pricing method.
The method calculates the approximate extended locational marginal prices of the given unit commitment instance, which modifies the instance data in 3 ways: (1) it removes the minimum generation requirement for each generator, (2) it averages the start-up cost over the offer blocks for each generator, and (3) it relaxes all the binary constraints and integrality. Similarly, the method returns a dictionary of AELMPs. Each key is usually a tuple of "Bus name" and time index.
However, this approximation method is not fully developed. The implementation is based on MISO Phase I only. It only supports fast start resources. More specifically, the minimum up/down time has to be zero. The method does not support time series of start-up costs. The method can only calculate for the first time slot if offline participation is not allowed. Example usage can be found below.
```julia
using UnitCommitment
using Cbc
using HiGHS
import UnitCommitment:
AELMP
# Read benchmark instance
instance = UnitCommitment.read("instance.json")
# Construct model (using state-of-the-art defaults)
model = UnitCommitment.build_model(
instance = instance,
optimizer = Cbc.Optimizer,
variable_names = true,
)
# Get the AELMP with the default policy:
# 1. Offline generators are allowed to participate in pricing
# 2. Start-up costs are considered.
# DO NOT use Cbc as the optimizer here. Cbc does not support dual values.
my_aelmp_default = UnitCommitment.compute_lmp(
model, # pre-solving is optional if allowing offline participation
AELMP.Method(),
optimizer = HiGHS.Optimizer
)
# Get the AELMPs with an alternative policy
# 1. Offline generators are NOT allowed to participate in pricing
# 2. Start-up costs are considered.
# UC model must be solved first if offline generators are NOT allowed
UnitCommitment.optimize!(model)
# then call the AELMP method
my_aelmp_alt = UnitCommitment.compute_lmp(
model, # pre-solving is required here
AELMP.Method(
allow_offline_participation=false,
consider_startup_costs=true
),
optimizer = HiGHS.Optimizer
)
# Accessing the 'my_aelmp_alt' dictionary
# Example: "b1" is the bus name, 1 is the first time slot
@show my_aelmp_alt["b1", 1]
```
Loading…
Cancel
Save