Internal functions

Index

Extension functions

EnergyModelsBase.create_linkFunction
create_link(m, 𝒯, 𝒫, l::Link, formulation::Formulation)

Set the constraints for a simple Link (input = output). Can serve as fallback option for all unspecified subtypes of Link.

All links with capacity, as indicated through the function has_capacity call furthermore the function constraints_capacity_installed for limiting the capacity to the installed capacity.

source
EnergyModelsBase.objectiveMethod
objective(m, 𝒳, 𝒫, 𝒯, modeltype::EnergyModel)

Create the objective for the optimization problem for a given modeltype.

The default option includes to the objective function:

  • the variable and fixed operating expenses for the individual nodes,
  • the variable and fixed operating expenses for the individual links, and
  • the cost for the emissions.

The values are not discounted.

This function serve as fallback option if no other method is specified for a specific modeltype.

source
EnergyModelsBase.objective_operationalFunction
objective_operational(m, elements, 𝒯ᴵⁿᵛ::TS.AbstractStratPers, modeltype::EnergyModel)

Create JuMP expressions indexed over the investment periods 𝒯ᴵⁿᵛ for different elements. The expressions correspond to the operational expenses of the different elements. The expressions are not discounted and do not take the duration of the investment periods into account.

By default, objective expressions are included for:

  • elements = 𝒩::Vector{<:Node}. In the case of a vector of nodes, the function returns the sum of the variable and fixed OPEX for all nodes whose method of the function has_opex returns true.
  • elements = 𝒩::Vector{<:Link}. In the case of a vector of links, the function returns the sum of the variable and fixed OPEX for all links whose method of the function has_opex returns true.
  • elements = 𝒩::Vector{<:Resource}. In the case of a vector of resources, the function returns the costs associated to the emissions using the function emission_price.
Default function

It is also possible to provide a tuple 𝒳 for only operational or only investment objective contributions. In this situation, the expression returns a value of 0 for all investment periods.

source
EnergyModelsBase.emissions_operationalFunction
emissions_operational(m, elements, 𝒫ᵉᵐ, 𝒯, modeltype::EnergyModel)

Create JuMP expressions indexed over the operational periods 𝒯 for different elements. The expressions correspond to the total emissions of a given type.

By default, objective expressions are included for:

  • elements = 𝒩::Vector{<:Node}. In the case of a vector of nodes, the function returns the sum of the emissions of all nodes whose method of the function has_emissions returns true. These nodes should be automatically identified without user intervention.
  • elements = 𝒩::Vector{<:Link}. In the case of a vector of links, the function returns the sum of the emissions of all links whose method of the function has_emissions returns true.
source

Constraint functions

EnergyModelsBase.constraints_nodeFunction
constraints_node(m, 𝒩, 𝒯, 𝒫, ℒ, modeltype::EnergyModel)

Create link constraints for each n ∈ 𝒩 depending on its type and calling the function create_node(m, n, 𝒯, 𝒫) for the individual node constraints.

Create constraints for fixed OPEX.

source
EnergyModelsBase.constraints_level_iterateFunction
constraints_level_iterate(
    m,
    n::Storage,
    prev_pers::PreviousPeriods,
    cyclic_pers::CyclicPeriods,
    per,
    ts::RepresentativePeriods,
    modeltype::EnergyModel,
)

Iterate through the individual time structures of a Storage node. This iteration function should in general allow for all necessary functionality for incorporating modifications.

In the case of RepresentativePeriods, this is achieved through calling the function constraints_level_rp to introduce, e.g., cyclic constraints as it is in the default case.

source
constraints_level_iterate(
    m,
    n::Storage,
    prev_pers::PreviousPeriods,
    per,
    ts::OperationalScenarios,
    modeltype::EnergyModel,
)

In the case of OperationalScenarios, this is achieved through calling the function constraints_level_scp. In the default case, no constraints are added.

