Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Battery storage cost constant version 2 #348

Open
wants to merge 25 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
53f7638
Added battery storage cost constant
toddleif Feb 6, 2024
4b85f29
Fixed bugs in code and added tests
toddleif Feb 11, 2024
284ec0f
Updates to test code and ran tests locally
toddleif Feb 12, 2024
321e353
Updates to runtests.jl to run without battery cost constants
toddleif Feb 13, 2024
7cb7460
Update to runtests.jl
toddleif Feb 13, 2024
334f7cf
Updates to runtests.jl
toddleif Feb 14, 2024
845e09a
Debugged financial result computation
toddleif Feb 16, 2024
42732c6
update to tests with Xpress
toddleif Feb 29, 2024
eb60c3c
Committing again to run tests
toddleif Mar 1, 2024
97173fb
Committing again to run tests
toddleif Mar 4, 2024
711ce88
Merge branch 'develop' into storage-cost-constraints-version2
toddleif Jun 3, 2024
f5192e3
Reformulated the equations to remove the indicator constraints. Updat…
toddleif Jun 4, 2024
60374c2
Added multinode capability to the battery cost constant
toddleif Jun 4, 2024
cb91a7e
Merge branch 'develop' into storage-cost-constraints-version2
adfarth Jul 3, 2024
8e5943d
Added note for the new inputs that are not used in the battery degrad…
toddleif Jul 3, 2024
1c7b658
Merge branch 'develop' into storage-cost-constraints-version2
adfarth Jul 3, 2024
c8c247d
Merge branch 'storage-cost-constraints-version2' of https://github.co…
toddleif Jul 3, 2024
4a20641
Revert "Merge branch 'storage-cost-constraints-version2' of https://g…
toddleif Jul 3, 2024
a887e78
Corrected the version number
toddleif Jul 3, 2024
88e25c4
Updates to the ElectricStorage cost constant code
toddleif Nov 3, 2024
6594016
Merge branch 'develop' into storage-cost-constraints-version2
toddleif Nov 3, 2024
b6fe81d
Update CHANGELOG.md
adfarth Nov 4, 2024
4138157
Edits based on code review
toddleif Nov 7, 2024
7c0acf0
Merge branch 'develop' into storage-cost-constraints-version2
adfarth Nov 7, 2024
ba610a6
Update electric_storage.jl
adfarth Nov 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions src/core/energy_storage/electric_storage.jl
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,13 @@ end
can_grid_charge::Bool = off_grid_flag ? false : true
installed_cost_per_kw::Real = 910.0
installed_cost_per_kwh::Real = 455.0
installed_cost_constant::Real = 0.0
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@toddleif could you please add a brief description of this input to this markdown area?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a great idea. I just added a description.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@toddleif I just modified the description to be in-line with the inputs and to just give a short high-level description of what that input is. Could you review?

replace_cost_per_kw::Real = 715.0
replace_cost_per_kwh::Real = 318.0
replace_cost_constant::Real = 0.0
inverter_replacement_year::Int = 10
battery_replacement_year::Int = 10
cost_constant_replacement_year::Int = 10
macrs_option_years::Int = 7
macrs_bonus_fraction::Float64 = 0.8
macrs_itc_reduction::Float64 = 0.5
Expand Down Expand Up @@ -180,10 +183,13 @@ Base.@kwdef struct ElectricStorageDefaults
can_grid_charge::Bool = off_grid_flag ? false : true
installed_cost_per_kw::Real = 910.0
installed_cost_per_kwh::Real = 455.0
installed_cost_constant::Real = 0.0
replace_cost_per_kw::Real = 715.0
replace_cost_per_kwh::Real = 318.0
replace_cost_constant::Real = 0.0
inverter_replacement_year::Int = 10
battery_replacement_year::Int = 10
cost_constant_replacement_year::Int = 10
macrs_option_years::Int = 7
macrs_bonus_fraction::Float64 = 0.8
macrs_itc_reduction::Float64 = 0.5
Expand Down Expand Up @@ -218,10 +224,13 @@ struct ElectricStorage <: AbstractElectricStorage
can_grid_charge::Bool
installed_cost_per_kw::Real
installed_cost_per_kwh::Real
installed_cost_constant::Real
replace_cost_per_kw::Real
replace_cost_per_kwh::Real
replace_cost_constant::Real
inverter_replacement_year::Int
battery_replacement_year::Int
cost_constant_replacement_year::Int
macrs_option_years::Int
macrs_bonus_fraction::Float64
macrs_itc_reduction::Float64
Expand All @@ -233,6 +242,7 @@ struct ElectricStorage <: AbstractElectricStorage
grid_charge_efficiency::Float64
net_present_cost_per_kw::Real
net_present_cost_per_kwh::Real
net_present_cost_cost_constant::Real
model_degradation::Bool
degradation::Degradation
minimum_avg_soc_fraction::Float64
Expand Down Expand Up @@ -274,6 +284,19 @@ struct ElectricStorage <: AbstractElectricStorage

