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

Add Grid Renewable Energy Fraction #426

Open
wants to merge 81 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 62 commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
0d4a787
Add API call for renewable energy fraction
pypapus Jul 30, 2024
71acc5e
Fixed cambium API call
pypapus Jul 31, 2024
eca3f12
Clean energy fraction added to scenarios
pypapus Aug 1, 2024
80d1d3e
Include profile of grid clean energy contribution in kW
pypapus Aug 1, 2024
c095d48
Updated help text and added checks for user-provided values
pypapus Aug 2, 2024
b67ff48
Corrected off-grid flag in scenario.jl
pypapus Aug 2, 2024
9a8f09f
Edited to remove cef calculation using BAU electric load
pypapus Aug 12, 2024
379eeab
Added new "cef_constraints" to calculate clean energy fraction of the…
pypapus Aug 12, 2024
26f5cec
Added cef (kWh) from the grid in accounting for renewable energy perc…
pypapus Aug 12, 2024
4cce89e
Added new function to calculate the clean_energy_fraction (kWh) grid …
pypapus Aug 12, 2024
6500b40
Added new input to include grid cef (kWh) in renewable energy percent…
pypapus Aug 12, 2024
98d22b5
Updated function adds grid clean energy kWh serving the load to results
pypapus Aug 12, 2024
c3c4d90
Merge branch 'develop' into gridRE-dev
adfarth Aug 12, 2024
e3b0300
removed "hours_per_time_step" to use model time step.
pypapus Aug 15, 2024
248481b
Added "annual_clean_grid_to_load_kwh" in results
pypapus Aug 15, 2024
1d77ec8
Merge branch 'gridRE-dev' of https://github.com/NREL/REopt.jl into gr…
pypapus Aug 15, 2024
fbf7691
Combined cambium_emissions_profile() and cambium_clean_energy_fractio…
pypapus Aug 16, 2024
29518dc
Update electric_utility.jl
adfarth Sep 10, 2024
132f982
Merge branch 'develop' into gridRE-dev
adfarth Nov 4, 2024
3a4bafd
spelling
adfarth Nov 5, 2024
8a34550
Merge branch 'develop' into gridRE-dev
adfarth Nov 12, 2024
dec6733
change cambium_metric_col to cambium_co2_metric
adfarth Nov 12, 2024
3916ba8
Change **cambium_emissions_region** to **cambium_region** and clean u…
adfarth Nov 12, 2024
37de923
Update electric_utility.jl
adfarth Nov 13, 2024
ff29a78
emissions_profile to profile_data
adfarth Nov 13, 2024
cee8176
reorganize constraints
adfarth Nov 13, 2024
8571808
minor edits
adfarth Nov 13, 2024
60cdeae
simplify constraints
adfarth Nov 14, 2024
7596768
Update renewable_energy_constraints.jl
adfarth Nov 14, 2024
434f928
Update site.jl
adfarth Nov 14, 2024
3b7a93a
update outputs
adfarth Nov 14, 2024
f2bb448
add outputs
adfarth Nov 14, 2024
a058fed
fix to align_profile_with_load_year
adfarth Nov 14, 2024
c2353fb
fixes to calcs
adfarth Nov 15, 2024
42be276
Update financial.jl
adfarth Nov 15, 2024
b9b1509
Update runtests.jl
adfarth Nov 15, 2024
82aaba4
add a test
adfarth Nov 15, 2024
394ffc8
Update CHANGELOG.md
adfarth Nov 15, 2024
bf72ef7
avoid annual grid RE if mpc
adfarth Nov 15, 2024
b57f878
Update runtests.jl
adfarth Nov 19, 2024
f333311
address failing tests
adfarth Nov 19, 2024
f2b2871
Update runtests.jl
adfarth Nov 20, 2024
c357ddf
change variable name
adfarth Nov 21, 2024
a26e268
conditionally show warning
adfarth Nov 26, 2024
b8a93c2
add soc_init_fraction
adfarth Nov 26, 2024
f09fe6e
small updates
adfarth Nov 26, 2024
9a4dd25
add a PV inputs check
adfarth Nov 26, 2024
9491bb9
fix test
adfarth Nov 26, 2024
5f6def7
fix to prod factor check
adfarth Dec 2, 2024
deeb15f
add description to outage_durations
adfarth Dec 6, 2024
a0c0b77
change output names to stay below 63 chars
adfarth Dec 12, 2024
df4e6f0
Merge branch 'develop' into gridRE-dev
adfarth Dec 12, 2024
9785939
Update CHANGELOG.md
hdunham Dec 13, 2024
92d067b
update changelog/comment
hdunham Dec 13, 2024
599e2e4
update notes about considerations when battery can export to grid in …
hdunham Dec 13, 2024
d1e9ff7
use REopt.KWH_PER_MMBTU in tests
hdunham Dec 13, 2024
52b3c0f
minor comment updates
hdunham Dec 13, 2024
f022754
clarify test "Renewable Energy from Grid"
hdunham Dec 13, 2024
c4d7871
typo
hdunham Dec 13, 2024
8ec5069
group renewable_energy_fraction_series with similar inputs in Electri…
hdunham Dec 13, 2024
08b0ecb
add to error msg
hdunham Dec 13, 2024
9c8b6a5
util function error_if_series_vals_not_0_to_1
hdunham Dec 13, 2024
818bedd
add to dictkeys_tosymbols
adfarth Dec 16, 2024
74a3c4b
fix Degredation docstring
hdunham Dec 16, 2024
156d035
Merge branch 'gridRE-dev' of https://github.com/NREL/REopt.jl into gr…
hdunham Dec 16, 2024
5fc1160
fix make sub hr time step export rates work
hdunham Dec 17, 2024
e90f270
Update CHANGELOG.md
hdunham Dec 17, 2024
360427b
update manifest
hdunham Dec 17, 2024
55ef6fc
Merge branch 'develop' into gridRE-dev
adfarth Dec 18, 2024
c372337
Revert "Merge branch 'develop' into gridRE-dev"
adfarth Dec 18, 2024
bdb9a45
Revert "update manifest"
adfarth Dec 18, 2024
699abdd
use == to test string
hdunham Dec 18, 2024
7bde370
Merge branch 'develop' into gridRE-dev
hdunham Dec 20, 2024
8d6fcc6
resolve env with 1.8.3
hdunham Dec 20, 2024
5610a11
update manifest to julia 1.11
hdunham Dec 23, 2024
a6bd8b5
simplify compat
hdunham Dec 23, 2024
f7a2d28
update authors
hdunham Dec 23, 2024
37d32e1
typo
hdunham Dec 23, 2024
cc70963
Merge branch 'develop' into gridRE-dev
adfarth Jan 6, 2025
210ec72
rm inaccurate note in docstring
hdunham Jan 8, 2025
c9c1aaa
Merge branch 'develop' into gridRE-dev
adfarth Jan 13, 2025
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
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,27 @@ Classify the change according to the following categories:
### Removed


