#!/mbari/LRAUV/oavenv/bin/python from netCDF4 import Dataset def nc4tonc3(filename4,filename3,clobber=False,nchunk=10,quiet=False,format='NETCDF3_64BIT'): """convert a netcdf 4 file (filename4) in NETCDF4_CLASSIC format to a netcdf 3 file (filename3) in NETCDF3_64BIT format.""" ncfile4 = Dataset(filename4,'r') if ncfile4.file_format != 'NETCDF4_CLASSIC': raise IOError('input file must be in NETCDF4_CLASSIC format') ncfile3 = Dataset(filename3,'w',clobber=clobber,format=format) # create dimensions. Check for unlimited dim. unlimdimname = False unlimdim = None # create global attributes. if not quiet: sys.stdout.write('copying global attributes ..\n') #for attname in ncfile4.ncattrs(): # setattr(ncfile3,attname,getattr(ncfile4,attname)) ncfile3.setncatts(ncfile4.__dict__) if not quiet: sys.stdout.write('copying dimensions ..\n') for dimname,dim in ncfile4.dimensions.items(): if dim.isunlimited(): unlimdimname = dimname unlimdim = dim ncfile3.createDimension(dimname,None) else: ncfile3.createDimension(dimname,len(dim)) # create variables. for varname,ncvar in ncfile4.variables.items(): if not quiet: sys.stdout.write('copying variable %s\n' % varname) # is there an unlimited dimension? if unlimdimname and unlimdimname in ncvar.dimensions: hasunlimdim = True else: hasunlimdim = False if hasattr(ncvar, '_FillValue'): FillValue = ncvar._FillValue else: FillValue = None var = ncfile3.createVariable(varname,ncvar.dtype,ncvar.dimensions,fill_value=FillValue) # fill variable attributes. attdict = ncvar.__dict__ if '_FillValue' in attdict: del attdict['_FillValue'] var.setncatts(attdict) #for attname in ncvar.ncattrs(): # if attname == '_FillValue': continue # setattr(var,attname,getattr(ncvar,attname)) # fill variables with data. if hasunlimdim: # has an unlim dim, loop over unlim dim index. # range to copy if nchunk: start = 0; stop = len(unlimdim); step = nchunk if step < 1: step = 1 for n in range(start, stop, step): nmax = n+nchunk if nmax > len(unlimdim): nmax=len(unlimdim) var[n:nmax] = ncvar[n:nmax] else: var[0:len(unlimdim)] = ncvar[:] else: # no unlim dim or 1-d variable, just copy all data at once. var[:] = ncvar[:] ncfile3.sync() # flush data to disk # close files. ncfile3.close() ncfile4.close() if __name__ == '__main__': import sys, getopt, os usage = """ Convert a netCDF 4 file (in NETCDF4_CLASSIC format) to netCDF 3 format. usage: %s [-h] [-o] [--chunk] netcdf4filename netcdf3filename -h -- Print usage message. -o -- Overwite destination file (default is to raise an error if output file already exists). --quiet=(0|1) -- if 1, don't print diagnostic information. --format -- netcdf3 format to use (NETCDF3_64BIT by default, can be set to NETCDF3_CLASSIC) --chunk=(integer) -- number of records along unlimited dimension to write at once. Default 10. Ignored if there is no unlimited dimension. chunk=0 means write all the data at once. \n""" % os.path.basename(sys.argv[0]) try: opts, pargs = getopt.getopt(sys.argv[1:], 'ho', ['format=','chunk=','quiet=']) except: (type, value, traceback) = sys.exc_info() sys.stdout.write("Error parsing the options. The error was: %s\n" % value) sys.stderr.write(usage) sys.exit(0) # default options quiet = 0 chunk = 1000 format = 'NETCDF3_64BIT' overwritefile = 0 # Get the options for option in opts: if option[0] == '-h': sys.stderr.write(usage) sys.exit(0) elif option[0] == '-o': overwritefile = 1 elif option[0] == '--quiet': quiet = int(option[1]) elif option[0] == '--format': format = option[1] elif option[0] == '--chunk': chunk = int(option[1]) else: sys.stdout.write("%s : Unrecognized option\n" % options[0]) sys.stderr.write(usage) sys.exit(0) # if we pass a number of files different from 2, abort if len(pargs) < 2 or len(pargs) > 2: sys.stdout.write("You need to pass both source and destination!\n.") sys.stderr.write(usage) sys.exit(0) # Catch the files passed as the last arguments filename4 = pargs[0] filename3 = pargs[1] # copy the data from filename4 to filename3. nc4tonc3(filename4,filename3,clobber=overwritefile,quiet=quiet,format=format)