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