netCDF-SDK

This document describes how to read and write NC and NC2 files with C.

Contents

The following files must be installed with your application. The files can be copied from a current UniPlot installation (R2018 or later). A 32bit and a 64 bit version is available. The file license.txt can be found in the UniPlot\samples\SDK\netCDF directory.

rs_updf_nc.dll
rs_updf.dll
rs_xlib.dll
zlib.dll
license.txt

Other files from the UniPlot\samples\SDK\netCDF directory:

ncread.c            - A simple example how to read data.
ncwrite.c           - A simple example how to write data.
win32\rs_updf_nc.lib      - The 32-Bit Import-Library.
x64\rs_updf_nc.lib  - The 64-Bit Import-Library.
up-nc.h             - The Header file.
map-data.nc2        - Simple example file.

Some Notes

  • The UniPlot-netCDF-SDK uses the netCDF 2.4 API.

    http://www.unidata.ucar.edu/software/netcdf/old_docs/really_old/guide_toc.html

  • The netCDF data files used with UniPlot can have three different formats:

    1. The original netCDF format as described in the link above. File size is limited to 2 GBytes. The first three characters in the file are “CDF”.

    2. A modified form of the original netCDF format with Intel byte order (Little Endian). These files cannot be read with the standard netCDF library. The file size is limited to 2 GBytes. The first three characters in the file are “CDH”.

    3. A UniPlot format that uses only the API of the netCDF library. The format supports compression and fast delete/add channel and attributes. The first three characters in the file are “UPD”. These files are similar to a file system. The data is saved in sectors.

      The file size is limited to 1 TB. Each channel can contain up to 2^31-1 data points.

  • If you use a Microsoft C-Compiler you can compile the examples with:

    cl ncread.c x64\rs_updf_nc.lib
    

    The path for your C-Compiler must be set.

    Start the program with:

    ncread map-data.nc2
    

    The example prints the first 10 data points of each channel. More test files can be created using UniPlot.

  • Instead of using the Import-Library rs_updf_nc.lib, you can load the functions dynamically using LoadLibrary, (LoadLibraryEx, GetModuleHandle) and GetProcAddress.

  • For some data file formats, for example INCA-MDF, UniPlot saves the data in the netCDF file with a delay. The file contains the complete structure with all attributes and channels. The channel data is saved in the netCDF file, when the channel data is accessed.

    To check if the data is already saved in the netCDF file read the value of the channel attribute _nc_dl_loaded. If the attribute has the value 1 the data is valid.

Examples

 1/*
 2 compile: cl ncwrite.c rs_updf_nc.lib
 3*/
 4
 5#include <stdlib.h>
 6#include <stdio.h>
 7#include "up-nc.h"
 8
 9int error(char *msg)
10{
11    fprintf(stderr, "%s", msg);
12    exit(1);
13}
14
15void main(int argc, char *argv[])
16{
17    test();
18    exit(0);
19}
20
21int test()
22{
23    int ncid;
24    double *p;
25    int dimid;
26    int i, varid, start, count, len;
27    double scale = 1.0, offset = 0.0;
28
29    ncid = nccreate("test1.nc2");
30    if (ncid == -1) {
31        error("cannot open output file");
32    }
33
34    ncredef(ncid);
35
36    // Globale Attributes
37
38    varid = -1;
39    ncattput(ncid, varid, "Origin", NC_CHAR, 1, "");
40    ncattput(ncid, varid, "Source", NC_CHAR, 1, "");
41    len = strlen("enorise GmbH (www.uniplot.com)")+1;
42    ncattput(ncid, varid, "Creator", NC_CHAR, len, "enorise GmbH (www.uniplot.com)");
43    ncattput(ncid, varid, "Date", NC_CHAR, strlen("15 Nov 2013")+1, "15 Nov 2013");
44    ncattput(ncid, varid, "Time", NC_CHAR, strlen("09:24:20")+1, "09:24:20");
45
46    // Dimensions
47    dimid = ncdimdef(ncid, "n", 100);
48
49    // Kanäle und Kanal-Attribute
50    varid = ncvardef(ncid, "var1", NC_DOUBLE, 1, &dimid);
51    ncattput(ncid, varid, "units", NC_CHAR, strlen("1/min")+1, "1/min");
52
53    ncattput(ncid, varid, "scale_factor", NC_DOUBLE, 1, &scale);
54    ncattput(ncid, varid, "add_offset", NC_DOUBLE, 1, &offset);
55
56    ncendef(ncid);
57
58    // Write the channel data
59
60    p = (double*) malloc(100*sizeof(double));
61    for (i = 0; i < 100; i++) p[i] = (double) i;
62    start = 0;
63    count = 100;
64    ncvarput(ncid, varid, &start, &count, p);
65    free(p);
66    ncclose(ncid);
67    return 0;
68}

