Skip to content

Commit

Permalink
Merge pull request #353 from NREL/develop
Browse files Browse the repository at this point in the history
v0.40.0 Update to 2024 MACRS Bonus Deprecation of 60%, fix Obj
  • Loading branch information
adfarth committed Mar 4, 2024
2 parents 614ec84 + d58f301 commit 2c7ced6
Show file tree
Hide file tree
Showing 14 changed files with 40 additions and 56 deletions.
7 changes: 5 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,12 @@ Classify the change according to the following categories:
### Deprecated
### Removed

## Develop 1/29/2024
## v0.40.0
### Changed
- Test commit to check history purge preservation
- Changed **macrs_bonus_fraction** to from 0.80 to 0.60 (60%) for CHP, ElectricStorage, ColdThermalStorage, HotThermalStorage GHP, PV, Wind

### Fixed
- In `reopt.jl`, group objective function incentives (into **ObjectivePenalties**) and avoid directly modifying m[:Costs]. Previously, some of these were incorrectly included in the reported **Financial.lcc**.

## v0.39.1
### Changed
Expand Down
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "REopt"
uuid = "d36ad4e8-d74a-4f7a-ace1-eaea049febf6"
authors = ["Nick Laws", "Hallie Dunham <hallie.dunham@nrel.gov>", "Bill Becker <william.becker@nrel.gov>", "Bhavesh Rathod <bhavesh.rathod@nrel.gov>", "Alex Zolan <alexander.aolan@nrel.gov>", "Amanda Farthing <amanda.farthing@nrel.gov>"]
version = "0.39.1"
version = "0.40.0"

[deps]
ArchGDAL = "c9ce4bd3-c3d5-55b8-8973-c0e20141b8c3"
Expand Down
4 changes: 2 additions & 2 deletions src/core/chp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ conflict_res_min_allowable_fraction_of_max = 0.25
is_electric_only::Bool = false # If CHP is a prime generator that does not supply heat
macrs_option_years::Int = 5
macrs_bonus_fraction::Float64 = 0.8
macrs_bonus_fraction::Float64 = 0.6
macrs_itc_reduction::Float64 = 0.5
federal_itc_fraction::Float64 = 0.3
federal_rebate_per_kw::Float64 = 0.0
Expand Down Expand Up @@ -110,7 +110,7 @@ Base.@kwdef mutable struct CHP <: AbstractCHP
is_electric_only::Bool = false