source
constraints_level_iterate(
    m,
    n::Storage,
    prev_pers::PreviousPeriods,
    per,
    ts::SimpleTimes,
    modeltype::EnergyModel,
)

In the case of SimpleTimes, the iterator function is at its lowest level. In this situation,the previous level is calculated using the function previous_level and used for the storage balance. The the approach for calculating the previous_level is depending on the types in the parameteric type PreviousPeriods.

In addition, additional bounds can be included on the initial level within an operational period.

source
EnergyModelsBase.constraints_level_rpFunction
constraints_level_rp(m, n::Storage, per, modeltype::EnergyModel)

Provides additional contraints for representative periods.

The default approach is to set the total change in all representative periods within a strategic period to 0. This implies that the Storage node cannot accumulate energy between individual strategic periods.

source
constraints_level_rp(m, n::Storage{<:Accumulating}, per, modeltype::EnergyModel)

When a Storage{<:Accumulating} is used, the cyclic constraint for restricting the level change within a strategic period to 0 (through setting the sum of :stor_level_Δ_rp within a strategic period to 0) is not implemented as accumulation within a strategic period is desirable.

This implies that Accumulating behaviours require the developer to introduce the function previous_level in the case of prev_pers = PreviousPeriods{<:NothingPeriod, Nothing, Nothing}.

source
constraints_level_rp(m, n::Storage{CyclicRepresentative}, per, modeltype::EnergyModel)

When a Storage{CyclicRepresentative} is used, the change in the representative period is constrained to 0.

source
EnergyModelsBase.constraints_level_scpFunction
constraints_level_scp(m, n::Storage, per, modeltype::EnergyModel)

Provides additional constraints for scenario periods.

The default approach is to not provide any constraints.

source
constraints_level_scp(m, n::Storage{CyclicRepresentative}, per, modeltype::EnergyModel)

When a Storage{CyclicRepresentative} is used, the final level in an operational scenario is constrained to be the same in all operational scenarios.

source
EnergyModelsBase.constraints_level_boundsFunction
constraints_level_bounds(
    m,
    n::Storage,
    t::TS.TimePeriod,
    prev_pers::TS.TimePeriod,
    modeltype::EnergyModel,
)

Provides bounds on the initial storage level in an operational period to account for the level being modelled at the end of the operational periods.

The default approach is to not provide bounds.

source
constraints_level_bounds(
    m,
    n::Storage,
    t::TS.TimePeriod,
    cyclic_pers::CyclicPeriods{<:TS.AbstractRepresentativePeriod},
    modeltype::EnergyModel,
)

When representative periods are used and the previous operational period is nothing, then bounds are incorporated to avoid that the initial level storage level is violating the maximum and minimum level.

source

Variable creation functions

EnergyModelsBase.variables_capacityFunction
variables_capacity(m, 𝒩::Vector{<:Node}, 𝒯, modeltype::EnergyModel)
variables_capacity(m, ℒ::Vector{<:Link}, 𝒯, modeltype::EnergyModel)

Declaration of different capacity variables for the element types introduced in EnergyModelsBase. EnergyModelsBase introduces two elements for an energy system, and hence, provides the user with two individual methods:

Node variables

All nodes, excluding Storage and Availability nodes have the following capacity variables:

  • cap_use[n, t] is the capacity utilization of node n in operational period t.
  • cap_inst[n, t] is the installed capacity of node n in operational period t.

Storage nodes have multiple capacities. The storage level (the amount of mass/energy) stored is described through the followign variables

  • stor_level[n, t] is the storage level of storage n at the end of operational period t.
  • stor_level_Δ_op[n, t] is the storage level change of storage n in operational period t.
  • stor_level_Δ_rp[n, t_rp] is the storage level change of storage n in representative period t_rp. These variables are only created if the time structure includes representative periods.
  • stor_level_Δ_sp[n, t_inv] is storage level change of storage n in investment period t_inv. These variables are optional and created through SparseVariables. This implies you have to create a method for the function variables_node for your node type that should use these variables.
  • stor_level_inst[n, t] is the installed storage capacity for storage n in operational period t, constrained in the operational case to the provided capacity in the storage parameters used in the field :level.

