wrfout  0.0-0.dev0.dirty.el6
 All Data Structures Files Functions Variables Typedefs Enumerations Groups
wrfout_read_data.c
Go to the documentation of this file.
1 /******************************************************************************
2 *
3 * Author:
4 * name: Brian Ermold
5 * phone: 509-375-2277
6 * email: brian.ermold@pnnl.gov
7 *
8 ******************************************************************************/
9 
10 /** @file wrfout_read_data.c
11  * WRFOUT Read Data Functions.
12  */
13 
14 #include "wrfout_ingest.h"
15 
16 /**
17  * Read the global attributes from a raw WRFOUT file into the output dataset.
18  *
19  * If an error occurs in this function it will be appended to the log and
20  * error mail messages, and the process status will be set appropriately.
21  *
22  * @param ncid Id of the open NetCDF file.
23  * @param wrfout pointer to the output dataset.
24  *
25  * @retval 1 if successful
26  * @retval 0 if a fatal error occurred
27  */
28 int wrfout_read_global_atts(int ncid, CDSGroup *wrfout)
29 {
30  int ai;
31  CDSAtt *att;
32  nc_type att_type;
33  size_t att_length;
34  int status;
35 
36  /* Loop over global attributes in the output dataset */
37 
38  for (ai = 0; ai < wrfout->natts; ++ai) {
39 
40  att = wrfout->atts[ai];
41 
42  /* Skip atts that already have a value defined */
43 
44  if (att->length) continue;
45 
46  /* Get the data type and length of the attribute in the input file */
47 
48  status = ncds_inq_att(
49  ncid, NC_GLOBAL, att->name, &att_type, &att_length);
50 
51  if (status == -1) {
52  DSPROC_ERROR( NULL,
53  "Could not get '%s' attribute from input NetCDF file\n",
54  att->name);
55  return(0);
56  }
57 
58  /* Skip attributes that aren't found or do not have a value
59  * in the input file. */
60 
61  if (status == 0 || att_length == 0) {
62  continue;
63  }
64 
65  /* Allocate memory for the attribute value. */
66 
67  status = cds_set_att_value(att, att->type, att_length, NULL);
68  if (!status) {
69  DSPROC_ERROR( NULL,
70  "Could not allocate memory for '%s' attribute value\n",
71  att->name);
72  return(0);
73  }
74 
75  /* Read in the attribute value. */
76 
77  switch (att->type) {
78  case CDS_BYTE:
79  status = nc_get_att_schar(ncid, NC_GLOBAL, att->name, att->value.bp);
80  break;
81  case CDS_CHAR:
82  status = nc_get_att_text(ncid, NC_GLOBAL, att->name, att->value.cp);
83  break;
84  case CDS_SHORT:
85  status = nc_get_att_short(ncid, NC_GLOBAL, att->name, att->value.sp);
86  break;
87  case CDS_INT:
88  status = nc_get_att_int(ncid, NC_GLOBAL, att->name, att->value.ip);
89  break;
90  case CDS_FLOAT:
91  status = nc_get_att_float(ncid, NC_GLOBAL, att->name, att->value.fp);
92  break;
93  case CDS_DOUBLE:
94  status = nc_get_att_double(ncid, NC_GLOBAL, att->name, att->value.dp);
95  break;
96  default:
97  DSPROC_ERROR( NULL,
98  "Could not get netcdf attribute value for: %s\n"
99  " -> invalid CDSDataType in output dataset\n",
100  att->name, nc_strerror(status));
101  return(0);
102  }
103 
104  if (status != NC_NOERR) {
105  DSPROC_ERROR( NULL,
106  "Could not get netcdf attribute value for: %s\n"
107  " -> %s\n",
108  att->name, nc_strerror(status));
109  return(0);
110  }
111  }
112 
113  return(1);
114 }
115 
116 /**
117  * Read the data from a raw WRFOUT data file into the output dataset.
118  *
119  * If an error occurs in this function it will be appended to the log and
120  * error mail messages, and the process status will be set appropriately.
121  *
122  * @param data pointer to the UserData structure
123  *
124  * @retval nsamples number of data records read in
125  * @retval 0 if this is a bad file
126  * @retval -1 if a fatal error occurred
127  */
129 {
130  CDSGroup *wrfout = data->out_ds;
131  CDSGroup *wrfin = (CDSGroup *)NULL;
132  int ncid = 0;
133  time_t *times = (time_t *)NULL;
134 
135  char full_path[PATH_MAX];
136  size_t nsamples;
137  CDSVar *time_var;
138  time_t base_time;
139  float *minutes;
140  size_t ti;
141 
142  CDSVar *out_var;
143  CDSVar *in_var;
144  char in_var_name[NC_MAX_NAME];
145  char *chrp;
146  size_t count;
147  int status;
148  int vi;
149 
150  /************************************************************
151  * Open the input NetCDF file.
152  *************************************************************/
153 
154  DSPROC_DEBUG_LV1("Reading file: %s\n", data->file_name);
155 
156  snprintf(full_path, PATH_MAX, "%s/%s", data->input_dir, data->file_name);
157 
158  /* Open the NetCDF file */
159 
160  if (!ncds_open(full_path, NC_NOWRITE, &ncid)) {
161  DSPROC_ERROR( NULL,
162  "Could not open input NetCDF file: %s\n", full_path);
163  goto ERROR_EXIT;
164  }
165 
166  /* Create a new CDS group for the input dataset */
167 
168  wrfin = cds_define_group(NULL, data->file_name);
169  if (!wrfin) {
170  DSPROC_ERROR( NULL,
171  "Could not create input dataset for: %s\n", full_path);
172  goto ERROR_EXIT;
173  }
174 
175  /************************************************************
176  * Copy times from the input dataset to the output dataset.
177  *************************************************************/
178 
179  DSPROC_DEBUG_LV1("Reading time values from: %s\n", wrfin->name);
180 
181  /* Read in the "XTIME" variable from the input dataset.
182  * The XTIME variable contains the time in minutes since
183  * a reference time. */
184 
185  nsamples = 0;
186  time_var = ncds_get_var(ncid, "XTIME", 0, &nsamples, wrfin,
187  NULL, 0, NULL, 0, 0, NULL, NULL, NULL, NULL);
188 
189  if (!time_var) {
190  DSPROC_ERROR( NULL,
191  "Could not get 'XTIME' variable from: %s\n", full_path);
192  goto ERROR_EXIT;
193  }
194 
195  /* Unfortunately the dsproc_get_sample_times function is not properly
196  * handling times that are not in seconds, so we need to get the reference
197  * time from the units string and add the minute offsets to it. On a
198  * positve note the dsproc_get_base_time function does work properly to
199  * get the reference time from the units string. */
200 
201  /* Get the base time from the units string. */
202 
203  base_time = dsproc_get_base_time(time_var);
204  if (!base_time) {
205  DSPROC_ERROR( NULL,
206  "Could not get base time from 'XTIME' units string in file: %s\n",
207  full_path);
208  goto ERROR_EXIT;
209  }
210 
211  /* Get minutes since base_time */
212 
213  minutes = dsproc_get_var_data_index(time_var);
214  if (!minutes) {
215  goto ERROR_EXIT;
216  }
217 
218  /* Allocate memory for times converted to seconds since 1970 */
219 
220  times = (time_t *)malloc(nsamples * sizeof(time_t));
221  if (!times) {
222  DSPROC_ERROR( NULL,
223  "Could not allocated memory for time data\n");
224  goto ERROR_EXIT;
225  }
226 
227  /* Convert times to seconds since 1970 */
228 
229  for (ti = 0; ti < nsamples; ++ti) {
230  times[ti] = base_time + (time_t)(minutes[ti] * 60);
231  }
232 
233  /* Set times in output dataset */
234 
235  DSPROC_DEBUG_LV1("Setting time values in output dataset: %s\n",
236  wrfout->name);
237 
238  if (!dsproc_set_sample_times(wrfout, 0, nsamples, times)) {
239  return(-1);
240  }
241 
242  /* Set begin and end times used when renaming raw file */
243 
244  data->begin_time = times[0];
245  data->end_time = times[nsamples-1];
246 
247  /************************************************************
248  * Copy across dimension lengths.
249  *************************************************************/
250 
251  DSPROC_DEBUG_LV1("Reading dimension lengths from: %s\n", wrfin->name);
252 
253  if (ncds_read_dims(ncid, wrfin) < 0) {
254  DSPROC_ERROR( NULL,
255  "Could not read dimensions from: %s\n", full_path);
256  goto ERROR_EXIT;
257  }
258 
259  /* This will set the dimension lengths for all dimensions defined
260  * in the output dataset that are also found in the input dataset. */
261 
262  DSPROC_DEBUG_LV1("Setting dimension lengths in output dataset: %s\n",
263  wrfout->name);
264 
265  if (!cds_copy_dims(wrfin, wrfout, NULL, NULL, CDS_EXCLUSIVE)) {
266  DSPROC_ERROR( NULL,
267  "Could not copy dimensions to output dataset\n");
268  goto ERROR_EXIT;
269  }
270 
271  /************************************************************
272  * Copy across global attributes.
273  *************************************************************/
274 
275  DSPROC_DEBUG_LV1("Reading global attributes from: %s\n", wrfin->name);
276 
277  /* The input NetCDF file uses the int64 data type for some of its
278  * global attributes so we can't use the ncds_read_atts and
279  * cds_copy_atts functions (these only support the netcdf classic model).
280  * Instead we need to use the core NetCDF functions. */
281 
282  if (!wrfout_read_global_atts(ncid, wrfout)) {
283  goto ERROR_EXIT;
284  }
285 
286  /************************************************************
287  * Copy data from the input dataset to the output dataset.
288  *************************************************************/
289 
290  DSPROC_DEBUG_LV1("Copying across variable data and attribute values:\n");
291 
292  /* Loop over variables in the output dataset.
293  * Skip the first three time variables. */
294 
295  for (vi = 3; vi < wrfout->nvars; ++vi) {
296 
297  out_var = wrfout->vars[vi];
298 
299  if (strcmp(out_var->name, "lon") == 0) {
300  strcpy(in_var_name, "XLONG");
301  }
302  else if (strcmp(out_var->name, "lat") == 0) {
303  strcpy(in_var_name, "XLAT");
304  }
305  else {
306  /* All other input variables have the same name as the output
307  * variable converted to uppercase. */
308 
309  strcpy(in_var_name, out_var->name);
310  for (chrp = in_var_name; *chrp; ++chrp) *chrp = toupper(*chrp);
311  }
312 
313  /* Read in the input variable, along with it's attributes */
314 
315  count = 0;
316  in_var = ncds_get_var(ncid, in_var_name, 0, &count, wrfin,
317  NULL, 0, NULL, 0, 0, NULL, NULL, NULL, NULL);
318 
319  if (!in_var) {
320  DSPROC_ERROR( NULL,
321  "Could not get the '%s' variable from: %s\n",
322  in_var_name, full_path);
323  goto ERROR_EXIT;
324  }
325 
326  /* Copy the input variable data to the output variable.
327  * This will also copy across the attibute values for attributes
328  * that are also defined in the output variable and do not already
329  * have a value defined. */
330 
331  DSPROC_DEBUG_LV1(" - %s -> %s\n", in_var_name, out_var->name);
332 
333  status = cds_copy_var(
334  in_var, wrfout, out_var->name,
335  NULL, NULL, NULL, NULL,
336  0, 0, 0, CDS_EXCLUSIVE, NULL);
337 
338  if (status < 0) {
339  DSPROC_ERROR( NULL,
340  "Could not copy input variable '%s' to output variable '%s'\n",
341  in_var_name, out_var->name);
342  goto ERROR_EXIT;
343  }
344 
345  /* Free up the memory used by the input variable */
346 
347  cds_delete_var(in_var);
348  }
349 
350  /* Cleanup and exit */
351 
352  ncds_close(ncid);
353  cds_delete_group(wrfin);
354  free(times);
355 
356  return(nsamples);
357 
358 ERROR_EXIT:
359 
360  /* Never ever use goto statements... unless it is to cleanup and exit
361  * from a function that has multiple exit points that all need to do
362  * the same cleanup before exiting. */
363 
364  if (ncid) ncds_close(ncid);
365  if (wrfin) cds_delete_group(wrfin);
366  if (times) free(times);
367 
368  return(-1);
369 }