Skip to content

Commit

Permalink
Merge pull request #364 from NREL/develop
Browse files Browse the repository at this point in the history
v0.43.0
  • Loading branch information
Bill-Becker committed Mar 18, 2024
2 parents c884e78 + 023d325 commit 19e6580
Show file tree
Hide file tree
Showing 7 changed files with 27 additions and 16 deletions.
8 changes: 6 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,18 @@ Classify the change according to the following categories:
### Deprecated
### Removed

## v0.43.0
### Fixed
- `simple_payback_years` calculation when there is export credit
- Issue with `SteamTurbine` heuristic size and default calculation when `size_class` was input
- BAU emissions calculation with heating load which was using thermal instead of fuel

## v0.42.0
### Changed
- In `core/pv.jl` a change was made to make sure we are using the same assumptions as PVWatts guidelines, the default `tilt` angle for a fixed array should be 20 degrees, irrespective of it being a rooftop `(1)` or ground-mounted (open-rack)`(2)` system. By default the `tilt` will be set to 20 degrees for ground-mount and rooftop, and 0 degrees for axis-tracking (`array_type = (3) or (4)`)

> "The PVWatts® default value for the tilt angle depends on the array type: For a fixed array, the default value is 20 degrees, and for one-axis tracking the default value is zero. A common rule of thumb for fixed arrays is to set the tilt angle to the latitude of the system's location to maximize the system's total electrical output over the year. Use a lower tilt angle favor peak production in the summer months when the sun is high in the sky, or a higher tilt angle to increase output during winter months. Higher tilt angles tend to cost more for racking and mounting hardware, and may increase the risk of wind damage to the array."


## v0.41.0
### Changed
- Changed default source for CO2 grid emissions values to NREL's Cambium 2022 Database (by default: CO2e, long-run marginal emissions rates levelized (averaged) over the analysis period, assuming start year 2024). Added new emissions inputs and call to Cambium API in `src/core/electric_utility.jl`. Included option for user to use AVERT data for CO2 using **co2_from_avert** boolean.
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.42.0"
version = "0.43.0"

[deps]
ArchGDAL = "c9ce4bd3-c3d5-55b8-8973-c0e20141b8c3"
Expand Down
5 changes: 4 additions & 1 deletion src/core/bau_inputs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,10 @@ function setup_bau_emissions_inputs(p::REoptInputs, s_bau::BAUScenario, generato
## Boiler emissions
if "ExistingBoiler" in p.techs.all
for heat_type in ["space_heating", "dhw"]
bau_emissions_lb_CO2_per_year += getproperty(p.s,Symbol("$(heat_type)_load")).annual_mmbtu * p.s.existing_boiler.emissions_factor_lb_CO2_per_mmbtu
# Divide by existing_boiler.efficiency because annual_mmbtu is thermal, so convert to fuel
bau_emissions_lb_CO2_per_year += getproperty(p.s,Symbol("$(heat_type)_load")).annual_mmbtu /
p.s.existing_boiler.efficiency *
p.s.existing_boiler.emissions_factor_lb_CO2_per_mmbtu
end
end

Expand Down
4 changes: 2 additions & 2 deletions src/core/chp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ end
is_electric_only::Bool=false)
Depending on the set of inputs, different sets of outputs are determine in addition to all CHP cost and performance parameter defaults:
1. Inputs: existing_boiler_production_type_steam_or_hw and avg_boiler_fuel_load_mmbtu_per_hour
1. Inputs: hot_water_or_steam and avg_boiler_fuel_load_mmbtu_per_hour
Outputs: prime_mover, size_class, chp_elec_size_heuristic_kw, chp_max_size_kw
2. Inputs: prime_mover and avg_boiler_fuel_load_mmbtu_per_hour
Outputs: size_class, chp_elec_size_heuristic_kw, chp_max_size_kw
Expand All @@ -345,7 +345,7 @@ Depending on the set of inputs, different sets of outputs are determine in addit
Outputs: chp_elec_size_heuristic_kw, chp_max_size_kw
The main purpose of this function is to communicate the following mapping of dependency of CHP defaults versus
existing_boiler_production_type_steam_or_hot_water and avg_boiler_fuel_load_mmbtu_per_hour:
hot_water_or_steam and avg_boiler_fuel_load_mmbtu_per_hour:
If hot_water and <= 27 MMBtu/hr avg_boiler_fuel_load_mmbtu_per_hour --> prime_mover = recip_engine of size_class X
If hot_water and > 27 MMBtu/hr avg_boiler_fuel_load_mmbtu_per_hour --> prime_mover = combustion_turbine of size_class X
If steam and <= 7 MMBtu/hr avg_boiler_fuel_load_mmbtu_per_hour --> prime_mover = recip_engine of size_class X
Expand Down
2 changes: 1 addition & 1 deletion src/core/scenario.jl
Original file line number Diff line number Diff line change
Expand Up @@ -615,7 +615,7 @@ function Scenario(d::Dict; flex_hvac_from_json=false)
end

