.. highlightlang:: us .. index:: netCDF-SDK .. _netCDF-SDK: 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. .. _netCDF-SDK-example: Examples -------- .. code-block:: c :linenos: /* compile: cl ncwrite.c rs_updf_nc.lib */ #include #include #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 .. code-block:: c :linenos: // compile: cl test_nc_string.c rs_updf_nc.lib #include #include #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: .. code-block:: c :linenos: /* 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 #include #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); } .. _netCDF-SDK-conventions: 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: .. list-table:: :header-rows: 1 * - 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: .. list-table:: :header-rows: 1 * - 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. .. list-table:: :header-rows: 1 * - 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 :ref:`printf`. * - Description - NC_CHAR - Description string. * - Comment - NC_CHAR - Comment string. In addition, the channel can also contain other attributes. .. _netCDF-SDK-seealso: See also ---------- .. list-table:: :header-rows: 0 * - :ref:`overview-netcdf-files` * - :ref:`ncdump_exe` * - :ref:`ncgen_exe` * - :ref:`overview-date-and-time` History ------- .. list-table:: :header-rows: 1 * - 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: :sub:`id-1961936`