The charge capacity variables are describing the charging of a Storage:

  • stor_charge_use[n, t] is the charging rate of storage n in operational period t.
  • stor_charge_inst[n, t] is the installed charging capacity, e.g., power, of storage n in operational period t, constrained in the operational case to the provided capacity in the storage parameters used in the field :charge. This variable is only declared if the Storage node has a field charge and the storage parameters include a capacity.

The discharge capacity variables are describing the discharging of a Storage:

  • stor_discharge_use[n, t] is the discharging rate of storage n in operational period t.
  • stor_discharge_inst[n, t] is the installed discharging capacity, e.g., power, of storage n in operational period t, constrained in the operational case to the provided capacity in the storage parameters used in the field :discharge. This variable is only declared if the Storage node has a field discharge and the storage parameters include a capacity.
Link variables

The capacity variables are only created for links, if the function has_capacity has received an additional method for a given link l returning the value true.

  • link_cap_inst[l, t] is the installed capacity of link l in operational period t.
source
EnergyModelsBase.variables_flowFunction
variables_flow(m, 𝒩::Vector{<:Node}, 𝒯, modeltype::EnergyModel)
variables_flow(m, ℒ::Vector{<:Link}, 𝒯, modeltype::EnergyModel)

Declaration of flow OPEX variables for the element types introduced in EnergyModelsBase. EnergyModelsBase introduces two elements for an energy system, and hence, provides the user with two individual methods:

Node variables
  • flow_in[n, t, p] is the flow into node n in operational period t for resource p. The inflow resources of node n are extracted using the function inputs.
  • flow_out[n, t, p] is the flow from node n in operational period t for resource p. The outflow resources of node n are extracted using the function outputs.
Link variables
  • link_in[n, t] is the flow into link l in operational period t for resource p. The inflow resources of link l are extracted using the function inputs.
  • link_out[n, t, p] is the flow from link l in operational period t for resource p. The outflow resources of link l are extracted using the function outputs.

By default, all nodes 𝒩 and links only allow for unidirectional flow. You can specify bidirection flow through providing a method to the function is_unidirectional for new link/node types.

source
EnergyModelsBase.variables_opexFunction
variables_opex(m, 𝒩::Vector{<:Node}, 𝒯, modeltype::EnergyModel)
variables_opex(m, ℒ::Vector{<:Link}, 𝒯, modeltype::EnergyModel)

Declaration of different OPEX variables for the element types introduced in EnergyModelsBase. EnergyModelsBase introduces two elements for an energy system, and hence, provides the user with two individual methods:

Node variables
  • opex_var[n, t_inv] are the variable operating expenses of node n in investment period t_inv. The values can be negative to account for revenue streams
  • opex_fixed[n, t_inv] are the fixed operating expenses of node n in investment period t_inv.
Link variables

The OPEX variables are only created for links, if the function has_opex has received an additional method for a given link l returning the value true.

  • link_opex_var[n, t_inv] are the variable operating expenses of link l in investment period t_inv. The values can be negative to account for revenue streams
  • link_opex_fixed[n, t_inv] are the fixed operating expenses of node n in investment period t_inv.
source
EnergyModelsBase.variables_capexMethod
variables_capex(m, 𝒩::Vector{<:Node}, 𝒯, modeltype::EnergyModel)
variables_capex(m, ℒ::Vector{<:Link}, 𝒯, modeltype::EnergyModel)

Declaration of different capital expenditures variables for the element types introduced in EnergyModelsBase. EnergyModelsBase introduces two elements for an energy system, and hence, provides the user with two individual methods:

The default method is empty but it is required for multiple dispatch in investment models.

