This page describes a proposal for storing unstructured model data in a netCDF file. Compared to the other proposal, this proposal intends to not only store the mesh and the (staggered) values, but also the information required for a consistent spatial interpretation of the value. The additional information may for instance indicate whether values should be considered constant or linearly varying across elements. The concepts are described in an attached memo and some mails to the Google group on ugrid-interoperability by David Ham (ICOM model).

The proposal distinguishes the following concepts:

  • vertices: these are the (abstract) points that form the basis of the mesh.
  • topology: the topology defines the connectivity of the vertices and defines the elements.
  • function space: a function space links elements to the indices of the degrees of freedom.
  • fields: the fields are variables that specify a value for each degree of freedom.

Due to the wide variety in unstructured mesh models, some relevant concepts have not yet been worked out in detail. This includes the following concepts:

  • adaptive mesh topology (this could be supported by defining a time_concatenation attribute for a time-series of mesh topologies)
  • 3D fully unstructured meshes (this can be defined analogous to the conventions for 2D mixed element topologies)
  • local model features, such as weirs and other structures located at cell interfaces (see e.g. the other other proposal)

More details can be found in the various sections below:

Topology.

The storage of the topology doesn't deviate much from the other proposal. However, for the time being we will keep the examples more lean and mean by indicating only the minimal data. Furthermore, one should note that where the other proposal uses the word node for the points of the mesh, this proposal uses the word vertex for those points.

2D triangular mesh topology.

The topology information is stored as attributes to a dummy variable (in the example below called "Topology"). The first new attribute is dimensionality: its value should be integer 2 for a 2D (triangular) mesh. The second new attribute is element_vertex_connectivity that specifies the actual topology of how the (triangular) elements map to the vertices. Note that this maps to the face_node_connectivity in the other proposal. The vertex_coordinates attribute points to the lat,lon coordinates of the vertices; we will fill in the details below once we have defined the variables on the topology.

Consistent with the CF-conventions compression option, the connectivity indices are 0-based, i.e. if the "Element_vertices" array contains values 0, 1 and 2 then this means that that element connects the first three points.

Example:

dimensions:
        nElements = 2 ;
        Three = 3 ;

variables:
// Mesh topology
        integer Element_vertices(nElements, Three) ;
                Element_vertices:standard_name = "" ;  // YET TO BE DETERMINED
                Element_vertices:long_name = "Maps every triangular element to its three corner vertices." ;
        integer Topology ;
                Topology:standard_name = "" ;  // YET TO BE DETERMINED
                Topology:long_name = "Topology data of 2D unstructured mesh" ;
                Topology:dimensionality = 2 ;
                Topology:element_vertex_connectivity = "Element_vertices" ;
                Topology:vertex_coordinates = "...see below..." ;

The example explicitly defines a simple topology consisting of two triangles. This example also implicitly defines a second topology, namely the topology of the boundary edges on which boundary forcings may be prescribed. If this second topology is going to be used, then it's probably wise to make this definition more explicit.

Function Space.

The next step is defining the function space on the mesh. One needs to define the basis functions that span up the function space and the element topology on which they are defined. For this we define function space variables as integer variables that via its values points for every element to the associated degrees of freedom of the function space, and via its attribute standard_basis_functions points to the basis functions associated with this function space (here: the linear basis functions P1). Basis functions can be specified in two ways: either by means of the attribute standard_basis_functions in which case its value is taken from the table of commonly used function spaces below.

Name

Meaning

P0

constant functions on element

P1

linear continuous functions

...

...

The second way to define the basis functions is by explicitly specifying the equations for the basis functions by means of an attribute basis_functions_formula. For more information see the section on basis functions below.

Consistent with the CF-conventions compression option, the function space indices are 0-based, i.e. if the "FSpace" array contains values 0, 1 and 2 then this means that that element is associated with the first three degrees of freedom.

Example:

dimensions:
        nElements = 2 ;
        Three = 3 ;
        nDoFperElement = 3 ;

variables:
// Mesh topology
        integer Element_vertices(nElements, Three) ;
                Element_vertices:standard_name = "" ;  // YET TO BE DETERMINED
                Element_vertices:long_name = "Maps every triangular element to its three corner vertices." ;
        integer Topology ;
                Topology:standard_name = "" ;  // YET TO BE DETERMINED
                Topology:long_name = "Topology data of 2D unstructured mesh" ;
                Topology:dimensionality = 2 ;
                Topology:element_vertex_connectivity = "Element_vertices" ;
                Topology:vertex_coordinates = "...see below..." ;

