How to model hydropower coupling

This how-to aims at demonstrating how we can model a hydropower system in Spine (SpineOpt.jl and Spine-Toolbox) with different assumptions and goals. It starts off by setting up a simple model of system of two hydropower plants and gradually introduces additional features.

Info

In each of the next sections, we perform incremental changes to the initial simple hydropower model. If you want to keep the database that you created, you can duplicate the database file (right-click on the input database and select Duplicate and duplicate files) and perform the changes in the new database. You need to configure the workflow accordingly in order to run the database you want (please check the Simple System tutorial for how to do that).

Note

Many of the figures here use the old pre-v1.0.0 input data structure! Thus, parameter names might differ slightly from the latest ones, and unit__node__node has been replaced with unit_flow__unit_flow.

Context

The goal of the model is to capture the combined operation of two hydropower plants (Språnget and Fallet) that operate on the same river as shown in the picture bellow. Each power plant has its own reservoir and generates electricity by discharging water. The plants might need to spill water, i.e., release water from their reservoirs without generating electricity, for various reasons. The water discharged or spilled by the upstream power plant follows the river route and becomes available to the downstream power plant.

A system of two hydropower plants.

Setting up a basic hydropower model

The picture below shows how such a system of hydropower plants translates to a SpineOpt model. It looks quite daunting at first glance, but we'll break it down in smaller parts in the following subsections.

Two hydropower plants in SpineOpt

The model of this section is available as the example file hydro_power_coupling.json. You can import it into an empty input database to compare it with the steps below.

Starting point

  1. Create a workflow in Spine Toolbox with an input database, a Run SpineOpt tool and an output database, as on the Verify installation page.
  2. Double-click the input database to open it in the Spine DB editor.
  3. Download the SpineOpt database template with the Download raw file button at the top right of the file view.
  4. Download the basic SpineOpt model in the same way.
  5. In the Spine DB editor, select File > Import... and import the downloaded files, first spineopt_template.json and then basic_model_template.json. The order matters: the basic model can only be imported once the classes of the SpineOpt template exist. The basic model contains the model simple, the temporal block flat, the deterministic stochastic structure and the report report1.
  6. Press Commit in the toolbar.

To enter a value, select its class in the Entity tree and fill in the entity byname, parameter name, alternative and value on the empty row of the Parameter value table. In the steps below, enter all values with the alternative Base. For values marked (drop-down), double-click the value cell and pick the value from the drop-down list. For values marked with a type, such as (Duration), right-click the value cell, select Edit... and choose that parameter type.

Note

In the Parameter value table, the first row is a filter row. Enter new values on the empty row below it.

Model

Before we can create the hydropower system, we'll have to define a model, temporal structure and stochastic structure. The basic model in the templates will do. Though, we'll change the temporal resolution to 6h and the model start / end to for 1 day as an example.

As for the report, we are typically interested in the outputs: node_state, unit_flows and connection_flows.

  1. In the Entity tree, select the model class and add the following values on the empty row of the Parameter value table:
groupclassentity bynameparameter namealternativevalue
modelsimplemodel_startBase2000-01-01T00:00:00 (Date time)
modelsimplemodel_endBase2000-01-02T00:00:00 (Date time)
  1. In the Entity tree, select the temporal_block class. The temporal block flat already has a resolution of 1D from the basic model. Right-click the value 1D, select Edit... and change it to 6h.
  2. Right-click the report__output class, select Add entities..., add report1 | node_state, report1 | unit_flow and report1 | connection_flow and press OK.
  3. Press Commit.

Nodes and grids

Nodes are at the center of a SpineOpt system, so let's start with that. There are other ways to model hydropower plants but here we represent each hydropower plant with 2 nodes, an 'upper' node to represent the water arriving at each plant and a 'lower' node to represent the water that is discharged and becomes available to the next plant. The general idea of splitting these in 2 nodes is to be able to simulate a time delay between the entrance and the exit (although in this tutorial we will not go in detail in this time delay).

Additionally we need a node for electricity.

Optionally, we can indicate that we are dealing with water flows and electricity production through grids. Note that grids are only indicative and are not strictly necessary. As in the picture below, we define a water and an electricity grid, and we connect these to the nodes with node__grid entities.

  1. Right-click the node class, select Add entities..., add sprang_upper, sprang_lower, fall_upper, fall_lower and electricity and press OK.
  2. Right-click the grid class and add water and electricity in the same way.
  3. Right-click the node__grid class and add sprang_upper | water, sprang_lower | water, fall_upper | water, fall_lower | water and electricity | electricity.