source
EnergyModelsBase.variables_emissionFunction
variables_emission(m, ℒ::Vector{<:Node}, 𝒫, 𝒯, modeltype::EnergyModel)
variables_emission(m, ℒ::Vector{<:Link}, 𝒫, 𝒯, modeltype::EnergyModel)
variables_emission(m, 𝒯, 𝒫, modeltype::EnergyModel)

Declaration of emissions variables for the element types introduced in EnergyModelsBase as well as global emission variables. EnergyModelsBase introduces two elements for an energy system, and hence, provides the user with in total three individual methods, including the global variables:

Node variables
  • emissions_node[n_em, t, p_em] are the emissions of node n_em with emissions in operational period t of emission resource p_em. The values can be negative to account for removal of emissions resources from the environment, through, e.g., direct air capture.
Link variables
  • emissions_node[n_em, t, p_em] are the emissions of link l_em with emissions in operational period t of emission resource p_em. The values can only be positive as links should not allow for removal.
Global variables
  • emissions_total[t, p_em] are the total emissions of in operational period t of emission resource p_em. The values can be negative to account for removal of emissions resources from the environment, through, e.g., direct air capture.
  • emissions_strategic[t_inv, p_em] are the total emissions of in operational period t of emission resource p_em. The values can be negative to account for removal of emissions resources from the environment, through, e.g., direct air capture. The variable has an upper bound introduced through the function emission_limit of the EnergyModel.

The inclusion of node and link emissions require that the function has_emissions returns true for the given node or link. This is by default achieved for nodes through inclusion of EmissionData in nodes while links require you to explicitly provide a method for your link type.

source
EnergyModelsBase.variables_elementsFunction
variables_elements(m, 𝒩::Vector{<:Node}, 𝒯, modeltype::EnergyModel)
variables_elements(m, ℒ::Vector{<:Link}, 𝒯, modeltype::EnergyModel)

Loop through all element types and create variables specific to each type. It starts at the top level and subsequently move through the branches until it reaches a leave. That is, node nodes, variables_node will be called on a Node before it is called on NetworkNode-nodes.

EnergyModelsBase provides the user with two element types, Link and Node:

source

Check functions

EnergyModelsBase.check_dataFunction
check_data(case, modeltype::EnergyModel, check_timeprofiles::Bool)

Check if the case data is consistent. Use the @assert_or_log macro when testing. Currently only checking node data.

source
EnergyModelsBase.check_case_dataFunction
check_case_data(case)

Checks the case dictionary is in the correct format.

Checks

  • The dictionary requires the keys :T, :nodes, :links, and :products.
  • The individual keys are of the correct type, that is
    • :T::TimeStructure,
    • :nodes::Vector{<:Node},
    • :links::Vector{<:Link}, and
    • :products::Vector{<:Resource}.
source
EnergyModelsBase.check_modelFunction
check_model(case, modeltype::EnergyModel, check_timeprofiles::Bool)

Checks the modeltype .

Checks

  • All ResourceEmits require a corresponding value in the field emission_limit.
  • The emission_limit time profiles cannot have a finer granulation than StrategicProfile.
  • The emission_price time profiles cannot have a finer granulation than StrategicProfile.

Conditional checks (if check_timeprofiles=true)

  • The profiles in emission_limit have to have the same length as the number of strategic periods.
  • The profiles in emission_price have to have the same length as the number of strategic periods.
source
EnergyModelsBase.check_nodeFunction
check_node(n::Node, 𝒯, modeltype::EnergyModel, check_timeprofiles::Bool)

Check that the fields of a Node corresponds to required structure.

The default approach calls the subroutine check_node_default which provides the user with default checks for Source, NetworkNode, Availability, Storage, and Sink nodes.

Creating a new node type

When developing a new node with new checks, it is important to create a new method for check_node. You can then call within this function the default tests for the corresponding supertype through calling the function check_node_default.

source
EnergyModelsBase.check_node_defaultFunction
check_node_default(n::Node, 𝒯, modeltype::EnergyModel, check_timeprofiles::Bool)

This method checks that a Node node is valid. By default, that does not include any checks.

