Skip to content

Commit

Permalink
add soc_init_fraction
Browse files Browse the repository at this point in the history
from PR#447
  • Loading branch information
adfarth committed Nov 26, 2024
1 parent a26e268 commit b8a93c2
Show file tree
Hide file tree
Showing 6 changed files with 23 additions and 7 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ Classify the change according to the following categories:
- ElectricUtility **annual_renewable_electricity_supplied_kwh**
- Site **onsite_and_grid_renewable_electricity_fraction_of_elec_load**
- Site **onsite_and_grid_renewable_energy_fraction_of_elec_and_thermal_load**
- Added input option optimize_soc_init_fraction (defaults to false) to ElectricStorage, which makes the optimization choose the inital SOC (equal to final SOC) instead of using soc_init_fraction. The initial SOC is also constrained to equal the final SOC, which eliminates the "free energy" issue. We currently do not fix SOC when soc_init_fraction is used because this has caused infeasibility.
### Changed
- Changed name of the following inputs:
- ElectricUtility input **cambium_metric_col** changed to **cambium_co2_metric**
Expand Down
19 changes: 15 additions & 4 deletions src/constraints/storage_constraints.jl
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,21 @@ end


function add_general_storage_dispatch_constraints(m, p, b; _n="")
# Constraint (4a): initial state of charge
@constraint(m,
m[Symbol("dvStoredEnergy"*_n)][b, 0] == p.s.storage.attr[b].soc_init_fraction * m[Symbol("dvStorageEnergy"*_n)][b]
)
# Constraint (4a): initial and final state of charge
if hasproperty(p.s.storage.attr[b], :optimize_soc_init_fraction) && p.s.storage.attr[b].optimize_soc_init_fraction
print("\nOptimizing "*b*" inital SOC and constraining initial SOC = final SOC. soc_init_fraction will not apply.\n")
@constraint(m,
m[Symbol("dvStoredEnergy"*_n)][b, 0] == m[:dvStoredEnergy][b, maximum(p.time_steps)]
)
else
@constraint(m,
m[Symbol("dvStoredEnergy"*_n)][b, 0] == p.s.storage.attr[b].soc_init_fraction * m[Symbol("dvStorageEnergy"*_n)][b]
)
# TODO: constrain final soc to equal initial soc
# @constraint(m,
# m[Symbol("dvStoredEnergy"*_n)][b, maximum(p.time_steps)] == p.s.storage.attr[b].soc_init_fraction * m[Symbol("dvStorageEnergy"*_n)][b]
# )
end

#Constraint (4n): State of charge upper bound is storage system size
@constraint(m, [ts in p.time_steps],
Expand Down
2 changes: 1 addition & 1 deletion src/core/absorption_chiller.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
min_ton::Float64 = 0.0, # Minimum thermal power size constraint for optimization
max_ton::Float64 = BIG_NUMBER, # Maximum thermal power size constraint for optimization
cop_thermal::Union{Float64, Nothing} = nothing, # Absorption chiller system coefficient of performance - conversion of hot thermal power input to usable cooling thermal energy output
cop_electric::Float64 = 14.1, # Absorption chiller electric consumption CoP from cooling tower heat rejection - conversion of electric power input to usable cooling thermal energy outpu
cop_electric::Float64 = 14.1, # Absorption chiller electric consumption CoP from cooling tower heat rejection - conversion of electric power input to usable cooling thermal energy output
macrs_option_years::Float64 = 0, # MACRS schedule for financial analysis. Set to zero to disable
macrs_bonus_fraction::Float64 = 0 # Percent of upfront project costs to depreciate under MACRS
heating_load_input::Union{String, Nothing} = nothing # heating load that serves as input to absorption chiller
Expand Down
4 changes: 4 additions & 0 deletions src/core/energy_storage/electric_storage.jl
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ end
model_degradation::Bool = false
degradation::Dict = Dict()
minimum_avg_soc_fraction::Float64 = 0.0
optimize_soc_init_fraction::Bool = false # If true, soc_init_fraction will not apply. Model will optimize initial SOC and constrain initial SOC = final SOC.
min_duration_hours::Real = 0.0 # Minimum amount of time storage can discharge at its rated power capacity
max_duration_hours::Real = 100000.0 # Maximum amount of time storage can discharge at its rated power capacity (ratio of ElectricStorage size_kwh to size_kw)
```
Expand Down Expand Up @@ -220,6 +221,7 @@ Base.@kwdef struct ElectricStorageDefaults
model_degradation::Bool = false
degradation::Dict = Dict()
minimum_avg_soc_fraction::Float64 = 0.0
optimize_soc_init_fraction::Bool = false
min_duration_hours::Real = 0.0
max_duration_hours::Real = 100000.0
end
Expand Down Expand Up @@ -263,6 +265,7 @@ struct ElectricStorage <: AbstractElectricStorage
model_degradation::Bool
degradation::Degradation
minimum_avg_soc_fraction::Float64
optimize_soc_init_fraction::Bool
min_duration_hours::Real
max_duration_hours::Real

Expand Down Expand Up @@ -356,6 +359,7 @@ struct ElectricStorage <: AbstractElectricStorage
s.model_degradation,
degr,
s.minimum_avg_soc_fraction,
s.optimize_soc_init_fraction,
s.min_duration_hours,
s.max_duration_hours
)
Expand Down
2 changes: 1 addition & 1 deletion src/results/electric_load.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# REopt®, Copyright (c) Alliance for Sustainable Energy, LLC. See also https://github.com/NREL/REopt.jl/blob/master/LICENSE.
"""
`ElectricLoad` results keys:
- `load_series_kw` vector of site load in every time step
- `load_series_kw` vector of site load in every time step. Does not (currently) include electric load for any new heating or cool techs.
- `critical_load_series_kw` vector of site critical load in every time step
- `annual_calculated_kwh` sum of the `load_series_kw`
- `offgrid_load_met_series_kw` vector of electric load met by generation techs, for off-grid scenarios only
Expand Down
2 changes: 1 addition & 1 deletion src/results/financial.jl
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ function get_depreciation_schedule(p::REoptInputs, tech::Union{AbstractTech,Abst

federal_itc_fraction = 0.0
try
federal_itc_fraction = tech.federal_itc_fraction # TODO: also check for total_itc_fraction as storage does not use federal_itc_fraction?
federal_itc_fraction = tech.federal_itc_fraction
catch
@warn "Did not find $(tech).federal_itc_fraction so using 0.0 in calculation of depreciation_schedule."
end
Expand Down

0 comments on commit b8a93c2

Please sign in to comment.