SWE Common encoding of CF-NetCDF coverage data

The NetCDF file format was designed to store multidimensional coverage and has some similiraties in design with the SWE Common Data Model standard, especially in terms of its ability to store any kind of sensor data. This makes it possible to fairly simply convert from one format to another, thus enabling most datasets currently existing in NetCDF format to be served in SWE common format by simply doing a real time on the fly conversion. This tutorial shows how the multiple coverage types defined in the CF convention for NetCDF can be elegantly described and encoded in SWE Common binary blocks.

CF NetCDF examples of reference have been found on this page https://cf-pcmdi.llnl.gov/trac/wiki/PointObservationConventions

Point Data

This example is to represent data at scattered, unconnected points.

In NetCDF, both data and coordinates use the same, single dimension. The 'coordinates' attribute is used on the data variables to unambiguously identify the time, lat, lon and height auxiliary coordinate variables.

dimensions:
  obs = 1234 ;

variables:
  double time(obs) ;
    time:long_name = "time of measurement" ;
    time:units = "days since 1970-01-01 00:00:00" ;
  float lon(obs) ;
    lon:long_name = "longitude of the observation";
    lon:units = "degrees_east";
  float lat(obs) ;
    lat:long_name = "latitude of the observation" ;
    lat:units = "degrees_north" ;
  float alt(obs) ;
    alt:long_name = "altitude above MSL" ;
    alt:units = "m";
    alt:positive = "up";

  float humidity(obs) ;
    humidity:long_name = "specific humidity" ;
    humidity:coordinates = "time lat lon alt" ;
  float temp(obs) ;
    temp:long_name = "temperature" ;
    temp:units = "Celsius" ;
    temp:coordinates = "time lat lon alt" ;

attributes:
  :CF\:featureType = "point";

With SWE Common Data Model language, the exact same structure (i.e. parallel arrays of same dimension) can be described as shown below.

<DataRecord>
  <field name="obs_count" gml:id="OBS_DIMENSION">
    <Count definition="urn:ogc:def:data:OGC:ArrayDimension" axisCode="obs">
       <value>1234</value> <!-- This number would actually be embedded in the data stream -->
    </Count>
  </field>
  <field name="timeArray">
    <DataArray>
      <elementCount ref="OBS_DIMENSION"/>
      <elementType name="time">
        <Time definiton="urn:ogc:def:property:OGC:SamplingTime" referenceTime="1970-01-01T00:00:00Z">
          <uom code="d"/>
        </Time> 
      </elementType>
    </DataArray>
  </field>
  <field name="lonArray">
    <DataArray>
      <elementCount ref="OBS_DIMENSION"/>
      <elementType name="lon">
        <Quantity definition="urn:ogc:def:property:OGC:Longitude" referenceFrame="urn:ogc:def:crs:EPSG:6.7:4979" axisCode="X">
          <gml:description>Longitude of the observation</gml:description>
          <gml:name>Longitude</gml:name>
          <uom code="deg"/>
        </Quantity>
      </elementType>
    </DataArray>
  </field>
  <field name="latArray">
    <DataArray>
      <elementCount ref="OBS_DIMENSION"/>
      <elementType name="lat">
        <Quantity definition="urn:ogc:def:property:OGC:GeodeticLatitude" referenceFrame="urn:ogc:def:crs:EPSG:6.7:4979" axisCode="Y">
          <gml:description>Geodetic latitude of the observation</gml:description>
          <gml:name>Latitude</gml:name>
          <uom code="deg"/>
        </Quantity>
      </elementType>
    </DataArray>
  </field>
  <field name="altArray">
    <DataArray>
      <elementCount ref="OBS_DIMENSION"/>
      <elementType name="alt">
        <Quantity definition="urn:ogc:def:property:OGC:AltitudeAboveMSL" referenceFrame="urn:ogc:def:crs:EPSG:6.7:4979" axisCode="Z">
          <gml:description>Altitude of the observation above main sea level</gml:description>
          <gml:name>Altitude above MSL</gml:name>
          <uom code="m"/>
        </Quantity>
      </elementType>
    </DataArray>
  </field>
  <field name="humidityArray">
    <DataArray>
      <elementCount ref="OBS_DIMENSION"/>
      <elementType name="humidity">
        <Quantity definition="urn:ogc:def:property:OGC:SpecificHumidity">
          <gml:name>Specific Humidity</gml:name>
          <uom code="%"/>
        </Quantity>
      </elementType>
    </DataArray>
  </field>
  <field name="tempArray">
    <DataArray>
      <elementCount ref="OBS_DIMENSION"/>
      <elementType name="temp">
        <Quantity definition="urn:ogc:def:property:OGC:AirTemperature">
          <gml:name>Temperature</gml:name>
          <uom code="Cel"/>
        </Quantity>
      </elementType>
    </DataArray>
  </field>
