REopt Inputs
Inputs to run_reopt
can be provided in one of three formats:
- a file path (string) to a JSON file,
- a
Dict
, or - using the
REoptInputs
struct
Any one of these types can be passed to the run_reopt
method.
The first option is perhaps the most straightforward one. For example, the minimum requirements for a JSON scenario file would look like:
{
"Site": {
"longitude": -118.1164613,
"latitude": 34.5794343
},
"ElectricLoad": {
"doe_reference_name": "MidriseApartment",
"annual_kwh": 1000000.0
},
"ElectricTariff": {
"urdb_label": "5ed6c1a15457a3367add15ae"
}
}
The order of the keys do not matter. Note that this scenario does not include any energy generation technologies and therefore the results can be used as a baseline for comparison to scenarios that result in cost-optimal generation technologies.
To add PV to the analysis simply add a PV key with an empty dictionary (to use default values):
{
"Site": {
"longitude": -118.1164613,
"latitude": 34.5794343
},
"ElectricLoad": {
"doe_reference_name": "MidriseApartment",
"annual_kwh": 1000000.0
},
"ElectricTariff": {
"urdb_label": "5ed6c1a15457a3367add15ae"
},
"PV": {}
}
This scenario will consider the option to purchase a solar PV system to reduce energy costs, and if solar PV can reduce the energy costs then REopt will provide the optimal PV capacity (assuming perfect foresight!). To use other than default values for PV
see the PV struct definition. For example, the site under consideration might have some existing PV capacity to account for, which can be done by setting the existing_kw
key to the appropriate value.
Scenario
The Scenario
struct captures all of the objects that can be included in a scenario.json:
REopt.Scenario
— TypeScenario(d::Dict; flex_hvac_from_json=false)
Constructor for Scenario struct, where d
has upper-case keys:
- Site (required)
- ElectricTariff (required)
- ElectricLoad (required)
- PV (optional, can be Array)
- Wind (optional)
- ElectricStorage (optional)
- ElectricUtility (optional)
- Financial (optional)
- Generator (optional)
- DomesticHotWaterLoad (optional)
- SpaceHeatingLoad (optional)
- ExistingBoiler (optional)
- CHP (optional)
- FlexibleHVAC (optional)
- ExistingChiller (optional)
All values of d
are expected to be Dicts
except for PV
, which can be either a Dict
or Dict[]
.
Set flex_hvac_from_json=true
if FlexibleHVAC
values were loaded in from JSON (necessary to handle conversion of Vector of Vectors from JSON to a Matrix in Julia).
Scenario(fp::String)
Consruct Scenario from filepath fp
to JSON with keys aligned with the Scenario(d::Dict)
method.
BAUScenario
The BAUScenario
struct is for running Business-As-Usual scenarios, i.e. without any new technologies. The results of the BAU scenario are used to calculate other Financial
results such as the net present value.
REopt.BAUScenario
— TypeBAUScenario(s::Scenario)
Constructor for BAUScenario (BAU = Business As Usual) struct.
- sets the PV and Generator maxkw values to the existingkw values
- sets wind and storage max_kw values to zero
Site
REopt.Site
— TypeSite
Inputs related to the physical location:
function Site(;
latitude::Real,
longitude::Real,
land_acres::Union{Float64, Nothing} = nothing,
roof_squarefeet::Union{Float64, Nothing} = nothing,
min_resil_timesteps::Int=0,
mg_tech_sizes_equal_grid_sizes::Bool = true,
node::Int = 1,
)
ElectricLoad
REopt.ElectricLoad
— TypeElectricLoad(;
loads_kw::Array{<:Real,1} = Real[],
path_to_csv::String = "",
year::Int = 2020,
doe_reference_name::String = "",
blended_doe_reference_names::Array{String, 1} = String[],
blended_doe_reference_percents::Array{<:Real,1} = Real[],
city::String = "",
annual_kwh::Union{Real, Nothing} = nothing,
monthly_totals_kwh::Array{<:Real,1} = Real[],
critical_loads_kw::Union{Missing, Array{Real,1}} = missing,
loads_kw_is_net::Bool = true,
critical_loads_kw_is_net::Bool = false,
critical_load_pct::Real = 0.5,
time_steps_per_hour::Int = 1
)
Must provide either loads_kw
or path_to_csv
or [doe_reference_name
and city
] or doe_reference_name
or [blended_doe_reference_names
and blended_doe_reference_percents
].
When only doe_reference_name
is provided the Site.latitude
and Site.longitude
are used to look up the ASHRAE climate zone, which determines the appropriate DoE Commercial Reference Building profile.
When using the [doe_reference_name
and city
] option, choose city
from one of the cities used to represent the ASHRAE climate zones:
- Albuquerque
- Atlanta
- Baltimore
- Boulder
- Chicago
- Duluth
- Fairbanks
- Helena
- Houston
- LosAngeles
- Miami
- Minneapolis
- Phoenix
- SanFrancisco
- Seattle
and doe_reference_name
from:
- FastFoodRest
- FullServiceRest
- Hospital
- LargeHotel
- LargeOffice
- MediumOffice
- MidriseApartment
- Outpatient
- PrimarySchool
- RetailStore
- SecondarySchool
- SmallHotel
- SmallOffice
- StripMall
- Supermarket
- Warehouse
- FlatLoad
Each city
and doe_reference_name
combination has a default annual_kwh
, or you can provide your own annual_kwh
or monthly_totals_kwh
and the reference profile will be scaled appropriately.
ElectricTariff
REopt.ElectricTariff
— Typestruct ElectricTariff
- data for electric tariff in reopt model
- can be defined using custom rates or URDB rate
- very similar to the URDB struct but includes export rates and bins
REopt.ElectricTariff
— MethodElectricTariff
ElectricTariff constructor
function ElectricTariff(;
urdb_label::String="",
urdb_response::Dict=Dict(),
urdb_utility_name::String="",
urdb_rate_name::String="",
year::Int=2020,
time_steps_per_hour::Int=1,
NEM::Bool=false,
wholesale_rate::T1=nothing,
export_rate_beyond_net_metering_limit::T2=nothing,
monthly_energy_rates::Array=[],
monthly_demand_rates::Array=[],
blended_annual_energy_rate::S=nothing,
blended_annual_demand_rate::R=nothing,
add_monthly_rates_to_urdb_rate::Bool=false,
tou_energy_rates_per_kwh::Array=[],
add_tou_energy_rates_to_urdb_rate::Bool=false,
remove_tiers::Bool=false,
demand_lookback_months::AbstractArray{Int64, 1}=Int64[],
demand_lookback_percent::Float64=0.0,
demand_lookback_range::Int=0,
coincident_peak_load_active_timesteps::Vector{Vector{Int64}}=[Int64[]],
coincident_peak_load_charge_per_kw::AbstractVector{<:Real}=Real[]
) where {
T1 <: Union{Nothing, Int, Float64, Array},
T2 <: Union{Nothing, Int, Float64, Array},
S <: Union{Nothing, Int, Float64},
R <: Union{Nothing, Int, Float64}
}
The NEM
boolean is determined by the ElectricUtility.netmeteringlimit_kw. There is no need to pass in a NEM
value.
Financial
REopt.Financial
— TypeFinancial
Financial data struct with inner constructor:
function Financial(;
om_cost_escalation_pct::Float64 = 0.025,
elec_cost_escalation_pct::Float64 = 0.019,
boiler_fuel_cost_escalation_pct::Float64 = 0.034,
chp_fuel_cost_escalation_pct::Float64 = 0.034,
offtaker_tax_pct::Float64 = 0.26,
offtaker_discount_pct = 0.0564,
third_party_ownership::Bool = false,
owner_tax_pct::Float64 = 0.26,
owner_discount_pct::Float64 = 0.0564,
analysis_years::Int = 25,
value_of_lost_load_per_kwh::Union{Array{R,1}, R} where R<:Real = 1.00,
microgrid_upgrade_cost_pct::Float64 = 0.3,
macrs_five_year::Array{Float64,1} = [0.2, 0.32, 0.192, 0.1152, 0.1152, 0.0576], # IRS pub 946
macrs_seven_year::Array{Float64,1} = [0.1429, 0.2449, 0.1749, 0.1249, 0.0893, 0.0892, 0.0893, 0.0446]
)
When third_party_ownership
is false
the offtaker's discount and tax percentages are used throughout the model:
if !third_party_ownership
owner_tax_pct = offtaker_tax_pct
owner_discount_pct = offtaker_discount_pct
end
ElectricUtility
REopt.ElectricUtility
— TypeElectricUtility
Base.@kwdef struct ElectricUtility
outage_start_time_step::Int=0 # for modeling a single outage, with critical load spliced into the baseline load ...
outage_end_time_step::Int=0 # ... utiltity production_factor = 0 during the outage
allow_simultaneous_export_import::Bool=true # if true the site has two meters (in effect)
# variables below used for minimax the expected outage cost,
# with max taken over outage start time, expectation taken over outage duration
outage_start_timesteps::Array{Int,1}=Int[] # we minimize the maximum outage cost over outage start times
outage_durations::Array{Int,1}=Int[] # one-to-one with outage_probabilities, outage_durations can be a random variable
outage_probabilities::Array{Real,1}=[1.0]
outage_timesteps::Union{Missing, UnitRange} = isempty(outage_durations) ? missing : 1:maximum(outage_durations)
scenarios::Union{Missing, UnitRange} = isempty(outage_durations) ? missing : 1:length(outage_durations)
end
PV
REopt.PV
— TypePV
struct with inner constructor:
function PV(;
tilt::Real,
array_type::Int=1,
module_type::Int=0,
losses::Real=0.14,
azimuth::Real=180,
gcr::Real=0.4,
radius::Int=0,
name::String="PV",
location::String="both",
existing_kw::Real=0,
min_kw::Real=0,
max_kw::Real=1.0e9,
installed_cost_per_kw::Real=1592.0,
om_cost_per_kw::Real=17.0,
degradation_pct::Real=0.005,
macrs_option_years::Int = 5,
macrs_bonus_pct::Float64 = 1.0,
macrs_itc_reduction::Float64 = 0.5,
kw_per_square_foot::Float64=0.01,
acres_per_kw::Float64=6e-3,
inv_eff::Float64=0.96,
dc_ac_ratio::Float64=1.2,
prod_factor_series::Union{Missing, Array{Real,1}} = missing,
federal_itc_pct::Float64 = 0.26,
federal_rebate_per_kw::Float64 = 0.0,
state_ibi_pct::Float64 = 0.0,
state_ibi_max::Float64 = 1.0e10,
state_rebate_per_kw::Float64 = 0.0,
state_rebate_max::Float64 = 1.0e10,
utility_ibi_pct::Float64 = 0.0,
utility_ibi_max::Float64 = 1.0e10,
utility_rebate_per_kw::Float64 = 0.0,
utility_rebate_max::Float64 = 1.0e10,
production_incentive_per_kwh::Float64 = 0.0,
production_incentive_max_benefit::Float64 = 1.0e9,
production_incentive_years::Int = 1,
production_incentive_max_kw::Float64 = 1.0e9
can_net_meter::Bool = true,
can_wholesale::Bool = true,
can_export_beyond_nem_limit::Bool = true
)
If tilt
is not provided then it is set to the Site.latitude
. (Which is handled in the Scenario
struct.)
Wind
REopt.Wind
— TypeWind
struct with inner constructor:
function Wind(;
min_kw = 0.0,
max_kw = 1.0e9,
installed_cost_per_kw = 0.0,
om_cost_per_kw = 35.0,
prod_factor_series = missing,
size_class = "",
wind_meters_per_sec = [],
wind_direction_degrees = [],
temperature_celsius = [],
pressure_atmospheres = [],
macrs_option_years = 5,
macrs_bonus_pct = 0.0,
macrs_itc_reduction = 0.5,
federal_itc_pct = 0.26,
federal_rebate_per_kw = 0.0,
state_ibi_pct = 0.0,
state_ibi_max = 1.0e10,
state_rebate_per_kw = 0.0,
state_rebate_max = 1.0e10,
utility_ibi_pct = 0.0,
utility_ibi_max = 1.0e10,
utility_rebate_per_kw = 0.0,
utility_rebate_max = 1.0e10,
production_incentive_per_kwh = 0.0,
production_incentive_max_benefit = 1.0e9,
production_incentive_years = 1,
production_incentive_max_kw = 1.0e9,
can_net_meter = true,
can_wholesale = true,
can_export_beyond_nem_limit = true
)
size_class
must be one of ["residential", "commercial", "medium", "large"]. If size_class
is not provided then it is determined based on the average electric load.
If no installed_cost_per_kw
is provided (or it is 0.0) then it is determined from:
size_class_to_installed_cost = Dict(
"residential"=> 11950.0,
"commercial"=> 7390.0,
"medium"=> 4440.0,
"large"=> 3450.0
)
The Federal Investment Tax Credit is adjusted based on the size_class
as follows (if the default of 0.3 is not changed):
size_class_to_itc_incentives = Dict(
"residential"=> 0.3,
"commercial"=> 0.3,
"medium"=> 0.12,
"large"=> 0.12
)
If the prod_factor_series
is not provided then NREL's System Advisor Model (SAM) is used to get the wind turbine production factor.
Wind resource values are optional, i.e. (wind_meters_per_sec
, wind_direction_degrees
, temperature_celsius
, and pressure_atmospheres
). If not provided then the resource values are downloaded from NREL's Wind Toolkit. These values are passed to SAM to get the turbine production factor.
ElectricStorage
REopt.ElectricStorageDefaults
— TypeElectricStorageDefaults
Electric storage system defaults. Overridden by user inputs.
Base.@kwdef struct ElectricStorageDefaults
min_kw::Float64 = 0.0
max_kw::Float64 = 1.0e4
min_kwh::Float64 = 0.0
max_kwh::Float64 = 1.0e6
internal_efficiency_pct::Float64 = 0.975
inverter_efficiency_pct::Float64 = 0.96
rectifier_efficiency_pct::Float64 = 0.96
soc_min_pct::Float64 = 0.2
soc_init_pct::Float64 = 0.5
can_grid_charge::Bool = true
installed_cost_per_kw::Float64 = 775.0
installed_cost_per_kwh::Float64 = 388.0
replace_cost_per_kw::Float64 = 440.0
replace_cost_per_kwh::Float64 = 220.0
inverter_replacement_year::Int = 10
battery_replacement_year::Int = 10
macrs_option_years::Int = 7
macrs_bonus_pct::Float64 = 1.0
macrs_itc_reduction::Float64 = 0.5
total_itc_pct::Float64 = 0.0
total_rebate_per_kw::Float64 = 0.0
total_rebate_per_kwh::Float64 = 0.0
charge_efficiency::Float64 = rectifier_efficiency_pct * internal_efficiency_pct^0.5
discharge_efficiency::Float64 = inverter_efficiency_pct * internal_efficiency_pct^0.5
grid_charge_efficiency::Float64 = can_grid_charge ? charge_efficiency : 0.0
model_degradation::Bool = false
degradation::Dict = Dict()
end
REopt.Degradation
— TypeDegradation
Inputs used when ElectricStorage.model_degradation
is true
:
Base.@kwdef mutable struct Degradation
calendar_fade_coefficient::Float64 = 2.46E-03
cycle_fade_coefficient::Float64 = 7.82E-05
installed_cost_per_kwh_declination_rate::Float64 = 0.05
maintenance_strategy::String = "augmentation" # one of ["augmentation", "replacement"]
maintenance_cost_per_kwh::Vector{<:Real} = Real[]
end
None of the above values are required. If ElectricStorage.model_degradation
is true
then the defaults above are used. If the maintenance_cost_per_kwh
is not provided then it is determined using the ElectricStorage.installed_cost_per_kwh
and the installed_cost_per_kwh_declination_rate
along with a present worth factor $f$ to account for the present cost of buying a battery in the future. The present worth factor for each day is:
$f(day) = \frac{ (1-r_g)^\frac{day}{365} } { (1+r_d)^\frac{day}{365} }$
where $r_g$ = installed_cost_per_kwh_declination_rate
and $r_d$ = p.s.financial.owner_discount_pct
.
Note this day-specific calculation of the present-worth factor accumulates differently from the annually updated discount rate for other net-present value calculations in REopt, and has a higher effective discount rate as a result. The present worth factor is used in two different ways, depending on the maintenance_strategy
, which is described below.
When modeling degradation the following ElectricStorage inputs are not used:
replace_cost_per_kw
replace_cost_per_kwh
inverter_replacement_year
battery_replacement_year
The are replaced by the maintenance_cost_per_kwh
vector.
When providing the maintenance_cost_per_kwh
it must have a length equal to Financial.analysis_years*365
.
Battery State Of Health
The state of health [SOH
] is a linear function of the daily average state of charge [Eavg
] and the daily equivalent full cycles [EFC
]. The initial SOH
is set to the optimal battery energy capacity (in kWh). The evolution of the SOH
beyond the first day is:
$SOH[d] = SOH[d-1] - h\left( \frac{1}{2} k_{cal} Eavg[d-1] / \sqrt{d} + k_{cyc} EFC[d-1] \quad \forall d \in \{2\dots D\} \right)$
where:
- $k_{cal}$ is the
calendar_fade_coefficient
- $k_{cyc}$ is the
cycle_fade_coefficient
- $h$ is the hours per time step
- $D$ is the total number of days, 365 *
analysis_years
The SOH
is used to determine the maintence cost of the storage system, which depends on the maintenance_strategy
.
Augmentation Maintenance Strategy
The augmentation maintenance strategy assumes that the battery energy capacity is maintained by replacing degraded cells daily in terms of cost. Using the definition of the SOH
above the maintenance cost is:
$C_{\text{aug}} = \sum_{d \in \{2\dots D\}} 0.8 C_{\text{install}} f(day) \left( SOH[d-1] - SOH[d] \right)$
where
- the $0.8$ factor accounts for sunk costs that do not need to be paid;
- $C_{\text{install}}$ is the
ElectricStorage.installed_cost_per_kwh
; and - $SOH[d-1] - SOH[d]$ is the incremental amount of battery capacity lost in a day.
The $C_{\text{aug}}$ is added to the objective function to be minimized with all other costs.
Replacement Maintenance Strategy
Modeling the replacement maintenance strategy is more complex than the augmentation strategy. Effectively the replacement strategy says that the battery has to be replaced once the SOH
hits 80% of the optimal, purchased capacity. It is possible that multiple replacements could be required under this strategy.
The "replacement" maintenance strategy requires integer variables and indicator constraints. Not all solvers support indicator constraints and some solvers are slow with integer variables.
The replacement strategy cost is:
$C_{\text{repl}} = B_{\text{kWh}} N_{\text{repl}} f(d_{80}) C_{\text{install}}$
where:
- $B_{\text{kWh}}$ is the optimal battery capacity (
ElectricStorage.size_kwh
in the results dictionary); - $N_{\text{repl}}$ is the number of battery replacments required (a function of the month in which the
SOH
reaches 80% of original capacity); - $f(d_{80})$ is the present worth factor at approximately the 15th day of the month that the
SOH
reaches 80% of original capacity.
The $C_{\text{repl}}$ is added to the objective function to be minimized with all other costs.
Example of inputs
The following shows how one would use the degradation model in REopt via the Scenario inputs:
{
...
"ElectricStorage": {
"installed_cost_per_kwh": 390,
...
"model_degradation": true,
"degradation": {
"calendar_fade_coefficient": 2.86E-03,
"cycle_fade_coefficient": 6.22E-05,
"installed_cost_per_kwh_declination_rate": 0.06,
"maintenance_strategy": "replacement",
...
}
},
...
}
Note that not all of the above inputs are necessary. When not providing calendar_fade_coefficient
for example the default value will be used.
Generator
REopt.Generator
— TypeGenerator
struct with inner constructor:
function Generator(;
existing_kw::Real=0,
min_kw::Real=0,
max_kw::Real=1.0e6,
installed_cost_per_kw::Real=500.0,
om_cost_per_kw::Real=10.0,
om_cost_per_kwh::Float64=0.0,
fuel_cost_per_gallon::Float64 = 3.0,
fuel_slope_gal_per_kwh::Float64 = 0.076,
fuel_intercept_gal_per_hr::Float64 = 0.0,
fuel_avail_gal::Float64 = 660.0,
min_turn_down_pct::Float64 = 0.0,
only_runs_during_grid_outage::Bool = true,
sells_energy_back_to_grid::Bool = false,
can_net_meter::Bool = false,
can_wholesale::Bool = false,
can_export_beyond_nem_limit = false,
macrs_option_years::Int = 0,
macrs_bonus_pct::Float64 = 1.0,
macrs_itc_reduction::Float64 = 0.0,
federal_itc_pct::Float64 = 0.0,
federal_rebate_per_kw::Float64 = 0.0,
state_ibi_pct::Float64 = 0.0,
state_ibi_max::Float64 = 1.0e10,
state_rebate_per_kw::Float64 = 0.0,
state_rebate_max::Float64 = 1.0e10,
utility_ibi_pct::Float64 = 0.0,
utility_ibi_max::Float64 = 1.0e10,
utility_rebate_per_kw::Float64 = 0.0,
utility_rebate_max::Float64 = 1.0e10,
production_incentive_per_kwh::Float64 = 0.0,
production_incentive_max_benefit::Float64 = 1.0e9,
production_incentive_years::Int = 0,
production_incentive_max_kw::Float64 = 1.0e9,
)
Settings
REopt.Settings
— TypeSettings
Data struct for top-level Scenario settings. Captures inputs that do not logically fall under any of the other data structs.
Base.@kwdef struct Settings
time_steps_per_hour::Int = 1
run_bau::Bool = true
end
ExistingBoiler
REopt.ExistingBoiler
— TypeExistingBoiler
The ExistingBoiler
default operating cost is zero. Please provide the fuel_cost_per_mmbtu
field for the ExistingBoiler
if you want non-zero BAU heating costs. The fuel_cost_per_mmbtu
can be a scalar, a list of 12 monthly values, or a time series of values for every time step. ExistingBoiler
function ExistingBoiler(;
max_heat_demand_kw::Real=0,
production_type::String = "hot_water",
chp_prime_mover::String = "",
max_thermal_factor_on_peak_load::Real = 1.25,
efficiency::Real = 0.0,
fuel_cost_per_mmbtu::Union{<:Real, AbstractVector{<:Real}} = 0.0,
time_steps_per_hour::Int = 1
)
CHP
REopt.CHP
— TypeCHP
struct with outer constructor:
prime_mover::String = ""
# following must be provided by user if not providing prime_mover
installed_cost_per_kw::Union{Float64, AbstractVector{Float64}} = NaN
tech_sizes_for_cost_curve::Union{Float64, AbstractVector{Float64}} = NaN
om_cost_per_kwh::Float64 = NaN
elec_effic_half_load = NaN
elec_effic_full_load::Float64 = NaN
min_turn_down_pct::Float64 = NaN
thermal_effic_full_load::Float64 = NaN
thermal_effic_half_load::Float64 = NaN
min_allowable_kw::Float64 = NaN
max_kw::Float64 = NaN
cooling_thermal_factor::Float64 = NaN # only needed with cooling load
unavailability_periods::AbstractVector{Dict} = Dict[]
size_class::Int = 1
min_kw::Float64 = 0.0
fuel_cost_per_mmbtu::Union{<:Real, AbstractVector{<:Real}} = 0.0,
om_cost_per_kw::Float64 = 0.0
om_cost_per_hr_per_kw_rated::Float64 = 0.0
supplementary_firing_capital_cost_per_kw::Float64 = 150.0
supplementary_firing_max_steam_ratio::Float64 = 1.0
supplementary_firing_efficiency::Float64 = 0.92
standby_rate_us_dollars_per_kw_per_month = 0.0
reduces_demand_charges = true
use_default_derate::Bool = true
max_derate_factor::Float64 = 1.0
derate_start_temp_degF::Float64 = 0.0
derate_slope_pct_per_degF::Float64 = 0.0
can_supply_steam_turbine::Bool=false
macrs_option_years::Int = 5
macrs_bonus_pct::Float64 = 1.0
macrs_itc_reduction::Float64 = 0.5
federal_itc_pct::Float64 = 0.1
federal_rebate_per_kw::Float64 = 0.0
state_ibi_pct::Float64 = 0.0
state_ibi_max::Float64 = 1.0e10
state_rebate_per_kw::Float64 = 0.0
state_rebate_max::Float64 = 1.0e10
utility_ibi_pct::Float64 = 0.0
utility_ibi_max::Float64 = 1.0e10
utility_rebate_per_kw::Float64 = 0.0
utility_rebate_max::Float64 = 1.0e10
production_incentive_per_kwh::Float64 = 0.0
production_incentive_max_benefit::Float64 = 1.0e9
production_incentive_years::Int = 0
production_incentive_max_kw::Float64 = 1.0e9
can_net_meter::Bool = false
can_wholesale::Bool = false
can_export_beyond_nem_limit::Bool = false
can_curtail::Bool = false
# emissions_factor_lb_CO2_per_mmbtu::Float64
HotStorage
REopt.HotThermalStorageDefaults
— TypeHotThermalStorageDefaults
Base.@kwdef struct HotThermalStorageDefaults <: AbstractThermalStorageDefaults
min_gal::Float64 = 0.0
max_gal::Float64 = 0.0
hot_water_temp_degF::Float64 = 180.0
cool_water_temp_degF::Float64 = 160.0
internal_efficiency_pct::Float64 = 0.999999
soc_min_pct::Float64 = 0.1
soc_init_pct::Float64 = 0.5
installed_cost_per_gal::Float64 = 1.50
thermal_decay_rate_fraction::Float64 = 0.0004
om_cost_per_gal::Float64 = 0.0
macrs_option_years::Int = 0
macrs_bonus_pct::Float64 = 0.0
total_rebate_per_kwh::Float64 = 0.0
end
ColdStorage
REopt.ColdThermalStorageDefaults
— TypeColdThermalStorageDefaults
Cold thermal energy storage sytem; specifically, a chilled water system used to
meet thermal cooling loads.
Base.@kwdef struct ColdThermalStorageDefaults <: AbstractThermalStorageDefaults
min_gal::Float64 = 0.0
max_gal::Float64 = 0.0
hot_water_temp_degF::Float64 = 56.0
cool_water_temp_degF::Float64 = 44.0
internal_efficiency_pct::Float64 = 0.999999
soc_min_pct::Float64 = 0.1
soc_init_pct::Float64 = 0.5
installed_cost_per_gal::Float64 = 1.50
thermal_decay_rate_fraction::Float64 = 0.0004
om_cost_per_gal::Float64 = 0.0
macrs_option_years::Int = 0
macrs_bonus_pct::Float64 = 0.0
macrs_itc_reduction::Float64 = 0.0
total_itc_pct::Float64 = 0.0
total_rebate_per_kwh::Float64 = 0.0
end
DomesticHotWaterLoad
REopt.DomesticHotWaterLoad
— TypeDomesticHotWaterLoad
There are many ways in which a DomesticHotWaterLoad can be defined:
- When using either
doe_reference_name
orblended_doe_reference_names
in anElectricLoad
one only needs to provide the input key "DomesticHotWaterLoad" in theScenario
(JSON or Dict). In this case the values from DoE reference names from theElectricLoad
will be used to define theDomesticHotWaterLoad
. - One can provide the
doe_reference_name
orblended_doe_reference_names
directly in theDomesticHotWaterLoad
key within theScenario
. These values can be combined with theannual_mmbtu
ormonthly_mmbtu
inputs to scale the DoE reference profile(s). - One can provide the
fuel_loads_mmbtu_per_hour
value in theDomesticHotWaterLoad
key within theScenario
.
function DomesticHotWaterLoad(;
doe_reference_name::String = "",
city::String = "",
blended_doe_reference_names::Array{String, 1} = String[],
blended_doe_reference_percents::Array{<:Real,1} = Real[],
annual_mmbtu::Union{Real, Nothing} = nothing,
monthly_mmbtu::Array{<:Real,1} = Real[],
fuel_loads_mmbtu_per_hour::Array{<:Real,1} = Real[],
time_steps_per_hour::Int = 1,
latitude::Real=0.0,
longitude::Real=0.0
)
SpaceHeatingLoad
REopt.SpaceHeatingLoad
— Typefunction SpaceHeatingLoad(;
doe_reference_name::String = "",
city::String = "",
blended_doe_reference_names::Array{String, 1} = String[],
blended_doe_reference_percents::Array{<:Real,1} = Real[],
annual_mmbtu::Union{Real, Nothing} = nothing,
monthly_mmbtu::Array{<:Real,1} = Real[],
fuel_loads_mmbtu_per_hour::Array{<:Real,1} = Real[]
)
There are many ways to define a SpaceHeatingLoad
:
- a time-series via the
fuel_loads_mmbtu_per_hour
, - scaling a DoE Commercial Reference Building (CRB) profile or a blend of CRB profiles to either the
annual_mmbtu
ormonthly_mmbtu
values; - or using the
doe_reference_name
orblended_doe_reference_names
from theElectricLoad
.
When using an ElectricLoad
defined from a doe_reference_name
or blended_doe_reference_names
one only needs to provide an empty Dict in the scenario JSON to add a SpaceHeatingLoad
to a Scenario
, i.e.:
...
"ElectricLoad": {"doe_reference_name": "MidriseApartment"},
"SpaceHeatingLoad" : {},
...
In this case the values provided for doe_reference_name
, or blended_doe_reference_names
and blended_doe_reference_percents
are copied from the ElectricLoad
to the SpaceHeatingLoad
.
FlexibleHVAC
REopt.FlexibleHVAC
— TypeFlexibleHVAC
Every model with FlexibleHVAC
includes a preprocessing step to calculate the business-as-usual (BAU) cost of meeting the thermal loads using a dead-band controller. The BAU cost is then used in the binary decision for purchasing the FlexibleHVAC
system: if the FlexibleHVAC
system is purchased then the heating and cooling costs are determined by the HVAC dispatch that minimizes the lifecycle cost of energy. If the FlexibleHVAC
system is not purchased then the BAU heating and cooling costs must be paid.
There are two construction methods for FlexibleHVAC
, which depend on whether or not the data was loaded in from a JSON file. The issue with data from JSON is that the vector-of-vectors from the JSON file must be appropriately converted to Julia Matrices. When loading in a Scenario from JSON that includes a FlexibleHVAC
model if you include the flex_hvac_from_json
argument to the Scenario
constructor then the conversion to Matrices will be done appropriately. For example:
At least one of the inputs for temperature_upper_bound_degC
or temperature_lower_bound_degC
must be provided to evaluate the FlexibleHVAC
option. For example, if only temperature_lower_bound_degC
is provided then only a heating system will be evaluated. Also, the heating system will only be used (or purchased) if the exogenous_inputs
lead to the temperature at the control_node
going below the temperature_lower_bound_degC
.
The ExistingChiller
is electric and so its operating cost is determined by the ElectricTariff
.
The ExistingBoiler
default operating cost is zero. Please provide the fuel_cost_per_mmbtu
field for the ExistingBoiler
if you want non-zero BAU heating costs. The fuel_cost_per_mmbtu
can be a scalar, a list of 12 monthly values, or a time series of values for every time step.
REopt.FlexibleHVAC
— Methodfunction FlexibleHVAC(;
system_matrix::AbstractMatrix,
input_matrix::AbstractMatrix,
exogenous_inputs::AbstractMatrix,
control_node::Int64,
initial_temperatures::AbstractVector,
temperature_upper_bound_degC::Union{Real, Nothing} = nothing,
temperature_lower_bound_degC::Union{Real, Nothing} = nothing,
installed_cost::Float64
)
When the A, B, and u values are in Matrix format (note u is normally a vector but in our case it has a time index in the second dimension)
REopt.FlexibleHVAC
— MethodFlexibleHVAC(dict_from_json::Dict)