/* This is part of the netCDF package. Copyright 2018 University Corporation for Atmospheric Research/Unidata See COPYRIGHT file for conditions of use. Test netcdf-4 variables. Ed Hartnett, Ward Fisher */ #include "nc_tests.h" #include "err_macros.h" #include "netcdf.h" #define FILE_NAME "tst_vars.nc" #define VAR_BYTE_NAME "Portrait_of_Maria_Trip" #define VAR_CHAR_NAME "Landscape_wth_stone_bridge" #define VAR_SHORT_NAME "Self-portrait_as_a_young_man" #define VAR_INT_NAME "Jeremiah_lamenting_the_destruction_of_Jerusalem" #define VAR_FLOAT_NAME "The_Syndics_of_the_Drapers_Guild" #define VAR_DOUBLE_NAME "Self-portrait_as_the_apstle_Paul" #define VAR_UBYTE_NAME "Tobias_and_Anna_with_the_kid" #define VAR_USHORT_NAME "The_Jewish_Bride" #define VAR_UINT_NAME "The_prophetess_Anna" #define VAR_INT64_NAME "Titus_as_a_Monk" #define VAR_UINT64_NAME "The_Night_Watch" #define DIM1_NAME "x" #define DIM1_LEN 2 #define DIM2_NAME "y" #define DIM2_LEN 3 #define DIM3_NAME "strlen" #define DIM3_LEN 25 #define NC_ERR 2 /* From here down, the defines are for the creation of the pres_temp_4D example file, which is also created under examples, but here is created in all file formats, and more extensively tested for correctness. We are writing 4D data, a 2 x 6 x 12 lvl-lat-lon grid, with 2 timesteps of data. */ #define NDIMS_EX 4 #define NLAT 60 #define NLON 120 #define LAT_NAME "latitude" #define LON_NAME "longitude" #define NREC 1000 #define REC_NAME "time" #define LVL_NAME "level" #define NLVL 2 /* Names of things. */ #define PRES_NAME "pressure" #define TEMP_NAME "temperature" #define UNITS "units" #define DEGREES_EAST "degrees_east" #define DEGREES_NORTH "degrees_north" /* There are 4 vars, two for data, two for coordinate data. */ #define NVARS_EX 4 /* These are used to construct some example data. */ #define SAMPLE_PRESSURE 900 #define SAMPLE_TEMP 9.0 #define START_LAT 25.0 #define START_LON -125.0 /* For the units attributes. */ #define UNITS "units" #define PRES_UNITS "hPa" #define TEMP_UNITS "celsius" #define LAT_UNITS "degrees_north" #define LON_UNITS "degrees_east" #define MAX_ATT_LEN 80 int create_4D_example(char *file_name, int cmode) { /* IDs for the netCDF file, dimensions, and variables. */ int ncid, lon_dimid, lat_dimid, lvl_dimid, rec_dimid; int lat_varid, lon_varid, pres_varid, temp_varid; int dimids[NDIMS_EX]; /* The start and count arrays will tell the netCDF library where to write our data. */ size_t start[NDIMS_EX], count[NDIMS_EX]; /* Program variables to hold the data we will write out. We will only need enough space to hold one timestep of data; one record. */ float pres_out[NLVL][NLAT][NLON]; float temp_out[NLVL][NLAT][NLON]; /* These program variables hold the latitudes and longitudes. */ float lats[NLAT], lons[NLON]; /* Loop indexes. */ int lvl, lat, lon, rec, i = 0; /* Create some pretend data. If this wasn't an example program, we * would have some real data to write, for example, model * output. */ for (lat = 0; lat < NLAT; lat++) lats[lat] = START_LAT + 5.*lat; for (lon = 0; lon < NLON; lon++) lons[lon] = START_LON + 5.*lon; for (lvl = 0; lvl < NLVL; lvl++) for (lat = 0; lat < NLAT; lat++) for (lon = 0; lon < NLON; lon++) { pres_out[lvl][lat][lon] = SAMPLE_PRESSURE + i; temp_out[lvl][lat][lon] = SAMPLE_TEMP + i++; } /* Create the file. */ if (nc_create(file_name, cmode, &ncid)) ; /* Define the dimensions. The record dimension is defined to have * unlimited length - it can grow as needed. In this example it is * the time dimension.*/ if (nc_def_dim(ncid, LVL_NAME, NLVL, &lvl_dimid)) ; if (nc_def_dim(ncid, LAT_NAME, NLAT, &lat_dimid)) ; if (nc_def_dim(ncid, LON_NAME, NLON, &lon_dimid)) ; if (nc_def_dim(ncid, REC_NAME, NC_UNLIMITED, &rec_dimid)) ; /* Define the coordinate variables. We will only define coordinate variables for lat and lon. Ordinarily we would need to provide an array of dimension IDs for each variable's dimensions, but since coordinate variables only have one dimension, we can simply provide the address of that dimension ID (&lat_dimid) and similarly for (&lon_dimid). */ if (nc_def_var(ncid, LAT_NAME, NC_FLOAT, 1, &lat_dimid, &lat_varid)) ; if (nc_def_var(ncid, LON_NAME, NC_FLOAT, 1, &lon_dimid, &lon_varid)) ; /* Assign units attributes to coordinate variables. */ if (nc_put_att_text(ncid, lat_varid, UNITS, strlen(DEGREES_NORTH), DEGREES_NORTH)) ; if (nc_put_att_text(ncid, lon_varid, UNITS, strlen(DEGREES_EAST), DEGREES_EAST)) ; /* The dimids array is used to pass the dimids of the dimensions of the netCDF variables. Both of the netCDF variables we are creating share the same four dimensions. In C, the unlimited dimension must come first on the list of dimids. */ dimids[0] = rec_dimid; dimids[1] = lvl_dimid; dimids[2] = lat_dimid; dimids[3] = lon_dimid; /* Define the netCDF variables for the pressure and temperature * data. */ if (nc_def_var(ncid, PRES_NAME, NC_FLOAT, NDIMS_EX, dimids, &pres_varid)) ; if (nc_def_var_deflate(ncid, pres_varid, NC_SHUFFLE, 1, 4)) ; if (nc_def_var(ncid, TEMP_NAME, NC_FLOAT, NDIMS_EX, dimids, &temp_varid)) ; if (nc_def_var_deflate(ncid, temp_varid, NC_SHUFFLE, 1, 4)) ; /* Assign units attributes to the netCDF variables. */ if (nc_put_att_text(ncid, pres_varid, UNITS, strlen(PRES_UNITS), PRES_UNITS)) ; if (nc_put_att_text(ncid, temp_varid, UNITS, strlen(TEMP_UNITS), TEMP_UNITS)) ; /* End define mode. */ if (nc_enddef(ncid)) ; /* Write the coordinate variable data. This will put the latitudes and longitudes of our data grid into the netCDF file. */ if (nc_put_var_float(ncid, lat_varid, &lats[0])) ; if (nc_put_var_float(ncid, lon_varid, &lons[0])) ; /* These settings tell netcdf to write one timestep of data. (The setting of start[0] inside the loop below tells netCDF which timestep to write.) */ count[0] = 1; count[1] = NLVL; count[2] = NLAT; count[3] = NLON; start[1] = 0; start[2] = 0; start[3] = 0; /* Write the pretend data. This will write our surface pressure and surface temperature data. The arrays only hold one timestep worth of data. We will just rewrite the same data for each timestep. In a real application, the data would change between timesteps. */ for (rec = 0; rec < NREC; rec++) { start[0] = rec; /* This won't work due to bad id. */ if (nc_put_vara_float(ncid + MILLION, pres_varid, start, count, &pres_out[0][0][0]) != NC_EBADID) ; /* Now write the data. */ if (nc_put_vara_float(ncid, pres_varid, start, count, &pres_out[0][0][0])) ; if (nc_put_vara_float(ncid, temp_varid, start, count, &temp_out[0][0][0])) ; } /* Close the file. */ if (nc_close(ncid)) ; return err; } int check_4D_example(char *file_name, int expected_format) { int ncid; int format, ndims_in, nvars_in, natts_in; int dimid[NDIMS_EX]; int varid[NVARS_EX]; char dim_name_in[NDIMS_EX][NC_MAX_NAME]; char var_name_in[NVARS_EX][NC_MAX_NAME]; char name_in[NC_MAX_NAME + 1]; char units_in[NC_MAX_NAME + 1]; nc_type xtype_in; size_t len_in; int i; if (nc_open(file_name, 0, &ncid)) ; /* Count stuff. */ if (nc_inq_format(ncid, &format)) ; if (nc_inq_ndims(ncid, &ndims_in)) ; if (ndims_in != NDIMS_EX) ; if (nc_inq_nvars(ncid, &nvars_in)) ; if (nvars_in != NVARS_EX) ; if (nc_inq_natts(ncid, &natts_in)) ; if (natts_in != 0) ; if (format != expected_format) ; /* Check dimensions. */ ndims_in = 0; if (nc_inq_dimids(ncid, &ndims_in, dimid, 0)) ; if (ndims_in != NDIMS_EX) ; for (i = 0; i < NDIMS_EX; i++) { if (dimid[i] != i) ; if (nc_inq_dimname(ncid, i, dim_name_in[i])) ; } if (strcmp(dim_name_in[0], LVL_NAME) || strcmp(dim_name_in[1], LAT_NAME) || strcmp(dim_name_in[2], LON_NAME) || strcmp(dim_name_in[3], REC_NAME)) ; /* Check variables. */ nvars_in = 0; if (nc_inq_varids(ncid, &nvars_in, varid)) ; if (nvars_in != NVARS_EX) ; for (i = 0; i < NVARS_EX; i++) { if (varid[i] != i) ; if (nc_inq_varname(ncid, i, var_name_in[i])) ; } if (strcmp(var_name_in[0], LAT_NAME) || strcmp(var_name_in[1], LON_NAME) || strcmp(var_name_in[2], PRES_NAME) || strcmp(var_name_in[3], TEMP_NAME)) ; if (nc_inq_var(ncid, 0, name_in, &xtype_in, &ndims_in, dimid, &natts_in)) ; if (strcmp(name_in, LAT_NAME) || xtype_in != NC_FLOAT || ndims_in != 1 || dimid[0] != 1 || natts_in != 1) ; if (nc_inq_var(ncid, 1, name_in, &xtype_in, &ndims_in, dimid, &natts_in)) ; if (strcmp(name_in, LON_NAME) || xtype_in != NC_FLOAT || ndims_in != 1 || dimid[0] != 2 || natts_in != 1) ; if (nc_inq_var(ncid, 2, name_in, &xtype_in, &ndims_in, dimid, &natts_in)) ; if (strcmp(name_in, PRES_NAME) || xtype_in != NC_FLOAT || ndims_in != 4 || dimid[0] != 3 || dimid[1] != 0 || dimid[2] != 1 || dimid[3] != 2 || natts_in != 1) ; if (nc_inq_var(ncid, 3, name_in, &xtype_in, &ndims_in, dimid, &natts_in)) ; if (strcmp(name_in, TEMP_NAME) || xtype_in != NC_FLOAT || ndims_in != 4 || dimid[0] != 3 || dimid[1] != 0 || dimid[2] != 1 || dimid[3] != 2 || natts_in != 1) ; /* Check variable atts. */ if (nc_inq_att(ncid, 0, UNITS, &xtype_in, &len_in)) ; if (xtype_in != NC_CHAR || len_in != strlen(DEGREES_NORTH)) ; if (nc_get_att_text(ncid, 0, UNITS, units_in)) ; if (strncmp(units_in, DEGREES_NORTH, strlen(DEGREES_NORTH))) ; if (nc_inq_att(ncid, 1, UNITS, &xtype_in, &len_in)) ; if (xtype_in != NC_CHAR || len_in != strlen(DEGREES_EAST)) ; if (nc_get_att_text(ncid, 1, UNITS, units_in)) ; if (strncmp(units_in, DEGREES_EAST, strlen(DEGREES_EAST))) ; if (nc_inq_att(ncid, 2, UNITS, &xtype_in, &len_in)) ; if (xtype_in != NC_CHAR || len_in != strlen(PRES_UNITS)) ; if (nc_get_att_text(ncid, 2, UNITS, units_in)) ; if (strncmp(units_in, PRES_UNITS, strlen(PRES_UNITS))) ; if (nc_inq_att(ncid, 3, UNITS, &xtype_in, &len_in)) ; if (xtype_in != NC_CHAR || len_in != strlen(TEMP_UNITS)) ; if (nc_get_att_text(ncid, 3, UNITS, units_in)) ; if (strncmp(units_in, TEMP_UNITS, strlen(TEMP_UNITS))) ; if (nc_close(ncid)) ; return err; } int main(int argc, char **argv) { #define NC3_NETCDF4_FILE "tst_pres_temp_4D_netcdf4.nc" printf("*** testing 4D example file in netCDF-4/HDF5 format..."); if (create_4D_example(NC3_NETCDF4_FILE, NC_CLOBBER|NC_NETCDF4)) ; if (check_4D_example(NC3_NETCDF4_FILE, NC_FORMAT_NETCDF4)) ; SUMMARIZE_ERR; FINAL_RESULTS; }