net_present_cost_per_kwh -= s.total_rebate_per_kwh

net_present_cost_cost_constant = effective_cost(;
itc_basis = s.installed_cost_constant,
replacement_cost = s.cost_constant_replacement_year >= f.analysis_years ? 0.0 : s.replace_cost_constant,
replacement_year = s.cost_constant_replacement_year,
discount_rate = f.owner_discount_rate_fraction,
tax_rate = f.owner_tax_rate_fraction,
itc = s.total_itc_fraction,
macrs_schedule = s.macrs_option_years == 7 ? f.macrs_seven_year : f.macrs_five_year,
macrs_bonus_fraction = s.macrs_bonus_fraction,
macrs_itc_reduction = s.macrs_itc_reduction

)

if haskey(d, :degradation)
degr = Degradation(;dictkeys_tosymbols(d[:degradation])...)
else
Expand All @@ -283,13 +306,15 @@ struct ElectricStorage <: AbstractElectricStorage
# copy the replace_costs in case we need to change them
replace_cost_per_kw = s.replace_cost_per_kw
replace_cost_per_kwh = s.replace_cost_per_kwh
replace_cost_constant = s.replace_cost_constant
if s.model_degradation
if haskey(d, :replace_cost_per_kw) && d[:replace_cost_per_kw] != 0.0 ||
haskey(d, :replace_cost_per_kwh) && d[:replace_cost_per_kwh] != 0.0
adfarth marked this conversation as resolved.
Show resolved Hide resolved
@warn "Setting ElectricStorage replacement costs to zero. Using degradation.maintenance_cost_per_kwh instead."
end
replace_cost_per_kw = 0.0
replace_cost_per_kwh = 0.0
replace_cost_constant = 0.0
end