</DataRecord>

SWE Common can also be used to describe the same data set in an interleaved manner, so that each observation is represented as a consistent record rather than using a separate array for each variable. This type of structure is more suitable when the data needs to be streamed in real time, one observation after another.

<DataStream>
  <elementCount>
    <Count definition="urn:def:ogc:data:OGC:ArrayDimension" axisCode="obs">
      <value>1234</value>
    </Count>
  <elementCount>
  <elementType name="station_data">
    <DataRecord>
      <field name="time">
        <Time definiton="urn:ogc:def:property:OGC:SamplingTime" referenceTime="1970-01-01T00:00:00Z">
          <uom code="d"/>
        </Time>  
      </field>
      <field name="location"> 
        <Vector definition="urn:ogc:def:data:LocationVector" referenceFrame="urn:ogc:def:crs:EPSG:6.7:4979">
          <coordinate name="lon">
            <Quantity definition="urn:ogc:def:property:OGC:Longitude" axisCode="X">
              <gml:description>Longitude of the observation</gml:description>
              <gml:name>Longitude</gml:name>
              <uom code="deg"/>
            </Quantity>
          </coordinate>
          <coordinate name="lat">
            <Quantity definition="urn:ogc:def:property:OGC:GeodeticLatitude" axisCode="Y">
              <gml:description>Geodetic latitude of the observation</gml:description>
              <gml:name>Latitude</gml:name>
              <uom code="deg"/>
            </Quantity>
          </coordinate>
          <coordinate name="alt">
            <Quantity definition="urn:ogc:def:property:OGC:AltitudeAboveMSL" axisCode="Z">
              <gml:description>Altitude of the observation above mean sea level</gml:description>
              <gml:name>Altitude above MSL</gml:name>
              <uom code="m"/>
            </Quantity>
          </coordinate>
        </Vector>
      </field>
      <field name="humidity">
        <Quantity definition="urn:ogc:def:property:OGC:SpecificHumidity">
          <gml:name>Specific Humidity</gml:name>
          <uom code="%"/>
        </Quantity>
      </field>
      <field name="temp">
        <Quantity definition="urn:ogc:def:property:OGC:AirTemperature">
          <gml:name>Temperature</gml:name>
          <uom code="Cel"/>
        </Quantity>
      </field>
    </DataRecord>
  </elementType>
</DataStream>

Time series of Station Data

Point data may be taken at a set of named locations called stations. The set of observations at a particular station, if ordered by time, is a time series, and the file contains a collection of time series data at named locations called stations.

In NetCDF, such dataset is stored using either a multidimensional array (as shown below) or as a continuous ragged array or non-continuous ragged array.

dimensions:
  station = UNLIMITED ;
  obs = 13 ;

