#include #include #include "netcdf.hh" void gen(const char *path) // Generate a netCDF file { NcNewFile nc (path, NcNewFile::Clobber); // Create, leave in define mode // Check if the file was opened successfully if (! nc.is_valid()) { cerr << "can't create netCDF file " << path << "\n"; return; } // Create dimensions const int NLATS = 4; const int NLONS = 3; const int NFRTIMES = 2; const int TIMELEN = 20; NcDim* latd = nc.add_dim("lat", NLATS); NcDim* lond = nc.add_dim("lon", NLONS); NcDim* frtimed = nc.add_dim("frtime"); // unlimited dimension NcDim* timelend = nc.add_dim("timelen", TIMELEN); // Create variables and their attributes NcVar* P = nc.add_var("P", ncFloat, frtimed, latd, lond); P->add_att("long_name", "pressure at maximum wind"); P->add_att("units", "hectopascals"); static float range[] = {0., 1500.}; P->add_att("valid_range", 2, range); P->add_att("_FillValue", -9999.0f); NcVar* lat = nc.add_var("lat", ncFloat, latd); lat->add_att("long_name", "latitude"); lat->add_att("units", "degrees_north"); NcVar* lon = nc.add_var("lon", ncFloat, lond); lon->add_att("long_name", "longitude"); lon->add_att("units", "degrees_east"); NcVar* frtime = nc.add_var("frtime", ncLong, frtimed); frtime->add_att("long_name", "forecast time"); frtime->add_att("units", "hours"); NcVar* reftime = nc.add_var("reftime",ncChar,timelend); reftime->add_att("long_name", "reference time"); reftime->add_att("units", "text_time"); NcVar* scalar = nc.add_var("scalarv", ncLong); scalar->add_att("scalar_att", 1); // Global attributes nc.add_att("history", "created by Unidata LDM from NPS broadcast"); nc.add_att("title", "NMC Global Product Set: Pressure at Maximum Wind"); // Start writing data, implictly leaves define mode float lats[NLATS] = {-90, -87.5, -85, -82.5}; lat->put(lats, NLATS); float lons[NLONS] = {-180, -175, -170}; lon->put(lons, NLONS); static long frtimes[NFRTIMES] = {12, 18}; frtime->put(frtimes, NFRTIMES); static char* s = "1992-3-21 12:00" ; reftime->put(s, strlen(s)); static float P_data[] = { 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 970, 971, 972, 973 }; // We could write all P data at once with P->put(P_data, P->edges()), // but instead we write one record at a time, to show use of setcur(). long rec = 0; // start at zero-th const long nrecs = 1; // # records to write P->put(&P_data[0], nrecs, NLATS, NLONS); // write zero-th record P->set_cur(++rec); // set to next record P->put(&P_data[NLATS*NLONS], nrecs, NLATS, NLONS); // write next record // close of nc takes place in destructor } /* * Convert pathname of netcdf file into name for CDL, by taking last component * of path and stripping off any extension. The returned string is in static * storage, so copy it if you need to keep it. */ static char * cdl_name(const char *path) { static char np[MAX_NC_NAME]; char *cp = strrchr(path, '/'); // assumes Unix pathnames if (cp) strncpy(&np[0], ++cp, MAX_NC_NAME); else strncpy(&np[0], path, MAX_NC_NAME); if (cp = strrchr(np, '.')) *cp = '\0'; return np; } // A derived class, just like NcOldFile except knows how to "dump" its // dimensions, variables, global attributes, and data in ASCII form. class DumpableNcFile : public NcOldFile { public: DumpableNcFile(const char* path) : NcOldFile(path) {} ; void dumpdims( void ); void dumpvars( void ); void dumpgatts( void ); void dumpdata( void ); }; void DumpableNcFile::dumpdims( void ) { for (int n=0; n < num_dims(); n++) { NcDim* dim = get_dim(n); cout << "\t" << dim->name() << " = " ; if (dim->is_unlimited()) cout << "UNLIMITED" << " ;\t " << "// " << dim->size() << " currently\n"; else cout << dim->size() << " ;\n"; } } void dumpatts(NcVar& var) { NcToken vname = var.name(); NcAtt *ap; for(int n = 0; ap = var.get_att(n); n++) { cout << "\t\t" << vname << ":" << ap->name() << " = " ; NcValues *vals = ap->values(); cout << *vals << " ;" << endl ; delete ap; delete vals; } } void DumpableNcFile::dumpvars( void ) { static char *typename[] = {"","byte","char","short","long","float","double"}; NcVar *vp; for(int n = 0; vp = get_var(n); n++) { cout << "\t" << typename[vp->type()] << " " << vp->name() ; if (vp->num_dims() > 0) { cout << "("; for (int d = 0; d < vp->num_dims(); d++) { NcDim* dim = vp->get_dim(d); cout << dim->name(); if (d < vp->num_dims()-1) cout << ", "; } cout << ")"; } cout << " ;\n"; // now dump each of this variable's attributes dumpatts(*vp); } } void DumpableNcFile::dumpgatts( void ) { NcAtt *ap; for(int n = 0; ap = get_att(n); n++) { cout << "\t\t" << ":" << ap->name() << " = " ; NcValues *vals = ap->values(); cout << *vals << " ;" << endl ; delete vals; delete ap; } } void DumpableNcFile::dumpdata( ) { NcVar *vp; for (int n = 0; vp = get_var(n); n++) { cout << " " << vp->name() << " = "; NcValues* vals = vp->values(); cout << *vals << " ;" << endl ; delete vals; } } void dump(const char *path) { DumpableNcFile nc(path); // opens in read-only mode cout << "netcdf " << cdl_name(path) << " {" << endl << "dimensions:" << endl ; nc.dumpdims(); cout << "variables:" << endl; nc.dumpvars(); if (nc.num_atts() > 0) cout << "// global attributes" << endl ; nc.dumpgatts(); cout << "data:" << endl; nc.dumpdata(); cout << "}" << endl; } int main( void ) // test new netCDF interface { const char* path = "example.nc"; gen(path); // create a netCDF file dump(path); // print what's in it return 0; }