Writing a string channel

 1// compile: cl test_nc_string.c rs_updf_nc.lib
 2
 3#include <stdlib.h>
 4#include <stdio.h>
 5#include "up-nc.h"
 6
 7#define MIN(a,b) (((a)<(b))?(a):(b))
 8
 9void main()
10{
11    int ncid, varid, n1, len1, start[2], count[2], dimids[2];
12    char *s;
13
14    ncid = nccreate("d:\\test2.nc2");
15
16    // Number of Points 10,000
17    n1 = ncdimdef(ncid, "n", 10000);
18
19    // Legth of the longest string, e. g. 32
20    len1 = ncdimdef(ncid, "len", 32);
21
22    dimids[0] = n1;
23    dimids[1] = len1;
24    varid = ncvardef(ncid, "StringChannel", NC_CHAR, 2, dimids);
25    ncendef(ncid);
26
27    start[0] = 0;
28    start[1] = 0;
29    count[0] = 1;
30    count[1] = 5;
31    ncvarput(ncid, varid, start, count, "Hello");
32
33    s = "This is a long string";
34    start[0] = 10;
35    start[1] = 0;
36    count[0] = 1;
37    count[1] = MIN(32, strlen(s));
38    ncvarput(ncid, varid, start, count, s);
39
40    ncclose(ncid);
41}

