Basic Single Reservoir

This example shows how to build a simple single reservoir model.

File Structure

The file structure looks as follows:

<base_dir>
│   <model_file>.py
├───input
│   ├───(plot_table.csv)
│   └───rtcDataConfig.xml
│   └───rtcParameterConfig.xml
│   └───timeseries_import.xml
├───lookup_tables
│   ├───lookup_tables.csv
│   ├───(<data1>.csv)
│   ├───(<data2>.csv)
│   └───(<data3>.csv)
└───output

The <base_dir> is the base directory that contains all files to run the model. It consists of the following files and folders.

  • <model_file>.py: main model file that describes all the schemes for controlling the reservoir flow.

  • input: directory containing all parameters and external input data.

    • plot_table.csv (optional): file that describes how the output should be visualised.

    • rtcParameterConfig.xml: file that contains the model parameters.

    • timeseries_import.xml: file with all input timeseries and initial conditions.

    • rtcDataConfig.xml: file that contains the mappings for input/output timeseries (from FEWS) and internal model variables.

  • lookup_tables: directory that contains all data for lookup tables.

    • lookup_tables.csv: file that describes all lookup tables.

    • ***.csv: data files that contain data for generating lookup tables.

Each of these files will be described in more detail in the following sections.

Creating Template Files

Using the command rtc-tools-reservoir-template -d <base_dir> -n <reservoir_name> from the command line will create a directory <base_dir> with template files for a reservoir model called <reservoir_name>. The directory <base_dir> will be created in the current working directory and will contain a file structure as described above. The generated source file and data files are all template files that need to be completed by the user.

Main Model File

An example of the main model file <model_file>.py is given below.

 1"""Example that illustrates how to create a basic model."""
 2
 3from pathlib import Path
 4
 5from rtctools.util import run_simulation_problem
 6
 7from rtctools_simulation.reservoir.model import InputVar, ModelConfig, ReservoirModel
 8
 9CONFIG = ModelConfig(base_dir=Path(__file__).parent)
10
11
12class SingleReservoir(ReservoirModel):
13    """Example single reservoir model."""
14
15    def apply_schemes(self):
16        """Apply schemes for controlling the reservoir."""
17
18        # Get current time.
19        datetime = self.get_current_datetime()
20        # Apply schemes.
21        h = self.get_var("H")
22        h_crest = self.get_var("H_crest")
23        self.include_rainevap()
24        if h > h_crest:
25            april = 4
26            september = 9
27            if april <= datetime.month <= september:
28                self.set_q(
29                    target_variable=InputVar.Q_OUT,
30                    input_type="parameter",
31                    input_data=0.4,
32                )
33            else:
34                self.apply_spillway()
35        else:
36            self.set_q(
37                target_variable=InputVar.Q_OUT,
38                input_type="parameter",
39                input_data=0.2,
40            )
41
42    def calculate_output_variables(self):
43        """Calculate additional output variables."""
44        self.calculate_rule_curve_deviation(periods=3, h_var="H")
45
46
47# Create and run the model.
48if __name__ == "__main__":
49    run_simulation_problem(SingleReservoir, config=CONFIG)

The template file mentioned in the previous section will look very similar to this file, except that the apply_schemes() method still needs to be filled out, and the optional def, calculate_output_variables(), is not added..

The line

CONFIG = ModelConfig(base_dir=Path(__file__).parent)

sets the model configuration. This model configuration is defined by the base directory base_dir. In most cases, the base directory is Path(__file__).parent, which is the directory of the current file.

The line

class SingleReservoir(ReservoirModel):

defines a class SingleReservoir that inherits all properties and functionalities of the predefined class ReservoirModel. An overview of this class can be found in Reservoir API and details of the underlying model it uses can be found in Single Reservoir Model.

The method apply_schemes() is called every timestep and contains the logic for which schemes are applied. The first argument self is the SingleReservoir object itself. Since SingleReservoir inherits from ReservoirModel, self can call any of the ReservoirModel methods, such as get_current_datetime(), get_var(), set_q(), apply_spillway(). An overview of all available ReservoirModel methods can be found in Reservoir API.

In this example, the apply_schemes() method starts by including rain and rain evaporation by calling self.include_rainevap(). Since apply_schemes() is applied at each time step, this means rain and evaporation is included at each time step. The method then checks if the elevation H is higher than the crest elevation H_crest. If this is the case, and the current month is in between April and September, the outflow is set by set_q(). Otherwise, the spillway scheme is applied. If the elevation is below the crest elevation, the outflow is set by set_q().

