Skip to content

Commit 3ce7468

Browse files
authored
Merge branch 'main' into rh/add_more_honduras_structs
2 parents a8fc069 + deb98f3 commit 3ce7468

File tree

4 files changed

+149
-2
lines changed

4 files changed

+149
-2
lines changed

src/PowerSystems.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,9 @@ export get_compression_settings
391391
export CompressionSettings
392392
export CompressionTypes
393393

394+
# Parsing functions
395+
export create_poly_cost
396+
394397
#export make_time_series
395398
export get_bus_numbers
396399
export get_name

src/descriptors/power_system_inputs.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,21 @@
366366
"description": "Heat required to startup from cold",
367367
"default_value": null
368368
},
369+
{
370+
"name": "heat_rate_a0",
371+
"description": "Heat rate constant term",
372+
"default_value": null
373+
},
374+
{
375+
"name": "heat_rate_a1",
376+
"description": "Heat rate proportional term",
377+
"default_value": null
378+
},
379+
{
380+
"name": "heat_rate_a2",
381+
"description": "Heat rate quadratic term",
382+
"default_value": null
383+
},
369384
{
370385
"name": "heat_rate_avg_0",
371386
"description": "Heat rate Average 0 TODO",

src/parsers/power_system_table_data.jl

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -823,8 +823,16 @@ function make_cost(
823823
) where {T <: ThermalGen}
824824
fuel_price = gen.fuel_price / 1000.0
825825

826-
cost_pairs = get_cost_pairs(gen, cost_colnames)
827-
var_cost, fixed = create_pwinc_cost(cost_pairs)
826+
# We check if there is any Quadratic or Linear Data defined. If not we fall back to create PiecewiseIncrementalCurve
827+
quadratic_fields = (gen.heat_rate_a0, gen.heat_rate_a1, gen.heat_rate_a2)
828+
829+
if any(field -> field != nothing, quadratic_fields)
830+
var_cost, fixed =
831+
create_poly_cost(gen, ["heat_rate_a0", "heat_rate_a1", "heat_rate_a2"])
832+
else
833+
cost_pairs = get_cost_pairs(gen, cost_colnames)
834+
var_cost, fixed = create_pwinc_cost(cost_pairs)
835+
end
828836

829837
startup_cost, shutdown_cost = calculate_uc_cost(data, gen, fuel_price)
830838

@@ -956,6 +964,45 @@ function create_pwl_cost(
956964
return var_cost
957965
end
958966

967+
"""
968+
create_poly_cost(gen, cost_colnames)
969+
970+
Return a Polynomial function cost based on the coeffiecients provided on gen.
971+
972+
Three supported cases,
973+
1. If three values are passed then we have data looking like: `a2 * x^2 + a1 * x + a0`,
974+
2. If `a1` and `a0` are passed then we have data looking like: `a1 * x + a0`,
975+
3. If only `a1` is passed then we have data looking like: `a1 * x`.
976+
"""
977+
function create_poly_cost(
978+
gen, cost_colnames,
979+
)
980+
fixed_cost = 0.0
981+
parse_maybe_nothing(x) = isnothing(x) ? nothing : tryparse(Float64, x)
982+
a2 = parse_maybe_nothing(getfield(gen, Symbol("heat_rate_a2")))
983+
a1 = parse_maybe_nothing(getfield(gen, Symbol("heat_rate_a1")))
984+
a0 = parse_maybe_nothing(getfield(gen, Symbol("heat_rate_a0")))
985+
986+
if !isnothing(a2) && (isnothing(a1) || isnothing(a0))
987+
throw(
988+
DataFormatError(
989+
"All coefficients must be passed if quadratic term is passed.",
990+
),
991+
)
992+
end
993+
994+
if !any(isnothing.([a2, a1, a0]))
995+
@debug "QuadraticCurve created for $(gen.name)"
996+
return QuadraticCurve(a2, a1, a0), fixed_cost
997+
end
998+
if all(isnothing.([a2, a0])) && !isnothing(a1)
999+
@debug "LinearCurve created for $(gen.name)"
1000+
return LinearCurve(a1), fixed_cost
1001+
end
1002+
@debug "LinearCurve created for $(gen.name)"
1003+
return LinearCurve(a1, a0), fixed_cost
1004+
end
1005+
9591006
function create_pwinc_cost(
9601007
cost_pairs,
9611008
)

test/test_power_system_table_data.jl

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,3 +181,85 @@ end
181181
g = get_components(ThermalStandard, sys)
182182
@test get_variable.(get_operation_cost.(g)) == get_variable.(get_operation_cost.(g))
183183
end
184+
185+
@testset "Test create_poly_cost function" begin
186+
cost_colnames = ["heat_rate_a0", "heat_rate_a1", "heat_rate_a2"]
187+
188+
# Coefficients for a CC using natural gas
189+
a2 = -0.000531607
190+
a1 = 0.060554675
191+
a0 = 8.951100118
192+
193+
# First test that return quadratic if all coefficients are provided.
194+
# We convert the coefficients to string to mimic parsing from csv
195+
example_generator = (
196+
name = "test-gen",
197+
heat_rate_a0 = string(a0),
198+
heat_rate_a1 = string(a1),
199+
heat_rate_a2 = string(a2),
200+
)
201+
cost_curve, fixed_cost = create_poly_cost(example_generator, cost_colnames)
202+
@assert cost_curve isa QuadraticCurve
203+
@assert isapprox(get_quadratic_term(cost_curve), a2, atol = 0.01)
204+
@assert isapprox(get_proportional_term(cost_curve), a1, atol = 0.01)
205+
@assert isapprox(get_constant_term(cost_curve), a0, atol = 0.01)
206+
207+
# Test return linear with both proportional and constant term
208+
example_generator = (
209+
name = "test-gen",
210+
heat_rate_a0 = string(a0),
211+
heat_rate_a1 = string(a1),
212+
heat_rate_a2 = nothing,
213+
)
214+
cost_curve, fixed_cost = create_poly_cost(example_generator, cost_colnames)
215+
@assert cost_curve isa LinearCurve
216+
@assert isapprox(get_proportional_term(cost_curve), a1, atol = 0.01)
217+
@assert isapprox(get_constant_term(cost_curve), a0, atol = 0.01)
218+
219+
# Test return linear with just proportional term
220+
example_generator = (
221+
name = "test-gen",
222+
heat_rate_a0 = nothing,
223+
heat_rate_a1 = string(a1),
224+
heat_rate_a2 = nothing,
225+
)
226+
cost_curve, fixed_cost = create_poly_cost(example_generator, cost_colnames)
227+
@assert cost_curve isa LinearCurve
228+
@assert isapprox(get_proportional_term(cost_curve), a1, atol = 0.01)
229+
230+
# Test raises error if a2 is passed but other coefficients are nothing
231+
example_generator = (
232+
name = "test-gen",
233+
heat_rate_a0 = nothing,
234+
heat_rate_a1 = nothing,
235+
heat_rate_a2 = string(a2),
236+
)
237+
@test_throws IS.DataFormatError create_poly_cost(example_generator, cost_colnames)
238+
example_generator = (
239+
name = "test-gen",
240+
heat_rate_a0 = nothing,
241+
heat_rate_a1 = string(a1),
242+
heat_rate_a2 = string(a2),
243+
)
244+
@test_throws IS.DataFormatError create_poly_cost(example_generator, cost_colnames)
245+
example_generator = (
246+
name = "test-gen",
247+
heat_rate_a0 = string(a0),
248+
heat_rate_a1 = nothing,
249+
heat_rate_a2 = string(a2),
250+
)
251+
@test_throws IS.DataFormatError create_poly_cost(example_generator, cost_colnames)
252+
253+
# Test that it works with zero proportional and constant term
254+
example_generator = (
255+
name = "test-gen",
256+
heat_rate_a0 = string(0.0),
257+
heat_rate_a1 = string(0.0),
258+
heat_rate_a2 = string(a2),
259+
)
260+
cost_curve, fixed_cost = create_poly_cost(example_generator, cost_colnames)
261+
@assert cost_curve isa QuadraticCurve
262+
@assert isapprox(get_quadratic_term(cost_curve), a2, atol = 0.01)
263+
@assert isapprox(get_proportional_term(cost_curve), 0.0, atol = 0.01)
264+
@assert isapprox(get_constant_term(cost_curve), 0.0, atol = 0.01)
265+
end

0 commit comments

Comments
 (0)