/[escript]/trunk/escript/src/nctst.cpp
ViewVC logotype

Contents of /trunk/escript/src/nctst.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1127 - (show annotations)
Tue May 8 03:23:12 2007 UTC (13 years, 6 months ago) by gross
File size: 14434 byte(s)


1 /*********************************************************************
2 * Copyright 2005, UCAR/Unidata See COPYRIGHT file for copying and
3 * redistribution conditions.
4 *
5 * This runs the C++ tests for netCDF.
6 *
7 * $Id: nctst.cpp,v 1.27 2006/08/20 21:03:45 ed Exp $
8 *********************************************************************/
9
10 #include <config.h>
11 #include <iostream>
12 using namespace std;
13
14 #include <string.h>
15 #include "netcdfcpp.h"
16
17 const char LAT[] = "lat";
18 const char LON[] = "lon";
19 const char FRTIME[] = "frtime";
20 const char TIMELEN1[] = "timelen";
21 const char P_NAME[] = "P";
22 const char PRES_MAX_WIND[] = "pressure at maximum wind";
23 const char LONG_NAME[] = "long_name";
24 const char UNITS[] = "units";
25 const char VALID_RANGE[] = "valid_range";
26 const char FILL_VALUE[] = "_FillValue";
27 const char DEGREES_NORTH[] = "degrees_north";
28 const char LONGITUDE[] = "longitude";
29 const char LATITUDE[] = "latitude";
30 const char HECTOPASCALS[] = "hectopascals";
31 const char DEGREES_EAST[] = "degrees_east";
32 const char HOURS[] = "hours";
33 const char FORECAST_TIME[] = "forecast time";
34 const char REFERENCE_TIME[] = "reference time";
35 const char REFTIME[] = "reftime";
36 const char TEXT_TIME[] = "text_time";
37 const char SCALARV[] = "scalarv";
38 const char SCALAR_ATT[] = "scalar_att";
39 const int SCALAR_VALUE = 1;
40 const char HISTORY[] = "history";
41 const char TITLE[] = "title";
42 const char HISTORY_STR[] = "created by Unidata LDM from NPS broadcast";
43 const char TITLE_STR[] = "NMC Global Product Set: Pressure at Maximum Wind";
44
45 const int NC_ERR = 2;
46 const int NLATS = 4;
47 const int NLONS = 3;
48 const int NFRTIMES = 2;
49 const int TIMESTRINGLEN = 20;
50 const int NRANGES = 2;
51
52 // These are data values written out by the gen() function, and read
53 // in again and checked by the read() function.
54 static float range[] = {0., 1500.};
55 static float lats[NLATS] = {-90, -87.5, -85, -82.5};
56 static float lons[NLONS] = {-180, -175, -170};
57 static int frtimes[NFRTIMES] = {12, 18};
58 static const char* s = "1992-3-21 12:00";
59 static float fill_value = -9999.0;
60 static float P_data[NFRTIMES][NLATS][NLONS] = {
61 {{950, 951, 952}, {953, 954, 955}, {956, 957, 958}, {959, 960, 961}},
62 {{962, 963, 964}, {965, 966, 967}, {968, 969, 970}, {971, 972, 973}}
63 };
64
65
66 // Check a string attribute to make sure it has the correct value.
67 int
68 check_string_att(NcAtt *att, const char *theName, const char *value)
69 {
70 if (!att->is_valid() || strncmp(att->name(), theName, strlen(theName)) ||
71 att->type() != ncChar || att->num_vals() != (long)strlen(value))
72 return NC_ERR;
73
74 char *value_in = att->as_string(0);
75 if (strncmp(value_in, value, strlen(value)))
76 return NC_ERR;
77 delete value_in;
78
79 return 0;
80 }
81
82 // Check the units and long_name attributes of a var to make sure they
83 // are what is expected.
84 int
85 check_u_ln_atts(NcVar *var, const char *units, const char *long_name)
86 {
87 NcAtt *att;
88
89 if (!(att = var->get_att(UNITS)))
90 return NC_ERR;
91 if (check_string_att(att, UNITS, units))
92 return NC_ERR;
93 delete att;
94
95 if (!(att = var->get_att(LONG_NAME)))
96 return NC_ERR;
97 if (check_string_att(att, LONG_NAME, long_name))
98 return NC_ERR;
99 delete att;
100
101 return 0;
102 }
103
104 // This reads the netCDF file created by gen() and ensures that
105 // everything is there as expected.
106 int read(const char* path)
107 {
108 NcAtt *att;
109
110 // open the file
111 NcFile nc(path);
112
113 if (!nc.is_valid())
114 return 2;
115
116 // Check the numbers of things.
117 if (nc.num_dims() != 4 || nc.num_vars() != 6 ||
118 nc.num_atts() != 2)
119 return NC_ERR;
120
121 // Check the global attributes.
122 if (!(att = nc.get_att(HISTORY)))
123 return NC_ERR;
124 if (check_string_att(att, HISTORY, HISTORY_STR))
125 return NC_ERR;
126 delete att;
127
128 if (!(att = nc.get_att(TITLE)))
129 return NC_ERR;
130 if (check_string_att(att, TITLE, TITLE_STR))
131 return NC_ERR;
132 delete att;
133
134 // Check the dimensions.
135 NcDim *latDim, *lonDim, *frtimeDim, *timeLenDim;
136
137 if (!(latDim = nc.get_dim(LAT)))
138 return NC_ERR;
139 if (!latDim->is_valid() || strncmp(latDim->name(), LAT, strlen(LAT)) ||
140 latDim->size() != NLATS || latDim->is_unlimited())
141 return NC_ERR;
142
143 if (!(lonDim = nc.get_dim(LON)))
144 return NC_ERR;
145 if (!lonDim->is_valid() || strncmp(lonDim->name(), LON, strlen(LON)) ||
146 lonDim->size() != NLONS || lonDim->is_unlimited())
147 return NC_ERR;
148
149 if (!(frtimeDim = nc.get_dim(FRTIME)))
150 return NC_ERR;
151 if (!frtimeDim->is_valid() || strncmp(frtimeDim->name(), FRTIME, strlen(FRTIME)) ||
152 frtimeDim->size() != 2 || !frtimeDim->is_unlimited())
153 return NC_ERR;
154
155 if (!(timeLenDim = nc.get_dim(TIMELEN1)))
156 return NC_ERR;
157 if (!timeLenDim->is_valid() || strncmp(timeLenDim->name(), TIMELEN1, strlen(TIMELEN1)) ||
158 timeLenDim->size() != TIMESTRINGLEN || timeLenDim->is_unlimited())
159 return NC_ERR;
160
161 // Check the coordinate variables.
162 NcVar *latVar, *lonVar, *frtimeVar, *refTimeVar;
163
164 // Get the latitude.
165 if (!(latVar = nc.get_var(LAT)))
166 return NC_ERR;
167
168 // Check units and long name.
169 if (check_u_ln_atts(latVar, DEGREES_NORTH, LATITUDE))
170 return NC_ERR;
171
172 // Get the longitude.
173 if (!(lonVar = nc.get_var(LON)))
174 return NC_ERR;
175
176 // Check units and long name.
177 if (check_u_ln_atts(lonVar, DEGREES_EAST, LONGITUDE))
178 return NC_ERR;
179
180 // Get the forecast time coordinate variable.
181 if (!(frtimeVar = nc.get_var(FRTIME)))
182 return NC_ERR;
183
184 // Check units and long name.
185 if (check_u_ln_atts(frtimeVar, HOURS, FORECAST_TIME))
186 return NC_ERR;
187
188 // Get the refTime coordinate variable.
189 if (!(refTimeVar = nc.get_var(REFTIME)))
190 return NC_ERR;
191
192 // Check units and long name.
193 if (check_u_ln_atts(refTimeVar, TEXT_TIME, REFERENCE_TIME))
194 return NC_ERR;
195
196 // Check the data variables.
197 NcVar *pVar, *scalarVar;
198
199 if (!(pVar = nc.get_var(P_NAME)))
200 return NC_ERR;
201
202 // Check units and long name.
203 if (check_u_ln_atts(pVar, HECTOPASCALS, PRES_MAX_WIND))
204 return NC_ERR;
205
206 // Check the valid range, and check the values.
207 if (!(att = pVar->get_att(VALID_RANGE)))
208 return NC_ERR;
209 if (!att->is_valid() || strncmp(att->name(), VALID_RANGE, strlen(VALID_RANGE)) ||
210 att->type() != ncFloat || att->num_vals() != NRANGES)
211 return NC_ERR;
212 float range_in[NRANGES] = {att->as_float(0), att->as_float(1)};
213 if (range_in[0] != range[0] || range_in[1] != range[1])
214 return NC_ERR;
215 delete att;
216
217 // Check the fill value, and check the value.
218 if (!(att = pVar->get_att(FILL_VALUE)))
219 return NC_ERR;
220 if (!att->is_valid() || strncmp(att->name(), FILL_VALUE, strlen(FILL_VALUE)) ||
221 att->type() != ncFloat || att->num_vals() != 1)
222 return NC_ERR;
223 float fill_value_in = att->as_float(0);
224 if (fill_value_in != fill_value)
225 return NC_ERR;
226 delete att;
227
228 // Check the data in the pressure variable.
229 float P_data_in[NFRTIMES][NLATS][NLONS];
230 pVar->get(&P_data_in[0][0][0], NFRTIMES, NLATS, NLONS);
231 for (int f = 0; f < NFRTIMES; f++)
232 for (int la = 0; la < NLATS; la++)
233 for (int lo = 0; lo < NLONS; lo++)
234 if (P_data_in[f][la][lo] != P_data[f][la][lo])
235 return NC_ERR;
236
237 // Get the scalar variable.
238 if (!(scalarVar = nc.get_var(SCALARV)))
239 return NC_ERR;
240
241 // Check for the scalar attribute of the scalar variable and check its value.
242 if (!(att = scalarVar->get_att(SCALAR_ATT)))
243 return NC_ERR;
244 if (!att->is_valid() || strncmp(att->name(), SCALAR_ATT, strlen(SCALAR_ATT)) ||
245 att->type() != ncInt || att->num_vals() != 1)
246 return NC_ERR;
247 int value_in = att->as_int(0);
248 if (value_in != SCALAR_VALUE)
249 return NC_ERR;
250 delete att;
251
252 // Check the value of the scalar variable.
253
254
255 return 0;
256 }
257
258 int gen(const char* path, NcFile::FileFormat format) // Generate a netCDF file
259 {
260
261 NcFile nc(path, NcFile::Replace, NULL, 0, format); // Create, leave in define mode
262
263 // Check if the file was opened successfully
264 if (! nc.is_valid()) {
265 cerr << "can't create netCDF file " << path << "\n";
266 return NC_ERR;
267 }
268
269 // Create dimensions
270 NcDim* latd = nc.add_dim(LAT, NLATS);
271 NcDim* lond = nc.add_dim(LON, NLONS);
272 NcDim* frtimed = nc.add_dim(FRTIME); // unlimited dimension
273 NcDim* timelend = nc.add_dim(TIMELEN1, TIMESTRINGLEN);
274
275 // Create variables and their attributes
276 NcVar* P = nc.add_var(P_NAME, ncFloat, frtimed, latd, lond);
277 P->add_att(LONG_NAME, PRES_MAX_WIND);
278 P->add_att(UNITS, HECTOPASCALS);
279 P->add_att(VALID_RANGE, NRANGES, range);
280 P->add_att(FILL_VALUE, fill_value);
281
282 NcVar* lat = nc.add_var(LAT, ncFloat, latd);
283 lat->add_att(LONG_NAME, LATITUDE);
284 lat->add_att(UNITS, DEGREES_NORTH);
285
286 NcVar* lon = nc.add_var(LON, ncFloat, lond);
287 lon->add_att(LONG_NAME, LONGITUDE);
288 lon->add_att(UNITS, DEGREES_EAST);
289
290 NcVar* frtime = nc.add_var(FRTIME, ncLong, frtimed);
291 frtime->add_att(LONG_NAME, FORECAST_TIME);
292 frtime->add_att(UNITS, HOURS);
293
294 NcVar* reftime = nc.add_var(REFTIME, ncChar, timelend);
295 reftime->add_att(LONG_NAME, REFERENCE_TIME);
296 reftime->add_att(UNITS, TEXT_TIME);
297
298 NcVar* scalar = nc.add_var(SCALARV, ncInt);
299 scalar->add_att(SCALAR_ATT, SCALAR_VALUE);
300
301 // Global attributes
302 nc.add_att(HISTORY, HISTORY_STR);
303 nc.add_att(TITLE, TITLE_STR);
304
305 // Start writing data, implictly leaves define mode
306
307 lat->put(lats, NLATS);
308
309 lon->put(lons, NLONS);
310
311 frtime->put(frtimes, NFRTIMES);
312
313 reftime->put(s, strlen(s));
314
315 // We could write all P data at once with P->put(&P_data[0][0][0], P->edges()),
316 // but instead we write one record at a time, to show use of setcur().
317 long rec = 0; // start at zero-th
318 const long nrecs = 1; // # records to write
319 P->put(&P_data[0][0][0], nrecs, NLATS, NLONS); // write zero-th record
320 P->set_cur(++rec); // set to next record
321 P->put(&P_data[1][0][0], nrecs, NLATS, NLONS); // write next record
322
323 // close of nc takes place in destructor
324 return 0;
325 }
326
327 /*
328 * Convert pathname of netcdf file into name for CDL, by taking last component
329 * of path and stripping off any extension. The returned string is in static
330 * storage, so copy it if you need to keep it.
331 */
332 static char*
333 cdl_name(const char* path)
334 {
335 const char* cp = path + strlen(path);
336 while (*(cp-1) != '/' && cp != path) // assumes UNIX path separator
337 cp--;
338
339 static char np[NC_MAX_NAME];
340 strncpy(&np[0], cp, NC_MAX_NAME);
341
342 char* ep = np + strlen(np);
343 while (*ep != '.' && ep != np)
344 ep--;
345 if (*ep == '.')
346 *ep = '\0';
347 return np;
348 }
349
350 // A derived class, just like NcFile except knows how to "dump" its
351 // dimensions, variables, global attributes, and data in ASCII form.
352 class DumpableNcFile : public NcFile
353 {
354 public:
355 DumpableNcFile(const char* path, NcFile::FileMode mode = ReadOnly)
356 : NcFile(path, mode) {} ;
357 void dumpdims( void );
358 void dumpvars( void );
359 void dumpgatts( void );
360 void dumpdata( void );
361 };
362
363 void DumpableNcFile::dumpdims( void )
364 {
365
366 for (int n=0; n < num_dims(); n++) {
367 NcDim* dim = get_dim(n);
368 cout << "\t" << dim->name() << " = " ;
369 if (dim->is_unlimited())
370 cout << "UNLIMITED" << " ;\t " << "// " << dim->size() <<
371 " currently\n";
372 else
373 cout << dim->size() << " ;\n";
374 }
375 }
376
377 void dumpatts(NcVar& var)
378 {
379 NcToken vname = var.name();
380 NcAtt* ap;
381 for(int n = 0; (ap = var.get_att(n)); n++) {
382 cout << "\t\t" << vname << ":" << ap->name() << " = " ;
383 NcValues* vals = ap->values();
384 cout << *vals << " ;" << endl ;
385 delete ap;
386 delete vals;
387 }
388 }
389
390 void DumpableNcFile::dumpvars( void )
391 {
392 int n;
393 static const char* types[] =
394 {"","byte","char","short","long","float","double"};
395 NcVar* vp;
396
397 for(n = 0; (vp = get_var(n)); n++) {
398 cout << "\t" << types[vp->type()] << " " << vp->name() ;
399
400 if (vp->num_dims() > 0) {
401 cout << "(";
402 for (int d = 0; d < vp->num_dims(); d++) {
403 NcDim* dim = vp->get_dim(d);
404 cout << dim->name();
405 if (d < vp->num_dims()-1)
406 cout << ", ";
407 }
408 cout << ")";
409 }
410 cout << " ;\n";
411 // now dump each of this variable's attributes
412 dumpatts(*vp);
413 }
414 }
415
416 void DumpableNcFile::dumpgatts( void )
417 {
418 NcAtt* ap;
419 for(int n = 0; (ap = get_att(n)); n++) {
420 cout << "\t\t" << ":" << ap->name() << " = " ;
421 NcValues* vals = ap->values();
422 cout << *vals << " ;" << endl ;
423 delete vals;
424 delete ap;
425 }
426 }
427
428 void DumpableNcFile::dumpdata( )
429 {
430 NcVar* vp;
431 for (int n = 0; (vp = get_var(n)); n++) {
432 cout << " " << vp->name() << " = ";
433 NcValues* vals = vp->values();
434 cout << *vals << " ;" << endl ;
435 delete vals;
436 }
437 }
438
439 void dump(const char* path)
440 {
441 DumpableNcFile nc(path); // default is open in read-only mode
442
443 cout << "netcdf " << cdl_name(path) << " {" << endl <<
444 "dimensions:" << endl ;
445
446 nc.dumpdims();
447
448 cout << "variables:" << endl;
449
450 nc.dumpvars();
451
452 if (nc.num_atts() > 0)
453 cout << "// global attributes" << endl ;
454
455 nc.dumpgatts();
456
457 cout << "data:" << endl;
458
459 nc.dumpdata();
460
461 cout << "}" << endl;
462 }
463
464 /* Test everything for classic and 64-bit offsetfiles. If netcdf-4 is
465 * included, that means another whole round of testing. */
466 #ifdef USE_NETCDF4
467 #define NUM_FORMATS (4)
468 #else
469 #define NUM_FORMATS (2)
470 #endif
471
472 int
473 main( void ) // test new netCDF interface
474 {
475
476 cout << "*** Testing C++ API with " << NUM_FORMATS
477 << " different netCDF formats.\n";
478
479 // Set up the format constants.
480 NcFile::FileFormat format[NUM_FORMATS] = {NcFile::Classic, NcFile::Offset64Bits
481 #ifdef USE_NETCDF4
482 , NcFile::Netcdf4, NcFile::Netcdf4Classic
483 #endif
484 };
485
486 // Set up the file names.
487 char file_name[NUM_FORMATS][NC_MAX_NAME] =
488 {"nctst_classic.nc", "nctst_64bit_offset.nc"
489 #ifdef USE_NETCDF4
490 , "nctst_netcdf4.nc", "nctst_netcdf4_classic.nc"
491 #endif
492 };
493
494 int errs = 0;
495 for (int i = 0; i < NUM_FORMATS; i++)
496 {
497 if (gen(file_name[i], format[i]) ||
498 read(file_name[i]))
499 {
500 cout << "*** FAILURE with file " << file_name[i] << "\n";
501 errs++;
502 }
503 else
504 cout << "*** SUCCESS with file " << file_name[i] << "\n";
505 }
506
507 cout << "\n*** Total number of failures: " << errs << "\n";
508 if (errs)
509 cout << "*** nctst FAILURE!\n";
510 else
511 cout << "*** nctst SUCCESS!\n";
512
513 return errs;
514 }

  ViewVC Help
Powered by ViewVC 1.1.26