From bd64b1f798668503ae37ed71274dd2c103f1cb9a Mon Sep 17 00:00:00 2001 From: Ethan Russell Date: Mon, 5 Jun 2023 12:38:32 -0400 Subject: [PATCH 01/21] Add more welfare calculations including regulatory factor --- benchmark/benchmark_helper.jl | 4 +- docs/src/results/formulas.md | 11 ++- src/io/data.jl | 6 +- src/model/newgens.jl | 5 +- src/results/formulas.jl | 120 +++++++++++++++++++++++++++-- src/results/results_formulas.csv | 51 ++++++++---- src/types/modifications/Storage.jl | 13 +++- test/data/3bus/bus.csv | 8 +- test/data/3bus/gen.csv | 12 +-- test/data/3bus/storage.csv | 4 +- 10 files changed, 195 insertions(+), 39 deletions(-) diff --git a/benchmark/benchmark_helper.jl b/benchmark/benchmark_helper.jl index 4c1a0801..f536f6a9 100644 --- a/benchmark/benchmark_helper.jl +++ b/benchmark/benchmark_helper.jl @@ -14,13 +14,15 @@ function make_random_inputs(;n_bus = 100, n_gen = 100, n_branch=100, n_af=100, n bus = DataFrame( ref_bus = fill(false, n_bus), plnom = rand(n_bus), - country = rand(countries(), n_bus) + country = rand(countries(), n_bus), + reg_factor = rand(n_bus), ) ref_bus_idx = rand(1:n_bus) bus.ref_bus[ref_bus_idx] = true gen = DataFrame( bus_idx = rand(1:n_bus, n_gen), + reg_factor = rand(n_gen), status = trues(n_gen), build_status = rand(build_status_opts(), n_gen), build_type = rand(build_type_opts(), n_gen), diff --git a/docs/src/results/formulas.md b/docs/src/results/formulas.md index cf55b1d4..c9aa2cc7 100644 --- a/docs/src/results/formulas.md +++ b/docs/src/results/formulas.md @@ -11,9 +11,18 @@ get_results_formulas get_results_formula compute_result ResultsFormula +``` + +## Result Aggregation Functions +```@docs Sum SumYearly +AverageYearly +MinYearly +MaxYearly SumHourly +AverageHourly MinHourly -AverageYearly +MaxHourly +CostOfServiceRebate ``` \ No newline at end of file diff --git a/src/io/data.jl b/src/io/data.jl index 70640970..334456d4 100644 --- a/src/io/data.jl +++ b/src/io/data.jl @@ -472,7 +472,7 @@ function setup_table!(config, data, ::Val{:gen}) ### Map bus characteristics to generators names_before = propertynames(gen) - leftjoin!(gen, bus, on=:bus_idx) + leftjoin!(gen, select(bus, Not(:reg_factor)), on=:bus_idx) select!(gen, Not(:plnom)) disallowmissing!(gen) names_after = propertynames(gen) @@ -684,7 +684,8 @@ function summarize_table(::Val{:gen}) (:emis_co2, Float64, ShortTonsPerMWhGenerated, false, "The emission rate per MWh of CO2"), (:capt_co2_percent, Float64, NA, false, "The percentage of co2 emissions captured, to be sequestered."), (:heat_rate, Float64, MMBtuPerMWhGenerated, false, "Heat rate, or MMBtu of fuel consumed per MWh electricity generated (0 for generators that don't use combustion)"), - (:chp_co2_multi,Float64,NA,false,"The percentage of CO2 emissions from CHP attributed to the power generation. Used to calculate CO2e") + (:chp_co2_multi,Float64,NA,false,"The percentage of CO2 emissions from CHP attributed to the power generation. Used to calculate CO2e"), + (:reg_factor, Float64, NA, true, "The percentage of generation that dispatches to a cost-of-service regulated market"), ) return df end @@ -699,6 +700,7 @@ function summarize_table(::Val{:bus}) df = TableSummary() push!(df, (:ref_bus, Bool, NA, true, "Whether or not the bus is a reference bus. There should be a single reference bus for each island."), + (:reg_factor, Float64, NA, true, "The percentage of generation that dispatches to a cost-of-service regulated market"), ) return df end diff --git a/src/model/newgens.jl b/src/model/newgens.jl index 4c78c636..86e39e30 100644 --- a/src/model/newgens.jl +++ b/src/model/newgens.jl @@ -46,7 +46,7 @@ function make_newgens!(config, data, newgen) #get the names of specifications that will be pulled from the build_gen table spec_names = filter!( - !in((:bus_idx, :gen_latitude, :gen_longitude, :year_off, :year_shutdown, :pcap_inv)), + !in((:bus_idx, :gen_latitude, :gen_longitude, :reg_factor, :year_off, :year_shutdown, :pcap_inv)), propertynames(newgen) ) #this needs to be updated if there is anything else in gen that isn't a spec @@ -88,6 +88,7 @@ function make_newgens!(config, data, newgen) #add gen location hasproperty(newgen, :gen_latitude) && (newgen_row[:gen_latitude] = bus.bus_latitude[bus_idx]) hasproperty(newgen, :gen_longitude) && (newgen_row[:gen_longitude] = bus.bus_longitude[bus_idx]) + hasproperty(newgen, :reg_factor) && (newgen_row[:reg_factor] = bus.reg_factor[bus_idx]) push!(newgen, newgen_row, promote=true) end @@ -101,6 +102,8 @@ function make_newgens!(config, data, newgen) newgen_row = Dict{}(:bus_idx => bus_idx, (spec_name=>spec_row[spec_name] for spec_name in spec_names)...) hasproperty(newgen, :gen_latitude) && (newgen_row[:gen_latitude] = bus.bus_latitude[bus_idx]) hasproperty(newgen, :gen_longitude) && (newgen_row[:gen_longitude] = bus.bus_longitude[bus_idx]) + hasproperty(newgen, :reg_factor) && (newgen_row[:reg_factor] = bus.reg_factor[bus_idx]) + newgen_row[:year_shutdown] = add_to_year(spec_row.year_on, spec_row.age_shutdown) newgen_row[:year_off] = "y9999" newgen_row[:pcap_inv] = 0.0 diff --git a/src/results/formulas.jl b/src/results/formulas.jl index 98f3f080..3aa39150 100644 --- a/src/results/formulas.jl +++ b/src/results/formulas.jl @@ -92,7 +92,7 @@ function add_results_formula!(data, table_name::Symbol, result_name::Symbol, for # Raw results calculations. I.e. "SumHourly(vom, egen)" if startswith(formula, r"[\w]+\(") - args_string = match(r"\([^\)]+\)", formula).match + args_string = match(r"\([^\)]*\)", formula).match dependent_columns = collect(Symbol(m.match) for m in eachmatch(r"(\w+)", args_string)) fn_string = match(r"([\w]+)\(",formula).captures[1] T = getfield(E4ST, Symbol(fn_string)) @@ -101,7 +101,7 @@ function add_results_formula!(data, table_name::Symbol, result_name::Symbol, for # Derived results calculations: I.e. "vom_total / egen_total" else - dependent_columns = collect(Symbol(m.match) for m in eachmatch(r"(\w+)", formula)) + dependent_columns = collect(Symbol(m.match) for m in eachmatch(r"([A-Za-z]\w+)", formula)) isderived = true fn = _ResultsFunction(formula) end @@ -145,7 +145,7 @@ struct Tail <: Function end _Func(s::String) = _Func(Meta.parse(s)) _Func(e::Expr) = Op{getfield(Base, e.args[1]), _Func((view(e.args, 2:length(e.args))...,))} _Func(s::Symbol) = Var{s} -_Func(n::Number) = Num{n} +_Func(n::Number) = Num{Float64(n)} function _Func(args::Tuple) Args{_Func(first(args)), _Func(Base.tail(args))} end @@ -275,7 +275,7 @@ function compute_results!(df, data, table_name, result_name, idx_sets, year_idx_ fn = res_formula.fn res = fn(df) - df[!, result_name] = res + df[!, result_name] .= res end return nothing end @@ -321,6 +321,49 @@ function (f::Sum{3})(data, table, idxs, yr_idxs, hr_idxs) _sum(table[!, col1], table[!, col2], table[!, col3], idxs) end + +@doc raw""" + MinYearly(cols...) <: Function + +This function returns the minimum yearly value. + +```math +\min_{y \in \text{yr\_idxs}} \sum_{i \in \text{idxs}, h \in \text{hr\_idxs}} \prod_{c \in \text{cols}} \text{table}[i, c][y, h] +``` +""" +struct MinYearly{N} <: Function + cols::NTuple{N, Symbol} +end +MinYearly(cols::Symbol...) = MinYearly(cols) +export MinYearly + +function (f::MinYearly{1})(data, table, idxs, yr_idxs, hr_idxs) + col1, = f.cols + v1 = table[!, col1] + minimum(_sum_yearly(v1, idxs, y, hr_idxs) for y in yr_idxs) +end + +@doc raw""" + MaxYearly(cols...) <: Function + +This function returns the maximum yearly value. + +```math +\max_{y \in \text{yr\_idxs}} \sum_{i \in \text{idxs}, h \in \text{hr\_idxs}} \prod_{c \in \text{cols}} \text{table}[i, c][y, h] +``` +""" +struct MaxYearly{N} <: Function + cols::NTuple{N, Symbol} +end +MaxYearly(cols::Symbol...) = MaxYearly(cols) +export MaxYearly + +function (f::MaxYearly{1})(data, table, idxs, yr_idxs, hr_idxs) + col1, = f.cols + v1 = table[!, col1] + maximum(_sum_yearly(v1, idxs, y, hr_idxs) for y in yr_idxs) +end + @doc raw""" AverageYearly(cols...) <: Function @@ -329,8 +372,6 @@ Function used in results formulas. Computes the sum of the products of the colu ```math \frac{\sum_{i \in \text{idxs}} \sum_{y \in \text{yr\_idxs}} \prod_{c \in \text{cols}} \text{table}[i, c][y]}{\text{length(yr\_idxs)}} ``` - -When specifying in a formula, looks like `average_yearly(cols...)` """ struct AverageYearly{N} <: Function cols::NTuple{N, Symbol} @@ -402,6 +443,27 @@ function (f::MinHourly{1})(data, table, idxs, yr_idxs, hr_idxs) minimum(_sum_hourly(v1, idxs, y, h) for h in hr_idxs for y in yr_idxs) end +@doc raw""" + MaxHourly(cols...) <: Function + +This function returns the maximum hourly value. + +```math +\max_{y \in \text{yr\_idxs}, h \in \text{hr\_idxs}} \sum_{i \in \text{idxs}} \prod_{c \in \text{cols}} \text{table}[i, c][y, h] +``` +""" +struct MaxHourly{N} <: Function + cols::NTuple{N, Symbol} +end +MaxHourly(cols::Symbol...) = MaxHourly(cols) +export MaxHourly + +function (f::MaxHourly{1})(data, table, idxs, yr_idxs, hr_idxs) + col1, = f.cols + v1 = table[!, col1] + maximum(_sum_hourly(v1, idxs, y, h) for h in hr_idxs for y in yr_idxs) +end + @doc raw""" SumHourly(cols...) <: Function @@ -431,6 +493,52 @@ function (f::SumHourly{3})(data, table, idxs, yr_idxs, hr_idxs) end +@doc raw""" + AverageHourly(cols...) <: Function + +Function used in results formulas. Computes the sum of the products of the columns for each index in idxs for each year and hour, divided by the number of hours. + +```math +\frac{\sum_{i \in \text{idxs}} \sum_{y \in \text{yr\_idxs}} \prod_{c \in \text{cols}} \text{table}[i, c][y]}{\sum_{y \in \text{yr\_idxs}, h \in \text{hr\_idxs}} w_{h}} +``` +""" +struct AverageHourly{N} <: Function + cols::NTuple{N, Symbol} +end +AverageHourly(cols::Symbol...) = AverageHourly(cols) +export AverageHourly + +function (f::AverageHourly{1})(data, table, idxs, yr_idxs, hr_idxs) + col1, = f.cols + hour_weights = get_hour_weights(data) + _sum_hourly(table[!, col1], idxs, yr_idxs, hr_idxs) / sum(hour_weights[hr_idx] for hr_idx in hr_idxs, yr_idx in yr_idxs) +end + +function (f::AverageHourly{2})(data, table, idxs, yr_idxs, hr_idxs) + col1,col2 = f.cols + hour_weights = get_hour_weights(data) + _sum_hourly(table[!, col1], table[!, col2], idxs, yr_idxs, hr_idxs) / sum(hour_weights[hr_idx] for hr_idx in hr_idxs, yr_idx in yr_idxs) +end + +function (f::AverageHourly{3})(data, table, idxs, yr_idxs, hr_idxs) + col1,col2,col3 = f.cols + hour_weights = get_hour_weights(data) + _sum_hourly(table[!, col1], table[!, col2], table[!, col3], idxs, yr_idxs, hr_idxs) / sum(hour_weights[hr_idx] for hr_idx in hr_idxs, yr_idx in yr_idxs) +end + + +""" + CostOfServiceRebate() <: Function + +This is a special function that computes the sum of the net total revenue times the regulatory factor `reg_factor`. This only works for the gen table. +""" +struct CostOfServiceRebate <: Function end +function (::CostOfServiceRebate)(data, table, idxs, yr_idxs, hr_idxs) + reg_factor = table.reg_factor + return sum0(reg_factor[i] * compute_result(data, :gen, :net_total_revenue, i, yr_idxs, hr_idxs) for i in idxs) +end +export CostOfServiceRebate + diff --git a/src/results/results_formulas.csv b/src/results/results_formulas.csv index 4cb5ec70..7a185024 100644 --- a/src/results/results_formulas.csv +++ b/src/results/results_formulas.csv @@ -1,27 +1,19 @@ table_name,result_name,formula,unit,description gen,egen_total,SumHourly(egen),MWhGenerated,"Total energy generated, in MWh" +gen,pgen_avg,AverageHourly(pgen),MWGenerated,Average power generation +gen,pgen_min,MinHourly(pgen),MWGenerated,Minimum power generation in an hour +gen,pgen_max,MaxHourly(pgen),MWGenerated,Maximum power generation in an hour gen,ecap_total,SumHourly(ecap),MWhCapacity,"Total energy capacity, in MWh" gen,pcap_total,AverageYearly(pcap),MWCapacity,"Average power capacity. If multiple years given, the average is taken." gen,ecap_available_total,"SumHourly(ecap,af)",MWhCapacity,"Total available energy capacity, in MWh" gen,pcap_start_total,Sum(pcap0),MWCapacity,Starting power capacity. gen,pcap_built_total,SumYearly(pcap_built),MWCapacity,Total power capacity built. Ignores subsets of hours and returns the built capacity for the whole year(s). gen,pcap_retired_total,SumYearly(pcap_retired),MWCapacity,Total power capacity retired. Ignores subsets of hours and returns the retired capacity for the whole year(s). -gen,vom_cost,"SumHourly(vom,egen)",Dollars,"Variable Operation and Maintenance paid, in dollars" -gen,vom_per_mwh,vom_cost/egen_total,DollarsPerMWhGenerated,Generation-weighted average of variable operation and maintenance costs -gen,fom_cost,"SumHourly(fom,ecap)",Dollars,"Fixed Operation and Maintenance paid, in dollars" -gen,fom_per_mwh,fom_cost/egen_total,DollarsPerMWhGenerated,Fixed Operation and Maintenance paid per MWh of energy generated -gen,capex_cost,"SumYearly(capex_obj, ecap_inv_sim)",Dollars,"Capital expenditures paid, in dollars, as seen by objective function" -gen,capex_per_mwh,capex_cost/egen_total,DollarsPerMWhGenerated,Capital expenditures paid per MWh of energy generated +gen,pcap_retired_percent,pcap_retired_total / pcap_start_total,MWCapacity,Percent of existing power capacity that was retired. Could be misleading if multiple years and generators were built and retired. gen,cf_avg,egen_total/ecap_total,MWhGeneratedPerMWhCapacity,Average Capacity Factor -gen,fuel_cost,"SumHourly(fuel_price,heat_rate,egen)",Dollars,Total cost of fuel -gen,fuel_price_per_mwh,fuel_cost/egen_total,DollarsPerMWhGenerated,Fuel price per MWh generated -gen,fuel_burned,"SumHourly(heat_rate,egen)",MMBtu,Amount of fuel burned -gen,fuel_price_per_mmbtu,fuel_cost_total/fuel_burned,DollarsPerMMBtu,Average price of fuel burned +gen,cf_hourly_min,MinHourly(cf),MWhGeneratedPerMWhCapacity,Minimum observed capacity factor +gen,cf_hourly_max,MaxHourly(cf),MWhGeneratedPerMWhCapacity,Maximum observed capacity factor gen,heat_rate_avg,fuel_burned / egen_total,MMBtuPerMWhGenerated,Average heat rate (fuel burned in MMBtu per MWh) -gen,variable_cost,fuel_cost+vom_cost,Dollars,"Variable costs for operation, including fuel and vom." -gen,variable_cost_per_mwh,variable_cost/egen_total,Dollars,"Variable costs for operation, per MWh of generation. Includes fuel and vom" -gen,fixed_cost,capex_cost + fom_cost,Dollars,"Fixed costs, including capex (not just what the optimization saw) and fom" -gen,fixed_cost_per_mwh,fixed_cost/egen_total,DollarsPerMWhGenerated,Fixed costs per mwh generated gen,emis_co2_total,"SumHourly(emis_co2,egen)",ShortTons,Total CO2 emissions gen,emis_nox_total,"SumHourly(emis_nox,egen)",Pounds,Total NOx emissions gen,emis_so2_total,"SumHourly(emis_so2,egen)",Pounds,Total SO2 emissions @@ -35,6 +27,37 @@ gen,capt_co2_rate,capt_co2_total/egen_total,ShortTonsPerMWhGenerated,Average rat gen,af_avg,ecap_available_total / ecap_total,MWhGeneratedPerMWhCapacity,Average availability factor (i.e. energy capacity available / energy capacity) gen,electricity_revenue,"SumHourly(lmp_egen, egen)",Dollars,Revenue earned by generators for the energy they served to the grid gen,electricity_price,electricity_revenue / egen,Dollars,Average price earned by generators for the energy they served to the grid +gen,vom_cost,"SumHourly(vom,egen)",Dollars,"Variable Operation and Maintenance paid, in dollars" +gen,vom_per_mwh,vom_cost/egen_total,DollarsPerMWhGenerated,Generation-weighted average of variable operation and maintenance costs +gen,fom_cost,"SumHourly(fom,ecap)",Dollars,"Fixed Operation and Maintenance paid, in dollars" +gen,fom_per_mwh,fom_cost/egen_total,DollarsPerMWhGenerated,Fixed Operation and Maintenance paid per MWh of energy generated +gen,capex_cost,"SumYearly(capex_obj, ecap_inv_sim)",Dollars,"Capital expenditures paid, in dollars, as seen by objective function" +gen,capex_per_mwh,capex_cost/egen_total,DollarsPerMWhGenerated,Levelized capital expenditures paid per MWh of energy generated +gen,fuel_cost,"SumHourly(fuel_price,heat_rate,egen)",Dollars,Total cost of fuel +gen,fuel_price_per_mwh,fuel_cost/egen_total,DollarsPerMWhGenerated,Fuel price per MWh generated +gen,fuel_burned,"SumHourly(heat_rate,egen)",MMBtu,Amount of fuel burned +gen,fuel_price_per_mmbtu,fuel_cost_total/fuel_burned,DollarsPerMMBtu,Average price of fuel burned +gen,variable_cost,fuel_cost+vom_cost,Dollars,"Variable costs for operation, including fuel and vom." +gen,variable_cost_per_mwh,variable_cost/egen_total,DollarsPerMWhGenerated,"Variable costs for operation, per MWh of generation. Includes fuel and vom" +gen,production_subsidy,0,Dollars,Total production subsidy for generation +gen,production_subsidy_per_mwh,production_subsidy / egen_total,DollarsPerMWhGenerated,Average production subsidy for a MWh of generation +gen,net_variable_cost,production_subsidy - variable_cost,Dollars,Total variable costs minus production subsidies +gen,net_variable_cost_per_mwh,net_variable_cost / egen_total,DollarsPerMWhGenerated,Average variable costs minus production subsidies for a MWh of energy +gen,fixed_cost,capex_cost + fom_cost,Dollars,"Fixed costs, including capex (not just what the optimization saw) and fom" +gen,fixed_cost_permw_perhr,fixed_cost/ecap_total,DollarsPerMWCapacityPerHour,Fixed costs per mw per hour +gen,invest_subsidy,0,Dollars,Investment subsidies to go to generators +gen,invest_subsidy_permw_perhr,invest_subsidy / ecap_total,DollarsPerMWCapacityPerHour,Average investment subsidy per MW per hour +gen,net_fixed_cost,fixed_cost - invest_subsidy,Dollars,Fixed costs minus investment subsidies +gen,net_fixed_cost_permw_perhr,net_fixed_cost / ecap_total,DollarsPerMWCapacityPerHour,Average net fixed cost per MW per hour. Fixed costs minus investment subsidies +gen,production_cost,variable_cost + fixed_cost,Dollars,"Cost of production, includes fixed and variable costs" +gen,production_cost_per_mwh,production_cost / egen_total,DollarsPerMWhGenerated,"Average cost of production for a MWh of power, including variable and fixed costs" +gen,net_production_cost,net_variable_cost + net_fixed_cost,Dollars,"Net cost of production, including fixed and variable costs minus investment and production subsidies" +gen,net_production_cost_per_mwh,net_production_cost / egen_total,DollarsPerMWhGenerated,"Average net cost of producing a MWh of power, including fixed and variable costs minus investment and production subsidies" +gen,total_cost,net_production_cost,Dollars,"Total cost of production. Right now contains only net_production_cost, but may eventually contain past capex costs" +gen,total_cost_per_mwh,total_cost / egen_total,DollarsPerMWhGenerated,"Average cost of producing a MWh of power. Right now contains only net_production_cost, but may eventually contain past capex costs" +gen,going_forward_cost,variable_cost + fixed_cost,Dollars,Total going forward cost +gen,net_total_revenue,electricity_revenue - total_cost,Dollars,"Net total revenue, including electricity revenue minus total cost" +gen,cost_of_service_rebate,CostOfServiceRebate(),Dollars,"This is a specially calculated result, which the sum of net_total_revenue * reg_factor for each generator" bus,elnom_total,SumHourly(elnom),MWhLoad,Nominal load energy bus,elserv_total,SumHourly(elserv),MWhServed,Total load energy served bus,eflow_in_total,SumHourly(eflow_in),MWhFlow,Total energy flowing into all the buses in this region (not necessarily net flow into the region) diff --git a/src/types/modifications/Storage.jl b/src/types/modifications/Storage.jl index 2c83c4fd..8608402a 100644 --- a/src/types/modifications/Storage.jl +++ b/src/types/modifications/Storage.jl @@ -84,6 +84,7 @@ function summarize_table(::Val{:storage}) (:hour_groupby, String, NA, true, "The column of the `hours` table to group by. For example `day`"), (:hour_duration, String, NA, true, "The column of the `hours` table specifying the duration of each representatibe hour"), (:hour_order, String, NA, true, "The column of the `hours` table specifying the sequence of the hours."), + (:reg_factor, Float64, NA, true, "The percentage of power that dispatches to a cost-of-service regulated market"), ) end @@ -196,7 +197,7 @@ function modify_setup_data!(mod::Storage, config, data) ### Map bus characteristics to storage names_before = propertynames(storage) - leftjoin!(storage, bus, on=:bus_idx) + leftjoin!(storage, select(bus, Not(:reg_factor)), on=:bus_idx) select!(storage, Not(:plnom)) disallowmissing!(storage) names_after = propertynames(storage) @@ -220,7 +221,7 @@ function add_buildable_storage!(config, data) bus = get_table(data, :bus) spec_names = filter!( - !in((:bus_idx, :year_off, :year_shutdown, :pcap_inv)), + !in((:bus_idx, :reg_factor, :year_off, :year_shutdown, :pcap_inv)), propertynames(storage) ) years = get_years(data) @@ -247,6 +248,10 @@ function add_buildable_storage!(config, data) new_row[:year_shutdown] = add_to_year(year, spec_row.age_shutdown) new_row[:year_off] = "y9999" new_row[:pcap_inv] = 0.0 + + # Add reg_factor if needed + hasproperty(storage, :reg_factor) && (new_row[:reg_factor] = bus.reg_factor[bus_idx]) + push!(storage, new_row, promote=true) end else # exogenous @@ -257,10 +262,14 @@ function add_buildable_storage!(config, data) # for exogenously specified storage, only one storage device is created with the specified year_on new_row = Dict{}(:bus_idx => bus_idx, (spec_name=>spec_row[spec_name] for spec_name in spec_names)...) + new_row[:year_shutdown] = add_to_year(spec_row.year_on, spec_row.age_shutdown) new_row[:year_off] = "y9999" new_row[:pcap_inv] = 0.0 + # Add reg_factor if needed + hasproperty(storage, :reg_factor) && (new_row[:reg_factor] = bus.reg_factor[bus_idx]) + push!(storage, new_row, promote=true) end end diff --git a/test/data/3bus/bus.csv b/test/data/3bus/bus.csv index 611a9692..98035c1a 100644 --- a/test/data/3bus/bus.csv +++ b/test/data/3bus/bus.csv @@ -1,4 +1,4 @@ -ref_bus,plnom,country,buildngcc,buildsolar,state -0,0.2,narnia,1,1,beaverdam -1,1.6,archenland,1,0,stormness -0,0.2,archenland,1,1,anvard \ No newline at end of file +ref_bus,reg_factor,plnom,country,buildngcc,buildsolar,state +0,0,0.2,narnia,1,1,beaverdam +1,1,1.6,archenland,1,0,stormness +0,1,0.2,archenland,1,1,anvard \ No newline at end of file diff --git a/test/data/3bus/gen.csv b/test/data/3bus/gen.csv index 6ae260c4..c4dd4c8e 100644 --- a/test/data/3bus/gen.csv +++ b/test/data/3bus/gen.csv @@ -1,6 +1,6 @@ -bus_idx,status,build_status,build_type,build_id,genfuel,gentype,econ_life,pcap_inv,pcap0,pcap_min,pcap_max,cf_min,vom,fuel_price,fom,capex,year_on,year_off,year_shutdown,emis_co2,capt_co2_percent,heat_rate,chp_co2_multi -3,1,built,exog,,coal,coal,30,2.0,2.0,0,2,0.6,2,0.5555555555555556,20,7,y2020,y9999,y2045,1,0,9,1.0 -1,1,built,exog,,solar,solar,30,0.5,0.5,0,0.5,0,2,0,5,5,y2027,y9999,y2050,0,0,0,1.0 -3,1,built,exog,,ng,ngccccs,30,0.5,0.5,0,0.5,0.6,1.5,0.14285714285714285,6,6,y2025,y9999,y2055,0.6,0.9,7,1.0 -1,1,built,exog,,wind,wind,30,0.05,0.05,0,0.05,0,0.1,0,2,3,y2015,y9999,y2035,0,0,0,1.0 -1,1,built,exog,,ng,ngt_chp,30,0.01,0.01,0,0.01,0.6,2,0.25,7,7,y2030,y9999,y2050,0.6,0,8,0.67 \ No newline at end of file +bus_idx,status,reg_factor,build_status,build_type,build_id,genfuel,gentype,econ_life,pcap_inv,pcap0,pcap_min,pcap_max,cf_min,vom,fuel_price,fom,capex,year_on,year_off,year_shutdown,emis_co2,capt_co2_percent,heat_rate,chp_co2_multi +3,1,0.75,built,exog,,coal,coal,30,2.0,2.0,0,2,0.6,2,0.5555555555555556,20,7,y2020,y9999,y2045,1,0,9,1.0 +1,1,0,built,exog,,solar,solar,30,0.5,0.5,0,0.5,0,2,0,5,5,y2027,y9999,y2050,0,0,0,1.0 +3,1,0.75,built,exog,,ng,ngccccs,30,0.5,0.5,0,0.5,0.6,1.5,0.14285714285714285,6,6,y2025,y9999,y2055,0.6,0.9,7,1.0 +1,1,0,built,exog,,wind,wind,30,0.05,0.05,0,0.05,0,0.1,0,2,3,y2015,y9999,y2035,0,0,0,1.0 +1,1,0.1,built,exog,,ng,ngt_chp,30,0.01,0.01,0,0.01,0.6,2,0.25,7,7,y2030,y9999,y2050,0.6,0,8,0.67 \ No newline at end of file diff --git a/test/data/3bus/storage.csv b/test/data/3bus/storage.csv index 06c734b1..59372491 100644 --- a/test/data/3bus/storage.csv +++ b/test/data/3bus/storage.csv @@ -1,2 +1,2 @@ -bus_idx,status,build_status,build_type,build_id,year_on,econ_life,year_shutdown,year_off,pcap_inv,pcap0,pcap_min,pcap_max,vom,fom,capex,duration_discharge,storage_efficiency,side,hour_groupby,hour_duration,hour_order -1,1,built,real,,y2020,30,y2050,y9999,0.05,0.05,0,0.05,0.5,0.5,5,8,0.9,load,day,day_duration,day_order \ No newline at end of file +bus_idx,status,reg_factor,build_status,build_type,build_id,year_on,econ_life,year_shutdown,year_off,pcap_inv,pcap0,pcap_min,pcap_max,vom,fom,capex,duration_discharge,storage_efficiency,side,hour_groupby,hour_duration,hour_order +1,1,0,built,real,,y2020,30,y2050,y9999,0.05,0.05,0,0.05,0.5,0.5,5,8,0.9,load,day,day_duration,day_order \ No newline at end of file From 1910539e27b3b9657b465b52cfe4dd1979daa76e Mon Sep 17 00:00:00 2001 From: Ethan Russell Date: Mon, 5 Jun 2023 12:39:17 -0400 Subject: [PATCH 02/21] Add the E4ST logo --- docs/src/assets/logo.png | Bin 0 -> 219363 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/src/assets/logo.png diff --git a/docs/src/assets/logo.png b/docs/src/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..6b3c2e49d2ff8b24e7ce2cad95563c95c591fbcb GIT binary patch literal 219363 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� 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 Date: Mon, 5 Jun 2023 13:25:12 -0400 Subject: [PATCH 03/21] Add the ability to add things to a result formula, add itc to invest_subsidy --- src/results/formulas.jl | 60 ++++++++++++++++++++++++++++----------- src/types/policies/ITC.jl | 9 +++++- 2 files changed, 52 insertions(+), 17 deletions(-) diff --git a/src/results/formulas.jl b/src/results/formulas.jl index 3aa39150..726a0868 100644 --- a/src/results/formulas.jl +++ b/src/results/formulas.jl @@ -90,27 +90,34 @@ function add_results_formula!(data, table_name::Symbol, result_name::Symbol, for results_formulas = get_results_formulas(data) - # Raw results calculations. I.e. "SumHourly(vom, egen)" - if startswith(formula, r"[\w]+\(") - args_string = match(r"\([^\)]*\)", formula).match - dependent_columns = collect(Symbol(m.match) for m in eachmatch(r"(\w+)", args_string)) - fn_string = match(r"([\w]+)\(",formula).captures[1] - T = getfield(E4ST, Symbol(fn_string)) - fn = T(dependent_columns...) - isderived = false - - # Derived results calculations: I.e. "vom_total / egen_total" - else - dependent_columns = collect(Symbol(m.match) for m in eachmatch(r"([A-Za-z]\w+)", formula)) - isderived = true - fn = _ResultsFunction(formula) - end + rf = ResultsFormula(table_name, result_name, formula, unit, description) # push!(results_formulas_table, (;table_name, result_name, formula, unit, description, dependent_columns, fn)) - results_formulas[table_name, result_name] = ResultsFormula(table_name, result_name, formula, unit, description, isderived, dependent_columns, fn) + results_formulas[table_name, result_name] = rf end export add_results_formula! +""" + add_to_results_formula!(data, table_name::Symbol, result_name::Symbol, formula::String) + +Adds a term to an existing results formula. Can be more complex expressions. +* if it is a derived formula (like `\"vom_cost + fom_cost\"`), then you can supply any expression to get added to the formula, like `\"-my_result_name / 2\"` +* if it is a primary formula (like `\"SumHourly(col1, col2)\"`), then you can provide additional columns like `\"col3, col4\"`. +""" +function add_to_results_formula!(data, table_name::Symbol, result_name::Symbol, formula::String) + rf = get_results_formula(data, table_name, result_name) + formula_original = rf.formula + if rf.isderived + formula_new = string(formula_original, " + ", formula) + else + formula_new = replace(formula_original, ")"=>",$formula)") + end + rf_new = ResultsFormula(table_name, result_name, formula_new, rf.unit, rf.description) + results_formulas = get_results_formulas(data) + results_formulas[table_name, result_name] = rf_new +end +export add_to_results_formula! + """ struct ResultsFormula @@ -129,6 +136,27 @@ struct ResultsFormula end export ResultsFormula +function ResultsFormula(table_name::Symbol, result_name::Symbol, formula::String, unit::Type{<:Unit}, description::String) + + # Raw results calculations. I.e. "SumHourly(vom, egen)" + if startswith(formula, r"[\w]+\(") + args_string = match(r"\([^\)]*\)", formula).match + dependent_columns = collect(Symbol(m.match) for m in eachmatch(r"(\w+)", args_string)) + fn_string = match(r"([\w]+)\(",formula).captures[1] + T = getfield(E4ST, Symbol(fn_string)) + fn = T(dependent_columns...) + isderived = false + + # Derived results calculations: I.e. "vom_total / egen_total" + else + dependent_columns = collect(Symbol(m.match) for m in eachmatch(r"([A-Za-z]\w+)", formula)) + isderived = true + fn = _ResultsFunction(formula) + end + + return ResultsFormula(table_name, result_name, formula, unit, description, isderived, dependent_columns, fn) +end + struct _ResultsFunction{F} <: Function end function _ResultsFunction(s::String) fn = _Func(s) diff --git a/src/types/policies/ITC.jl b/src/types/policies/ITC.jl index c00f0ff7..6e7d0ca3 100644 --- a/src/types/policies/ITC.jl +++ b/src/types/policies/ITC.jl @@ -79,4 +79,11 @@ function E4ST.modify_model!(pol::ITC, config, data, model) # end # data[:gen] = gen add_obj_term!(data, model, PerMWCap(), pol.name, oper = -) -end \ No newline at end of file +end + +function E4ST.modify_results!(pol::ITC, config, data) + total_result_name = "$(pol.name)_cost" + total_result_sym = Symbol(total_result_name) + add_results_formula!(data, :gen, total_result_sym, "SumHourly($(pol.name),egen)", Dollars, "The total amount of credit recieved for the $(pol.name) policy") + add_to_results_formula!(data, :gen, :invest_subsidy, total_result_name) +end From d91d1240a5d54eae83b63120a870e0d435a0683f Mon Sep 17 00:00:00 2001 From: Ethan Russell Date: Mon, 5 Jun 2023 17:31:12 -0400 Subject: [PATCH 04/21] Add more formulas, add objective coefficients --- docs/src/results/formulas.md | 1 + src/model/dcopf.jl | 1 - src/model/util.jl | 7 +++++++ src/results/formulas.jl | 26 ++++++++++++++++++++++++++ src/results/parse.jl | 26 ++++++++++++++++++++++++-- src/results/results_formulas.csv | 8 +++++--- test/testresultprocessing.jl | 12 ++++++++++++ 7 files changed, 75 insertions(+), 6 deletions(-) diff --git a/docs/src/results/formulas.md b/docs/src/results/formulas.md index c9aa2cc7..f4dca353 100644 --- a/docs/src/results/formulas.md +++ b/docs/src/results/formulas.md @@ -21,6 +21,7 @@ AverageYearly MinYearly MaxYearly SumHourly +SumHourlyWeighted AverageHourly MinHourly MaxHourly diff --git a/src/model/dcopf.jl b/src/model/dcopf.jl index b24c31c0..b92ae2e2 100644 --- a/src/model/dcopf.jl +++ b/src/model/dcopf.jl @@ -102,7 +102,6 @@ function setup_dcopf!(config, data, model) 1000 * pgen_gen[gen_idx, yr_idx, hr_idx] <= # Scale by 1000 in this constraint to improve matrix coefficient range. Some af values are very small. 1000 * get_cf_max(config, data, gen_idx, yr_idx, hr_idx) * pcap_gen[gen_idx, yr_idx] ) - # TODO: Add af_threshold here. # Constrain Reference Bus for ref_bus_idx in get_ref_bus_idxs(data), yr_idx in 1:nyear, hr_idx in 1:nhour diff --git a/src/model/util.jl b/src/model/util.jl index 8a81f4cf..74aa2fab 100644 --- a/src/model/util.jl +++ b/src/model/util.jl @@ -138,3 +138,10 @@ function add_build_constraints!(data, model, table_name::Symbol, pcap_name::Symb end export add_build_constraints! +function Base.getindex(ex::GenericAffExpr{V, K}, x::K) where {K, V} + return get(ex.terms, x, zero(V)) +end + +function Base.getindex(ex::GenericAffExpr{V, K}, x) where {K, V} + return 0.0 +end \ No newline at end of file diff --git a/src/results/formulas.jl b/src/results/formulas.jl index 726a0868..3f9c160a 100644 --- a/src/results/formulas.jl +++ b/src/results/formulas.jl @@ -520,6 +520,32 @@ function (f::SumHourly{3})(data, table, idxs, yr_idxs, hr_idxs) _sum_hourly(table[!, col1], table[!, col2], table[!, col3], idxs, yr_idxs, hr_idxs) end +@doc raw""" + SumHourlyWeighted(cols...) <: Function + +This is a function that adds up the product of each of the values given to it times the hour weight for each of the years and hours given. + +```math +\sum_{i \in \text{idxs}} \sum_{y \in \text{yr\_idxs}} \sum_{h \in \text{hr\_idxs}} w_{h} \prod_{c \in \text{cols}} \text{table}[i, c][y, h] +``` +""" +struct SumHourlyWeighted{N} <: Function + cols::NTuple{N, Symbol} +end +SumHourlyWeighted(cols::Symbol...) = SumHourlyWeighted(cols) +export SumHourlyWeighted + +function (f::SumHourlyWeighted{1})(data, table, idxs, yr_idxs, hr_idxs) + col1, = f.cols + hc = data[:hours_container]::HoursContainer + _sum_hourly(table[!, col1], hc, idxs, yr_idxs, hr_idxs) +end +function (f::SumHourlyWeighted{2})(data, table, idxs, yr_idxs, hr_idxs) + col1,col2 = f.cols + hc = data[:hours_container]::HoursContainer + _sum_hourly(table[!, col1], table[!, col2], hc, idxs, yr_idxs, hr_idxs) +end + @doc raw""" AverageHourly(cols...) <: Function diff --git a/src/results/parse.jl b/src/results/parse.jl index 21e3b976..38439af8 100644 --- a/src/results/parse.jl +++ b/src/results/parse.jl @@ -11,8 +11,22 @@ function parse_results!(config, data, model) obj_scalar = config[:objective_scalar] - results_raw = Dict(k => (@info "Parsing Result $k"; value_or_shadow_price(v, obj_scalar)) for (k,v) in object_dictionary(model)) + od = object_dictionary(model) + + # Pull out all the shadow prices or values for each of the variables/constraints + results_raw = Dict(k => (@info "Parsing Result $k"; value_or_shadow_price(v, obj_scalar)) for (k,v) in od) results_raw[:cons_pgen_max] ./= 1000 + + # Gather each of the objective function coefficients + obj = model[:obj]::AffExpr + obj_coef = OrderedDict{Symbol, Any}() + for (k,v) in od + if v isa AbstractArray{<:VariableRef} + obj_coef[k] = map(x->obj[x], v) + end + end + obj_coef[:pcap_gen_inv_sim] = map(x->obj[x], model[:pcap_gen_inv_sim]) + results_raw[:obj_coef] = obj_coef # Empty the model now that we have retrieved all info, to save RAM and prevent the user from accidentally accessing un-scaled data. empty!(model) @@ -126,7 +140,7 @@ function parse_power_results!(config, data) # Weight things by hour as needed egen_bus = weight_hourly(data, pgen_bus) - ecap_gen = weight_hourly(data, repeat(pcap_gen, 1,1,nhr)) + ecap_gen = weight_hourly(data, pcap_gen) elserv_bus = weight_hourly(data, plserv_bus) elcurt_bus = weight_hourly(data, plcurt_bus) elnom_bus = weight_hourly(data, get_table_col(data, :bus, :plnom)) @@ -138,6 +152,11 @@ function parse_power_results!(config, data) eflow_out_bus = map(x-> max(x,0), eflow_bus) eflow_in_bus = map(x-> max(-x,0), eflow_bus) + obj_pcap_price_raw = res_raw[:obj_coef][:pcap_gen]::Array{Float64, 2} + obj_pcap_price = obj_pcap_price_raw ./ hours_per_year + obj_pgen_price_raw = res_raw[:obj_coef][:pgen_gen]::Array{Float64, 3} + obj_pgen_price = unweight_hourly(data, obj_pgen_price_raw) + obj_pcap_inv_price = res_raw[:obj_coef][:pcap_gen_inv_sim]::Vector{Float64} # Create new things as needed cf = pgen_gen ./ pcap_gen @@ -183,6 +202,9 @@ function parse_power_results!(config, data) add_table_col!(data, :gen, :pcap_inv_sim, pcap_gen_inv_sim, MWCapacity, "Total power generation capacity that was invested for the generator during the sim. (single value). Still the same even after retirement") add_table_col!(data, :gen, :ecap_inv_sim, ecap_gen_inv_sim, MWhCapacity, "Total annual power generation energy capacity that was invested for the generator during the sim. (pcap_inv_sim * hours per year) (single value). Still the same even after retirement") add_table_col!(data, :gen, :cf, cf, MWhGeneratedPerMWhCapacity, "Capacity Factor, or average power generation/power generation capacity, 0 when no generation") + add_table_col!(data, :gen, :obj_pcap_price, obj_pcap_price, DollarsPerMWCapacityPerHour, "Objective function coefficient, in dollars, for one hour of 1MW capacity") + add_table_col!(data, :gen, :obj_pgen_price, obj_pgen_price, DollarsPerMWhGenerated, "Objective function coefficient, in dollars, for one MWh of generation") + add_table_col!(data, :gen, :obj_pcap_inv_price, obj_pcap_inv_price, DollarsPerMWBuiltCapacity, "Objective function coefficient, in dollars, for one MW of capacity invested") # Add things to the branch table add_table_col!(data, :branch, :pflow, pflow_branch, MWFlow,"Average Power flowing through branch") diff --git a/src/results/results_formulas.csv b/src/results/results_formulas.csv index 7a185024..9bbc7435 100644 --- a/src/results/results_formulas.csv +++ b/src/results/results_formulas.csv @@ -3,9 +3,9 @@ gen,egen_total,SumHourly(egen),MWhGenerated,"Total energy generated, in MWh" gen,pgen_avg,AverageHourly(pgen),MWGenerated,Average power generation gen,pgen_min,MinHourly(pgen),MWGenerated,Minimum power generation in an hour gen,pgen_max,MaxHourly(pgen),MWGenerated,Maximum power generation in an hour -gen,ecap_total,SumHourly(ecap),MWhCapacity,"Total energy capacity, in MWh" +gen,ecap_total,SumHourlyWeighted(pcap),MWhCapacity,"Total energy capacity, in MWh" gen,pcap_total,AverageYearly(pcap),MWCapacity,"Average power capacity. If multiple years given, the average is taken." -gen,ecap_available_total,"SumHourly(ecap,af)",MWhCapacity,"Total available energy capacity, in MWh" +gen,ecap_available_total,"SumHourlyWeighted(pcap,af)",MWhCapacity,"Total available energy capacity, in MWh" gen,pcap_start_total,Sum(pcap0),MWCapacity,Starting power capacity. gen,pcap_built_total,SumYearly(pcap_built),MWCapacity,Total power capacity built. Ignores subsets of hours and returns the built capacity for the whole year(s). gen,pcap_retired_total,SumYearly(pcap_retired),MWCapacity,Total power capacity retired. Ignores subsets of hours and returns the retired capacity for the whole year(s). @@ -29,7 +29,7 @@ gen,electricity_revenue,"SumHourly(lmp_egen, egen)",Dollars,Revenue earned by ge gen,electricity_price,electricity_revenue / egen,Dollars,Average price earned by generators for the energy they served to the grid gen,vom_cost,"SumHourly(vom,egen)",Dollars,"Variable Operation and Maintenance paid, in dollars" gen,vom_per_mwh,vom_cost/egen_total,DollarsPerMWhGenerated,Generation-weighted average of variable operation and maintenance costs -gen,fom_cost,"SumHourly(fom,ecap)",Dollars,"Fixed Operation and Maintenance paid, in dollars" +gen,fom_cost,"SumHourlyWeighted(fom,pcap)",Dollars,"Fixed Operation and Maintenance paid, in dollars" gen,fom_per_mwh,fom_cost/egen_total,DollarsPerMWhGenerated,Fixed Operation and Maintenance paid per MWh of energy generated gen,capex_cost,"SumYearly(capex_obj, ecap_inv_sim)",Dollars,"Capital expenditures paid, in dollars, as seen by objective function" gen,capex_per_mwh,capex_cost/egen_total,DollarsPerMWhGenerated,Levelized capital expenditures paid per MWh of energy generated @@ -58,6 +58,8 @@ gen,total_cost_per_mwh,total_cost / egen_total,DollarsPerMWhGenerated,"Average c gen,going_forward_cost,variable_cost + fixed_cost,Dollars,Total going forward cost gen,net_total_revenue,electricity_revenue - total_cost,Dollars,"Net total revenue, including electricity revenue minus total cost" gen,cost_of_service_rebate,CostOfServiceRebate(),Dollars,"This is a specially calculated result, which the sum of net_total_revenue * reg_factor for each generator" +gen,obj_pcap_cost,"SumHourlyWeighted(pcap, obj_pcap_price)",Dollars,"Cost for pcap in the objective, including investment" +gen,obj_pgen_cost,"SumHourly(egen, obj_pgen_price)",Dollars,Cost for pgen in the objective bus,elnom_total,SumHourly(elnom),MWhLoad,Nominal load energy bus,elserv_total,SumHourly(elserv),MWhServed,Total load energy served bus,eflow_in_total,SumHourly(eflow_in),MWhFlow,Total energy flowing into all the buses in this region (not necessarily net flow into the region) diff --git a/test/testresultprocessing.jl b/test/testresultprocessing.jl index d73b745d..1508ea1e 100644 --- a/test/testresultprocessing.jl +++ b/test/testresultprocessing.jl @@ -23,6 +23,18 @@ @test data1 == data2 || data1 === data2 end + @testset "Test welfare calculations" begin + config = read_config(config_file) + data = read_data(config) + model = setup_model(config, data) + optimize!(model) + parse_results!(config, data, model) + + # Test that the objective values are the same as the accounting values, at least for this simplified example + @test compute_result(data, :gen, :obj_pgen_cost) ≈ compute_result(data, :gen, :variable_cost) + @test compute_result(data, :gen, :obj_pcap_cost) ≈ compute_result(data, :gen, :fixed_cost) + end + @testset "Test reading/saving model from .jls file" begin config = read_config(config_file) config[:base_out_path] = "../out/3bus1" From 97ee5b768f2544950db3f73840fcd17602748f4c Mon Sep 17 00:00:00 2001 From: Ethan Russell Date: Tue, 6 Jun 2023 17:28:42 -0400 Subject: [PATCH 05/21] Add more welfare calculations, results formulas and tests --- src/results/formulas.jl | 2 +- src/results/parse.jl | 16 +++++++++++--- src/results/process.jl | 31 +++++++++++++++++++++++++++ src/results/results_formulas.csv | 27 +++++++++++++++++------ src/results/welfare.jl | 10 ++++++--- src/types/modifications/Storage.jl | 6 +++--- test/data/3bus/aggregate_template.csv | 12 +++++------ test/testoptimizemodel.jl | 7 ++++++ test/testresultprocessing.jl | 4 ++-- 9 files changed, 91 insertions(+), 24 deletions(-) diff --git a/src/results/formulas.jl b/src/results/formulas.jl index 3f9c160a..90bd5c99 100644 --- a/src/results/formulas.jl +++ b/src/results/formulas.jl @@ -589,7 +589,7 @@ This is a special function that computes the sum of the net total revenue times struct CostOfServiceRebate <: Function end function (::CostOfServiceRebate)(data, table, idxs, yr_idxs, hr_idxs) reg_factor = table.reg_factor - return sum0(reg_factor[i] * compute_result(data, :gen, :net_total_revenue, i, yr_idxs, hr_idxs) for i in idxs) + return sum0(reg_factor[i] * compute_result(data, :gen, :net_total_revenue_prelim, i, yr_idxs, hr_idxs) for i in idxs) end export CostOfServiceRebate diff --git a/src/results/parse.jl b/src/results/parse.jl index 38439af8..09714f82 100644 --- a/src/results/parse.jl +++ b/src/results/parse.jl @@ -235,12 +235,22 @@ function parse_lmp_results!(config, data) # Add the LMP's to the results and to the bus table res_raw[:lmp_elserv_bus] = lmp_elserv - add_table_col!(data, :bus, :lmp_elserv, lmp_elserv, DollarsPerMWhServed,"Locational Marginal Price of Energy Served") + + # Compensate for line losses for lmp seen by consumers at buses. + if config[:line_loss_type] == "plserv" + line_loss_rate = config[:line_loss_rate]::Float64 + + # lmp_elserv is dollars per MWh before losses, so we need to inflate the cost to compensate + plserv_scalar = 1/(1-line_loss_rate) + add_table_col!(data, :bus, :lmp_elserv, lmp_elserv .* plserv_scalar, DollarsPerMWhServed,"Locational Marginal Price of Energy Served") + else + add_table_col!(data, :bus, :lmp_elserv, lmp_elserv, DollarsPerMWhServed,"Locational Marginal Price of Energy Served") + end # Add lmp to generators gen = get_table(data, :gen) - lmp_bus = get_table_col(data, :bus, :lmp_elserv) - lmp_gen = lmp_bus[gen.bus_idx] + bus_idxs = gen.bus_idx::Vector{Int64} + lmp_gen = [view(lmp_elserv, i, :, :) for i in bus_idxs] add_table_col!(data, :gen, :lmp_egen, lmp_gen, DollarsPerMWhServed, "Locational Marginal Price of Energy Served") # # Get the shadow price of the positive and negative branch power flow constraints ($/(MW incremental transmission)) diff --git a/src/results/process.jl b/src/results/process.jl index 0e5b2747..f8f8f5c1 100644 --- a/src/results/process.jl +++ b/src/results/process.jl @@ -10,6 +10,10 @@ function process_results!(config::OrderedDict, data::OrderedDict) modify_results!(mod, config, data) end + # Save the summary table and results formulas + save_summary_table(config, data) + save_results_formulas(config, data) + if get(config, :save_data_processed, true) serialize(get_out_path(config,"data_processed.jls"), data) end @@ -58,3 +62,30 @@ function process_results!(mod_file::String, out_path::String; processed=true) process_results!(config; processed) end export process_results! + +function save_summary_table(config, data) + st = get_table(data, :summary_table) + out_file = get_out_path(config, "summary_table.csv") + CSV.write(out_file, st) +end + + +function save_results_formulas(config, data) + table = DataFrame(; + table_name=Symbol[], + result_name=Symbol[], + formula=String[], + unit=Type[], + description = String[] + ) + results_formulas = get_results_formulas(data) + for (k,v) in results_formulas + (table_name, result_name) = k + formula = v.formula + unit = v.unit + description = v.description + push!(table, (;table_name, result_name, formula, unit, description)) + end + out_file = get_out_path(config, "results_formulas.csv") + CSV.write(out_file, table) +end \ No newline at end of file diff --git a/src/results/results_formulas.csv b/src/results/results_formulas.csv index 9bbc7435..bc19cc27 100644 --- a/src/results/results_formulas.csv +++ b/src/results/results_formulas.csv @@ -53,11 +53,20 @@ gen,production_cost,variable_cost + fixed_cost,Dollars,"Cost of production, incl gen,production_cost_per_mwh,production_cost / egen_total,DollarsPerMWhGenerated,"Average cost of production for a MWh of power, including variable and fixed costs" gen,net_production_cost,net_variable_cost + net_fixed_cost,Dollars,"Net cost of production, including fixed and variable costs minus investment and production subsidies" gen,net_production_cost_per_mwh,net_production_cost / egen_total,DollarsPerMWhGenerated,"Average net cost of producing a MWh of power, including fixed and variable costs minus investment and production subsidies" -gen,total_cost,net_production_cost,Dollars,"Total cost of production. Right now contains only net_production_cost, but may eventually contain past capex costs" +gen,gs_cost,0,Dollars,Cost from generation standards +gen,gs_cost_per_mwh,gs_cost / egen_total,DollarsPerMWhGenerated,"Average cost from generation standards, per MWh" +gen,pol_cost,gs_cost - invest_subsidy - production_subsidy,Dollars,Cost for all generators from all policy types. +gen,pol_cost_per_mwh,pol_cost / egen_total,DollarsPerMWhGenerated,"Average cost for all generators from all policy types, per MWh." +gen,total_cost_prelim,going_forward_cost,Dollars,"Total cost of production. Right now contains only going_forward_cost, but may eventually contain past capex costs" +gen,total_cost_prelim_per_mwh,total_cost / egen_total,DollarsPerMWhGenerated,"Average cost of producing a MWh of power. Right now contains only net_production_cost, but may eventually contain past capex costs" +gen,going_forward_cost,production_cost - pol_cost,Dollars,Total going forward cost +gen,net_total_revenue_prelim,electricity_revenue - total_cost_prelim,Dollars,"Preliminary net total revenue, including electricity revenue minus total cost, before adjusting for cost-of-service rebates" +gen,cost_of_service_rebate,CostOfServiceRebate(),Dollars,"This is a specially calculated result, which is the sum of net_total_revenue_prelim * reg_factor for each generator" +gen,total_cost,total_cost_prelim + cost_of_service_rebate,Dollars,"Total cost of production. Right now contains only going_forward_cost, but may eventually contain past capex costs" gen,total_cost_per_mwh,total_cost / egen_total,DollarsPerMWhGenerated,"Average cost of producing a MWh of power. Right now contains only net_production_cost, but may eventually contain past capex costs" -gen,going_forward_cost,variable_cost + fixed_cost,Dollars,Total going forward cost -gen,net_total_revenue,electricity_revenue - total_cost,Dollars,"Net total revenue, including electricity revenue minus total cost" -gen,cost_of_service_rebate,CostOfServiceRebate(),Dollars,"This is a specially calculated result, which the sum of net_total_revenue * reg_factor for each generator" +gen,net_total_revenue,net_total_revenue_prelim - cost_of_service_rebate,Dollars,Net total revenue after adjusting for the cost-of-service rebate +gen,net_variable_revenue,electricity_revenue - net_variable_cost - cost_of_service_rebate,Dollars,Net variable revenue including electiricy revenue minus net variable costs +gen,net_going_forward_revenue,electricity_revenue - going_forward_cost - cost_of_service_rebate,Dollars,"Net going forward revenue, including electricity revenue minus going forward cost" gen,obj_pcap_cost,"SumHourlyWeighted(pcap, obj_pcap_price)",Dollars,"Cost for pcap in the objective, including investment" gen,obj_pgen_cost,"SumHourly(egen, obj_pgen_price)",Dollars,Cost for pgen in the objective bus,elnom_total,SumHourly(elnom),MWhLoad,Nominal load energy @@ -65,7 +74,13 @@ bus,elserv_total,SumHourly(elserv),MWhServed,Total load energy served bus,eflow_in_total,SumHourly(eflow_in),MWhFlow,Total energy flowing into all the buses in this region (not necessarily net flow into the region) bus,eflow_out_total,SumHourly(eflow_out),MWhFlow,Total energy flowing out of all the buses in this region (not necessarily net flow out of the region) bus,elcurt_total,SumHourly(elcurt),MWhCurtailed,Total energy curtailed in this region +bus,plserv_max,MaxHourly(plserv),MWServed,Maximum hourly load power served in the region +bus,plserv_min,MinHourly(plserv),MWServed,Minimum hourly load power served in the region +bus,plnom_max,MaxHourly(plnom),MWLoad,Maximum nominal hourly load power in the region +bus,plnom_min,MinHourly(plnom),MWLoad,Minimum nominal hourly load power in the region +bus,plcurt_max,MaxHourly(plcurt),MWCurtailed,Maximum hourly load power curtailed in the region +bus,plcurt_min,MinHourly(plcurt),MWCurtailed,Minimum hourly load power curtailed in the region +bus,electricity_cost,"SumHourly(elserv,lmp_elserv)",Dollars,Total cost of electricity served +bus,electricity_price,electricity_cost / elserv_total,DollarsPerMWhServed,Average cost of electricity served branch,eflow_total,SumHourly(eflow),MWhFlow,Total energy flowing in this branch branch,pflow_hourly_min,MinHourly(pflow),MWFlow,Minimum sum of power flowing in these branches -bus,cost_elserv,"SumHourly(elserv,lmp_elserv)",Dollars,Total cost of electricity served -bus,price_elserv,cost_elserv / elserv_total,DollarsPerMWhServed,Average cost of electricity served diff --git a/src/results/welfare.jl b/src/results/welfare.jl index c08f5871..1866f95a 100644 --- a/src/results/welfare.jl +++ b/src/results/welfare.jl @@ -8,9 +8,13 @@ function setup_welfare!(config, data) data[:welfare] = welfare # Producer welfare - add_welfare_term!(data, :producer, :gen, :variable_cost, -) - add_welfare_term!(data, :producer, :gen, :fixed_cost, -) - add_welfare_term!(data, :producer, :gen, :electricity_revenue, +) + add_welfare_term!(data, :producer, :gen, :net_total_revenue_prelim, +) + add_welfare_term!(data, :producer, :gen, :cost_of_service_rebate, -) + + # Consumer welfare + add_welfare_term!(data, :consumer, :gen, :cost_of_service_rebate, +) + add_welfare_term!(data, :consumer, :bus, :electricity_cost, -) + # Make sure to have a term for policy costs that would get transferred to consumers, for policies like nuclear preservation, installed reserve margins, portfolio standards # TODO: Add transfer for CO2 paid diff --git a/src/types/modifications/Storage.jl b/src/types/modifications/Storage.jl index 8608402a..48a77d73 100644 --- a/src/types/modifications/Storage.jl +++ b/src/types/modifications/Storage.jl @@ -468,9 +468,6 @@ function modify_results!(mod::Storage, config, data) add_table_col!(data, :storage, :ecap_inv_sim, ecap_inv_sim, MWhCapacity, "Total yearly energy discharge capacity that was invested for the generator during the sim. (pcap_inv_sim * hours per year) (single value). Still the same even after retirement") - add_results_formula!(data, :storage, :pcap_total, "AverageYearly(pcap)", MWCapacity, "Total discharge power capacity (if multiple years given, calculates the average)") - add_results_formula!(data, :storage, :echarge_total, "SumHourly(echarge)", MWhCharged, "Total energy charged") - add_results_formula!(data, :storage, :edischarge_total, "SumHourly(edischarge)", MWhDischarged, "Total energy discharged") transform!(storage, [:pcharge, :storage_efficiency] => ByRow((p,η) -> p * (1 - η)) => :ploss @@ -480,6 +477,9 @@ function modify_results!(mod::Storage, config, data) eloss = weight_hourly(data, storage.ploss) add_table_col!(data, :storage, :eloss, eloss, MWhServed, "Energy that was lost by the battery, counted as served load") + add_results_formula!(data, :storage, :pcap_total, "AverageYearly(pcap)", MWCapacity, "Total discharge power capacity (if multiple years given, calculates the average)") + add_results_formula!(data, :storage, :echarge_total, "SumHourly(echarge)", MWhCharged, "Total energy charged") + add_results_formula!(data, :storage, :edischarge_total, "SumHourly(edischarge)", MWhDischarged, "Total energy discharged") add_results_formula!(data, :storage, :eloss_total, "SumHourly(eloss)", MWhLoss, "Total energy loss") update_build_status!(config, data, :storage) diff --git a/test/data/3bus/aggregate_template.csv b/test/data/3bus/aggregate_template.csv index d4ccb122..f8c1ce58 100644 --- a/test/data/3bus/aggregate_template.csv +++ b/test/data/3bus/aggregate_template.csv @@ -14,12 +14,12 @@ gen,cf_avg,genfuel=>solar,,, gen,cf_avg,genfuel=>wind,,, gen,cf_avg,genfuel=>coal,,, gen,cf_avg,genfuel=>nuclear,,, -bus,price_elserv,country=>narnia,y2030,season=>summer, -bus,price_elserv,country=>narnia,y2030,season=>winter, -bus,price_elserv,country=>narnia,y2035,season=>summer, -bus,price_elserv,country=>narnia,y2035,season=>winter, -bus,price_elserv,country=>narnia,y2040,season=>summer, -bus,price_elserv,country=>narnia,y2040,season=>winter, +bus,electricity_price,country=>narnia,y2030,season=>summer, +bus,electricity_price,country=>narnia,y2030,season=>winter, +bus,electricity_price,country=>narnia,y2035,season=>summer, +bus,electricity_price,country=>narnia,y2035,season=>winter, +bus,electricity_price,country=>narnia,y2040,season=>summer, +bus,electricity_price,country=>narnia,y2040,season=>winter, gen,vom_cost,genfuel=>ng,,, gen,vom_cost,genfuel=>solar,,, gen,vom_cost,genfuel=>wind,,, diff --git a/test/testoptimizemodel.jl b/test/testoptimizemodel.jl index f8dd00ba..78fed23b 100644 --- a/test/testoptimizemodel.jl +++ b/test/testoptimizemodel.jl @@ -25,6 +25,13 @@ @test all(p->abs(p)<1e-6, total_elcurt) end + @testset "Test bus results match gen results" begin + # Test that revenue of electricity for generators equals the cost for consumers + line_loss_rate = config[:line_loss_rate] + @test compute_result(data, :bus, :elserv_total) ≈ (compute_result(data, :gen, :egen_total)) * (1 - line_loss_rate) + @test compute_result(data, :bus, :electricity_cost) ≈ compute_result(data, :gen, :electricity_revenue) + end + @testset "Test DC lines" begin res_raw = get_raw_results(data) @test haskey(data, :dc_line) diff --git a/test/testresultprocessing.jl b/test/testresultprocessing.jl index 1508ea1e..644c22f5 100644 --- a/test/testresultprocessing.jl +++ b/test/testresultprocessing.jl @@ -140,8 +140,8 @@ @test 0 <= compute_result(data, :gen, :cf_avg, :gentype=>"solar", :, :) <= compute_result(data, :gen, :af_avg, :gentype=>"solar", :, :) # Test that the average LMP times energy served equals the sum of LMP - elec_cost = compute_result(data, :bus, :cost_elserv) - elec_price = compute_result(data, :bus, :price_elserv) + elec_cost = compute_result(data, :bus, :electricity_cost) + elec_price = compute_result(data, :bus, :electricity_price) elec_quantity = compute_result(data, :bus, :elserv_total) @test elec_cost ≈ elec_price * elec_quantity From 9fe808bf619551602273d227ebe9b024525c1275 Mon Sep 17 00:00:00 2001 From: Ethan Russell Date: Wed, 7 Jun 2023 15:17:58 -0400 Subject: [PATCH 06/21] Add CCUS costs to welfare --- src/results/results_formulas.csv | 5 +++-- src/results/welfare.jl | 9 +++------ src/types/modifications/CCUS.jl | 5 ++++- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/results/results_formulas.csv b/src/results/results_formulas.csv index bc19cc27..1fc0deee 100644 --- a/src/results/results_formulas.csv +++ b/src/results/results_formulas.csv @@ -53,13 +53,14 @@ gen,production_cost,variable_cost + fixed_cost,Dollars,"Cost of production, incl gen,production_cost_per_mwh,production_cost / egen_total,DollarsPerMWhGenerated,"Average cost of production for a MWh of power, including variable and fixed costs" gen,net_production_cost,net_variable_cost + net_fixed_cost,Dollars,"Net cost of production, including fixed and variable costs minus investment and production subsidies" gen,net_production_cost_per_mwh,net_production_cost / egen_total,DollarsPerMWhGenerated,"Average net cost of producing a MWh of power, including fixed and variable costs minus investment and production subsidies" -gen,gs_cost,0,Dollars,Cost from generation standards +gen,gs_cost,0,Dollars,Cost for generators to buy credits from generation standards gen,gs_cost_per_mwh,gs_cost / egen_total,DollarsPerMWhGenerated,"Average cost from generation standards, per MWh" gen,pol_cost,gs_cost - invest_subsidy - production_subsidy,Dollars,Cost for all generators from all policy types. gen,pol_cost_per_mwh,pol_cost / egen_total,DollarsPerMWhGenerated,"Average cost for all generators from all policy types, per MWh." +gen,government_revenue,-invest_subsidy - production_subsidy,Dollars,Government revenue earned from generators +gen,going_forward_cost,production_cost - pol_cost,Dollars,Total going forward cost gen,total_cost_prelim,going_forward_cost,Dollars,"Total cost of production. Right now contains only going_forward_cost, but may eventually contain past capex costs" gen,total_cost_prelim_per_mwh,total_cost / egen_total,DollarsPerMWhGenerated,"Average cost of producing a MWh of power. Right now contains only net_production_cost, but may eventually contain past capex costs" -gen,going_forward_cost,production_cost - pol_cost,Dollars,Total going forward cost gen,net_total_revenue_prelim,electricity_revenue - total_cost_prelim,Dollars,"Preliminary net total revenue, including electricity revenue minus total cost, before adjusting for cost-of-service rebates" gen,cost_of_service_rebate,CostOfServiceRebate(),Dollars,"This is a specially calculated result, which is the sum of net_total_revenue_prelim * reg_factor for each generator" gen,total_cost,total_cost_prelim + cost_of_service_rebate,Dollars,"Total cost of production. Right now contains only going_forward_cost, but may eventually contain past capex costs" diff --git a/src/results/welfare.jl b/src/results/welfare.jl index 1866f95a..5ad22398 100644 --- a/src/results/welfare.jl +++ b/src/results/welfare.jl @@ -14,15 +14,12 @@ function setup_welfare!(config, data) # Consumer welfare add_welfare_term!(data, :consumer, :gen, :cost_of_service_rebate, +) add_welfare_term!(data, :consumer, :bus, :electricity_cost, -) + add_welfare_term!(data, :consumer, :gen, :gs_cost, +) # Make sure to have a term for policy costs that would get transferred to consumers, for policies like nuclear preservation, installed reserve margins, portfolio standards - # TODO: Add transfer for CO2 paid - - # Consumer welfare - # Government welfare - - + add_welfare_term!(data, :government, :gen, :government_revenue, +) + # Make sure that emissions caps and prices get added to govt. revenue and production cost. end export setup_welfare! diff --git a/src/types/modifications/CCUS.jl b/src/types/modifications/CCUS.jl index 70e5f6dd..1ad8acca 100644 --- a/src/types/modifications/CCUS.jl +++ b/src/types/modifications/CCUS.jl @@ -463,7 +463,10 @@ function modify_results!(mod::CCUS, config, data) add_results_formula!(data, :ccus_paths, :storer_cost_per_short_ton, "storer_cost_total/stored_co2_total", Dollars, "Average storage cost of CCUS per short ton via this pathway, from the perspective of the sequesterer") add_results_formula!(data, :ccus_paths, :storer_revenue_per_short_ton, "storer_revenue_total/stored_co2_total", Dollars, "Total revenue earned from storage for CCUS per short ton via this pathway. This is the amount paid by the EGU's to the sequesterer, equal to the clearing price minus the transport cost.") add_results_formula!(data, :ccus_paths, :storer_profit_per_short_ton, "storer_profit_total/stored_co2_total", Dollars, "Total profit earned from storing a short ton of CO2 via this pathway, equal to the revenue minus the cost.") - + + # Adjust welfare + add_to_results_formula!(data, :gen, :production_cost, "cost_capt_co2") # this gets added to producer welfare + add_welfare_term!(data, :sequesterer, :ccus_paths, :storer_profit_total, +) # Throw error message if there are profits ≥ 0. all(v->all(>=(0), v), ccus_paths.storer_profit) || @warn "All CCUS profits should be ≥ 0, but found $(minimum(minimum, ccus_paths.storer_profit))" From 659a69f3374be56c5673787e4568feeb56be4e56 Mon Sep 17 00:00:00 2001 From: Ethan Russell Date: Wed, 7 Jun 2023 16:55:12 -0400 Subject: [PATCH 07/21] Add policies to welfare --- src/results/formulas.jl | 4 ++-- src/results/results_formulas.csv | 8 ++++++-- src/types/modifications/GenerationStandard.jl | 7 ++++--- src/types/policies/EmissionCap.jl | 6 ++++-- src/types/policies/EmissionPrice.jl | 4 +++- src/types/policies/PTC.jl | 8 +++++++- 6 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/results/formulas.jl b/src/results/formulas.jl index 767484e8..a244c8ce 100644 --- a/src/results/formulas.jl +++ b/src/results/formulas.jl @@ -98,13 +98,13 @@ end export add_results_formula! """ - add_to_results_formula!(data, table_name::Symbol, result_name::Symbol, formula::String) + add_to_results_formula!(data, table_name::Symbol, result_name::Symbol, formula) Adds a term to an existing results formula. Can be more complex expressions. * if it is a derived formula (like `\"vom_cost + fom_cost\"`), then you can supply any expression to get added to the formula, like `\"-my_result_name / 2\"` * if it is a primary formula (like `\"SumHourly(col1, col2)\"`), then you can provide additional columns like `\"col3, col4\"`. """ -function add_to_results_formula!(data, table_name::Symbol, result_name::Symbol, formula::String) +function add_to_results_formula!(data, table_name::Symbol, result_name::Symbol, formula) rf = get_results_formula(data, table_name, result_name) formula_original = rf.formula if rf.isderived diff --git a/src/results/results_formulas.csv b/src/results/results_formulas.csv index 1fc0deee..c58da716 100644 --- a/src/results/results_formulas.csv +++ b/src/results/results_formulas.csv @@ -53,9 +53,13 @@ gen,production_cost,variable_cost + fixed_cost,Dollars,"Cost of production, incl gen,production_cost_per_mwh,production_cost / egen_total,DollarsPerMWhGenerated,"Average cost of production for a MWh of power, including variable and fixed costs" gen,net_production_cost,net_variable_cost + net_fixed_cost,Dollars,"Net cost of production, including fixed and variable costs minus investment and production subsidies" gen,net_production_cost_per_mwh,net_production_cost / egen_total,DollarsPerMWhGenerated,"Average net cost of producing a MWh of power, including fixed and variable costs minus investment and production subsidies" -gen,gs_cost,0,Dollars,Cost for generators to buy credits from generation standards +gen,gs_cost,0,Dollars,Cost for load serving entities to buy credits from generators for all generation standards gen,gs_cost_per_mwh,gs_cost / egen_total,DollarsPerMWhGenerated,"Average cost from generation standards, per MWh" -gen,pol_cost,gs_cost - invest_subsidy - production_subsidy,Dollars,Cost for all generators from all policy types. +gen,emission_cap_cost,0,Dollars,Cost for paying for allowances for all emissions caps. +gen,emission_cap_cost_per_mwh,emission_cap_cost / egen_total,DollarsPerMWhGenerated,"Average cost, per MWh, for paying for allowances from all emission caps" +gen,emission_cost,0,Dollars,Cost for paying all emissions prices. +gen,emission_cost_per_mwh,emission_cost / egen_total,DollarsPerMWhGenerated,"Average cost, per MWh, for paying emission prices" +gen,pol_cost,-gs_cost - invest_subsidy - production_subsidy,Dollars,Cost for all generators from all policy types. gen,pol_cost_per_mwh,pol_cost / egen_total,DollarsPerMWhGenerated,"Average cost for all generators from all policy types, per MWh." gen,government_revenue,-invest_subsidy - production_subsidy,Dollars,Government revenue earned from generators gen,going_forward_cost,production_cost - pol_cost,Dollars,Total going forward cost diff --git a/src/types/modifications/GenerationStandard.jl b/src/types/modifications/GenerationStandard.jl index 86a31914..ba2e95c5 100644 --- a/src/types/modifications/GenerationStandard.jl +++ b/src/types/modifications/GenerationStandard.jl @@ -173,14 +173,15 @@ function modify_results!(pol::GenerationStandard, config, data) # set to shadow_prc * crediting for i in gen_idxs - gen[i, Symbol("$(pol.name)_prc")] = abs.(shadow_prc) .* gen[i, pol.name] + gen[i, Symbol("$(pol.name)_prc")] = -(shadow_prc) .* gen[i, pol.name] end # policy cost, price * credit * generation prc_name = Symbol("$(pol.name)_prc") - add_results_formula!(data, :gen, Symbol("$(pol.name)_cost"), "SumHourly($(prc_name), egen)", Dollars, "Cost of $(pol.name) based on the shadow price on the constraint and the generator credit level.") - + cost_name = Symbol("$(pol.name)_cost") + add_results_formula!(data, :gen, cost_name, "SumHourly($(prc_name), egen)", Dollars, "Cost of $(pol.name) based on the shadow price on the constraint and the generator credit level.") + add_to_results_formula!(data, :gen, :gs_cost, cost_name) end export modify_results! diff --git a/src/types/policies/EmissionCap.jl b/src/types/policies/EmissionCap.jl index 4117c0ea..7f46713c 100644 --- a/src/types/policies/EmissionCap.jl +++ b/src/types/policies/EmissionCap.jl @@ -46,12 +46,14 @@ function E4ST.modify_results!(pol::EmissionCap, config, data) # create column for per MWh price of the policy in :gen shadow_prc = get_shadow_price_as_ByYear(data, Symbol("cons_$(pol.name)_max")) #($/EmissionsUnit) - prc_col = [abs.(shadow_prc) .* g[pol.name] .* g[pol.emis_col] for g in eachrow(gen)] #($/MWh Generated) + prc_col = [(-shadow_prc) .* g[pol.name] .* g[pol.emis_col] for g in eachrow(gen)] #($/MWh Generated) add_table_col!(data, :gen, Symbol("$(pol.name)_prc"), prc_col, DollarsPerMWhGenerated, "Shadow price of $(pol.name) converted to DollarsPerMWhGenerated") # policy cost, shadow price (per MWh generated) * generation - add_results_formula!(data, :gen, Symbol("$(pol.name)_cost"), "SumHourly($(pol.name)_prc, egen)", Dollars, "The cost of $(pol.name) based on the shadow price of the generation constraint") + cost_name = Symbol("$(pol.name)_cost") + add_results_formula!(data, :gen, cost_name, "SumHourly($(pol.name)_prc, egen)", Dollars, "The cost of $(pol.name) based on the shadow price of the generation constraint") + add_to_results_formula!(data, :gen, :emission_cap_cost, cost_name) end """ diff --git a/src/types/policies/EmissionPrice.jl b/src/types/policies/EmissionPrice.jl index e54ff66a..3acca7d5 100644 --- a/src/types/policies/EmissionPrice.jl +++ b/src/types/policies/EmissionPrice.jl @@ -57,7 +57,9 @@ end """ function E4ST.modify_results!(pol::EmissionPrice, config, data) # policy cost, price per mwh * generation - add_results_formula!(data, :gen, Symbol("$(pol.name)_cost"), "SumHourly($(pol.name), egen)", Dollars, "The cost of $(pol.name)") + cost_name = Symbol("$(pol.name)_cost") + add_results_formula!(data, :gen, cost_name, "SumHourly($(pol.name), egen)", Dollars, "The cost of $(pol.name)") + add_to_results_formula!(data, :gen, :emission_cost, cost_name) #add_results_formula!(data, :gen, Symbol("$(pol.name)_qual_gen"), "SumHourly($(pol.name),egen)", Dollars, "The cost of $(pol.name)") end \ No newline at end of file diff --git a/src/types/policies/PTC.jl b/src/types/policies/PTC.jl index c96ebe30..c9b25d9e 100644 --- a/src/types/policies/PTC.jl +++ b/src/types/policies/PTC.jl @@ -86,7 +86,13 @@ Calculates PTC policy cost as a results formula in the gen table. PTC Cost = PTC """ function E4ST.modify_results!(pol::PTC, config, data) # policy cost, PTC value * generation - add_results_formula!(data, :gen, Symbol("$(pol.name)_cost"), "SumHourly($(pol.name), egen)", Dollars, "The cost of $(pol.name)") + result_name = "$(pol.name)_cost" + result_name_sym = Symbol(result_name) + add_results_formula!(data, :gen, result_name_sym, "SumHourly($(pol.name), egen)", Dollars, "The cost of $(pol.name)") + add_to_results_formula!(data, :gen, :production_subsidy, result_name) + + add_results_formula!(data, :gen, Symbol("$(pol.name)_capex_adj_total"), "SumYearly(ecap_inv_sim, $(pol.name)_capex_adj)", Dollars, "The necessary investment-based objective function penalty for having the subsidy end before the economic lifetime.") + # Note there is no need to adjust welfare for the capex adjustment end From f616581a400924f3de3a530b279f51fe8b46076c Mon Sep 17 00:00:00 2001 From: Ethan Russell Date: Thu, 8 Jun 2023 12:50:53 -0400 Subject: [PATCH 08/21] Add many more results formulas for Storage --- src/results/formulas.jl | 14 ++++---- src/results/results_formulas.csv | 12 +++---- src/types/modifications/Storage.jl | 52 +++++++++++++++++++++++++++++- 3 files changed, 65 insertions(+), 13 deletions(-) diff --git a/src/results/formulas.jl b/src/results/formulas.jl index a244c8ce..2ab08736 100644 --- a/src/results/formulas.jl +++ b/src/results/formulas.jl @@ -40,7 +40,7 @@ function filter_results_formulas!(data) return isvalid else table = get_table(data, table_name) - invalid_cols = filter(col->!hasproperty(table, col), dependent_columns) + invalid_cols = filter(col->!hasproperty(table, col) && !haskey(data, col), dependent_columns) isvalid = isempty(invalid_cols) isvalid || @warn "Result $result_name for table $table_name cannot be computed because table does not have columns:\n $invalid_cols" return isvalid @@ -588,14 +588,16 @@ end """ - CostOfServiceRebate() <: Function + CostOfServiceRebate(table_name) <: Function -This is a special function that computes the sum of the net total revenue times the regulatory factor `reg_factor`. This only works for the gen table. +This is a special function that computes the sum of the net total revenue times the regulatory factor `reg_factor`. This only works for the gen table and storage table. """ -struct CostOfServiceRebate <: Function end -function (::CostOfServiceRebate)(data, table, idxs, yr_idxs, hr_idxs) +struct CostOfServiceRebate <: Function + table_name::Symbol +end +function (f::CostOfServiceRebate)(data, table, idxs, yr_idxs, hr_idxs) reg_factor = table.reg_factor - return sum0(reg_factor[i] * compute_result(data, :gen, :net_total_revenue_prelim, i, yr_idxs, hr_idxs) for i in idxs) + return sum0(reg_factor[i] * compute_result(data, f.table_name, :net_total_revenue_prelim, i, yr_idxs, hr_idxs) for i in idxs) end export CostOfServiceRebate diff --git a/src/results/results_formulas.csv b/src/results/results_formulas.csv index c58da716..e43ac7ed 100644 --- a/src/results/results_formulas.csv +++ b/src/results/results_formulas.csv @@ -41,7 +41,7 @@ gen,variable_cost,fuel_cost+vom_cost,Dollars,"Variable costs for operation, incl gen,variable_cost_per_mwh,variable_cost/egen_total,DollarsPerMWhGenerated,"Variable costs for operation, per MWh of generation. Includes fuel and vom" gen,production_subsidy,0,Dollars,Total production subsidy for generation gen,production_subsidy_per_mwh,production_subsidy / egen_total,DollarsPerMWhGenerated,Average production subsidy for a MWh of generation -gen,net_variable_cost,production_subsidy - variable_cost,Dollars,Total variable costs minus production subsidies +gen,net_variable_cost,variable_cost - production_subsidy,Dollars,Total variable costs minus production subsidies gen,net_variable_cost_per_mwh,net_variable_cost / egen_total,DollarsPerMWhGenerated,Average variable costs minus production subsidies for a MWh of energy gen,fixed_cost,capex_cost + fom_cost,Dollars,"Fixed costs, including capex (not just what the optimization saw) and fom" gen,fixed_cost_permw_perhr,fixed_cost/ecap_total,DollarsPerMWCapacityPerHour,Fixed costs per mw per hour @@ -59,15 +59,15 @@ gen,emission_cap_cost,0,Dollars,Cost for paying for allowances for all emissions gen,emission_cap_cost_per_mwh,emission_cap_cost / egen_total,DollarsPerMWhGenerated,"Average cost, per MWh, for paying for allowances from all emission caps" gen,emission_cost,0,Dollars,Cost for paying all emissions prices. gen,emission_cost_per_mwh,emission_cost / egen_total,DollarsPerMWhGenerated,"Average cost, per MWh, for paying emission prices" -gen,pol_cost,-gs_cost - invest_subsidy - production_subsidy,Dollars,Cost for all generators from all policy types. +gen,pol_cost,emission_cap_cost + emission_cost - gs_cost - invest_subsidy - production_subsidy,Dollars,Cost for all generators from all policy types. gen,pol_cost_per_mwh,pol_cost / egen_total,DollarsPerMWhGenerated,"Average cost for all generators from all policy types, per MWh." -gen,government_revenue,-invest_subsidy - production_subsidy,Dollars,Government revenue earned from generators -gen,going_forward_cost,production_cost - pol_cost,Dollars,Total going forward cost +gen,government_revenue,emission_cap_cost + emission_cost - invest_subsidy - production_subsidy,Dollars,Government revenue earned from generators +gen,going_forward_cost,production_cost + pol_cost,Dollars,Total going forward cost gen,total_cost_prelim,going_forward_cost,Dollars,"Total cost of production. Right now contains only going_forward_cost, but may eventually contain past capex costs" gen,total_cost_prelim_per_mwh,total_cost / egen_total,DollarsPerMWhGenerated,"Average cost of producing a MWh of power. Right now contains only net_production_cost, but may eventually contain past capex costs" gen,net_total_revenue_prelim,electricity_revenue - total_cost_prelim,Dollars,"Preliminary net total revenue, including electricity revenue minus total cost, before adjusting for cost-of-service rebates" -gen,cost_of_service_rebate,CostOfServiceRebate(),Dollars,"This is a specially calculated result, which is the sum of net_total_revenue_prelim * reg_factor for each generator" -gen,total_cost,total_cost_prelim + cost_of_service_rebate,Dollars,"Total cost of production. Right now contains only going_forward_cost, but may eventually contain past capex costs" +gen,cost_of_service_rebate,CostOfServiceRebate(gen),Dollars,"This is a specially calculated result, which is the sum of net_total_revenue_prelim * reg_factor for each generator" +gen,total_cost,total_cost_prelim + cost_of_service_rebate,Dollars,Total cost of production including the preliminary total cost and the cost of service rebate to consumers. gen,total_cost_per_mwh,total_cost / egen_total,DollarsPerMWhGenerated,"Average cost of producing a MWh of power. Right now contains only net_production_cost, but may eventually contain past capex costs" gen,net_total_revenue,net_total_revenue_prelim - cost_of_service_rebate,Dollars,Net total revenue after adjusting for the cost-of-service rebate gen,net_variable_revenue,electricity_revenue - net_variable_cost - cost_of_service_rebate,Dollars,Net variable revenue including electiricy revenue minus net variable costs diff --git a/src/types/modifications/Storage.jl b/src/types/modifications/Storage.jl index 48a77d73..198d17a0 100644 --- a/src/types/modifications/Storage.jl +++ b/src/types/modifications/Storage.jl @@ -458,6 +458,9 @@ function modify_results!(mod::Storage, config, data) echarge_stor = weight_hourly(data, pcharge_stor) edischarge_stor = weight_hourly(data, pdischarge_stor) + lmp_bus = get_table_col(data, :bus, :lmp_elserv) + bus_idxs = storage.bus_idx::Vector{Int64} + lmp_stor = [lmp_bus[i] for i in bus_idxs] add_table_col!(data, :storage, :pcap, pcap_stor, MWCapacity, "Power Discharge capacity of the storage device") add_table_col!(data, :storage, :pcharge, pcharge_stor, MWCharged, "Rate of charging, in MW") @@ -466,7 +469,7 @@ function modify_results!(mod::Storage, config, data) add_table_col!(data, :storage, :edischarge, edischarge_stor, MWhDischarged, "Energy that was discharged by the storage device") add_table_col!(data, :storage, :pcap_inv_sim, pcap_inv_sim, MWCapacity, "Total power discharge capacity that was invested for the generator during the sim. (single value). Still the same even after retirement") add_table_col!(data, :storage, :ecap_inv_sim, ecap_inv_sim, MWhCapacity, "Total yearly energy discharge capacity that was invested for the generator during the sim. (pcap_inv_sim * hours per year) (single value). Still the same even after retirement") - + add_table_col!(data, :storage, :lmp_e, lmp_stor, DollarsPerMWhDischarged, "Locational marginal price of electricity") transform!(storage, @@ -481,6 +484,53 @@ function modify_results!(mod::Storage, config, data) add_results_formula!(data, :storage, :echarge_total, "SumHourly(echarge)", MWhCharged, "Total energy charged") add_results_formula!(data, :storage, :edischarge_total, "SumHourly(edischarge)", MWhDischarged, "Total energy discharged") add_results_formula!(data, :storage, :eloss_total, "SumHourly(eloss)", MWhLoss, "Total energy loss") + + # Add electricity cost and revenue + add_results_formula!(data, :storage, :electricity_revenue, "SumHourly(lmp_e, edischarge)", Dollars, "Revenue from discharging electricity to the grid") + add_results_formula!(data, :storage, :electricity_cost, "SumHourly(lmp_e, echarge)", Dollars, "Cost of electricity to charge the storage units") + + # Add production costs + add_results_formula!(data, :storage, :vom_cost, "SumHourly(vom, edischarge)", Dollars, "Total variable operation and maintenance cost for discharging energy") + add_results_formula!(data, :storage, :vom_per_mwh, "vom_cost / edischarge_total", DollarsPerMWhDischarged, "Average variable operation and maintenance cost for discharging 1 MWh of energy") + add_results_formula!(data, :storage, :fom_cost, "SumHourlyWeighted(fom, pcap)", Dollars, "Total fixed operation and maintenance cost paid, in dollars") + add_results_formula!(data, :storage, :vom_per_mwh, "fom_cost / edischarge_total", DollarsPerMWhDischarged, "Average fixed operation and maintenance cost for discharging 1 MWh of energy") + add_results_formula!(data, :storage, :capex_cost, "SumYearly(capex_obj, ecap_inv_sim)", Dollars, "Total annualized capital expenditures paid, in dollars") + add_results_formula!(data, :storage, :capex_per_mwh, "capex_cost / edischarge_total", DollarsPerMWhDischarged, "Average capital cost for discharging 1 MWh of energy") + + # Variable costs + add_results_formula!(data, :storage, :variable_cost, "vom_cost", Dollars, "Total variable costs for operation, including vom. One day if storage has fuel, this could include fuel also") + add_results_formula!(data, :storage, :variable_cost_per_mwh, "variable_cost / edischarge_total", DollarsPerMWhDischarged, "Average variable costs for operation, including vom, for discharging 1MWh from storage. One day if storage has fuel, this could include fuel also") + add_results_formula!(data, :storage, :production_subsidy, "0", Dollars, "Total production subsidy for storage") + add_results_formula!(data, :storage, :production_subsidy_per_mwh, "production_subsidy / edischarge_total", DollarsPerMWhDischarged, "Average production subsidy for discharging 1 MWh from storage") + add_results_formula!(data, :storage, :net_variable_cost, "variable_cost - production_subsidy", Dollars, "Net variable costs for storage") + add_results_formula!(data, :storage, :net_variable_cost_per_mwh, "net_variable_cost / edischarge_total", DollarsPerMWhDischarged, "Average net variable costs per MWh of discharged energy") + + # Fixed costs + add_results_formula!(data, :storage, :fixed_cost, "capex_cost + fom_cost", Dollars, "Total fixed costs including capex and fom costs") + add_results_formula!(data, :storage, :fixed_cost_permw_perhr, "fixed_cost / ecap_total", DollarsPerMWCapacityPerHour, "Fixed costs, per MW per hour") + add_results_formula!(data, :storage, :invest_subsidy, "0", Dollars, "Investment subsidies to go to the producer") + add_results_formula!(data, :storage, :invest_subsidy_permw_perhr, "invest_subsidy / ecap_total", DollarsPerMWCapacityPerHour, "Investment subsidies per MW per hour") + add_results_formula!(data, :storage, :net_fixed_cost, "fixed_cost - invest_subsidy", Dollars, "Fixed costs minus investment subsidies") + add_results_formula!(data, :storage, :net_fixed_cost_permw_perhr, "net_fixed_cost / ecap_total", DollarsPerMWCapacityPerHour, "Average net fixed cost per MW per hour.") + + # Production costs + add_results_formula!(data, :storage, :production_cost, "variable_cost + fixed_cost", Dollars, "Cost of production, includes fixed and variable costs but not energy cost") + add_results_formula!(data, :storage, :production_cost_per_mwh, "production_cost / edischarge_total", DollarsPerMWhDischarged, "Average cost of production for a MWh of energy discharge, including variable and fixed costs but not energy cost") + add_results_formula!(data, :storage, :net_production_cost, "net_variable_cost + net_fixed_cost", Dollars, "Net cost of production, includes fixed and variable costs and investment and production subsidies, but not energy cost") + add_results_formula!(data, :storage, :net_production_cost_per_mwh, "net_production_cost / edischarge_total", DollarsPerMWhDischarged, "Average net cost of discharging 1 MWh of energy") + + # Policy costs + add_results_formula!(data, :storage, :pol_cost, "-invest_subsidy - production_subsidy", Dollars, "Cost from all policy types") + add_results_formula!(data, :storage, :pol_cost_per_mwh, "pol_cost / edischarge_total", DollarsPerMWhDischarged, "Average policy cost per MWh of discharged energy") + add_results_formula!(data, :storage, :government_revenue, "- invest_subsidy - production_subsidy", Dollars, "Government revenue earned from storage of energy") + add_results_formula!(data, :storage, :going_forward_cost, "production_cost + pol_cost", Dollars, "Total cost of production and policies") + add_results_formula!(data, :storage, :total_cost_prelim, "going_forward_cost", Dollars, "Total cost of production. Right now only includes going_forward_cost, but may eventually contain past capex cost") + add_results_formula!(data, :storage, :net_total_revenue_prelim, "electricity_revenue - electricity_cost - total_cost_prelim", Dollars, "Preliminary net total revenue, including electricity costs/revenue and total cost, before adjusting for cost-of-service rebates") + add_results_formula!(data, :storage, :cost_of_service_rebate, "CostOfServiceRebate(storage)", Dollars, "This is a specially calculated result, which is the sum of net_total_revenue_prelim * reg_factor for each generator") + add_results_formula!(data, :storage, :total_cost, "total_cost_prelim + cost_of_service_rebate", Dollars, "The total cost after adjusting for the cost of service") + add_results_formula!(data, :storage, :net_total_revenue, "net_total_revenue_prelim - cost_of_service_rebate", Dollars, "Net total revenue after adjusting for the cost-of-service rebate") + add_results_formula!(data, :storage, :net_going_forward_revenue, "electricity_revenue - net_variable_cost - cost_of_service_rebate", Dollars, "Net going forward revenue, including electricity revenue minus going forward cost") + update_build_status!(config, data, :storage) From ee9b654e4adfbfff2f56729102cb1db8d5d37f96 Mon Sep 17 00:00:00 2001 From: Ethan Russell Date: Fri, 9 Jun 2023 08:50:49 -0400 Subject: [PATCH 09/21] Do not filter retired generators that are still within their econ life --- src/results/parse.jl | 19 +++++++++++++++++-- src/results/process.jl | 9 ++++++++- src/results/results_formulas.csv | 9 +++++---- src/types/modifications/Storage.jl | 28 ++++++++++++++++++++++++++-- test/testoptimizemodel.jl | 2 ++ 5 files changed, 58 insertions(+), 9 deletions(-) diff --git a/src/results/parse.jl b/src/results/parse.jl index 69ca6e31..697fd55e 100644 --- a/src/results/parse.jl +++ b/src/results/parse.jl @@ -301,6 +301,9 @@ export parse_lmp_results! Save the `gen` table to `get_out_path(config, "gen.csv")` """ function save_updated_gen_table(config, data) + years = get_years(data) + year_end = last(years) + gen = get_table(data, :gen) original_cols = data[:gen_table_original_cols] @@ -322,9 +325,21 @@ function save_updated_gen_table(config, data) # Filter anything with capacity below the threshold thresh = config[:pcap_retirement_threshold] - filter!(:pcap0 => >(thresh), gen_tmp) + filter!(gen_tmp) do row + # Keep anything above the threshold + row.pcap0 > thresh && return true + row.pcap_inv <= thresh && return false + + row.build_type == "exog" && return false + + # Below the threshold, check to see if we are still within the economic lifetime + year_econ_life = add_to_year(row.year_on, row.econ_life) + year_econ_life > year_end && return true + + return false + end - # Combine generators that are the same + # Combine generators that are the same. This is for things like ccus that get split up. gdf = groupby(gen_tmp, Not(:pcap0)) gen_tmp_combined = combine(gdf, :pcap0 => sum => :pcap0 diff --git a/src/results/process.jl b/src/results/process.jl index f8f8f5c1..0be6d12b 100644 --- a/src/results/process.jl +++ b/src/results/process.jl @@ -64,7 +64,14 @@ end export process_results! function save_summary_table(config, data) - st = get_table(data, :summary_table) + table = get_table(data, :summary_table) + + st = filter(row->has_table(data, row.table_name) && hasproperty(get_table(data, row.table_name), row.column_name), table) + + for row in eachrow(st) + row.data_type = eltype(get_table_col(data, row.table_name, row.column_name)) + end + out_file = get_out_path(config, "summary_table.csv") CSV.write(out_file, st) end diff --git a/src/results/results_formulas.csv b/src/results/results_formulas.csv index e43ac7ed..b0f493e7 100644 --- a/src/results/results_formulas.csv +++ b/src/results/results_formulas.csv @@ -27,12 +27,12 @@ gen,capt_co2_rate,capt_co2_total/egen_total,ShortTonsPerMWhGenerated,Average rat gen,af_avg,ecap_available_total / ecap_total,MWhGeneratedPerMWhCapacity,Average availability factor (i.e. energy capacity available / energy capacity) gen,electricity_revenue,"SumHourly(lmp_egen, egen)",Dollars,Revenue earned by generators for the energy they served to the grid gen,electricity_price,electricity_revenue / egen,Dollars,Average price earned by generators for the energy they served to the grid -gen,vom_cost,"SumHourly(vom,egen)",Dollars,"Variable Operation and Maintenance paid, in dollars" +gen,vom_cost,"SumHourly(vom,egen)",Dollars,"Variable Operation and Maintenance cost incurred, in dollars" gen,vom_per_mwh,vom_cost/egen_total,DollarsPerMWhGenerated,Generation-weighted average of variable operation and maintenance costs -gen,fom_cost,"SumHourlyWeighted(fom,pcap)",Dollars,"Fixed Operation and Maintenance paid, in dollars" +gen,fom_cost,"SumHourlyWeighted(fom,pcap)",Dollars,"Fixed Operation and Maintenance cost incurred, in dollars" gen,fom_per_mwh,fom_cost/egen_total,DollarsPerMWhGenerated,Fixed Operation and Maintenance paid per MWh of energy generated -gen,capex_cost,"SumYearly(capex_obj, ecap_inv_sim)",Dollars,"Capital expenditures paid, in dollars, as seen by objective function" -gen,capex_per_mwh,capex_cost/egen_total,DollarsPerMWhGenerated,Levelized capital expenditures paid per MWh of energy generated +gen,capex_cost,"SumYearly(capex_obj, ecap_inv_sim)",Dollars,"Capital expenditures, in dollars, as seen by objective function" +gen,capex_per_mwh,capex_cost/egen_total,DollarsPerMWhGenerated,Levelized capital expenditures per MWh of energy generated gen,fuel_cost,"SumHourly(fuel_price,heat_rate,egen)",Dollars,Total cost of fuel gen,fuel_price_per_mwh,fuel_cost/egen_total,DollarsPerMWhGenerated,Fuel price per MWh generated gen,fuel_burned,"SumHourly(heat_rate,egen)",MMBtu,Amount of fuel burned @@ -89,3 +89,4 @@ bus,electricity_cost,"SumHourly(elserv,lmp_elserv)",Dollars,Total cost of electr bus,electricity_price,electricity_cost / elserv_total,DollarsPerMWhServed,Average cost of electricity served branch,eflow_total,SumHourly(eflow),MWhFlow,Total energy flowing in this branch branch,pflow_hourly_min,MinHourly(pflow),MWFlow,Minimum sum of power flowing in these branches +branch,pflow_hourly_max,MaxHourly(pflow),MWFlow,Maximum sum of power flowing in these branches diff --git a/src/types/modifications/Storage.jl b/src/types/modifications/Storage.jl index 198d17a0..48364b34 100644 --- a/src/types/modifications/Storage.jl +++ b/src/types/modifications/Storage.jl @@ -531,9 +531,16 @@ function modify_results!(mod::Storage, config, data) add_results_formula!(data, :storage, :net_total_revenue, "net_total_revenue_prelim - cost_of_service_rebate", Dollars, "Net total revenue after adjusting for the cost-of-service rebate") add_results_formula!(data, :storage, :net_going_forward_revenue, "electricity_revenue - net_variable_cost - cost_of_service_rebate", Dollars, "Net going forward revenue, including electricity revenue minus going forward cost") + # Update Welfare + # Producer welfare + add_welfare_term!(data, :producer, :storage, :net_total_revenue_prelim, +) + add_welfare_term!(data, :producer, :storage, :cost_of_service_rebate, -) - update_build_status!(config, data, :storage) + # Consumer welfare + add_welfare_term!(data, :consumer, :storage, :cost_of_service_rebate, +) + # Update and save the storage table + update_build_status!(config, data, :storage) save_updated_storage_table(config, data) end export modify_results! @@ -544,6 +551,9 @@ export modify_results! Saves the updated storage table with any additional storage units, updated capacities, etc. """ function save_updated_storage_table(config, data) + years = get_years(data) + year_end = last(years) + storage = get_table(data, :storage) original_cols = data[:storage_table_original_cols] @@ -566,7 +576,21 @@ function save_updated_storage_table(config, data) # Filter anything with capacity below the threshold thresh = config[:pcap_retirement_threshold] - filter!(:pcap0 => >(thresh), storage_tmp) + + filter!(storage_tmp) do row + # Keep anything above the threshold + row.pcap0 > thresh && return true + row.pcap_inv <= thresh && return false + + row.build_type == "exog" && return false + + # Below the threshold, check to see if we are still within the economic lifetime + year_econ_life = add_to_year(row.year_on, row.econ_life) + year_econ_life > year_end && return true + + return false + end + storage_tmp.pcap_max = copy(storage_tmp.pcap0) diff --git a/test/testoptimizemodel.jl b/test/testoptimizemodel.jl index 78fed23b..e7d4a460 100644 --- a/test/testoptimizemodel.jl +++ b/test/testoptimizemodel.jl @@ -52,8 +52,10 @@ @test compute_result(data, :gen, :pcap_retired_total, [:build_type=>"endog"]) < 0.001 # Shouldn't be retiring endogenously built capacity. updated_gen_table = read_table(get_out_path(config, "gen.csv")) + @test ~any(row->(row.pcap_inv <= 0), eachrow(updated_gen_table)) + for row in eachrow(gen) if contains(row.build_status, "retired") @test row.year_off in get_years(data) From 189fcd5f367ffff2c95d6806a8455bde006e8a5d Mon Sep 17 00:00:00 2001 From: Ethan Russell Date: Fri, 9 Jun 2023 12:55:57 -0400 Subject: [PATCH 10/21] Fix ITC merge conflict --- src/types/policies/ITC.jl | 17 ----------------- src/types/policies/ITCStorage.jl | 2 ++ 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/src/types/policies/ITC.jl b/src/types/policies/ITC.jl index 89f2f55c..975b3f94 100644 --- a/src/types/policies/ITC.jl +++ b/src/types/policies/ITC.jl @@ -63,23 +63,6 @@ end Calculates ITC cost as seen by the objective (cost_obj) which is ITC value * capacity (where ITC value is credit level as a % multiplied by capital cost) """ -function E4ST.modify_results!(pol::ITC, config, data) - - # calculate objective policy cost (based on capacity in each sim year) - add_results_formula!(data, :gen, Symbol("$(pol.name)_cost_obj"), "SumYearly($(pol.name),ecap_inv_sim)", Dollars, "The cost of $(pol.name) as seen by the objective, not used for gov spending welfare") - #add_results_formula!(data, :gen, Symbol("$(pol.name)_cost_obj"), "SumHourly($(pol.name),ecap)", Dollars, "The cost of $(pol.name) as seen by the objective, not necessarily used for gov spending welfare") - - # for gen_idx in gen_idxs - # g = gen[gen_idx, :] - - # # credit yearly * capex_obj for that year, capex_obj is only non zero in year_on so ITC should only be non zero in year_on - # vals_tmp = [credit_yearly[i]*g.capex_obj.v[i] for i in 1:length(years)] - # gen[gen_idx, pol.name] = ByYear(vals_tmp) - # end - # data[:gen] = gen - add_obj_term!(data, model, PerMWCap(), pol.name, oper = -) -end - function E4ST.modify_results!(pol::ITC, config, data) total_result_name = "$(pol.name)_cost_obj" total_result_sym = Symbol(total_result_name) diff --git a/src/types/policies/ITCStorage.jl b/src/types/policies/ITCStorage.jl index cf7d34bd..b37174e2 100644 --- a/src/types/policies/ITCStorage.jl +++ b/src/types/policies/ITCStorage.jl @@ -99,4 +99,6 @@ function E4ST.modify_results!(pol::ITCStorage, config, data) # calculate welfare policy cost (obj policy cost spread over all years of investment represented by the sim years) # if using pol_cost_obj, update the description provided in add_results_forumla above + + add_to_results_formula!(data, :storage, :invest_subsidy, total_result_name) end \ No newline at end of file From 7b50a0c4c599a8b58988f18f5719b173abf7abad Mon Sep 17 00:00:00 2001 From: Ethan Russell Date: Fri, 9 Jun 2023 16:17:09 -0400 Subject: [PATCH 11/21] fix name in ITCStorage --- src/types/policies/ITCStorage.jl | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/types/policies/ITCStorage.jl b/src/types/policies/ITCStorage.jl index b37174e2..acb316ca 100644 --- a/src/types/policies/ITCStorage.jl +++ b/src/types/policies/ITCStorage.jl @@ -91,10 +91,13 @@ function E4ST.modify_results!(pol::ITCStorage, config, data) @warn "ITCStorage policy given, yet no storage defined. Consider adding a Storage modification." return end - + + total_result_name = "$(pol.name)_cost_obj" + total_result_sym = Symbol(total_result_name) + # calculate objective policy cost (based on capacity in each sim year) - add_results_formula!(data, :storage, Symbol("$(pol.name)_cost_obj"), "SumYearly($(pol.name),ecap_inv_sim)", Dollars, "The cost of $(pol.name) as seen by the objective, not used for gov spending welfare") + add_results_formula!(data, :storage, total_result_sym, "SumYearly($(pol.name),ecap_inv_sim)", Dollars, "The cost of $(pol.name) as seen by the objective, not used for gov spending welfare") #add_results_formula!(data, :gen, Symbol("$(pol.name)_cost_obj"), "SumHourly($(pol.name),ecap)", Dollars, "The cost of $(pol.name) as seen by the objective, not necessarily used for gov spending welfare") # calculate welfare policy cost (obj policy cost spread over all years of investment represented by the sim years) From cc582988c354a7e78f6fb1de6c105aac0dc2dc09 Mon Sep 17 00:00:00 2001 From: Ethan Russell Date: Fri, 9 Jun 2023 16:42:14 -0400 Subject: [PATCH 12/21] Add results formula for emission price investment cost adjustment --- src/types/policies/EmissionPrice.jl | 2 +- src/types/policies/PTC.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/types/policies/EmissionPrice.jl b/src/types/policies/EmissionPrice.jl index 54a6f7d3..f1b4b1d3 100644 --- a/src/types/policies/EmissionPrice.jl +++ b/src/types/policies/EmissionPrice.jl @@ -95,7 +95,7 @@ function E4ST.modify_results!(pol::EmissionPrice, config, data) add_results_formula!(data, :gen, cost_name, "SumHourly($(pol.name), egen)", Dollars, "The cost of $(pol.name)") add_to_results_formula!(data, :gen, :emission_cost, cost_name) - #add_results_formula!(data, :gen, Symbol("$(pol.name)_qual_gen"), "SumHourly($(pol.name),egen)", Dollars, "The cost of $(pol.name)") + should_adjust_invest_cost(pol) && add_results_formula!(data, :gen, Symbol("$(pol.name)_capex_adj_total"), "SumYearly(ecap_inv_sim, $(pol.name)_capex_adj)", Dollars, "The necessary investment-based objective function penalty for having the subsidy end before the economic lifetime.") end """ diff --git a/src/types/policies/PTC.jl b/src/types/policies/PTC.jl index bb5306b8..7e8505e6 100644 --- a/src/types/policies/PTC.jl +++ b/src/types/policies/PTC.jl @@ -104,7 +104,7 @@ function E4ST.modify_results!(pol::PTC, config, data) add_results_formula!(data, :gen, result_name_sym, "SumHourly($(pol.name), egen)", Dollars, "The cost of $(pol.name)") add_to_results_formula!(data, :gen, :production_subsidy, result_name) - add_results_formula!(data, :gen, Symbol("$(pol.name)_capex_adj_total"), "SumYearly(ecap_inv_sim, $(pol.name)_capex_adj)", Dollars, "The necessary investment-based objective function penalty for having the subsidy end before the economic lifetime.") + should_adjust_invest_cost(pol) && add_results_formula!(data, :gen, Symbol("$(pol.name)_capex_adj_total"), "SumYearly(ecap_inv_sim, $(pol.name)_capex_adj)", Dollars, "The necessary investment-based objective function penalty for having the subsidy end before the economic lifetime.") # Note there is no need to adjust welfare for the capex adjustment end From 0ad3f91aafa68396aabb08b0505ee8641f9fd243 Mon Sep 17 00:00:00 2001 From: Ethan Russell Date: Fri, 9 Jun 2023 16:56:36 -0400 Subject: [PATCH 13/21] Now the summarize model should be logging --- test/testresultprocessing.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/testresultprocessing.jl b/test/testresultprocessing.jl index 644c22f5..27bf6051 100644 --- a/test/testresultprocessing.jl +++ b/test/testresultprocessing.jl @@ -257,7 +257,7 @@ @testset "Test results processing from already-saved results" begin ### Run E4ST - out_path, _ = run_e4st(config_file) + out_path, _ = run_e4st(config_file, log_model_summary=true) # Now read the config from the out_path, with some results processing mods too. Could also add the mods manually here. mod_file= joinpath(@__DIR__, "config/config_res.yml") From 4a51e8c79cc4527dcb44ea82431945a2a9349f1b Mon Sep 17 00:00:00 2001 From: Ethan Russell Date: Mon, 12 Jun 2023 10:59:40 -0400 Subject: [PATCH 14/21] Add transmission capex and routine capex to the model --- benchmark/benchmark_helper.jl | 2 ++ src/io/data.jl | 21 ++++++++++------- src/model/dcopf.jl | 2 ++ src/results/parse.jl | 2 +- src/results/results_formulas.csv | 6 ++++- src/types/Unit.jl | 2 +- src/types/modifications/Storage.jl | 36 +++++++++++++++++++++++++---- src/types/policies/EmissionPrice.jl | 2 +- src/types/policies/ITC.jl | 2 +- src/types/policies/ITCStorage.jl | 2 +- src/types/policies/PTC.jl | 2 +- test/data/3bus/build_gen.csv | 16 ++++++------- test/data/3bus/build_storage.csv | 4 ++-- test/data/3bus/gen.csv | 12 +++++----- test/data/3bus/storage.csv | 4 ++-- test/testsetupmodel.jl | 9 +++++++- 16 files changed, 86 insertions(+), 38 deletions(-) diff --git a/benchmark/benchmark_helper.jl b/benchmark/benchmark_helper.jl index f536f6a9..2fce64e5 100644 --- a/benchmark/benchmark_helper.jl +++ b/benchmark/benchmark_helper.jl @@ -36,6 +36,8 @@ function make_random_inputs(;n_bus = 100, n_gen = 100, n_branch=100, n_af=100, n heat_rate = 10*rand(n_gen), fom = rand(n_gen), capex = rand(n_gen), + transmission_capex=rand(n_gen), + routine_capex=rand(n_gen), year_on = year2str.(rand(2000:2023, n_gen)), year_off = fill("y9999", n_gen), year_shutdown = fill("y9999", n_gen), diff --git a/src/io/data.jl b/src/io/data.jl index 3df2ee4f..25719705 100644 --- a/src/io/data.jl +++ b/src/io/data.jl @@ -441,14 +441,15 @@ function setup_table!(config, data, ::Val{:gen}) # set to capex for unbuilt generators in and after the year_on # set to 0 for already built capacity because capacity expansion isn't considered for existing generators capex_obj = Container[ByNothing(0.0) for i in 1:nrow(gen)] - for idx_g in 1:nrow(gen) + transmission_capex_obj = Container[ByNothing(0.0) for i in 1:nrow(gen)] + for (idx_g, g) in enumerate(eachrow(gen)) g = gen[idx_g,:] g.build_status == "unbuilt" || continue - g_capex_obj = [g.capex * (year >= g.year_on && year < add_to_year(g.year_on, g.econ_life)) for year in get_years(data)] - # g_capex_obj = [g.capex * (year == g.year_on) for year in get_years(data)] - capex_obj[idx_g] = ByYear(g_capex_obj) + capex_obj[idx_g] = ByYear([g.capex * (year >= g.year_on && year < add_to_year(g.year_on, g.econ_life)) for year in get_years(data)]) + transmission_capex_obj[idx_g] = ByYear([g.transmission_capex * (year >= g.year_on && year < add_to_year(g.year_on, g.econ_life)) for year in get_years(data)]) end - add_table_col!(data, :gen, :capex_obj, capex_obj, DollarsPerMWBuiltCapacity, "Hourly capital expenditures that is passed into the objective function. 0 for already built capacity") + add_table_col!(data, :gen, :capex_obj, capex_obj, DollarsPerMWBuiltCapacityPerHour, "Hourly capital expenditures that is passed into the objective function. 0 for already built capacity") + add_table_col!(data, :gen, :transmission_capex_obj, transmission_capex_obj, DollarsPerMWBuiltCapacityPerHour, "Hourly capital expenditures for transmission that is passed into the objective function. 0 for already built capacity") # capex_econ = Container[ByNothing(0.0) for i in 1:nrow(gen)] # for idx_g in 1:nrow(gen) @@ -456,7 +457,7 @@ function setup_table!(config, data, ::Val{:gen}) # g_capex = [g.capex * (year >= g.year_on && year < g.year_off) for year in get_years(data)] # Possibly change this to be based on economic lifetime # capex_econ[idx_g] = ByYear(g_capex) # end - # add_table_col!(data, :gen, :capex_econ, capex_econ, DollarsPerMWBuiltCapacity, "Hourly capital expenditures to be paid between year_on and year_off") + # add_table_col!(data, :gen, :capex_econ, capex_econ, DollarsPerMWBuiltCapacityPerHour, "Hourly capital expenditures to be paid between year_on and year_off") ### Add age column as by ByYear based on year_on @@ -677,7 +678,9 @@ function summarize_table(::Val{:gen}) (:fuel_price, Float64, DollarsPerMMBtu, false, "Fuel cost per MMBtu of fuel used. `heat_rate` column also necessary when supplying `fuel_price`"), (:heat_rate, Float64, MMBtuPerMWhGenerated, false, "Heat rate, or MMBtu of fuel consumed per MWh electricity generated (0 for generators that don't use combustion)"), (:fom, Float64, DollarsPerMWCapacityPerHour, true, "Hourly fixed operation and maintenance cost for a MW of generation capacity"), - (:capex, Float64, DollarsPerMWBuiltCapacity, false, "Hourly capital expenditures for a MW of generation capacity"), + (:capex, Float64, DollarsPerMWBuiltCapacityPerHour, true, "Hourly capital expenditures for a MW of generation capacity"), + (:transmission_capex, Float64, DollarsPerMWBuiltCapacityPerHour, true, "Hourly capital expenditures for the transmission supporting a MW of generation capacity"), + (:routine_capex, Float64, DollarsPerMWCapacityPerHour, true, "Routing capital expenditures for a MW of discharge capacity"), (:cf_min, Float64, MWhGeneratedPerMWhCapacity, false, "The minimum capacity factor, or operable ratio of power generation to capacity for the generator to operate. Take care to ensure this is not above the hourly availability factor in any of the hours, or else the model may be infeasible. Set to zero by default."), (:cf_max, Float64, MWhGeneratedPerMWhCapacity, false, "The maximum capacity factor, or operable ratio of power generation to capacity for the generator to operate"), (:cf_hist, Float64, MWhGeneratedPerMWhCapacity, false, "The historical capacity factor for the generator, or the gentype if no previous data is available. Primarily used to calculate estimate policy value (PTC and EmissionPrice capex_adj)"), @@ -778,7 +781,9 @@ function summarize_table(::Val{:build_gen}) (:vom, Float64, DollarsPerMWhGenerated, true, "Variable operation and maintenance cost per MWh of generation"), (:fuel_price, Float64, DollarsPerMMBtu, false, "Fuel cost per MMBtu of fuel used. `heat_rate` column also necessary when supplying `fuel_price`"), (:fom, Float64, DollarsPerMWCapacityPerHour, true, "Hourly fixed operation and maintenance cost for a MW of generation capacity"), - (:capex, Float64, DollarsPerMWBuiltCapacity, false, "Hourly capital expenditures for a MW of generation capacity"), + (:capex, Float64, DollarsPerMWBuiltCapacityPerHour, true, "Hourly capital expenditures for a MW of generation capacity"), + (:transmission_capex, Float64, DollarsPerMWBuiltCapacityPerHour, true, "Hourly capital expenditures for the transmission supporting a MW of generation capacity"), + (:routine_capex, Float64, DollarsPerMWCapacityPerHour, true, "Routing capital expenditures for a MW of discharge capacity"), (:cf_min, Float64, MWhGeneratedPerMWhCapacity, false, "The minimum capacity factor, or operable ratio of power generation to capacity for the generator to operate. Take care to ensure this is not above the hourly availability factor in any of the hours, or else the model may be infeasible. Set to zero by default."), (:cf_max, Float64, MWhGeneratedPerMWhCapacity, false, "The maximum capacity factor, or operable ratio of power generation to capacity for the generator to operate"), (:cf_hist, Float64, MWhGeneratedPerMWhCapacity, false, "The historical capacity factor for the generator or the gentype. Primarily used to calculate estimate policy value (PTC and EmissionPrice capex_adj)"), diff --git a/src/model/dcopf.jl b/src/model/dcopf.jl index e944b7ee..d9720fe1 100644 --- a/src/model/dcopf.jl +++ b/src/model/dcopf.jl @@ -153,6 +153,7 @@ function setup_dcopf!(config, data, model) end add_obj_term!(data, model, PerMWCap(), :fom, oper = +) + add_obj_term!(data, model, PerMWCap(), :routine_capex, oper = +) @expression(model, pcap_gen_inv_sim[gen_idx in axes(gen,1)], @@ -166,6 +167,7 @@ function setup_dcopf!(config, data, model) ) add_obj_term!(data, model, PerMWCapInv(), :capex_obj, oper = +) + add_obj_term!(data, model, PerMWCapInv(), :transmission_capex_obj, oper = +) # Curtailment Cost add_obj_term!(data, model, PerMWhCurtailed(), :curtailment_cost, oper = +) diff --git a/src/results/parse.jl b/src/results/parse.jl index 3429f448..47196b69 100644 --- a/src/results/parse.jl +++ b/src/results/parse.jl @@ -234,7 +234,7 @@ function parse_power_results!(config, data) add_table_col!(data, :gen, :cf, cf, MWhGeneratedPerMWhCapacity, "Capacity Factor, or average power generation/power generation capacity, 0 when no generation") add_table_col!(data, :gen, :obj_pcap_price, obj_pcap_price, DollarsPerMWCapacityPerHour, "Objective function coefficient, in dollars, for one hour of 1MW capacity") add_table_col!(data, :gen, :obj_pgen_price, obj_pgen_price, DollarsPerMWhGenerated, "Objective function coefficient, in dollars, for one MWh of generation") - add_table_col!(data, :gen, :obj_pcap_inv_price, obj_pcap_inv_price, DollarsPerMWBuiltCapacity, "Objective function coefficient, in dollars, for one MW of capacity invested") + add_table_col!(data, :gen, :obj_pcap_inv_price, obj_pcap_inv_price, DollarsPerMWBuiltCapacityPerHour, "Objective function coefficient, in dollars, for one MW of capacity invested") # Add things to the branch table add_table_col!(data, :branch, :pflow, pflow_branch, MWFlow,"Average Power flowing through branch") diff --git a/src/results/results_formulas.csv b/src/results/results_formulas.csv index b0f493e7..191e4641 100644 --- a/src/results/results_formulas.csv +++ b/src/results/results_formulas.csv @@ -31,8 +31,12 @@ gen,vom_cost,"SumHourly(vom,egen)",Dollars,"Variable Operation and Maintenance c gen,vom_per_mwh,vom_cost/egen_total,DollarsPerMWhGenerated,Generation-weighted average of variable operation and maintenance costs gen,fom_cost,"SumHourlyWeighted(fom,pcap)",Dollars,"Fixed Operation and Maintenance cost incurred, in dollars" gen,fom_per_mwh,fom_cost/egen_total,DollarsPerMWhGenerated,Fixed Operation and Maintenance paid per MWh of energy generated +gen,routine_capex_cost,"SumHourlyWeighted(routine_capex, pcap)",Dollars,"Routine capital expenditures incurred, in dollars" +gen,routine_capex_per_mwh,routine_capex_cost / egen_total,DollarsPerMWhGenerated,Routine capital expenditures incurred per MWh of energy generated gen,capex_cost,"SumYearly(capex_obj, ecap_inv_sim)",Dollars,"Capital expenditures, in dollars, as seen by objective function" gen,capex_per_mwh,capex_cost/egen_total,DollarsPerMWhGenerated,Levelized capital expenditures per MWh of energy generated +gen,transmission_capex_cost,"SumYearly(transmission_capex_obj, ecap_inv_sim)",Dollars,"Capital expenditures for transmission, in dollars, as seen by objective function" +gen,transmission_capex_per_mwh,transmission_capex_cost/egen_total,DollarsPerMWhGenerated,Levelized capital expenditures for transmission per MWh of energy generated gen,fuel_cost,"SumHourly(fuel_price,heat_rate,egen)",Dollars,Total cost of fuel gen,fuel_price_per_mwh,fuel_cost/egen_total,DollarsPerMWhGenerated,Fuel price per MWh generated gen,fuel_burned,"SumHourly(heat_rate,egen)",MMBtu,Amount of fuel burned @@ -43,7 +47,7 @@ gen,production_subsidy,0,Dollars,Total production subsidy for generation gen,production_subsidy_per_mwh,production_subsidy / egen_total,DollarsPerMWhGenerated,Average production subsidy for a MWh of generation gen,net_variable_cost,variable_cost - production_subsidy,Dollars,Total variable costs minus production subsidies gen,net_variable_cost_per_mwh,net_variable_cost / egen_total,DollarsPerMWhGenerated,Average variable costs minus production subsidies for a MWh of energy -gen,fixed_cost,capex_cost + fom_cost,Dollars,"Fixed costs, including capex (not just what the optimization saw) and fom" +gen,fixed_cost,capex_cost + fom_cost + routine_capex_cost + transmission_capex_cost,Dollars,"Fixed costs, including capex (not just what the optimization saw) and fom" gen,fixed_cost_permw_perhr,fixed_cost/ecap_total,DollarsPerMWCapacityPerHour,Fixed costs per mw per hour gen,invest_subsidy,0,Dollars,Investment subsidies to go to generators gen,invest_subsidy_permw_perhr,invest_subsidy / ecap_total,DollarsPerMWCapacityPerHour,Average investment subsidy per MW per hour diff --git a/src/types/Unit.jl b/src/types/Unit.jl index e9975ccd..886b9ec3 100644 --- a/src/types/Unit.jl +++ b/src/types/Unit.jl @@ -20,7 +20,7 @@ struct PoundsPerMWhGenerated <: Unit end; export PoundsPerMWhGenerated struct DollarsPerMWhServed <: Unit end; export DollarsPerMWhServed struct Dollars <: Unit end; export Dollars struct DollarsPerMWCapacityPerHour <: Unit end; export DollarsPerMWCapacityPerHour -struct DollarsPerMWBuiltCapacity <: Unit end; export DollarsPerMWBuiltCapacity +struct DollarsPerMWBuiltCapacityPerHour <: Unit end; export DollarsPerMWBuiltCapacityPerHour struct DollarsPerMWhGenerated <: Unit end; export DollarsPerMWhGenerated struct DollarsPerMWhDischarged <: Unit end; export DollarsPerMWhDischarged struct DollarsPerMWFlow <: Unit end; export DollarsPerMWFlow diff --git a/src/types/modifications/Storage.jl b/src/types/modifications/Storage.jl index 48364b34..3c12ebc9 100644 --- a/src/types/modifications/Storage.jl +++ b/src/types/modifications/Storage.jl @@ -76,7 +76,9 @@ function summarize_table(::Val{:storage}) (:pcap_max, Float64, MWCapacity, true, "Maximum nameplate power discharge capacity of the storage device"), (:vom, Float64, DollarsPerMWhGenerated, true, "Variable operation and maintenance cost per MWh of energy discharged"), (:fom, Float64, DollarsPerMWCapacityPerHour, true, "Hourly fixed operation and maintenance cost for a MW of discharge capacity"), - (:capex, Float64, DollarsPerMWBuiltCapacity, true, "Hourly capital expenditures for a MW of discharge capacity"), + (:capex, Float64, DollarsPerMWBuiltCapacityPerHour, true, "Hourly capital expenditures for a MW of discharge capacity"), + (:transmission_capex, Float64, DollarsPerMWBuiltCapacityPerHour, false, "Hourly capital expenditures for the transmission supporting a MW of discharge capacity"), + (:routine_capex, Float64, DollarsPerMWCapacityPerHour, true, "Routing capital expenditures for a MW of discharge capacity"), (:duration_discharge, Float64, Hours, true, "Number of hours to fully discharge the storage device, from full."), (:duration_charge, Float64, Hours, false, "Number of hours to fully charge the empty storage device from empty. (Defaults to equal `duration_discharge`)"), (:storage_efficiency, Float64, MWhDischargedPerMWhCharged, true, "The round-trip efficiency of the battery."), @@ -112,7 +114,9 @@ function summarize_table(::Val{:build_storage}) (:pcap_max, Float64, MWCapacity, true, "Maximum nameplate power discharge capacity of the storage device"), (:vom, Float64, DollarsPerMWhGenerated, true, "Variable operation and maintenance cost per MWh of energy discharged"), (:fom, Float64, DollarsPerMWCapacityPerHour, true, "Hourly fixed operation and maintenance cost for a MW of discharge capacity"), - (:capex, Float64, DollarsPerMWBuiltCapacity, true, "Hourly capital expenditures for a MW of discharge capacity"), + (:capex, Float64, DollarsPerMWBuiltCapacityPerHour, true, "Hourly capital expenditures for a MW of discharge capacity"), + (:transmission_capex, Float64, DollarsPerMWBuiltCapacityPerHour, true, "Hourly capital expenditures for the transmission supporting a MW of discharge capacity"), + (:routine_capex, Float64, DollarsPerMWCapacityPerHour, true, "Routing capital expenditures for a MW of discharge capacity"), (:duration_discharge, Float64, Hours, true, "Number of hours to fully discharge the storage device, from full."), (:duration_charge, Float64, Hours, false, "Number of hours to fully charge the empty storage device from empty. (Defaults to equal `duration_discharge`)"), (:storage_efficiency, Float64, MWhDischargedPerMWhCharged, true, "The round-trip efficiency of the device."), @@ -154,11 +158,13 @@ function modify_setup_data!(mod::Storage, config, data) ### Create capex_obj (the capex used in the optimization/objective function) # set to capex for unbuilt generators in the year_on # set to 0 for already built capacity because capacity expansion isn't considered for existing generators - add_table_col!(data, :storage, :capex_obj, Container[ByNothing(0.0) for i in 1:nrow(storage)], DollarsPerMWBuiltCapacity, "Hourly capital expenditures that is passed into the objective function. 0 for already built capacity") + add_table_col!(data, :storage, :capex_obj, Container[ByNothing(0.0) for i in 1:nrow(storage)], DollarsPerMWBuiltCapacityPerHour, "Hourly capital expenditures that is passed into the objective function. 0 for already built capacity") + add_table_col!(data, :storage, :transmission_capex_obj, Container[ByNothing(0.0) for i in 1:nrow(storage)], DollarsPerMWBuiltCapacityPerHour, "Hourly transmission capital expenditures that is passed into the objective function. 0 for already built capacity") for row in eachrow(storage) row.build_status == "unbuilt" || continue row.capex_obj = ByYear([row.capex * (year >= row.year_on && year < add_to_year(row.year_on, row.econ_life)) for year in years]) + row.transmission_capex_obj = ByYear([row.transmission_capex * (year >= row.year_on && year < add_to_year(row.year_on, row.econ_life)) for year in years]) end storage.num_intervals = fill(0, nrow(storage)) @@ -404,6 +410,14 @@ function modify_model!(mod::Storage, config, data, model) ) ) + @expression(model, + routine_capex_stor[yr_idx in 1:nyr], + sum( + pcap_stor[stor_idx, yr_idx] * get_table_num(data, :storage, :routine_capex, stor_idx, yr_idx, :) + for stor_idx in axes(storage,1) + ) + ) + @expression(model, @@ -424,10 +438,20 @@ function modify_model!(mod::Storage, config, data, model) for stor_idx in axes(storage,1) ) ) + @expression(model, + transmission_capex_obj_stor[yr_idx in 1:nyr], + sum( + pcap_stor_inv_sim[stor_idx] * get_table_num(data, :storage, :transmission_capex_obj, stor_idx, yr_idx, :) + for stor_idx in axes(storage,1) + ) + ) + add_obj_exp!(data, model, PerMWhGen(), :vom_stor, oper = +) add_obj_exp!(data, model, PerMWCap(), :fom_stor, oper = +) + add_obj_exp!(data, model, PerMWCap(), :routine_capex_stor, oper = +) add_obj_exp!(data, model, PerMWCapInv(), :capex_obj_stor, oper = +) + add_obj_exp!(data, model, PerMWCapInv(), :transmission_capex_obj_stor, oper = +) end """ @@ -493,9 +517,13 @@ function modify_results!(mod::Storage, config, data) add_results_formula!(data, :storage, :vom_cost, "SumHourly(vom, edischarge)", Dollars, "Total variable operation and maintenance cost for discharging energy") add_results_formula!(data, :storage, :vom_per_mwh, "vom_cost / edischarge_total", DollarsPerMWhDischarged, "Average variable operation and maintenance cost for discharging 1 MWh of energy") add_results_formula!(data, :storage, :fom_cost, "SumHourlyWeighted(fom, pcap)", Dollars, "Total fixed operation and maintenance cost paid, in dollars") - add_results_formula!(data, :storage, :vom_per_mwh, "fom_cost / edischarge_total", DollarsPerMWhDischarged, "Average fixed operation and maintenance cost for discharging 1 MWh of energy") + add_results_formula!(data, :storage, :fom_per_mwh, "fom_cost / edischarge_total", DollarsPerMWhDischarged, "Average fixed operation and maintenance cost for discharging 1 MWh of energy") + add_results_formula!(data, :storage, :routine_capex_cost, "SumHourlyWeighted(routine_capex, pcap)", Dollars, "Total routine capex cost paid, in dollars") + add_results_formula!(data, :storage, :routine_capex_per_mwh, "fom_cost / edischarge_total", DollarsPerMWhDischarged, "Average routine capex cost for discharging 1 MWh of energy") add_results_formula!(data, :storage, :capex_cost, "SumYearly(capex_obj, ecap_inv_sim)", Dollars, "Total annualized capital expenditures paid, in dollars") add_results_formula!(data, :storage, :capex_per_mwh, "capex_cost / edischarge_total", DollarsPerMWhDischarged, "Average capital cost for discharging 1 MWh of energy") + add_results_formula!(data, :storage, :transmission_capex_cost, "SumYearly(transmission_capex_obj, ecap_inv_sim)", Dollars, "Total annualized transmission capital expenditures paid, in dollars") + add_results_formula!(data, :storage, :transmission_capex_per_mwh, "transmission_capex_cost / edischarge_total", DollarsPerMWhDischarged, "Average transmission capital cost for discharging 1 MWh of energy") # Variable costs add_results_formula!(data, :storage, :variable_cost, "vom_cost", Dollars, "Total variable costs for operation, including vom. One day if storage has fuel, this could include fuel also") diff --git a/src/types/policies/EmissionPrice.jl b/src/types/policies/EmissionPrice.jl index f1b4b1d3..1112ff0c 100644 --- a/src/types/policies/EmissionPrice.jl +++ b/src/types/policies/EmissionPrice.jl @@ -55,7 +55,7 @@ function E4ST.modify_model!(pol::EmissionPrice, config, data, model) # note: >2 used here for emisprc value and 0 length(unique(pol.prices)) > 2 && @warn "The current E4ST EmissionPrice mod isn't formulated correctly for both a variable EmissionPrice value (ie. 2020: 12, 2025: 15) and year_from_ref filters, please only specify a single value" - add_table_col!(data, :gen, Symbol("$(pol.name)_capex_adj"), Container[ByNothing(0.0) for i in 1:nrow(gen)], DollarsPerMWBuiltCapacity, + add_table_col!(data, :gen, Symbol("$(pol.name)_capex_adj"), Container[ByNothing(0.0) for i in 1:nrow(gen)], DollarsPerMWBuiltCapacityPerHour, "Adjustment factor added to the obj function as a PerMWCapInv term to account for emisprc payments that do not continue through the entire econ lifetime of a generator.") end diff --git a/src/types/policies/ITC.jl b/src/types/policies/ITC.jl index 975b3f94..880b405d 100644 --- a/src/types/policies/ITC.jl +++ b/src/types/policies/ITC.jl @@ -33,7 +33,7 @@ function E4ST.modify_setup_data!(pol::ITC, config, data) years = get_years(data) #create column of annualized ITC values - add_table_col!(data, :gen, pol.name, Container[ByNothing(0.0) for i in 1:nrow(gen)], DollarsPerMWBuiltCapacity, + add_table_col!(data, :gen, pol.name, Container[ByNothing(0.0) for i in 1:nrow(gen)], DollarsPerMWBuiltCapacityPerHour, "Investment tax credit value for $(pol.name)") #update column for gen_idx diff --git a/src/types/policies/ITCStorage.jl b/src/types/policies/ITCStorage.jl index acb316ca..328ba22b 100644 --- a/src/types/policies/ITCStorage.jl +++ b/src/types/policies/ITCStorage.jl @@ -38,7 +38,7 @@ function E4ST.modify_setup_data!(pol::ITCStorage, config, data) years = get_years(data) #create column of annualized ITCStorage values - add_table_col!(data, :storage, pol.name, Container[ByNothing(0.0) for i in 1:nrow(storage)], DollarsPerMWBuiltCapacity, + add_table_col!(data, :storage, pol.name, Container[ByNothing(0.0) for i in 1:nrow(storage)], DollarsPerMWBuiltCapacityPerHour, "Investment tax credit value for $(pol.name)") #update column for gen_idx diff --git a/src/types/policies/PTC.jl b/src/types/policies/PTC.jl index 7e8505e6..4fcb85d2 100644 --- a/src/types/policies/PTC.jl +++ b/src/types/policies/PTC.jl @@ -53,7 +53,7 @@ function E4ST.modify_setup_data!(pol::PTC, config, data) # note: >2 used here for PTC value and 0 length(unique(pol.values)) > 2 && @warn "The current E4ST PTC mod isn't formulated correctly for both a variable PTC value (ie. 2020: 12, 2025: 15) and year_from_ref filters, please only specify a single PTC value" - add_table_col!(data, :gen, Symbol("$(pol.name)_capex_adj"), Container[ByNothing(0.0) for i in 1:nrow(gen)], DollarsPerMWBuiltCapacity, + add_table_col!(data, :gen, Symbol("$(pol.name)_capex_adj"), Container[ByNothing(0.0) for i in 1:nrow(gen)], DollarsPerMWBuiltCapacityPerHour, "Adjustment factor added to the obj function as a PerMWCapInv term to account for PTC payments that do not continue through the entire econ lifetime of a generator.") end #update column for gen_idx diff --git a/test/data/3bus/build_gen.csv b/test/data/3bus/build_gen.csv index 9e82f7ac..5cbde491 100644 --- a/test/data/3bus/build_gen.csv +++ b/test/data/3bus/build_gen.csv @@ -1,8 +1,8 @@ -source,area,subarea,status,build_status,build_type,build_id,genfuel,gentype,pcap0,pcap_min,pcap_max,cf_min,cf_hist,vom,fuel_price,fom,capex,year_on,econ_life,year_on_min,year_on_max,age_shutdown,emis_co2,capt_co2_percent,heat_rate,chp_co2_multi -none,country,narnia,1,unbuilt,endog,test_solar_build,solar,solar,0,0,0.5,0,0.25,2,0,1.5,6,,30,y2015,,30,0,0,0,1 -none,country,archenland,1,unbuilt,endog,test_wind_build,wind,wind,0,0,0.5,0,0.4,2,0,6,6,,30,y2015,,30,0,0,0,1 -none,country,archenland,1,unbuilt,endog,test_oswind_build,wind,oswind,0,0,0.5,0,0.4,5,0,6,6,,30,y2035,,30,0,0,0,1 -none,country,narnia,1,unbuilt,endog,test_coal_build,coal,coal,0,0,1,0.6,0.68,2,0.5555555555555556,6,7,,30,,y2030,30,1,0,9,1 -none,buildngcc,1,1,unbuilt,endog,test_ngcc_build,ng,ngcc,0,0,1.5,0,0.58,1,0.21428571428571427,5,5,,30,y2015,,30,0.6,0,7,1 -none,bus_idx,1,1,unbuilt,exog,test_exog_nuc_build,nuclear,nuclear,0.5,0,0.5,0.6,0.92,10,5,5,10,y2020,30,,,30,0,0,1,1 -none,bus_idx,2,1,unbuilt,exog,test_exog_solar_build,solar,solar,0.5,0,1,0,0.25,2,0,2.5,5,y2060,30,,,30,0,0,0,1 \ No newline at end of file +source,area,subarea,status,build_status,build_type,build_id,genfuel,gentype,pcap0,pcap_min,pcap_max,cf_min,cf_hist,vom,fuel_price,fom,capex,transmission_capex,routine_capex,year_on,econ_life,year_on_min,year_on_max,age_shutdown,emis_co2,capt_co2_percent,heat_rate,chp_co2_multi +none,country,narnia,1,unbuilt,endog,test_solar_build,solar,solar,0,0,0.5,0,0.25,2,0,1.5,6,0.1,0,,30,y2015,,30,0,0,0,1 +none,country,archenland,1,unbuilt,endog,test_wind_build,wind,wind,0,0,0.5,0,0.4,2,0,6,6,0.1,0,,30,y2015,,30,0,0,0,1 +none,country,archenland,1,unbuilt,endog,test_oswind_build,wind,oswind,0,0,0.5,0,0.4,5,0,6,6,0.3,0,,30,y2035,,30,0,0,0,1 +none,country,narnia,1,unbuilt,endog,test_coal_build,coal,coal,0,0,1,0.6,0.68,2,0.5555555555555556,6,7,0.1,0,,30,,y2030,30,1,0,9,1 +none,buildngcc,1,1,unbuilt,endog,test_ngcc_build,ng,ngcc,0,0,1.5,0,0.58,1,0.21428571428571427,5,5,0.1,0,,30,y2015,,30,0.6,0,7,1 +none,bus_idx,1,1,unbuilt,exog,test_exog_nuc_build,nuclear,nuclear,0.5,0,0.5,0.6,0.92,10,5,5,10,0.1,0,y2020,30,,,30,0,0,1,1 +none,bus_idx,2,1,unbuilt,exog,test_exog_solar_build,solar,solar,0.5,0,1,0,0.25,2,0,2.5,5,0.1,0,y2060,30,,,30,0,0,0,1 \ No newline at end of file diff --git a/test/data/3bus/build_storage.csv b/test/data/3bus/build_storage.csv index b2f2f318..8a24e922 100644 --- a/test/data/3bus/build_storage.csv +++ b/test/data/3bus/build_storage.csv @@ -1,2 +1,2 @@ -area,subarea,status,build_status,build_type,build_id,year_on,econ_life,year_on_min,year_on_max,age_shutdown,pcap0,pcap_min,pcap_max,vom,fom,capex,duration_discharge,duration_charge,storage_efficiency,side,hour_groupby,hour_duration,hour_order -country,narnia,1,unbuilt,endog,test_battery_build,,30,y2020,y2050,30,0.0,0.0,0.05,0.1,0.2,1,4,8,0.8,load,day,day_duration,day_order \ No newline at end of file +area,subarea,status,build_status,build_type,build_id,year_on,econ_life,year_on_min,year_on_max,age_shutdown,pcap0,pcap_min,pcap_max,vom,fom,capex,transmission_capex,routine_capex,duration_discharge,duration_charge,storage_efficiency,side,hour_groupby,hour_duration,hour_order +country,narnia,1,unbuilt,endog,test_battery_build,,30,y2020,y2050,30,0.0,0.0,0.05,0.1,0.2,1,0.1,0,4,8,0.8,load,day,day_duration,day_order \ No newline at end of file diff --git a/test/data/3bus/gen.csv b/test/data/3bus/gen.csv index 45fcbe5a..d54daeb2 100644 --- a/test/data/3bus/gen.csv +++ b/test/data/3bus/gen.csv @@ -1,6 +1,6 @@ -bus_idx,status,reg_factor,build_status,build_type,build_id,genfuel,gentype,econ_life,pcap_inv,pcap0,pcap_min,pcap_max,cf_min,cf_hist,vom,fuel_price,fom,capex,year_on,year_off,year_shutdown,emis_co2,capt_co2_percent,heat_rate,chp_co2_multi -3,1,0.75,built,exog,,coal,coal,30,2.0,2.0,0,2,0.6,0.68,2,0.5555555555555556,20,7,y2020,y9999,y2045,1,0,9,1.0 -1,1,0,built,exog,,solar,solar,30,0.5,0.5,0,0.5,0,0.25,2,0,5,5,y2027,y9999,y2050,0,0,0,1.0 -3,1,0.75,built,exog,,ng,ngccccs,30,0.5,0.5,0,0.5,0.6,0.55,1.5,0.14285714285714285,6,6,y2025,y9999,y2055,0.6,0.9,7,1.0 -1,1,0,built,exog,,wind,wind,30,0.05,0.05,0,0.05,0,0.4,0.1,0,2,3,y2015,y9999,y2035,0,0,0,1.0 -1,1,0.1,built,exog,,ng,ngt_chp,30,0.01,0.01,0,0.01,0.6,0.23,2,0.25,7,7,y2030,y9999,y2050,0.6,0,8,0.67 \ No newline at end of file +bus_idx,status,reg_factor,build_status,build_type,build_id,genfuel,gentype,econ_life,pcap_inv,pcap0,pcap_min,pcap_max,cf_min,cf_hist,vom,fuel_price,fom,capex,transmission_capex,routine_capex,year_on,year_off,year_shutdown,emis_co2,capt_co2_percent,heat_rate,chp_co2_multi +3,1,0.75,built,exog,,coal,coal,30,2.0,2.0,0,2,0.6,0.68,2,0.5555555555555556,20,7,0.1,0.2,y2020,y9999,y2045,1,0,9,1.0 +1,1,0,built,exog,,solar,solar,30,0.5,0.5,0,0.5,0,0.25,2,0,5,5,0.5,0.1,y2027,y9999,y2050,0,0,0,1.0 +3,1,0.75,built,exog,,ng,ngccccs,30,0.5,0.5,0,0.5,0.6,0.55,1.5,0.14285714285714285,6,6,0.1,0.2,y2025,y9999,y2055,0.6,0.9,7,1.0 +1,1,0,built,exog,,wind,wind,30,0.05,0.05,0,0.05,0,0.4,0.1,0,2,3,0.5,0.3,y2015,y9999,y2035,0,0,0,1.0 +1,1,0.1,built,exog,,ng,ngt_chp,30,0.01,0.01,0,0.01,0.6,0.23,2,0.25,7,7,0.1,0.1,y2030,y9999,y2050,0.6,0,8,0.67 \ No newline at end of file diff --git a/test/data/3bus/storage.csv b/test/data/3bus/storage.csv index 59372491..8af2dffc 100644 --- a/test/data/3bus/storage.csv +++ b/test/data/3bus/storage.csv @@ -1,2 +1,2 @@ -bus_idx,status,reg_factor,build_status,build_type,build_id,year_on,econ_life,year_shutdown,year_off,pcap_inv,pcap0,pcap_min,pcap_max,vom,fom,capex,duration_discharge,storage_efficiency,side,hour_groupby,hour_duration,hour_order -1,1,0,built,real,,y2020,30,y2050,y9999,0.05,0.05,0,0.05,0.5,0.5,5,8,0.9,load,day,day_duration,day_order \ No newline at end of file +bus_idx,status,reg_factor,build_status,build_type,build_id,year_on,econ_life,year_shutdown,year_off,pcap_inv,pcap0,pcap_min,pcap_max,vom,fom,capex,transmission_capex,routine_capex,duration_discharge,storage_efficiency,side,hour_groupby,hour_duration,hour_order +1,1,0,built,real,,y2020,30,y2050,y9999,0.05,0.05,0,0.05,0.5,0.5,5,0.01,0.2,8,0.9,load,day,day_duration,day_order \ No newline at end of file diff --git a/test/testsetupmodel.jl b/test/testsetupmodel.jl index da2675f2..968f71ba 100644 --- a/test/testsetupmodel.jl +++ b/test/testsetupmodel.jl @@ -16,6 +16,13 @@ @test haskey(data[:obj_vars], :vom) @test haskey(data[:obj_vars], :capex_obj) @test haskey(data[:obj_vars], :curtailment_cost) - @test model[:obj] == sum(model[:curtailment_cost]) + sum(model[:fom]) + sum(model[:fuel_price]) + sum(model[:vom]) + sum(model[:capex_obj]) #this won't be a good system level test + @test model[:obj] == + sum(model[:curtailment_cost]) + + sum(model[:fom]) + + sum(model[:fuel_price]) + + sum(model[:vom]) + + sum(model[:capex_obj]) + + sum(model[:transmission_capex_obj]) + + sum(model[:routine_capex]) #this won't be a good system level test end end \ No newline at end of file From 8a2e978ab214be3f318d582e13a846b3e587590e Mon Sep 17 00:00:00 2001 From: Ethan Russell Date: Tue, 13 Jun 2023 09:38:36 -0400 Subject: [PATCH 15/21] Add past investment cost and subsidy, as well as year unbuilt --- src/io/data.jl | 39 +++++++++++++++++++++++++++--- src/io/util.jl | 13 ++++++++++ src/model/newgens.jl | 10 ++++++-- src/types/Containers.jl | 2 +- src/types/modifications/Storage.jl | 5 +++- 5 files changed, 62 insertions(+), 7 deletions(-) diff --git a/src/io/data.jl b/src/io/data.jl index 25719705..666b6eb8 100644 --- a/src/io/data.jl +++ b/src/io/data.jl @@ -417,8 +417,37 @@ Creates age column which is a ByYear column. Unbuilt generators have a negative function setup_table!(config, data, ::Val{:gen}) bus = get_table(data, :bus) gen = get_table(data, :gen) + years = get_years(data) - data[:gen_table_original_cols] = propertynames(gen) + # Set up year_unbuilt before setting up new gens. Plus we will want to save the column + hasproperty(gen, :year_unbuilt) || (gen.year_unbuilt = map(y->add_to_year(y, -1), gen.year_on)) + + # Set up past capex cost and subsidy to be for built generators only + # Make columns as needed + hasproperty(gen, :past_invest_cost) || (gen.past_invest_cost = zeros(nrow(gen))) + hasproperty(gen, :past_invest_subsidy) || (gen.past_invest_subsidy = zeros(nrow(gen))) + z = Container(0.0) + _to_container!(gen, :past_invest_cost) + _to_container!(gen, :past_invest_subsidy) + for (idx_g, g) in enumerate(eachrow(gen)) + if g.build_status == "unbuilt" + if any(!=(0), g.past_invest_cost) || any(!=(0), g.past_invest_subsidy) + @warn "Generator $idx_g is unbuilt yet has past capex cost/subsidy, setting to zero" + g.past_invest_cost = z + g.past_invest_subsidy = z + end + else + past_invest_percentages = get_past_invest_percentages(g, years) + g.past_invest_cost = g.past_invest_cost .* past_invest_percentages + g.past_invest_subsidy = g.past_invest_subsidy .* past_invest_percentages + + # g.past_invest_cost = ByYear([g.past_invest_cost[] * (year >= g.year_on && year < add_to_year(g.year_on, g.econ_life)) for year in get_years(data)]) + # g.past_invest_subsidy = ByYear([g.past_invest_subsidy[] * (year >= g.year_on && year < add_to_year(g.year_on, g.econ_life)) for year in get_years(data)]) + end + end + + original_cols = propertynames(gen) + data[:gen_table_original_cols] = original_cols #removes capex_obj if read in from previous sim :capex_obj in propertynames(data[:gen]) && select!(data[:gen], Not(:capex_obj)) @@ -440,10 +469,10 @@ function setup_table!(config, data, ::Val{:gen}) ### Create capex_obj (the capex used in the optimization/objective function) # set to capex for unbuilt generators in and after the year_on # set to 0 for already built capacity because capacity expansion isn't considered for existing generators + capex_obj = Container[ByNothing(0.0) for i in 1:nrow(gen)] transmission_capex_obj = Container[ByNothing(0.0) for i in 1:nrow(gen)] for (idx_g, g) in enumerate(eachrow(gen)) - g = gen[idx_g,:] g.build_status == "unbuilt" || continue capex_obj[idx_g] = ByYear([g.capex * (year >= g.year_on && year < add_to_year(g.year_on, g.econ_life)) for year in get_years(data)]) transmission_capex_obj[idx_g] = ByYear([g.transmission_capex * (year >= g.year_on && year < add_to_year(g.year_on, g.econ_life)) for year in get_years(data)]) @@ -486,6 +515,7 @@ function setup_table!(config, data, ::Val{:gen}) # Add necessary columns if they don't exist. hasproperty(gen, :af) || (gen.af = fill(ByNothing(1.0), nrow(gen))) hasproperty(gen, :fuel_price) || (gen.fuel_price = fill(0.0, nrow(gen))) + return gen end export setup_table! @@ -665,6 +695,7 @@ function summarize_table(::Val{:gen}) (:build_type, AbstractString, NA, true, "Whether the generator is 'real', 'exog' (exogenously built), or 'endog' (endogenously built)"), (:build_id, AbstractString, NA, true, "Identifier of the build row. For pre-existing generators not specified in the build file, this is usually left empty"), (:year_on, YearString, Year, true, "The first year of operation for the generator. (For new gens this is also the year it was built)"), + (:year_unbuilt,YearString, Year, false, "The latest year the generator was known not to be built. Defaults to year_on - 1. Used for past capex accounting."), (:econ_life, Float64, NumYears, true, "The number of years in the economic lifetime of the generator."), (:year_off, YearString, Year, true, "The first year that the generator is no longer operating in the simulation, computed from the simulation. Leave as y9999 if an existing generator that has not been retired in the simulation yet."), (:year_shutdown, YearString, Year, true, "The forced (exogenous) shutdown year for the generator. Often equal to the year_on plus the econ_life"), @@ -680,7 +711,9 @@ function summarize_table(::Val{:gen}) (:fom, Float64, DollarsPerMWCapacityPerHour, true, "Hourly fixed operation and maintenance cost for a MW of generation capacity"), (:capex, Float64, DollarsPerMWBuiltCapacityPerHour, true, "Hourly capital expenditures for a MW of generation capacity"), (:transmission_capex, Float64, DollarsPerMWBuiltCapacityPerHour, true, "Hourly capital expenditures for the transmission supporting a MW of generation capacity"), - (:routine_capex, Float64, DollarsPerMWCapacityPerHour, true, "Routing capital expenditures for a MW of discharge capacity"), + (:routine_capex, Float64, DollarsPerMWCapacityPerHour, true, "Routine capital expenditures for a MW of discharge capacity"), + (:past_invest_cost, Float64, DollarsPerMWCapacityPerHour, false, "Investment costs per MW of initial capacity per hour, for past investments"), + (:past_invest_subsidy, Float64, DollarsPerMWCapacityPerHour, false, "Investment subsidies from govt. per MW of initial capacity per hour, for past investments"), (:cf_min, Float64, MWhGeneratedPerMWhCapacity, false, "The minimum capacity factor, or operable ratio of power generation to capacity for the generator to operate. Take care to ensure this is not above the hourly availability factor in any of the hours, or else the model may be infeasible. Set to zero by default."), (:cf_max, Float64, MWhGeneratedPerMWhCapacity, false, "The maximum capacity factor, or operable ratio of power generation to capacity for the generator to operate"), (:cf_hist, Float64, MWhGeneratedPerMWhCapacity, false, "The historical capacity factor for the generator, or the gentype if no previous data is available. Primarily used to calculate estimate policy value (PTC and EmissionPrice capex_adj)"), diff --git a/src/io/util.jl b/src/io/util.jl index 182223f6..dfcebdc6 100644 --- a/src/io/util.jl +++ b/src/io/util.jl @@ -624,3 +624,16 @@ export anyany function Base.convert(T::Type{Symbol}, x::String) return Symbol(x) end + + +function get_past_invest_percentages(g, years) + year_on = g.year_on::AbstractString + year_unbuilt = g.year_unbuilt::AbstractString + econ_life = g.econ_life::Float64 + diff = diff_years(year_on, year_unbuilt) + v = map(years) do y + percent = (diff_years(year_on, y) - econ_life) / diff + return min(1.0, max(0.0, percent)) + end + return OriginalContainer(0.0, ByYear(v)) +end \ No newline at end of file diff --git a/src/model/newgens.jl b/src/model/newgens.jl index 86e39e30..478d0873 100644 --- a/src/model/newgens.jl +++ b/src/model/newgens.jl @@ -46,7 +46,7 @@ function make_newgens!(config, data, newgen) #get the names of specifications that will be pulled from the build_gen table spec_names = filter!( - !in((:bus_idx, :gen_latitude, :gen_longitude, :reg_factor, :year_off, :year_shutdown, :pcap_inv)), + !in((:bus_idx, :gen_latitude, :gen_longitude, :reg_factor, :year_off, :year_shutdown, :pcap_inv, :year_unbuilt, :past_invest_cost, :past_invest_subsidy)), propertynames(newgen) ) #this needs to be updated if there is anything else in gen that isn't a spec @@ -73,7 +73,7 @@ function make_newgens!(config, data, newgen) for bus_idx in bus_idxs if spec_row.build_type == "endog" # for endogenous new builds, a new gen is created for each sim year - for year in years + for (yr_idx, year) in enumerate(years) year < year_on_min && continue year > year_on_max && continue #populate newgen_row with specs @@ -81,9 +81,12 @@ function make_newgens!(config, data, newgen) #set year_on and off newgen_row[:year_on] = year + newgen_row[:year_unbuilt] = get(years, yr_idx - 1, config[:year_gen_data]) newgen_row[:year_shutdown] = add_to_year(year, spec_row.age_shutdown) newgen_row[:year_off] = "y9999" newgen_row[:pcap_inv] = 0.0 + newgen_row[:past_invest_cost] = Container(0.0) + newgen_row[:past_invest_subsidy] = Container(0.0) #add gen location hasproperty(newgen, :gen_latitude) && (newgen_row[:gen_latitude] = bus.bus_latitude[bus_idx]) @@ -107,6 +110,9 @@ function make_newgens!(config, data, newgen) newgen_row[:year_shutdown] = add_to_year(spec_row.year_on, spec_row.age_shutdown) newgen_row[:year_off] = "y9999" newgen_row[:pcap_inv] = 0.0 + newgen_row[:year_unbuilt] = add_to_year(newgen_row[:year_on], -1) + newgen_row[:past_invest_cost] = Container(0.0) + newgen_row[:past_invest_subsidy] = Container(0.0) push!(newgen, newgen_row, promote=true) end diff --git a/src/types/Containers.jl b/src/types/Containers.jl index 25201d5c..0e4b2ef3 100644 --- a/src/types/Containers.jl +++ b/src/types/Containers.jl @@ -681,6 +681,6 @@ function _to_container(v::Vector{Container}) v end function _to_container(v::Vector) - Container[ByNothing(x) for x in v] + Container[Container(x) for x in v] end diff --git a/src/types/modifications/Storage.jl b/src/types/modifications/Storage.jl index 3c12ebc9..fdc77faf 100644 --- a/src/types/modifications/Storage.jl +++ b/src/types/modifications/Storage.jl @@ -67,6 +67,7 @@ function summarize_table(::Val{:storage}) (:build_type, AbstractString, NA, true, "Whether the storage device is 'real', 'exog' (exogenously built), or 'endog' (endogenously built)"), (:build_id, AbstractString, NA, true, "Identifier of the build row. For pre-existing storage devices not specified in the build file, this is usually left empty"), (:year_on, YearString, Year, true, "The first year of operation for the storage device. (For new devices this is also the year it was built)"), + (:year_unbuilt,YearString, Year, false, "The latest year the generator was known not to be built. Defaults to year_on - 1. Used for past capex accounting."), (:econ_life, Float64, NumYears, true, "The number of years in the economic lifetime of the storage device."), (:year_off, YearString, Year, true, "The first year that the storage unit is no longer operating in the simulation, computed from the simulation. Leave as y9999 if an existing storage unit that has not been retired in the simulation yet."), (:year_shutdown, YearString, Year, true, "The forced (exogenous) shutdown year for the storage unit."), @@ -78,7 +79,9 @@ function summarize_table(::Val{:storage}) (:fom, Float64, DollarsPerMWCapacityPerHour, true, "Hourly fixed operation and maintenance cost for a MW of discharge capacity"), (:capex, Float64, DollarsPerMWBuiltCapacityPerHour, true, "Hourly capital expenditures for a MW of discharge capacity"), (:transmission_capex, Float64, DollarsPerMWBuiltCapacityPerHour, false, "Hourly capital expenditures for the transmission supporting a MW of discharge capacity"), - (:routine_capex, Float64, DollarsPerMWCapacityPerHour, true, "Routing capital expenditures for a MW of discharge capacity"), + (:routine_capex, Float64, DollarsPerMWCapacityPerHour, true, "Routine capital expenditures for a MW of discharge capacity"), + (:past_invest_cost, Float64, DollarsPerMWCapacityPerHour, false, "Investment costs per MW of initial capacity per hour, for past investments"), + (:past_invest_subsidy, Float64, DollarsPerMWCapacityPerHour, false, "Investment subsidies from govt. per MW of initial capacity per hour, for past investments"), (:duration_discharge, Float64, Hours, true, "Number of hours to fully discharge the storage device, from full."), (:duration_charge, Float64, Hours, false, "Number of hours to fully charge the empty storage device from empty. (Defaults to equal `duration_discharge`)"), (:storage_efficiency, Float64, MWhDischargedPerMWhCharged, true, "The round-trip efficiency of the battery."), From 77240781e752fc2e2bca98a4398cefff07970da1 Mon Sep 17 00:00:00 2001 From: Ethan Russell Date: Tue, 13 Jun 2023 13:58:26 -0400 Subject: [PATCH 16/21] Add past capex accounting for generators --- src/io/data.jl | 5 +-- src/io/util.jl | 2 +- src/results/parse.jl | 17 ++++++-- src/results/results_formulas.csv | 9 +++- src/types/modifications/Storage.jl | 6 ++- src/types/policies/ITC.jl | 20 +++++---- src/types/policies/ITCStorage.jl | 27 ++++++------ test/data/3bus/adjust_yearly.csv | 12 +++--- test/data/3bus/adjust_yearly_limited.csv | 4 +- test/data/3bus/build_gen.csv | 14 +++---- test/data/3bus/load_match.csv | 8 ++-- test/testiteration.jl | 52 ++++++++++++++++++++++++ 12 files changed, 123 insertions(+), 53 deletions(-) diff --git a/src/io/data.jl b/src/io/data.jl index 666b6eb8..2cad8b46 100644 --- a/src/io/data.jl +++ b/src/io/data.jl @@ -440,9 +440,6 @@ function setup_table!(config, data, ::Val{:gen}) past_invest_percentages = get_past_invest_percentages(g, years) g.past_invest_cost = g.past_invest_cost .* past_invest_percentages g.past_invest_subsidy = g.past_invest_subsidy .* past_invest_percentages - - # g.past_invest_cost = ByYear([g.past_invest_cost[] * (year >= g.year_on && year < add_to_year(g.year_on, g.econ_life)) for year in get_years(data)]) - # g.past_invest_subsidy = ByYear([g.past_invest_subsidy[] * (year >= g.year_on && year < add_to_year(g.year_on, g.econ_life)) for year in get_years(data)]) end end @@ -709,7 +706,7 @@ function summarize_table(::Val{:gen}) (:fuel_price, Float64, DollarsPerMMBtu, false, "Fuel cost per MMBtu of fuel used. `heat_rate` column also necessary when supplying `fuel_price`"), (:heat_rate, Float64, MMBtuPerMWhGenerated, false, "Heat rate, or MMBtu of fuel consumed per MWh electricity generated (0 for generators that don't use combustion)"), (:fom, Float64, DollarsPerMWCapacityPerHour, true, "Hourly fixed operation and maintenance cost for a MW of generation capacity"), - (:capex, Float64, DollarsPerMWBuiltCapacityPerHour, true, "Hourly capital expenditures for a MW of generation capacity"), + (:capex, Float64, DollarsPerMWBuiltCapacityPerHour, true, "Hourly capital expenditures for a MW of generation capacity. For already-built generators, this is not accounted for in the optimization or accounting. For accounting for investment costs and subsidies in built generators, use `past_invest_cost` and `past_invest_subsidy`"), (:transmission_capex, Float64, DollarsPerMWBuiltCapacityPerHour, true, "Hourly capital expenditures for the transmission supporting a MW of generation capacity"), (:routine_capex, Float64, DollarsPerMWCapacityPerHour, true, "Routine capital expenditures for a MW of discharge capacity"), (:past_invest_cost, Float64, DollarsPerMWCapacityPerHour, false, "Investment costs per MW of initial capacity per hour, for past investments"), diff --git a/src/io/util.jl b/src/io/util.jl index dfcebdc6..6e2fc9af 100644 --- a/src/io/util.jl +++ b/src/io/util.jl @@ -632,7 +632,7 @@ function get_past_invest_percentages(g, years) econ_life = g.econ_life::Float64 diff = diff_years(year_on, year_unbuilt) v = map(years) do y - percent = (diff_years(year_on, y) - econ_life) / diff + percent = (diff_years(year_on, y) + econ_life) / diff return min(1.0, max(0.0, percent)) end return OriginalContainer(0.0, ByYear(v)) diff --git a/src/results/parse.jl b/src/results/parse.jl index 47196b69..fefef517 100644 --- a/src/results/parse.jl +++ b/src/results/parse.jl @@ -206,7 +206,6 @@ function parse_power_results!(config, data) pcap_built[:, yr_idx] .= max.( pcap_cur .- pcap_prev, 0.0) end - # Add things to the bus table add_table_col!(data, :bus, :pgen, pgen_bus, MWGenerated,"Average Power Generated at this bus") add_table_col!(data, :bus, :egen, egen_bus, MWhGenerated,"Electricity Generated at this bus for the weighted representative hour") @@ -240,6 +239,10 @@ function parse_power_results!(config, data) add_table_col!(data, :branch, :pflow, pflow_branch, MWFlow,"Average Power flowing through branch") add_table_col!(data, :branch, :eflow, eflow_branch, MWhFlow,"Electricity flowing through branch") + + # Update pcap_inv + gen.pcap_inv = max.(gen.pcap_inv, gen.pcap_inv_sim) + return end export parse_power_results! @@ -303,6 +306,7 @@ Save the `gen` table to `get_out_path(config, "gen.csv")` """ function save_updated_gen_table(config, data) years = get_years(data) + nyr = get_num_years(data) year_end = last(years) gen = get_table(data, :gen) @@ -324,6 +328,14 @@ function save_updated_gen_table(config, data) return row.pcap_inv_sim end + # Gather the past investment costs and subsidies + for i in 1:nrow(gen_tmp) + gen_tmp.build_status[i] == "new" || continue + @info "updating the past investment cost/subsidy for $i" + gen_tmp.past_invest_cost[i] = maximum(yr_idx->compute_result(data, :gen, :invest_cost_permw_perhr, i, yr_idx), 1:nyr) + gen_tmp.past_invest_subsidy[i] = maximum(yr_idx->compute_result(data, :gen, :invest_subsidy_permw_perhr, i, yr_idx), 1:nyr) + end + # Filter anything with capacity below the threshold thresh = config[:pcap_retirement_threshold] filter!(gen_tmp) do row @@ -331,7 +343,7 @@ function save_updated_gen_table(config, data) row.pcap0 > thresh && return true row.pcap_inv <= thresh && return false - row.build_type == "exog" && return false + row.build_type == "exog" && return false # We don't care to keep track of exogenous past capex # Below the threshold, check to see if we are still within the economic lifetime year_econ_life = add_to_year(row.year_on, row.econ_life) @@ -347,7 +359,6 @@ function save_updated_gen_table(config, data) ) gen_tmp_combined.pcap_max = copy(gen_tmp_combined.pcap0) - CSV.write(get_out_path(config, "gen.csv"), gen_tmp_combined) return nothing end diff --git a/src/results/results_formulas.csv b/src/results/results_formulas.csv index 191e4641..20beb2b5 100644 --- a/src/results/results_formulas.csv +++ b/src/results/results_formulas.csv @@ -10,6 +10,7 @@ gen,pcap_start_total,Sum(pcap0),MWCapacity,Starting power capacity. gen,pcap_built_total,SumYearly(pcap_built),MWCapacity,Total power capacity built. Ignores subsets of hours and returns the built capacity for the whole year(s). gen,pcap_retired_total,SumYearly(pcap_retired),MWCapacity,Total power capacity retired. Ignores subsets of hours and returns the retired capacity for the whole year(s). gen,pcap_retired_percent,pcap_retired_total / pcap_start_total,MWCapacity,Percent of existing power capacity that was retired. Could be misleading if multiple years and generators were built and retired. +gen,ecap_inv_total,SumHourlyWeighted(pcap_inv),MWhCapacity,Total invested energy capacity over the time given gen,cf_avg,egen_total/ecap_total,MWhGeneratedPerMWhCapacity,Average Capacity Factor gen,cf_hourly_min,MinHourly(cf),MWhGeneratedPerMWhCapacity,Minimum observed capacity factor gen,cf_hourly_max,MaxHourly(cf),MWhGeneratedPerMWhCapacity,Maximum observed capacity factor @@ -37,6 +38,8 @@ gen,capex_cost,"SumYearly(capex_obj, ecap_inv_sim)",Dollars,"Capital expenditure gen,capex_per_mwh,capex_cost/egen_total,DollarsPerMWhGenerated,Levelized capital expenditures per MWh of energy generated gen,transmission_capex_cost,"SumYearly(transmission_capex_obj, ecap_inv_sim)",Dollars,"Capital expenditures for transmission, in dollars, as seen by objective function" gen,transmission_capex_per_mwh,transmission_capex_cost/egen_total,DollarsPerMWhGenerated,Levelized capital expenditures for transmission per MWh of energy generated +gen,past_invest_cost_total,"SumHourlyWeighted(past_invest_cost, pcap_inv)",Dollars,Investment costs from past investments +gen,past_invest_subsidy_total,"SumHourlyWeighted(past_invest_subsidy, pcap_inv)",Dollars,Investment subsidies from past investments gen,fuel_cost,"SumHourly(fuel_price,heat_rate,egen)",Dollars,Total cost of fuel gen,fuel_price_per_mwh,fuel_cost/egen_total,DollarsPerMWhGenerated,Fuel price per MWh generated gen,fuel_burned,"SumHourly(heat_rate,egen)",MMBtu,Amount of fuel burned @@ -47,10 +50,12 @@ gen,production_subsidy,0,Dollars,Total production subsidy for generation gen,production_subsidy_per_mwh,production_subsidy / egen_total,DollarsPerMWhGenerated,Average production subsidy for a MWh of generation gen,net_variable_cost,variable_cost - production_subsidy,Dollars,Total variable costs minus production subsidies gen,net_variable_cost_per_mwh,net_variable_cost / egen_total,DollarsPerMWhGenerated,Average variable costs minus production subsidies for a MWh of energy -gen,fixed_cost,capex_cost + fom_cost + routine_capex_cost + transmission_capex_cost,Dollars,"Fixed costs, including capex (not just what the optimization saw) and fom" +gen,fixed_cost,fom_cost + routine_capex_cost + invest_cost,Dollars,"Fixed costs, including capex (not just what the optimization saw) and fom" gen,fixed_cost_permw_perhr,fixed_cost/ecap_total,DollarsPerMWCapacityPerHour,Fixed costs per mw per hour +gen,invest_cost,transmission_capex_cost + capex_cost,Dollars,"Investment costs for generators, including capex cost and transmission capex cost" +gen,invest_cost_permw_perhr,invest_cost / ecap_inv_total,DollarsPerMWCapacityPerHour,Average investment cost per MW invested per hour gen,invest_subsidy,0,Dollars,Investment subsidies to go to generators -gen,invest_subsidy_permw_perhr,invest_subsidy / ecap_total,DollarsPerMWCapacityPerHour,Average investment subsidy per MW per hour +gen,invest_subsidy_permw_perhr,invest_subsidy / ecap_inv_total,DollarsPerMWCapacityPerHour,Average investment subsidy per MW invested per hour gen,net_fixed_cost,fixed_cost - invest_subsidy,Dollars,Fixed costs minus investment subsidies gen,net_fixed_cost_permw_perhr,net_fixed_cost / ecap_total,DollarsPerMWCapacityPerHour,Average net fixed cost per MW per hour. Fixed costs minus investment subsidies gen,production_cost,variable_cost + fixed_cost,Dollars,"Cost of production, includes fixed and variable costs" diff --git a/src/types/modifications/Storage.jl b/src/types/modifications/Storage.jl index fdc77faf..fc7fc79b 100644 --- a/src/types/modifications/Storage.jl +++ b/src/types/modifications/Storage.jl @@ -455,6 +455,10 @@ function modify_model!(mod::Storage, config, data, model) add_obj_exp!(data, model, PerMWCap(), :routine_capex_stor, oper = +) add_obj_exp!(data, model, PerMWCapInv(), :capex_obj_stor, oper = +) add_obj_exp!(data, model, PerMWCapInv(), :transmission_capex_obj_stor, oper = +) + + # Add some results so that policy mods can add to the investment subsidy + add_results_formula!(data, :storage, :invest_subsidy, "0", Dollars, "Investment subsidies to go to the producer") + add_results_formula!(data, :storage, :invest_subsidy_permw_perhr, "invest_subsidy / ecap_total", DollarsPerMWCapacityPerHour, "Investment subsidies per MW per hour") end """ @@ -539,8 +543,6 @@ function modify_results!(mod::Storage, config, data) # Fixed costs add_results_formula!(data, :storage, :fixed_cost, "capex_cost + fom_cost", Dollars, "Total fixed costs including capex and fom costs") add_results_formula!(data, :storage, :fixed_cost_permw_perhr, "fixed_cost / ecap_total", DollarsPerMWCapacityPerHour, "Fixed costs, per MW per hour") - add_results_formula!(data, :storage, :invest_subsidy, "0", Dollars, "Investment subsidies to go to the producer") - add_results_formula!(data, :storage, :invest_subsidy_permw_perhr, "invest_subsidy / ecap_total", DollarsPerMWCapacityPerHour, "Investment subsidies per MW per hour") add_results_formula!(data, :storage, :net_fixed_cost, "fixed_cost - invest_subsidy", Dollars, "Fixed costs minus investment subsidies") add_results_formula!(data, :storage, :net_fixed_cost_permw_perhr, "net_fixed_cost / ecap_total", DollarsPerMWCapacityPerHour, "Average net fixed cost per MW per hour.") diff --git a/src/types/policies/ITC.jl b/src/types/policies/ITC.jl index 880b405d..cb8415cc 100644 --- a/src/types/policies/ITC.jl +++ b/src/types/policies/ITC.jl @@ -54,7 +54,16 @@ end Subtracts the ITC price * Capacity in that year from the objective function using [`add_obj_term!(data, model, PerMWCap(), pol.name, oper = -)`](@ref) """ function E4ST.modify_model!(pol::ITC, config, data, model) - add_obj_term!(data, model, PerMWCapInv(), pol.name, oper = -) + add_obj_term!(data, model, PerMWCapInv(), pol.name, oper = -) + + total_result_name = "$(pol.name)_cost_obj" + total_result_sym = Symbol(total_result_name) + + # calculate objective policy cost (based on capacity in each sim year) + add_results_formula!(data, :gen, total_result_sym, "SumYearly($(pol.name),ecap_inv_sim)", Dollars, "The cost of $(pol.name) as seen by the objective, not used for gov spending welfare") + #add_results_formula!(data, :gen, Symbol("$(pol.name)_cost_obj"), "SumHourly($(pol.name),ecap)", Dollars, "The cost of $(pol.name) as seen by the objective, not necessarily used for gov spending welfare") + + add_to_results_formula!(data, :gen, :invest_subsidy, total_result_name) end @@ -64,12 +73,5 @@ end Calculates ITC cost as seen by the objective (cost_obj) which is ITC value * capacity (where ITC value is credit level as a % multiplied by capital cost) """ function E4ST.modify_results!(pol::ITC, config, data) - total_result_name = "$(pol.name)_cost_obj" - total_result_sym = Symbol(total_result_name) - - # calculate objective policy cost (based on capacity in each sim year) - add_results_formula!(data, :gen, total_result_sym, "SumYearly($(pol.name),ecap_inv_sim)", Dollars, "The cost of $(pol.name) as seen by the objective, not used for gov spending welfare") - #add_results_formula!(data, :gen, Symbol("$(pol.name)_cost_obj"), "SumHourly($(pol.name),ecap)", Dollars, "The cost of $(pol.name) as seen by the objective, not necessarily used for gov spending welfare") - - add_to_results_formula!(data, :gen, :invest_subsidy, total_result_name) + end diff --git a/src/types/policies/ITCStorage.jl b/src/types/policies/ITCStorage.jl index 328ba22b..d95b3b47 100644 --- a/src/types/policies/ITCStorage.jl +++ b/src/types/policies/ITCStorage.jl @@ -78,20 +78,8 @@ function E4ST.modify_model!(pol::ITCStorage, config, data, model) ) add_obj_exp!(data, model, PerMWCapInv(), name, oper = -) -end - - -""" - E4ST.modify_results!(pol::ITCStorage, config, data) -> - -Calculates ITCStorage cost as seen by the objective (cost_obj) which is ITCStorage value * capacity (where ITCStorage value is credit level as a % multiplied by capital cost) -""" -function E4ST.modify_results!(pol::ITCStorage, config, data) - if ~haskey(data, :storage) - @warn "ITCStorage policy given, yet no storage defined. Consider adding a Storage modification." - return - end + # Add things to results here so it gets saved in the right places total_result_name = "$(pol.name)_cost_obj" total_result_sym = Symbol(total_result_name) @@ -104,4 +92,17 @@ function E4ST.modify_results!(pol::ITCStorage, config, data) # if using pol_cost_obj, update the description provided in add_results_forumla above add_to_results_formula!(data, :storage, :invest_subsidy, total_result_name) +end + + +""" + E4ST.modify_results!(pol::ITCStorage, config, data) -> + +Calculates ITCStorage cost as seen by the objective (cost_obj) which is ITCStorage value * capacity (where ITCStorage value is credit level as a % multiplied by capital cost) +""" +function E4ST.modify_results!(pol::ITCStorage, config, data) + if ~haskey(data, :storage) + @warn "ITCStorage policy given, yet no storage defined. Consider adding a Storage modification." + return + end end \ No newline at end of file diff --git a/test/data/3bus/adjust_yearly.csv b/test/data/3bus/adjust_yearly.csv index eae07026..792780b1 100644 --- a/test/data/3bus/adjust_yearly.csv +++ b/test/data/3bus/adjust_yearly.csv @@ -1,6 +1,6 @@ -description,table_name,variable_name,operation,filter1,filter2,status,y2020,y2025,y2030,y2035,y2040 -Reduce the FOM in narnia for solar generators,gen,fom,add,country=>narnia,gentype=>solar,1,0.0,-0.1,-0.2,-0.3,-0.4 -Scale the branch max power flow to match a 5% annual growth rate starting in 2020,branch,pflow_max,scale,,,1,1.0,1.276,1.629,2.079,2.653 -"Set the yearly value of damage rate of CO2, using values from Rennert et. al.",,r_dam_co2,set,,,1,150.26,166.91,183.56,198.59,213.61 -"Set the yearly value of damage rate of NOx emissions, in dollars per pound",,r_dam_nox,set,,,1,24.18,27.11,30.05,33.00,35.60 -"Global warming potential of methane, based on SCC/SCM from Rennert et. al.",,ch4_gwp,set,,,1,10.481081,11.812652,12.902655,14.280164,15.463878 \ No newline at end of file +description,table_name,variable_name,operation,filter1,filter2,status,y2020,y2025,y2030,y2035,y2040,y2050,y2060,y2070 +Reduce the FOM in narnia for solar generators,gen,fom,add,country=>narnia,gentype=>solar,1,0.0,-0.1,-0.2,-0.3,-0.4,-0.5,-0.6,-0.6 +Scale the branch max power flow to match a 5% annual growth rate starting in 2020,branch,pflow_max,scale,,,1,1.0,1.276,1.629,2.079,2.653,4.322,7.040,11.467 +"Set the yearly value of damage rate of CO2, using values from Rennert et. al. (constant after 2040)",,r_dam_co2,set,,,1,150.26,166.91,183.56,198.59,213.61,213.61,213.61,213.61 +"Set the yearly value of damage rate of NOx emissions, in dollars per pound (constant after 2040)",,r_dam_nox,set,,,1,24.18,27.11,30.05,33.00,35.60,35.60,35.60,35.60 +"Global warming potential of methane, based on SCC/SCM from Rennert et. al. (constant after 2040)",,ch4_gwp,set,,,1,10.481081,11.812652,12.902655,14.280164,15.463878,15.463878,15.463878,15.463878 \ No newline at end of file diff --git a/test/data/3bus/adjust_yearly_limited.csv b/test/data/3bus/adjust_yearly_limited.csv index 1e52758c..3e068957 100644 --- a/test/data/3bus/adjust_yearly_limited.csv +++ b/test/data/3bus/adjust_yearly_limited.csv @@ -1,2 +1,2 @@ -description,table_name,variable_name,operation,filter1,filter2,status,y2020,y2025,y2030,y2035,y2040 -"Global warming potential of methane, based on SCC/SCM from Rennert et. al.",,ch4_gwp,set,,,1,10.481081,11.812652,12.902655,14.280164,15.463878 \ No newline at end of file +description,table_name,variable_name,operation,filter1,filter2,status,y2020,y2025,y2030,y2035,y2040,y2050,y2060,y2070 +"Global warming potential of methane, based on SCC/SCM from Rennert et. al. (constant after 2040)",,ch4_gwp,set,,,1,10.481081,11.812652,12.902655,14.280164,15.463878,15.463878,15.463878,15.463878 \ No newline at end of file diff --git a/test/data/3bus/build_gen.csv b/test/data/3bus/build_gen.csv index 5cbde491..a1f3a5df 100644 --- a/test/data/3bus/build_gen.csv +++ b/test/data/3bus/build_gen.csv @@ -1,8 +1,8 @@ source,area,subarea,status,build_status,build_type,build_id,genfuel,gentype,pcap0,pcap_min,pcap_max,cf_min,cf_hist,vom,fuel_price,fom,capex,transmission_capex,routine_capex,year_on,econ_life,year_on_min,year_on_max,age_shutdown,emis_co2,capt_co2_percent,heat_rate,chp_co2_multi -none,country,narnia,1,unbuilt,endog,test_solar_build,solar,solar,0,0,0.5,0,0.25,2,0,1.5,6,0.1,0,,30,y2015,,30,0,0,0,1 -none,country,archenland,1,unbuilt,endog,test_wind_build,wind,wind,0,0,0.5,0,0.4,2,0,6,6,0.1,0,,30,y2015,,30,0,0,0,1 -none,country,archenland,1,unbuilt,endog,test_oswind_build,wind,oswind,0,0,0.5,0,0.4,5,0,6,6,0.3,0,,30,y2035,,30,0,0,0,1 -none,country,narnia,1,unbuilt,endog,test_coal_build,coal,coal,0,0,1,0.6,0.68,2,0.5555555555555556,6,7,0.1,0,,30,,y2030,30,1,0,9,1 -none,buildngcc,1,1,unbuilt,endog,test_ngcc_build,ng,ngcc,0,0,1.5,0,0.58,1,0.21428571428571427,5,5,0.1,0,,30,y2015,,30,0.6,0,7,1 -none,bus_idx,1,1,unbuilt,exog,test_exog_nuc_build,nuclear,nuclear,0.5,0,0.5,0.6,0.92,10,5,5,10,0.1,0,y2020,30,,,30,0,0,1,1 -none,bus_idx,2,1,unbuilt,exog,test_exog_solar_build,solar,solar,0.5,0,1,0,0.25,2,0,2.5,5,0.1,0,y2060,30,,,30,0,0,0,1 \ No newline at end of file +none,country,narnia,1,unbuilt,endog,test_solar_build,solar,solar,0,0,0.5,0,0.25,2,0,1.5,6,0.1,0,,35,y2015,,30,0,0,0,1 +none,country,archenland,1,unbuilt,endog,test_wind_build,wind,wind,0,0,0.5,0,0.4,2,0,6,6,0.1,0,,35,y2015,,30,0,0,0,1 +none,country,archenland,1,unbuilt,endog,test_oswind_build,wind,oswind,0,0,0.5,0,0.4,5,0,6,6,0.3,0,,35,y2035,,30,0,0,0,1 +none,country,narnia,1,unbuilt,endog,test_coal_build,coal,coal,0,0,1,0.6,0.68,2,0.5555555555555556,6,7,0.1,0,,35,,y2030,30,1,0,9,1 +none,buildngcc,1,1,unbuilt,endog,test_ngcc_build,ng,ngcc,0,0,1.5,0,0.58,1,0.21428571428571427,5,5,0.1,0,,35,y2015,,30,0.6,0,7,1 +none,bus_idx,1,1,unbuilt,exog,test_exog_nuc_build,nuclear,nuclear,0.5,0,0.5,0.6,0.92,10,5,5,10,0.1,0,y2020,35,,,30,0,0,1,1 +none,bus_idx,2,1,unbuilt,exog,test_exog_solar_build,solar,solar,0.5,0,1,0,0.25,2,0,2.5,5,0.1,0,y2060,35,,,30,0,0,0,1 \ No newline at end of file diff --git a/test/data/3bus/load_match.csv b/test/data/3bus/load_match.csv index 716ba05e..33ba3e89 100644 --- a/test/data/3bus/load_match.csv +++ b/test/data/3bus/load_match.csv @@ -1,4 +1,4 @@ -area,subarea,load_type,status,y2020,y2025,y2030,y2035,y2040 -country,narnia,,1,1000,1200,1400,1600,1800 -country,archenland,,1,10000,12000,14000,16000,18000 -,,,1,14000,15000,16000,18000,19800 \ No newline at end of file +area,subarea,load_type,status,y2020,y2025,y2030,y2035,y2040,y2050,y2060,y2070 +country,narnia,,1,1000,1200,1400,1600,1800,2000,2200,2400 +country,archenland,,1,10000,12000,14000,16000,18000,20000,22000,24000 +,,,1,14000,15000,16000,18000,19800,22000,24000,28000 \ No newline at end of file diff --git a/test/testiteration.jl b/test/testiteration.jl index 85472b38..1301a02d 100644 --- a/test/testiteration.jl +++ b/test/testiteration.jl @@ -85,4 +85,56 @@ # TODO: think of any tests here that would better check the functionality end + + @testset "Test past capex calculations in sequential simulations" begin + config_itc_file = joinpath(@__DIR__, "config", "config_3bus_itc.yml") + config = read_config(config_file, config_itc_file) + data = read_data(config) + model = setup_model(config, data) + optimize!(model) + parse_results!(config, data, model) + process_results!(config, data) + + @test compute_result(data, :gen, :past_invest_cost_total) == 0.0 + @test compute_result(data, :gen, :past_invest_subsidy_total) == 0.0 + + gen_updated_file = get_out_path(config, "gen.csv") + gen_updated = read_table(gen_updated_file) + + # Make sure that the past invest costs get updated for the next sim + @test any(>(0.0), gen_updated.past_invest_cost) + @test any(>(0.0), gen_updated.past_invest_subsidy) + + # Now run another sim with the updated gen table + config_itc_file = joinpath(@__DIR__, "config", "config_3bus_itc.yml") + config = read_config(config_file, config_itc_file) + config[:years] = ["y2050", "y2060", "y2070"] + config[:year_gen_data] = "y2040" + config[:gen_file] = gen_updated_file + data = read_data(config) + model = setup_model(config, data) + optimize!(model) + parse_results!(config, data, model) + process_results!(config, data) + gen = get_table(data, :gen) + + @test compute_result(data, :gen, :past_invest_cost_total) > 0.0 + @test compute_result(data, :gen, :past_invest_subsidy_total) > 0.0 + + # Test that no past invest cost for exogenous generators + @test compute_result(data, :gen, :past_invest_cost_total, :build_type=>"exog") == 0.0 + @test compute_result(data, :gen, :past_invest_cost_total, :build_status=>"new") == 0.0 + @test compute_result(data, :gen, :past_invest_subsidy_total, :build_type=>"exog") == 0.0 + @test compute_result(data, :gen, :past_invest_subsidy_total, :build_status=>"new") == 0.0 + + @test any(==("y2020"), gen.year_unbuilt) + gen_idxs_unbuilt_2020 = get_row_idxs(gen, :year_unbuilt=>"y2020") + for gen_idx in gen_idxs_unbuilt_2020 + # In 2050, the investment cost should be half of the full amount. + @test gen.econ_life[gen_idx] == 35 + @test gen.past_invest_cost[gen_idx][1] ≈ 1.0 * (gen.transmission_capex[gen_idx] + gen.capex[gen_idx]) + @test gen.past_invest_cost[gen_idx][2] ≈ 0.5 * (gen.transmission_capex[gen_idx] + gen.capex[gen_idx]) + @test gen.past_invest_cost[gen_idx][3] ≈ 0.0 + end + end end \ No newline at end of file From 86f70cad1153d75db684b52b5f9d96f17ab64b95 Mon Sep 17 00:00:00 2001 From: Ethan Russell Date: Tue, 13 Jun 2023 14:07:10 -0400 Subject: [PATCH 17/21] Minor update to total cost for generators to include past invest cost/subs --- src/results/results_formulas.csv | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/results/results_formulas.csv b/src/results/results_formulas.csv index 20beb2b5..afa78558 100644 --- a/src/results/results_formulas.csv +++ b/src/results/results_formulas.csv @@ -70,14 +70,14 @@ gen,emission_cost,0,Dollars,Cost for paying all emissions prices. gen,emission_cost_per_mwh,emission_cost / egen_total,DollarsPerMWhGenerated,"Average cost, per MWh, for paying emission prices" gen,pol_cost,emission_cap_cost + emission_cost - gs_cost - invest_subsidy - production_subsidy,Dollars,Cost for all generators from all policy types. gen,pol_cost_per_mwh,pol_cost / egen_total,DollarsPerMWhGenerated,"Average cost for all generators from all policy types, per MWh." -gen,government_revenue,emission_cap_cost + emission_cost - invest_subsidy - production_subsidy,Dollars,Government revenue earned from generators +gen,government_revenue,emission_cap_cost + emission_cost - invest_subsidy - production_subsidy - past_invest_subsidy_total,Dollars,Government revenue earned from generators gen,going_forward_cost,production_cost + pol_cost,Dollars,Total going forward cost -gen,total_cost_prelim,going_forward_cost,Dollars,"Total cost of production. Right now contains only going_forward_cost, but may eventually contain past capex costs" -gen,total_cost_prelim_per_mwh,total_cost / egen_total,DollarsPerMWhGenerated,"Average cost of producing a MWh of power. Right now contains only net_production_cost, but may eventually contain past capex costs" +gen,total_cost_prelim,going_forward_cost + past_invest_cost_total - past_invest_subsidy_total,Dollars,"Total cost of production, including past investment costs and subsidies" +gen,total_cost_prelim_per_mwh,total_cost / egen_total,DollarsPerMWhGenerated,"Average cost of producing a MWh of power, including pst investment costs and subsidies" gen,net_total_revenue_prelim,electricity_revenue - total_cost_prelim,Dollars,"Preliminary net total revenue, including electricity revenue minus total cost, before adjusting for cost-of-service rebates" gen,cost_of_service_rebate,CostOfServiceRebate(gen),Dollars,"This is a specially calculated result, which is the sum of net_total_revenue_prelim * reg_factor for each generator" gen,total_cost,total_cost_prelim + cost_of_service_rebate,Dollars,Total cost of production including the preliminary total cost and the cost of service rebate to consumers. -gen,total_cost_per_mwh,total_cost / egen_total,DollarsPerMWhGenerated,"Average cost of producing a MWh of power. Right now contains only net_production_cost, but may eventually contain past capex costs" +gen,total_cost_per_mwh,total_cost / egen_total,DollarsPerMWhGenerated,"Average cost of producing 1 MWh of energy, including the preliminary total cost and the cost of service rebate to consumers." gen,net_total_revenue,net_total_revenue_prelim - cost_of_service_rebate,Dollars,Net total revenue after adjusting for the cost-of-service rebate gen,net_variable_revenue,electricity_revenue - net_variable_cost - cost_of_service_rebate,Dollars,Net variable revenue including electiricy revenue minus net variable costs gen,net_going_forward_revenue,electricity_revenue - going_forward_cost - cost_of_service_rebate,Dollars,"Net going forward revenue, including electricity revenue minus going forward cost" From 7b0248b9c2f22db00ad003e8af790d3b0d1398ef Mon Sep 17 00:00:00 2001 From: Ethan Russell Date: Tue, 13 Jun 2023 17:06:21 -0400 Subject: [PATCH 18/21] Make sure the past capex accounting works for storage, minor fixes --- src/model/newgens.jl | 10 +++- src/types/modifications/Storage.jl | 78 ++++++++++++++++++++++++------ test/data/3bus/build_gen.csv | 2 +- test/testiteration.jl | 14 ++++-- 4 files changed, 83 insertions(+), 21 deletions(-) diff --git a/src/model/newgens.jl b/src/model/newgens.jl index 478d0873..3385b316 100644 --- a/src/model/newgens.jl +++ b/src/model/newgens.jl @@ -44,6 +44,12 @@ function make_newgens!(config, data, newgen) gen = get_table(data, :gen) years = get_years(data) + # Filter any already-built exogenous generators + filter!(build_gen) do row + row.build_type == "exog" && row.year_on >= config[:year_gen_data] && return false + return true + end + #get the names of specifications that will be pulled from the build_gen table spec_names = filter!( !in((:bus_idx, :gen_latitude, :gen_longitude, :reg_factor, :year_off, :year_shutdown, :pcap_inv, :year_unbuilt, :past_invest_cost, :past_invest_subsidy)), @@ -82,7 +88,7 @@ function make_newgens!(config, data, newgen) #set year_on and off newgen_row[:year_on] = year newgen_row[:year_unbuilt] = get(years, yr_idx - 1, config[:year_gen_data]) - newgen_row[:year_shutdown] = add_to_year(year, spec_row.age_shutdown) + newgen_row[:year_shutdown] = "y9999" # add_to_year(year, spec_row.age_shutdown) newgen_row[:year_off] = "y9999" newgen_row[:pcap_inv] = 0.0 newgen_row[:past_invest_cost] = Container(0.0) @@ -107,7 +113,7 @@ function make_newgens!(config, data, newgen) hasproperty(newgen, :gen_longitude) && (newgen_row[:gen_longitude] = bus.bus_longitude[bus_idx]) hasproperty(newgen, :reg_factor) && (newgen_row[:reg_factor] = bus.reg_factor[bus_idx]) - newgen_row[:year_shutdown] = add_to_year(spec_row.year_on, spec_row.age_shutdown) + newgen_row[:year_shutdown] = "y9999" #add_to_year(spec_row.year_on, spec_row.age_shutdown) newgen_row[:year_off] = "y9999" newgen_row[:pcap_inv] = 0.0 newgen_row[:year_unbuilt] = add_to_year(newgen_row[:year_on], -1) diff --git a/src/types/modifications/Storage.jl b/src/types/modifications/Storage.jl index fc7fc79b..e582780c 100644 --- a/src/types/modifications/Storage.jl +++ b/src/types/modifications/Storage.jl @@ -144,6 +144,30 @@ function modify_setup_data!(mod::Storage, config, data) hours = get_table(data, :hours) years = get_years(data) + # Set up year_unbuilt before setting up new gens. Plus we will want to save the column + hasproperty(storage, :year_unbuilt) || (storage.year_unbuilt = map(y->add_to_year(y, -1), storage.year_on)) + + # Set up past capex cost and subsidy to be for built generators only + # Make columns as needed + hasproperty(storage, :past_invest_cost) || (storage.past_invest_cost = zeros(nrow(storage))) + hasproperty(storage, :past_invest_subsidy) || (storage.past_invest_subsidy = zeros(nrow(storage))) + z = Container(0.0) + _to_container!(storage, :past_invest_cost) + _to_container!(storage, :past_invest_subsidy) + for (idx_g, g) in enumerate(eachrow(storage)) + if g.build_status == "unbuilt" + if any(!=(0), g.past_invest_cost) || any(!=(0), g.past_invest_subsidy) + @warn "Generator $idx_g is unbuilt yet has past capex cost/subsidy, setting to zero" + g.past_invest_cost = z + g.past_invest_subsidy = z + end + else + past_invest_percentages = get_past_invest_percentages(g, years) + g.past_invest_cost = g.past_invest_cost .* past_invest_percentages + g.past_invest_subsidy = g.past_invest_subsidy .* past_invest_percentages + end + end + data[:storage_table_original_cols] = propertynames(storage) add_buildable_storage!(config, data) @@ -159,8 +183,8 @@ function modify_setup_data!(mod::Storage, config, data) end ### Create capex_obj (the capex used in the optimization/objective function) - # set to capex for unbuilt generators in the year_on - # set to 0 for already built capacity because capacity expansion isn't considered for existing generators + # set to capex for unbuilt storage units in the year_on + # set to 0 for already built capacity because capacity expansion isn't considered for existing storage units add_table_col!(data, :storage, :capex_obj, Container[ByNothing(0.0) for i in 1:nrow(storage)], DollarsPerMWBuiltCapacityPerHour, "Hourly capital expenditures that is passed into the objective function. 0 for already built capacity") add_table_col!(data, :storage, :transmission_capex_obj, Container[ByNothing(0.0) for i in 1:nrow(storage)], DollarsPerMWBuiltCapacityPerHour, "Hourly transmission capital expenditures that is passed into the objective function. 0 for already built capacity") @@ -229,8 +253,14 @@ function add_buildable_storage!(config, data) build_storage = get_table(data, :build_storage) bus = get_table(data, :bus) + # Filter any already-built exogenous storage units + filter!(build_storage) do row + row.build_type == "exog" && row.year_on >= config[:year_gen_data] && return false + return true + end + spec_names = filter!( - !in((:bus_idx, :reg_factor, :year_off, :year_shutdown, :pcap_inv)), + !in((:bus_idx, :reg_factor, :year_off, :year_shutdown, :pcap_inv, :year_unbuilt, :past_invest_cost, :past_invest_subsidy)), propertynames(storage) ) years = get_years(data) @@ -247,16 +277,19 @@ function add_buildable_storage!(config, data) for bus_idx in bus_idxs if spec_row.build_type == "endog" # For endogenous new builds a new storage device is created for each year - for year in years + for (yr_idx, year) in enumerate(years) year < year_on_min && continue year > year_on_max && continue # Make row to add to the storage table new_row = Dict(:bus_idx => bus_idx, (spec_name=>spec_row[spec_name] for spec_name in spec_names)...) new_row[:year_on] = year - new_row[:year_shutdown] = add_to_year(year, spec_row.age_shutdown) + new_row[:year_unbuilt] = get(years, yr_idx - 1, config[:year_gen_data]) + new_row[:year_shutdown] = "y9999" #add_to_year(year, spec_row.age_shutdown) new_row[:year_off] = "y9999" new_row[:pcap_inv] = 0.0 + new_row[:past_invest_cost] = Container(0.0) + new_row[:past_invest_subsidy] = Container(0.0) # Add reg_factor if needed hasproperty(storage, :reg_factor) && (new_row[:reg_factor] = bus.reg_factor[bus_idx]) @@ -272,9 +305,12 @@ function add_buildable_storage!(config, data) # for exogenously specified storage, only one storage device is created with the specified year_on new_row = Dict{}(:bus_idx => bus_idx, (spec_name=>spec_row[spec_name] for spec_name in spec_names)...) - new_row[:year_shutdown] = add_to_year(spec_row.year_on, spec_row.age_shutdown) + new_row[:year_shutdown] = "y9999" #add_to_year(spec_row.year_on, spec_row.age_shutdown) new_row[:year_off] = "y9999" new_row[:pcap_inv] = 0.0 + new_row[:year_unbuilt] = add_to_year(new_row[:year_on], -1) + new_row[:past_invest_cost] = Container(0.0) + new_row[:past_invest_subsidy] = Container(0.0) # Add reg_factor if needed hasproperty(storage, :reg_factor) && (new_row[:reg_factor] = bus.reg_factor[bus_idx]) @@ -458,7 +494,7 @@ function modify_model!(mod::Storage, config, data, model) # Add some results so that policy mods can add to the investment subsidy add_results_formula!(data, :storage, :invest_subsidy, "0", Dollars, "Investment subsidies to go to the producer") - add_results_formula!(data, :storage, :invest_subsidy_permw_perhr, "invest_subsidy / ecap_total", DollarsPerMWCapacityPerHour, "Investment subsidies per MW per hour") + add_results_formula!(data, :storage, :invest_subsidy_permw_perhr, "invest_subsidy / ecap_inv_total", DollarsPerMWCapacityPerHour, "Investment subsidies per MW per hour") end """ @@ -498,10 +534,12 @@ function modify_results!(mod::Storage, config, data) add_table_col!(data, :storage, :pdischarge, pcharge_stor, MWDischarged, "Rate of discharging, in MW") add_table_col!(data, :storage, :echarge, echarge_stor, MWhCharged, "Energy that went into charging the storage device (includes any round-trip storage losses)") add_table_col!(data, :storage, :edischarge, edischarge_stor, MWhDischarged, "Energy that was discharged by the storage device") - add_table_col!(data, :storage, :pcap_inv_sim, pcap_inv_sim, MWCapacity, "Total power discharge capacity that was invested for the generator during the sim. (single value). Still the same even after retirement") - add_table_col!(data, :storage, :ecap_inv_sim, ecap_inv_sim, MWhCapacity, "Total yearly energy discharge capacity that was invested for the generator during the sim. (pcap_inv_sim * hours per year) (single value). Still the same even after retirement") + add_table_col!(data, :storage, :pcap_inv_sim, pcap_inv_sim, MWCapacity, "Total power discharge capacity that was invested for the storage unit during the sim. (single value). Still the same even after retirement") + add_table_col!(data, :storage, :ecap_inv_sim, ecap_inv_sim, MWhCapacity, "Total yearly energy discharge capacity that was invested for the storage unit during the sim. (pcap_inv_sim * hours per year) (single value). Still the same even after retirement") add_table_col!(data, :storage, :lmp_e, lmp_stor, DollarsPerMWhDischarged, "Locational marginal price of electricity") + # Update pcap_inv + storage.pcap_inv = max.(storage.pcap_inv, storage.pcap_inv_sim) transform!(storage, [:pcharge, :storage_efficiency] => ByRow((p,η) -> p * (1 - η)) => :ploss @@ -515,6 +553,7 @@ function modify_results!(mod::Storage, config, data) add_results_formula!(data, :storage, :echarge_total, "SumHourly(echarge)", MWhCharged, "Total energy charged") add_results_formula!(data, :storage, :edischarge_total, "SumHourly(edischarge)", MWhDischarged, "Total energy discharged") add_results_formula!(data, :storage, :eloss_total, "SumHourly(eloss)", MWhLoss, "Total energy loss") + add_results_formula!(data, :storage, :ecap_inv_total, "SumHourlyWeighted(pcap_inv)", MWhCapacity, "Total invested energy discharge capacity over the time period given.") # Add electricity cost and revenue add_results_formula!(data, :storage, :electricity_revenue, "SumHourly(lmp_e, edischarge)", Dollars, "Revenue from discharging electricity to the grid") @@ -531,12 +570,16 @@ function modify_results!(mod::Storage, config, data) add_results_formula!(data, :storage, :capex_per_mwh, "capex_cost / edischarge_total", DollarsPerMWhDischarged, "Average capital cost for discharging 1 MWh of energy") add_results_formula!(data, :storage, :transmission_capex_cost, "SumYearly(transmission_capex_obj, ecap_inv_sim)", Dollars, "Total annualized transmission capital expenditures paid, in dollars") add_results_formula!(data, :storage, :transmission_capex_per_mwh, "transmission_capex_cost / edischarge_total", DollarsPerMWhDischarged, "Average transmission capital cost for discharging 1 MWh of energy") + add_results_formula!(data, :storage, :invest_cost, "transmission_capex_cost + capex_cost", Dollars, "Total annualized investment costs, in dollars") + add_results_formula!(data, :storage, :invest_cost_permw_perhr, "invest_cost / ecap_inv_total", DollarsPerMWCapacityPerHour, "Average investment cost per MW of invested capacity per hour") # Variable costs add_results_formula!(data, :storage, :variable_cost, "vom_cost", Dollars, "Total variable costs for operation, including vom. One day if storage has fuel, this could include fuel also") add_results_formula!(data, :storage, :variable_cost_per_mwh, "variable_cost / edischarge_total", DollarsPerMWhDischarged, "Average variable costs for operation, including vom, for discharging 1MWh from storage. One day if storage has fuel, this could include fuel also") add_results_formula!(data, :storage, :production_subsidy, "0", Dollars, "Total production subsidy for storage") add_results_formula!(data, :storage, :production_subsidy_per_mwh, "production_subsidy / edischarge_total", DollarsPerMWhDischarged, "Average production subsidy for discharging 1 MWh from storage") + add_results_formula!(data, :storage, :past_invest_cost_total, "SumHourlyWeighted(past_invest_cost, pcap_inv)", Dollars, "Past investment cost for storage") + add_results_formula!(data, :storage, :past_invest_subsidy_total, "SumHourlyWeighted(past_invest_subsidy, pcap_inv)", Dollars, "Past investment subsidy for storage") add_results_formula!(data, :storage, :net_variable_cost, "variable_cost - production_subsidy", Dollars, "Net variable costs for storage") add_results_formula!(data, :storage, :net_variable_cost_per_mwh, "net_variable_cost / edischarge_total", DollarsPerMWhDischarged, "Average net variable costs per MWh of discharged energy") @@ -555,9 +598,9 @@ function modify_results!(mod::Storage, config, data) # Policy costs add_results_formula!(data, :storage, :pol_cost, "-invest_subsidy - production_subsidy", Dollars, "Cost from all policy types") add_results_formula!(data, :storage, :pol_cost_per_mwh, "pol_cost / edischarge_total", DollarsPerMWhDischarged, "Average policy cost per MWh of discharged energy") - add_results_formula!(data, :storage, :government_revenue, "- invest_subsidy - production_subsidy", Dollars, "Government revenue earned from storage of energy") + add_results_formula!(data, :storage, :government_revenue, "- invest_subsidy - production_subsidy - past_production_subsidy_total", Dollars, "Government revenue earned from storage of energy") add_results_formula!(data, :storage, :going_forward_cost, "production_cost + pol_cost", Dollars, "Total cost of production and policies") - add_results_formula!(data, :storage, :total_cost_prelim, "going_forward_cost", Dollars, "Total cost of production. Right now only includes going_forward_cost, but may eventually contain past capex cost") + add_results_formula!(data, :storage, :total_cost_prelim, "going_forward_cost + past_invest_cost_total - past_invest_subsidy_total", Dollars, "Total cost of production. Right now only includes going_forward_cost, but may eventually contain past capex cost") add_results_formula!(data, :storage, :net_total_revenue_prelim, "electricity_revenue - electricity_cost - total_cost_prelim", Dollars, "Preliminary net total revenue, including electricity costs/revenue and total cost, before adjusting for cost-of-service rebates") add_results_formula!(data, :storage, :cost_of_service_rebate, "CostOfServiceRebate(storage)", Dollars, "This is a specially calculated result, which is the sum of net_total_revenue_prelim * reg_factor for each generator") add_results_formula!(data, :storage, :total_cost, "total_cost_prelim + cost_of_service_rebate", Dollars, "The total cost after adjusting for the cost of service") @@ -585,6 +628,7 @@ Saves the updated storage table with any additional storage units, updated capac """ function save_updated_storage_table(config, data) years = get_years(data) + nyr = get_num_years(data) year_end = last(years) storage = get_table(data, :storage) @@ -601,21 +645,27 @@ function save_updated_storage_table(config, data) # Update pcap0 to be the last value of pcap storage_tmp.pcap0 = last.(storage.pcap) - storage_tmp.pcap_inv = map(eachrow(storage)) do row row.build_status == "new" || return row.pcap_inv return row.pcap_inv_sim end + # Gather the past investment costs and subsidies + for i in 1:nrow(storage_tmp) + storage_tmp.build_status[i] == "new" || continue + @info "updating the past investment cost/subsidy for $i" + storage_tmp.past_invest_cost[i] = maximum(yr_idx->compute_result(data, :storage, :invest_cost_permw_perhr, i, yr_idx), 1:nyr) + storage_tmp.past_invest_subsidy[i] = maximum(yr_idx->compute_result(data, :storage, :invest_subsidy_permw_perhr, i, yr_idx), 1:nyr) + end + # Filter anything with capacity below the threshold thresh = config[:pcap_retirement_threshold] - filter!(storage_tmp) do row # Keep anything above the threshold row.pcap0 > thresh && return true row.pcap_inv <= thresh && return false - row.build_type == "exog" && return false + row.build_type == "exog" && return false # We don't care to keep track of exogenous past capex # Below the threshold, check to see if we are still within the economic lifetime year_econ_life = add_to_year(row.year_on, row.econ_life) diff --git a/test/data/3bus/build_gen.csv b/test/data/3bus/build_gen.csv index a1f3a5df..0076cc9d 100644 --- a/test/data/3bus/build_gen.csv +++ b/test/data/3bus/build_gen.csv @@ -4,5 +4,5 @@ none,country,archenland,1,unbuilt,endog,test_wind_build,wind,wind,0,0,0.5,0,0.4, none,country,archenland,1,unbuilt,endog,test_oswind_build,wind,oswind,0,0,0.5,0,0.4,5,0,6,6,0.3,0,,35,y2035,,30,0,0,0,1 none,country,narnia,1,unbuilt,endog,test_coal_build,coal,coal,0,0,1,0.6,0.68,2,0.5555555555555556,6,7,0.1,0,,35,,y2030,30,1,0,9,1 none,buildngcc,1,1,unbuilt,endog,test_ngcc_build,ng,ngcc,0,0,1.5,0,0.58,1,0.21428571428571427,5,5,0.1,0,,35,y2015,,30,0.6,0,7,1 -none,bus_idx,1,1,unbuilt,exog,test_exog_nuc_build,nuclear,nuclear,0.5,0,0.5,0.6,0.92,10,5,5,10,0.1,0,y2020,35,,,30,0,0,1,1 +none,bus_idx,1,1,unbuilt,exog,test_exog_nuc_build,nuclear,nuclear,0.5,0,0.5,0.6,0.92,2,5,5,10,0.1,0,y2021,35,,,30,0,0,1,1 none,bus_idx,2,1,unbuilt,exog,test_exog_solar_build,solar,solar,0.5,0,1,0,0.25,2,0,2.5,5,0.1,0,y2060,35,,,30,0,0,0,1 \ No newline at end of file diff --git a/test/testiteration.jl b/test/testiteration.jl index 1301a02d..9db873c2 100644 --- a/test/testiteration.jl +++ b/test/testiteration.jl @@ -88,7 +88,8 @@ @testset "Test past capex calculations in sequential simulations" begin config_itc_file = joinpath(@__DIR__, "config", "config_3bus_itc.yml") - config = read_config(config_file, config_itc_file) + config_stor_file = joinpath(@__DIR__, "config", "config_stor.yml") + config = read_config(config_file, config_itc_file, config_stor_file) data = read_data(config) model = setup_model(config, data) optimize!(model) @@ -100,26 +101,31 @@ gen_updated_file = get_out_path(config, "gen.csv") gen_updated = read_table(gen_updated_file) + storage_updated_file = get_out_path(config, "storage.csv") + storage_updated = read_table(storage_updated_file) # Make sure that the past invest costs get updated for the next sim @test any(>(0.0), gen_updated.past_invest_cost) @test any(>(0.0), gen_updated.past_invest_subsidy) # Now run another sim with the updated gen table - config_itc_file = joinpath(@__DIR__, "config", "config_3bus_itc.yml") - config = read_config(config_file, config_itc_file) + config = read_config(config_file, config_itc_file, config_stor_file) config[:years] = ["y2050", "y2060", "y2070"] config[:year_gen_data] = "y2040" config[:gen_file] = gen_updated_file + config[:mods][:stor] = Storage(;name=:stor, file=storage_updated_file, build_file = config[:mods][:stor].build_file) data = read_data(config) model = setup_model(config, data) optimize!(model) + @test check(model) parse_results!(config, data, model) process_results!(config, data) gen = get_table(data, :gen) @test compute_result(data, :gen, :past_invest_cost_total) > 0.0 @test compute_result(data, :gen, :past_invest_subsidy_total) > 0.0 + @test compute_result(data, :storage, :past_invest_cost_total) > 0.0 + @test compute_result(data, :storage, :past_invest_subsidy_total) > 0.0 # Test that no past invest cost for exogenous generators @test compute_result(data, :gen, :past_invest_cost_total, :build_type=>"exog") == 0.0 @@ -128,7 +134,7 @@ @test compute_result(data, :gen, :past_invest_subsidy_total, :build_status=>"new") == 0.0 @test any(==("y2020"), gen.year_unbuilt) - gen_idxs_unbuilt_2020 = get_row_idxs(gen, :year_unbuilt=>"y2020") + gen_idxs_unbuilt_2020 = get_row_idxs(gen, [:year_unbuilt=>"y2020", :build_type=>"endog"]) for gen_idx in gen_idxs_unbuilt_2020 # In 2050, the investment cost should be half of the full amount. @test gen.econ_life[gen_idx] == 35 From a0deb058fbc28dbfdbea97222466c64f0914d934 Mon Sep 17 00:00:00 2001 From: Ethan Russell Date: Wed, 14 Jun 2023 09:05:17 -0400 Subject: [PATCH 19/21] Add sequential storage --- docs/src/types/iterable.md | 1 + src/results/parse.jl | 8 +++++++- src/types/Iterable.jl | 9 +++++++++ src/types/iterables/RunSequential.jl | 3 --- src/types/modifications/Storage.jl | 19 ++++++++++++++----- test/testiteration.jl | 1 + 6 files changed, 32 insertions(+), 9 deletions(-) diff --git a/docs/src/types/iterable.md b/docs/src/types/iterable.md index acc55080..98848147 100644 --- a/docs/src/types/iterable.md +++ b/docs/src/types/iterable.md @@ -3,6 +3,7 @@ Iterable ```@docs Iterable init! +issequential should_iterate iterate! should_reread_data diff --git a/src/results/parse.jl b/src/results/parse.jl index fefef517..8f68e6b1 100644 --- a/src/results/parse.jl +++ b/src/results/parse.jl @@ -359,7 +359,13 @@ function save_updated_gen_table(config, data) ) gen_tmp_combined.pcap_max = copy(gen_tmp_combined.pcap0) - CSV.write(get_out_path(config, "gen.csv"), gen_tmp_combined) + file_out = get_out_path(config, "gen.csv") + CSV.write(file_out, gen_tmp_combined) + + # Update config[:gen_file] to be from the current out_path + if issequential(get_iterator(config)) + config[:gen_file] = file_out + end return nothing end export save_updated_gen_table diff --git a/src/types/Iterable.jl b/src/types/Iterable.jl index 06c2728d..7f8f0df0 100644 --- a/src/types/Iterable.jl +++ b/src/types/Iterable.jl @@ -19,6 +19,7 @@ iter: ## Interfaces * [`init!(iter::Iterable, config)`](@ref) - (optional) Initialize `iter` with `config`, making any changes. +* [`issequential(iter)`](@ref) - (optional) returns whether or not the iterator will move forward in time sequentially. Defaults to true so that the config can be reused for another simulation. * [`should_iterate(iter, config, data)`](@ref) - return whether or not the simulation should continue for another iteration. * [`iterate!(iter, config, data)`](@ref) - Makes any changes to any of the structures between iterations. * [`should_reread_data(iter)`](@ref) - Returns whether or not to reread the data when iterating. @@ -43,6 +44,14 @@ function init!(iter::Iterable, config) end export init! +""" + issequential(iter) -> ::Bool + +Return whether or not the iterator advances in years. This may be necessary for some Modifications, whether they prepare the config to move forward or not. Default is `true`. +""" +issequential(iter::Iterable) = true +export issequential + """ should_iterate(iter, config, data) -> Bool diff --git a/src/types/iterables/RunSequential.jl b/src/types/iterables/RunSequential.jl index 60391117..f8c6df29 100644 --- a/src/types/iterables/RunSequential.jl +++ b/src/types/iterables/RunSequential.jl @@ -60,9 +60,6 @@ Iterates by: * Changing `config[:gen_file]` """ function iterate!(iter::RunSequential, config, data) - # Update config[:gen_file] to be from the current out_path - config[:gen_file] = get_out_path(config, "gen.csv") - # Increment iter.state iter.state += 1 diff --git a/src/types/modifications/Storage.jl b/src/types/modifications/Storage.jl index e582780c..7fbe0d1d 100644 --- a/src/types/modifications/Storage.jl +++ b/src/types/modifications/Storage.jl @@ -1,5 +1,5 @@ """ - struct Storage <: Modification + mutable struct Storage <: Modification Storage(;name, file, build_file="") @@ -41,7 +41,7 @@ Each storage device can either be on the "gen" side or the "load" side, as speci * `pcharge_stor` gets added to `plserv_bus` * `pdischarge_stor` gets subtracted from `plserv_bus` """ -struct Storage <: Modification +mutable struct Storage <: Modification name::Symbol file::String build_file::String @@ -598,9 +598,9 @@ function modify_results!(mod::Storage, config, data) # Policy costs add_results_formula!(data, :storage, :pol_cost, "-invest_subsidy - production_subsidy", Dollars, "Cost from all policy types") add_results_formula!(data, :storage, :pol_cost_per_mwh, "pol_cost / edischarge_total", DollarsPerMWhDischarged, "Average policy cost per MWh of discharged energy") - add_results_formula!(data, :storage, :government_revenue, "- invest_subsidy - production_subsidy - past_production_subsidy_total", Dollars, "Government revenue earned from storage of energy") + add_results_formula!(data, :storage, :government_revenue, "- invest_subsidy - production_subsidy - past_invest_subsidy_total", Dollars, "Government revenue earned from storage of energy") add_results_formula!(data, :storage, :going_forward_cost, "production_cost + pol_cost", Dollars, "Total cost of production and policies") - add_results_formula!(data, :storage, :total_cost_prelim, "going_forward_cost + past_invest_cost_total - past_invest_subsidy_total", Dollars, "Total cost of production. Right now only includes going_forward_cost, but may eventually contain past capex cost") + add_results_formula!(data, :storage, :total_cost_prelim, "going_forward_cost + past_invest_cost_total - past_invest_subsidy_total", Dollars, "Total cost of production, including going_forward_cost, and past investment cost and subsidy.") add_results_formula!(data, :storage, :net_total_revenue_prelim, "electricity_revenue - electricity_cost - total_cost_prelim", Dollars, "Preliminary net total revenue, including electricity costs/revenue and total cost, before adjusting for cost-of-service rebates") add_results_formula!(data, :storage, :cost_of_service_rebate, "CostOfServiceRebate(storage)", Dollars, "This is a specially calculated result, which is the sum of net_total_revenue_prelim * reg_factor for each generator") add_results_formula!(data, :storage, :total_cost, "total_cost_prelim + cost_of_service_rebate", Dollars, "The total cost after adjusting for the cost of service") @@ -615,9 +615,16 @@ function modify_results!(mod::Storage, config, data) # Consumer welfare add_welfare_term!(data, :consumer, :storage, :cost_of_service_rebate, +) + # Government revenue + add_welfare_term!(data, :govermnent, :storage, :government_revenue, +) + # Update and save the storage table update_build_status!(config, data, :storage) save_updated_storage_table(config, data) + + if issequential(get_iterator(config)) + mod.file = get_out_path(config, "storage.csv") + end end export modify_results! @@ -684,7 +691,9 @@ function save_updated_storage_table(config, data) ) storage_tmp_combined.pcap_max = copy(storage_tmp_combined.pcap0) - CSV.write(get_out_path(config, "storage.csv"), storage_tmp_combined) + file_out = get_out_path(config, "storage.csv") + CSV.write(file_out, storage_tmp_combined) + return nothing end export save_updated_storage_table \ No newline at end of file diff --git a/test/testiteration.jl b/test/testiteration.jl index 9db873c2..713af763 100644 --- a/test/testiteration.jl +++ b/test/testiteration.jl @@ -15,6 +15,7 @@ avg_ng_prices::Vector{Float64}=Float64[] avg_ng_egen::Vector{Float64}=Float64[] end + E4ST.issequential(iter::TargetAvgAnnualNGGen) = false E4ST.fieldnames_for_yaml(::Type{TargetAvgAnnualNGGen}) = (:target, :tol) function E4ST.should_iterate(iter::TargetAvgAnnualNGGen, config, data) tgt = iter.target From 2e291b52ce144dd23bd7296eb0053bd6da1a8c3a Mon Sep 17 00:00:00 2001 From: Ethan Russell Date: Wed, 14 Jun 2023 14:03:49 -0400 Subject: [PATCH 20/21] Minor comments and corrections --- src/io/util.jl | 4 ++++ src/results/results_formulas.csv | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/io/util.jl b/src/io/util.jl index 6e2fc9af..c523c596 100644 --- a/src/io/util.jl +++ b/src/io/util.jl @@ -625,7 +625,11 @@ function Base.convert(T::Type{Symbol}, x::String) return Symbol(x) end +""" + get_past_invest_percentages(g, years) -> ::ByYear +Computes the percentage of past investment costs and/or subsidies to still be paid in each `year`, given the `year_on`, `year_unbuilt` and `econ_life` of `g`. +""" function get_past_invest_percentages(g, years) year_on = g.year_on::AbstractString year_unbuilt = g.year_unbuilt::AbstractString diff --git a/src/results/results_formulas.csv b/src/results/results_formulas.csv index afa78558..62db6a16 100644 --- a/src/results/results_formulas.csv +++ b/src/results/results_formulas.csv @@ -73,7 +73,7 @@ gen,pol_cost_per_mwh,pol_cost / egen_total,DollarsPerMWhGenerated,"Average cost gen,government_revenue,emission_cap_cost + emission_cost - invest_subsidy - production_subsidy - past_invest_subsidy_total,Dollars,Government revenue earned from generators gen,going_forward_cost,production_cost + pol_cost,Dollars,Total going forward cost gen,total_cost_prelim,going_forward_cost + past_invest_cost_total - past_invest_subsidy_total,Dollars,"Total cost of production, including past investment costs and subsidies" -gen,total_cost_prelim_per_mwh,total_cost / egen_total,DollarsPerMWhGenerated,"Average cost of producing a MWh of power, including pst investment costs and subsidies" +gen,total_cost_prelim_per_mwh,total_cost_prelim / egen_total,DollarsPerMWhGenerated,"Average cost of producing a MWh of power, including pst investment costs and subsidies" gen,net_total_revenue_prelim,electricity_revenue - total_cost_prelim,Dollars,"Preliminary net total revenue, including electricity revenue minus total cost, before adjusting for cost-of-service rebates" gen,cost_of_service_rebate,CostOfServiceRebate(gen),Dollars,"This is a specially calculated result, which is the sum of net_total_revenue_prelim * reg_factor for each generator" gen,total_cost,total_cost_prelim + cost_of_service_rebate,Dollars,Total cost of production including the preliminary total cost and the cost of service rebate to consumers. From ca2a465e14e4de06a6ef3bd1aca03173fef2b013 Mon Sep 17 00:00:00 2001 From: Ethan Russell Date: Wed, 14 Jun 2023 14:58:55 -0400 Subject: [PATCH 21/21] Change _to_container to to_container --- docs/src/types/container.md | 6 ++++++ src/io/data.jl | 4 ++-- src/types/Containers.jl | 27 +++++++++++++++++++-------- src/types/modifications/Adjust.jl | 6 +++--- src/types/modifications/Storage.jl | 4 ++-- 5 files changed, 32 insertions(+), 15 deletions(-) diff --git a/docs/src/types/container.md b/docs/src/types/container.md index e289f49b..c17b0c44 100644 --- a/docs/src/types/container.md +++ b/docs/src/types/container.md @@ -3,4 +3,10 @@ Container ```@docs Container +ByNothing +ByYear +ByHour +ByYearAndHour +to_container +to_container! ``` \ No newline at end of file diff --git a/src/io/data.jl b/src/io/data.jl index 2cad8b46..b2b81404 100644 --- a/src/io/data.jl +++ b/src/io/data.jl @@ -427,8 +427,8 @@ function setup_table!(config, data, ::Val{:gen}) hasproperty(gen, :past_invest_cost) || (gen.past_invest_cost = zeros(nrow(gen))) hasproperty(gen, :past_invest_subsidy) || (gen.past_invest_subsidy = zeros(nrow(gen))) z = Container(0.0) - _to_container!(gen, :past_invest_cost) - _to_container!(gen, :past_invest_subsidy) + to_container!(gen, :past_invest_cost) + to_container!(gen, :past_invest_subsidy) for (idx_g, g) in enumerate(eachrow(gen)) if g.build_status == "unbuilt" if any(!=(0), g.past_invest_cost) || any(!=(0), g.past_invest_subsidy) diff --git a/src/types/Containers.jl b/src/types/Containers.jl index 5da7c2ff..ed48c097 100644 --- a/src/types/Containers.jl +++ b/src/types/Containers.jl @@ -669,20 +669,31 @@ function Base.show(io::IO, c::LoadContainer) print(io, "$n-element LoadContainer of $(l)×$m Matrix") end +""" + to_container!(table, col_name) -function _to_container!(table::DataFrame, col_name) - v = _to_container(table[!, col_name])::Vector{Container} +Converts `table[!, :col_name]` to a `Vector{Container}`. +""" +function to_container!(table::DataFrame, col_name) + v = to_container(table[!, col_name])::Vector{Container} table[!, col_name] = v end -function _to_container!(table::SubDataFrame, col_name) - _to_container!(getfield(table, :parent), col_name)::Vector{Container} +function to_container!(table::SubDataFrame, col_name) + to_container!(getfield(table, :parent), col_name)::Vector{Container} end -function _to_container(v::Vector{Container}) + +""" + to_container(v) -> cv::Vector{Container} + +Converts `v` to a `Vector{Container}` +""" +function to_container(v::Vector{Container}) v end -function _to_container(v::Vector) +function to_container(v::Vector) Container[Container(x) for x in v] end -export _to_container! -export _to_container + +export to_container! +export to_container diff --git a/src/types/modifications/Adjust.jl b/src/types/modifications/Adjust.jl index 448abc1c..790f88b3 100644 --- a/src/types/modifications/Adjust.jl +++ b/src/types/modifications/Adjust.jl @@ -178,7 +178,7 @@ function adjust_hourly!(config, data, row) vals = [row["h$h"] for h in 1:get_num_hours(data)] # Make sure the appropriate column is a Vector{Container} - _to_container!(table, variable_name) + to_container!(table, variable_name) for r in eachrow(table) r[variable_name] = operate_hourly(oper, r[variable_name], vals, yr_idx, nyr) end @@ -215,7 +215,7 @@ function adjust_yearly!(config, data, row) vals = [row[y] for y in get_years(data)] # Make sure the appropriate column is a Vector{Container} - _to_container!(table, variable_name) + to_container!(table, variable_name) for r in eachrow(table) r[variable_name] = operate_yearly(oper, r[variable_name], vals) @@ -251,7 +251,7 @@ function adjust_by_age!(config, data, row) age_type = row.age_type # Make sure the appropriate column is a Vector{Container} - _to_container!(table, variable_name) + to_container!(table, variable_name) last_sim_year = get(config, :year_previous_sim, config[:year_gen_data]) diff --git a/src/types/modifications/Storage.jl b/src/types/modifications/Storage.jl index 7fbe0d1d..fbcf83f2 100644 --- a/src/types/modifications/Storage.jl +++ b/src/types/modifications/Storage.jl @@ -152,8 +152,8 @@ function modify_setup_data!(mod::Storage, config, data) hasproperty(storage, :past_invest_cost) || (storage.past_invest_cost = zeros(nrow(storage))) hasproperty(storage, :past_invest_subsidy) || (storage.past_invest_subsidy = zeros(nrow(storage))) z = Container(0.0) - _to_container!(storage, :past_invest_cost) - _to_container!(storage, :past_invest_subsidy) + to_container!(storage, :past_invest_cost) + to_container!(storage, :past_invest_subsidy) for (idx_g, g) in enumerate(eachrow(storage)) if g.build_status == "unbuilt" if any(!=(0), g.past_invest_cost) || any(!=(0), g.past_invest_subsidy)