Profile
Note
This section of the documentation is auto-generated from the code of the Julia-based core model. Refer to IESopt.jl for any further details (which may require some familiarity with Julia).
If you spot incorrect math-mode rendering, or similar issues, please file an issue, since rendering documentation from Julia to Python is not the easiest task.
Overview
A Profile
allows representing “model boundaries” - parts of initial problem that are not endogenously modelled - with a support for time series data. Examples are hydro reservoir inflows, electricity demand, importing gas, and so on. Besides modelling fixed profiles, they also allow different ways to modify the value endogenously.
Basic Examples
A Profile
that depicts a fixed electricity demand:
demand_XY:
type: Profile
carrier: electricity
node_from: grid
value: demand_XY@input_file
A Profile
that handles cost of fuel:
fuel_gas:
type: Profile
carrier: gas
node_to: country_gas_grid
mode: create
cost: 100.0
A Profile
that handles CO2 emission costs:
co2_cost:
type: Profile
carrier: co2
node_from: total_co2
mode: destroy
cost: 150.0
A Profile
that handles selling electricity:
sell_electricity:
type: Profile
carrier: electricity
node_from: internal_grid_node
mode: destroy
cost: -30.0
Parameters
carrier
Carrier
of this Profile
. Must match the Carrier
of the Node
that this connects to.
mandatory: yes
default: \(-\)
values: string
unit: -
value
The concrete value of this Profile
- either static or as time series. Only applicable if mode: fixed
.
mandatory: no
default: \(-\)
values: numeric,
col@file
unit: power
node_from
Name of the Node
that this Profile
draws energy from. Exactly one of node_from
and node_to
must be set.
mandatory: no
default: \(-\)
values: string
unit: -
node_to
Name of the Node
that this Profile
feeds energy to. Exactly one of node_from
and node_to
must be set.
mandatory: no
default: \(-\)
values: string
unit: -
mode
The mode of operation of this Profile
. fixed
uses the supplied value
, ranged
allows ranging between lb
and ub
, while create
(must specify node_to
) and destroy
(must specify node_from
) handle arbitrary energy flows that are bounded from below by 0
. Use fixed
if you want to fix the value of the Profile
to a specific value, e.g., a given energy demand. Use create
to “import” energy into the model, e.g., from a not explicitly modelled gas market, indcucing a certain cost
for buying that energy. Use destroy
to “export” energy from the model, e.g., to handle CO2 going into the atmosphere (which may be taxed, etc., by the cost
of this Profile
). Use ranged
if you need more fine grained control over the value of the Profile
, than what create
and destroy
allow (e.g., a grid limited energy supplier).
mandatory: no
default: \(fixed\)
values: -
unit: -
lb
The lower bound of the range of this Profile
(must be used together with mode: ranged
).
mandatory: no
default: \(-\infty\)
values: numeric
unit: power
ub
The upper bound of the range of this Profile
(must be used together with mode: ranged
).
mandatory: no
default: \(+\infty\)
values: numeric
unit: power
cost
Cost per unit of energy that this Profile
injects or withdraws from a Node
. Refer to the basic examples to see how this can be combined with mode
for different use cases.
mandatory: no
default: \(0\)
values: numeric
unit: monetary per energy
build_priority
Priority for the build order of components. Components with higher build_priority are built before. This can be useful for addons, that connect multiple components and rely on specific components being initialized before others.
mandatory: no
default: \(0\)
values: numeric
unit: -
Detailed reference
Expressions
value
How to access this expression?
# Using Julia (`IESopt.jl`):
import IESopt
model = IESopt.run(...) # assuming this is your model
IESopt.get_component(model, "your_profile").exp.value
# Using Python (`iesopt`):
import iesopt
model = iesopt.run(...) # assuming this is your model
model.get_component("your_profile").exp.value
Full implementation and all details: profile/exp_value @ IESopt.jl
Construct the
JuMP.AffExpr
that keeps the total value of thisProfile
for eachSnapshot
.
This is skipped if the
value
of thisProfile
is handled by anExpression
. Otherwise it is initialized based onprofile.value
.
Variables
aux_value
How to access this variable?
# Using Julia (`IESopt.jl`):
import IESopt
model = IESopt.run(...) # assuming this is your model
IESopt.get_component(model, "your_profile").var.aux_value
# Using Python (`iesopt`):
import iesopt
model = iesopt.run(...) # assuming this is your model
model.get_component("your_profile").var.aux_value
Full implementation and all details: profile/var_aux_value @ IESopt.jl
Add the variable that is used in this
Profile
s value to themodel
.
The variable
var_value[t]
is constructed and is linked to the correctNode
s. There are different ways, IESopt interprets this, based on the setting ofprofile.mode
:
fixed: The value is already handled by the constant term of
profile.exp.value
and NO variable is constructed.create, destroy, or ranged: This models the creation or destruction of energy - used mainly to represent model boundaries, and energy that comes into the model or leaves the model’s scope. It is however important that
create
should mostly be used feeding into aNode
(profile.node_from = nothing
) anddestroy
withdrawing from aNode
(profile.node_to = nothing
). Iflb
andub
are defined,ranged
can be used that allows a more detailed control over theProfile
, specifying upper and lower bounds for everySnapshot
. See_profile_con_value_bounds!(profile::Profile)
for details on the specific bounds for each case.
This variable is added to the
profile.exp.value
. Additionally, the energy (thatprofile.exp.value
represents) gets “injected” at theNode
s that theprofile
is connected to, resulting in
Constraints
value_bounds
How to access this constraint?
# Using Julia (`IESopt.jl`):
import IESopt
model = IESopt.run(...) # assuming this is your model
IESopt.get_component(model, "your_profile").con.value_bounds
# Using Python (`iesopt`):
import iesopt
model = iesopt.run(...) # assuming this is your model
model.get_component("your_profile").con.value_bounds
Full implementation and all details: profile/con_value_bounds @ IESopt.jl
Add the constraint defining the bounds of this
profile
to themodel
.
This heavily depends on the
mode
setting, as it does nothing if themode
is set tofixed
, or thevalue
is actually controlled by anExpression
. The variable can be accessed viaprofile.var.aux_value[t]
, but using the normal result extraction is recommended, since that properly handles theprofile.exp.value
instead.
Otherwise:
if profile.mode === :create or profile.mode === :destroy
if profile.mode === :ranged
Here,
lb
andub
can be left empty, which drops the respective constraint.
Objectives
cost
How to access this objective?
# Using Julia (`IESopt.jl`):
import IESopt
model = IESopt.run(...) # assuming this is your model
IESopt.get_component(model, "your_profile").obj.cost
# Using Python (`iesopt`):
import iesopt
model = iesopt.run(...) # assuming this is your model
model.get_component("your_profile").obj.cost
Full implementation and all details: profile/obj_cost @ IESopt.jl
Add the (potential) cost of this
Profile
to the global objective function.
The
profile.cost
setting specifies a potential cost for the creation (“resource costs”, i.e. importing gas into the model) or destruction (“penalties”, i.e. costs linked to the emission of CO2). It can have a unique value for everySnapshot
, i.e. allowing to model a time-varying gas price throughout the year.
The contribution to the global objective function is as follows:
Here \(\omega_t\) is the
weight
ofSnapshot
t
, and \(\text{value}_t\) actually refers to the value ofprofile.exp.value[t]
(and not only on the maybe non-existing variable).