Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Table of Contents

Status
colourYellow
titleDocumentation in development



Introduction

The Integrated Reservoir Model is a General Adapter module written in Java, developed by Deltares. The model class is part of the Delft-FEWS code base.

The Reservoir model is developed and designed as a relatively straightforward reservoir routing model, that simulates flow through a reservoir with a level-outflow release table defined. Specifically, the model is able to precisely replicate  the uncontrolled outlet reservoir behaviour of the legacy Deltares RTC-Tools 1 codebase, which is no longer developed and supported. Because the adapter model is based on Java, it can run on Windows/Linux systems.

...

Configuring a pi-version 1.8 is required for the diagnostics of the model.

IDmapping

The model will write diagnostics to the filename that is configured in the General Adapter (the model reads it from the outputDiagnosticFile field in the run_info file). The logging will be to the level that is configured in Delft-FEWS (typically debug/info/warn/error).

idMapping
Anchor
IRM_IDmapping
IRM_IDmapping

The location/parameters used in Delft-FEWS can be transformed to model variableId locations/parameters The location/parameters used in Delft-FEWS can be transformed to model variableId locations/parameters by ID-mapping. The configuration files for ID-mapping can be of a general form, as long as the reservoir model have been set up with identical variables for the inputs/outputs. The model will look for the required variables (as configured in the IRM model file) in the parameter field of the PI timeseries. 

...

The reservoir model requires at a minimum the following timeseries:

  • level or storage state value (at model start time)
  • inflow timeseries (complete run period)
  • outflow release timeseries (optional)   

exportRunFileActivity

...

The executeActivity runs the model. The model runs of the Delft-FEWS JRE, so the ReservoirModelAdapter binaries can be specified within the binDir element. The Reservoir Model class itself is called nl.deltares.fews.reservoirmodel.ReservoirModelAdapter. It is required to provide the path of the run_info file as an argument to the model.

...

The model results (typically consisting of level, storage, inflow and outflow release timeseries) can be imported using the importActivities. The importFile name configured will be written to the run_info file and consequently be created by the Reservoir model. Note that specific idImport configuration is required.      

...

The model definition for the reservoir can be configured in a model file that follows the Integrated Reservoir Model schema. The model options are described below.

Schema


An example Integrated Reservoir Model file is For reference, an example IntegratedReservoirModel file is attached.