source
check_node_default(n::Availability, 𝒯, modeltype::EnergyModel, check_timeprofiles::Bool)

This method checks that an Availability node is valid. By default, that does not include any checks.

source
check_node_default(n::Source, 𝒯, modeltype::EnergyModel, check_timeprofiles::Bool)

Subroutine that can be utilized in other packages for incorporating the standard tests for a Source node.

Checks

  • The field cap is required to be non-negative.
  • The values of the dictionary output are required to be non-negative.
  • The value of the field fixed_opex is required to be non-negative and accessible through a StrategicPeriod as outlined in the function check_fixed_opex(n, 𝒯ᴵⁿᵛ, check_timeprofiles).
source
check_node_default(n::NetworkNode, 𝒯, modeltype::EnergyModel, check_timeprofiles::Bool)

Subroutine that can be utilized in other packages for incorporating the standard tests for a NetworkNode node.

Checks

  • The field cap is required to be non-negative.
  • The values of the dictionary input are required to be non-negative.
  • The values of the dictionary output are required to be non-negative.
  • The value of the field fixed_opex is required to be non-negative and accessible through a StrategicPeriod as outlined in the function check_fixed_opex(n, 𝒯ᴵⁿᵛ, check_timeprofiles).
source
check_node_default(n::Storage, 𝒯, modeltype::EnergyModel, check_timeprofiles::Bool)

Subroutine that can be utilized in other packages for incorporating the standard tests for a Storage node.