steam_turbine = nothing
if haskey(d, "SteamTurbine") && d["SteamTurbine"]["max_kw"] > 0.0
if haskey(d, "SteamTurbine")
if !isnothing(existing_boiler)
total_fuel_heating_load_mmbtu_per_hour = (space_heating_load.loads_kw + dhw_load.loads_kw) / existing_boiler.efficiency / KWH_PER_MMBTU
avg_boiler_fuel_load_mmbtu_per_hour = sum(total_fuel_heating_load_mmbtu_per_hour) / length(total_fuel_heating_load_mmbtu_per_hour)
Expand Down
14 changes: 9 additions & 5 deletions src/core/steam_turbine.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
```julia
size_class::Union{Int64, Nothing} = nothing
min_kw::Float64 = 0.0
max_kw::Float64 = 0.0
max_kw::Float64 = 1.0e9
electric_produced_to_thermal_consumed_ratio::Float64 = NaN
thermal_produced_to_thermal_consumed_ratio::Float64 = NaN
is_condensing::Bool = false
Expand Down Expand Up @@ -34,7 +34,7 @@
Base.@kwdef mutable struct SteamTurbine <: AbstractSteamTurbine
size_class::Union{Int64, Nothing} = nothing
min_kw::Float64 = 0.0
max_kw::Float64 = 0.0
max_kw::Float64 = 1.0e9
electric_produced_to_thermal_consumed_ratio::Float64 = NaN
thermal_produced_to_thermal_consumed_ratio::Float64 = NaN
is_condensing::Bool = false
Expand Down Expand Up @@ -204,15 +204,20 @@ function get_steam_turbine_defaults_size_class(;avg_boiler_fuel_load_mmbtu_per_h
defaults = JSON.parsefile(joinpath(dirname(@__FILE__), "..", "..", "data", "steam_turbine", "steam_turbine_default_data.json"))
class_bounds = [(0.0, 25000.0), (0, 1000.0), (1000.0, 5000.0), (5000.0, 25000.0)]
n_classes = length(class_bounds)
steam_turbine_electric_efficiency = 0.07 # Typical, steam_turbine_kwe / boiler_fuel_kwt
st_elec_size_heuristic_kw = nothing
if !isnothing(size_class)
if size_class < 0 || size_class > (n_classes-1)
throw(@error("Invalid size_class $size_class given for steam_turbine, must be in [0,1,2,3]"))
end
if !isnothing(avg_boiler_fuel_load_mmbtu_per_hour)
thermal_power_in_kw = avg_boiler_fuel_load_mmbtu_per_hour * KWH_PER_MMBTU
st_elec_size_heuristic_kw = thermal_power_in_kw * steam_turbine_electric_efficiency
end
elseif !isnothing(avg_boiler_fuel_load_mmbtu_per_hour)
if avg_boiler_fuel_load_mmbtu_per_hour <= 0
throw(@error("avg_boiler_fuel_load_mmbtu_per_hour must be > 0.0 MMBtu/hr"))
end
steam_turbine_electric_efficiency = 0.07 # Typical, steam_turbine_kwe / boiler_fuel_kwt
thermal_power_in_kw = avg_boiler_fuel_load_mmbtu_per_hour * KWH_PER_MMBTU
st_elec_size_heuristic_kw = thermal_power_in_kw * steam_turbine_electric_efficiency
# With heuristic size, find the suggested size class
Expand All @@ -234,7 +239,6 @@ function get_steam_turbine_defaults_size_class(;avg_boiler_fuel_load_mmbtu_per_h
end
else
size_class = 0
st_elec_size_heuristic_kw = nothing
end

steam_turbine_defaults = get_steam_turbine_defaults(size_class, defaults)
Expand All @@ -243,7 +247,7 @@ function get_steam_turbine_defaults_size_class(;avg_boiler_fuel_load_mmbtu_per_h
("prime_mover", "steam_turbine"),
("size_class", size_class),
("default_inputs", steam_turbine_defaults),
("chp_size_based_on_avg_heating_load_kw", st_elec_size_heuristic_kw),
("chp_elec_size_heuristic_kw", st_elec_size_heuristic_kw),
("size_class_bounds", class_bounds)
])

Expand Down
8 changes: 4 additions & 4 deletions src/results/proforma.jl
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ function proforma_results(p::REoptInputs, d::Dict)

# Optimal Case calculations
electricity_bill_series = escalate_elec(d["ElectricTariff"]["year_one_bill_before_tax"])
export_credit_series = escalate_elec(d["ElectricTariff"]["year_one_export_benefit_before_tax"])
export_credit_series = escalate_elec(-d["ElectricTariff"]["year_one_export_benefit_before_tax"])

# In the two party case the electricity and export credits are incurred by the offtaker not the developer
if third_party
Expand Down Expand Up @@ -190,8 +190,8 @@ function proforma_results(p::REoptInputs, d::Dict)
electricity_bill_series = escalate_elec(d["ElectricTariff"]["year_one_bill_before_tax"])
electricity_bill_series_bau = escalate_elec(d["ElectricTariff"]["year_one_bill_before_tax_bau"])

export_credit_series = escalate_elec(-d["ElectricTariff"]["lifecycle_export_benefit_after_tax"])
export_credit_series_bau = escalate_elec(-d["ElectricTariff"]["lifecycle_export_benefit_after_tax_bau"])
export_credit_series = escalate_elec(-d["ElectricTariff"]["year_one_export_benefit_before_tax"])
export_credit_series_bau = escalate_elec(-d["ElectricTariff"]["year_one_export_benefit_before_tax_bau"])

annual_income_from_host_series = repeat([-1 * r["annualized_payment_to_third_party"]], years)

Expand Down Expand Up @@ -225,7 +225,7 @@ function proforma_results(p::REoptInputs, d::Dict)

else # get cumulative cashflow for offtaker
electricity_bill_series_bau = escalate_elec(d["ElectricTariff"]["year_one_bill_before_tax_bau"])
export_credit_series_bau = escalate_elec(-d["ElectricTariff"]["lifecycle_export_benefit_after_tax_bau"])
export_credit_series_bau = escalate_elec(-d["ElectricTariff"]["year_one_export_benefit_before_tax_bau"])
total_operating_expenses_bau = electricity_bill_series_bau + export_credit_series_bau + m.om_series_bau
total_cash_incentives_bau = m.total_pbi_bau * (1 - p.s.financial.offtaker_tax_rate_fraction)

Expand Down

4 comments on commit 19e6580

@Bill-Becker
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@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/103068

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.43.0 -m "<description of version>" 19e65802c156100a55d4ffaa6146e981de2bfb20
git push origin v0.43.0

Also, note the warning: Version 0.43.0 skips over 0.42.0
This can be safely ignored. However, if you want to fix this you can do so. Call register() again after making the fix. This will update the Pull request.

@Bill-Becker
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@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 updated: JuliaRegistries/General/103068

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.43.0 -m "<description of version>" 19e65802c156100a55d4ffaa6146e981de2bfb20
git push origin v0.43.0

Please sign in to comment.