# -*- coding: iso-8859-15 -*- # Python reader of ISD files ## e.g. # read_ISD.py -c '#' -f 722317-13970-2005 -d description.dat -g true -t 19491201000000,seconds -s 'Baton Rouge METRO R,30.537,-91.147,23.2' import numpy as np from optparse import OptionParser import os from netCDF4 import Dataset as NetCDFFile main = 'read_ISD.py' errormsg = 'ERROR -- error -- ERROR -- error' warnmsg = 'WARNING -- warning -- WARNING -- warning' # version version=1.1 # Filling values for floats, integer and string fillValueF = 1.e20 fillValueI = -99999 fillValueS = '---' # Length of the string variables StringLength = 200 ####### Different fixed tabuled values quality_vals = ['Passed gross limits check', 'Passed all quality control checks', \ 'Suspect', 'Erroneous', \ 'Passed gross limits check , data originate from an NCDC data source', \ 'Passed all quality control checks, data originate from an NCDC data source', \ 'Suspect, data originate from an NCDC data source', \ 'Erroneous, data originate from an NCDC data source', \ 'Passed gross limits check if element is present' ] def searchInlist(listname, nameFind): """ Function to search a value within a list listname = list nameFind = value to find >>> searInlist(['1', '2', '3', '5'], '5') True """ for x in listname: if x == nameFind: return True return False def set_attribute(ncvar, attrname, attrvalue): """ Sets a value of an attribute of a netCDF variable. Removes previous attribute value if exists ncvar = object netcdf variable attrname = name of the attribute attrvalue = value of the attribute """ import numpy as np from netCDF4 import Dataset as NetCDFFile attvar = ncvar.ncattrs() if searchInlist(attvar, attrname): attr = ncvar.delncattr(attrname) attr = ncvar.setncattr(attrname, attrvalue) return ncvar def basicvardef(varobj, vstname, vlname, vunits): """ Function to give the basic attributes to a variable varobj= netCDF variable object vstname= standard name of the variable vlname= long name of the variable vunits= units of the variable """ attr = varobj.setncattr('standard_name', vstname) attr = varobj.setncattr('long_name', vlname) attr = varobj.setncattr('units', vunits) return def remove_NONascii(string): """ Function to remove that characters which are not in the standard 127 ASCII string= string to transform >>> remove_NONascii('Lluís') Lluis """ fname = 'remove_NONascii' newstring = string RTFchar= ['á', 'é', 'í', 'ó', 'ú', 'à', 'è', 'ì', 'ò', 'ù', 'â', 'ê', 'î', 'ô', \ 'û', 'ä', 'ë', 'ï', 'ö', 'ü', 'ç', 'ñ','æ', 'œ', 'Á', 'É', 'Í', 'Ó', 'Ú', 'À', \ 'È', 'Ì', 'Ò', 'Ù', 'Â', 'Ê', 'Î', 'Ô', 'Û', 'Ä', 'Ë', 'Ï', 'Ö', 'Ü', 'Ç', 'Ñ',\ 'Æ', 'Œ', '\n', '\t'] ASCchar= ['a', 'e', 'i', 'o', 'u', 'a', 'e', 'i', 'o', 'u', 'a', 'e', 'i', 'o', \ 'u', 'a', 'e', 'i', 'o', 'u', 'c', 'n','ae', 'oe', 'A', 'E', 'I', 'O', 'U', 'A', \ 'E', 'I', 'O', 'U', 'A', 'E', 'I', 'O', 'U', 'A', 'E', 'I', 'O', 'U', 'C', 'N',\ 'AE', 'OE', '', ' '] Nchars = len(RTFchar) for ichar in range(Nchars): foundchar = string.find(RTFchar[ichar]) if foundchar != -1: newstring = newstring.replace(RTFchar[ichar], ASCchar[ichar]) return newstring def read_description(fdobs, dbg): """ reads the description file of the observational data-set fdobs= descriptive observational data-set dbg= boolean argument for debugging * Each station should have a 'description.dat' file with: institution=Institution who creates the data department=Department within the institution scientists=names of the data producers contact=contact of the data producers description=description of the observations acknowledgement=sentence of acknowlegement comment=comment for the measurements MissingValue='|' list of ASCII values for missing values within the data (as they appear!) comment=comments varN='|' list of variable names varLN='|' list of long variable names varU='|' list units of the variables varBUFR='|' list BUFR code of the variables varTYPE='|' list of variable types ('D', 'F', 'I', 'I64', 'S') varOPER='|' list of operations to do to the variables to meet their units ([oper],[val]) [oper]=-,sumc,subc,mulc,divc (nothing, add, rest, multiply and divide) varL='|' list of length of the sections for each variable within a given line (Fortran-like) NAMElon=name of the variable with the longitude (x position) NAMElat=name of the variable with the latitude (y position) NAMEheight=ind_alt NAMEtime=name of the varibale with the time FMTtime=format of the time (as in 'C', 'CFtime' for already CF-like time) """ fname = 'read_description' descobj = open(fdobs, 'r') desc = {} namevalues = [] for line in descobj: if line[0:1] != '#' and len(line) > 1 : descn = remove_NONascii(line.split('=')[0]) descv = remove_NONascii(line.split('=')[1]) namevalues.append(descn) if descn[0:3] != 'var': if descn != 'MissingValue': desc[descn] = descv else: desc[descn] = [] for dn in descv.split('|'): desc[descn].append(dn) print ' ' + fname + ': missing values found:',desc[descn] elif descn[0:3] == 'var': desc[descn] = descv.split('|') elif descn[0:4] == 'NAME': desc[descn] = descv elif descn[0:3] == 'FMT': desc[descn] = descv if dbg: Nvars = len(desc['varN']) print ' ' + fname + ": description content of '" + fdobs + "'______________" for varn in namevalues: if varn[0:3] != 'var': print ' ' + varn + ':',desc[varn] elif varn == 'varN': print ' * Variables:' for ivar in range(Nvars): varname = desc['varN'][ivar] varLname = desc['varLN'][ivar] varunits = desc['varU'][ivar] varsec = int(desc['varL'][ivar]) if desc.has_key('varBUFR'): varbufr = desc['varBUFR'][ivar] else: varbufr = None if desc['varOPER'] is not None: opv = desc['varOPER'][ivar] else: opv = None print ' ', ivar, varname+':',varLname,'[',varunits, \ ']','bufr code:',varbufr,'oper:',opv descobj.close() return desc def value_fmt(val, miss, op, fmt): """ Function to transform an ASCII value to a given format val= value to transform miss= list of possible missing values op= operation to perform to the value fmt= format to take: 'D': float double precission 'F': float 'I': integer 'I64': 64-bits integer 'S': string >>> value_fmt('9876.12', '-999', 'F') 9876.12 """ fname = 'value_fmt' aopers = ['sumc','subc','mulc','divc'] fmts = ['D', 'F', 'I', 'I64', 'S'] Nfmts = len(fmts) if not searchInlist(miss,val): if searchInlist(miss,'empty') and len(val) == 0: newval = None else: if op != '-': opern = op.split(',')[0] operv = np.float(op.split(',')[1]) if not searchInlist(aopers,opern): print errormsg print ' ' + fname + ": operation '" + opern + "' not ready!!" print ' availables:',aopers quit(-1) else: opern = 'sumc' operv = 0. if not searchInlist(fmts, fmt): print errormsg print ' ' + fname + ": format '" + fmt + "' not ready !!" quit(-1) else: if fmt == 'D': opv = np.float32(operv) if opern == 'sumc': newval = np.float32(val) + opv elif opern == 'subc': newval = np.float32(val) - opv elif opern == 'mulc': newval = np.float32(val) * opv elif opern == 'divc': newval = np.float32(val) / opv elif fmt == 'F': opv = np.float(operv) if opern == 'sumc': newval = np.float(val) + opv elif opern == 'subc': newval = np.float(val) - opv elif opern == 'mulc': newval = np.float(val) * opv elif opern == 'divc': newval = np.float(val) / opv elif fmt == 'I': opv = int(operv) if opern == 'sumc': newval = int(val) + opv elif opern == 'subc': newval = int(val) - opv elif opern == 'mulc': newval = int(val) * opv elif opern == 'divc': newval = int(val) / opv elif fmt == 'I64': opv = np.int64(operv) if opern == 'sumc': newval = np.int64(val) + opv elif opern == 'subc': newval = np.int64(val) - opv elif opern == 'mulc': newval = np.int64(val) * opv elif opern == 'divc': newval = np.int64(val) / opv elif fmt == 'S': newval = val else: newval = None return newval def writing_str_nc(varo, values, Lchar): """ Function to write string values in a netCDF variable as a chain of 1char values varo= netCDF variable object values = list of values to introduce Lchar = length of the string in the netCDF file """ Nvals = len(values) for iv in range(Nvals): if values[iv] is None: stringv = 'None' else: stringv = values[iv] charvals = np.chararray(Lchar) Lstr = len(stringv) charvals[Lstr:Lchar] = '' for ich in range(Lstr): charvals[ich] = stringv[ich:ich+1] varo[iv,:] = charvals return def Stringtimes_CF(tvals, fmt, Srefdate, tunits, dbg): """ Function to transform a given data in String formats to a CF date tvals= string temporal values fmt= format of the the time values Srefdate= reference date in [YYYY][MM][DD][HH][MI][SS] format tunits= units to use ('weeks', 'days', 'hours', 'minutes', 'seconds') dbg= debug >>> Stringtimes_CF(['19760217082712','20150213101837'], '%Y%m%d%H%M%S', '19491201000000', 'hours', False) [229784.45333333 571570.31027778] """ import datetime as dt fname = 'Stringtimes' dimt = len(tvals) yrref = int(Srefdate[0:4]) monref = int(Srefdate[4:6]) dayref = int(Srefdate[6:8]) horref = int(Srefdate[8:10]) minref = int(Srefdate[10:12]) secref = int(Srefdate[12:14]) refdate = dt.datetime( yrref, monref, dayref, horref, minref, secref) cftimes = np.zeros((dimt), dtype=np.float) Nfmt=len(fmt.split('%')) if dbg: print ' ' + fname + ': fmt=',fmt,'refdate:',Srefdate,'uits:',tunits, \ 'date dt_days dt_time deltaseconds CFtime _______' for it in range(dimt): # Removing excess of mili-seconds (up to 6 decimals) if fmt.split('%')[Nfmt-1] == 'f': tpoints = tvals[it].split('.') if len(tpoints[len(tpoints)-1]) > 6: milisec = '{0:.6f}'.format(np.float('0.'+tpoints[len(tpoints)-1]))[0:7] newtval = '' for ipt in range(len(tpoints)-1): newtval = newtval + tpoints[ipt] + '.' newtval = newtval + str(milisec)[2:len(milisec)+1] else: newtval = tvals[it] tval = dt.datetime.strptime(newtval, fmt) else: tval = dt.datetime.strptime(tvals[it], fmt) deltatime = tval - refdate deltaseconds = deltatime.days*24.*3600. + deltatime.seconds + \ deltatime.microseconds/100000. if tunits == 'weeks': deltat = 7.*24.*3600. elif tunits == 'days': deltat = 24.*3600. elif tunits == 'hours': deltat = 3600. elif tunits == 'minutes': deltat = 60. elif tunits == 'seconds': deltat = 1. else: print errormsg print ' ' + fname + ": time units '" + tunits + "' not ready !!" quit(-1) cftimes[it] = deltaseconds / deltat if dbg: print ' ' + tvals[it], deltatime, deltaseconds, cftimes[it] return cftimes def additional_vars(string): """ Function for the additional variables string: sectino of the file line which has to be evaluated """ fname = 'additional_vars' Lstring=len(string) # Generic list of additional variables '-' for range of values addvars0 = ['AA1-4', 'AB1', 'AC1', 'AD1', 'AE1', 'AG1', 'AH1-6', 'AI1-6', 'AJ1', \ 'AK1', 'AL1-4', 'AM1', 'AN1', 'AO1-4', 'AP1-4', 'HPD', 'AU1-9', 'AW1-4', \ 'AX1-6', 'AY1-2', 'AZ1-2', 'CB1-2', 'CF1-3', 'CG1-3', 'CH1-2', 'CI1', 'CN1-4', \ 'CO1-9', 'CR1', 'CT1-3', 'CU1-3', 'CV1-3', 'CW1-3', 'CX1-3', 'ED1', 'GA1-6', \ 'GE1', 'GF1', 'GG1-6', 'GH1', 'GJ1', 'GK1', 'GM1', 'GN1', 'GO1', 'GP1', 'GQ1', \ 'GR1', 'HL1', 'IA1-2', 'IB1-2', 'IC1', 'KA1-4', 'KB1-3', 'KC1-2', 'KD1-2', \ 'KE1', 'KF1', 'KG1-2', 'MA1', 'MD1', 'ME1', 'MF1', 'MG1', 'MH1', 'MK1', \ 'MV1-7', 'MW1-7', 'OA1-3', 'OB1-2', 'OC1', 'OD1-3', 'OE1-3', 'RH1-3', 'SA1', \ 'ST1', 'UA1', 'UG1-2', 'WA1', 'WD1', 'WG1', 'WJ1', 'REM', 'EQD', 'N01-99', \ 'QNN'] addvars = [] for avar in addvars0: if avar.find('-') == -1: addvars.append(avar) else: totrange=avar.split('-') erange = totrange[1] if len(erange) > 1: irange = totrange[0][1:3] else: irange = totrange[0][2:3] for ir in range(int(irange), int(erange)+1): if len(erange) > 1: addvars.append(avar[0:1] + str(ir).zfill(2)) else: addvars.append(avar[0:2] + str(ir)) # print addvars # Looking for the variables ichar=0 additionals = [] while ichar <= Lstring: sec3 = string[ichar:ichar+3] if searchInlist(addvars, sec3): additionals.append(sec3) # print ' ' , sec3, 'Additional!!' ichar = ichar + 2 ichar = ichar + 1 return additionals def read_datavalues_conline(dataf, comchar, fmt, oper, Lv, miss, varns, dbg): """ Function to read from an ASCII file values in ISH format (continuos line) dataf= data file comchar= list of the characters indicating comment in the file dbg= debug mode or not fmt= list of kind of values to be found oper= list of operations to perform Lv= length of the value section miss= missing value varns= list of name of the variables to find """ fname = 'read_datavalues_conline' ofile = open(dataf, 'r') Nvals = len(fmt) if oper is None: opers = [] for ioper in range(Nvals): opers.append('-') else: opers = oper finalvalues = {} iline = 0 for line in ofile: line = line.replace('\n','').replace(chr(13),'') Lline = len(line) if not searchInlist(comchar,line[0:1]) and len(line) > 1: # Removing no-value columns values = [] for ivar in range(Nvals): if ivar == 0: isec = 0 else: isec = int(Lv[ivar-1]) esec = int(Lv[ivar]) val = line[isec:esec] values.append(val) if dbg: print iline, varns[ivar],'value:',values[ivar],miss,opers[ivar], \ fmt[ivar] if iline == 0: listvals = [] listvals.append(value_fmt(values[ivar], miss, opers[ivar], \ fmt[ivar])) finalvalues[varns[ivar]] = listvals else: listvals = finalvalues[varns[ivar]] listvals.append(value_fmt(values[ivar], miss, opers[ivar], \ fmt[ivar])) finalvalues[varns[ivar]] = listvals # Additional variables if Lline > esec and line[esec:esec+3] == 'ADD': if iline == 0: print ' ' + fname + ': Additional variables!!' ichar=esec+3 print ' ', additional_vars(line[esec+4:Lline+1]) else: # First line without values if iline == 0: iline = -1 iline = iline + 1 ofile.close() return finalvalues def adding_station_desc(onc,stdesc): """ Function to add a station description in a netCDF file onc= netCDF object stdesc= station description lon, lat, height """ fname = 'adding_station_desc' newvar = onc.createVariable( 'station', 'c', ('StrLength')) newvar[0:len(stdesc[0])] = stdesc[0].replace('!', ' ') newdim = onc.createDimension('nst',1) newvar = objfile.createVariable( 'lonstGDM', 'c', ('nst','StrLength')) Gv = int(stdesc[1]) Dv = int((stdesc[1] - Gv)*60.) Mv = int((stdesc[1] - Gv - Dv/60.)*3600.) writing_str_nc(newvar, [str(Gv)+"d" + str(Dv)+"m" + str(Mv)+'s'], StringLength) if onc.variables.has_key('lon'): print warnmsg print ' ' + fname + ": variable 'lon' already exist !!" print " renaming it as 'lonst'" lonname = 'lonst' else: lonname = 'lon' newvar = onc.createVariable( lonname, 'f4', ('nst')) basicvardef(newvar, lonname, 'longitude', 'degrees_West' ) newvar[:] = stdesc[1] newvar = objfile.createVariable( 'latstGDM', 'c', ('nst','StrLength')) Gv = int(stdesc[2]) Dv = int((stdesc[2] - Gv)*60.) Mv = int((stdesc[2] - Gv - Dv/60.)*3600.) writing_str_nc(newvar, [str(Gv)+"d" + str(Dv)+"m" + str(Mv)+'s'], StringLength) if onc.variables.has_key('lat'): print warnmsg print ' ' + fname + ": variable 'lat' already exist !!" print " renaming it as 'latst'" latname = 'latst' else: latname = 'lat' newvar = onc.createVariable( latname, 'f4', ('nst')) basicvardef(newvar, lonname, 'latitude', 'degrees_North' ) newvar[:] = stdesc[2] if onc.variables.has_key('height'): print warnmsg print ' ' + fname + ": variable 'height' already exist !!" print " renaming it as 'heightst'" heightname = 'heightst' else: heightname = 'height' newvar = onc.createVariable( heightname, 'f4', ('nst')) basicvardef(newvar, heightname, 'height above sea level', 'm' ) newvar[:] = stdesc[3] return ####### ###### ##### #### ### ## # strCFt="Refdate,tunits (CF reference date [YYYY][MM][DD][HH][MI][SS] format and " + \ " and time units: 'weeks', 'days', 'hours', 'miuntes', 'seconds')" parser = OptionParser() parser.add_option("-c", "--comments", dest="charcom", help="':', list of characters used for comments", metavar="VALUES") parser.add_option("-d", "--descriptionfile", dest="fdesc", help="description file to use", metavar="FILE") parser.add_option("-f", "--file", dest="obsfile", help="observational file to use", metavar="FILE") parser.add_option("-g", "--debug", dest="debug", help="whther debug is required ('false', 'true')", metavar="VALUE") parser.add_option("-s", "--stationLocation", dest="stloc", help="',' list with Name, longitude, latitude and height of the station", metavar="VALUES") parser.add_option("-t", "--CFtime", dest="CFtime", help=strCFt, metavar="VALUE") (opts, args) = parser.parse_args() ####### ####### ## MAIN ####### ofile='ISD.nc' if opts.charcom is None: print warnmsg print ' ' + main + ': No list of comment characters provided!!' print ' assuming no need!' charcomments = [] else: charcomments = opts.charcom.split(':') if opts.fdesc is None: print errormsg print ' ' + main + ': No description file for the observtional data provided!!' quit(-1) if opts.obsfile is None: print errormsg print ' ' + main + ': ISD file not provided !!' quit(-1) if opts.debug is None: print warnmsg print ' ' + main + ': No debug provided!!' print " assuming 'False'" debug = False else: if opts.debug == 'true': debug = True else: debug = False if not os.path.isfile(opts.fdesc): print errormsg print ' ' + main + ": description file '" + opts.fdesc + "' does not exist !!" quit(-1) if not os.path.isfile(opts.obsfile): print errormsg print ' ' + main + ": observational file '" + opts.obsfile + "' does not exist !!" quit(-1) if opts.CFtime is None: print warnmsg print ' ' + main + ': No CFtime criteria are provided !!' print " either time is already in CF-format ('timeFMT=CFtime') in '" + \ opts.fdesc + "'" print " or assuming refdate: '19491201000000' and time units: 'hours'" referencedate = '19491201000000' timeunits = 'hours' else: referencedate = opts.CFtime.split(',')[0] timeunits = opts.CFtime.split(',')[1] if opts.stloc is None: print errornmsg print ' ' + main + ': No station location provided !!' quit(-1) else: print opts.stloc.split(',') stationdesc = [opts.stloc.split(',')[0], np.float(opts.stloc.split(',')[1]), \ np.float(opts.stloc.split(',')[2]), np.float(opts.stloc.split(',')[3])] # Reading description file ## description = read_description(opts.fdesc, debug) Nvariables=len(description['varN']) formats = description['varTYPE'] if len(formats) != Nvariables: print errormsg print ' ' + main + ': number of formats:',len(formats),' and number of ' + \ 'variables', Nvariables,' does not coincide!!' print ' * what is found is _______' if Nvariables > len(formats): Nshow = len(formats) for ivar in range(Nshow): print ' ',description['varN'][ivar],':', description['varLN'][ivar],\ '[', description['varU'][ivar], '] fmt:', formats[ivar] print ' missing values for:', description['varN'][Nshow:Nvariables+1] else: Nshow = Nvariables for ivar in range(Nshow): print ' ',description['varN'][ivar],':', description['varLN'][ivar],\ '[', description['varU'][ivar], '] fmt:', formats[ivar] print ' excess of formats for:', formats[Nshow:len(formats)+1] quit(-1) # Reading values ## datavalues = read_datavalues_conline(opts.obsfile, charcomments, formats, \ description['varOPER'], description['varL'], description['MissingValue'], \ description['varN'], debug) # Total number of values Ntvalues = len(datavalues[description['varN'][0]]) print main + ': total temporal values found:',Ntvalues objfile = NetCDFFile(ofile, 'w') # Creation of dimensions ## objfile.createDimension('time',None) objfile.createDimension('StrLength',StringLength) # Creation of variables ## for ivar in range(Nvariables): varn = description['varN'][ivar] print " including: '" + varn + "' ... .. ." if formats[ivar] == 'D': newvar = objfile.createVariable(varn, 'f32', ('time'), fill_value=fillValueF) basicvardef(newvar, varn, description['varLN'][ivar], \ description['varU'][ivar]) vals = np.array(datavalues[varn]) for iv in range(Ntvalues): if vals[iv] is None: vals[iv] = fillValueF newvar[:] = vals # newvar[:] = np.where(datavalues[varn] is None, fillValueF, datavalues[varn]) elif formats[ivar] == 'F': newvar = objfile.createVariable(varn, 'f', ('time'), fill_value=fillValueF) basicvardef(newvar, varn, description['varLN'][ivar], \ description['varU'][ivar]) vals = np.array(datavalues[varn]) for iv in range(Ntvalues): if vals[iv] is None: vals[iv] = fillValueF newvar[:] = vals # newvar[:] = np.where(datavalues[varn] is None, fillValueF, datavalues[varn]) elif formats[ivar] == 'I': newvar = objfile.createVariable(varn, 'i', ('time'), fill_value=fillValueI) basicvardef(newvar, varn, description['varLN'][ivar], \ description['varU'][ivar]) # Why is not wotking with integers? vals = np.array(datavalues[varn]) for iv in range(Ntvalues): if vals[iv] is None: vals[iv] = fillValueI newvar[:] = vals elif formats[ivar] == 'S': newvar = objfile.createVariable(varn, 'c', ('time','StrLength')) basicvardef(newvar, varn, description['varLN'][ivar], \ description['varU'][ivar]) writing_str_nc(newvar, datavalues[varn], StringLength) # Time variable in CF format ## if description['FMTtime'] == 'CFtime': timevals = datavalues[description['NAMEtime']] iv = 0 for ivn in description['varN']: if ivn == description['NAMEtime']: tunits = description['varU'][iv] break iv = iv + 1 else: # Time as a composition of different columns tcomposite = description['NAMEtime'].find('@') if tcomposite != -1: timevars = description['NAMEtime'].split('@') print warnmsg print ' ' + main + ': time values as combination of different columns!' print ' combining:',timevars,' with a final format: ',description['FMTtime'] timeSvals = [] if debug: print ' ' + main + ': creating times _______' for it in range(Ntvalues): tSvals = '' for tvar in timevars: tSvals = tSvals + datavalues[tvar][it] + ' ' timeSvals.append(tSvals[0:len(tSvals)-1]) if debug: print it, '*' + timeSvals[it] + '*' timevals = Stringtimes_CF(timeSvals, description['FMTtime'], referencedate, \ timeunits, debug) else: timevals = Stringtimes_CF(datavalues[description['NAMEtime']], \ description['FMTtime'], referencedate, timeunits, debug) CFtimeRef = referencedate[0:4] +'-'+ referencedate[4:6] +'-'+ referencedate[6:8] + \ ' ' + referencedate[8:10] +':'+ referencedate[10:12] +':'+ referencedate[12:14] tunits = timeunits + ' since ' + CFtimeRef if objfile.variables.has_key('time'): print warnmsg print ' ' + main + ": variable 'time' already exist !!" print " renaming it as 'CFtime'" timeCFname = 'CFtime' newdim = objfile.renameDimension('time','CFtime') newvar = objfile.createVariable( timeCFname, 'f8', ('CFtime')) basicvardef(newvar, timeCFname, 'time', tunits ) else: timeCFname = 'time' newvar = objfile.createVariable( timeCFname, 'f8', ('time')) basicvardef(newvar, timeCFname, 'time', tunits ) set_attribute(newvar, 'calendar', 'standard') newvar[:] = timevals # Global attributes ## for descn in description.keys(): if descn[0:3] != 'var' and descn[0:4] != 'NAME' and descn[0:3] != 'FMT': string='' for sval in description[descn]: string = string + str(sval) + ', ' set_attribute(objfile, descn, string) set_attribute(objfile,'author_nc','Lluis Fita') set_attribute(objfile,'institution_nc','Laboratoire de Meteorology Dynamique, ' + \ 'LMD-Jussieu, UPMC, Paris') set_attribute(objfile,'country_nc','France') set_attribute(objfile,'script_nc',main) set_attribute(objfile,'version_script',version) # Adding three variables with the station name, location, longitude, latitude and height adding_station_desc(objfile,stationdesc) objfile.sync() objfile.close() print main + ": Successfull generation of netcdf observational file '" + ofile + "' !!"