{ "cells": [ { "cell_type": "markdown", "id": "fa98ee2b", "metadata": {}, "source": [ "(reservoir)=\n", "# reservoir\n", "A reservoir that is part of a regulated hydropower watercourse\n", "\n", "| | |\n", "|---|---|\n", "|Input connections|{ref}`plant`, {ref}`gate`, {ref}`junction`, {ref}`volume_constraint`, {ref}`cut_group`, {ref}`inflow_series`, {ref}`tunnel`, {ref}`river`|\n", "|Output connections|{ref}`plant`, {ref}`river`, {ref}`gate`, {ref}`tunnel`, {ref}`cut_group`, {ref}`inflow_series`, {ref}`junction_gate`, {ref}`junction`, {ref}`creek_intake`, {ref}`volume_constraint`|\n", "|License|SHOP_OPEN|\n", "|Release version|13.0.0.a|\n", "\n", "```{contents}\n", ":local:\n", ":depth: 1\n", "```\n", "\n", "\n", "\n", "## Required input \n", "The reservoir object is one of the fundamental building blocks of a SHOP model, and has the following mandatory input attributes:\n", "- [max_vol](reservoir:max_vol): Maximum volume of the reservoir at the point of forced overflow.\n", "- [lrl](reservoir:lrl): Lowest regulated level, should correspond to zero volume stored.\n", "- [hrl](reservoir:hrl): Highest regulated level, should correspond to max_vol volume stored.\n", "- [vol_head](reservoir:vol_head): The relation between reservoir volume and level (masl).\n", "- [start_head](reservoir:start_head) / [start_vol](reservoir:start_vol): The reservoir level at the beginning of the optimisation, either given in masl or Mm3.\n", "\n", "## Volume and level\n", "The relation between volume and level is required and given by the [vol_head](reservoir:vol_head) attribute, which is a piecewise linear [XY-curve](datatype:xy). The vol_head curve should go above the point (max_vol, hrl) to describe overflow situations. The total reservoir volume before forced overflow is given by [max_vol](reservoir:max_vol). The [max_vol](reservoir:max_vol) attribute can either represent only the active volume or the full volume of the reservoir. If only the active volume is considered, [lrl](reservoir:lrl) will coincide with zero volume.\n", "\n", "\n", "## Reservoir level limit constraints\n", "The user can specify different types of reservoir limits to enforce correct physical behaviour and to enforce different physical and environmental restrictions. Figure 1 illustrates the available reservoir level limits and Table 1 gives an overview of their related inputs and outputs. \n", "\n", "||\n", "|---|\n", "|Figure 1: Overview of reservoir limit types.|\n", "\n", "|Attribute|Constraint type|Penalty input|Penalty output|Objective|\n", "|---|---|---|---|---|\n", "|[flow_descr](reservoir:flow_descr) \\[meter\\]||[overflow_cost](reservoir:overflow_cost)||[nonphysical_spill_cost](objective:nonphysical_spill_cost), [physical_spill_cost](objective:physical_spill_cost)|\n", "|[max_vol](reservoir:max_vol),[hrl](reservoir:hrl)|soft|[penalty_cost](penalty_cost)|[penalty](reservoir:penalty), [endpoint_penalty](reservoir:endpoint_penalty)|[rsv_penalty](objective:rsv_penalty), [rsv_end_penalty](objective:rsv_end_penalty)|\n", "|[max_vol_constr](reservoir:max_vol_constr)|hard|||||\n", "|[tactical_limit_max](reservoir:tactical_limit_max)|soft|[tactical_cost_max](reservoir:tactical_cost_max)|[tactical_penalty_up](reservoir:tactical_penalty_up), [tactical_penalty](reservoir:tactical_penalty)|[rsv_tactical_penalty](objective:rsv_tactical_penalty)|\n", "|[tactical_limit_min](reservoir:tactical_limit_min)|soft|[tactical_cost_min](reservoir:tactical_cost_min)|[tactical_penalty_down](reservoir:tactical_penalty_down), [tactical_penalty](reservoir:tactical_penalty)|[rsv_tactical_penalty](objective:rsv_tactical_penalty)|\n", "|[min_vol_constr](reservoir:min_vol_constr)|hard|||||\n", "|[lrl](reservoir:lrl)|soft|[penalty_cost](penalty_cost)|[penalty](reservoir:penalty), [endpoint_penalty](reservoir:endpoint_penalty), [end_penalty](reservoir:end_penalty)|[rsv_penalty](objective:rsv_penalty), [rsv_end_penalty](objective:rsv_end_penalty)|\n", "\n", "The outer limits are typically [max_vol](reservoir:max_vol), [hrl](reservoir:hrl) and [lrl](reservoir:lrl), which represent the physical limts the system is designed for and regulated to operate within. These are soft constraints, allowing SHOP to provide a solution even in situations where the input is overspecified so that no physical solution exist. In this case, a penalty will be applied. \n", "\n", "The [min_vol_constr](reservoir:min_vol_constr) and [max_vol_constr](reservoir:max_vol_constr) are time dependent operation constraints. These can, for example, be used if the system must be operated within given limits due to maintenance. However, hard constraints should be used carefully since they may cause infeasibility or non-physical behaviour in other parts of the system.\n", "\n", "The tactical limits, [tactical_limit_min](reservoir:tactical_limit_min) and [tactical_limit_max](reservoir:tactical_limit_max), let the user specify time dependent soft constraints at a time dependent self defined cost.\n", "\n", "Additionally, the reservoir level can be constrained by ramping constraints, such as [level_ramping_up](reservoir:level_ramping_up), [level_ramping_down](reservoir:level_ramping_down), and the [dynamic_level_limit](reservoir:dynamic_level_limit) constraint. \n", "\n", "\n", "## Overflow\n", "In reservoirs where overflow may occur, the [vol_head](reservoir:vol_head) curve must also contain the relevant space above the [hrl](reservoir:hrl) and max_vol. To ensure that the spilled water is directed to the right reservoir and assigned a reasonable penalty cost, the reservoir object should be connected to a [](river), with the river [](river:upstream_elevation) equal to the reservoir hrl. The overflow rate as a function of the reservoir level is then described by the [up_head_flow_curve](river:up_head_flow_curve), and an overflow penalty can be given by setting the river [flow_cost](river:flow_cost). The river can be connected to a downstream reservoir if the spillage should be directed there instead of to the ocean. This is described in more detail in the [overflow example](reservoir-overflow).\n", "\n", "Previously, the {ref}`gate` object has been used for overflow modelling. Gate objects will be removed in SHOP 19 (2027 Q2), and so using rivers is the recommended way for future compatibility. To model overflow using gates, the upstream reservoir has to been connected to the gate using connection type **SPILL**. Overflow is described by the [flow_descr](reservoir:flow_descr) [XY-curve](datatype:xy), where the x-values represents reservoir levels and the y-values are the overflow rates in $m^3/s$. The first xy pair must be [hrl](reservoir:hrl) and zero, meaning that there is no overflow at [hrl](reservoir:hrl). The following xy pairs must have increasing x and y values.\n", "\n", "### Physical overflow description\n", "The overflow description is a linear relaxation, hence overflow may occur in situations where it is not physically possible. SHOP includes a MIP formulation that can be used to prevent this, which can be activated using the river [mip_flag](river:mip_flag), reservoir [overflow_mip_flag](reservoir:overflow_mip_flag), or [universal_overflow_mip](global_settings:universal_overflow_mip). See the [overflow modelling example](reservoir-overflow) for further details.\n", "\n", "\n", "## Water values\n", "The value of stored water beyond the optimization horizon will typically come from a seasonal- or long-term model. Details on how to set the water values can be found [here](water-value-descriptions). Se also the [individual water values example](individual-water-values).\n", "\n", "### Reservoir schedule, slack and cut descriptions\n", "Reservoir [schedule](reservoir:schedule) can be used instead of water values to impose a specific strategy on a reservoir. Since this limits the way the system can be operated, it should be used very carefully. A schedule can be set either for the end value or for specific moments throughout the optimization period. The reservoir [upper_slack](reservoir:upper_slack) and [lower_slack](reservoir:lower_slack) limits can be used in combination with a reservoir schedule. When upper_slack and/or lower_slack is used together with a schedule, the reservoir trajectory is bound to be within the upper_slack and lower_slack values. If only one of the slack parameters are given, the reservoir schedule will act as the missing upper/lower bound.\n", "\n", "For further details on the use of reservoir schedule see the [reservoir schedule example](reservoir-schedule).\n", "\n", "## Ramping\n", "Ramping constraints limit how rapidly the volume or head of a reservoir can change over time, for example, to avoid excessive wear of the reservoir shores. Ramping constraints can be set individually for the up and down direction. They can be set in terms of volume with [volume_ramping_up](reservoir:volume_ramping_up) and [volume_ramping_down](reservoir:volume_ramping_down), or in terms of level with [level_ramping_up](reservoir:level_ramping_up) and [level_ramping_down](reservoir:level_ramping_down). \n", "\n", "Other ramping constraint types include [level_amplitude_ramping_limit_up](reservoir:level_amplitude_ramping_limit_up), [level_amplitude_ramping_limit_down](reservoir:level_amplitude_ramping_limit_down), [level_nonseq_ramping_limit_up](reservoir:level_nonseq_ramping_limit_up) and [level_nonseq_ramping_limit_down](reservoir:level_nonseq_ramping_limit_down), demonstrated in the [amplitude and non-sequential ramping example](reservoir-amplitude-nonseq-ramping). Complex ramping is demonstrated in the [complex ramping on reservoir level example](reservoir-complex-ramping). The complex ramping types include [limit_level_period_ramping_up](reservoir:limit_level_period_ramping_up), [limit_level_period_ramping_down](reservoir:limit_level_period_ramping_down), [average_level_rolling_ramping_up](reservoir:average_level_rolling_ramping_up) and [average_level_rolling_ramping_down](reservoir:average_level_rolling_ramping_down). The [dynamic_level_limit](reservoir:dynamic_level_limit) constraint is similar to the limit period level ramping, except the difference in reservoir level is found within the same time period instead of between consecutive time periods. See the\n", "[reservoir dynamic level limit example](reservoir-dynamic-level-limit) for more information about this constraint.\n", "\n", "## Examples\n", " - [](cut-description)\n", " - [](water-value-descriptions)\n", " - [](individual-water-values)\n", " - [](ramping)\n", " - [](reservoir-overflow)\n", " - [](reservoir-schedule)\n", " - [](reservoir-complex-ramping)\n", " - [](creek-intake-example)\n", " - [](reservoir-dynamic-level-limit)\n", " - [](reservoir-amplitude-nonseq-ramping)\n", " \n", "\n", "## References\n", " - Modelling overflow using mixed integer programming in short-term hydropower scheduling {cite}`Litlabo2023`\n", " \n", "\n", "## Attributes" ] }, { "cell_type": "code", "execution_count": 1, "id": "34a8139b", "metadata": { "tags": [ "remove-input", "full-width" ] }, "outputs": [ { "data": { "text/html": [ "