Skip to content

Commit

Permalink
feat: add non-clean version of some examples
Browse files Browse the repository at this point in the history
  • Loading branch information
Stefan Strömer committed Jun 1, 2024
1 parent ac69f21 commit d3ca200
Show file tree
Hide file tree
Showing 68 changed files with 178,680 additions and 0 deletions.
91 changes: 91 additions & 0 deletions src/examples/02_advanced_single_node.iesopt.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Comments indicate points of this model file that changed compared to the previous examples. All other elements are not
# explained/described anymore. See also: 01_basic_single_node.yaml

config:
optimization:
problem_type: LP
snapshots:
count: 4
solver:
name: highs

carriers:
electricity: {}
gas: {}
co2: {}

components:
# This is the single node power grid that connects everything. It now does **not** include any storage itself.
node:
type: Node
carrier: electricity

# This models the storage of a simple battery energy storage system, extending the previous example without losses.
# It features bounds that indicate, that the battery can only be used inside a 10%-90% SoC, and will be charged and
# discharged by separate units.
bess:
type: Node
carrier: electricity
has_state: true
state_lb: 1
state_ub: 9

# This is the direction of the inverter that is used to charge the BESS with an efficiency of 90% and a limit of 3.
inverter_charge:
type: Unit
inputs: {electricity: node}
outputs: {electricity: bess}
capacity: 3 in:electricity
conversion: 1 electricity -> 0.9 electricity

# This is the direction of the inverter that is used to discharge the BESS with an efficiency of 90% and a limit of 3.
inverter_discharge:
type: Unit
inputs: {electricity: bess}
outputs: {electricity: node}
capacity: 3 out:electricity
conversion: 1 electricity -> 0.9 electricity

# The wind power plant now features a (low) marginal cost of generation.
plant_wind:
type: Unit
outputs: {electricity: node}
conversion: ~ -> 1 electricity
capacity: 10 out:electricity
availability_factor: [0.9, 0.1, 0.1, 0.1]
marginal_cost: 1.0 per out:electricity

plant_gas:
type: Unit
inputs: {gas: gas_grid}
outputs: {electricity: node, co2: total_co2}
conversion: 1 gas -> 0.4 electricity + 0.2 co2
capacity: 10 out:electricity

demand:
type: Profile
carrier: electricity
node_from: node
value: [1, 4, 5, 5]

gas_grid:
type: Node
carrier: gas

total_co2:
type: Node
carrier: co2

create_gas:
type: Profile
carrier: gas
node_to: gas_grid
mode: create
cost: 50.0

co2_emissions:
type: Profile
carrier: co2
node_from: total_co2
mode: destroy
cost: 100.0
89 changes: 89 additions & 0 deletions src/examples/03_basic_two_nodes.iesopt.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Comments indicate points of this model file that changed compared to the previous examples. All other elements are not
# explained/described anymore. See also: 02_advanced_single_node.yaml

config:
optimization:
problem_type: LP
snapshots:
count: 4
solver:
name: highs

carriers:
electricity: {}
gas: {}
co2: {}

components:
# There are now two nodes in the power grid, that will be connected by a line; node2 includes a lossless storage.
node1:
type: Node
carrier: electricity

node2:
type: Node
carrier: electricity
has_state: true
state_lb: 0
state_ub: 10

# This new type of core component is used to connect two nodes (that use the same energy carrier). It can model
# directional flows, losses, delays, flow limits, and so on. Specifying "capacity" as we do it here, constructs a
# connection that allows flows with -5 <= flow <= 5. The Nodes that are set as "from" and "to" indicate the direction
# of the flow; here positive values relate to a flow "from node1 to node2".
conn:
type: Connection
capacity: 5
node_from: node1
node_to: node2

# The wind power plant now feeds into node2 with a modified availability factor.
plant_wind:
type: Unit
outputs: {electricity: node2}
conversion: ~ -> 1 electricity
capacity: 10 out:electricity
availability_factor: [0.9, 0.0, 0.9, 0.0]

# The gas power plant now feeds into node1.
plant_gas:
type: Unit
inputs: {gas: gas_grid}
outputs: {electricity: node1, co2: total_co2}
conversion: 1 gas -> 0.4 electricity + 0.2 co2
capacity: 10 out:electricity

# Both nodes feature a unique demand time series, represented by two different Profiles.
demand1:
type: Profile
carrier: electricity
node_from: node1
value: [3, 3, 3, 3]

demand2:
type: Profile
carrier: electricity
node_from: node2
value: [4, 3, 1, 5]

gas_grid:
type: Node
carrier: gas

total_co2:
type: Node
carrier: co2

create_gas:
type: Profile
carrier: gas
node_to: gas_grid
mode: create
cost: 50.0

