apply_adjust Scheme Example
This example shows how to use the ReservoirModel.apply_adjust() scheme when modelling a single reservoir model.
Note
For details about the full model file structure please see Basic Single Reservoir.
We consider a reservoir with a single inflow, Q_in, and an outflow Q_out.
There are observed elevations for the first portion of timesteps (until 13th of June). At these times, the simulation should
be adjusted based upon these observed values. Hence the outflow from the reservoir will be corrected to prevent diverging
water balances between simulation and observation. At times without elevation observations, reservoir outflow should be 0.4 m3/s.
The ReservoirModel.apply_adjust() scheme can be applied to model these operations.
Main Model (python) File
An example of the main model file adjust_example.py is given below.
1"""Example that illustrates use of the adjust scheme
2and extracting bounds from lookup tables."""
3
4import logging
5import os
6import sys
7from pathlib import Path
8
9from rtctools.util import run_simulation_problem
10
11import rtctools_simulation.lookup_table as lut
12from rtctools_simulation.reservoir.model import InputVar, ModelConfig, ReservoirModel
13
14CONFIG = ModelConfig(base_dir=Path(__file__).parent)
15logger = logging.getLogger("rtctools")
16
17
18class SingleReservoir(ReservoirModel):
19 """Example single reservoir model."""
20
21 def pre(self, *args, **kwargs):
22 super().pre(*args, **kwargs)
23
24 # We can extract the min and max values in the provided lookup tables within the
25 # pre-processing.
26 base_folder = Path(sys.path[0])
27 lookup_tables_csv = Path(
28 os.path.join(os.path.join(base_folder, "lookup_tables"), "lookup_tables.csv")
29 )
30 lookup_tables_dir = os.path.join(base_folder, "lookup_tables")
31 lookup_tables_bounds = lut.get_lookup_tables_bounds_from_csv(
32 file=lookup_tables_csv, data_dir=lookup_tables_dir
33 )
34 logger.info(
35 "Volumes in the lookup table 'h_from_v' are in the range "
36 f"{lookup_tables_bounds['h_from_v']['volume_m3']}"
37 )
38 logger.info(
39 "Elevations in the lookup table 'v_from_h' are in the range "
40 f"{lookup_tables_bounds['v_from_h']['height_m']}"
41 )
42
43 def apply_schemes(self):
44 """Apply schemes for controlling the reservoir."""
45
46 # Apply schemes.
47 self.set_q(
48 target_variable=InputVar.Q_OUT,
49 input_type="parameter",
50 input_data=0.4,
51 )
52 self.apply_adjust()
53
54
55# Create and run the model.
56if __name__ == "__main__":
57 run_simulation_problem(SingleReservoir, config=CONFIG)
The template file mentioned in the Basic Single Reservoir will look very similar to this file,
except that the apply_schemes() method still needs to be filled out.
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 ReservoirModel.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
ReservoirModel.apply_adjust().
An overview of all available ReservoirModel methods
can be found in Reservoir API.
The ReservoirModel.set_q() scheme is applied to set reservoir outflow to 0.4 m3/s.
The ReservoirModel.apply_adjust() scheme is then applied to correct for elevation observations
when they are supplied to the model.
Lookup tables
This model uses only the standard lookup table h_from_v, for other lookup tables, defaults from the generated template files can be used.
Lookup table h_from_v is also used to convert the observed elevations (H_observed) into observed volumes.
This model also contains extraction of minimum and maximum values from the provided lookup tables. This is done by using the function
get_lookup_tables_bounds_from_csv() (see Lookup Tables). This function returns a dictionary which for each lookup table, stores the min
and max values for each variable. In this example we add some of these to the logger. This results in the following messages:
INFO Volumes in the lookup table ‘h_from_v’ are in the range [0, 180636966]
INFO Elevations in the lookup table ‘v_from_h’ are in the range [1542.306754, 1606.315533]
Note
For further details about the lookup tables please see Basic Single Reservoir.
Input Data Files
The ReservoirModel.apply_adjust() scheme requires observed elevation data supplied via the timeseries_import.xml
<series>
<header>
<type>instantaneous</type>
<moduleInstanceId>reservoir</moduleInstanceId>
<locationId>reservoir</locationId>
<parameterId>H.obs</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="1598.32" flag="8"/>
<event date="2022-06-07" time="06:00:00" value="1598.32" flag="8"/>
<event date="2022-06-07" time="07:00:00" value="1598.32" flag="8"/>
<event date="2022-06-07" time="08:00:00" value="1598.32" flag="8"/>
<event date="2022-06-07" time="09:00:00" value="1598.32" flag="8"/>
<event date="2022-06-07" time="10:00:00" value="1598.32" flag="8"/>
This additional input data is mapped to the internal variable, H_observed, using the rtcDataConfig.xml.
<!--Observations and states of model at t0-->
<timeSeries id="H_observed">
<PITimeSeries>
<locationId>reservoir</locationId>
<parameterId>H.obs</parameterId>
</PITimeSeries>
</timeSeries>
Note
For further details about input file structure please see Basic Single Reservoir.
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. Observed (constant) elevations are provided for the initial time period.
By choosing Show results from previous run, results are shown without the ReservoirModel.apply_adjust() scheme.
It can be seen that in this case the simulated elevations differ from observations.