Two hydropower plants in SpineOpt

Flows by means of connections

We'll ensure a correct flow between the nodes through connections. The flows include:

  • local inflows in the reservoirs,
  • internal flows in the hydropower plants (between the 'upper' and 'lower' nodes),
  • the discharge flow that exits the Språnget hydropower plant at the lower node and flows to the upper node of the Fallet hydropower plant,
  • the spill flow that bypasses the Språnget hydropower plant at the upper node and flows to the upper node of the Fallet hydropower plant,
  • the discharge flow that exits the Fallet hydropower plant at the lower node and flows to the downstream river,
  • the spill flow that bypasses the Fallet hydropower plant at the upper node and flows to the downstream river.

For the local inflows in the reservoirs, we actually do not need a connection. Instead, we can model this as a negative demand in one of the nodes of the power plant. Here we use an inflow of 112 for Språnget and 2 for Fallet:

groupclassentity bynameparameter namealternativevalue
nodesprang_upperdemandBase-112.0
nodefall_upperdemandBase-2.0

The flow within each hydropower plant, i.e. the discharge flow between the 'upper' and the 'lower' node to generate the electricity, will also not be handled by the connection but by the units. In fact, anything that happens between the 'upper' and 'lower' nodes will be handled by the units.

For each of the remaining flows we create a connection entity. These connections need to be connected to nodes to function properly. To that end we'll use the connection__from_node. As the name suggests, we connect the connection to the node where the flow comes from, e.g. the 'lower' node of the Språnget hydropower plant to the connection between the 'lower' node of the Språnget and the 'upper' node of the Fallet hydropower plant.

The two connections that bring water to the Fallet hydropower plant also need a connection__to_node to the 'upper' node of the Fallet hydropower plant. Without it, the water from Språnget cannot reach Fallet, and SpineOpt stops with an error when building the model. The two connections to the downstream river only need the connection__from_node, as the water leaves the modelled system there.

As the flows are unbound by default, we also need to define the relation between the nodes and the flows with the connection__node__node entities. We need one between the 'upper' node of the Språnget hydropower plant and the 'upper' node of the Fallet hydropower plant for the corresponding spill connection. We also need one between the 'lower' node of the Språnget hydropower plant and the 'upper' node of the Fallet hydropower plant for the corresponding discharge connection. We bind the flows by setting the fix_ratio_out_in_connection_flow to 1.0, i.e. all the water that enters the connection also leaves it.

  1. In the Entity tree, select the node class and enter the inflows above.
  2. Right-click the connection class and add sprang_to_fall_spill, sprang_to_fall_disc, fall_to_downstream_spill and fall_to_downstream_disc.
  3. Right-click the connection__from_node class and add sprang_to_fall_spill | sprang_upper, sprang_to_fall_disc | sprang_lower, fall_to_downstream_spill | fall_upper and fall_to_downstream_disc | fall_lower.

connection__from_node

  1. Right-click the connection__to_node class and add sprang_to_fall_spill | fall_upper and sprang_to_fall_disc | fall_upper.
  2. Right-click the connection__node__node class and add sprang_to_fall_spill | fall_upper | sprang_upper and sprang_to_fall_disc | fall_upper | sprang_lower. The first node is the one where the flow goes and the second the one where it comes from.

connection__node_node

  1. In the Entity tree, select the connection__node__node class, enter the following values and press Commit:
groupclassentity bynameparameter namealternativevalue
connection__node__nodesprang_to_fall_disc ǀ fall_upper ǀ sprang_lowerfix_ratio_out_in_connection_flowBase1.0
connection__node__nodesprang_to_fall_spill ǀ fall_upper ǀ sprang_upperfix_ratio_out_in_connection_flowBase1.0

Energy conversion by means of units

Each hydropower plant uses a unit to convert the flow of water to electricity. These units are connected to the 'upper' and 'lower' nodes of the hydropower plants and the 'electricity' node. Water enters the 'upper' node, so the 'upper' node is connected to the unit through the node__to_unit. Water is then discharged, so the 'lower' node is connected to the unit through the unit__to_node. As the water discharges, electricity is produced, so the 'electricity' node is also connected to the unit through the unit__to_node.

