The REoptInputs structure

The REoptInputs structure uses the Scenario to build all of the data necessary to construct the JuMP mathematical model.

REoptInputs

REoptLite.REoptInputsType
REoptInputs

The data structure for all the inputs necessary to construct the JuMP model.

struct REoptInputs <: AbstractInputs
    s::AbstractScenario
    techs::Techs
    min_sizes::Dict{String, Float64}  # (techs)
    max_sizes::Dict{String, Float64}  # (techs)
    existing_sizes::Dict{String, Float64}  # (techs)
    cap_cost_slope::Dict{String, Any}  # (techs)
    om_cost_per_kw::Dict{String, Float64}  # (techs)
    time_steps::UnitRange
    time_steps_with_grid::Array{Int, 1}
    time_steps_without_grid::Array{Int, 1}
    hours_per_timestep::Float64
    months::UnitRange
    production_factor::DenseAxisArray{Float64, 2}  # (techs, time_steps)
    levelization_factor::Dict{String, Float64}  # (techs)
    value_of_lost_load_per_kwh::Array{R, 1} where R<:Real #default set to 1 US dollar per kwh
    pwf_e::Float64
    pwf_om::Float64
    third_party_factor::Float64
    pvlocations::Array{Symbol, 1}
    maxsize_pv_locations::DenseAxisArray{Float64, 1}  # indexed on pvlocations
    pv_to_location::Dict{String, Dict{Symbol, Int64}}  # (techs.pv, pvlocations)
    ratchets::UnitRange
    techs_by_exportbin::Dict{Symbol, AbstractArray}  # keys can include [:NEM, :WHL, :CUR]
    export_bins_by_tech::Dict
    n_segs_by_tech::Dict{String, Int}
    seg_min_size::Dict{String, Dict{Int, Float64}}
    seg_max_size::Dict{String, Dict{Int, Float64}}
    seg_yint::Dict{String, Dict{Int, Float64}}
    pbi_pwf::Dict{String, Any}  # (pbi_techs)
    pbi_max_benefit::Dict{String, Any}  # (pbi_techs)
    pbi_max_kw::Dict{String, Any}  # (pbi_techs)
    pbi_benefit_per_kwh::Dict{String, Any}  # (pbi_techs)
    boiler_efficiency::Dict{String, Float64}
end
source
REoptLite.REoptInputsMethod
REoptInputs(fp::String)

Use fp to load in JSON scenario:

function REoptInputs(fp::String)
    s = Scenario(JSON.parsefile(fp))
    REoptInputs(s)
end

Useful if you want to manually modify REoptInputs before solving the model.

source
REoptLite.REoptInputsMethod
REoptInputs(s::AbstractScenario)

Constructor for REoptInputs. Translates the Scenario into all the data necessary for building the JuMP model.

source

Design Concepts for REoptInputs

At a high level the REoptInputs constructor does the following tasks:

  • build index sets for the JuMP model decision variables,
  • create maps from one set to another set,
  • and generate coefficient arrays necessary for model constraints.

Index Sets

There are a few String[] that are built by REoptInputs that are then used as index sets in the model constraints. The primary index set is the techs.all array of strings, which contains all the technolgy names that are being modeled. With the techs.all array we can easily apply a constraint over all technolgies. For example:

@constraint(m, [t in p.techs.all],
    m[Symbol("dvSize"*_n)][t] <= p.max_sizes[t]
)

where p is the REoptInputs struct. There are a couple things to note from this last example:

  1. The decision variable dvSize is accessed in the JuMP.Model m using the Symbol notation so that this constraint can be used in the multi-node case in addition to the single node case. The _n input value is an empty string by default and in the case of a multi-node model the _n string will be set by the Site.node integer. For example, if Site.node is 3 then _n is "_3".
  2. The p.max_sizes array is also indexed on p.techs.all. The max_sizes is built in the REoptInputs constructor by using all the technologies in the Scenario that have max_kw values greater than zero.

Besides the techs.all array the are many sub-sets, such as techs.pv, techs.gen, techs.elec, p.techs.segmented, techs.no_curtail, that allow us to apply constraints to those sets. For example:

for t in p.techs.no_curtail
    for ts in p.time_steps
        fix(m[Symbol("dvCurtail"*_n)][t, ts] , 0.0, force=true)
    end
end

Set maps

The set maps are best explained with an example. The techs_by_exportbin map uses each technology'sattributes (eg. PV) to map each technology to which export bins that technology can access. The export bins include:

  1. :NEM (Net Energy Metering)
  2. :WHL (Wholesale)
  3. :EXC (Excess, beyond NEM))

The bins that a technolgy can access are determined by the technologies attributes can_net_meter, can_wholesale, and can_export_beyond_nem_limit. So if PV.can_net_meter = true, Wind.can_net_meter = true and all the other attributes are false then the techs_by_exportbin will only have one non-empty key:

techs_by_exportbin = Dict(
    :NEM => ["PV", "Wind"],
    :WHL => [],
    :EXC => []
)

A use-case example for the techs_by_exportbin map is defining the net metering benefit:

NEM_benefit = @expression(m, p.pwf_e * p.hours_per_timestep *
    sum( sum(p.s.electric_tariff.export_rates[:NEM][ts] * m[Symbol("dvProductionToGrid"*_n)][t, :NEM, ts] 
        for t in p.techs_by_exportbin[:NEM]) for ts in p.time_steps)
)

Other set maps include: export_bins_by_tech and n_segs_by_tech. The latter tells how many cost curve segments each technology has.

Coefficient Arrays

The JuMP model costs are formulated in net present value terms, accounting for all benefits (production, capacity, and investment incentives) and the total cost over the analysis_period. The REoptInputs constructor translates the raw input parameters, such as the operations and maintenance costs, into present value terms using the provided discount rate. For example, the pwf_e is the present worth factor for electricity that accounts for the elec_cost_escalation_pct, the analysis_period, and the offtaker_discount_pct. Note that tax benefits are applied directly in the JuMP model for clarity on which costs are tax-deductible and which are not.

Besides econimic parameters, the REoptInputs constructor also puts together the important production_factor array. The production_factor array is simple for continuously variable generators (such as the Generator), for which the production_factor is 1 in all time steps. However, for variable generators (such as Wind and PV) the production_factor varies by time step. If the user does not provide the PV production factor, for example, then the REoptInputs constructor uses the PVWatts API to download the location specific PV production factor. REoptInputs also accounts for the PV.degradation_pct in building the production_factor array.