macrs_option_years::Int = 5
macrs_bonus_fraction::Float64 = 0.8
macrs_bonus_fraction::Float64 = 0.6
macrs_itc_reduction::Float64 = 0.5
federal_rebate_per_kw::Float64 = 0.0
state_ibi_fraction::Float64 = 0.0
Expand Down
4 changes: 2 additions & 2 deletions src/core/energy_storage/electric_storage.jl
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ end
inverter_replacement_year::Int = 10
battery_replacement_year::Int = 10
macrs_option_years::Int = 7
macrs_bonus_fraction::Float64 = 0.8
macrs_bonus_fraction::Float64 = 0.6
macrs_itc_reduction::Float64 = 0.5
total_itc_fraction::Float64 = 0.3
total_rebate_per_kw::Real = 0.0
Expand Down Expand Up @@ -185,7 +185,7 @@ Base.@kwdef struct ElectricStorageDefaults
inverter_replacement_year::Int = 10
battery_replacement_year::Int = 10
macrs_option_years::Int = 7
macrs_bonus_fraction::Float64 = 0.8
macrs_bonus_fraction::Float64 = 0.6
macrs_itc_reduction::Float64 = 0.5
total_itc_fraction::Float64 = 0.3
total_rebate_per_kw::Real = 0.0
Expand Down
8 changes: 4 additions & 4 deletions src/core/energy_storage/thermal_storage.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Cold thermal energy storage sytem; specifically, a chilled water system used to
thermal_decay_rate_fraction::Float64 = 0.0004 # Thermal loss (gain) rate as a fraction of energy storage capacity, per hour (frac*energy_capacity/hr = kw_thermal)
om_cost_per_gal::Float64 = 0.0 # Yearly fixed O&M cost dependent on storage energy size
macrs_option_years::Int = 7
macrs_bonus_fraction::Float64 = 0.8
macrs_bonus_fraction::Float64 = 0.6
macrs_itc_reduction::Float64 = 0.5
total_itc_fraction::Float64 = 0.3
total_rebate_per_kwh::Float64 = 0.0
Expand All @@ -36,7 +36,7 @@ Base.@kwdef struct ColdThermalStorageDefaults <: AbstractThermalStorageDefaults
thermal_decay_rate_fraction::Float64 = 0.0004
om_cost_per_gal::Float64 = 0.0
macrs_option_years::Int = 7
macrs_bonus_fraction::Float64 = 0.8
macrs_bonus_fraction::Float64 = 0.6
macrs_itc_reduction::Float64 = 0.5
total_itc_fraction::Float64 = 0.3
total_rebate_per_kwh::Float64 = 0.0
Expand All @@ -58,7 +58,7 @@ end
thermal_decay_rate_fraction::Float64 = 0.0004
om_cost_per_gal::Float64 = 0.0
macrs_option_years::Int = 7
macrs_bonus_fraction::Float64 = 0.8
macrs_bonus_fraction::Float64 = 0.6
macrs_itc_reduction::Float64 = 0.5
total_itc_fraction::Float64 = 0.3
total_rebate_per_kwh::Float64 = 0.0
Expand All @@ -76,7 +76,7 @@ Base.@kwdef struct HotThermalStorageDefaults <: AbstractThermalStorageDefaults
thermal_decay_rate_fraction::Float64 = 0.0004
om_cost_per_gal::Float64 = 0.0
macrs_option_years::Int = 7
macrs_bonus_fraction::Float64 = 0.8
macrs_bonus_fraction::Float64 = 0.6
macrs_itc_reduction::Float64 = 0.5
total_itc_fraction::Float64 = 0.3
total_rebate_per_kwh::Float64 = 0.0
Expand Down
4 changes: 2 additions & 2 deletions src/core/generator.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
can_export_beyond_nem_limit = false,
can_curtail::Bool = false,
macrs_option_years::Int = 0,
macrs_bonus_fraction::Real = 1.0,
macrs_bonus_fraction::Real = 0.0,
macrs_itc_reduction::Real = 0.0,
federal_itc_fraction::Real = 0.0,
federal_rebate_per_kw::Real = 0.0,
Expand Down Expand Up @@ -116,7 +116,7 @@ struct Generator <: AbstractGenerator
can_export_beyond_nem_limit = false,
can_curtail::Bool = false,
macrs_option_years::Int = 0,
macrs_bonus_fraction::Real = 1.0,
macrs_bonus_fraction::Real = 0.0,
macrs_itc_reduction::Real = 0.0,
federal_itc_fraction::Real = 0.0,
federal_rebate_per_kw::Real = 0.0,
Expand Down
4 changes: 2 additions & 2 deletions src/core/ghp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ struct with outer constructor:
can_serve_dhw::Bool = false
macrs_option_years::Int = 5
macrs_bonus_fraction::Float64 = 0.8
macrs_bonus_fraction::Float64 = 0.6
macrs_itc_reduction::Float64 = 0.5
federal_itc_fraction::Float64 = 0.3
federal_rebate_per_ton::Float64 = 0.0
Expand Down Expand Up @@ -85,7 +85,7 @@ Base.@kwdef mutable struct GHP <: AbstractGHP
aux_unit_capacity_sizing_factor_on_peak_load::Float64 = 1.2

macrs_option_years::Int = 5
macrs_bonus_fraction::Float64 = 0.8
macrs_bonus_fraction::Float64 = 0.6
macrs_itc_reduction::Float64 = 0.5
federal_itc_fraction::Float64 = 0.3
federal_rebate_per_ton::Float64 = 0.0
Expand Down
4 changes: 2 additions & 2 deletions src/core/pv.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
om_cost_per_kw::Real=18.0,
degradation_fraction::Real=0.005,
macrs_option_years::Int = 5,
macrs_bonus_fraction::Real = 0.8,
macrs_bonus_fraction::Real = 0.6,
macrs_itc_reduction::Real = 0.5,
kw_per_square_foot::Real=0.01,
acres_per_kw::Real=6e-3,
Expand Down Expand Up @@ -117,7 +117,7 @@ mutable struct PV <: AbstractTech
om_cost_per_kw::Real=18.0,
degradation_fraction::Real=0.005,
macrs_option_years::Int = 5,
macrs_bonus_fraction::Real = 0.8,
macrs_bonus_fraction::Real = 0.6,
macrs_itc_reduction::Real = 0.5,
kw_per_square_foot::Real=0.01,
acres_per_kw::Real=6e-3,
Expand Down
41 changes: 12 additions & 29 deletions src/core/reopt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ function build_reopt!(m::JuMP.AbstractModel, p::REoptInputs)
m[:GHPOMCosts] = 0.0
m[:AvoidedCapexByGHP] = 0.0
m[:ResidualGHXCapCost] = 0.0
m[:ObjectivePenalties] = 0.0