Additionally, we add a unit to represent the income from selling the electricity production in the electricity market. The electricity price will be represented by a negative variable operation and maintenance (VOM) cost on the node__to_unit between the electricity node and the unit.

  1. Right-click the unit class and add sprang_plant, fall_plant and electricity_load.
  2. Right-click the node__to_unit class and add sprang_upper | sprang_plant, fall_upper | fall_plant and electricity | electricity_load.
  3. Right-click the unit__to_node class and add sprang_plant | sprang_lower, sprang_plant | electricity, fall_plant | fall_lower and fall_plant | electricity.

units

Again, by default the flows are unbound, so we have to bind them with unit_flow__unit_flow entities. The discharge flow from the 'upper' node flows in its entirety to the 'lower' node, so the flow_ratio_equality_coefficient between the 'lower' and the 'upper' node is 1.0. For the conversion from water flow to electricity, we need to take the conversion efficiency of the plant into account: the flow_ratio_equality_coefficient between the 'electricity' and the 'upper' node is 0.6 for the Språnget hydropower plant and 0.68 for the Fallet hydropower plant.

  1. Right-click the unit_flow__unit_flow class, select Add entities... and choose the unit, its output flow and its input flow, resulting in sprang_plant | sprang_lower | sprang_upper | sprang_plant, sprang_plant | electricity | sprang_upper | sprang_plant, fall_plant | fall_lower | fall_upper | fall_plant and fall_plant | electricity | fall_upper | fall_plant.
  2. Enter the following values and press Commit. Select the class of each row in the Entity tree before entering its values. The capacities limit the water flow into the units and the electricity production.
groupclassentity bynameparameter namealternativevalue
node__to_unitsprang_upper ǀ sprang_plantcapacity_per_unitBase115.0
node__to_unitfall_upper ǀ fall_plantcapacity_per_unitBase165.0
node__to_unitelectricity ǀ electricity_loadvom_costBasesee below (Time series fixed resolution)
unit__to_nodesprang_plant ǀ electricitycapacity_per_unitBase69.0
unit__to_nodefall_plant ǀ electricitycapacity_per_unitBase112.2
unit_flow__unit_flowsprang_plant ǀ sprang_lower ǀ sprang_upper ǀ sprang_plantflow_ratio_equality_coefficientBase1.0
unit_flow__unit_flowsprang_plant ǀ electricity ǀ sprang_upper ǀ sprang_plantflow_ratio_equality_coefficientBase0.6
unit_flow__unit_flowfall_plant ǀ fall_lower ǀ fall_upper ǀ fall_plantflow_ratio_equality_coefficientBase1.0
unit_flow__unit_flowfall_plant ǀ electricity ǀ fall_upper ǀ fall_plantflow_ratio_equality_coefficientBase0.68

For the electricity price, set the start time to 2000-01-01T00:00:00 and the resolution to 6h in the Edit value dialog, and enter the following values. Any (negative) values are fine, but these give the results shown at the end of this section.

tvalue
2000-01-01T00:00:00-325.0
2000-01-01T06:00:00-250.0
2000-01-01T12:00:00-425.0
2000-01-01T18:00:00-400.0

Storage in nodes

To model the reservoirs of each hydropower plant, we leverage the node_state variable to represent storage capability. We only need to do this for one of the two nodes that we have used to model each plant and we choose the upper level node. To activate the storage functionality of a node, we set the value of the parameter storage_active as true. Then, we need to set the capacity of the reservoir by setting the storage_state_max parameter value.

