REopt Inputs

Inputs to run_reopt can be provided in one of three formats:

  1. a file path (string) to a JSON file,
  2. a Dict, or
  3. 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 Lite 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:

REoptLite.ScenarioType
Scenario(d::Dict)

Constructor for Scenario struct, where d has upper-case keys:

All values of d are expected to be Dicts except for PV, which can be either a Dict or Dict[].

struct Scenario
    settings::Settings
    site::Site
    pvs::Array{PV, 1}
    wind::Wind
    storage::Storage
    electric_tariff::ElectricTariff
    electric_load::ElectricLoad
    electric_utility::ElectricUtility
    financial::Financial
    generator::Generator
    dhw_load::DomesticHotWaterLoad
    space_heating_load::SpaceHeatingLoad
    existing_boiler::ExistingBoiler
    chp::CHP
end
source
Scenario(fp::String)

Consruct Scenario from filepath fp to JSON with keys aligned with the Scenario(d::Dict) method.

source

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.

REoptLite.BAUScenarioType
BAUScenario(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
source

Site

REoptLite.SiteType
Site

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, 
    )
source

ElectricLoad

REoptLite.ElectricLoadType
ElectricLoad(;
    loads_kw::Union{Missing, Array{<:Real,1}} = missing,
    year::Int = 2020,
    doe_reference_name::Union{Missing, String} = missing,
    blended_doe_reference_names::Array{String, 1} = String[],
    blended_doe_reference_percents::Array{<:Float64,1} = Float64[],
    city::Union{Missing, String} = missing,
    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
)

Must provide either loads_kw 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.

source

ElectricTariff

REoptLite.ElectricTariffType
struct 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
source
REoptLite.ElectricTariffMethod
ElectricTariff

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::T=nothing, 
    monthly_energy_rates::Array=[],
    monthly_demand_rates::Array=[],
    blended_annual_energy_rate::S=nothing,
    blended_annual_demand_rate::R=nothing,
    remove_tiers::Bool=false,
    demand_lookback_months::AbstractArray{Int64, 1}=Int64[],
    demand_lookback_percent::Float64=0.0,
    demand_lookback_range::Int=0,
    ) where {
        T <: Union{Nothing, Int, Float64, Array}, 
        S <: Union{Nothing, Int, Float64}, 
        R <: Union{Nothing, Int, Float64}
    }
Note

The NEM boolean is determined by the ElectricUtility.netmeteringlimit_kw. There is no need to pass in a NEM value.

source

Financial

REoptLite.FinancialType
Financial

Financial data struct with inner constructor:

function Financial(;
    om_cost_escalation_pct::Float64 = 0.025,
    elec_cost_escalation_pct::Float64 = 0.023,
    boiler_fuel_cost_escalation_pct::Float64
    chp_fuel_cost_escalation_pct::Float64    
    offtaker_tax_pct::Float64 = 0.26,
    offtaker_discount_pct = 0.083,
    third_party_ownership::Bool = false,
    owner_tax_pct::Float64 = 0.26,
    owner_discount_pct::Float64 = 0.083,
    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]
)
Note

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
source

ElectricUtility

REoptLite.ElectricUtilityType
ElectricUtility

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
source

PV

REoptLite.PVType
PV

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=1600.0,
    om_cost_per_kw::Real=16.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
)
Note

If tilt is not provided then it is set to the Site.latitude. (Which is handled in the Scenario struct.)

source

Storage

REoptLite.ElecStorageType
Storage

Currently only electric storage is modeled but thermal storage will be added soon.

TODO update this doc string and perhaps the way we define arbitrary storage.

Base.@kwdef struct ElecStorage <: AbstractStorage
    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 = 840.0
    installed_cost_per_kwh::Float64 = 420.0
    replace_cost_per_kw::Float64 = 410.0
    replace_cost_per_kwh::Float64 = 200.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
end
source

Wind

REoptLite.WindType
Wind

struct with inner constructor:

function Wind(;
    min_kw = 0.0,
    max_kw = 1.0e9,
    installed_cost_per_kw = 0.0,
    om_cost_per_kw = 40.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.

source

Generator

REoptLite.GeneratorType
Generator

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,
)
source

DomesticHotWaterLoad

REoptLite.DomesticHotWaterLoadType
DomesticHotWaterLoad

There are many ways in which a DomesticHotWaterLoad can be defined:

  1. When using either doe_reference_name or blended_doe_reference_names in an ElectricLoad one only needs to provide the input key "DomesticHotWaterLoad" in the Scenario (JSON or Dict). In this case the values from DoE reference names from the ElectricLoad will be used to define the DomesticHotWaterLoad.
  2. One can provide the doe_reference_name or blended_doe_reference_names directly in the DomesticHotWaterLoad key within the Scenario. These values can be combined with the annual_mmbtu or monthly_mmbtu inputs to scale the DoE reference profile(s).
  3. One can provide the fuel_loads_mmbtu_per_hour value in the DomesticHotWaterLoad key within the Scenario.
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
)
source

SpaceHeatingLoad

REoptLite.SpaceHeatingLoadType
SpaceHeatingLoad

There are many ways in which a SpaceHeatingLoad can be defined:

  1. When using either doe_reference_name or blended_doe_reference_names in an ElectricLoad one only needs to provide the input key "SpaceHeatingLoad" in the Scenario (JSON or Dict). In this case the values from DoE reference names from the ElectricLoad will be used to define the SpaceHeatingLoad.
  2. One can provide the doe_reference_name or blended_doe_reference_names directly in the SpaceHeatingLoad key within the Scenario. These values can be combined with the annual_mmbtu or monthly_mmbtu inputs to scale the DoE reference profile(s).
  3. One can provide the fuel_loads_mmbtu_per_hour value in the SpaceHeatingLoad key within the Scenario.
function 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[],
    time_steps_per_hour::Int = 1,
    latitude::Real=0.0,
    longitude::Real=0.0
)
source

ExistingBoiler

REoptLite.ExistingBoilerType
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
)
source

CHP

REoptLite.CHPType
CHP

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
source

Settings

REoptLite.SettingsType
Settings

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
source