## gridRE-dev
Copy link
Collaborator

Choose a reason for hiding this comment

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

is the plan to merge #456 into this and then merge together or to merge one first?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I was thinking we would merge this one first if possible, because we might not get to that one until mid January. That PR would address an issue that already exists with all of the % RE calculations, whereas this one adds new RE outputs (that do also have the whole total load issue). Do you think that's an okay approach?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes but another thought is that if there is a known issue that we aren't fixing right away I wonder if it makes sense to temporarily remove the affected total load related outputs and/or note it somewhere for users. Mid Jan is pretty soon though especially with the holidays so maybe not worth the time to do that.

### Added
- Added the following inputs to account for the clean or renewable energy fraction of grid-purchased electricity:
- **ElectricUtility** **cambium_cef_metric** to utilize clean energy data from NREL's Cambium database
- **ElectricUtility** **renewable_energy_fraction_series** to supply a custom grid clean or renewable energy scalar or series
- **Site** **include_grid_renewable_fraction_in_RE_constraints** - to allow user to choose whether to include grid RE in min max constraints
- Added the following outputs:
- **ElectricUtility** **annual_renewable_electricity_supplied_kwh**
- **Site** **onsite_and_grid_renewable_electricity_fraction_of_elec_load**
- **Site** **onsite_and_grid_renewable_energy_fraction_of_total_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**
- Changed name of the following outputs:
- **ElectricUtility** **cambium_emissions_region** changed to **cambium_region**
- **Site** **annual_renewable_electricity_kwh** changed to **annual_onsite_renewable_electricity_kwh**
- **Site** **renewable_electricity_fraction** changed to **onsite_renewable_electricity_fraction_of_elec_load**
- **Site** **total_renewable_energy_fraction** changed to **onsite_renewable_energy_fraction_of_total_load**
- Changed name of function (also available as endpoint through REopt API) from **cambium_emissions_profile** to **cambium_profile**