// Function spaces
        integer FSpace(nElements, nDoFperElement) ;
                FSpace:standard_name = "" ; // YET TO BE DETERMINED
                FSpace:long_name = "Function space S1: maps every triangular element to the associated degrees-of-freedom." ;
                FSpace:standard_basis_functions = "P1" ;

For a continuous function space the degrees of freedom for the individual elements will be linked. In that case the FSpace variables contains the same data as the Element_vertices table (and the total number of freedoms will equal the number of vertices). For a discontinuous function space this will not be the case (and the total number of freedoms will equal three times the number of elements).

Field Variables.

The final step is in defining the actual variable fields (i.e. the values associated with the degrees of freedom of the function space). This is done by specifying variables of dimension nDegreesOfFreedom (constant in time) or by variables of dimension (nTimeSteps,nDegreesOfFreedom) where nTimeSteps matches the dimensionality of the time coordinate and nDegreesOfFreedom matches the number of degrees of freedom associated with the function space referred to by the variable attribute function_space.

Example:

dimensions:
        nElements = 2 ;
        nDoFperElement = 3 ;
        nDoFofFSpace = 4 ;

        // common dimensions
        Three = 3 ;
        time = UNLIMITED ; // (1 currently)

variables:
// Mesh topology
        integer Element_vertices(nElements, Three) ;
                Element_vertices:standard_name = "" ;  // YET TO BE DETERMINED
                Element_vertices:long_name = "Maps every triangular element to its three corner vertices." ;
        integer Topology ;
                Topology:standard_name = "" ;  // YET TO BE DETERMINED
                Topology:long_name = "Topology data of 2D unstructured mesh" ;
                Topology:dimensionality = 2 ;
                Topology:element_vertex_connectivity = "Element_vertices" ;
                Topology:vertex_coordinates = "lat lon" ;

// Function spaces
        integer FSpace(nElements, nDoFperElement) ;
                FSpace:standard_name = "" ; // YET TO BE DETERMINED
                FSpace:long_name = "Function space S1: maps every triangular element to the associated degrees-of-freedom." ;
                FSpace:standard_basis_functions = "P1" ;

// Time coordinate
        double time(time) ;
                time:standard_name = "time" ;
                time:units = "seconds since 1992-08-31 00:00:00" ;

// Variables
        double zwl(time, nDoFofFSpace) ;
                zwl:standard_name = "sea_surface_height_above_geoid" ;
                zwl:units = "m" ;
                zwl:function_space = "FSpace" ;
        double depth(nDoFofFSpace) ;
                depth:standard_name = "sea_floor_depth_below_geoid" ;
                depth:units = "m" ;
                depth:positive = "down" ;
                depth:function_space = "FSpace" ;
        double lat(nDoFofFSpace) ;
                lat:standard_name = "latitude" ;
                lat:units = "degrees_east" ;
                lat:function_space = "FSpace" ;
        double lon(nDoFofFSpace) ;
                lat:standard_name = "longitude" ;
                lat:units = "degrees_north" ;
                lat:function_space = "FSpace" ;

The example shows water level, bed level and the coordinates for a case with all linear basis functions. More complex examples need to be added.

Defining basis function formulae.

Below you'll find an example of how basis functions could be specified in netCDF:

dimensions:
    Three = 3 ;
    maxStringLen = 5 ;

variables:

// Degree of freedom locations in local coordinates.
    double DOF_locations_P1_Tri(Three, Three) ;
        DOF_locations_P1_Tri:standard_name = "" ; // YET TO BE DETERMINED
        DOF_locations_P1_Tri:long_name = "DOF locations in local coordinates for P1 Triangular elements"
        DOF_locations_P1_Tri:dimension = 2 ;
        DOF_locations_P1_Tri:coordinates = "barycentric" ;


// Basis functions
    char Basis_functions_P1_Tri(Three,maxStringLen) ;
        Basis_functions_P1_Tri:standard_name = "" ; // YET TO BE DETERMINED
        Basis_functions_P1_Tri:long_name = "Basis functions in local coordinates for P1 Triangular elements" ;
        Basis_functions_P1_Tri:continuity = "continuous";
        Basis_functions_P1_Tri:topological_dimension = 2 ;
        Basis_functions_P1_Tri:data_dimension = 1 ;
        Basis_functions_P1_Tri:coordinates = "barycentric" ;



data:

    DOF_locations_P1_Tri = 1, 0, 0,
                           0, 1, 0,
                           0, 0, 1;

    Basis_functions_P1_Tri = "xi[0]",
                             "xi[1]",
                             "xi[2]";
  • No labels