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

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

Parent Directory Parent Directory | Revision Log Revision Log


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


1 gross 1127 /*********************************************************************
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