From 53355ce83b3931059fc10de400657a5c93aa5b84 Mon Sep 17 00:00:00 2001 From: Barrows Date: Wed, 12 Jun 2024 19:55:43 -0600 Subject: [PATCH 01/12] fixing tabular parser --- src/descriptors/power_system_inputs.json | 2 +- src/parsers/power_system_table_data.jl | 802 ++++++++++++----------- 2 files changed, 411 insertions(+), 393 deletions(-) diff --git a/src/descriptors/power_system_inputs.json b/src/descriptors/power_system_inputs.json index d792e398ab..bd8ede62ff 100644 --- a/src/descriptors/power_system_inputs.json +++ b/src/descriptors/power_system_inputs.json @@ -629,7 +629,7 @@ "unit": "$/MW", "name": "fixed_cost", "description": "Fixed Cost of Generation", - "default_value": null + "default_value": 0.0 }, { "unit": "$/start", diff --git a/src/parsers/power_system_table_data.jl b/src/parsers/power_system_table_data.jl index 6de6f6c6b1..39c56137d1 100644 --- a/src/parsers/power_system_table_data.jl +++ b/src/parsers/power_system_table_data.jl @@ -12,23 +12,23 @@ const INPUT_CATEGORY_NAMES = [ ] struct PowerSystemTableData base_power::Float64 - category_to_df::Dict{InputCategory, DataFrames.DataFrame} - timeseries_metadata_file::Union{String, Nothing} + category_to_df::Dict{InputCategory,DataFrames.DataFrame} + timeseries_metadata_file::Union{String,Nothing} directory::String user_descriptors::Dict descriptors::Dict - generator_mapping::Dict{NamedTuple, DataType} + generator_mapping::Dict{NamedTuple,DataType} end function PowerSystemTableData( - data::Dict{String, Any}, + data::Dict{String,Any}, directory::String, - user_descriptors::Union{String, Dict}, - descriptors::Union{String, Dict}, - generator_mapping::Union{String, Dict}; - timeseries_metadata_file = joinpath(directory, "timeseries_pointers"), + user_descriptors::Union{String,Dict}, + descriptors::Union{String,Dict}, + generator_mapping::Union{String,Dict}; + timeseries_metadata_file=joinpath(directory, "timeseries_pointers"), ) - category_to_df = Dict{InputCategory, DataFrames.DataFrame}() + category_to_df = Dict{InputCategory,DataFrames.DataFrame}() if !haskey(data, "bus") throw(DataFormatError("key 'bus' not found in input data")) @@ -103,14 +103,14 @@ function PowerSystemTableData( directory::AbstractString, base_power::Float64, user_descriptor_file::AbstractString; - descriptor_file = POWER_SYSTEM_DESCRIPTOR_FILE, - generator_mapping_file = GENERATOR_MAPPING_FILE, - timeseries_metadata_file = joinpath(directory, "timeseries_pointers"), + descriptor_file=POWER_SYSTEM_DESCRIPTOR_FILE, + generator_mapping_file=GENERATOR_MAPPING_FILE, + timeseries_metadata_file=joinpath(directory, "timeseries_pointers"), ) files = readdir(directory) REGEX_DEVICE_TYPE = r"(.*?)\.csv" REGEX_IS_FOLDER = r"^[A-Za-z]+$" - data = Dict{String, Any}() + data = Dict{String,Any}() if length(files) == 0 error("No files in the folder") @@ -123,7 +123,7 @@ function PowerSystemTableData( try if match(REGEX_IS_FOLDER, d_file) !== nothing @info "Parsing csv files in $d_file ..." - d_file_data = Dict{String, Any}() + d_file_data = Dict{String,Any}() for file in readdir(joinpath(directory, d_file)) if match(REGEX_DEVICE_TYPE, file) !== nothing @info "Parsing csv data in $file ..." @@ -162,7 +162,7 @@ function PowerSystemTableData( user_descriptor_file, descriptor_file, generator_mapping_file; - timeseries_metadata_file = timeseries_metadata_file, + timeseries_metadata_file=timeseries_metadata_file, ) end @@ -219,12 +219,12 @@ making type conversions as necessary. Refer to the PowerSystems descriptor file for field names that will be created. """ -function iterate_rows(data::PowerSystemTableData, category; na_to_nothing = true) +function iterate_rows(data::PowerSystemTableData, category; na_to_nothing=true) df = get_dataframe(data, category) field_infos = _get_field_infos(data, category, names(df)) Channel() do channel for row in eachrow(df) - obj = _read_data_row(data, row, field_infos; na_to_nothing = na_to_nothing) + obj = _read_data_row(data, row, field_infos; na_to_nothing=na_to_nothing) put!(channel, obj) end end @@ -247,17 +247,17 @@ Throws DataFormatError if time_series with multiple resolutions are detected. """ function System( data::PowerSystemTableData; - time_series_resolution = nothing, - time_series_in_memory = false, - time_series_directory = nothing, - runchecks = true, + time_series_resolution=nothing, + time_series_in_memory=false, + time_series_directory=nothing, + runchecks=true, kwargs..., ) sys = System( data.base_power; - time_series_in_memory = time_series_in_memory, - time_series_directory = time_series_directory, - runchecks = runchecks, + time_series_in_memory=time_series_in_memory, + time_series_directory=time_series_directory, + runchecks=runchecks, kwargs..., ) set_units_base_system!(sys, IS.UnitSystem.DEVICE_BASE) @@ -284,7 +284,7 @@ function System( get(kwargs, :timeseries_metadata_file, getfield(data, :timeseries_metadata_file)) if !isnothing(timeseries_metadata_file) - add_time_series!(sys, timeseries_metadata_file; resolution = time_series_resolution) + add_time_series!(sys, timeseries_metadata_file; resolution=time_series_resolution) end check(sys) @@ -312,39 +312,39 @@ function bus_csv_parser!(sys::System, data::PowerSystemTableData) bus_id = isnothing(bus.bus_id) ? ix : bus.bus_id ps_bus = ACBus(; - number = bus_id, - name = name, - bustype = bus_type, - angle = bus.angle, - magnitude = bus.voltage, - voltage_limits = voltage_limits, - base_voltage = bus.base_voltage, - area = area, - load_zone = get_component(LoadZone, sys, string(zone)), + number=bus_id, + name=name, + bustype=bus_type, + angle=bus.angle, + magnitude=bus.voltage, + voltage_limits=voltage_limits, + base_voltage=bus.base_voltage, + area=area, + load_zone=get_component(LoadZone, sys, string(zone)), ) add_component!(sys, ps_bus) # add load if the following info is nonzero if (bus.max_active_power != 0.0) || (bus.max_reactive_power != 0.0) load = PowerLoad(; - name = name, - available = true, - bus = ps_bus, - active_power = bus.active_power, - reactive_power = bus.reactive_power, - base_power = bus.base_power, - max_active_power = bus.max_active_power, - max_reactive_power = bus.max_reactive_power, + name=name, + available=true, + bus=ps_bus, + active_power=bus.active_power, + reactive_power=bus.reactive_power, + base_power=bus.base_power, + max_active_power=bus.max_active_power, + max_reactive_power=bus.max_reactive_power, ) add_component!(sys, load) end if (bus.shunt_b != 0.0) || (bus.shunt_g != 0.0) shunt = FixedAdmittance(; - name = name, - available = true, - bus = ps_bus, - Y = (bus.shunt_g + bus.shunt_b * im), + name=name, + available=true, + bus=ps_bus, + Y=(bus.shunt_g + bus.shunt_b * im), ) add_component!(sys, shunt) end @@ -373,44 +373,44 @@ function branch_csv_parser!(sys::System, data::PowerSystemTableData) if branch_type == Line b = branch.primary_shunt / 2 value = Line(; - name = name, - available = available, - active_power_flow = pf, - reactive_power_flow = qf, - arc = connection_points, - r = branch.r, - x = branch.x, - b = (from = b, to = b), - rate = branch.rate, - angle_limits = ( - min = branch.min_angle_limits, - max = branch.max_angle_limits, + name=name, + available=available, + active_power_flow=pf, + reactive_power_flow=qf, + arc=connection_points, + r=branch.r, + x=branch.x, + b=(from=b, to=b), + rate=branch.rate, + angle_limits=( + min=branch.min_angle_limits, + max=branch.max_angle_limits, ), ) elseif branch_type == Transformer2W value = Transformer2W(; - name = name, - available = available, - active_power_flow = pf, - reactive_power_flow = qf, - arc = connection_points, - r = branch.r, - x = branch.x, - primary_shunt = branch.primary_shunt, - rate = branch.rate, + name=name, + available=available, + active_power_flow=pf, + reactive_power_flow=qf, + arc=connection_points, + r=branch.r, + x=branch.x, + primary_shunt=branch.primary_shunt, + rate=branch.rate, ) elseif branch_type == TapTransformer value = TapTransformer(; - name = name, - available = available, - active_power_flow = pf, - reactive_power_flow = qf, - arc = connection_points, - r = branch.r, - x = branch.x, - primary_shunt = branch.primary_shunt, - tap = branch.tap, - rate = branch.rate, + name=name, + available=available, + active_power_flow=pf, + reactive_power_flow=qf, + arc=connection_points, + r=branch.r, + x=branch.x, + primary_shunt=branch.primary_shunt, + tap=branch.tap, + rate=branch.rate, ) elseif branch_type == PhaseShiftingTransformer # TODO create PhaseShiftingTransformer @@ -434,7 +434,7 @@ function dc_branch_csv_parser!(sys::System, data::PowerSystemTableData) elseif isnothing(dc_branch[min]) min_lim = dc_branch[max] * -1.0 end - return (min = min_lim, max = dc_branch[max]) + return (min=min_lim, max=dc_branch[max]) end for dc_branch in iterate_rows(data, InputCategory.DC_BRANCH) @@ -467,46 +467,46 @@ function dc_branch_csv_parser!(sys::System, data::PowerSystemTableData) :max_reactive_power_limit_to, ) - loss = (l0 = 0.0, l1 = dc_branch.loss) #TODO: Can we infer this from the other data?, + loss = (l0=0.0, l1=dc_branch.loss) #TODO: Can we infer this from the other data?, value = TwoTerminalHVDCLine(; - name = dc_branch.name, - available = available, - active_power_flow = dc_branch.active_power_flow, - arc = connection_points, - active_power_limits_from = activepowerlimits_from, - active_power_limits_to = activepowerlimits_to, - reactive_power_limits_from = reactivepowerlimits_from, - reactive_power_limits_to = reactivepowerlimits_to, - loss = loss, + name=dc_branch.name, + available=available, + active_power_flow=dc_branch.active_power_flow, + arc=connection_points, + active_power_limits_from=activepowerlimits_from, + active_power_limits_to=activepowerlimits_to, + reactive_power_limits_from=reactivepowerlimits_from, + reactive_power_limits_to=reactivepowerlimits_to, + loss=loss, ) else rectifier_taplimits = ( - min = dc_branch.rectifier_tap_limits_min, - max = dc_branch.rectifier_tap_limits_max, + min=dc_branch.rectifier_tap_limits_min, + max=dc_branch.rectifier_tap_limits_max, ) rectifier_xrc = dc_branch.rectifier_xrc #TODO: What is this?, rectifier_firingangle = dc_branch.rectifier_firingangle inverter_taplimits = ( - min = dc_branch.inverter_tap_limits_min, - max = dc_branch.inverter_tap_limits_max, + min=dc_branch.inverter_tap_limits_min, + max=dc_branch.inverter_tap_limits_max, ) inverter_xrc = dc_branch.inverter_xrc #TODO: What is this? inverter_firingangle = ( - min = dc_branch.inverter_firing_angle_min, - max = dc_branch.inverter_firing_angle_max, + min=dc_branch.inverter_firing_angle_min, + max=dc_branch.inverter_firing_angle_max, ) value = TwoTerminalVSCDCLine(; - name = dc_branch.name, - available = true, - active_power_flow = pf, - arc = connection_points, - rectifier_taplimits = rectifier_taplimits, - rectifier_xrc = rectifier_xrc, - rectifier_firingangle = rectifier_firingangle, - inverter_taplimits = inverter_taplimits, - inverter_xrc = inverter_xrc, - inverter_firingangle = inverter_firingangle, + name=dc_branch.name, + available=true, + active_power_flow=pf, + arc=connection_points, + rectifier_taplimits=rectifier_taplimits, + rectifier_xrc=rectifier_xrc, + rectifier_firingangle=rectifier_firingangle, + inverter_taplimits=inverter_taplimits, + inverter_xrc=inverter_xrc, + inverter_firingangle=inverter_firingangle, ) end @@ -519,10 +519,10 @@ Add generators to the System from the raw data. """ struct _HeatRateColumns - columns::Base.Iterators.Zip{Tuple{Array{Symbol, 1}, Array{Symbol, 1}}} + columns::Base.Iterators.Zip{Tuple{Array{Symbol,1},Array{Symbol,1}}} end struct _CostPointColumns - columns::Base.Iterators.Zip{Tuple{Array{Symbol, 1}, Array{Symbol, 1}}} + columns::Base.Iterators.Zip{Tuple{Array{Symbol,1},Array{Symbol,1}}} end function gen_csv_parser!(sys::System, data::PowerSystemTableData) @@ -575,13 +575,13 @@ function cache_storage(data::PowerSystemTableData) return gen_head_dict, gen_tail_dict end for s in iterate_rows(data, InputCategory.STORAGE) - if occursin("head", normalize(s.position; casefold = true)) + if occursin("head", normalize(s.position; casefold=true)) if !haskey(gen_head_dict, s.generator_name) gen_head_dict[s.generator_name] = s else throw(DataFormatError("Duplicate head storage found for gen $s")) end - elseif occursin("tail", normalize(s.position; casefold = true)) + elseif occursin("tail", normalize(s.position; casefold=true)) if !haskey(gen_tail_dict, s.generator_name) gen_tail_dict[s.generator_name] = s else @@ -610,14 +610,14 @@ function load_csv_parser!(sys::System, data::PowerSystemTableData) end load = PowerLoad(; - name = rawload.name, - available = rawload.available, - bus = bus, - active_power = rawload.active_power, - reactive_power = rawload.reactive_power, - max_active_power = rawload.max_active_power, - max_reactive_power = rawload.max_reactive_power, - base_power = rawload.base_power, + name=rawload.name, + available=rawload.available, + bus=bus, + active_power=rawload.active_power, + reactive_power=rawload.reactive_power, + max_active_power=rawload.max_active_power, + max_reactive_power=rawload.max_reactive_power, + base_power=rawload.base_power, ) add_component!(sys, load) end @@ -721,7 +721,7 @@ function services_csv_parser!(sys::System, data::PowerSystemTableData) gen.name, ) area = string( - buses[bus_ids .== get_number(get_bus(sys_gen)), bus_area_column][1], + buses[bus_ids.==get_number(get_bus(sys_gen)), bus_area_column][1], ) if gen.category in device_subcategories && area in regions _add_device!(contributing_devices, device_categories, gen.name) @@ -807,99 +807,130 @@ function make_generator(data::PowerSystemTableData, gen, cost_colnames, bus, gen return generator end -function calculate_variable_cost( - data::PowerSystemTableData, - gen, - cost_colnames::_HeatRateColumns, - base_power, -) - fuel_cost = gen.fuel_price / 1000.0 +function make_cost(::Type{T}, data, gen, cost_colnames::_HeatRateColumns) where {T<:ThermalGen} + fuel_price = gen.fuel_price / 1000.0 - vom = isnothing(gen.variable_cost) ? 0.0 : gen.variable_cost + cost_pairs = get_cost_pairs(gen, cost_colnames) + var_cost, fixed = create_pwinc_cost(cost_pairs) - if fuel_cost > 0.0 - var_cost = - [(getfield(gen, hr), getfield(gen, mw)) for (hr, mw) in cost_colnames.columns] - var_cost = unique([ - (tryparse(Float64, string(c[1])), tryparse(Float64, string(c[2]))) for - c in var_cost if !in(nothing, c) - ]) - if isempty(var_cost) - @warn "Unable to calculate variable cost for $(gen.name)" var_cost maxlog = 5 - end - else - var_cost = [(0.0, 0.0)] - end + startup_cost, shutdown_cost = calculate_uc_cost(data, gen, fuel_price) - if length(var_cost) > 1 - var_cost[2:end] = [ - ( - ( - var_cost[i][1] * fuel_cost * (var_cost[i][2] - var_cost[i - 1][2]) + - var_cost[i][2] * vom - ), - var_cost[i][2], - ) .* gen.active_power_limits_max .* base_power for i in 2:length(var_cost) - ] - var_cost[1] = - ((var_cost[1][1] * fuel_cost + vom) * var_cost[1][2], var_cost[1][2]) .* - gen.active_power_limits_max .* base_power - - fixed = max( - 0.0, - var_cost[1][1] - - (var_cost[2][1] / (var_cost[2][2] - var_cost[1][2]) * var_cost[1][2]), - ) - var_cost[1] = (var_cost[1][1] - fixed, var_cost[1][2]) + op_cost = ThermalGenerationCost( + FuelCurve(var_cost, UnitSystem.NATURAL_UNITS, fuel_price), + fixed * fuel_price, + startup_cost, + shutdown_cost, + ) + return op_cost +end + +function make_cost(::Type{T}, data, gen, cost_colnames::_CostPointColumns) where {T<:ThermalGen} + cost_pairs = get_cost_pairs(gen, cost_colnames) + var_cost = create_pwl_cost(cost_pairs) + startup_cost, shutdown_cost = calculate_uc_cost(data, gen, fuel_price) - for i in 2:length(var_cost) - var_cost[i] = (var_cost[i - 1][1] + var_cost[i][1], var_cost[i][2]) + op_cost = ThermalGenerationCost( + CostCurve(var_cost, UnitSystem.NATURAL_UNITS), + gen.fixed_cost, + startup_cost, + shutdown_cost, + ) + return op_cost +end + +function make_cost(::Type{T}, data, gen, cost_colnames::_HeatRateColumns) where {T<:HydroGen} + fuel_price = gen.fuel_price / 1000.0 + cost_pairs = get_cost_pairs(gen, cost_colnames) + var_cost, fixed = create_pwinc_cost(cost_pairs) + op_cost = HydroGenerationCost( + FuelCurve(var_cost, UnitSystem.NATURAL_UNITS, fuel_price), + fixed * fuel_price) + return op_cost +end + +function make_cost(::Type{T}, data, gen, cost_colnames::_CostPointColumns) where {T<:HydroGen} + cost_pairs = get_cost_pairs(gen, cost_colnames) + var_cost = create_pwl_cost(cost_pairs) + op_cost = HydroGenerationCost( + CostCurve(var_cost, UnitSystem.NATURAL_UNITS), + gen.fixed_cost) + return op_cost +end + +function make_cost(::Type{T}, data, gen, cost_colnames::_HeatRateColumns) where {T<:RenewableGen} + @warn "Heat rate parsing not valid for RenewableGen replacing with zero cost" + var_cost = CostCurve( + value_curve=LinearCurve(0.0), + power_units=UnitSystem.NATURAL_UNITS, + vom_cost=isnothing(gen.variable_cost) ? 0.0 : gen.variable_cost + ) + op_cost = RenewableGenerationCost(var_cost) + return op_cost +end + +function make_cost(::Type{T}, data, gen, cost_colnames::_CostPointColumns) where {T<:RenewableGen} + cost_pairs = get_cost_pairs(gen, cost_colnames) + var_cost = CostCurve( + value_curve=cost_pairs, + power_units=UnitSystem.NATURAL_UNITS, + vom_cost=isnothing(gen.variable_cost) ? 0.0 : gen.variable_cost + ) + op_cost = RenewableGenerationCost(var_cost) + return op_cost +end + +function get_cost_pairs(gen::NamedTuple, cost_colnames) + base_power = gen.base_mva * gen.active_power_limits_max + vals = [] + for (c, pt) in cost_colnames.columns + x = getfield(gen, pt) + y = getfield(gen, c) + + if !in(nothing, [x, y]) + push!(vals, + (x=tryparse(Float64, string(x)) * base_power, + y=tryparse(Float64, string(y)))) end - var_cost = PiecewiseLinearData([(x, y) for (y, x) in var_cost]) + end - elseif length(var_cost) == 1 + last_increasing_point = findfirst(x -> x < 0.0, [diff(getfield.(vals, :x))..., -Inf]) + return vals[1:last_increasing_point] +end + +function create_pwl_cost( + cost_pairs +) + if length(cost_pairs) > 1 + var_cost = PiecewisePointCurve(PiecewiseLinearData(cost_pairs)) + elseif length(cost_pairs) == 1 # if there is only one point, use it to determine the constant $/MW cost - var_cost = LinearFunctionData(var_cost[1][1] * fuel_cost + vom) - fixed = 0.0 + var_cost = LinearCurve(cost_pairs[1].y) + else + @warn "Unable to calculate variable cost for $(gen.name)" cost_pairs maxlog = 5 end - return var_cost, fixed, fuel_cost + + return var_cost end -function calculate_variable_cost( - data::PowerSystemTableData, - gen, - cost_colnames::_CostPointColumns, - base_power, +function create_pwinc_cost( + cost_pairs ) - vom = isnothing(gen.variable_cost) ? 0.0 : gen.variable_cost - - var_cost = [(getfield(gen, c), getfield(gen, mw)) for (c, mw) in cost_colnames.columns] - var_cost = unique([ - (tryparse(Float64, string(c[1])), tryparse(Float64, string(c[2]))) for - c in var_cost if !in(nothing, c) - ]) - - var_cost = [ - ( - (var_cost[i][1] + vom), - (var_cost[i][2] .* gen.active_power_limits_max .* base_power), - ) for i in 1:length(var_cost) - ] - - if length(var_cost) > 1 - fixed = max( - 0.0, - var_cost[1][1] - - (var_cost[2][1] + vom / (var_cost[2][2] - var_cost[1][2]) * var_cost[1][2]), - ) - var_cost = [(var_cost[i][1] - fixed, var_cost[i][2]) for i in 1:length(var_cost)] - var_cost = PiecewiseLinearData([(x, y) for (y, x) in var_cost]) - elseif length(var_cost) == 1 - var_cost = LinearFunctionData(var_cost[1][1]) + if length(cost_pairs) > 1 + x_points = getfield.(cost_pairs, :x) + y_points = getfield.(cost_pairs, :y) + b = y_points[1] - y_points[2] * x_points[1] + fixed = (y_points[1] - y_points[2]) * x_points[1] + + var_cost = PiecewiseIncrementalCurve(first(y_points) - b, x_points, y_points[2:end]) + elseif length(cost_pairs) == 1 + # if there is only one point, use it to determine the constant $/MW cost + var_cost = LinearCurve(cost_pairs[1].y) fixed = 0.0 + else + @warn "Unable to calculate variable cost for $(gen.name)" cost_pairs maxlog = 5 end - return var_cost, fixed, 0.0 + return var_cost, fixed end function calculate_uc_cost(data, gen, fuel_cost) @@ -923,20 +954,20 @@ function calculate_uc_cost(data, gen, fuel_cost) return startup_cost, shutdown_cost end -function make_minmaxlimits(min::Union{Nothing, Float64}, max::Union{Nothing, Float64}) +function make_minmaxlimits(min::Union{Nothing,Float64}, max::Union{Nothing,Float64}) if isnothing(min) && isnothing(max) minmax = nothing else - minmax = (min = min, max = max) + minmax = (min=min, max=max) end return minmax end function make_ramplimits( gen; - ramplimcol = :ramp_limits, - rampupcol = :ramp_up, - rampdncol = :ramp_down, + ramplimcol=:ramp_limits, + rampupcol=:ramp_up, + rampdncol=:ramp_down, ) ramp = get(gen, ramplimcol, nothing) if !isnothing(ramp) @@ -948,7 +979,7 @@ function make_ramplimits( down = get(gen, rampdncol, ramp) down = typeof(down) <: AbstractString ? tryparse(Float64, down) : down end - ramplimits = isnothing(up) && isnothing(down) ? nothing : (up = up, down = down) + ramplimits = isnothing(up) && isnothing(down) ? nothing : (up=up, down=down) return ramplimits end @@ -964,16 +995,16 @@ function make_timelimits(gen, up_column::Symbol, down_column::Symbol) if isnothing(up_time) && isnothing(down_time) nothing else - (up = up_time, down = down_time) + (up=up_time, down=down_time) end return timelimits end function make_reactive_params( gen; - powerfield = :reactive_power, - minfield = :reactive_power_limits_min, - maxfield = :reactive_power_limits_max, + powerfield=:reactive_power, + minfield=:reactive_power_limits_min, + maxfield=:reactive_power_limits_max, ) reactive_power = get(gen, powerfield, 0.0) reactive_power_limits_min = get(gen, minfield, nothing) @@ -981,10 +1012,10 @@ function make_reactive_params( if isnothing(reactive_power_limits_min) && isnothing(reactive_power_limits_max) reactive_power_limits = nothing elseif isnothing(reactive_power_limits_min) - reactive_power_limits = (min = 0.0, max = reactive_power_limits_max) + reactive_power_limits = (min=0.0, max=reactive_power_limits_max) else reactive_power_limits = - (min = reactive_power_limits_min, max = reactive_power_limits_max) + (min=reactive_power_limits_min, max=reactive_power_limits_max) end return reactive_power, reactive_power_limits end @@ -992,7 +1023,7 @@ end function make_thermal_generator(data::PowerSystemTableData, gen, cost_colnames, bus) @debug "Making ThermaStandard" _group = IS.LOG_GROUP_PARSING gen.name active_power_limits = - (min = gen.active_power_limits_min, max = gen.active_power_limits_max) + (min=gen.active_power_limits_min, max=gen.active_power_limits_max) (reactive_power, reactive_power_limits) = make_reactive_params(gen) rating = calculate_rating(active_power_limits, reactive_power_limits) ramplimits = make_ramplimits(gen) @@ -1001,15 +1032,8 @@ function make_thermal_generator(data::PowerSystemTableData, gen, cost_colnames, fuel = parse_enum_mapping(ThermalFuels, gen.fuel) base_power = gen.base_mva - var_cost, fixed, fuel_cost = - calculate_variable_cost(data, gen, cost_colnames, base_power) - startup_cost, shutdown_cost = calculate_uc_cost(data, gen, fuel_cost) - op_cost = ThermalGenerationCost( - CostCurve(InputOutputCurve(var_cost)), - fixed, - startup_cost, - shutdown_cost, - ) + + op_cost = make_cost(ThermalStandard, data, gen, cost_colnames) gen_must_run = isnothing(gen.must_run) ? false : gen.must_run if !isa(gen_must_run, Bool) @@ -1017,22 +1041,22 @@ function make_thermal_generator(data::PowerSystemTableData, gen, cost_colnames, end return ThermalStandard(; - name = gen.name, - available = gen.available, - status = gen.status_at_start, - bus = bus, - active_power = gen.active_power, - reactive_power = reactive_power, - rating = rating, - prime_mover_type = primemover, - fuel = fuel, - active_power_limits = active_power_limits, - reactive_power_limits = reactive_power_limits, - ramp_limits = ramplimits, - time_limits = timelimits, - operation_cost = op_cost, - base_power = base_power, - must_run = gen_must_run, + name=gen.name, + available=gen.available, + status=gen.status_at_start, + bus=bus, + active_power=gen.active_power, + reactive_power=reactive_power, + rating=rating, + prime_mover_type=primemover, + fuel=fuel, + active_power_limits=active_power_limits, + reactive_power_limits=reactive_power_limits, + ramp_limits=ramplimits, + time_limits=timelimits, + operation_cost=op_cost, + base_power=base_power, + must_run=gen_must_run, ) end @@ -1047,7 +1071,7 @@ function make_thermal_generator_multistart( @debug "Making ThermalMultiStart" _group = IS.LOG_GROUP_PARSING gen.name base_power = get_base_power(thermal_gen) var_cost, fixed, fuel_cost = - calculate_variable_cost(data, gen, cost_colnames, base_power) + create_pwl_cost(data, gen, cost_colnames, base_power) if var_cost isa LinearFunctionData no_load_cost = 0.0 else @@ -1066,11 +1090,11 @@ function make_thermal_generator_multistart( end lag_warm = isnothing(gen.warm_start_time) ? 0.0 : gen.warm_start_time lag_cold = isnothing(gen.cold_start_time) ? 0.0 : gen.cold_start_time - startup_timelimits = (hot = lag_hot, warm = lag_warm, cold = lag_cold) + startup_timelimits = (hot=lag_hot, warm=lag_warm, cold=lag_cold) start_types = sum(values(startup_timelimits) .> 0.0) startup_ramp = isnothing(gen.startup_ramp) ? 0.0 : gen.startup_ramp shutdown_ramp = isnothing(gen.shutdown_ramp) ? 0.0 : gen.shutdown_ramp - power_trajectory = (startup = startup_ramp, shutdown = shutdown_ramp) + power_trajectory = (startup=startup_ramp, shutdown=shutdown_ramp) hot_start_cost = isnothing(gen.hot_start_cost) ? gen.startup_cost : gen.hot_start_cost if isnothing(hot_start_cost) if hasfield(typeof(gen), :startup_heat_cold_cost) @@ -1083,7 +1107,7 @@ function make_thermal_generator_multistart( end warm_start_cost = isnothing(gen.warm_start_cost) ? START_COST : gen.hot_start_cost #TODO cold_start_cost = isnothing(gen.cold_start_cost) ? START_COST : gen.cold_start_cost - startup_cost = (hot = hot_start_cost, warm = warm_start_cost, cold = cold_start_cost) + startup_cost = (hot=hot_start_cost, warm=warm_start_cost, cold=cold_start_cost) shutdown_cost = gen.shutdown_cost if isnothing(shutdown_cost) @@ -1100,26 +1124,26 @@ function make_thermal_generator_multistart( ) return ThermalMultiStart(; - name = get_name(thermal_gen), - available = get_available(thermal_gen), - status = get_status(thermal_gen), - bus = get_bus(thermal_gen), - active_power = get_active_power(thermal_gen), - reactive_power = get_reactive_power(thermal_gen), - rating = get_rating(thermal_gen), - prime_mover_type = get_prime_mover_type(thermal_gen), - fuel = get_fuel(thermal_gen), - active_power_limits = get_active_power_limits(thermal_gen), - reactive_power_limits = get_reactive_power_limits(thermal_gen), - ramp_limits = get_ramp_limits(thermal_gen), - power_trajectory = power_trajectory, - time_limits = get_time_limits(thermal_gen), - start_time_limits = startup_timelimits, - start_types = start_types, - operation_cost = op_cost, - base_power = get_base_power(thermal_gen), - time_at_status = get_time_at_status(thermal_gen), - must_run = get_must_run(thermal_gen), + name=get_name(thermal_gen), + available=get_available(thermal_gen), + status=get_status(thermal_gen), + bus=get_bus(thermal_gen), + active_power=get_active_power(thermal_gen), + reactive_power=get_reactive_power(thermal_gen), + rating=get_rating(thermal_gen), + prime_mover_type=get_prime_mover_type(thermal_gen), + fuel=get_fuel(thermal_gen), + active_power_limits=get_active_power_limits(thermal_gen), + reactive_power_limits=get_reactive_power_limits(thermal_gen), + ramp_limits=get_ramp_limits(thermal_gen), + power_trajectory=power_trajectory, + time_limits=get_time_limits(thermal_gen), + start_time_limits=startup_timelimits, + start_types=start_types, + operation_cost=op_cost, + base_power=get_base_power(thermal_gen), + time_at_status=get_time_at_status(thermal_gen), + must_run=get_must_run(thermal_gen), ) end @@ -1133,7 +1157,7 @@ function make_hydro_generator( ) @debug "Making HydroGen" _group = IS.LOG_GROUP_PARSING gen.name active_power_limits = - (min = gen.active_power_limits_min, max = gen.active_power_limits_max) + (min=gen.active_power_limits_min, max=gen.active_power_limits_max) (reactive_power, reactive_power_limits) = make_reactive_params(gen) rating = calculate_rating(active_power_limits, reactive_power_limits) ramp_limits = make_ramplimits(gen) @@ -1153,34 +1177,31 @@ function make_hydro_generator( DataFormatError("Cannot find head storage for $(gen.name) in storage.csv"), ) end - storage = (head = head_dict[gen.name], tail = get(tail_dict, gen.name, nothing)) + storage = (head=head_dict[gen.name], tail=get(tail_dict, gen.name, nothing)) - var_cost, fixed, fuel_cost = - calculate_variable_cost(data, gen, cost_colnames, base_power) - operation_cost = - HydroGenerationCost(CostCurve(InputOutputCurve(var_cost)), fixed) + operation_cost = make_cost(HydroGen, data, gen, cost_colnames) if gen_type == HydroEnergyReservoir @debug "Creating $(gen.name) as HydroEnergyReservoir" _group = IS.LOG_GROUP_PARSING hydro_gen = HydroEnergyReservoir(; - name = gen.name, - available = gen.available, - bus = bus, - active_power = gen.active_power, - reactive_power = reactive_power, - prime_mover_type = parse_enum_mapping(PrimeMovers, gen.unit_type), - rating = rating, - active_power_limits = active_power_limits, - reactive_power_limits = reactive_power_limits, - ramp_limits = ramp_limits, - time_limits = time_limits, - operation_cost = operation_cost, - base_power = base_power, - storage_capacity = storage.head.storage_capacity, - inflow = storage.head.input_active_power_limit_max, - initial_storage = storage.head.energy_level, + name=gen.name, + available=gen.available, + bus=bus, + active_power=gen.active_power, + reactive_power=reactive_power, + prime_mover_type=parse_enum_mapping(PrimeMovers, gen.unit_type), + rating=rating, + active_power_limits=active_power_limits, + reactive_power_limits=reactive_power_limits, + ramp_limits=ramp_limits, + time_limits=time_limits, + operation_cost=operation_cost, + base_power=base_power, + storage_capacity=storage.head.storage_capacity, + inflow=storage.head.input_active_power_limit_max, + initial_storage=storage.head.energy_level, ) elseif gen_type == HydroPumpedStorage @@ -1188,75 +1209,75 @@ function make_hydro_generator( IS.LOG_GROUP_PARSING pump_active_power_limits = ( - min = gen.pump_active_power_limits_min, - max = gen.pump_active_power_limits_max, + min=gen.pump_active_power_limits_min, + max=gen.pump_active_power_limits_max, ) (pump_reactive_power, pump_reactive_power_limits) = make_reactive_params( gen; - powerfield = :pump_reactive_power, - minfield = :pump_reactive_power_limits_min, - maxfield = :pump_reactive_power_limits_max, + powerfield=:pump_reactive_power, + minfield=:pump_reactive_power_limits_min, + maxfield=:pump_reactive_power_limits_max, ) pump_rating = calculate_rating(pump_active_power_limits, pump_reactive_power_limits) pump_ramp_limits = make_ramplimits( gen; - ramplimcol = :pump_ramp_limits, - rampupcol = :pump_ramp_up, - rampdncol = :pump_ramp_down, + ramplimcol=:pump_ramp_limits, + rampupcol=:pump_ramp_up, + rampdncol=:pump_ramp_down, ) pump_time_limits = make_timelimits(gen, :pump_min_up_time, :pump_min_down_time) hydro_gen = HydroPumpedStorage(; - name = gen.name, - available = gen.available, - bus = bus, - active_power = gen.active_power, - reactive_power = reactive_power, - rating = rating, - base_power = base_power, - prime_mover_type = parse_enum_mapping(PrimeMovers, gen.unit_type), - active_power_limits = active_power_limits, - reactive_power_limits = reactive_power_limits, - ramp_limits = ramp_limits, - time_limits = time_limits, - rating_pump = pump_rating, - active_power_limits_pump = pump_active_power_limits, - reactive_power_limits_pump = pump_reactive_power_limits, - ramp_limits_pump = pump_ramp_limits, - time_limits_pump = pump_time_limits, - storage_capacity = ( - up = storage.head.storage_capacity, - down = storage.head.storage_capacity, + name=gen.name, + available=gen.available, + bus=bus, + active_power=gen.active_power, + reactive_power=reactive_power, + rating=rating, + base_power=base_power, + prime_mover_type=parse_enum_mapping(PrimeMovers, gen.unit_type), + active_power_limits=active_power_limits, + reactive_power_limits=reactive_power_limits, + ramp_limits=ramp_limits, + time_limits=time_limits, + rating_pump=pump_rating, + active_power_limits_pump=pump_active_power_limits, + reactive_power_limits_pump=pump_reactive_power_limits, + ramp_limits_pump=pump_ramp_limits, + time_limits_pump=pump_time_limits, + storage_capacity=( + up=storage.head.storage_capacity, + down=storage.head.storage_capacity, ), - inflow = storage.head.input_active_power_limit_max, - outflow = storage.tail.input_active_power_limit_max, - initial_storage = ( - up = storage.head.energy_level, - down = storage.tail.energy_level, + inflow=storage.head.input_active_power_limit_max, + outflow=storage.tail.input_active_power_limit_max, + initial_storage=( + up=storage.head.energy_level, + down=storage.tail.energy_level, ), - storage_target = ( - up = storage.head.storage_target, - down = storage.tail.storage_target, + storage_target=( + up=storage.head.storage_target, + down=storage.tail.storage_target, ), - operation_cost = operation_cost, - pump_efficiency = storage.tail.efficiency, + operation_cost=operation_cost, + pump_efficiency=storage.tail.efficiency, ) end elseif gen_type == HydroDispatch @debug "Creating $(gen.name) as HydroDispatch" _group = IS.LOG_GROUP_PARSING hydro_gen = HydroDispatch(; - name = gen.name, - available = gen.available, - bus = bus, - active_power = gen.active_power, - reactive_power = reactive_power, - rating = rating, - prime_mover_type = parse_enum_mapping(PrimeMovers, gen.unit_type), - active_power_limits = active_power_limits, - reactive_power_limits = reactive_power_limits, - ramp_limits = ramp_limits, - time_limits = time_limits, - base_power = base_power, + name=gen.name, + available=gen.available, + bus=bus, + active_power=gen.active_power, + reactive_power=reactive_power, + rating=rating, + prime_mover_type=parse_enum_mapping(PrimeMovers, gen.unit_type), + active_power_limits=active_power_limits, + reactive_power_limits=reactive_power_limits, + ramp_limits=ramp_limits, + time_limits=time_limits, + base_power=base_power, ) else error("Tabular data parser does not currently support $gen_type creation") @@ -1274,42 +1295,39 @@ function make_renewable_generator( @debug "Making RenewableGen" _group = IS.LOG_GROUP_PARSING gen.name generator = nothing active_power_limits = - (min = gen.active_power_limits_min, max = gen.active_power_limits_max) + (min=gen.active_power_limits_min, max=gen.active_power_limits_max) (reactive_power, reactive_power_limits) = make_reactive_params(gen) rating = calculate_rating(active_power_limits, reactive_power_limits) base_power = gen.base_mva - var_cost, fixed, fuel_cost = - calculate_variable_cost(data, gen, cost_colnames, base_power) - @assert fixed == 0 "RenewableGenerationCost cannot have a fixed cost, got $fixed with variable cost $varcost" - operation_cost = RenewableGenerationCost(CostCurve(InputOutputCurve(var_cost))) + operation_cost = make_cost(RenewableGen, data, gen, cost_colnames) if gen_type == RenewableDispatch @debug "Creating $(gen.name) as RenewableDispatch" _group = IS.LOG_GROUP_PARSING generator = RenewableDispatch(; - name = gen.name, - available = gen.available, - bus = bus, - active_power = gen.active_power, - reactive_power = reactive_power, - rating = rating, - prime_mover_type = parse_enum_mapping(PrimeMovers, gen.unit_type), - reactive_power_limits = reactive_power_limits, - power_factor = gen.power_factor, - operation_cost = operation_cost, - base_power = base_power, + name=gen.name, + available=gen.available, + bus=bus, + active_power=gen.active_power, + reactive_power=reactive_power, + rating=rating, + prime_mover_type=parse_enum_mapping(PrimeMovers, gen.unit_type), + reactive_power_limits=reactive_power_limits, + power_factor=gen.power_factor, + operation_cost=operation_cost, + base_power=base_power, ) elseif gen_type == RenewableFix @debug "Creating $(gen.name) as RenewableFix" _group = IS.LOG_GROUP_PARSING generator = RenewableFix(; - name = gen.name, - available = gen.available, - bus = bus, - active_power = gen.active_power, - reactive_power = reactive_power, - rating = rating, - prime_mover_type = parse_enum_mapping(PrimeMovers, gen.unit_type), - power_factor = gen.power_factor, - base_power = base_power, + name=gen.name, + available=gen.available, + bus=bus, + active_power=gen.active_power, + reactive_power=reactive_power, + rating=rating, + prime_mover_type=parse_enum_mapping(PrimeMovers, gen.unit_type), + power_factor=gen.power_factor, + base_power=base_power, ) else error("Unsupported type $gen_type") @@ -1321,44 +1339,44 @@ end function make_storage(data::PowerSystemTableData, gen, bus, storage) @debug "Making Storage" _group = IS.LOG_GROUP_PARSING storage.name state_of_charge_limits = - (min = storage.min_storage_capacity, max = storage.storage_capacity) + (min=storage.min_storage_capacity, max=storage.storage_capacity) input_active_power_limits = ( - min = storage.input_active_power_limit_min, - max = storage.input_active_power_limit_max, + min=storage.input_active_power_limit_min, + max=storage.input_active_power_limit_max, ) output_active_power_limits = ( - min = storage.output_active_power_limit_min, - max = if isnothing(storage.output_active_power_limit_max) + min=storage.output_active_power_limit_min, + max=if isnothing(storage.output_active_power_limit_max) gen.active_power_limits_max else storage.output_active_power_limit_max end, ) - efficiency = (in = storage.input_efficiency, out = storage.output_efficiency) + efficiency = (in=storage.input_efficiency, out=storage.output_efficiency) (reactive_power, reactive_power_limits) = make_reactive_params(storage) battery = EnergyReservoirStorage(; - name = gen.name, - available = storage.available, - bus = bus, - prime_mover_type = parse_enum_mapping(PrimeMovers, gen.unit_type), - storage_technology_type = StorageTech.OTHER_CHEM, - initial_energy = storage.energy_level, - state_of_charge_limits = state_of_charge_limits, - rating = storage.rating, - active_power = storage.active_power, - input_active_power_limits = input_active_power_limits, - output_active_power_limits = output_active_power_limits, - efficiency = efficiency, - reactive_power = reactive_power, - reactive_power_limits = reactive_power_limits, - base_power = storage.base_power, - operation_cost = StorageCost(), + name=gen.name, + available=storage.available, + bus=bus, + prime_mover_type=parse_enum_mapping(PrimeMovers, gen.unit_type), + storage_technology_type=StorageTech.OTHER_CHEM, + initial_energy=storage.energy_level, + state_of_charge_limits=state_of_charge_limits, + rating=storage.rating, + active_power=storage.active_power, + input_active_power_limits=input_active_power_limits, + output_active_power_limits=output_active_power_limits, + efficiency=efficiency, + reactive_power=reactive_power, + reactive_power_limits=reactive_power_limits, + base_power=storage.base_power, + operation_cost=StorageCost(), ) return battery end -const CATEGORY_STR_TO_COMPONENT = Dict{String, DataType}( +const CATEGORY_STR_TO_COMPONENT = Dict{String,DataType}( "ACBus" => ACBus, "Generator" => Generator, "Reserve" => Service, @@ -1379,7 +1397,7 @@ function _read_config_file(file_path::String) return open(file_path) do io data = YAML.load(io) # Replace keys with enums. - config_data = Dict{InputCategory, Vector}() + config_data = Dict{InputCategory,Vector}() for (key, val) in data # TODO: need to change user_descriptors.yaml to use reserve instead. if key == "reserves" @@ -1397,9 +1415,9 @@ struct _FieldInfo custom_name::String per_unit_conversion::NamedTuple{ (:From, :To, :Reference), - Tuple{UnitSystem, UnitSystem, String}, + Tuple{UnitSystem,UnitSystem,String}, } - unit_conversion::Union{NamedTuple{(:From, :To), Tuple{String, String}}, Nothing} + unit_conversion::Union{NamedTuple{(:From, :To),Tuple{String,String}},Nothing} default_value::Any # TODO unit, value ranges and options end @@ -1415,9 +1433,9 @@ function _get_field_infos(data::PowerSystemTableData, category::InputCategory, d # Cache whether PowerSystems uses a column's values as system-per-unit. # The user's descriptors indicate that the raw data is already system-per-unit or not. - per_unit = Dict{String, IS.UnitSystem}() - unit = Dict{String, Union{String, Nothing}}() - custom_names = Dict{String, String}() + per_unit = Dict{String,IS.UnitSystem}() + unit = Dict{String,Union{String,Nothing}}() + custom_names = Dict{String,String}() for descriptor in data.user_descriptors[category] custom_name = descriptor["custom_name"] if descriptor["custom_name"] in df_names @@ -1453,25 +1471,25 @@ function _get_field_infos(data::PowerSystemTableData, category::InputCategory, d end pu_conversion = ( - From = per_unit[name], - To = item_unit_system, - Reference = per_unit_reference, + From=per_unit[name], + To=item_unit_system, + Reference=per_unit_reference, ) expected_unit = get(item, "unit", nothing) if !isnothing(expected_unit) && !isnothing(unit[name]) && expected_unit != unit[name] - unit_conversion = (From = unit[name], To = expected_unit) + unit_conversion = (From=unit[name], To=expected_unit) else unit_conversion = nothing end else custom_name = name pu_conversion = ( - From = item_unit_system, - To = item_unit_system, - Reference = per_unit_reference, + From=item_unit_system, + To=item_unit_system, + Reference=per_unit_reference, ) unit_conversion = nothing end @@ -1486,7 +1504,7 @@ function _get_field_infos(data::PowerSystemTableData, category::InputCategory, d end """Reads values from dataframe row and performs necessary conversions.""" -function _read_data_row(data::PowerSystemTableData, row, field_infos; na_to_nothing = true) +function _read_data_row(data::PowerSystemTableData, row, field_infos; na_to_nothing=true) fields = Vector{String}() vals = Vector() for field_info in field_infos From ee29416bdcfed444b0bedb415b620abb273f0fe3 Mon Sep 17 00:00:00 2001 From: Barrows Date: Wed, 12 Jun 2024 20:05:33 -0600 Subject: [PATCH 02/12] whitespace --- src/parsers/power_system_table_data.jl | 656 +++++++++++++------------ 1 file changed, 343 insertions(+), 313 deletions(-) diff --git a/src/parsers/power_system_table_data.jl b/src/parsers/power_system_table_data.jl index 39c56137d1..de2a0f369e 100644 --- a/src/parsers/power_system_table_data.jl +++ b/src/parsers/power_system_table_data.jl @@ -12,23 +12,23 @@ const INPUT_CATEGORY_NAMES = [ ] struct PowerSystemTableData base_power::Float64 - category_to_df::Dict{InputCategory,DataFrames.DataFrame} - timeseries_metadata_file::Union{String,Nothing} + category_to_df::Dict{InputCategory, DataFrames.DataFrame} + timeseries_metadata_file::Union{String, Nothing} directory::String user_descriptors::Dict descriptors::Dict - generator_mapping::Dict{NamedTuple,DataType} + generator_mapping::Dict{NamedTuple, DataType} end function PowerSystemTableData( - data::Dict{String,Any}, + data::Dict{String, Any}, directory::String, - user_descriptors::Union{String,Dict}, - descriptors::Union{String,Dict}, - generator_mapping::Union{String,Dict}; - timeseries_metadata_file=joinpath(directory, "timeseries_pointers"), + user_descriptors::Union{String, Dict}, + descriptors::Union{String, Dict}, + generator_mapping::Union{String, Dict}; + timeseries_metadata_file = joinpath(directory, "timeseries_pointers"), ) - category_to_df = Dict{InputCategory,DataFrames.DataFrame}() + category_to_df = Dict{InputCategory, DataFrames.DataFrame}() if !haskey(data, "bus") throw(DataFormatError("key 'bus' not found in input data")) @@ -103,14 +103,14 @@ function PowerSystemTableData( directory::AbstractString, base_power::Float64, user_descriptor_file::AbstractString; - descriptor_file=POWER_SYSTEM_DESCRIPTOR_FILE, - generator_mapping_file=GENERATOR_MAPPING_FILE, - timeseries_metadata_file=joinpath(directory, "timeseries_pointers"), + descriptor_file = POWER_SYSTEM_DESCRIPTOR_FILE, + generator_mapping_file = GENERATOR_MAPPING_FILE, + timeseries_metadata_file = joinpath(directory, "timeseries_pointers"), ) files = readdir(directory) REGEX_DEVICE_TYPE = r"(.*?)\.csv" REGEX_IS_FOLDER = r"^[A-Za-z]+$" - data = Dict{String,Any}() + data = Dict{String, Any}() if length(files) == 0 error("No files in the folder") @@ -123,7 +123,7 @@ function PowerSystemTableData( try if match(REGEX_IS_FOLDER, d_file) !== nothing @info "Parsing csv files in $d_file ..." - d_file_data = Dict{String,Any}() + d_file_data = Dict{String, Any}() for file in readdir(joinpath(directory, d_file)) if match(REGEX_DEVICE_TYPE, file) !== nothing @info "Parsing csv data in $file ..." @@ -162,7 +162,7 @@ function PowerSystemTableData( user_descriptor_file, descriptor_file, generator_mapping_file; - timeseries_metadata_file=timeseries_metadata_file, + timeseries_metadata_file = timeseries_metadata_file, ) end @@ -219,12 +219,12 @@ making type conversions as necessary. Refer to the PowerSystems descriptor file for field names that will be created. """ -function iterate_rows(data::PowerSystemTableData, category; na_to_nothing=true) +function iterate_rows(data::PowerSystemTableData, category; na_to_nothing = true) df = get_dataframe(data, category) field_infos = _get_field_infos(data, category, names(df)) Channel() do channel for row in eachrow(df) - obj = _read_data_row(data, row, field_infos; na_to_nothing=na_to_nothing) + obj = _read_data_row(data, row, field_infos; na_to_nothing = na_to_nothing) put!(channel, obj) end end @@ -247,17 +247,17 @@ Throws DataFormatError if time_series with multiple resolutions are detected. """ function System( data::PowerSystemTableData; - time_series_resolution=nothing, - time_series_in_memory=false, - time_series_directory=nothing, - runchecks=true, + time_series_resolution = nothing, + time_series_in_memory = false, + time_series_directory = nothing, + runchecks = true, kwargs..., ) sys = System( data.base_power; - time_series_in_memory=time_series_in_memory, - time_series_directory=time_series_directory, - runchecks=runchecks, + time_series_in_memory = time_series_in_memory, + time_series_directory = time_series_directory, + runchecks = runchecks, kwargs..., ) set_units_base_system!(sys, IS.UnitSystem.DEVICE_BASE) @@ -284,7 +284,7 @@ function System( get(kwargs, :timeseries_metadata_file, getfield(data, :timeseries_metadata_file)) if !isnothing(timeseries_metadata_file) - add_time_series!(sys, timeseries_metadata_file; resolution=time_series_resolution) + add_time_series!(sys, timeseries_metadata_file; resolution = time_series_resolution) end check(sys) @@ -312,39 +312,39 @@ function bus_csv_parser!(sys::System, data::PowerSystemTableData) bus_id = isnothing(bus.bus_id) ? ix : bus.bus_id ps_bus = ACBus(; - number=bus_id, - name=name, - bustype=bus_type, - angle=bus.angle, - magnitude=bus.voltage, - voltage_limits=voltage_limits, - base_voltage=bus.base_voltage, - area=area, - load_zone=get_component(LoadZone, sys, string(zone)), + number = bus_id, + name = name, + bustype = bus_type, + angle = bus.angle, + magnitude = bus.voltage, + voltage_limits = voltage_limits, + base_voltage = bus.base_voltage, + area = area, + load_zone = get_component(LoadZone, sys, string(zone)), ) add_component!(sys, ps_bus) # add load if the following info is nonzero if (bus.max_active_power != 0.0) || (bus.max_reactive_power != 0.0) load = PowerLoad(; - name=name, - available=true, - bus=ps_bus, - active_power=bus.active_power, - reactive_power=bus.reactive_power, - base_power=bus.base_power, - max_active_power=bus.max_active_power, - max_reactive_power=bus.max_reactive_power, + name = name, + available = true, + bus = ps_bus, + active_power = bus.active_power, + reactive_power = bus.reactive_power, + base_power = bus.base_power, + max_active_power = bus.max_active_power, + max_reactive_power = bus.max_reactive_power, ) add_component!(sys, load) end if (bus.shunt_b != 0.0) || (bus.shunt_g != 0.0) shunt = FixedAdmittance(; - name=name, - available=true, - bus=ps_bus, - Y=(bus.shunt_g + bus.shunt_b * im), + name = name, + available = true, + bus = ps_bus, + Y = (bus.shunt_g + bus.shunt_b * im), ) add_component!(sys, shunt) end @@ -373,44 +373,44 @@ function branch_csv_parser!(sys::System, data::PowerSystemTableData) if branch_type == Line b = branch.primary_shunt / 2 value = Line(; - name=name, - available=available, - active_power_flow=pf, - reactive_power_flow=qf, - arc=connection_points, - r=branch.r, - x=branch.x, - b=(from=b, to=b), - rate=branch.rate, - angle_limits=( - min=branch.min_angle_limits, - max=branch.max_angle_limits, + name = name, + available = available, + active_power_flow = pf, + reactive_power_flow = qf, + arc = connection_points, + r = branch.r, + x = branch.x, + b = (from = b, to = b), + rate = branch.rate, + angle_limits = ( + min = branch.min_angle_limits, + max = branch.max_angle_limits, ), ) elseif branch_type == Transformer2W value = Transformer2W(; - name=name, - available=available, - active_power_flow=pf, - reactive_power_flow=qf, - arc=connection_points, - r=branch.r, - x=branch.x, - primary_shunt=branch.primary_shunt, - rate=branch.rate, + name = name, + available = available, + active_power_flow = pf, + reactive_power_flow = qf, + arc = connection_points, + r = branch.r, + x = branch.x, + primary_shunt = branch.primary_shunt, + rate = branch.rate, ) elseif branch_type == TapTransformer value = TapTransformer(; - name=name, - available=available, - active_power_flow=pf, - reactive_power_flow=qf, - arc=connection_points, - r=branch.r, - x=branch.x, - primary_shunt=branch.primary_shunt, - tap=branch.tap, - rate=branch.rate, + name = name, + available = available, + active_power_flow = pf, + reactive_power_flow = qf, + arc = connection_points, + r = branch.r, + x = branch.x, + primary_shunt = branch.primary_shunt, + tap = branch.tap, + rate = branch.rate, ) elseif branch_type == PhaseShiftingTransformer # TODO create PhaseShiftingTransformer @@ -434,7 +434,7 @@ function dc_branch_csv_parser!(sys::System, data::PowerSystemTableData) elseif isnothing(dc_branch[min]) min_lim = dc_branch[max] * -1.0 end - return (min=min_lim, max=dc_branch[max]) + return (min = min_lim, max = dc_branch[max]) end for dc_branch in iterate_rows(data, InputCategory.DC_BRANCH) @@ -467,46 +467,46 @@ function dc_branch_csv_parser!(sys::System, data::PowerSystemTableData) :max_reactive_power_limit_to, ) - loss = (l0=0.0, l1=dc_branch.loss) #TODO: Can we infer this from the other data?, + loss = (l0 = 0.0, l1 = dc_branch.loss) #TODO: Can we infer this from the other data?, value = TwoTerminalHVDCLine(; - name=dc_branch.name, - available=available, - active_power_flow=dc_branch.active_power_flow, - arc=connection_points, - active_power_limits_from=activepowerlimits_from, - active_power_limits_to=activepowerlimits_to, - reactive_power_limits_from=reactivepowerlimits_from, - reactive_power_limits_to=reactivepowerlimits_to, - loss=loss, + name = dc_branch.name, + available = available, + active_power_flow = dc_branch.active_power_flow, + arc = connection_points, + active_power_limits_from = activepowerlimits_from, + active_power_limits_to = activepowerlimits_to, + reactive_power_limits_from = reactivepowerlimits_from, + reactive_power_limits_to = reactivepowerlimits_to, + loss = loss, ) else rectifier_taplimits = ( - min=dc_branch.rectifier_tap_limits_min, - max=dc_branch.rectifier_tap_limits_max, + min = dc_branch.rectifier_tap_limits_min, + max = dc_branch.rectifier_tap_limits_max, ) rectifier_xrc = dc_branch.rectifier_xrc #TODO: What is this?, rectifier_firingangle = dc_branch.rectifier_firingangle inverter_taplimits = ( - min=dc_branch.inverter_tap_limits_min, - max=dc_branch.inverter_tap_limits_max, + min = dc_branch.inverter_tap_limits_min, + max = dc_branch.inverter_tap_limits_max, ) inverter_xrc = dc_branch.inverter_xrc #TODO: What is this? inverter_firingangle = ( - min=dc_branch.inverter_firing_angle_min, - max=dc_branch.inverter_firing_angle_max, + min = dc_branch.inverter_firing_angle_min, + max = dc_branch.inverter_firing_angle_max, ) value = TwoTerminalVSCDCLine(; - name=dc_branch.name, - available=true, - active_power_flow=pf, - arc=connection_points, - rectifier_taplimits=rectifier_taplimits, - rectifier_xrc=rectifier_xrc, - rectifier_firingangle=rectifier_firingangle, - inverter_taplimits=inverter_taplimits, - inverter_xrc=inverter_xrc, - inverter_firingangle=inverter_firingangle, + name = dc_branch.name, + available = true, + active_power_flow = pf, + arc = connection_points, + rectifier_taplimits = rectifier_taplimits, + rectifier_xrc = rectifier_xrc, + rectifier_firingangle = rectifier_firingangle, + inverter_taplimits = inverter_taplimits, + inverter_xrc = inverter_xrc, + inverter_firingangle = inverter_firingangle, ) end @@ -519,10 +519,10 @@ Add generators to the System from the raw data. """ struct _HeatRateColumns - columns::Base.Iterators.Zip{Tuple{Array{Symbol,1},Array{Symbol,1}}} + columns::Base.Iterators.Zip{Tuple{Array{Symbol, 1}, Array{Symbol, 1}}} end struct _CostPointColumns - columns::Base.Iterators.Zip{Tuple{Array{Symbol,1},Array{Symbol,1}}} + columns::Base.Iterators.Zip{Tuple{Array{Symbol, 1}, Array{Symbol, 1}}} end function gen_csv_parser!(sys::System, data::PowerSystemTableData) @@ -575,13 +575,13 @@ function cache_storage(data::PowerSystemTableData) return gen_head_dict, gen_tail_dict end for s in iterate_rows(data, InputCategory.STORAGE) - if occursin("head", normalize(s.position; casefold=true)) + if occursin("head", normalize(s.position; casefold = true)) if !haskey(gen_head_dict, s.generator_name) gen_head_dict[s.generator_name] = s else throw(DataFormatError("Duplicate head storage found for gen $s")) end - elseif occursin("tail", normalize(s.position; casefold=true)) + elseif occursin("tail", normalize(s.position; casefold = true)) if !haskey(gen_tail_dict, s.generator_name) gen_tail_dict[s.generator_name] = s else @@ -610,14 +610,14 @@ function load_csv_parser!(sys::System, data::PowerSystemTableData) end load = PowerLoad(; - name=rawload.name, - available=rawload.available, - bus=bus, - active_power=rawload.active_power, - reactive_power=rawload.reactive_power, - max_active_power=rawload.max_active_power, - max_reactive_power=rawload.max_reactive_power, - base_power=rawload.base_power, + name = rawload.name, + available = rawload.available, + bus = bus, + active_power = rawload.active_power, + reactive_power = rawload.reactive_power, + max_active_power = rawload.max_active_power, + max_reactive_power = rawload.max_reactive_power, + base_power = rawload.base_power, ) add_component!(sys, load) end @@ -721,7 +721,7 @@ function services_csv_parser!(sys::System, data::PowerSystemTableData) gen.name, ) area = string( - buses[bus_ids.==get_number(get_bus(sys_gen)), bus_area_column][1], + buses[bus_ids .== get_number(get_bus(sys_gen)), bus_area_column][1], ) if gen.category in device_subcategories && area in regions _add_device!(contributing_devices, device_categories, gen.name) @@ -807,7 +807,12 @@ function make_generator(data::PowerSystemTableData, gen, cost_colnames, bus, gen return generator end -function make_cost(::Type{T}, data, gen, cost_colnames::_HeatRateColumns) where {T<:ThermalGen} +function make_cost( + ::Type{T}, + data, + gen, + cost_colnames::_HeatRateColumns, +) where {T <: ThermalGen} fuel_price = gen.fuel_price / 1000.0 cost_pairs = get_cost_pairs(gen, cost_colnames) @@ -824,7 +829,12 @@ function make_cost(::Type{T}, data, gen, cost_colnames::_HeatRateColumns) where return op_cost end -function make_cost(::Type{T}, data, gen, cost_colnames::_CostPointColumns) where {T<:ThermalGen} +function make_cost( + ::Type{T}, + data, + gen, + cost_colnames::_CostPointColumns, +) where {T <: ThermalGen} cost_pairs = get_cost_pairs(gen, cost_colnames) var_cost = create_pwl_cost(cost_pairs) startup_cost, shutdown_cost = calculate_uc_cost(data, gen, fuel_price) @@ -838,7 +848,12 @@ function make_cost(::Type{T}, data, gen, cost_colnames::_CostPointColumns) where return op_cost end -function make_cost(::Type{T}, data, gen, cost_colnames::_HeatRateColumns) where {T<:HydroGen} +function make_cost( + ::Type{T}, + data, + gen, + cost_colnames::_HeatRateColumns, +) where {T <: HydroGen} fuel_price = gen.fuel_price / 1000.0 cost_pairs = get_cost_pairs(gen, cost_colnames) var_cost, fixed = create_pwinc_cost(cost_pairs) @@ -848,7 +863,12 @@ function make_cost(::Type{T}, data, gen, cost_colnames::_HeatRateColumns) where return op_cost end -function make_cost(::Type{T}, data, gen, cost_colnames::_CostPointColumns) where {T<:HydroGen} +function make_cost( + ::Type{T}, + data, + gen, + cost_colnames::_CostPointColumns, +) where {T <: HydroGen} cost_pairs = get_cost_pairs(gen, cost_colnames) var_cost = create_pwl_cost(cost_pairs) op_cost = HydroGenerationCost( @@ -857,23 +877,33 @@ function make_cost(::Type{T}, data, gen, cost_colnames::_CostPointColumns) where return op_cost end -function make_cost(::Type{T}, data, gen, cost_colnames::_HeatRateColumns) where {T<:RenewableGen} +function make_cost( + ::Type{T}, + data, + gen, + cost_colnames::_HeatRateColumns, +) where {T <: RenewableGen} @warn "Heat rate parsing not valid for RenewableGen replacing with zero cost" - var_cost = CostCurve( - value_curve=LinearCurve(0.0), - power_units=UnitSystem.NATURAL_UNITS, - vom_cost=isnothing(gen.variable_cost) ? 0.0 : gen.variable_cost + var_cost = CostCurve(; + value_curve = LinearCurve(0.0), + power_units = UnitSystem.NATURAL_UNITS, + vom_cost = isnothing(gen.variable_cost) ? 0.0 : gen.variable_cost, ) op_cost = RenewableGenerationCost(var_cost) return op_cost end -function make_cost(::Type{T}, data, gen, cost_colnames::_CostPointColumns) where {T<:RenewableGen} +function make_cost( + ::Type{T}, + data, + gen, + cost_colnames::_CostPointColumns, +) where {T <: RenewableGen} cost_pairs = get_cost_pairs(gen, cost_colnames) - var_cost = CostCurve( - value_curve=cost_pairs, - power_units=UnitSystem.NATURAL_UNITS, - vom_cost=isnothing(gen.variable_cost) ? 0.0 : gen.variable_cost + var_cost = CostCurve(; + value_curve = cost_pairs, + power_units = UnitSystem.NATURAL_UNITS, + vom_cost = isnothing(gen.variable_cost) ? 0.0 : gen.variable_cost, ) op_cost = RenewableGenerationCost(var_cost) return op_cost @@ -888,8 +918,8 @@ function get_cost_pairs(gen::NamedTuple, cost_colnames) if !in(nothing, [x, y]) push!(vals, - (x=tryparse(Float64, string(x)) * base_power, - y=tryparse(Float64, string(y)))) + (x = tryparse(Float64, string(x)) * base_power, + y = tryparse(Float64, string(y)))) end end @@ -898,7 +928,7 @@ function get_cost_pairs(gen::NamedTuple, cost_colnames) end function create_pwl_cost( - cost_pairs + cost_pairs, ) if length(cost_pairs) > 1 var_cost = PiecewisePointCurve(PiecewiseLinearData(cost_pairs)) @@ -913,7 +943,7 @@ function create_pwl_cost( end function create_pwinc_cost( - cost_pairs + cost_pairs, ) if length(cost_pairs) > 1 x_points = getfield.(cost_pairs, :x) @@ -954,20 +984,20 @@ function calculate_uc_cost(data, gen, fuel_cost) return startup_cost, shutdown_cost end -function make_minmaxlimits(min::Union{Nothing,Float64}, max::Union{Nothing,Float64}) +function make_minmaxlimits(min::Union{Nothing, Float64}, max::Union{Nothing, Float64}) if isnothing(min) && isnothing(max) minmax = nothing else - minmax = (min=min, max=max) + minmax = (min = min, max = max) end return minmax end function make_ramplimits( gen; - ramplimcol=:ramp_limits, - rampupcol=:ramp_up, - rampdncol=:ramp_down, + ramplimcol = :ramp_limits, + rampupcol = :ramp_up, + rampdncol = :ramp_down, ) ramp = get(gen, ramplimcol, nothing) if !isnothing(ramp) @@ -979,7 +1009,7 @@ function make_ramplimits( down = get(gen, rampdncol, ramp) down = typeof(down) <: AbstractString ? tryparse(Float64, down) : down end - ramplimits = isnothing(up) && isnothing(down) ? nothing : (up=up, down=down) + ramplimits = isnothing(up) && isnothing(down) ? nothing : (up = up, down = down) return ramplimits end @@ -995,16 +1025,16 @@ function make_timelimits(gen, up_column::Symbol, down_column::Symbol) if isnothing(up_time) && isnothing(down_time) nothing else - (up=up_time, down=down_time) + (up = up_time, down = down_time) end return timelimits end function make_reactive_params( gen; - powerfield=:reactive_power, - minfield=:reactive_power_limits_min, - maxfield=:reactive_power_limits_max, + powerfield = :reactive_power, + minfield = :reactive_power_limits_min, + maxfield = :reactive_power_limits_max, ) reactive_power = get(gen, powerfield, 0.0) reactive_power_limits_min = get(gen, minfield, nothing) @@ -1012,10 +1042,10 @@ function make_reactive_params( if isnothing(reactive_power_limits_min) && isnothing(reactive_power_limits_max) reactive_power_limits = nothing elseif isnothing(reactive_power_limits_min) - reactive_power_limits = (min=0.0, max=reactive_power_limits_max) + reactive_power_limits = (min = 0.0, max = reactive_power_limits_max) else reactive_power_limits = - (min=reactive_power_limits_min, max=reactive_power_limits_max) + (min = reactive_power_limits_min, max = reactive_power_limits_max) end return reactive_power, reactive_power_limits end @@ -1023,7 +1053,7 @@ end function make_thermal_generator(data::PowerSystemTableData, gen, cost_colnames, bus) @debug "Making ThermaStandard" _group = IS.LOG_GROUP_PARSING gen.name active_power_limits = - (min=gen.active_power_limits_min, max=gen.active_power_limits_max) + (min = gen.active_power_limits_min, max = gen.active_power_limits_max) (reactive_power, reactive_power_limits) = make_reactive_params(gen) rating = calculate_rating(active_power_limits, reactive_power_limits) ramplimits = make_ramplimits(gen) @@ -1041,22 +1071,22 @@ function make_thermal_generator(data::PowerSystemTableData, gen, cost_colnames, end return ThermalStandard(; - name=gen.name, - available=gen.available, - status=gen.status_at_start, - bus=bus, - active_power=gen.active_power, - reactive_power=reactive_power, - rating=rating, - prime_mover_type=primemover, - fuel=fuel, - active_power_limits=active_power_limits, - reactive_power_limits=reactive_power_limits, - ramp_limits=ramplimits, - time_limits=timelimits, - operation_cost=op_cost, - base_power=base_power, - must_run=gen_must_run, + name = gen.name, + available = gen.available, + status = gen.status_at_start, + bus = bus, + active_power = gen.active_power, + reactive_power = reactive_power, + rating = rating, + prime_mover_type = primemover, + fuel = fuel, + active_power_limits = active_power_limits, + reactive_power_limits = reactive_power_limits, + ramp_limits = ramplimits, + time_limits = timelimits, + operation_cost = op_cost, + base_power = base_power, + must_run = gen_must_run, ) end @@ -1090,11 +1120,11 @@ function make_thermal_generator_multistart( end lag_warm = isnothing(gen.warm_start_time) ? 0.0 : gen.warm_start_time lag_cold = isnothing(gen.cold_start_time) ? 0.0 : gen.cold_start_time - startup_timelimits = (hot=lag_hot, warm=lag_warm, cold=lag_cold) + startup_timelimits = (hot = lag_hot, warm = lag_warm, cold = lag_cold) start_types = sum(values(startup_timelimits) .> 0.0) startup_ramp = isnothing(gen.startup_ramp) ? 0.0 : gen.startup_ramp shutdown_ramp = isnothing(gen.shutdown_ramp) ? 0.0 : gen.shutdown_ramp - power_trajectory = (startup=startup_ramp, shutdown=shutdown_ramp) + power_trajectory = (startup = startup_ramp, shutdown = shutdown_ramp) hot_start_cost = isnothing(gen.hot_start_cost) ? gen.startup_cost : gen.hot_start_cost if isnothing(hot_start_cost) if hasfield(typeof(gen), :startup_heat_cold_cost) @@ -1107,7 +1137,7 @@ function make_thermal_generator_multistart( end warm_start_cost = isnothing(gen.warm_start_cost) ? START_COST : gen.hot_start_cost #TODO cold_start_cost = isnothing(gen.cold_start_cost) ? START_COST : gen.cold_start_cost - startup_cost = (hot=hot_start_cost, warm=warm_start_cost, cold=cold_start_cost) + startup_cost = (hot = hot_start_cost, warm = warm_start_cost, cold = cold_start_cost) shutdown_cost = gen.shutdown_cost if isnothing(shutdown_cost) @@ -1124,26 +1154,26 @@ function make_thermal_generator_multistart( ) return ThermalMultiStart(; - name=get_name(thermal_gen), - available=get_available(thermal_gen), - status=get_status(thermal_gen), - bus=get_bus(thermal_gen), - active_power=get_active_power(thermal_gen), - reactive_power=get_reactive_power(thermal_gen), - rating=get_rating(thermal_gen), - prime_mover_type=get_prime_mover_type(thermal_gen), - fuel=get_fuel(thermal_gen), - active_power_limits=get_active_power_limits(thermal_gen), - reactive_power_limits=get_reactive_power_limits(thermal_gen), - ramp_limits=get_ramp_limits(thermal_gen), - power_trajectory=power_trajectory, - time_limits=get_time_limits(thermal_gen), - start_time_limits=startup_timelimits, - start_types=start_types, - operation_cost=op_cost, - base_power=get_base_power(thermal_gen), - time_at_status=get_time_at_status(thermal_gen), - must_run=get_must_run(thermal_gen), + name = get_name(thermal_gen), + available = get_available(thermal_gen), + status = get_status(thermal_gen), + bus = get_bus(thermal_gen), + active_power = get_active_power(thermal_gen), + reactive_power = get_reactive_power(thermal_gen), + rating = get_rating(thermal_gen), + prime_mover_type = get_prime_mover_type(thermal_gen), + fuel = get_fuel(thermal_gen), + active_power_limits = get_active_power_limits(thermal_gen), + reactive_power_limits = get_reactive_power_limits(thermal_gen), + ramp_limits = get_ramp_limits(thermal_gen), + power_trajectory = power_trajectory, + time_limits = get_time_limits(thermal_gen), + start_time_limits = startup_timelimits, + start_types = start_types, + operation_cost = op_cost, + base_power = get_base_power(thermal_gen), + time_at_status = get_time_at_status(thermal_gen), + must_run = get_must_run(thermal_gen), ) end @@ -1157,7 +1187,7 @@ function make_hydro_generator( ) @debug "Making HydroGen" _group = IS.LOG_GROUP_PARSING gen.name active_power_limits = - (min=gen.active_power_limits_min, max=gen.active_power_limits_max) + (min = gen.active_power_limits_min, max = gen.active_power_limits_max) (reactive_power, reactive_power_limits) = make_reactive_params(gen) rating = calculate_rating(active_power_limits, reactive_power_limits) ramp_limits = make_ramplimits(gen) @@ -1177,7 +1207,7 @@ function make_hydro_generator( DataFormatError("Cannot find head storage for $(gen.name) in storage.csv"), ) end - storage = (head=head_dict[gen.name], tail=get(tail_dict, gen.name, nothing)) + storage = (head = head_dict[gen.name], tail = get(tail_dict, gen.name, nothing)) operation_cost = make_cost(HydroGen, data, gen, cost_colnames) @@ -1186,22 +1216,22 @@ function make_hydro_generator( IS.LOG_GROUP_PARSING hydro_gen = HydroEnergyReservoir(; - name=gen.name, - available=gen.available, - bus=bus, - active_power=gen.active_power, - reactive_power=reactive_power, - prime_mover_type=parse_enum_mapping(PrimeMovers, gen.unit_type), - rating=rating, - active_power_limits=active_power_limits, - reactive_power_limits=reactive_power_limits, - ramp_limits=ramp_limits, - time_limits=time_limits, - operation_cost=operation_cost, - base_power=base_power, - storage_capacity=storage.head.storage_capacity, - inflow=storage.head.input_active_power_limit_max, - initial_storage=storage.head.energy_level, + name = gen.name, + available = gen.available, + bus = bus, + active_power = gen.active_power, + reactive_power = reactive_power, + prime_mover_type = parse_enum_mapping(PrimeMovers, gen.unit_type), + rating = rating, + active_power_limits = active_power_limits, + reactive_power_limits = reactive_power_limits, + ramp_limits = ramp_limits, + time_limits = time_limits, + operation_cost = operation_cost, + base_power = base_power, + storage_capacity = storage.head.storage_capacity, + inflow = storage.head.input_active_power_limit_max, + initial_storage = storage.head.energy_level, ) elseif gen_type == HydroPumpedStorage @@ -1209,75 +1239,75 @@ function make_hydro_generator( IS.LOG_GROUP_PARSING pump_active_power_limits = ( - min=gen.pump_active_power_limits_min, - max=gen.pump_active_power_limits_max, + min = gen.pump_active_power_limits_min, + max = gen.pump_active_power_limits_max, ) (pump_reactive_power, pump_reactive_power_limits) = make_reactive_params( gen; - powerfield=:pump_reactive_power, - minfield=:pump_reactive_power_limits_min, - maxfield=:pump_reactive_power_limits_max, + powerfield = :pump_reactive_power, + minfield = :pump_reactive_power_limits_min, + maxfield = :pump_reactive_power_limits_max, ) pump_rating = calculate_rating(pump_active_power_limits, pump_reactive_power_limits) pump_ramp_limits = make_ramplimits( gen; - ramplimcol=:pump_ramp_limits, - rampupcol=:pump_ramp_up, - rampdncol=:pump_ramp_down, + ramplimcol = :pump_ramp_limits, + rampupcol = :pump_ramp_up, + rampdncol = :pump_ramp_down, ) pump_time_limits = make_timelimits(gen, :pump_min_up_time, :pump_min_down_time) hydro_gen = HydroPumpedStorage(; - name=gen.name, - available=gen.available, - bus=bus, - active_power=gen.active_power, - reactive_power=reactive_power, - rating=rating, - base_power=base_power, - prime_mover_type=parse_enum_mapping(PrimeMovers, gen.unit_type), - active_power_limits=active_power_limits, - reactive_power_limits=reactive_power_limits, - ramp_limits=ramp_limits, - time_limits=time_limits, - rating_pump=pump_rating, - active_power_limits_pump=pump_active_power_limits, - reactive_power_limits_pump=pump_reactive_power_limits, - ramp_limits_pump=pump_ramp_limits, - time_limits_pump=pump_time_limits, - storage_capacity=( - up=storage.head.storage_capacity, - down=storage.head.storage_capacity, + name = gen.name, + available = gen.available, + bus = bus, + active_power = gen.active_power, + reactive_power = reactive_power, + rating = rating, + base_power = base_power, + prime_mover_type = parse_enum_mapping(PrimeMovers, gen.unit_type), + active_power_limits = active_power_limits, + reactive_power_limits = reactive_power_limits, + ramp_limits = ramp_limits, + time_limits = time_limits, + rating_pump = pump_rating, + active_power_limits_pump = pump_active_power_limits, + reactive_power_limits_pump = pump_reactive_power_limits, + ramp_limits_pump = pump_ramp_limits, + time_limits_pump = pump_time_limits, + storage_capacity = ( + up = storage.head.storage_capacity, + down = storage.head.storage_capacity, ), - inflow=storage.head.input_active_power_limit_max, - outflow=storage.tail.input_active_power_limit_max, - initial_storage=( - up=storage.head.energy_level, - down=storage.tail.energy_level, + inflow = storage.head.input_active_power_limit_max, + outflow = storage.tail.input_active_power_limit_max, + initial_storage = ( + up = storage.head.energy_level, + down = storage.tail.energy_level, ), - storage_target=( - up=storage.head.storage_target, - down=storage.tail.storage_target, + storage_target = ( + up = storage.head.storage_target, + down = storage.tail.storage_target, ), - operation_cost=operation_cost, - pump_efficiency=storage.tail.efficiency, + operation_cost = operation_cost, + pump_efficiency = storage.tail.efficiency, ) end elseif gen_type == HydroDispatch @debug "Creating $(gen.name) as HydroDispatch" _group = IS.LOG_GROUP_PARSING hydro_gen = HydroDispatch(; - name=gen.name, - available=gen.available, - bus=bus, - active_power=gen.active_power, - reactive_power=reactive_power, - rating=rating, - prime_mover_type=parse_enum_mapping(PrimeMovers, gen.unit_type), - active_power_limits=active_power_limits, - reactive_power_limits=reactive_power_limits, - ramp_limits=ramp_limits, - time_limits=time_limits, - base_power=base_power, + name = gen.name, + available = gen.available, + bus = bus, + active_power = gen.active_power, + reactive_power = reactive_power, + rating = rating, + prime_mover_type = parse_enum_mapping(PrimeMovers, gen.unit_type), + active_power_limits = active_power_limits, + reactive_power_limits = reactive_power_limits, + ramp_limits = ramp_limits, + time_limits = time_limits, + base_power = base_power, ) else error("Tabular data parser does not currently support $gen_type creation") @@ -1295,7 +1325,7 @@ function make_renewable_generator( @debug "Making RenewableGen" _group = IS.LOG_GROUP_PARSING gen.name generator = nothing active_power_limits = - (min=gen.active_power_limits_min, max=gen.active_power_limits_max) + (min = gen.active_power_limits_min, max = gen.active_power_limits_max) (reactive_power, reactive_power_limits) = make_reactive_params(gen) rating = calculate_rating(active_power_limits, reactive_power_limits) base_power = gen.base_mva @@ -1304,30 +1334,30 @@ function make_renewable_generator( if gen_type == RenewableDispatch @debug "Creating $(gen.name) as RenewableDispatch" _group = IS.LOG_GROUP_PARSING generator = RenewableDispatch(; - name=gen.name, - available=gen.available, - bus=bus, - active_power=gen.active_power, - reactive_power=reactive_power, - rating=rating, - prime_mover_type=parse_enum_mapping(PrimeMovers, gen.unit_type), - reactive_power_limits=reactive_power_limits, - power_factor=gen.power_factor, - operation_cost=operation_cost, - base_power=base_power, + name = gen.name, + available = gen.available, + bus = bus, + active_power = gen.active_power, + reactive_power = reactive_power, + rating = rating, + prime_mover_type = parse_enum_mapping(PrimeMovers, gen.unit_type), + reactive_power_limits = reactive_power_limits, + power_factor = gen.power_factor, + operation_cost = operation_cost, + base_power = base_power, ) elseif gen_type == RenewableFix @debug "Creating $(gen.name) as RenewableFix" _group = IS.LOG_GROUP_PARSING generator = RenewableFix(; - name=gen.name, - available=gen.available, - bus=bus, - active_power=gen.active_power, - reactive_power=reactive_power, - rating=rating, - prime_mover_type=parse_enum_mapping(PrimeMovers, gen.unit_type), - power_factor=gen.power_factor, - base_power=base_power, + name = gen.name, + available = gen.available, + bus = bus, + active_power = gen.active_power, + reactive_power = reactive_power, + rating = rating, + prime_mover_type = parse_enum_mapping(PrimeMovers, gen.unit_type), + power_factor = gen.power_factor, + base_power = base_power, ) else error("Unsupported type $gen_type") @@ -1339,44 +1369,44 @@ end function make_storage(data::PowerSystemTableData, gen, bus, storage) @debug "Making Storage" _group = IS.LOG_GROUP_PARSING storage.name state_of_charge_limits = - (min=storage.min_storage_capacity, max=storage.storage_capacity) + (min = storage.min_storage_capacity, max = storage.storage_capacity) input_active_power_limits = ( - min=storage.input_active_power_limit_min, - max=storage.input_active_power_limit_max, + min = storage.input_active_power_limit_min, + max = storage.input_active_power_limit_max, ) output_active_power_limits = ( - min=storage.output_active_power_limit_min, - max=if isnothing(storage.output_active_power_limit_max) + min = storage.output_active_power_limit_min, + max = if isnothing(storage.output_active_power_limit_max) gen.active_power_limits_max else storage.output_active_power_limit_max end, ) - efficiency = (in=storage.input_efficiency, out=storage.output_efficiency) + efficiency = (in = storage.input_efficiency, out = storage.output_efficiency) (reactive_power, reactive_power_limits) = make_reactive_params(storage) battery = EnergyReservoirStorage(; - name=gen.name, - available=storage.available, - bus=bus, - prime_mover_type=parse_enum_mapping(PrimeMovers, gen.unit_type), - storage_technology_type=StorageTech.OTHER_CHEM, - initial_energy=storage.energy_level, - state_of_charge_limits=state_of_charge_limits, - rating=storage.rating, - active_power=storage.active_power, - input_active_power_limits=input_active_power_limits, - output_active_power_limits=output_active_power_limits, - efficiency=efficiency, - reactive_power=reactive_power, - reactive_power_limits=reactive_power_limits, - base_power=storage.base_power, - operation_cost=StorageCost(), + name = gen.name, + available = storage.available, + bus = bus, + prime_mover_type = parse_enum_mapping(PrimeMovers, gen.unit_type), + storage_technology_type = StorageTech.OTHER_CHEM, + initial_energy = storage.energy_level, + state_of_charge_limits = state_of_charge_limits, + rating = storage.rating, + active_power = storage.active_power, + input_active_power_limits = input_active_power_limits, + output_active_power_limits = output_active_power_limits, + efficiency = efficiency, + reactive_power = reactive_power, + reactive_power_limits = reactive_power_limits, + base_power = storage.base_power, + operation_cost = StorageCost(), ) return battery end -const CATEGORY_STR_TO_COMPONENT = Dict{String,DataType}( +const CATEGORY_STR_TO_COMPONENT = Dict{String, DataType}( "ACBus" => ACBus, "Generator" => Generator, "Reserve" => Service, @@ -1397,7 +1427,7 @@ function _read_config_file(file_path::String) return open(file_path) do io data = YAML.load(io) # Replace keys with enums. - config_data = Dict{InputCategory,Vector}() + config_data = Dict{InputCategory, Vector}() for (key, val) in data # TODO: need to change user_descriptors.yaml to use reserve instead. if key == "reserves" @@ -1415,9 +1445,9 @@ struct _FieldInfo custom_name::String per_unit_conversion::NamedTuple{ (:From, :To, :Reference), - Tuple{UnitSystem,UnitSystem,String}, + Tuple{UnitSystem, UnitSystem, String}, } - unit_conversion::Union{NamedTuple{(:From, :To),Tuple{String,String}},Nothing} + unit_conversion::Union{NamedTuple{(:From, :To), Tuple{String, String}}, Nothing} default_value::Any # TODO unit, value ranges and options end @@ -1433,9 +1463,9 @@ function _get_field_infos(data::PowerSystemTableData, category::InputCategory, d # Cache whether PowerSystems uses a column's values as system-per-unit. # The user's descriptors indicate that the raw data is already system-per-unit or not. - per_unit = Dict{String,IS.UnitSystem}() - unit = Dict{String,Union{String,Nothing}}() - custom_names = Dict{String,String}() + per_unit = Dict{String, IS.UnitSystem}() + unit = Dict{String, Union{String, Nothing}}() + custom_names = Dict{String, String}() for descriptor in data.user_descriptors[category] custom_name = descriptor["custom_name"] if descriptor["custom_name"] in df_names @@ -1471,25 +1501,25 @@ function _get_field_infos(data::PowerSystemTableData, category::InputCategory, d end pu_conversion = ( - From=per_unit[name], - To=item_unit_system, - Reference=per_unit_reference, + From = per_unit[name], + To = item_unit_system, + Reference = per_unit_reference, ) expected_unit = get(item, "unit", nothing) if !isnothing(expected_unit) && !isnothing(unit[name]) && expected_unit != unit[name] - unit_conversion = (From=unit[name], To=expected_unit) + unit_conversion = (From = unit[name], To = expected_unit) else unit_conversion = nothing end else custom_name = name pu_conversion = ( - From=item_unit_system, - To=item_unit_system, - Reference=per_unit_reference, + From = item_unit_system, + To = item_unit_system, + Reference = per_unit_reference, ) unit_conversion = nothing end @@ -1504,7 +1534,7 @@ function _get_field_infos(data::PowerSystemTableData, category::InputCategory, d end """Reads values from dataframe row and performs necessary conversions.""" -function _read_data_row(data::PowerSystemTableData, row, field_infos; na_to_nothing=true) +function _read_data_row(data::PowerSystemTableData, row, field_infos; na_to_nothing = true) fields = Vector{String}() vals = Vector() for field_info in field_infos From d81c50a67bde1cd057059b35dd78e277c1b69c6c Mon Sep 17 00:00:00 2001 From: Barrows Date: Thu, 20 Jun 2024 05:54:01 -0600 Subject: [PATCH 03/12] fixing single cost point option --- src/parsers/power_system_table_data.jl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/parsers/power_system_table_data.jl b/src/parsers/power_system_table_data.jl index de2a0f369e..b81258226e 100644 --- a/src/parsers/power_system_table_data.jl +++ b/src/parsers/power_system_table_data.jl @@ -934,9 +934,10 @@ function create_pwl_cost( var_cost = PiecewisePointCurve(PiecewiseLinearData(cost_pairs)) elseif length(cost_pairs) == 1 # if there is only one point, use it to determine the constant $/MW cost - var_cost = LinearCurve(cost_pairs[1].y) + var_cost = LinearCurve(cost_pairs[1].y/cost_pairs[1].x) else - @warn "Unable to calculate variable cost for $(gen.name)" cost_pairs maxlog = 5 + @warn "$(gen.name) has no costs defined, using 0.0" cost_pairs maxlog = 5 + var_cost = LinearCurve(0.0) end return var_cost From c18e9ba4f79982264f33cd763fdc81121c96053d Mon Sep 17 00:00:00 2001 From: Barrows Date: Sat, 22 Jun 2024 10:49:04 -0600 Subject: [PATCH 04/12] cleaning up tabular fuel cost parser --- src/parsers/power_system_table_data.jl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/parsers/power_system_table_data.jl b/src/parsers/power_system_table_data.jl index b81258226e..64ffec2103 100644 --- a/src/parsers/power_system_table_data.jl +++ b/src/parsers/power_system_table_data.jl @@ -949,19 +949,19 @@ function create_pwinc_cost( if length(cost_pairs) > 1 x_points = getfield.(cost_pairs, :x) y_points = getfield.(cost_pairs, :y) - b = y_points[1] - y_points[2] * x_points[1] - fixed = (y_points[1] - y_points[2]) * x_points[1] - - var_cost = PiecewiseIncrementalCurve(first(y_points) - b, x_points, y_points[2:end]) + var_cost = PiecewiseIncrementalCurve( + first(y_points) * first(x_points), + x_points, + y_points[2:end], + ) elseif length(cost_pairs) == 1 # if there is only one point, use it to determine the constant $/MW cost var_cost = LinearCurve(cost_pairs[1].y) - fixed = 0.0 else @warn "Unable to calculate variable cost for $(gen.name)" cost_pairs maxlog = 5 end - return var_cost, fixed + return var_cost, 0.0 end function calculate_uc_cost(data, gen, fuel_cost) From c8af4bc69f1064738541df2ead23aafb64abb951 Mon Sep 17 00:00:00 2001 From: Clayton Barrows Date: Mon, 24 Jun 2024 12:21:15 -0600 Subject: [PATCH 05/12] Update src/parsers/power_system_table_data.jl Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/parsers/power_system_table_data.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parsers/power_system_table_data.jl b/src/parsers/power_system_table_data.jl index 64ffec2103..6368102a08 100644 --- a/src/parsers/power_system_table_data.jl +++ b/src/parsers/power_system_table_data.jl @@ -934,7 +934,7 @@ function create_pwl_cost( var_cost = PiecewisePointCurve(PiecewiseLinearData(cost_pairs)) elseif length(cost_pairs) == 1 # if there is only one point, use it to determine the constant $/MW cost - var_cost = LinearCurve(cost_pairs[1].y/cost_pairs[1].x) + var_cost = LinearCurve(cost_pairs[1].y / cost_pairs[1].x) else @warn "$(gen.name) has no costs defined, using 0.0" cost_pairs maxlog = 5 var_cost = LinearCurve(0.0) From e383e0979239d22ca48e41cce3d63e95ba4b639e Mon Sep 17 00:00:00 2001 From: Clayton Barrows Date: Mon, 24 Jun 2024 12:21:27 -0600 Subject: [PATCH 06/12] Update src/parsers/power_system_table_data.jl Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/parsers/power_system_table_data.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parsers/power_system_table_data.jl b/src/parsers/power_system_table_data.jl index 6368102a08..1f49c40b78 100644 --- a/src/parsers/power_system_table_data.jl +++ b/src/parsers/power_system_table_data.jl @@ -953,7 +953,7 @@ function create_pwinc_cost( first(y_points) * first(x_points), x_points, y_points[2:end], - ) + ) elseif length(cost_pairs) == 1 # if there is only one point, use it to determine the constant $/MW cost var_cost = LinearCurve(cost_pairs[1].y) From e2444736ee5994858890d429193ab716f6e0be29 Mon Sep 17 00:00:00 2001 From: Clayton Barrows Date: Mon, 24 Jun 2024 12:22:57 -0600 Subject: [PATCH 07/12] Update power_system_table_data.jl --- src/parsers/power_system_table_data.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parsers/power_system_table_data.jl b/src/parsers/power_system_table_data.jl index 1f49c40b78..d29f21f920 100644 --- a/src/parsers/power_system_table_data.jl +++ b/src/parsers/power_system_table_data.jl @@ -1051,7 +1051,7 @@ function make_reactive_params( return reactive_power, reactive_power_limits end -function make_thermal_generator(data::PowerSystemTableData, gen, cost_colnames, bus) +function make_thermal_generator(data::PowerSystemTableData, gen, cost_colnames::_CostPointColumns, bus) @debug "Making ThermaStandard" _group = IS.LOG_GROUP_PARSING gen.name active_power_limits = (min = gen.active_power_limits_min, max = gen.active_power_limits_max) From f689faaf4edc9e08691b5c8bf0b572ad43e53399 Mon Sep 17 00:00:00 2001 From: Clayton Barrows Date: Mon, 24 Jun 2024 13:09:44 -0600 Subject: [PATCH 08/12] Update src/parsers/power_system_table_data.jl Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/parsers/power_system_table_data.jl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/parsers/power_system_table_data.jl b/src/parsers/power_system_table_data.jl index d29f21f920..fa9db76a68 100644 --- a/src/parsers/power_system_table_data.jl +++ b/src/parsers/power_system_table_data.jl @@ -1051,7 +1051,12 @@ function make_reactive_params( return reactive_power, reactive_power_limits end -function make_thermal_generator(data::PowerSystemTableData, gen, cost_colnames::_CostPointColumns, bus) +function make_thermal_generator( + data::PowerSystemTableData, + gen, + cost_colnames::_CostPointColumns, + bus, +) @debug "Making ThermaStandard" _group = IS.LOG_GROUP_PARSING gen.name active_power_limits = (min = gen.active_power_limits_min, max = gen.active_power_limits_max) From 2a42025357b0d2db0a4084ec54d9cfabbe4a3681 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Mon, 1 Jul 2024 17:27:01 -0700 Subject: [PATCH 09/12] change matpower cost to device base --- src/parsers/power_models_data.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parsers/power_models_data.jl b/src/parsers/power_models_data.jl index 1c9af0f01e..4880060867 100644 --- a/src/parsers/power_models_data.jl +++ b/src/parsers/power_models_data.jl @@ -523,7 +523,7 @@ function make_thermal_gen( cost = QuadraticFunctionData(get.(Ref(coeffs), quadratic_degrees, 0)...) fixed = (d["ncost"] >= 1) ? last(d["cost"]) : 0.0 end - cost = CostCurve(InputOutputCurve((cost))) + cost = CostCurve(InputOutputCurve((cost)), UnitSystem.DEVICE_BASE) startup = d["startup"] shutdn = d["shutdown"] else From 3e5b46f498b48c0141908e2135098cb7a3e426ad Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Mon, 1 Jul 2024 17:27:15 -0700 Subject: [PATCH 10/12] remove throws now that is a FuelCurve --- test/test_cost_functions.jl | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/test_cost_functions.jl b/test/test_cost_functions.jl index 7339d17cc6..b62a1cfc03 100644 --- a/test/test_cost_functions.jl +++ b/test/test_cost_functions.jl @@ -326,8 +326,6 @@ end generators = collect(get_components(ThermalStandard, sys)) generator = get_component(ThermalStandard, sys, "322_CT_6") - @test_throws ArgumentError get_fuel_cost(generator) # Can't get the fuel cost of a CostCurve - op_cost = get_operation_cost(generator) value_curve = get_value_curve(get_variable(op_cost)) set_variable!(op_cost, FuelCurve(value_curve, 0.0)) From bc410590d3eefd89f43590faa63492d467ae54a3 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Mon, 1 Jul 2024 17:27:39 -0700 Subject: [PATCH 11/12] update multiple dispatch and vom linearcurve --- src/parsers/power_system_table_data.jl | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/parsers/power_system_table_data.jl b/src/parsers/power_system_table_data.jl index 1381774366..f1253ba2e7 100644 --- a/src/parsers/power_system_table_data.jl +++ b/src/parsers/power_system_table_data.jl @@ -835,6 +835,7 @@ function make_cost( gen, cost_colnames::_CostPointColumns, ) where {T <: ThermalGen} + fuel_price = gen.fuel_price / 1000.0 cost_pairs = get_cost_pairs(gen, cost_colnames) var_cost = create_pwl_cost(cost_pairs) startup_cost, shutdown_cost = calculate_uc_cost(data, gen, fuel_price) @@ -887,7 +888,11 @@ function make_cost( var_cost = CostCurve(; value_curve = LinearCurve(0.0), power_units = UnitSystem.NATURAL_UNITS, - vom_cost = isnothing(gen.variable_cost) ? 0.0 : gen.variable_cost, + vom_cost = if isnothing(gen.variable_cost) + LinearCurve(0.0) + else + LinearCurve(gen.variable_cost) + end, ) op_cost = RenewableGenerationCost(var_cost) return op_cost @@ -1054,7 +1059,7 @@ end function make_thermal_generator( data::PowerSystemTableData, gen, - cost_colnames::_CostPointColumns, + cost_colnames::Union{_CostPointColumns, _HeatRateColumns}, bus, ) @debug "Making ThermaStandard" _group = IS.LOG_GROUP_PARSING gen.name From 1a589cb3100dd65b1d2b0bf670ca2a3381acd13c Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Mon, 1 Jul 2024 17:27:54 -0700 Subject: [PATCH 12/12] fix i/o matpower with clayton data model comparison --- test/test_power_system_table_data.jl | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/test/test_power_system_table_data.jl b/test/test_power_system_table_data.jl index 1182c7c080..fc668cf0c8 100644 --- a/test/test_power_system_table_data.jl +++ b/test/test_power_system_table_data.jl @@ -94,18 +94,25 @@ end get_variable(mpgen_cost))), ) if length(mp_points) == 4 - cdm_points = get_points( - get_function_data( - get_value_curve( - get_variable(get_operation_cost(cdmgen))), - ), + cdm_op_cost = get_operation_cost(cdmgen) + @test get_fixed(cdm_op_cost) == 0.0 + fuel_curve = get_variable(cdm_op_cost) + fuel_cost = get_fuel_cost(fuel_curve) + mp_fixed = get_fixed(mpgen_cost) + io_curve = InputOutputCurve(get_value_curve(fuel_curve)) + cdm_points = get_points(io_curve) + @test all( + isapprox.( + [p.y * fuel_cost for p in cdm_points], + [p.y + mp_fixed for p in mp_points], + atol = 0.1), ) @test all( isapprox.( - [p.y for p in cdm_points], [p.y for p in mp_points], + [p.x for p in cdm_points], + [p.x * get_base_power(mpgen) for p in mp_points], atol = 0.1), ) - #@test PSY.compare_values(cdmgen.operation_cost, mpgen.operation_cost, compare_uuids = false) end end