Latest update June 10, 2012: first version of this page.

Delwaq is the generic Deltares finite volume water quality and ecology solver that has been linked to 1D network models (like Deltares' own SOBEK model) as well as both structured and unstructured 2D and 3D models (like Delft3D, Telemac, ROMS and Untrim). The program has been able to flexibly couple to all these hydrodynamic solvers without any major architecture redesign for over 20 year by strict separation of geometry, topology, quantities and process formulations. In fact, delwaq itself doesn't know anything about the model geometry; although this has been a major advantage, the lack of geometry data on the delwaq binary output files is starting to limit the wider uptake and hence we're looking at options to enable geometry data on the output file without limiting bothering the computational core with irrelevant data on geometric differences between the various hydrodynamic models. A common generic geometric description would be best such that delwaq only has to call a single routine to copy it to the output file. For this purpose we have selected the new CF unstructured grid proposal. What information do we need from the flow module?

  1. Number of segments A segment is a delwaq volume. Note that the volumes used by delwaq may be aggregations of the volumes used by the hydrodynamic solver.
  2. Volume aggregation A mapping of flow volumes to delwaq segments. The (internal) segments are numbered 1 to Number of segments. Note: in specific cases, delwaq may also run on a disaggregated grid, e.g. 3D reconstruction based on 2D results and the logarithmic velocity profile, or 1D subgrid reconstruction generalized to rotational-free flow reconstruction in 2D or 3D models. We'll not consider these cases here at this moment.
  3. Number of exchanges Number of connections amongst the segments as well as the number of exchanges with the outside world (boundary conditions).
  4. Segment/exchange topology For every exchange the from/to segments (as well as the "from-1" and "to+1" segments for higher order schemes). Virtual segments representing open boundaries are indicated using negative numbers, i.e. -1 to -Number of boundary segments.
  5. Volumes For every time step the volumes of all segments.
  6. Surface Areas The surface area of each volume (may be constant or may be time-varying).
  7. Flows For every time increment (i.e. time span between two times at which the volumes are given) the discharges for every exchange.
  8. Flow Areas For every exchange the cross-sectional area of the exchange.
  9. Depending on the application, for consistency one may also provide other quantities for each segment, e.g. velocity, bed roughness, shear stress, temperature, salinity, sediment concentrations, etc. as already computed by the flow module. Alternatively, such quantities may also be computed by the delwaq system itself.

The user needs to furthermore supply

  1. Substance Selection Selection of water quality and ecology quantities/substances that one wants to include in the simulation (a selection of the 500 predefined quantities or add your own).
  2. Process Selection Selection of the processes that should act on those substances (a selection of the 700 predefined processes or add your own).
  3. Parameter Selection Specification of the parameters associated with the selected processes; all parameters can be constant or time- and/or space-varying.
  4. Initial Conditions Obviously one will need initial conditions for all simulated water quality and ecology substances.
  5. Boundary Conditions Concentrations associated with the various open boundaries of the flow model as well as the mass of any emissions modeled as dry waste load in the delwaq model.

For the generation of the boundary conditions we'll need one additional bit of information from the flow model, namely the names of all open boundaries as well as their location and (negative) boundary segment numbers associated them.

Below you will find a first example of a netCDF file with all information that delwaq graphical user interface needs for a simple case with volumes defined on the faces of the grid (e.g. Delft3D, D-FLOW Flexible Mesh, ROMS, Untrim).
New items in this listing are the aggregation tables for volumes and exchanges, the from-to pointer table, and the boundary names and indices. These items are to be identified by means of the new attribute delwaq_role. This attribute has been introduced in agreement with the cf_role attribute for quantities that probably can't be standardized beyond the scope of delwaq.

delwaq_role

description

segment_aggregation_table

For every flow volume the segment number of the corresponding delwaq schematisation. Note that this array may have length nNodes (for node centred flow codes like CG finite element codes like Telemac) or nFaces (for face centred flow codes like D-Flow Flexible Mesh and Untrim). This table indicates which grid cells are included in the delwaq computation and which grid cells have been merged. It does not indicate numbers of open boundary segments.

exchange_aggregation_table

For every flow volume interface the exchange number of the corresponding delwaq schematisation; generally it will have length nEdges. This table indicates where the various exchanges are located on the grid for both internal and open boundary exchanges. Although it may be used to derive the associated from and to segment numbers, it does not indicate the (from/to) order or does it indicate the numbers of the open boundary segments. This table may be derived using the topological information of the flow grid, the segment_aggregation_table and the from_to_segment_table.

from_to_segment_table

This table is size nExchanges x 2: for every delwaq exchange it indicates the from (1st value) and to (2nd value) segment numbers. This table may be expanded to include "from-1" and "to+1" segment indices as well. Note that this table implicitly defines positive flow direction for all exchanges as well as the open boundary segment numbers.

boundary_name

For every open boundary its name. Note that a boundary is defined as one or more exchanges.

boundary_exchange_index

For every open boundary the numbers (and order) of the exchanges that are associated with that boundary.

Sketch of the flow (left) and delwaq (right) topologies used in the example below:

dimensions:
        nNodes = 12 ;
        nEdges = 21 ;
        nFaces = 10 ;
        maxNumNodesPerFace = 5 ;
        nSegments = 5 ;
        nExchanges = 12 ;
        nBoundaries = 4 ;
        maxLenBndName = 5 ;
        maxNumExchangesPerBnd = 2 ;
 
        Two = 2 ;
 
variables:
// Mesh topology
        integer Mesh ;
                Mesh:cf_role = "mesh_topology" ;
                Mesh:long_name = "Topology data of 2D unstructured mesh" ;
                Mesh:dimension = 2 ;
                Mesh:node_coordinates = "Mesh_node_x Mesh_node_y" ;
                Mesh:face_node_connectivity = "Mesh_face_nodes" ;
                Mesh:edge_node_connectivity = "Mesh_edge_nodes" ; // attribute required if variables will be defined on edges
                Mesh:edge_coordinates = "Mesh_edge_x Mesh_edge_y" ; // optional attribute (requires edge_node_connectivity)
                Mesh:face_coordinates = "Mesh_face_x Mesh_face_y" ; // optional attribute
                Mesh:face_edge_connectivity = "Mesh_face_edges" ; // optional attribute (requires edge_node_connectivity)
                Mesh:face_face_connectivity = "Mesh_face_links" ; // optional attribute
        integer Mesh_face_nodes(nFaces, maxNumNodesPerFace) ;
                Mesh_face_nodes:cf_role = "face_node_connectivity" ;
                Mesh_face_nodes:long_name = "Maps every face to its corner nodes." ;
                Mesh_face_nodes:_FillValue = 999999 ;
                Mesh_face_nodes:start_index = 1 ;
        integer Mesh_edge_nodes(nEdges, Two) ;
                Mesh_edge_nodes:cf_role = "edge_node_connectivity" ;
                Mesh_edge_nodes:long_name = "Maps every edge to the two nodes that it connects." ;
                Mesh_edge_nodes:start_index = 1 ;
 
// Mesh node coordinates
        double Mesh_node_x(nNodes) ;
                Mesh_node_x:standard_name = "longitude" ;
                Mesh_node_x:long_name = "Longitude of 2D mesh nodes." ;
                Mesh_node_x:units = "degrees_east" ;
        double Mesh_node_y(nNodes) ;
                Mesh_node_y:standard_name = "latitude" ;
                Mesh_node_y:long_name = "Latitude of 2D mesh nodes." ;
                Mesh_node_y:units = "degrees_north" ;
 
// Optional mesh face and edge coordinate variables
        double Mesh_face_x(nFaces) ;
                Mesh_face_x:standard_name = "longitude" ;
                Mesh_face_x:long_name = "Characteristics longitude of 2D mesh face." ;
                Mesh_face_x:units = "degrees_east" ;
                Mesh_face_x:bounds = "Mesh_face_xbnds" ;
        double Mesh_face_y(nFaces) ;
                Mesh_face_y:standard_name = "latitude" ;
                Mesh_face_y:long_name = "Characteristics latitude of 2D mesh face." ;
                Mesh_face_y:units = "degrees_north" ;
                Mesh_face_y:bounds = "Mesh_face_ybnds" ;
        double Mesh_face_xbnds(nFaces,maxNumNodesPerFace) ;
                Mesh_face_xbnds:standard_name = "longitude" ;
                Mesh_face_xbnds:long_name = "Longitude bounds of 2D mesh face (i.e. corner coordinates)." ;
                Mesh_face_xbnds:units = "degrees_east" ;
                Mesh_face_xbnds:_FillValue = 9.9692099683868690E36;
        double Mesh_face_ybnds(nFaces,maxNumNodesPerFace) ;
                Mesh_face_ybnds:standard_name = "latitude" ;
                Mesh_face_ybnds:long_name = "Latitude bounds of 2D mesh face (i.e. corner coordinates)." ;
                Mesh_face_ybnds:units = "degrees_north" ;
                Mesh_face_ybnds:_FillValue = 9.9692099683868690E36;
        double Mesh_edge_x(nEdges) ;
                Mesh_edge_x:standard_name = "longitude" ;
                Mesh_edge_x:long_name = "Characteristic longitude of 2D mesh edge (e.g. midpoint of the edge)." ;
                Mesh_edge_x:units = "degrees_east" ;
        double Mesh_edge_y(nEdges) ;
                Mesh_edge_y:standard_name = "latitude" ;
                Mesh_edge_y:long_name = "Characteristic latitude of 2D mesh edge (e.g. midpoint of the edge)." ;
                Mesh_edge_y:units = "degrees_north" ;
        // bounds variables for edges skipped

// Aggregation tables
        integer Dlwq_volaggr(nFaces) ;
                Dlwq_volaggr:delwaq_role = "segment_aggregation_table" ;
                Dlwq_volaggr:long_name = "delwaq segment number for each face (flow volume)" ;
                Dlwq_volaggr:mesh = "Mesh" ;
                Dlwq_volaggr:location = "face" ;
                Dlwq_volaggr:coordinates = "Mesh_face_x Mesh_face_y" ;
                Dlwq_volaggr:_FillValue = 0;
        integer Dlwq_flxaggr(nEdges) ;
                Dlwq_flxaggr:delwaq_role = "exchange_aggregation_table" ;
                Dlwq_flxaggr:long_name = "delwaq exchange number for each edge (flow boundary)" ;
                Dlwq_flxaggr:mesh = "Mesh" ;
                Dlwq_flxaggr:location = "edge" ;
                Dlwq_flxaggr:coordinates = "Mesh_edge_x Mesh_edge_y" ;
                Dlwq_flxaggr:_FillValue = 0;
        integer Dlwq_fromto(nExchanges,Two) ;
                Dlwq_fromto:delwaq_role = "from_to_segment_table" ;
                Dlwq_fromto:long_name = "delwaq from/to table" ;
                
// Boundary information
        char Bnd_name(nBoundaries, maxLenBndName) ;
                Bnd_name:delwaq_role = "boundary_name" ;
                Bnd_name:long_name = "boundary name for the delwaq user interface" ;
        char Bnd_exch(nBoundaries, maxNumExchangesPerBnd) ;
                Bnd_exch:delwaq_role = "boundary_exchange_index" ;
                Bnd_exch:long_name   = "indices of exchanges associated with the boundary" ;
                Bnd_exch:_FillValue  = 0;
        
data:

    Mesh = 0 ; // dummy
    
    Mesh_face_nodes =
         1,  2,  5, 999999, 999999,
         1,  5,  8, 999999, 999999,
         5,  9,  8, 999999, 999999,
         5,  6,  9, 999999, 999999,
         2, 12,  5, 999999, 999999,
         3,  4,  7,  6, 12,
         6, 10,  9, 999999, 999999,
         6,  7, 11, 10, 999999,
         5, 12,  6, 999999, 999999,
         2,  3, 12, 999999, 999999 ;

    Mesh_edge_nodes =
         1,  2,
         2,  3,
         3,  4,
         1,  5,
         2,  5,
         5,  6,
         6, 12,
         6,  8,
         4,  7,
         1,  8,
         5,  8,
         5,  9,
         6,  9,
         6, 10,
         7, 11,
         8,  9,
         9, 10,
        10, 11,
         2, 12,
         5, 12,
         3, 12 ;
 
    Mesh_node_x = ... ;  // data skipped
    Mesh_node_y = ... ;  // data skipped
    Mesh_face_x = ... ;  // data skipped
    Mesh_face_y = ... ;  // data skipped
    Mesh_face_xbnds = ... ;  // data skipped
    Mesh_face_ybnds = ... ;  // data skipped
    Mesh_edge_x = ... ;  // data skipped
    Mesh_edge_y = ... ;  // data skipped

    Dlwq_volaggr =
        1, 2, 2, 3, 1, 5, 3, 4, 1, 1 ;

    Dlwq_flxaggr =
        1, 0, 2, 3, 0, 0, 4, 5, 6, 7, 0, 8, 0, 10, 11, 0, 9, 12, 0, 0, 4 ;

    Dlwq_fromto =
       -1,  1,
       -4,  5,
        1,  2,
        1,  5,
        4,  5,
        5, -6,
       -2,  2,
        2,  3,
       -3,  9,
        3,  4,
        4, -7,
       -5,  4 ;

    Bnd_name =
       "west ",
       "north",
       "east ",
       "south" ;

    Bnd_exch =
       1,  7,
       2,  0,
       6, 11,
       9, 12 ;

This data file may or may not contain the volume and flux data needed for the delwaq computational core

dimensions:
        timeVol = 100 ; //nTimeSteps for volumes
        timeFlx = 99  ; //nTimeSteps for exchanges
 
variables:

// Volume and flux data on original flow grid
        double Flow_volumes(timeVol, nFaces) ;
                Flow_volumes:long_name = "volumes" ;
                Flow_volumes:units = "m3" ;
                Flow_volumes:mesh = "Mesh" ;
                Flow_volumes:location = "face" ;
                Flow_volumes:coordinates = "Mesh_face_x Mesh_face_y" ;
        double Flow_fluxes(timeFlx, nEdges) ;
                Flow_fluxes:long_name = "flux across edge" ;
                Flow_fluxes:units = "m3 s-1" ;
                Flow_fluxes:mesh = "Mesh"
                Flow_fluxes:location = "edge" ;
                Flow_fluxes:coordinates = "Mesh_edge_x Mesh_edge_y" ;

// or aggrgated data on delwaq topology
        double Dlwq_volumes(timeVol, nSegments) ;
                Dlwq_volumes:long_name = "volumes of segments" ;
                Dlwq_volumes:units = "m3" ;
        double Dlwq_fluxes(timeFlx, nExchanges) ;
                Dlwq_fluxes:long_name = "exchanges between segments" ;
                Dlwq_fluxes:units = "m3 s-1" ;

data:

    Flow_volumes = ... ; // data skipped
    Flow_fluxes = ... ; // data skipped