return new(
Expand All @@ -305,10 +330,13 @@ struct ElectricStorage <: AbstractElectricStorage
s.can_grid_charge,
s.installed_cost_per_kw,
s.installed_cost_per_kwh,
s.installed_cost_constant,
replace_cost_per_kw,
replace_cost_per_kwh,
replace_cost_constant,
s.inverter_replacement_year,
s.battery_replacement_year,
s.cost_constant_replacement_year,
s.macrs_option_years,
s.macrs_bonus_fraction,
s.macrs_itc_reduction,
Expand All @@ -320,6 +348,7 @@ struct ElectricStorage <: AbstractElectricStorage
s.grid_charge_efficiency,
net_present_cost_per_kw,
net_present_cost_per_kwh,
net_present_cost_cost_constant,
s.model_degradation,
degr,
s.minimum_avg_soc_fraction
Expand Down
12 changes: 11 additions & 1 deletion src/core/reopt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -358,9 +358,18 @@ function build_reopt!(m::JuMP.AbstractModel, p::REoptInputs)
end
end

# indicator function to say: if the energy capacity is greater than zero, then the dvBatteryIncluded binary is 1
adfarth marked this conversation as resolved.
Show resolved Hide resolved
@constraint(m, [b in p.s.storage.types.elec],
m[:dvBatteryIncluded][b] => {m[:dvStorageEnergy][b] >= 0}) # Question: is the >= actually just a greater-than sign?

# indicator function to say: if the energy capacity is zero, then the dvBatteryIncluded binary is 0
@constraint(m, [b in p.s.storage.types.elec],
!m[:dvBatteryIncluded][b] => {m[:dvStorageEnergy][b] == 0})

@expression(m, TotalStorageCapCosts, p.third_party_factor * (
sum( p.s.storage.attr[b].net_present_cost_per_kw * m[:dvStoragePower][b] for b in p.s.storage.types.elec) +
adfarth marked this conversation as resolved.
Show resolved Hide resolved
sum( p.s.storage.attr[b].net_present_cost_per_kwh * m[:dvStorageEnergy][b] for b in p.s.storage.types.all )
sum( p.s.storage.attr[b].net_present_cost_per_kwh * m[:dvStorageEnergy][b] for b in p.s.storage.types.all ) +
sum( p.s.storage.attr[b].net_present_cost_cost_constant * m[:dvBatteryIncluded][b] for b in p.s.storage.types.elec)
))

@expression(m, TotalPerUnitSizeOMCosts, p.third_party_factor * p.pwf_om *
Expand Down Expand Up @@ -565,6 +574,7 @@ function add_variables!(m::JuMP.AbstractModel, p::REoptInputs)
dvPeakDemandMonth[p.months, 1:p.s.electric_tariff.n_monthly_demand_tiers] >= 0 # Peak electrical power demand during month m [kW]
MinChargeAdder >= 0
binGHP[p.ghp_options], Bin # Can be <= 1 if require_ghp_purchase=0, and is ==1 if require_ghp_purchase=1
dvBatteryIncluded[p.s.storage.types.all], Bin # 0 if no battery is included, 1 if battery is included
adfarth marked this conversation as resolved.
Show resolved Hide resolved
end

if !isempty(p.techs.gen) # Problem becomes a MILP
Expand Down
3 changes: 2 additions & 1 deletion src/results/electric_storage.jl
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ function add_electric_storage_results(m::JuMP.AbstractModel, p::REoptInputs, d::
r["storage_to_load_series_kw"] = round.(value.(discharge), digits=3)

r["initial_capital_cost"] = r["size_kwh"] * p.s.storage.attr[b].installed_cost_per_kwh +
r["size_kw"] * p.s.storage.attr[b].installed_cost_per_kw
r["size_kw"] * p.s.storage.attr[b].installed_cost_per_kw +
p.s.storage.attr[b].installed_cost_constant
adfarth marked this conversation as resolved.
Show resolved Hide resolved

if p.s.storage.attr[b].model_degradation
r["state_of_health"] = value.(m[:SOH]).data / value.(m[:dvStorageEnergy])["ElectricStorage"];
Expand Down
13 changes: 11 additions & 2 deletions src/results/financial.jl
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,8 @@ function initial_capex(m::JuMP.AbstractModel, p::REoptInputs; _n="")
for b in p.s.storage.types.elec
if p.s.storage.attr[b].max_kw > 0
initial_capex += p.s.storage.attr[b].installed_cost_per_kw * value.(m[Symbol("dvStoragePower"*_n)])[b] +
p.s.storage.attr[b].installed_cost_per_kwh * value.(m[Symbol("dvStorageEnergy"*_n)])[b]
p.s.storage.attr[b].installed_cost_per_kwh * value.(m[Symbol("dvStorageEnergy"*_n)])[b] +
p.s.storage.attr[b].installed_cost_constant
adfarth marked this conversation as resolved.
Show resolved Hide resolved
end
end

Expand Down Expand Up @@ -238,12 +239,20 @@ function replacement_costs_future_and_present(m::JuMP.AbstractModel, p::REoptInp
else
future_cost_storage = p.s.storage.attr[b].replace_cost_per_kwh * value.(m[Symbol("dvStorageEnergy"*_n)])[b]
end
future_cost += future_cost_inverter + future_cost_storage
if p.s.storage.attr[b].cost_constant_replacement_year >= p.s.financial.analysis_years
future_cost_cost_constant = 0
else
future_cost_cost_constant = p.s.storage.attr[b].replace_cost_constant
end

future_cost += future_cost_inverter + future_cost_storage + future_cost_cost_constant

present_cost += future_cost_inverter * (1 - p.s.financial.owner_tax_rate_fraction) /
((1 + p.s.financial.owner_discount_rate_fraction)^p.s.storage.attr[b].inverter_replacement_year)
present_cost += future_cost_storage * (1 - p.s.financial.owner_tax_rate_fraction) /
((1 + p.s.financial.owner_discount_rate_fraction)^p.s.storage.attr[b].battery_replacement_year)
present_cost += future_cost_cost_constant * (1 - p.s.financial.owner_tax_rate_fraction) /
((1 + p.s.financial.owner_discount_rate_fraction)^p.s.storage.attr[b].cost_constant_replacement_year)
end

if !isempty(p.techs.gen) # Generator replacement
Expand Down
Loading