co2_emissions:
type: Profile
carrier: co2
node_from: total_co2
mode: destroy
cost: 100.0
105 changes: 105 additions & 0 deletions src/examples/04_constraint_safety.iesopt.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# This example demonstrates the effect and use of the inbuilt "constraint safety" feature. This artifically alters
# constraints inside the core components, in order to (hopefully) catch infeasibilities during the optimization run,
# returning a (partially) valid solution as well as an indication where the infeasibility occurs.
# Comments indicate points of this model file that changed compared to the previous examples. All other elements are not
# explained/described anymore. See also: 03_basic_two_nodes.yaml
#
# What does the safety feature do?
# Looking at the result of this optimization (e.g. using `JuMP.solution_summary(model, verbose=true)`), we can see that
# one of the "aux" (auxiliary) variables is not at 0 anymore (here: `connection_flow_aux[conn]`). This indicates that
# an additional 0.25 capacity are needed on the Connection "conn" to make the model feasible. This is also indicated by
# the large increase in the objective value (now being > 2.5e14), which comes from the constraint safety cost.
#
# Important: After optimizing the model, we can extract the "real" objective value from the solution using:
# `JuMP.value(model.ext[:objective])`. Keep in mind though, that this is the optimum that is achieved using the "fix"
# that the safety feature applies.

config:
optimization:
problem_type: LP
snapshots:
count: 4
solver:
name: highs
# This tells IESopt to enable the constraint safety feature (which is currently on by default).
constraint_safety: true
# This parameterizes the cost of utilizing the safety feature. This should be much higher than other costs in the
# objective function and defaults to 1e15. This, while being a rather safe number - meaning it most likely will not
# interfer in any wrong way with your model - comes at the cost of numerical instability. This can be handled
# "properly" by some solvers (like Gurobi) but will negatively impact others (like GLPK). To counter this we can
# specify a lower cost coefficient here. Consider setting a lower tolerance for these solvers, for example call
# `JuMP.set_optimizer_attribute(model, "tol_dj", 1e-12)` for GLPK.
constraint_safety_cost: 1.0e9

carriers:
electricity: {}
gas: {}
co2: {}

components:
node1:
type: Node
carrier: electricity

node2:
type: Node
carrier: electricity
has_state: true
state_lb: 0
state_ub: 10

# The capacity of the connection is reduced (from 5 to 1).
conn:
type: Connection
capacity: 1
node_from: node1
node_to: node2

# Furthermore, the wind availability factor is reduced to introduce an infeasibility.
plant_wind:
type: Unit
outputs: {electricity: node2}
conversion: ~ -> 1 electricity
capacity: 10 out:electricity
availability_factor: [0.4, 0.0, 0.4, 0.0]

plant_gas:
type: Unit
inputs: {gas: gas_grid}
outputs: {electricity: node1, co2: total_co2}
conversion: 1 gas -> 0.4 electricity + 0.2 co2
capacity: 10 out:electricity

demand1:
type: Profile
carrier: electricity
node_from: node1
value: [3, 3, 3, 3]

demand2:
type: Profile
carrier: electricity
node_from: node2
value: [4, 3, 1, 5]

gas_grid:
type: Node
carrier: gas

total_co2:
type: Node
carrier: co2

create_gas:
type: Profile
carrier: gas
node_to: gas_grid
mode: create
cost: 50.0

co2_emissions:
type: Profile
carrier: co2
node_from: total_co2
mode: destroy
cost: 100.0
105 changes: 105 additions & 0 deletions src/examples/05_basic_two_nodes_1y.iesopt.yaml

Large diffs are not rendered by default.

91 changes: 91 additions & 0 deletions src/examples/06_recursion_h2.iesopt.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Comments indicate points of this model file that changed compared to the previous examples. All other elements are not
# explained/described anymore.
# This example constructs a simple model that produces hydrogen from excess solar energy and tries to only import
# as little energy as possible (this is here done by only assigning a cost to H2 import).

config:
optimization:
problem_type: LP
snapshots:
count: 168
solver:
name: highs
results:
enabled: true
memory_only: true

# We not only define units but also colors, that can be later picked up by the standardized visualization tools. Observe
# the fact, that the hexcode is in "", since a `#` counts as starting an in-line comment. Also we use the "block" format
# that YAML supports instead of the in-line format that we used up until now. These are exactly the same.
carriers:
electricity:
unit: MWh
color: "rgba(50, 94, 23, 0.7)"
h2:
unit: MWh
color: "rgba(3, 36, 252, 0.7)"
solar:
unit: MWh
color: "rgba(255, 196, 0, 0.7)"

components:
elec_grid:
type: Node
carrier: electricity

h2_storage:
type: Node
carrier: h2
has_state: true
state_cyclic: geq
state_lb: 0
state_ub: 50

# While core components need a unique name, it is allowed to use a name for a core component that is used by a
# carrier. While this is obviously NOT recommended, it is possible and can sometimes
solar:
type: Node
carrier: solar

plant_gas:
type: Unit
inputs: {h2: h2_storage}
outputs: {electricity: elec_grid}
conversion: 1 h2 -> 0.8 electricity
capacity: 10 out:electricity