Depending on the constraints of your hydropower plant, you can also fix the initial and final values of the reservoir by setting the parameter storage_state_fix to the respective values (use nan values for the time steps that you don't want to impose such constraints). When fixing the initial value of a reservoir value, the value should be fixed at ‘t-1’ instead of ’t0’. That is because the initial value of a reservoir means the previous value before the first hour. With the 6h resolution, the initial value is therefore set at 1999-12-31T18:00:00, one time step before the model_start, and the final value at 2000-01-01T18:00:00, the start of the last time step.

  1. In the Entity tree, select the node class and enter the following values:
groupclassentity bynameparameter namealternativevalue
nodesprang_upperstorage_activeBasetrue
nodesprang_upperstorage_state_maxBase3600.0
nodesprang_upperstorage_state_fixBasesee below (Time series variable resolution)
nodefall_upperstorage_activeBasetrue
nodefall_upperstorage_state_maxBase3900.0
nodefall_upperstorage_state_fixBasesee below (Time series variable resolution)
  1. For storage_state_fix, enter the following rows in the Edit value dialog:
tsprang_upperfall_upper
1999-12-31T18:00:001000.01200.0
2000-01-01T00:00:00nannan
2000-01-01T06:00:00nannan
2000-01-01T12:00:00nannan
2000-01-01T18:00:001722.27768.0
  1. Press Commit.

Examining the results

At this point the model should be ready to run.

  1. Run the SpineOpt tool.
  2. Double-click the output database to open it in the Spine DB editor.
  3. Press the Index button in the toolbar to show the results in a pivot table.
  4. In the Entity tree, select report__unit__node__direction__stochastic_scenario for the unit_flow results.
  5. Under alternative in the Frozen table, pick the latest run ("Run SpineOpt@..."). Each run is saved as its own alternative.

You should get the following unit_flow results. The from_node flows of the plants are the water they discharge, the to_node flows to electricity their electricity production, and the flow from electricity to electricity_load the total electricity production.

reportunitnodedirectionstochastic_scenarioindexunit_flow
report1electricity_loadelectricityfrom_noderealization2000-01-01T00:00:00111.36
report1electricity_loadelectricityfrom_noderealization2000-01-01T06:00:000
report1electricity_loadelectricityfrom_noderealization2000-01-01T12:00:00181.2
report1electricity_loadelectricityfrom_noderealization2000-01-01T18:00:00181.2
report1fall_plantelectricityto_noderealization2000-01-01T00:00:0052.78
report1fall_plantelectricityto_noderealization2000-01-01T06:00:000
report1fall_plantelectricityto_noderealization2000-01-01T12:00:00112.2
report1fall_plantelectricityto_noderealization2000-01-01T18:00:00112.2
report1fall_plantfall_lowerto_noderealization2000-01-01T00:00:0077.62
report1fall_plantfall_lowerto_noderealization2000-01-01T06:00:000
report1fall_plantfall_lowerto_noderealization2000-01-01T12:00:00165
report1fall_plantfall_lowerto_noderealization2000-01-01T18:00:00165
report1fall_plantfall_upperfrom_noderealization2000-01-01T00:00:0077.62
report1fall_plantfall_upperfrom_noderealization2000-01-01T06:00:000
report1fall_plantfall_upperfrom_noderealization2000-01-01T12:00:00165
report1fall_plantfall_upperfrom_noderealization2000-01-01T18:00:00165
report1sprang_plantelectricityto_noderealization2000-01-01T00:00:0058.57
report1sprang_plantelectricityto_noderealization2000-01-01T06:00:000
report1sprang_plantelectricityto_noderealization2000-01-01T12:00:0069
report1sprang_plantelectricityto_noderealization2000-01-01T18:00:0069
report1sprang_plantsprang_lowerto_noderealization2000-01-01T00:00:0097.62
report1sprang_plantsprang_lowerto_noderealization2000-01-01T06:00:000
report1sprang_plantsprang_lowerto_noderealization2000-01-01T12:00:00115
report1sprang_plantsprang_lowerto_noderealization2000-01-01T18:00:00115
report1sprang_plantsprang_upperfrom_noderealization2000-01-01T00:00:0097.62
report1sprang_plantsprang_upperfrom_noderealization2000-01-01T06:00:000
report1sprang_plantsprang_upperfrom_noderealization2000-01-01T12:00:00115
report1sprang_plantsprang_upperfrom_noderealization2000-01-01T18:00:00115

For the reservoir levels, select report__node__stochastic_scenario in the Entity tree. You should get the following node_state results:

reportnodestochastic_scenarioindexnode_state
report1fall_upperrealization2000-01-01T00:00:001332
report1fall_upperrealization2000-01-01T06:00:001344
report1fall_upperrealization2000-01-01T12:00:001056
report1fall_upperrealization2000-01-01T18:00:00768
report1sprang_upperrealization2000-01-01T00:00:001086.27
report1sprang_upperrealization2000-01-01T06:00:001758.27
report1sprang_upperrealization2000-01-01T12:00:001740.27
report1sprang_upperrealization2000-01-01T18:00:001722.27

The plants produce at full capacity in the two most expensive time steps (prices 425 and 400) and save water in the cheapest one (price 250). The rest of the water is used in the first time step so that the reservoirs reach their fixed final values. The connection_flow results show the same water flows between the plants and to the downstream river.

Maximisation of Stored Water

Instead of fixing the water content of the reservoirs at the end of the planning period, we can consider that the remaining water in the reservoirs has a value and then maximize the value along with the revenues for producing electricity within the planning horizon. This objective term is often called the Value of stored water and we can approximate it by assuming that this water will be used to generate electricity in the future that would be sold at a forecasted price. The water stored in the upstream hydropower plant will become also available to the downstream plant and this should be taken into account.

Changes to the basic model

Start from the basic model of the previous section. If you want to keep it, duplicate the database first, as explained at the top of this page. If you don't have the basic model anymore, import hydro_power_coupling.json into an empty input database.

  1. Right-click the node class and add stored_water. This node will accumulate the water stored in the reservoirs at the end of the planning horizon.
  2. Right-click the node__grid class and add stored_water | water.
  3. Right-click the unit class and add sprang_stored_water, fall_stored_water and value_stored_water. The first two transfer the water left in the reservoirs to the stored_water node, and the third one is a sink that introduces the value of stored water in the objective function.
  4. Right-click the node__to_unit class and add stored_water | value_stored_water, sprang_upper | sprang_stored_water and fall_upper | fall_stored_water.
  5. Right-click the unit__to_node class and add sprang_stored_water | stored_water and fall_stored_water | stored_water.
  6. Right-click the unit_flow__unit_flow class and add sprang_stored_water | stored_water | sprang_upper | sprang_stored_water and fall_stored_water | stored_water | fall_upper | fall_stored_water.
  7. Extend the planning horizon of the model by one time step: in the Entity tree, select the model class and change the value of model_end to 2000-01-02T06:00:00.
  8. Remove the final values of the reservoirs: in the Entity tree, select the node class. In the Parameter value table, right-click the value of storage_state_fix of sprang_upper, select Edit..., select the last row (2000-01-01T18:00:00), right-click, select Remove rows and press OK. Do the same for fall_upper. The initial values stay.
  9. In the Entity tree, select the node__to_unit class. Right-click the value of vom_cost of electricity ǀ electricity_load, select Edit... and add a fifth value, 0.0, for the extra time step. The price is set to zero to ensure no electricity is sold during this time step.
  10. Enter the following values and press Commit. Select the class of each row in the Entity tree before entering its values:
groupclassentity bynameparameter namealternativevalue
node__to_unitstored_water ǀ value_stored_watervom_costBasesee below (Time series fixed resolution)
unit_flow__unit_flowsprang_stored_water ǀ stored_water ǀ sprang_upper ǀ sprang_stored_waterflow_ratio_equality_coefficientBase1.28
unit_flow__unit_flowfall_stored_water ǀ stored_water ǀ fall_upper ǀ fall_stored_waterflow_ratio_equality_coefficientBase0.68

For the vom_cost of value_stored_water, set the start time to 2000-01-01T00:00:00 and the resolution to 6h. We impose a zero cost for the original planning horizon and use an assumed future electricity price for the extra time step at the end of the horizon:

tvalue
2000-01-01T00:00:000.0
2000-01-01T06:00:000.0
2000-01-01T12:00:000.0
2000-01-01T18:00:000.0
2000-01-02T00:00:00-400.0

The efficiency of fall_stored_water is the same as that of fall_plant, as the water in Fallet's reservoir will be used to produce electricity by the Fallet plant only. On the other hand, the water from Språnget's reservoir will be used both by the Språnget and the Fallet plant, therefore we use the sum of the two efficiencies (0.6 + 0.68 = 1.28) for sprang_stored_water.

Examining the results

The model of this section is available as the example file hydro_power_coupling_stored_water.json. Run the model and open the results as in the basic model. You should get the following unit_flow results. To show only these rows, select only electricity_load, fall_plant and sprang_plant in the unit column header and only from_node in the direction column header:

reportunitnodedirectionstochastic_scenarioindexunit_flow
report1electricity_loadelectricityfrom_noderealization2000-01-01T00:00:000
report1electricity_loadelectricityfrom_noderealization2000-01-01T06:00:000
report1electricity_loadelectricityfrom_noderealization2000-01-01T12:00:00181.2
report1electricity_loadelectricityfrom_noderealization2000-01-01T18:00:00107.44
report1electricity_loadelectricityfrom_noderealization2000-01-02T00:00:000
report1fall_plantfall_upperfrom_noderealization2000-01-01T00:00:000
report1fall_plantfall_upperfrom_noderealization2000-01-01T06:00:000
report1fall_plantfall_upperfrom_noderealization2000-01-01T12:00:00165
report1fall_plantfall_upperfrom_noderealization2000-01-01T18:00:00158
report1fall_plantfall_upperfrom_noderealization2000-01-02T00:00:000
report1sprang_plantsprang_upperfrom_noderealization2000-01-01T00:00:000
report1sprang_plantsprang_upperfrom_noderealization2000-01-01T06:00:000
report1sprang_plantsprang_upperfrom_noderealization2000-01-01T12:00:00115
report1sprang_plantsprang_upperfrom_noderealization2000-01-01T18:00:000
report1sprang_plantsprang_upperfrom_noderealization2000-01-02T00:00:000

And the following node_state results:

reportnodestochastic_scenarioindexnode_state
report1fall_upperrealization2000-01-01T00:00:001212
report1fall_upperrealization2000-01-01T06:00:001224
report1fall_upperrealization2000-01-01T12:00:00936
report1fall_upperrealization2000-01-01T18:00:000
report1fall_upperrealization2000-01-02T00:00:000
report1sprang_upperrealization2000-01-01T00:00:001672
report1sprang_upperrealization2000-01-01T06:00:002344
report1sprang_upperrealization2000-01-01T12:00:002326
report1sprang_upperrealization2000-01-01T18:00:002998
report1sprang_upperrealization2000-01-02T00:00:000

The plants no longer produce in the first two time steps, as the stored water is worth more than the electricity sold at the prices 325 and 250. For example, water stored in Språnget is valued at 1.28 × 400 = 512, as it can later be used by both plants. In the extra time step (2000-01-02T00:00:00), all the remaining water is moved to the stored_water node and the reservoirs are emptied.

At 18:00, the electricity price (400) is equal to the assumed future electricity price, so selling and storing the water give the same value. Therefore, your results for 18:00 and the extra time step may differ from the ones above, while the objective value stays the same. The results from 00:00 to 12:00 should be the same.

As an exercise, try to retrieve the value of stored water as it is calculated by the model.

Spillage Constraints - Minimisation of Spilt Water

It might be the case that we need to impose certain limits to the amount of water that is spilt on each time step of the planning horizon, e.g., for environmental reasons, there can be a minimum and a maximum spillage level. At the same time, to avoid wasting water that could be used for producing electricity, we could explicitly impose the spillage minimisation to be added in the objective function.

Changes to the basic model

Start from the basic model, not from the stored water model. If you want to keep it, duplicate the database first, as explained at the top of this page. If you don't have the basic model anymore, import hydro_power_coupling.json into an empty input database. Here we replace the spill connection of Språnget with a unit, sprang_spill, which can limit and penalise the spilt water.

  1. In the Entity tree, expand the connection class, right-click sprang_to_fall_spill and select Remove.... Its connection__from_node, connection__to_node and connection__node__node entities are removed with it.
  2. Right-click the unit class and add sprang_spill.
  3. Right-click the node__to_unit class and add sprang_upper | sprang_spill.
  4. Right-click the unit__to_node class and add sprang_spill | fall_upper.
  5. Right-click the unit_flow__unit_flow class and add sprang_spill | fall_upper | sprang_upper | sprang_spill.
  6. Enter the following values and press Commit. Select the class of each row in the Entity tree before entering its values:
groupclassentity bynameparameter namealternativevalue
node__to_unitsprang_upper ǀ sprang_spillcapacity_per_unitBase1000.0
node__to_unitsprang_upper ǀ sprang_spillminimum_operating_pointBase0.001
node__to_unitsprang_upper ǀ sprang_spillvom_costBase1000.0
unitsprang_spillonline_variable_typeBasenone (drop-down)
unit_flow__unit_flowsprang_spill ǀ fall_upper ǀ sprang_upper ǀ sprang_spillflow_ratio_equality_coefficientBase1.0

What the values do:

  • capacity_per_unit 1000: the maximum spillage.
  • minimum_operating_point 0.001: the minimum spillage as a fraction of the capacity, i.e. 0.001 × 1000 = 1.
  • vom_cost 1000: a penalty for the spilt water, so that water is not spilt unnecessarily.
  • online_variable_type none: the minimum operating point applies only when the unit is online. With the default type linear, the model can avoid the minimum spillage by taking the unit offline. With none, the unit is always online.
  • flow_ratio_equality_coefficient 1: all the spilt water reaches Fallet.

Examining the results

The model of this section is available as the example file hydro_power_coupling_spillage.json. Run the model and open the results as in the basic model. You should get the following unit_flow results. To show only these rows, select only electricity_load, sprang_plant and sprang_spill in the unit column header. The results of fall_plant are the same as in the basic model.

reportunitnodedirectionstochastic_scenarioindexunit_flow
report1electricity_loadelectricityfrom_noderealization2000-01-01T00:00:00108.96
report1electricity_loadelectricityfrom_noderealization2000-01-01T06:00:000
report1electricity_loadelectricityfrom_noderealization2000-01-01T12:00:00181.2
report1electricity_loadelectricityfrom_noderealization2000-01-01T18:00:00181.2
report1sprang_plantelectricityto_noderealization2000-01-01T00:00:0056.17
report1sprang_plantelectricityto_noderealization2000-01-01T06:00:000
report1sprang_plantelectricityto_noderealization2000-01-01T12:00:0069
report1sprang_plantelectricityto_noderealization2000-01-01T18:00:0069
report1sprang_plantsprang_lowerto_noderealization2000-01-01T00:00:0093.62
report1sprang_plantsprang_lowerto_noderealization2000-01-01T06:00:000
report1sprang_plantsprang_lowerto_noderealization2000-01-01T12:00:00115
report1sprang_plantsprang_lowerto_noderealization2000-01-01T18:00:00115
report1sprang_plantsprang_upperfrom_noderealization2000-01-01T00:00:0093.62
report1sprang_plantsprang_upperfrom_noderealization2000-01-01T06:00:000
report1sprang_plantsprang_upperfrom_noderealization2000-01-01T12:00:00115
report1sprang_plantsprang_upperfrom_noderealization2000-01-01T18:00:00115
report1sprang_spillfall_upperto_noderealization2000-01-01T00:00:001
report1sprang_spillfall_upperto_noderealization2000-01-01T06:00:001
report1sprang_spillfall_upperto_noderealization2000-01-01T12:00:001
report1sprang_spillfall_upperto_noderealization2000-01-01T18:00:001
report1sprang_spillsprang_upperfrom_noderealization2000-01-01T00:00:001
report1sprang_spillsprang_upperfrom_noderealization2000-01-01T06:00:001
report1sprang_spillsprang_upperfrom_noderealization2000-01-01T12:00:001
report1sprang_spillsprang_upperfrom_noderealization2000-01-01T18:00:001

And the following node_state results:

reportnodestochastic_scenarioindexnode_state
report1fall_upperrealization2000-01-01T00:00:001314
report1fall_upperrealization2000-01-01T06:00:001332
report1fall_upperrealization2000-01-01T12:00:001050
report1fall_upperrealization2000-01-01T18:00:00768
report1sprang_upperrealization2000-01-01T00:00:001104.27
report1sprang_upperrealization2000-01-01T06:00:001770.27
report1sprang_upperrealization2000-01-01T12:00:001746.27
report1sprang_upperrealization2000-01-01T18:00:001722.27

Due to the spillage penalty, the spillage stays at its minimum of 1. Compared with the basic model, Språnget discharges less in the first time step (93.62 instead of 97.62), as the spilt water also reaches Fallet and the reservoirs still have to reach the same final values.

As an exercise, you can perform this process for the Fallet plant (you would also need to add another water node, downstream of Fallet).

Follow Contracted Load Curve

It is often the case that a system of hydropower plants should follow a given production profile. To model this in the given system, all we have to do is set a demand in the form of a timeseries to the electricity node.