1 /*! \file
2 A simple example of reading a netCDF file.
3 
4 This is an example which reads some surface pressure and
5 temperatures. The data file read by this program is produced by the
6 companion program sfc_pres_temp_wr.c. It is intended to illustrate the
7 use of the netCDF C API.
8 
9 Copyright 2006 University Corporation for Atmospheric
10 Research/Unidata.  See COPYRIGHT file for conditions of use.
11 
12 */
13 
14 #include <stdio.h>
15 #include <string.h>
16 #include <netcdf.h>
17 
18 /* This is the name of the data file we will read. */
19 #define FILE_NAME "sfc_pres_temp.nc"
20 
21 /* We are reading 2D data, a 6 x 12 lat-lon grid. */
22 #define NDIMS 2
23 #define NLAT 6
24 #define NLON 12
25 
26 #define LAT_NAME "latitude"
27 #define LON_NAME "longitude"
28 #define PRES_NAME "pressure"
29 #define TEMP_NAME "temperature"
30 
31 /* These are used to calculate the values we expect to find. */
32 #define SAMPLE_PRESSURE 900
33 #define SAMPLE_TEMP 9.0
34 #define START_LAT 25.0
35 #define START_LON -125.0
36 
37 /* For the units attributes. */
38 #define UNITS "units"
39 #define PRES_UNITS "hPa"
40 #define TEMP_UNITS "celsius"
41 #define LAT_UNITS "degrees_north"
42 #define LON_UNITS "degrees_east"
43 #define MAX_ATT_LEN 80
44 
45 /* Handle errors by printing an error message and exiting with a
46  * non-zero status. */
47 #define ERR(e) {printf("Error: %s\n", nc_strerror(e)); return 2;}
48 
49 int
main()50 main()
51 {
52    int ncid, pres_varid, temp_varid;
53    int lat_varid, lon_varid;
54 
55    /* We will read surface temperature and pressure fields. */
56    float pres_in[NLAT][NLON];
57    float temp_in[NLAT][NLON];
58 
59    /* For the lat lon coordinate variables. */
60    float lats_in[NLAT], lons_in[NLON];
61 
62    /* To check the units attributes. */
63    char pres_units_in[MAX_ATT_LEN], temp_units_in[MAX_ATT_LEN];
64    char lat_units_in[MAX_ATT_LEN], lon_units_in[MAX_ATT_LEN];
65 
66    /* We will learn about the data file and store results in these
67       program variables. */
68    int ndims_in, nvars_in, ngatts_in, unlimdimid_in;
69 
70    /* Loop indexes. */
71    int lat, lon;
72 
73    /* Error handling. */
74    int retval;
75 
76    /* Open the file. */
77    if ((retval = nc_open(FILE_NAME, NC_NOWRITE, &ncid)))
78       ERR(retval);
79 
80    /* There are a number of inquiry functions in netCDF which can be
81       used to learn about an unknown netCDF file. NC_INQ tells how
82       many netCDF variables, dimensions, and global attributes are in
83       the file; also the dimension id of the unlimited dimension, if
84       there is one. */
85    if ((retval = nc_inq(ncid, &ndims_in, &nvars_in, &ngatts_in,
86 			&unlimdimid_in)))
87       ERR(retval);
88 
89    /* In this case we know that there are 2 netCDF dimensions, 4
90       netCDF variables, no global attributes, and no unlimited
91       dimension. */
92    if (ndims_in != 2 || nvars_in != 4 || ngatts_in != 0 ||
93        unlimdimid_in != -1) return 2;
94 
95    /* Get the varids of the latitude and longitude coordinate
96     * variables. */
97    if ((retval = nc_inq_varid(ncid, LAT_NAME, &lat_varid)))
98       ERR(retval);
99    if ((retval = nc_inq_varid(ncid, LON_NAME, &lon_varid)))
100       ERR(retval);
101 
102    /* Read the coordinate variable data. */
103    if ((retval = nc_get_var_float(ncid, lat_varid, &lats_in[0])))
104       ERR(retval);
105    if ((retval = nc_get_var_float(ncid, lon_varid, &lons_in[0])))
106       ERR(retval);
107 
108    /* Check the coordinate variable data. */
109    for (lat = 0; lat < NLAT; lat++)
110       if (lats_in[lat] != START_LAT + 5.*lat)
111 	 return 2;
112    for (lon = 0; lon < NLON; lon++)
113       if (lons_in[lon] != START_LON + 5.*lon)
114 	 return 2;
115 
116    /* Get the varids of the pressure and temperature netCDF
117     * variables. */
118    if ((retval = nc_inq_varid(ncid, PRES_NAME, &pres_varid)))
119       ERR(retval);
120    if ((retval = nc_inq_varid(ncid, TEMP_NAME, &temp_varid)))
121       ERR(retval);
122 
123    /* Read the data. Since we know the contents of the file we know
124     * that the data arrays in this program are the correct size to
125     * hold all the data. */
126    if ((retval = nc_get_var_float(ncid, pres_varid, &pres_in[0][0])))
127       ERR(retval);
128    if ((retval = nc_get_var_float(ncid, temp_varid, &temp_in[0][0])))
129       ERR(retval);
130 
131    /* Check the data. */
132    for (lat = 0; lat < NLAT; lat++)
133       for (lon = 0; lon < NLON; lon++)
134 	 if (pres_in[lat][lon] != SAMPLE_PRESSURE + (lon * NLAT + lat) ||
135 	     temp_in[lat][lon] != SAMPLE_TEMP + .25 * (lon * NLAT + lat))
136 	    return 2;
137 
138    /* Each of the netCDF variables has a "units" attribute. Let's read
139       them and check them. */
140    if ((retval = nc_get_att_text(ncid, lat_varid, UNITS, lat_units_in)))
141       ERR(retval);
142    if (strncmp(lat_units_in, LAT_UNITS, strlen(LAT_UNITS)))
143       return 2;
144 
145    if ((retval = nc_get_att_text(ncid, lon_varid, UNITS, lon_units_in)))
146       ERR(retval);
147    if (strncmp(lon_units_in, LON_UNITS, strlen(LON_UNITS)))
148       return 2;
149 
150    if ((retval = nc_get_att_text(ncid, pres_varid, UNITS, pres_units_in)))
151       ERR(retval);
152    if (strncmp(pres_units_in, PRES_UNITS, strlen(PRES_UNITS)))
153       return 2;
154 
155    if ((retval = nc_get_att_text(ncid, temp_varid, UNITS, temp_units_in)))
156       ERR(retval);
157    if (strncmp(temp_units_in, TEMP_UNITS, strlen(TEMP_UNITS))) return 2;
158 
159    /* Close the file. */
160    if ((retval = nc_close(ncid)))
161       ERR(retval);
162 
163    printf("*** SUCCESS reading example file sfc_pres_temp.nc!\n");
164    return 0;
165 }
166