Skip to content

Commit 0f06c54

Browse files
committed
Added separate input types for the reservoirs and updated the inputs for water power
1 parent 3af2fc0 commit 0f06c54

6 files changed

Lines changed: 454 additions & 268 deletions

File tree

src/REopt.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ include("core/wind.jl")
125125
include("core/energy_storage/storage.jl")
126126
include("core/energy_storage/electric_storage.jl")
127127
include("core/energy_storage/thermal_storage.jl")
128+
include("core/energy_storage/water_storage.jl")
128129
include("core/generator.jl")
129130
include("core/doe_commercial_reference_building_loads.jl")
130131
include("core/electric_load.jl")

src/core/energy_storage/storage.jl

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ mutable struct StorageTypes
1616
thermal::Vector{String}
1717
hot::Vector{String}
1818
cold::Vector{String}
19+
water::Vector{String}
1920
end
2021
```
2122
"""
@@ -25,14 +26,15 @@ mutable struct StorageTypes
2526
thermal::Vector{String}
2627
hot::Vector{String}
2728
cold::Vector{String}
28-
29+
water::Vector{String}
2930

3031
function StorageTypes()
3132
new(
3233
String[],
3334
String[],
3435
String[],
3536
String[],
37+
String[],
3638
String[]
3739
)
3840
end
@@ -42,6 +44,7 @@ mutable struct StorageTypes
4244
elec_storage = String[]
4345
hot_storage = String[]
4446
cold_storage = String[]
47+
water_storage = String[]
4548

4649
for (k,v) in d
4750
if v.max_kw > 0.0 && v.max_kwh > 0.0
@@ -54,8 +57,10 @@ mutable struct StorageTypes
5457
push!(hot_storage, k)
5558
elseif typeof(v) <: ColdThermalStorage
5659
push!(cold_storage, k)
60+
elseif typeof(v) <: WaterStorage
61+
push!(water_storage, k)
5762
else
58-
throw(@error("Storage not labeled as Hot or Cold, or Electric."))
63+
throw(@error("Storage not labeled as Hot or Cold, Electric, or Water."))
5964
end
6065
end
6166
end
@@ -67,7 +72,8 @@ mutable struct StorageTypes
6772
elec_storage,
6873
thermal_storage,
6974
hot_storage,
70-
cold_storage
75+
cold_storage,
76+
water_storage
7177
)
7278
end
7379
end
Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
# REopt®, Copyright (c) Alliance for Energy Innovation, LLC. See also https://github.com/NatLabRockies/REopt.jl/blob/master/LICENSE.
2+
3+
4+
"""
5+
Upper reservoir water storage sytem
6+
7+
`UpperReservoirStorage` is an optional REopt input with the following keys and default values:
8+
9+
```julia
10+
water_inflow_cubic_meter_per_second::Array=[]
11+
minimum_volume_fraction_upper_reservoir::Float64 = 0.1
12+
maximum_volume_fraction_upper_reservoir::Float64 = 1.0
13+
initial_reservoir_volume_fraction_upper_reservoir::Float64 = 0.0
14+
minimum_capacity_cubic_meters_upper_reservoir::Float64 = 0.0
15+
maximum_capacity_cubic_meters_upper_reservoir::Float64 = 10000000.0
16+
cost_per_cubic_meter_upper_reservoir::Float64 = 25.0
17+
om_cost_per_cubic_meter::Float64 = 0.0 # Yearly fixed O&M cost dependent on storage energy size
18+
macrs_option_years::Int = 5 #Note: default may change if Site.sector is not "commercial/industrial"
19+
macrs_bonus_fraction::Float64 = 1.0 #Note: default may change if Site.sector is not "commercial/industrial"
20+
macrs_itc_reduction::Float64 = 0.5
21+
total_itc_fraction::Float64 = 0.3 #Note: default may change if Site.sector is not "commercial/industrial"
22+
total_rebate_per_cubic_meter::Float64 = 0.0
23+
```
24+
"""
25+
Base.@kwdef struct UpperReservoirStorageDefaults <: AbstractWaterStorageDefaults
26+
water_inflow_cubic_meter_per_second::Array=[]
27+
minimum_volume_fraction_upper_reservoir::Float64 = 0.1
28+
maximum_volume_fraction_upper_reservoir::Float64 = 1.0
29+
initial_reservoir_volume_fraction_upper_reservoir::Float64 = 0.0
30+
minimum_capacity_cubic_meters_upper_reservoir::Float64 = 0.0
31+
maximum_capacity_cubic_meters_upper_reservoir::Float64 = 10000000.0
32+
cost_per_cubic_meter_upper_reservoir::Float64 = 25.0
33+
om_cost_per_cubic_meter::Float64 = 0.0
34+
macrs_option_years::Int = 5
35+
macrs_bonus_fraction::Float64 = 1.0
36+
macrs_itc_reduction::Float64 = 0.5
37+
total_itc_fraction::Float64 = 0.3
38+
total_rebate_per_cubic_meter::Float64 = 0.0
39+
end
40+
41+
42+
"""
43+
`DownstreamReservoirStorage` is an optional REopt input with the following keys and default values:
44+
45+
```julia
46+
model_downstream_reservoir::Bool = true
47+
initial_reservoir_volume_fraction_downstream_reservoir::Float64 = 0.5
48+
minimum_volume_fraction_downstream_reservoir::Float64 = 0.2
49+
maximum_volume_fraction_downstream_reservoir::Float64 = 1.0
50+
minimum_capacity_cubic_meters_downstream_reservoir::Float64 = 0.0
51+
maximum_capacity_cubic_meters_downstream_reservoir::Float64 = 10000000.0
52+
cost_per_cubic_meter_downstream_reservoir::Float64 = 25.0
53+
minimum_outflow_from_downstream_reservoir_cubic_meter_per_second::Float64 = 0.0
54+
maximum_outflow_from_downstream_reservoir_cubic_meter_per_second::Float64 = 10000.0
55+
om_cost_per_cubic_meter::Float64 = 0.0
56+
macrs_option_years::Int = 5 #Note: default may change if Site.sector is not "commercial/industrial"
57+
macrs_bonus_fraction::Float64 = 1.0 #Note: default may change if Site.sector is not "commercial/industrial"
58+
macrs_itc_reduction::Float64 = 0.5
59+
total_itc_fraction::Float64 = 0.3 #Note: default may change if Site.sector is not "commercial/industrial"
60+
total_rebate_per_cubic_meter::Float64 = 0.0
61+
62+
```
63+
"""
64+
Base.@kwdef struct DownstreamReservoirStorageDefaults <: AbstractWaterStorageDefaults
65+
model_downstream_reservoir::Bool = true
66+
initial_reservoir_volume_fraction_downstream_reservoir::Float64 = 0.5
67+
minimum_volume_fraction_downstream_reservoir::Float64 = 0.2
68+
maximum_volume_fraction_downstream_reservoir::Float64 = 1.0
69+
minimum_capacity_cubic_meters_downstream_reservoir::Float64 = 0.0
70+
maximum_capacity_cubic_meters_downstream_reservoir::Float64 = 10000000.0
71+
cost_per_cubic_meter_downstream_reservoir::Float64 = 25.0
72+
minimum_outflow_from_downstream_reservoir_cubic_meter_per_second::Float64 = 0.0
73+
maximum_outflow_from_downstream_reservoir_cubic_meter_per_second::Float64 = 10000.0
74+
om_cost_per_cubic_meter::Float64 = 0.0
75+
macrs_option_years::Int = 5
76+
macrs_bonus_fraction::Float64 = 1.0
77+
macrs_itc_reduction::Float64 = 0.5
78+
total_itc_fraction::Float64 = 0.3
79+
total_rebate_per_cubic_meter::Float64 = 0.0
80+
end
81+
82+
83+
"""
84+
function UpperReservoirStorage(d::Dict, f::Financial, s::Site, time_steps_per_hour::Int)
85+
86+
Construct UpperReservoirStorage struct from Dict with keys-val pairs from the
87+
REopt UpperReservoirStorage and Financial inputs.
88+
"""
89+
struct UpperReservoirStorage <: AbstractWaterStorage
90+
water_inflow_cubic_meter_per_second::Array
91+
minimum_volume_fraction_upper_reservoir::Float64
92+
maximum_volume_fraction_upper_reservoir::Float64
93+
initial_reservoir_volume_fraction_upper_reservoir::Float64
94+
minimum_capacity_cubic_meters_upper_reservoir::Float64
95+
maximum_capacity_cubic_meters_upper_reservoir::Float64
96+
cost_per_cubic_meter_upper_reservoir::Float64
97+
om_cost_per_cubic_meter::Float64
98+
macrs_option_years::Int
99+
macrs_bonus_fraction::Float64
100+
macrs_itc_reduction::Float64
101+
total_itc_fraction::Float64
102+
total_rebate_per_cubic_meter::Float64
103+
net_present_cost_per_cubic_meter::Float64
104+
105+
function UpperReservoirStorage(d::Dict, f::Financial, s::Site, time_steps_per_hour::Int)
106+
set_sector_defaults!(d; struct_name="Storage", sector=s.sector, federal_procurement_type=s.federal_procurement_type)
107+
stor = UpperReservoirStorageDefaults(; d...)
108+
109+
macrs_schedule = [0.0]
110+
if stor.macrs_option_years == 5 || stor.macrs_option_years == 7
111+
macrs_schedule = stor.macrs_option_years == 7 ? f.macrs_seven_year : f.macrs_five_year
112+
elseif !(stor.macrs_option_years == 0)
113+
throw(@error("UpperReservoirStorage macrs_option_years must be 0, 5, or 7."))
114+
end
115+
116+
net_present_cost_per_cubic_meter = effective_cost(;
117+
itc_basis = stor.cost_per_cubic_meter_upper_reservoir,
118+
replacement_cost = 0.0,
119+
replacement_year = 100,
120+
discount_rate = f.owner_discount_rate_fraction,
121+
tax_rate = f.owner_tax_rate_fraction,
122+
itc = stor.total_itc_fraction,
123+
macrs_schedule = macrs_schedule,
124+
macrs_bonus_fraction = stor.macrs_bonus_fraction,
125+
macrs_itc_reduction = stor.macrs_itc_reduction
126+
) - stor.total_rebate_per_cubic_meter
127+
128+
tribuary_flow = stor.water_inflow_cubic_meter_per_second
129+
tributary_flow_length = length(stor.water_inflow_cubic_meter_per_second)
130+
131+
if (tributary_flow_length != 8760) && (tributary_flow_length != 17520) && (tributary_flow_length != 35040)
132+
throw(@error("Invalid length of the tributary flow vector"))
133+
elseif (time_steps_per_hour == 2) && (tributary_flow_length == 8760)
134+
@warn("Upscaling the tributary flow rate to match the time steps per hour")
135+
tribuary_flow = repeat(tribuary_flow, inner=time_steps_per_hour)
136+
elseif (time_steps_per_hour == 4) && (tributary_flow_length == 8760)
137+
@warn("Upscaling the tributary flow rate to match the time steps per hour")
138+
tribuary_flow = repeat(tribuary_flow, inner=time_steps_per_hour)
139+
#elseif
140+
# TODO: add more options for setting the tributary_flow variable to the correct length
141+
else
142+
print("\n No changes made to the tributary flow input vector \n")
143+
end
144+
145+
if stor.maximum_volume_fraction_upper_reservoir < stor.minimum_volume_fraction_upper_reservoir
146+
throw(@error("The 'maximum_volume_fraction_upper_reservoir' must be greater than or equal to the 'minimum_volume_fraction_upper_reservoir"))
147+
end
148+
if (stor.initial_reservoir_volume_fraction_upper_reservoir < stor.minimum_volume_fraction_upper_reservoir) || (stor.initial_reservoir_volume_fraction_upper_reservoir > stor.maximum_volume_fraction_upper_reservoir)
149+
throw(@error("The 'initial_reservoir_volume_fraction_upper_reservoir' must be between the 'minimum_volume_fraction_upper_reservoir' and 'maximum_volume_fraction_upper_reservoir' "))
150+
end
151+
152+
return new(
153+
stor.water_inflow_cubic_meter_per_second,
154+
stor.minimum_volume_fraction_upper_reservoir,
155+
stor.maximum_volume_fraction_upper_reservoir,
156+
stor.initial_reservoir_volume_fraction_upper_reservoir,
157+
stor.minimum_capacity_cubic_meters_upper_reservoir,
158+
stor.maximum_capacity_cubic_meters_upper_reservoir,
159+
stor.cost_per_cubic_meter_upper_reservoir,
160+
stor.om_cost_per_cubic_meter,
161+
stor.macrs_option_years,
162+
stor.macrs_bonus_fraction,
163+
stor.macrs_itc_reduction,
164+
stor.total_itc_fraction,
165+
stor.total_rebate_per_cubic_meter,
166+
net_present_cost_per_cubic_meter
167+
)
168+
end
169+
end
170+
171+
172+
"""
173+
function DownstreamReservoirStorage(d::Dict, f::Financial, s::Site, time_steps_per_hour::Int)
174+
175+
Construct DownstreamReservoirStorage struct from Dict with keys-val pairs from the
176+
REopt DownstreamReservoirStorage and Financial inputs.
177+
"""
178+
struct DownstreamReservoirStorage <: AbstractWaterStorage
179+
model_downstream_reservoir::Bool
180+
initial_reservoir_volume_fraction_downstream_reservoir::Float64
181+
minimum_volume_fraction_downstream_reservoir::Float64
182+
maximum_volume_fraction_downstream_reservoir::Float64
183+
minimum_capacity_cubic_meters_downstream_reservoir::Float64
184+
maximum_capacity_cubic_meters_downstream_reservoir::Float64
185+
cost_per_cubic_meter_downstream_reservoir::Float64
186+
minimum_outflow_from_downstream_reservoir_cubic_meter_per_second::Float64
187+
maximum_outflow_from_downstream_reservoir_cubic_meter_per_second::Float64
188+
om_cost_per_cubic_meter::Float64
189+
macrs_option_years::Int
190+
macrs_bonus_fraction::Float64
191+
macrs_itc_reduction::Float64
192+
total_itc_fraction::Float64
193+
total_rebate_per_cubic_meter::Float64
194+
net_present_cost_per_cubic_meter::Float64
195+
196+
function DownstreamReservoirStorage(d::Dict, f::Financial, s::Site, time_steps_per_hour::Int)
197+
set_sector_defaults!(d; struct_name="Storage", sector=s.sector, federal_procurement_type=s.federal_procurement_type)
198+
stor = DownstreamReservoirStorageDefaults(; d...)
199+
200+
macrs_schedule = [0.0]
201+
if stor.macrs_option_years == 5 || stor.macrs_option_years == 7
202+
macrs_schedule = stor.macrs_option_years == 7 ? f.macrs_seven_year : f.macrs_five_year
203+
elseif !(stor.macrs_option_years == 0)
204+
throw(@error("DownstreamReservoirStorage macrs_option_years must be 0, 5, or 7."))
205+
end
206+
207+
net_present_cost_per_cubic_meter = effective_cost(;
208+
itc_basis = stor.cost_per_cubic_meter_downstream_reservoir,
209+
replacement_cost = 0.0,
210+
replacement_year = 100,
211+
discount_rate = f.owner_discount_rate_fraction,
212+
tax_rate = f.owner_tax_rate_fraction,
213+
itc = stor.total_itc_fraction,
214+
macrs_schedule = macrs_schedule,
215+
macrs_bonus_fraction = stor.macrs_bonus_fraction,
216+
macrs_itc_reduction = stor.macrs_itc_reduction
217+
) - stor.total_rebate_per_cubic_meter
218+
219+
return new(
220+
stor.model_downstream_reservoir,
221+
stor.initial_reservoir_volume_fraction_downstream_reservoir,
222+
stor.minimum_volume_fraction_downstream_reservoir,
223+
stor.maximum_volume_fraction_downstream_reservoir,
224+
stor.minimum_capacity_cubic_meters_downstream_reservoir,
225+
stor.maximum_capacity_cubic_meters_downstream_reservoir,
226+
stor.cost_per_cubic_meter_downstream_reservoir,
227+
stor.minimum_outflow_from_downstream_reservoir_cubic_meter_per_second,
228+
stor.maximum_outflow_from_downstream_reservoir_cubic_meter_per_second,
229+
stor.om_cost_per_cubic_meter,
230+
stor.macrs_option_years,
231+
stor.macrs_bonus_fraction,
232+
stor.macrs_itc_reduction,
233+
stor.total_itc_fraction,
234+
stor.total_rebate_per_cubic_meter,
235+
net_present_cost_per_cubic_meter
236+
)
237+
end
238+
end
239+
240+
241+

0 commit comments

Comments
 (0)