Code Block
languagexml
<IntegratedReservoirModel xmlns="http://www.wldelft.nl/fews" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.wldelft.nl/fews https://fewsdocs.deltares.nl/schemas/version1.0/adapter-schemas/IntegratedReservoirModel.xsd">
    <general>
        <missingValue>-	<general>
		<missingValue>-999</missingValue>
    	</general>
    	<reservoir id="H555001">
        <general>
            		<general>
			<description>reservoir management H555001</description>
            			<poolRoutingScheme>levelPoolMethod</poolRoutingScheme>
            			<dynamicInterpolation>true</dynamicInterpolation>
            <elevationInterpolationMethod>linear interpolation</elevationInterpolationMethod>
            <elevationInterval>0.00005</elevationInterval>
        			<interpolationMethod>linear</interpolationMethod>
			<elevationInterval>0.0005</elevationInterval>
			<extrapolationMethod>linear</extrapolationMethod>
		</general>
        <!--Height (LGH) vs. Storage (m3)-->
        <storageCharacteristics>
            <storageTable>
                <elevationStorageRecord elevation="292.9" storage="0"/>
                <elevationStorageRecord elevation="293.0" storage="500"/>
                ...
                <elevationStorageRecord elevation="335.4" storage="720992000"/>
                <elevationStorageRecord elevation="335.6" storage="732795000"/>
            </storageTable>
        </storageCharacteristics>
        <!--Height (LGH) vs Spill (m3/s-->
        <uncontrolledOutlet id="outlet">
            <capacityCharacteristics>
                <outletTable>
                    <elevationOutletRecord elevation="292.9" outlet="0"/>
                    <elevationOutletRecord elevation="293.0" outlet="0"/>
					...
                    <elevationOutletRecord elevation="335.4" outlet="9768"/>
                    <elevationOutletRecord elevation="335.6" outlet="10278"/>
                				</outletTable>
            			</capacityCharacteristics>
            <input>
                <release>QOut</release>
            </input>
            <output>
                <release>QOut</release>
            </output>
        </uncontrolledOutlet>
        <input>
            <inflow>IIn</inflow>
            <level>HIn</level>
        </input>
        <output>
            <inflow>IOut</inflow>
            <release>QOut</release>
            <storage>SOut</storage>
            <level>HOut</level>
        </output>
    </reservoir>
</IntegratedReservoirModel>

general

In the general section, a missingValue element needs to be configured. It is important to match the missingValue as defined in the Delft-FEWS General Adapter configuration for the model run.

reservoir

The reservoir element contains the following sections:

  • general
    • poolRoutingScheme
    • dynamicInterpolation
    • elevationInterpolationMethod
    • elevationInterval
    • storageCharacteristics
  • uncontrolledOutlet
  • input
  • output

poolRoutingScheme

for the poolRoutingScheme element, one can choose the following options:

levelPoolMethod

The Level Pool method is a well known method for reservoir routing. in FEWS the method described in Applied hydrology from V.T.Chow is used. The level pool routing method is also referred to as Storage routing, the Storage-Indication method, or the Modified Puls method.

 This basis of this method is the following function:

 ((2S_(t+1))/Δt+Q_(t+1) )=(I_t+I_(t+1))+((2S_t)/Δt-Q_t )

In order to compute the outflow Qt, a storage-outflow function relating 2S/∆t+Q and Q is needed, this is the G(h) function. The elevation-storage-outflow table can be computed using this function:

 (h)=(2S(h))/Δt+Q(h)

In routing the flow through time, all terms in the right hand side of the above function are known, and so the values ((2S_(t+1))/Δt+Q_(t+1) ) can be computed. The value Qt+1 can be determined from the storage outflow function 2S/∆t+Q versus Q by linear interpolation of the tabular values. To set up the data required for the next time interval, the value K(t), ((2S_(t+1))/Δt-Q_(t+1) ) is calculated by:

 ((2S_(t+1))/Δt-Q_(t+1) )=((2S_(t+1))/Δt+Q_(t+1) )-2Q_(t+1)

The reservoir routing procedure in the Level Pool method is as follows:

 

...

		</uncontrolledOutlet>
		<input>
			<inflow>IIn</inflow>
			<level>HIn</level>
			<release>QOut</release>
		</input>
		<output>
			<inflow>IOut</inflow>
			<release>QOut</release>
			<storage>SOut</storage>
			<level>HOut</level>
			<error>EOut</error>
		</output>
	</reservoir>
</IntegratedReservoirModel>


In XML Grid View this looks the following

Image Added

general

In the general section of the reservoir model, a missingValue element needs to be configured. It is important to match the missingValue as defined in the Delft-FEWS General Adapter configuration for the model run.

reservoir

The reservoir element contains the following sections:

  • general
  • uncontrolledOutlet
  • input
  • output

general

The general section of the reservoir element contains the follwing fields:

  • poolRoutingScheme
  • dynamicInterpolation
  • interpolationMethod
  • elevationInterval
  • extrapolationMethod (from 2023.02)
  • storageCharacteristics
poolRoutingScheme

for the poolRoutingScheme element, one can choose the following options:

  • levelPoolMethod
  • backwardsEulerMethod
levelPoolMethod

The Level Pool method is a well known method for reservoir routing. Level Pool routing is a procedure for calculating the outflow hydrograph form a reservoir with a horizontal water surface, given its inflow hydrograph and storage-release characteristics. The level pool routing method is sometimes also referred to as Storage routing, the Storage-Indication method, or the Modified Puls method. For this reservoir model, the method described in Applied Hydrology from V.T.Chow (1988) is used.  

The reservoir routing procedure in the Level Pool method is as follows:

We define the value G is a function of Storage and Outflow, defined as G[S] = 2*S/Δt + O

where:

  • S represents the reservoir storage
  • O represents the reservoir release
  • Δt represents the time step

For each row in the the uncontrolledOutlet capacityCharacteristics outletTable, we can now precompute a G[S] value. This allows the model to look up the release O for a given G.

Image Added

The level pool method makes use of the following relations, that follow from the water balance equations (details in the handbook):

K[t] = G[t-1] - 2*O[t-1]

G[t]= ( I[t-1] + I[t] )+K[t]

 For the computation, we loop over all time intervals from t=0 to t=tend.

  1. If t=0
    1. Use the state values as provided in the input files. If either a level, or a storage are provided, look up the equivalent value.
    2. In case both level and storage are provided, use the lookup value to determine any inconsistencies. If found, the level is used as the basis and the storage at t=0 is recalculated
    3. no computation takes place at t=0
  2. If t=1 then
    1. K[1] = 2*S[0]/Δt - O[0] (inital storage and release values are known)
    2. G[1] is computed with G[1]= ( I[0] + I[1] )+K[1]
    3. Compute outlet O[1] by linearly interpolating the precomputed table using O(S) and G(S).
    4. In case an outlet O_input[1] timeseries is provided as part of the inputs, set O[1] = O_input[1]
    5. Compute storage S[1] = S[0] + Δt* ( I[1] - O[1] )
  3. If t>1 then
    1. K[t] = G[t-1] - 2*O[t-1]
    2. G[t] is computed with G[t]= ( I[t-1] + I[t] )+K[t]
    3. Compute outlet O[t] by linearly interpolating the precomputed table using O(S) and G(S).
    4. In case an outlet O_input[t] timeseries is provided as part of the inputs, set O[t] = O_input[t]
    5. Compute storage S[t] = S[t-1] + Δt* ( I[t] - O[t] )

A model that is configured to use the level-pool method will write the values for G and K for each timestep in the the diagnostics when run in debug mode.

backwardEulerMethod

The Backward Euler reservoir routing scheme is an implicit scheme that uses the backward difference approximation for the derivative. The equation for the backward Euler reservoir routing scheme can be written as follows:

S[t+1] = S[t] + Δt* ( I[t+1] - O[t+1,S[t]] )

where:

  • S[t+1] represents the reservoir storage at the next time step (n+1)
  • S[t] represents the reservoir storage at the current time step (n).
  • Δt represents the time step.
  • I[t+1] is the inflow into the reservoir at the next time step (n+1).
  • O[ t+1, S[t] ] is the reservoir release at the next time step (n+1), based on the storage-release relation using S[t] for the lookup input.
dynamicInterpolation

When the dynamicInterpolation element is set to true, the level/storage and level/outlet tables are inteprolated dynamically (every timestep), to the precise value, using the elevationInterpolationMethod. In this case, the elevationInterval element is ignored. 

When the dynamicInterpolation element is set to false, the level/storage and level/outlet tables are precalculated (only once) using the elevationInterpolationMethod, to the specified elevationInterval.  

interpolationMethod

Linear interpolation is the only available interpolation method

elevationInterval

The elevationInterval is the elevation resolution at which the configured level/storage and level/outlet tables need to be recalculated to achieve a higher granularity. Note that the level output at each timestep is processed to that specific elevationInterval. When the model looks up a value from the table, the largest precalculated table elements smaller than the lookup value will be used (i.e. the model always rounds down). The consequence is that reservoir inflows/releases at a timestep that result in level/storage changes smaller than the interval/resolution will not be taken into account. The model does not perform any shadow accounting to keep track of these volumes. This means that the model will generally underestimate the flow when dynamicInterpolation element is set to false, and water balance will not be closed for that run type. For larger reservoirs (more volume per unit water disk) the elevationInterval needs to be set to higher resolutions to account for this. 

extrapolationMethod

The available extrapolation options are: notAllowed. linear, maxMin

storageCharacteristics

The storageCharacteristic storageTable contains a storage-level lookup table that is strictly increasing. Note that this table should have the identical storage inputs as the capacityCharacteristics outletTable from the uncontrolledOutlet.

uncontrolledOutlet

The uncontrolledOutlet element contains capacityCharacteristics outletTable which relates storage-release. Note that this table should have the identical storage inputs as the storageCharacteristic storageTable.

input / output variables and files

In the input section, the model input variables will be configured.

The <input><inflow> element is required

The <input><level> element is optional, and can be set to the timeseries variable that can overwrite (take precedence) over the level as a result from the release table computation. For a given timestep, if the level input timeseries (e.g. HIn) contains a value, this level is applied. The model will determine the resulting release from closing the waterbalance (thus not using the release lookup value)

The <input><release> element is optional, and can similarly be set to the timeseries variable that can overwrite (take precedence) over the lookup value for the outlet. This means that for a given timestep, if the outlet input timeseries (e.g. QIn) contains a value, this release is applied. This input option was added in 2023.02

When both a level and a release input value are available for a timestep, the model will use those values and write them to the output. A waterbalance error term will be calculated and saved for that timestep as well.


The model will look for the required variables in the parameter field of the PI timeseries (see idMapping). The Reservoir Model code will try to parse the configured model variables (like IIn, QOut, etc) from the parameterId of the PI timeseries, the locationId is not used. In the output section, the model output variables will be configured. When writing the output timeseries, the locationId used in the import PI xml files will be used as the locationId in the output PI xml files. The output model variableId's will be used as the parameter in the timeseries.

The naming convention of the input and output timeseries filenames are free, the model will determine which files to read for the input based on the inputTimeSeriesFile filed in the run_info file. The following two input timeseries files are suggested:

  • importState.xml
    • level values, or (HIn)
    • storage values (SIn)
  • import.xml
    • inflow (IIn)
    • outlet (optional) (QIn)

The following output timeseries file is suggested:

  • export.xml
    • inflow (IOut)
    • release (QOut)
    • storage (SOut)
    • level (HOut)
    • error (EOut)

Note that for the suggested variableId's in the provided example, the postfix In and Out are used to denote if the series are Inputs for, or Outputs from the model.

State values

The startDateTime and endDateTime in the run_info file are used by the model to determine the start (startDateTime) and end (endDateTime) of the model run. The model will pick the starting (state) value for level/storage (level has precedent in case of an inconsistency), inflow, outlet from the inputTimeSeriesFiles at the specific datetime. It will use the output variables to look for the state timeseries. The model will first check for a state level value. If a starting level value is missing in the input, the model will use the starting storage value. If both starting level/storage cannot be determined from the input files, the model will use the first level element as defined in the storage table as the starting level. A Warning message will be generated to notify the operator of this situation.

Inflow and outlet values at the starting time are not required at the first timestep and these values will not be used for storage calculations (no calculation at the first timestep). When these values are not provided as inputs, a value of 0 is assumed (and written to the output).

When no inflows into the reservoir are defined at all, the model will not calculate, but also it will not error out. It will produce and export.xml with missings (except for the initial values). When some intermediate inflow values are missing, the model will stop calculating at the point. It will not error out (and not throw a warning), it will produces an export.xml with calculated values up until the point an inflow value was missing and it will have missings for all outputs from that moment in time.


In case state functionality is configured in the run_info file (inputStateDescriptionFile is defined), the model will also write (all) the outputs to the write location as defined in the stateLocation file (e.g. exportState.xml)

Image Added

Reservoir Model specifics

  • The Integrated Reservoir Model

...

backwardEulerMethod
dynamicInterpolation
elevationInterpolationMethod
elevationInterval

storageCharacteristics

strictly increasing, same number of elements

uncontrolled outlet

same number of elements

input / output files

The naming convention of the input and output timeseries files are free, the model will determine which files to read for the input based on the inputTimeSeriesFile filed in the run_info file. The following two input timeseries files are suggested:

  • importState.xml
    • level values, or
    • storage values
  • import.xml
    • Inflow
    • outflow (optional)

The startDateTime and endDateTime in the run_info file are used by the model to determine the start (startDateTime) and end (endDateTime) of the model run. The model will pick the starting (state) value for level/storage (level has precedent in case of an inconsistency)

, inflow, release from the inputTimeSeriesFiles at the specific .

If a starting level value is missing, the model will use the starting storage value. If both starting level/storage cannot be determined from the input files, the model will throw an error

inflow and outflow values at the starting time are not required at the first timestep. When they are not found, a value of 0 is used.

Reservoir Model specifics

  • The model can be considered "timestep ending", similar the the timestep definition of Delft-FEWS.
  • No calculations/processing is performed at the first timestep (t=0, startDateTime as set in the run_info.xml file)

...

The Reservoir Model can be run in parallel from Delft-FEWS. The runInLoop element of the workflow should be set to false. The general section of the General Adapter configuration should contain the %TEMP_DIR% property as the model rootDir. And lastly, to enable the parallel running of ensemble members the runInLoopParallelProcessorCount entry must be set in the global properties file. Here you either specify the number of cores to use or specify 100 to use all available cores.In the workflow

The workflow definition for a parallel model run:

Code Block
languagexml
    <activity>
        <runIndependent>true</runIndependent>
        <workflowId>Reservoir_Forecast</workflowId>
        <ensemble>
            <ensembleId>ENSEMBLE</ensembleId>
            <runInLoop>false</runInLoop>
        </ensemble>
    </activity>

The general section of the General Adapter configuration:

Code Block
xml
xml
<general>
  <rootDir>%TEMP_DIR%</rootDir>
  <workDir>%ROOT_DIR%/work</workDir>
  ...
</general>

In Entry in the global properties:

Config Example


No Format
# to use 4 cores/cpu's:
runInLoopParallelProcessorCount=4


...

From Delft-FEWS version 2023.01 onwards, it will be porssible to run the Reservoir Model adapter "in-memory" from Delft-FEWS, using the inMemoryFileTransfer element of the general section set to True.  In that case, all exported and imported files are transferred in memory between Delft-FEWS and the executed Reservoir Model.