variables:
  float lon(station) ;
    lon:long_name = "station longitude";
    lon:units = "degrees_east";
  float lat(station) ;
    lat:long_name = "station latitude" ;
    lat:units = "degrees_north" ;
  float alt(station) ;
    alt:long_name = "altitude above MSL" ;
    alt:units = "m" ;
    alt:positive= "up" ;
  char station_name(station, name_strlen) ;
    station_name:long_name = "station name" ;
    station_name:standard_name = "station_id";
  int station_info(station) ;
    station_info:long_name = "any kind of station info" ;

  double time(station, obs) ;
    time:long_name = "time of measurement" ;
    time:units = "days since 1970-01-01 00:00:00" ;
    time:missing_value = -999.9;
  float humidity(station, obs) ;
    humidity:long_name = "specific humidity" ;
    humidity:coordinates = "time lat lon alt" ;
    humidity:_FillValue = -999.9;
  float temp(station, obs) ;
    temp:long_name = "temperature" ;
    temp:units = "Celsius" ;
    temp:coordinates = "time lat lon alt" ;
    temp:_FillValue = -999.9;

attributes:
    :CF\:featureType = "stationTimeSeries";

Even though any of these structure can be described in SWE Common, we can avoid the unefficiency of the multidimensional array and the lack of flexibility of the ragded array by using variable size arrays as shown below:

<DataArray>
  <elementCount>
    <Count gml:id="STATION_DIMENSION" definition="urn:ogc:def:data:OGC:ArrayDimension">
      <value>23</value>
    </Count>
  </elementCount>
  <elementType name="StationData">
    <DataRecord>
      <field name="location"> 
        <Vector definition="urn:ogc:def:data:LocationVector" referenceFrame="urn:ogc:def:crs:EPSG:6.7:4979">
          <coordinate name="lon">
            <Quantity definition="urn:ogc:def:property:OGC:Longitude" axisCode="X">
              <gml:description>Longitude of the observation</gml:description>
              <gml:name>Longitude</gml:name>
              <uom code="deg"/>
            </Quantity>
          </coordinate>
          <coordinate name="lat">
            <Quantity definition="urn:ogc:def:property:OGC:GeodeticLatitude" axisCode="Y">
              <gml:description>Geodetic latitude of the observation</gml:description>
              <gml:name>Latitude</gml:name>
              <uom code="deg"/>
            </Quantity>
          </coordinate>
          <coordinate name="alt">
            <Quantity definition="urn:ogc:def:property:OGC:AltitudeAboveMSL" axisCode="Z">
              <gml:description>Altitude of the observation above mean sea level</gml:description>
              <gml:name>Altitude above MSL</gml:name>
              <uom code="m"/>
            </Quantity>
          </coordinate>
        </Vector>
      </field>
      <field name="ObservationCount">
        <Count gml:id="OBS_DIMENSION" definition="urn:ogc:def:data:OGC:ArrayDimension"/>
      </field>
      <field name="ObservationArray">
        <DataArray>
          <elementCount ref="OBS_DIMENSION"/>
          <elementType>
            <DataRecord>
              <field name="time">
                <Time definiton="urn:ogc:def:property:OGC:SamplingTime" referenceTime="1970-01-01T00:00:00Z">
                  <uom code="d"/>
                </Time>  
              </field>             
              <field name="humidity">
                <Quantity definition="urn:ogc:def:property:OGC:SpecificHumidity">
                  <gml:name>Specific Humidity</gml:name>
                  <uom code="%"/>
                </Quantity>
              </field>
              <field name="temp">
                <Quantity definition="urn:ogc:def:property:OGC:AirTemperature">
                  <gml:name>Temperature</gml:name>
                  <uom code="Cel"/>
                </Quantity>
              </field>
            </DataRecord> 
          </elementType>
        </DataArray>
      </field>
    </DataRecord>
  </elementType>
</DataArray>

Trajectory Data

Profile Data

Station Profile Data

-- AlexandreRobin - 24 Jun 2009
Topic revision: r1 - 24 Jun 2009, AlexandreRobin
This site is powered by FoswikiThe information you supply is used for OGC purposes only. We will never pass your contact details to any third party without your prior consent.
If you enter content here you are agreeing to the OGC privacy policy.

Copyright &© by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding OGC Public Wiki? Send feedback