plant_pv:
type: Unit
inputs: {solar: solar}
outputs: {electricity: elec_grid}
conversion: 1 solar -> 1 electricity
capacity: 5 out:electricity
availability_factor: [0.0, 0.0, 0.02, 0.07, 0.16, 0.26, 0.45, 0.66, 0.76, 0.88, 1.0, 1.0, 1.0, 0.95, 0.81, 0.66, 0.44, 0.26, 0.16, 0.06, 0.02, 0.01, 0.0, 0.0, 0.0, 0.01, 0.02, 0.06, 0.14, 0.26, 0.47, 0.63, 0.75, 0.88, 1.0, 1.0, 1.0, 1.0, 0.75, 0.61, 0.45, 0.25, 0.14, 0.07, 0.02, 0.0, 0.0, 0.0, 0.0, 0.01, 0.02, 0.07, 0.15, 0.26, 0.44, 0.61, 0.75, 1.0, 1.0, 1.0, 1.0, 0.88, 0.77, 0.65, 0.45, 0.27, 0.16, 0.07, 0.03, 0.01, 0.0, 0.0, 0.0, 0.01, 0.02, 0.07, 0.16, 0.3, 0.42, 0.59, 0.83, 0.88, 1.0, 1.0, 1.0, 0.9, 0.78, 0.57, 0.43, 0.28, 0.16, 0.06, 0.02, 0.0, 0.0, 0.0, 0.0, 0.0, 0.02, 0.06, 0.14, 0.26, 0.44, 0.57, 0.85, 0.96, 0.97, 1.0, 1.0, 1.0, 0.79, 0.64, 0.41, 0.26, 0.14, 0.07, 0.02, 0.0, 0.0, 0.0, 0.0, 0.0, 0.02, 0.07, 0.16, 0.3, 0.43, 0.63, 0.78, 0.9, 1.0, 1.0, 1.0, 0.91, 0.74, 0.58, 0.44, 0.28, 0.14, 0.07, 0.03, 0.0, 0.0, 0.0, 0.0, 0.0, 0.02, 0.07, 0.16, 0.28, 0.46, 0.66, 0.84, 0.9, 1.0, 1.0, 1.0, 0.97, 0.86, 0.63, 0.45, 0.27, 0.15, 0.06, 0.02, 0.0, 0.0, 0.0]

# Up until now we only ever restricted the output capacity. This time we cap the input capacity.
electrolyser:
type: Unit
inputs: {electricity: elec_grid}
outputs: {h2: h2_storage}
conversion: 1 electricity -> 0.7 h2
capacity: 10 in:electricity

# These profiles define a full "model boundary", allowing us to analyze the model easily afterwards.
create_solar:
type: Profile
mode: create
carrier: solar
node_to: solar

buy_h2:
type: Profile
mode: create
carrier: h2
node_to: h2_storage
cost: 100

demand:
type: Profile
carrier: electricity
node_from: elec_grid
value: [3.96, 4.24, 0.06, 3.36, 2.34, 0.22, 0.57, 4.41, 4.91, 3.01, 3.78, 4.36, 4.26, 2.2, 3.71, 4.35, 4.88, 2.25, 2.63, 2.15, 0.92, 4.18, 4.88, 2.85, 0.17, 2.48, 4.23, 4.72, 4.86, 1.46, 4.81, 1.94, 4.52, 4.77, 1.84, 1.27, 2.13, 4.15, 4.09, 1.16, 1.87, 2.18, 3.42, 3.7, 0.89, 0.93, 1.15, 2.62, 1.08, 1.72, 1.2, 0.06, 2.46, 4.73, 1.08, 0.41, 1.2, 0.53, 1.51, 2.59, 2.7, 4.83, 2.69, 0.51, 2.43, 3.2, 4.01, 0.21, 2.72, 1.5, 2.92, 2.51, 1.54, 2.63, 3.59, 4.86, 4.64, 4.88, 3.69, 3.64, 0.16, 3.4, 2.1, 3.87, 1.85, 3.6, 3.24, 3.61, 2.12, 0.43, 3.6, 3.94, 2.8, 0.78, 3.18, 3.05, 3.02, 4.14, 1.25, 3.05, 0.12, 3.54, 1.45, 1.53, 2.06, 0.23, 0.01, 3.47, 0.23, 3.21, 0.73, 3.33, 4.84, 0.89, 3.6, 4.87, 1.47, 3.48, 0.64, 2.77, 1.66, 2.79, 2.64, 4.73, 2.75, 0.44, 4.5, 2.7, 2.87, 1.76, 2.21, 2.48, 3.83, 3.81, 1.13, 2.53, 1.54, 1.32, 0.6, 4.25, 4.04, 2.23, 1.58, 4.9, 4.78, 2.85, 2.1, 0.2, 2.97, 2.26, 3.91, 0.68, 1.02, 1.61, 0.98, 4.5, 1.82, 2.41, 3.06, 3.05, 1.64, 0.03, 4.39, 3.03, 1.8, 0.37, 1.56, 2.17]
Loading

0 comments on commit d3ca200

Please sign in to comment.