The last line

# Create and run the model.
if __name__ == "__main__":
    run_simulation_problem(SingleReservoir, config=CONFIG)

runs a SingleReservoir model. To run the model, we can run python <model_file>.py from the command line.

Lookup tables

Lookup tables are used to define relations between volume, elevation, surface area, and outflow. They are defined in the <base_dir>/lookup_tables folder. A description of all lookup tables is given in the lookup_tables.csv file. In this example, this file looks as follows.

<base_dir>/lookup_tables/lookup_tables.csv

name

data

var_in

var_out

h_from_v

v_h.csv

volume_m3

height_m

v_from_h

v_h.csv

height_m

volume_m3

area_from_v

v_area.csv

volume_m3

area_m2

qspill_from_h

h_qspill.csv

height_m

qspill_m3_per_s

It consists of the following columns.

  • name: name of the lookup_table. The default reservoir model uses the lookup tables h_from_v, area_from_v, and qspill_from_h.

  • data: data file used to create the lookup table. This should a csv file where all fields are seperated by a ,.

  • var_in: input variable for creating the lookup table. This should be one of the columns in the data file.

  • var_out: output variable for creating the lookup table. This should be one of the columns in the data file.

A data file, such as v_h.csv, looks as follows.

<base_dir>/lookup_tables/v_h.csv

volume_m3

height_m

0

1542.306754

13439700

1562.118995

16152300

1563.643014

21700800

1566.691051

When setting up the model, the model object will look for the following lookup tables:

  • h_from_v

  • area_from_v

  • qout_from_v

  • qspill_from_h

It is therefore important to use these same names in the lookup_tables.csv file.

Input Data Files

The input folder contains a configuration file rtcDataConfig.xml a parameter file rtcParameterConfig.xml, and an input data file timeseries_import.xml.

The rtcDataConfig.xml file contains a mapping between external data and internal model variables. In this example, rtcParameterConfig.xml looks as follows.

<?xml version="1.0" encoding="UTF-8"?>
<rtcDataConfig xmlns="http://www.wldelft.nl/fews" xmlns:rtc="http://www.wldelft.nl/fews" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.wldelft.nl/fews ../xsd/rtcDataConfig.xsd">
  <timeSeries id="V">
    <PITimeSeries>
      <locationId>reservoir</locationId>
      <parameterId>V</parameterId>
    </PITimeSeries>
  </timeSeries>
  ...
</rtcDataConfig>

The line <timeSeries id=V> indicates that the model variable is called V and the lines <locationId>reservoir</locationId> and <parameterId>V</parameterId> indicate that V has locationId resrvoir and parameterId V. The locationId and parameterId are used to label data in data files such as the input file timeseries_import.xml or the output file timeseries_export.xml.

The input file timeseries_import.xml is usually not created by the user, but generated by a FEWS application. In this example, the input file contains the following lines.

    <series>
      <header>
        <type>instantaneous</type>
        <moduleInstanceId>reservoir</moduleInstanceId>
        <locationId>reservoir</locationId>
        <parameterId>V</parameterId>
        <timeStep unit="second" multiplier="3600"/>
        <startDate date="2022-06-07" time="06:00:00"/>
        <endDate date="2022-06-27" time="06:00:00"/>
        <forecastDate date="2022-06-07" time="06:00:00"/>
        <missVal>-999.0</missVal>
        <stationName>Reservoir1</stationName>
        <units>m3</units>
      </header>
      <event date="2022-06-07" time="06:00:00" value="136500000" flag="8"/>
    </series>

The line <event date="2022-06-07" time="06:00:00" value="136500000" flag="8"/> sets the value of V at the initial time (2022-06-07, 06:00:00). We only provide the reservoir volume V with an initial value and therefore there is only one event block. If we want to set a variable at each time step, like the inflow Q_in, we have an event block for each time step.

Output Data

The results of the simulation will appear in the output folder in a file called timeseries_export.xml. The data is linked to model variables via the rtcDataConfig.xml in the same way as with timeseries_import.xml.

Automatic Plotting

You can optionally include a plot_table.csv in the input folder. This is used by the rtc-tools-interfaces module (automatically installed with this package) to plot the model output. For more details on how to use this file and visualize results, see RTC-Tools-Interface.

The results of the simulation run can be seen in the plot below.