if !isempty(p.techs.all)
add_tech_size_constraints(m, p)
Expand Down Expand Up @@ -441,12 +442,7 @@ function build_reopt!(m::JuMP.AbstractModel, p::REoptInputs)
m[:TotalElecBill] * (1 - p.s.financial.offtaker_tax_rate_fraction) -

# Subtract Incentives, which are taxable
m[:TotalProductionIncentive] * (1 - p.s.financial.owner_tax_rate_fraction) +

# Comfort limit violation costs
#TODO: add this to objective like SOC incentive below and
#don't then subtract out when setting lcc in results/financial.jl
m[:dvComfortLimitViolationCost] +
m[:TotalProductionIncentive] * (1 - p.s.financial.owner_tax_rate_fraction) +

# Additional annual costs, tax deductible for owner (only applies when `off_grid_flag` is true)
p.s.financial.offgrid_other_annual_costs * p.pwf_om * (1 - p.s.financial.owner_tax_rate_fraction) +
Expand All @@ -470,36 +466,23 @@ function build_reopt!(m::JuMP.AbstractModel, p::REoptInputs)
add_to_expression!(Costs, m[:Lifecycle_Emissions_Cost_Health])
end

@expression(m, Objective,
m[:Costs]
)
## Modify objective with incentives that are not part of the LCC
# 1. Comfort limit violation costs
m[:ObjectivePenalties] += m[:dvComfortLimitViolationCost]
# 2. Incentive to keep SOC high
if !(isempty(p.s.storage.types.elec)) && p.s.settings.add_soc_incentive
# Incentive to keep SOC high
add_to_expression!(
Objective,
- sum(
m[:ObjectivePenalties] += -1 * sum(
m[:dvStoredEnergy][b, ts] for b in p.s.storage.types.elec, ts in p.time_steps
) / (8760. / p.hours_per_time_step)
)
end
# 3. Incentive to minimize unserved load in each outage, not just the max over outage start times
if !isempty(p.s.electric_utility.outage_durations)
# Incentive to minimize unserved load in each outage, not just the max over outage start times
add_to_expression!(
Objective,
sum(sum(0.0001 * m[:dvUnservedLoad][s, tz, ts] for ts in 1:p.s.electric_utility.outage_durations[s]) for s in p.s.electric_utility.scenarios, tz in p.s.electric_utility.outage_start_time_steps)
)
m[:ObjectivePenalties] += sum(sum(0.0001 * m[:dvUnservedLoad][s, tz, ts] for ts in 1:p.s.electric_utility.outage_durations[s])
for s in p.s.electric_utility.scenarios, tz in p.s.electric_utility.outage_start_time_steps)
end

@objective(m, Min, m[:Objective])

# if !(isempty(p.s.storage.types.elec)) && p.s.settings.add_soc_incentive # Keep SOC high
# @objective(m, Min, m[:Costs] -
# sum(m[:dvStoredEnergy][b, ts] for b in p.s.storage.types.elec, ts in p.time_steps) /
# (8760. / p.hours_per_time_step)
# )

# end
# Set model objective
@objective(m, Min, m[:Costs] + m[:ObjectivePenalties] )

for b in p.s.storage.types.elec
if p.s.storage.attr[b].model_degradation
Expand Down
4 changes: 2 additions & 2 deletions src/core/steam_turbine.jl
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
can_curtail::Bool = false
macrs_option_years::Int = 0
macrs_bonus_fraction::Float64 = 1.0
macrs_bonus_fraction::Float64 = 0.0
```
"""
Expand Down Expand Up @@ -56,7 +56,7 @@ Base.@kwdef mutable struct SteamTurbine <: AbstractSteamTurbine
can_curtail::Bool = false

macrs_option_years::Int = 0
macrs_bonus_fraction::Float64 = 1.0
macrs_bonus_fraction::Float64 = 0.0
end


Expand Down
4 changes: 2 additions & 2 deletions src/core/wind.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
pressure_atmospheres = [],
acres_per_kw = 0.03, # assuming a power density of 30 acres per MW for turbine sizes >= 1.5 MW. No size constraint applied to turbines below 1.5 MW capacity. (not exposed in API)
macrs_option_years = 5,
macrs_bonus_fraction = 0.8,
macrs_bonus_fraction = 0.6,
macrs_itc_reduction = 0.5,
federal_itc_fraction = 0.3,
federal_rebate_per_kw = 0.0,
Expand Down Expand Up @@ -111,7 +111,7 @@ struct Wind <: AbstractTech
pressure_atmospheres = [],
acres_per_kw = 0.03, # assuming a power density of 30 acres per MW for turbine sizes >= 1.5 MW. No size constraint applied to turbines below 1.5 MW capacity.
macrs_option_years = 5,
macrs_bonus_fraction = 0.8,
macrs_bonus_fraction = 0.6,
macrs_itc_reduction = 0.5,
federal_itc_fraction = 0.3,
federal_rebate_per_kw = 0.0,
Expand Down
6 changes: 2 additions & 4 deletions src/results/financial.jl
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,6 @@ calculated in combine_results function if BAU scenario is run:
"""
function add_financial_results(m::JuMP.AbstractModel, p::REoptInputs, d::Dict; _n="")
r = Dict{String, Float64}()
if !(Symbol("dvComfortLimitViolationCost"*_n) in keys(m.obj_dict))
m[Symbol("dvComfortLimitViolationCost"*_n)] = 0.0
end
if !(Symbol("TotalProductionIncentive"*_n) in keys(m.obj_dict)) # not currently included in multi-node modeling b/c these constraints require binary vars.
m[Symbol("TotalProductionIncentive"*_n)] = 0.0
end
Expand All @@ -54,7 +51,8 @@ function add_financial_results(m::JuMP.AbstractModel, p::REoptInputs, d::Dict; _
m[Symbol("GHPCapCosts"*_n)] = 0.0
end

r["lcc"] = value(m[Symbol("Costs"*_n)]) + 0.0001 * value(m[Symbol("MinChargeAdder"*_n)]) - value(m[Symbol("dvComfortLimitViolationCost"*_n)])
r["lcc"] = value(m[Symbol("Costs"*_n)]) + 0.0001 * value(m[Symbol("MinChargeAdder"*_n)])

r["lifecycle_om_costs_before_tax"] = value(m[Symbol("TotalPerUnitSizeOMCosts"*_n)] +
m[Symbol("TotalPerUnitProdOMCosts"*_n)] + m[Symbol("TotalPerUnitHourOMCosts"*_n)] + m[Symbol("GHPOMCosts"*_n)])

Expand Down
2 changes: 1 addition & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ using HiGHS
using JSON
using REopt
using DotEnv
DotEnv.config()
DotEnv.load!()
using Random
using DelimitedFiles
Random.seed!(42)
Expand Down
2 changes: 1 addition & 1 deletion test/test_with_xpress.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1479,7 +1479,7 @@ end
@test results["Site"]["total_renewable_energy_fraction_bau"] 0.132118 atol=1e-3 # 0.1354 atol=1e-3
# CO2 emissions - totals ≈ from grid, from fuelburn, ER, $/tCO2 breakeven
@test results["Site"]["lifecycle_emissions_reduction_CO2_fraction"] 0.8 atol=1e-3 # 0.8
@test results["Financial"]["breakeven_cost_of_emissions_reduction_per_tonne_CO2"] 373.9 atol=1e-1
@test results["Financial"]["breakeven_cost_of_emissions_reduction_per_tonne_CO2"] 374.0 atol=1e-1
@test results["Site"]["annual_emissions_tonnes_CO2"] 14.2 atol=1
@test results["Site"]["annual_emissions_tonnes_CO2_bau"] 70.99 atol=1
@test results["Site"]["annual_emissions_from_fuelburn_tonnes_CO2"] 0.0 atol=1 # 0.0
Expand Down

2 comments on commit 2c7ced6

@adfarth
Copy link
Collaborator Author

@adfarth adfarth commented on 2c7ced6 Mar 4, 2024

Choose a reason for hiding this comment

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

@JuliaRegistrator register.

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

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

Registration pull request created: JuliaRegistries/General/102253

Tip: Release Notes

Did you know you can add release notes too? Just add markdown formatted text underneath the comment after the text
"Release notes:" and it will be added to the registry PR, and if TagBot is installed it will also be added to the
release that TagBot creates. i.e.

@JuliaRegistrator register

Release notes:

## Breaking changes

- blah

To add them here just re-invoke and the PR will be updated.

Tagging

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v0.40.0 -m "<description of version>" 2c7ced69f878c1fc908284005490db2246fb8cd1
git push origin v0.40.0

Please sign in to comment.