-
Notifications
You must be signed in to change notification settings - Fork 81
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Initial refactor of cost functions #1071
Changes from 44 commits
5818ed1
23c6e0d
f7c1aab
4f1a34a
1fc21fb
a39cff7
771b98b
779f537
f8c28fe
6a267a6
6d19398
6ed554b
ddd5d08
2d434dd
3032e2d
cdfd673
0156734
7af370b
d7ff445
44e5f1a
d9f1e1d
652d09c
d63dae6
31b848a
f0fdd47
d055875
2d82421
a292ca0
3db189b
ccd9145
187bdc0
b824da4
b114f59
5923544
28220f1
dd537cb
982861b
9346083
a25c586
a49da75
259b6cb
0afc7bc
bd1cfeb
d758391
b26d639
e8193dd
f524e21
234936e
b0f4f60
39c87fb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# PowerSystems Cost Functions | ||
|
||
PowerSystems.jl provides an extensive type hierarchy to explicitly express relationships between power production and cost. This lets the modeler represent cost functions as linear, quadratic, or piecewise input-output curves, potentially piecewise marginal heat rates, average heat rates, and more, as best fits the input data. | ||
|
||
To represent a cost for a particular [`Component`](@ref), the modeler first chooses one of the variable cost representations in the table below. Then, they wrap this [`ProductionVariableCost`](@ref) in either a [`CostCurve`](@ref) to indicate a cost in currency or in a [`FuelCurve`](@ref) to indicate a cost per unit of fuel plus a fuel cost. Finally, the user creates a domain-specific [`OperationalCost`](@ref) that contains this variable cost as well as other costs that may exist in that domain, such as a fixed cost that is always incurred when the unit is on. For instance, we may have `RenewableGenerationCost(CostCurve(TODO), 0.0)` to represent the cost of a renewable unit that produces at TODO, or `ThermalGenerationCost(; variable = FuelCurve(TODO), fixed = TODO, start_up = TODO, shut_down = TODO)` to represent the cost of a thermal unit that produces at TODO. Below, we give the options for `ProductionVariableCost`s. Information on what domain-specific cost must be provided for a given component type can be found in that component type's documentation. | ||
|
||
## Variable Cost Representations | ||
For more details, see the documentation page for each type. | ||
| Type alias | Description | Constructor parameters | Example | | ||
| --- | --- | --- | --- | | ||
| `LinearCurve` | Linear input-output curve with zero no-load cost (constant average rate) | Average/marginal rate | `LinearCurve(3.0)` | | ||
| `LinearCurve` | Linear input-output curve with nonzero no-load cost (constant marginal rate) | Marginal rate, cost at zero production | `LinearCurve(3.0, 5.0)` | | ||
| `QuadraticCurve` | Quadratic input-output curve, may have nonzero no-load cost | Quadratic, proportional, and constant terms of input-output curve | `QuadraticCurve(1.0, 1.0, 18.0)` | | ||
| `PiecewisePointCurve` | Piecewise linear curve specified by cost values at production points | Vector of (production, cost) pairs | `PiecewisePointCurve([(1.0, 20.0), (2.0, 24.0), (3.0, 30.0)])` | | ||
| `PiecewiseIncrementalCurve` | Piecewise linear curve specified by marginal rates (slopes) between production points, may have nonzero initial value | Cost at minimum production point, vector of $n$ production points, vector of $n-1$ marginal rates/slopes of the curve segments between the points | `PiecewiseIncrementalCurve(20., [1.0, 2.0, 3.0], [4.0, 6.0])` | | ||
| `PiecewiseAverageCurve` | Piecewise linear curve specified by average rates between production points, may have nonzero initial value | Cost at minimum production point, vector of $n$ production points, vector of average rates at the $n-1$ latter points | `PiecewiseAverageCurve(20., [1.0, 2.0, 3.0], [12.0, 10.0])` | |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -42,25 +42,25 @@ export PhaseShiftingTransformer | |||||
export FunctionData | ||||||
export LinearFunctionData | ||||||
export QuadraticFunctionData | ||||||
export PolynomialFunctionData | ||||||
export PiecewiseLinearPointData | ||||||
export PiecewiseLinearSlopeData | ||||||
export PiecewiseLinearData | ||||||
export PiecewiseStepData | ||||||
export get_proportional_term | ||||||
export get_quadratic_term | ||||||
export get_constant_term | ||||||
export get_coefficients | ||||||
export get_slopes | ||||||
export get_x_lengths | ||||||
export is_convex | ||||||
export get_points | ||||||
export get_x_coords | ||||||
export get_y0 | ||||||
export get_y_coords | ||||||
|
||||||
export ThreePartCost | ||||||
export TwoPartCost | ||||||
export MultiStartCost | ||||||
export MarketBidCost | ||||||
export StorageManagementCost | ||||||
export ValueCurve, InputOutputCurve, IncrementalCurve, AverageRateCurve | ||||||
export LinearCurve, QuadraticCurve | ||||||
export PiecewisePointCurve, PiecewiseIncrementalCurve, PiecewiseAverageCurve | ||||||
export ProductionVariableCost, CostCurve, FuelCurve | ||||||
export OperationalCost, MarketBidCost, LoadCost, StorageCost | ||||||
export HydroGenerationCost, RenewableGenerationCost, ThermalGenerationCost | ||||||
export get_function_data, get_initial_input, get_value_curve, get_power_units, get_fuel_cost | ||||||
|
||||||
export Generator | ||||||
export HydroGen | ||||||
|
@@ -337,6 +337,12 @@ export get_data | |||||
export iterate_components | ||||||
export get_time_series_multiple | ||||||
export get_variable_cost | ||||||
export get_no_load_cost | ||||||
export get_start_up | ||||||
export get_shut_down | ||||||
export get_incremental_offer_curves | ||||||
export get_decremental_offer_curves | ||||||
export get_ancillary_services | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||||||
export get_services_bid | ||||||
export set_variable_cost! | ||||||
export set_service_bid! | ||||||
|
@@ -448,7 +454,7 @@ import Logging | |||||
import Dates | ||||||
import TimeSeries | ||||||
import DataFrames | ||||||
import DataStructures: OrderedDict | ||||||
import DataStructures: OrderedDict, SortedDict | ||||||
import JSON3 | ||||||
import CSV | ||||||
import YAML | ||||||
|
@@ -535,19 +541,18 @@ import InfrastructureSystems: | |||||
FunctionData, | ||||||
LinearFunctionData, | ||||||
QuadraticFunctionData, | ||||||
PolynomialFunctionData, | ||||||
PiecewiseLinearPointData, | ||||||
PiecewiseLinearSlopeData, | ||||||
PiecewiseLinearData, | ||||||
PiecewiseStepData, | ||||||
get_proportional_term, | ||||||
get_quadratic_term, | ||||||
get_constant_term, | ||||||
get_coefficients, | ||||||
get_slopes, | ||||||
running_sum, | ||||||
get_x_lengths, | ||||||
is_convex, | ||||||
get_points, # TODO possible rename to disambiguate from geographical information | ||||||
get_x_coords, | ||||||
get_y0, # TODO reevaluate whether this should be exported | ||||||
get_y_coords, | ||||||
get_raw_data, | ||||||
get_raw_data_type | ||||||
|
||||||
|
@@ -590,7 +595,6 @@ include("models/static_injection_subsystem.jl") | |||||
# PowerSystems models | ||||||
include("models/topological_elements.jl") | ||||||
include("models/branches.jl") | ||||||
include("models/operational_cost.jl") | ||||||
#include("models/network.jl") | ||||||
|
||||||
# Static types | ||||||
|
@@ -603,6 +607,18 @@ include("models/dynamic_generator_components.jl") | |||||
include("models/dynamic_inverter_components.jl") | ||||||
include("models/OuterControl.jl") | ||||||
|
||||||
# Costs | ||||||
include("models/cost_functions/ValueCurves.jl") | ||||||
include("models/cost_functions/cost_aliases.jl") | ||||||
include("models/cost_functions/variable_cost.jl") | ||||||
include("models/cost_functions/operational_cost.jl") | ||||||
include("models/cost_functions/MarketBidCost.jl") | ||||||
include("models/cost_functions/HydroGenerationCost.jl") | ||||||
include("models/cost_functions/LoadCost.jl") | ||||||
include("models/cost_functions/RenewableGenerationCost.jl") | ||||||
include("models/cost_functions/StorageCost.jl") | ||||||
include("models/cost_functions/ThermalGenerationCost.jl") | ||||||
|
||||||
# Include all auto-generated structs. | ||||||
include("models/generated/includes.jl") | ||||||
include("models/regulation_device.jl") | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -90,23 +90,43 @@ function _convert_cost(points::Vector) | |
@assert all(length.(points) .== 2) | ||
@assert all([all(typeof.(point) .<: Real) for point in points]) | ||
# NOTE: old representation stored points as (y, x); new representation is (x, y) | ||
return PiecewiseLinearPointData([(x, y) for (y, x) in points]) | ||
return PiecewiseLinearData([(x, y) for (y, x) in points]) | ||
end | ||
|
||
# _convert_op_cost: take a component type, an old operational cost type, and old operational | ||
# cost data; and create the proper new operational cost struct. Some of these cost structs | ||
# no longer exist, so we dispatch instead on symbols. | ||
_convert_op_cost(::Val{:ThermalStandard}, ::Val{:ThreePartCost}, op_cost::Dict) = | ||
ThermalGenerationCost( | ||
CostCurve(InputOutputCurve(op_cost["variable"])), | ||
op_cost["fixed"], | ||
op_cost["start_up"], | ||
op_cost["shut_down"], | ||
) | ||
|
||
# TODO implement remaining _convert_op_cost methods | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this need to happen? |
||
|
||
function _convert_data!( | ||
raw::Dict{String, Any}, | ||
::Val{Symbol("3.0.0")}, | ||
::Val{Symbol("4.0.0")}, | ||
) | ||
for component in vcat(raw["data"]["components"], raw["data"]["masked_components"]) | ||
# Convert costs: all old cost structs are in fields named `operation_cost` | ||
if haskey(component, "operation_cost") | ||
op_cost = component["operation_cost"] | ||
# Step 1: insert a FunctionData | ||
if op_cost["__metadata__"]["type"] in COST_CONTAINERS && | ||
haskey(op_cost["variable"], "cost") | ||
old_cost = op_cost["variable"]["cost"] | ||
new_cost = IS.serialize(_convert_cost(old_cost)) | ||
new_cost = _convert_cost(old_cost) | ||
op_cost["variable"] = new_cost | ||
end | ||
# Step 2: convert TwoPartCost/ThreePartCost to new domain-specific cost structs | ||
comp_type = Val{Symbol(component["__metadata__"]["type"])}() | ||
op_cost_type = Val{Symbol(op_cost["__metadata__"]["type"])}() | ||
new_op_cost = IS.serialize(_convert_op_cost(comp_type, op_cost_type, op_cost)) | ||
component["operation_cost"] = new_op_cost | ||
end | ||
end | ||
end | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can the TODOs get completed?