Read file:

  1/*
  2 compile:
  3
  4 cl ncread.c rs_updf_nc.lib
  5
  6 See also
  7
  8 * readme.txt
  9
 10 * http://www.unidata.ucar.edu/software/netcdf/old_docs/really_old/guide_toc.html
 11
 12*/
 13
 14#include <stdlib.h>
 15#include <stdio.h>
 16#include "up-nc.h"
 17
 18int error(char *msg)
 19{
 20    fprintf(stderr, "%s", msg);
 21    exit(0);
 22}
 23
 24int att_print(int ncid, int varid, int attnum)
 25{
 26    char name[MAX_NC_NAME+1];
 27    int i, data_type, len;
 28    double *dVal;
 29    float *fVal;
 30    int *iVal;
 31    short *sVal;
 32    char *cVal;
 33
 34    ncattname(ncid, varid, attnum, name);
 35    ncattinq(ncid, varid, name, &data_type, &len);
 36    switch (data_type) {
 37    case NC_CHAR:
 38        cVal = (char*) malloc(len * sizeof(char));
 39        ncattget(ncid, varid, name, cVal);
 40        printf("%s = ", name);
 41        for (i = 0; i < len; i++) {
 42            printf("%c", cVal[i]);
 43        }
 44        printf("\n");
 45        free(cVal);
 46        break;
 47
 48    case NC_BYTE:
 49        cVal = (char*) malloc(len * sizeof(char));
 50        ncattget(ncid, varid, name, cVal);
 51        printf("%s = ", name);
 52        for (i = 0; i < len; i++) {
 53            printf("%d ", cVal[i]);
 54        }
 55        printf("\n");
 56        free(cVal);
 57        break;
 58
 59    case NC_SHORT:
 60        sVal = (short*) malloc(len * sizeof(short));
 61        ncattget(ncid, varid, name, sVal);
 62        printf("%s = ", name);
 63        for (i = 0; i < len; i++) {
 64            printf("%d ", sVal[i]);
 65        }
 66        printf("\n");
 67        free(sVal);
 68        break;
 69
 70    case NC_LONG:
 71        iVal = (int*) malloc(len * sizeof(int));
 72        ncattget(ncid, varid, name, iVal);
 73        printf("%s = ", name);
 74        for (i = 0; i < len; i++) {
 75            printf("%d ", iVal[i]);
 76        }
 77        printf("\n");
 78        free(iVal);
 79        break;
 80
 81    case NC_FLOAT:
 82        fVal = (float*) malloc(len * sizeof(float));
 83        ncattget(ncid, varid, name, fVal);
 84        printf("%s = ", name);
 85        for (i = 0; i < len; i++) {
 86            printf("%f ", fVal[i]);
 87        }
 88        printf("\n");
 89        free(fVal);
 90        break;
 91
 92    case NC_DOUBLE:
 93        dVal = (double*) malloc(len * sizeof(double));
 94        ncattget(ncid, varid, name, dVal);
 95        printf("%s = ", name);
 96        for (i = 0; i < len; i++) {
 97            printf("%lf ", dVal[i]);
 98        }
 99        printf("\n");
100        free(dVal);
101        break;
102    }
103    return 0;
104}
105
106void main(int argc, char *argv[])
107{
108    int ncid;
109    int nvars, ngatts, data_type, ndims, natts, length, length2;
110    int dimids[MAX_NC_DIMS];
111    int i, j;
112    char name[136];
113    double *vals;
114    float *fvals;
115    char *cvals;
116    unsigned char *bvals;
117    short *svals;
118    int *ivals;
119    int ret, start;
120    int st[2], le[2];
121
122    int max_len = 10;
123
124    if (argc != 2) {
125        error("usage: ncread nc-file-name");
126    }
127
128    ncid = ncopen(argv[1], 0);
129    if (ncid == -1) {
130        error("cannot open input file");
131    }
132    ncinquire(ncid, 0, &nvars, &ngatts, 0);
133
134    printf("ngatts=%d\n", ngatts);
135    for (i = 0; i < ngatts; i++) {
136        att_print(ncid, -1, i);
137    }
138
139    printf("\nnvars=%d\n", nvars);
140
141    for (i = 0; i < nvars; i++) {
142        ncvarinq(ncid, i, name, &data_type, &ndims, dimids, &natts);
143
144        printf("%s\n", name);
145
146        printf("natts=%d\n", natts);
147        for (j = 0; j < natts; j++) {
148            att_print(ncid, i, j);
149        }
150
151        if (ndims != 1 && data_type != NC_CHAR) {
152            printf("Variable %s wird im Beispielprog. ignoriert wg. Anzahl Dimensionen != 1", name);
153            continue;
154        }
155        switch (data_type) {
156        case NC_CHAR:
157            if (ndims != 2) {
158                printf("Variable %s wird im Beispielprog. ignoriert wg. Anzahl Dimensionen != 2", name);
159                continue;
160            }
161            ncdiminq(ncid, dimids[0], 0, &length);
162            ncdiminq(ncid, dimids[1], 0, &length2);
163            cvals = (char*) malloc(length2 * sizeof(char));
164            if (cvals == 0) {
165                error("out of memory");
166            }
167            printf("len=%d\n", length);
168            for (j = 0; j < min(max_len, length); j++) {
169                st[0] = j;
170                st[1] = 0;
171                le[0] = 1;
172                le[1] = length2;
173                ret = ncvarget(ncid, i, st, le, cvals);
174                printf("%s\n", cvals);
175            }
176            free(cvals);
177            break;
178
179        case NC_BYTE:
180            ncdiminq(ncid, dimids[0], 0, &length);
181            bvals = (unsigned char*) malloc(length * sizeof(unsigned char));
182            if (bvals == 0) {
183                error("out of memory");
184            }
185            start = 0;
186            ret = ncvarget(ncid, i, &start, &length, bvals);
187            printf("len=%d\n", length);
188            for (j = 0; j < min(max_len, length); j++) {
189                printf("%f\n", bvals[j]);
190            }
191            free(bvals);
192            break;
193
194        case NC_SHORT:
195            ncdiminq(ncid, dimids[0], 0, &length);
196            svals = (short*) malloc(length * sizeof(short));
197            if (svals == 0) {
198                error("out of memory");
199            }
200            start = 0;
201            ret = ncvarget(ncid, i, &start, &length, svals);
202            printf("len=%d\n", length);
203            for (j = 0; j < min(max_len, length); j++) {
204                printf("%f\n", svals[j]);
205            }
206            free(svals);
207            break;
208
209        case NC_LONG:
210            ncdiminq(ncid, dimids[0], 0, &length);
211            ivals = (int*) malloc(length * sizeof(int));
212            if (ivals == 0) {
213                error("out of memory");
214            }
215            start = 0;
216            ret = ncvarget(ncid, i, &start, &length, ivals);
217            printf("len=%d\n", length);
218            for (j = 0; j < min(max_len, length); j++) {
219                printf("%f\n", ivals[j]);
220            }
221            free(ivals);
222            break;
223
224        case NC_FLOAT:
225            ncdiminq(ncid, dimids[0], 0, &length);
226            fvals = (float*) malloc(length * sizeof(float));
227            if (fvals == 0) {
228                error("out of memory");
229            }
230            start = 0;
231            ret = ncvarget(ncid, i, &start, &length, fvals);
232            printf("len=%d\n", length);
233            for (j = 0; j < min(max_len, length); j++) {
234                printf("%f\n", fvals[j]);
235            }
236            free(fvals);
237            break;
238
239        case NC_DOUBLE:
240            ncdiminq(ncid, dimids[0], 0, &length);
241            vals = (double*) malloc(length * sizeof(double));
242            if (vals == 0) {
243                error("out of memory");
244            }
245            start = 0;
246            ret = ncvarget(ncid, i, &start, &length, vals);
247            printf("len=%d\n", length);
248            for (j = 0; j < min(max_len, length); j++) {
249                printf("%lf\n", vals[j]);
250            }
251            free(vals);
252            break;
253        }
254    }
255
256    ncclose(ncid);
257}