Checks

  • The TimeProfile of the field capacity in the type in the field charge is required to be non-negative if the chosen composite type has the field capacity.
  • The TimeProfile of the field capacity in the type in the field level is required to be non-negative`.
  • The TimeProfile of the field capacity in the type in the field discharge is required to be non-negative if the chosen composite type has the field capacity.
  • The TimeProfile of the field fixed_opex is required to be non-negative and accessible through a StrategicPeriod as outlined in the function check_fixed_opex(n, 𝒯ᴵⁿᵛ, check_timeprofiles) for the chosen composite type .
  • The values of the dictionary input are required to be non-negative.
  • The values of the dictionary output are required to be non-negative.
source
check_node_default(n::Sink, 𝒯, modeltype::EnergyModel, check_timeprofiles::Bool)

Subroutine that can be utilized in other packages for incorporating the standard tests for a Sink node.

Checks

  • The field cap is required to be non-negative.
  • The values of the dictionary input are required to be non-negative.
  • The dictionary penalty is required to have the keys :deficit and :surplus.
  • The sum of the values :deficit and :surplus in the dictionary penalty has to be non-negative to avoid an infeasible model.
source
EnergyModelsBase.check_fixed_opexFunction
check_fixed_opex(n, 𝒯ᴵⁿᵛ, check_timeprofiles::Bool)

Checks that the fixed opex value follows the given TimeStructure. This check requires that a function opex_fixed(n) is defined for the input n which returns a TimeProfile.

Checks

  • The opex_fixed time profile cannot have a finer granulation than StrategicProfile.

Conditional checks (if check_timeprofiles=true)

  • The profiles in opex_fixed have to have the same length as the number of strategic periods.
source
EnergyModelsBase.check_node_dataMethod
check_node_data(n::Node, data::Data, 𝒯, modeltype::EnergyModel, check_timeprofiles::Bool)
check_node_data(n::Node, data::EmissionsData, 𝒯, modeltype::EnergyModel, check_timeprofiles::Bool)

Check that the included Data types of a Node corresponds to required structure. This function will always result in a multiple error message, if several instances of the same supertype is loaded.

Checks EmissionsData

  • Each node can only have a single EmissionsData.
  • Time profiles for process emissions, if present.
  • The value of the field co2_capture is required to be in the range $[0, 1]$, if CaptureData is used.
source
EnergyModelsBase.check_profileFunction
check_profile(fieldname, value::TimeProfile, 𝒯)

Check that an individual TimeProfile corresponds to the time structure 𝒯. It currently does not include support for identifying OperationalScenarios.

source
check_profile(fieldname, value::TimeProfile, ts::TimeStructure, sp)

Check that an individual TimeProfile corresponds to the time structure ts in strategic period sp. The function flow is designed to provide errors in all situations in which the the TimeProfile does not correspond to the chosen TimeStructure through the application of the @assert_or_log macro.

Examples for inconsistent combinations:

ts = SimpleTimes(3, 1)

# A too long OperationalProfile resulting in omitting the last 2 values
value = OperationalProfile([1, 2, 3, 4, 5])

# A too short OperationalProfile resulting in repetition of the last value once
value = OperationalProfile([1, 2])

If you use a more detailed TimeProfile than the TimeStructure, it will you provide you with a warning, e.g., using RepresentativeProfile without RepresentativePeriods.

It currently does not include support for identifying OperationalProfiles.

source
EnergyModelsBase.check_strategic_profileFunction
check_strategic_profile(time_profile::TimeProfile, message::String)

Function for checking that an individual TimeProfile does not include the wrong type for strategic indexing.

Checks

  • TimeProfiles accessed in StrategicPeriods cannot include OperationalProfile, ScenarioProfile, or RepresentativeProfile as this is not allowed through indexing on the TimeProfile.
source
EnergyModelsBase.check_representative_profileFunction
check_representative_profile(time_profile::TimeProfile, message::String)

Function for checking that an individual TimeProfile does not include the wrong type for representative periods indexing.

Input

  • time_profile - The time profile that should be checked.
  • message - A message that should be printed after the type of profile.

Checks

  • TimeProfiles accessed in RepresentativePeriods cannot include OperationalProfile or ScenarioProfile as this is not allowed through indexing on the TimeProfile.
source
EnergyModelsBase.check_scenario_profileFunction
check_scenario_profile(time_profile::TimeProfile, message::String)

Function for checking that an individual TimeProfile does not include the wrong type for scenario indexing.

Checks

  • TimeProfiles accessed in RepresentativePeriods cannot include OperationalProfile or ScenarioProfile as this is not allowed through indexing on the TimeProfile.
source

Identification functions

EnergyModelsBase.link_resFunction
link_res(l::Link)

Return the resources transported for a given link l.

The default approach is to use the intersection of the inputs of the to node and the outputs of the from node.

source
EnergyModelsBase.link_subFunction
link_sub(ℒ::Vector{<:Link}, n::Node)

Return connected links from the vector for a given node n as array. The first subarray corresponds to the from field, while the second to the to field.

source
EnergyModelsBase.res_emFunction
res_em(𝒫::Array{<:Resource})
res_em(𝒫::Dict)

Returns all emission resources for a

  • a given array ::Array{<:Resource}. The output is in this case an Array{<:Resource}
  • a given dictionary ::Dict. The output is in this case a dictionary Dict with the correct fields
source
EnergyModelsBase.res_notFunction
res_not(𝒩::Array{<:Resource}, res_inst)
res_not(𝒫::Dict, res_inst::Resource)

Return all resources that are not res_inst for

  • a given array ::Array{<:Resource}. The output is in this case an Array{<:Resource}
  • a given dictionary ::Dict. The output is in this case a dictionary Dict with the correct fields
source
EnergyModelsBase.res_subFunction
res_sub(𝒫::Array{<:Resource}, sub = ResourceEmit)

Return resources that are of type sub for a given Array ::Array{Resource}.

source

Miscellaneous functions

EnergyModelsBase.collect_typesFunction
collect_types(types_list)

Return a Dict of all the give types_list and their supertypes. The keys in the dictionary are the types, and their corresponding value is the number in the type hierarchy.

As an example, Node is at the top and will thus have the value 1. Types just below Node will have value 2, and so on.

source
EnergyModelsBase.sort_typesFunction
sort_types(types_list::Dict)

Sort the result of collect_types and return a vector where a supertype comes before all its subtypes.

source