## v0.48.2
### Added
- Battery residual value if choosing replacement strategy for degradation
Expand Down
2 changes: 1 addition & 1 deletion src/constraints/emissions_constraints.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ function add_emissions_constraints(m,p)
(1-p.s.site.CO2_emissions_reduction_max_fraction) * m[:Lifecycle_Emissions_Lbs_CO2_BAU]
)
end
else
elseif !isnothing(p.s.site.CO2_emissions_reduction_min_fraction) || !isnothing(p.s.site.CO2_emissions_reduction_max_fraction)
@warn "No emissions reduction constraints added, as BAU emissions have not been calculated."
end
end
Expand Down
34 changes: 26 additions & 8 deletions src/constraints/renewable_energy_constraints.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
add_re_elec_constraints(m,p)

Function to add minimum and/or maximum renewable electricity (as percentage of load) constraints, if specified by user.
Includes renewable energy from grid if specified by user using Site input include_grid_renewable_fraction_in_RE_constraints.

!!! note
When a single outage is modeled (using outage_start_time_step), renewable electricity calculations account for operations during this outage (e.g., the critical load is used during time_steps_without_grid)
Expand All @@ -11,14 +12,17 @@ Function to add minimum and/or maximum renewable electricity (as percentage of l
#Renewable electricity constraints
function add_re_elec_constraints(m,p)
if !isnothing(p.s.site.renewable_electricity_min_fraction)
@constraint(m, MinREElecCon, m[:AnnualREEleckWh] >= p.s.site.renewable_electricity_min_fraction*m[:AnnualEleckWh])
@constraint(m, MinREElecCon, m[:AnnualOnsiteREEleckWh] +
p.s.site.include_grid_renewable_fraction_in_RE_constraints * m[:AnnualGridREEleckWh]
>= p.s.site.renewable_electricity_min_fraction*m[:AnnualEleckWh])
end
if !isnothing(p.s.site.renewable_electricity_max_fraction)
@constraint(m, MaxREElecCon, m[:AnnualREEleckWh] <= p.s.site.renewable_electricity_max_fraction*m[:AnnualEleckWh])
@constraint(m, MaxREElecCon, m[:AnnualOnsiteREEleckWh] +
p.s.site.include_grid_renewable_fraction_in_RE_constraints * m[:AnnualGridREEleckWh]
<= p.s.site.renewable_electricity_max_fraction*m[:AnnualEleckWh])
end
end


"""
add_re_elec_calcs(m,p)

Expand Down Expand Up @@ -50,30 +54,44 @@ function add_re_elec_calcs(m,p)
# ))
# end

m[:AnnualREEleckWh] = @expression(m,p.hours_per_time_step * (
# Note: when we add capability for battery to discharge to grid, need to make sure only RE that is being consumed
# onsite is counted so battery doesn't become a back door for RE to grid.
m[:AnnualOnsiteREEleckWh] = @expression(m, p.hours_per_time_step * (
sum(p.production_factor[t,ts] * p.levelization_factor[t] * m[:dvRatedProduction][t,ts] *
p.tech_renewable_energy_fraction[t] for t in p.techs.elec, ts in p.time_steps
) - #total RE elec generation, excl steam turbine
sum(m[:dvProductionToStorage][b,t,ts]*p.tech_renewable_energy_fraction[t]*(
1-p.s.storage.attr[b].charge_efficiency*p.s.storage.attr[b].discharge_efficiency)
for t in p.techs.elec, b in p.s.storage.types.elec, ts in p.time_steps
) - #minus battery efficiency losses
sum(m[:dvCurtail][t,ts]*p.tech_renewable_energy_fraction[t] for t in p.techs.elec, ts in p.time_steps) - # minus curtailment.
sum(m[:dvCurtail][t,ts] * p.tech_renewable_energy_fraction[t]
for t in p.techs.elec, ts in p.time_steps
) - # minus curtailment
(1 - p.s.site.include_exported_renewable_electricity_in_total) *
sum(m[:dvProductionToGrid][t,u,ts]*p.tech_renewable_energy_fraction[t]
for t in p.techs.elec, u in p.export_bins_by_tech[t], ts in p.time_steps
) # minus exported RE, if RE accounting method = 0.
)
# + SteamTurbineAnnualREEleckWh # SteamTurbine RE Elec, already adjusted for p.hours_per_time_step
)
# Note: if battery ends up being allowed to discharge to grid, need to make sure only RE that is being consumed onsite is counted so battery doesn't become a back door for RE to grid.
# Note: calculations currently do not ascribe any renewable energy attribute to grid-purchased electricity

# Note: when we add capability for battery to discharge to grid, need to subtract out *grid RE* discharged from battery
# back to grid so that loop doesn't become a back door for increasing RE. This will require some careful thought!
m[:AnnualGridREEleckWh] = @expression(m, p.hours_per_time_step * (
sum(m[:dvGridPurchase][ts, tier] * p.s.electric_utility.renewable_energy_fraction_series[ts]
for ts in p.time_steps, tier in 1:p.s.electric_tariff.n_energy_tiers) # renewable energy from grid
adfarth marked this conversation as resolved.
Show resolved Hide resolved
- sum(m[:dvGridToStorage][b, ts] * p.s.electric_utility.renewable_energy_fraction_series[ts] *
(1 - p.s.storage.attr[b].charge_efficiency * p.s.storage.attr[b].discharge_efficiency)
for ts in p.time_steps, b in p.s.storage.types.elec
) # minus battery efficiency losses from grid charging storage (assumes all that is charged is discharged)
)
)

m[:AnnualEleckWh] = @expression(m,p.hours_per_time_step * (
# input electric load
sum(p.s.electric_load.loads_kw[ts] for ts in p.time_steps_with_grid)
+ sum(p.s.electric_load.critical_loads_kw[ts] for ts in p.time_steps_without_grid)
# tech electric loads
# tech electric loads #TODO: Uncomment and address any double counting with AnnualHeatkWh
Copy link
Collaborator

Choose a reason for hiding this comment

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

is this something you wanted to do in this PR?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I don't think so; we need to more holistically address the whole "total load" approach and make sure we have funding for this; @zolanaj has a separate PR for this: #456

Copy link
Collaborator

@hdunham hdunham Dec 16, 2024

Choose a reason for hiding this comment

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

got it, didin't realize this was part of that. it could be a good idea to note in #456 all the places like this that need to be considered/updated. not necessarily going through and finding all of them, cause that's the work of that PR, but just listing the ones that you already identified through this PR.

# + sum(m[:dvCoolingProduction][t,ts] for t in p.ElectricChillers, ts in p.time_steps )/ p.ElectricChillerCOP # electric chiller elec load
# + sum(m[:dvCoolingProduction][t,ts] for t in p.AbsorptionChillers, ts in p.time_steps )/ p.AbsorptionChillerElecCOP # absorportion chiller elec load
# + sum(p.GHPElectricConsumed[g,ts] * m[:binGHP][g] for g in p.GHPOptions, ts in p.time_steps) # GHP elec load
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 even when not optimized (ran into feasibility issues)
# @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
Loading
Loading