Conventions

  • Valid characters for attribute and channel names are: _[a-z][A-Z][0-9], A name should not start with an alphanumeric character. The name length is limited to 128 characters. The following 10 special characters are also allowed in names: . - + $ # ~ ! ^ & %.

  • Attribute and channel names should not start with an underscore _ or the characters nc_`. These names are reserved for internal purposes (e. g. for the attributes nc_min, nc_monotone, _FillValue, _nc_dl_loadinfo, etc.).

  • Channel names must be unique. The number of channels is limited to 20,000 per file.

  • Missing Values: For NC_DOUBLE- and NC_FLOAT channels the value 1e10 should be used as a missing value. For integer channels the attriubte missing_value should be added to the channel.

  • For time channels the channel data type NC_DOUBLE` (8 Bytes) should be used.

  • Time/Date channels should be saved in the Microsoft Excel Format with the datatype NC_DOUBLE:

    uniplot_time = unix_time / 86400 + 25569
    
    The Unix time are the seconds since 1.1.1970 00:00:00.
    The Excel time are the days since December 31, 1899.
    
    86400: seconds in a day (24*60*60)
    25569: days beween 1899-12-31 and 1970-01-01
    

    The attribute datatype should be saved with the Time/Date channel with one of the following values: “date”, “time” or “datetime”.

  • A string channel is a matrix of type NC_CHAR. The second dimention is the number of characters of the longest string. All other stings will be padded with NULL, see example below.

  • The following attributes should be saved in the file as global attributes:

    Attribute-Name

    Datatype

    Description

    Origin

    NC_CHAR

    Name of the original data file, e.g. c:\test-data\test.mdf4. Can be empty.

    Source

    NC_CHAR

    Create of the import filter, e. g. enorise GmbH (www.uniplot.com)

    Creator

    NC_CHAR

    Name of the import filter followed by a version number, e. g. MDF 4.1

    Date

    NC_CHAR

    Date as a string, e. g. 14 Nov 2013

    Time

    NC_CHAR

    Time as a string, e. g. 12:11:31,345

    In addition, the file can also contain other arbitrary attributes. For example, the project number, engine information,etc.

    The formula interpreter can access global attributes. example: The air pressure (barom) during the measurement could be specified as a channel or, if it was constant during the measurement, as a global attribute

    barom = 1013.4
    

    In this case another addtribute should define the unit:

    barom.units = "mbar"
    

    From UniPlot 2014, the attribute can be defined as following:

    barom = "1013.4 mbar"
    
  • Channels should have the following attributes:

    Attribute-Name

    Datatype

    Description

    title

    NC_CHAR

    Channel title.

    long_name

    NC_CHAR

    A long descriptive name. This could be used for labeling plots, for example.: zlrsb_w\ETKC:1 [s]

    units

    NC_CHAR

    A character string that specifies the units used for the variable’s data, e. g. Nm.

    scale_factor

    NC_DOUBLE

    If present for a variable, the data are to be multiplied by this factor after the data are read by the application that accesses the data. Normally 1.

    add_offset

    NC_DOUBLE

    If present for a variable, this number is to be added to the data after it is read by the application that accesses the data. Normally the value 0.

    The following attributes are optional.

    Attribute-Name

    Datatype

    Description

    missing_value

    As channel

    The data type of the attribute missing_value is the data type of the channel. Only required for integer channels, or if the data type is NC_FLOAT or NC_DOUBLE and the value 1e10 is not intended to be used.

    Type

    NC_CHAR

    Value is “Time Channel” or “Data Channel”.

    datatype

    NC_CHAR

    For Time/Date channel, values: “date” or “time” or “datetime”

    C_format

    NC_CHAR

    Format string to display the values in the data browser, e. g. %.2lf for two decimal places or %.6lf for 6 decimal places. see printf.

    Description

    NC_CHAR

    Description string.

    Comment

    NC_CHAR

    Comment string.

    In addition, the channel can also contain other attributes.

See also

Overview UniPlot Data Files

ncdump.exe

ncgen.exe

Overview Date and Time

History

Version

Description

1.4 (28.01.2019)

zlib.dll added to the list of DLLs.

1.4 (01.11.2017)

Correction. The two import libraries could only be used with R2015.x. The new libraries are for R2016 and higher.

1.3 (09 Jan 2015)

Description modified.

1.2 (21 Nov 2013)

Description modified.

1.1 (25 Mar 2011)

Writing added.

1.0 (21 Mar 2011)

First version.

Contact

If you have any questions please contact us:

id-1961936