def check_dependencies(self): self._check_import("netCDF4") from netCDF4 import getlibversion version = StrictVersion(getlibversion().split(" ")[0]) if version < StrictVersion("4.5"): raise ImportError("netCDF4 library must be at least version 4.5")
def software_stack(): """ Import all the hard dependencies. Returns a dict with the version. """ # Mandatory import numpy, scipy d = dict( numpy=numpy.version.version, scipy=scipy.version.version, ) # Optional but strongly suggested. try: import netCDF4, matplotlib d.update(dict( netCDF4=netCDF4.getlibversion(), matplotlib="Version: %s, backend: %s" % (matplotlib.__version__, matplotlib.get_backend()), )) except ImportError: pass # Optional (GUIs). try: import wx d["wx"] = wx.version() except ImportError: pass return d
def check_dependencies(self): # noqa: D102 self._check_import("netCDF4") from netCDF4 import getlibversion version = StrictVersion(getlibversion().split(" ")[0]) if version < StrictVersion("4.5"): raise ImportError("netCDF4 library must be at least version 4.5")
def software_stack(): """ Import all the hard dependencies. Returns a dict with the version. """ # Mandatory import numpy, scipy d = dict( numpy=numpy.version.version, scipy=scipy.version.version, ) # Optional but strongly suggested. try: import netCDF4, matplotlib d.update( dict( netCDF4=netCDF4.getlibversion(), matplotlib="Version: %s, backend: %s" % (matplotlib.__version__, matplotlib.get_backend()), )) except ImportError: pass # Optional (GUIs). try: import wx d["wx"] = wx.version() except ImportError: pass return d
def _ncversion(v=None): """Return the netCDF C library version. If v is None the full version number string is returned. If v is a full version number string the [major].[minor] number is returned as float""" if v is None: return str(netCDF4.getlibversion()).split()[0] # Full string version v = v.split('.') if len(v) == 1: v.append('0') return float('.'.join(v[0:2])) # [major].[minor] number as a float
def test_netcdf(): import netCDF4 as nc from birdy.client.converters import Netcdf4Converter, JSONConverter # Xarray is the default converter. Use netCDF4 here. if nc.getlibversion() > "4.5": m = WPSClient(url=url, processes=["output_formats"], converters=[Netcdf4Converter, JSONConverter]) ncdata, jsondata = m.output_formats().get(asobj=True) assert isinstance(ncdata, nc.Dataset) ncdata.close() assert isinstance(jsondata, dict)
def _show_system_info(self): super(MDTrajTester, self)._show_system_info() print('mdtraj version %s' % mdtraj.version.version) print('mdtraj is installed in %s' % os.path.dirname(mdtraj.__file__)) try: import tables print('tables version %s' % tables.__version__) print('tables hdf5 version %s' % tables.hdf5Version) except ImportError: print('tables is not installed') try: import netCDF4 print('netCDF4 version %s' % netCDF4.__version__) print('netCDF4 lib version %s' % netCDF4.getlibversion()) except ImportError: print('netCDF4 not installed')
def bulk2ncCanada(buoyFld, buoyId, verbose=True): ''' Code to convert bulk parameter text files from Peches et Oceans Canada into netcdf file. Usage: ------ bulk2ncCanada(buoyfld,buoyid,verbose) Input: ------ buoyfld = Folder where the bulk paramerter text files reside. buoyid = Netcdf buoy identifier (to figure out the file names) verbose = some extra information (True is default) Notes: Only the bulk parameter files must be present in that directory. The code is not smart enough (and I do not have the time to make it so) to figure out the bulk parameter files. ''' #=========================================================================== # Read and Clean Up Data #=========================================================================== # Dictionary translating from Canadian to US varNames = { 'VCAR': 'WVHT', 'VTPK': 'DPD', 'GSPD': 'GST', 'SSTP': 'WTMP', 'DATE': 'wave_time' } # They provide just one file archivo = buoyFld + '/c' + buoyId + '.csv' # Get the variable keys fobj = open(archivo) # Get variable names varkeys = fobj.readline().rstrip()[:-1].split(',') # Translate variables for aa in range(len(varkeys)): if varkeys[aa] in varNames: varkeys[aa] = varNames[varkeys[aa]] # Create netcdf file ------------------------------------------------------- nc = netCDF4.Dataset(buoyFld + '/' + buoyId + '.nc', 'w', format='NETCDF4') nc.Description = buoyId + ' Environment Canada Bulk Parameter Data' nc.rawdata = ( 'Fisheries and Oceans Canada\n' + 'http://www.meds-sdmm.dfo-mpo.gc.ca/isdm-gdsi/waves-vagues/index-eng.htm' ) nc.Created = time.ctime() nc.Software = 'Created with Python ' + sys.version nc.NetCDF_Lib = str(netCDF4.getlibversion()) nc.Script = os.path.realpath(__file__) # Create dimensions nc.createDimension('wave_time', None) # Create netcdf variables def create_nc_var(name, dimensions, units=None, longname=None): nc.createVariable(name, 'f8', dimensions) if units is not None: nc.variables[name].units = units if longname is not None: nc.variables[name].long_name = longname # Create NetCDF variables create_nc_var('wave_time', 'wave_time', 'seconds since 1900-01-01 00:00:00', 'measurement time UTC') if 'Q_FLAG' in varkeys: create_nc_var( 'Q_FLAG', 'wave_time', '', 'Quality Codes\n' + '0: No quality control has been performed\n' + '1: Good - QC has been performed: record appears correct\n' + '3: Doubtful - QC has been performed\n' + '4: Erroneous - QU has been performed\n' + '5: Changes - The record has been changed as a result of QC\n' + '6: Acceptable - QC has been performed: record seems ' + 'inconsistent with other records\n' + '7: Off Position - There is a problem with the buoy ' + 'position or mooring. Data may steel be useful') if 'LATITUDE' in varkeys: create_nc_var('LATITUDE', 'wave_time', 'degrees', 'Latitude') if 'LONGITUDE' in varkeys: create_nc_var('LONGITUDE', 'wave_time', 'degrees', 'Longitude') if 'DEPTH' in varkeys: create_nc_var('DEPTH', 'wave_time', 'meter', 'water depth') if 'WVHT' in varkeys: create_nc_var( 'WVHT', 'wave_time', 'meter', 'Significant wave height during the 20 minute sampling period') if 'DPD' in varkeys: create_nc_var( 'DPD', 'wave_time', 'second', 'Dominant wave period (period with the maximum wave energy)') if r'VWH$' in varkeys: create_nc_var('VWH$', 'wave_time', 'meter', 'Significant wave height (reported by the buoy)') if 'VCMX' in varkeys: create_nc_var('VCMX', 'wave_time', 'meter', 'Maximum zero crossing wave height (reported by buoy)') if r'VTP$' in varkeys: create_nc_var('VTP$', 'wave_time', 'second', 'Wave spectrum peak period (reported by the buoy)') if 'WDIR' in varkeys: create_nc_var( 'WDIR', 'wave_time', 'degrees', 'Wind direction (direction the wind is coming from in ' + 'degrees clockwise from true North') if 'WSPD' in varkeys: create_nc_var('WSPD', 'wave_time', 'meter second-1', 'Horizontal wind speed') if r'WSS$' in varkeys: create_nc_var('WSS$', 'wave_time', 'meter second-1', 'Horizontal scalar wind speed') if 'GST' in varkeys: create_nc_var('GST', 'wave_time', 'meter second-1', 'Gust wind speed') if 'ATMS' in varkeys: create_nc_var('ATMS', 'wave_time', 'mbar', 'Atmospheric pressure at sea level') if 'DRYT' in varkeys: create_nc_var('DRYT', 'wave_time', 'Celsius', 'Dry bulb temperature') if 'WTMP' in varkeys: create_nc_var('WTMP', 'wave_time', 'Celsius', 'Sea surface temperature') if 'ATMS1' in varkeys: create_nc_var('ATMS1', 'wave_time', 'mbar', 'Atmospheric pressure at sea level') if 'WSPD1' in varkeys: create_nc_var('WSPD1', 'wave_time', 'meter second-1', 'Horizontal wind speed') # Load wave data ---------------------------------------------- cnt = -1 # Counter variable for storing to file # Read line by line for tmpline in fobj: # Counter variable for NetCDF4 storage cnt += 1 # Parse input line tmpline = tmpline.rstrip().split(',') # Process time file # Datetime object tmptime = datetime.datetime.strptime(tmpline[1], '%m/%d/%Y %H:%M') # Seconds since 20th Century sectime = tmptime - datetime.datetime(1900, 1, 1, 0, 0, 0) secsecs = sectime.total_seconds() # Write to file nc['wave_time'][cnt] = secsecs # Write the rest of the variables for aa in range(2, len(varkeys)): try: tmpvar = np.float(tmpline[aa]) except: tmpvar = -99.0 nc[varkeys[aa]][cnt] = tmpvar # Close files fobj.close() nc.close()
def spec2nc(buoyfld, dtheta=5): ''' Code to convert NDBC spectral data files to netCDF format. Usage: ------ spec2nc(buoyfld,dtheta) Input: ------ buoyfld : Folder where the text files reside. Those should be the only files in the folder. dtheta : Directional resolution for the reconstruction of the frequency- direction spectrum. Defaults to 5 degrees. Notes: 1. NetCDF4 file will be generated 2. Code is not optimized since this is not something you will want to be running often. Beware of slow performance for large datasets. References: Kuik, A.J., G.Ph. van Vledder, and L.H. Holthuijsen, 1998: "Method for the Routine Analysis of Pitch-and-Roll Buoy Wave Data", Journal of Physical Oceanography, 18, 1020-1034. TODO: - Only works with newer formats (YY MM DD hh mm) - Fix negative energy (the fix is in the code just incorporate) ''' # For testing only --------------------------------------------------------- #buoyfld = '/home/shusin2/users/ggarcia/data/wave/b46029/spec/' #dtheta = 20 # -------------------------------------------------------------------------- # Construct directional angle angles = np.arange(0.0, 360.0, dtheta) # Time reference basetime = datetime.datetime(1900, 1, 1, 0, 0, 0) #=========================================================================== # Read file information #=========================================================================== # Get all files in folder archivos = glob.glob(buoyfld + '/*.txt') archivos = [x.split('/')[-1] for x in archivos] # Year information years = [x.split('.')[0][-4:] for x in archivos] # Get all year stamps years = list(set(years)) # Find unique years years.sort() # Sort years # Get buoy ID information buoyid = [x[0:5] for x in archivos] # Find buoy ids buoyid = list(set(buoyid)) # Find unique ids if len(buoyid) > 1: print('This code does not support conversion for multiple buoys') buoyid = buoyid[0] print(' ' + buoyid + ' will be processed') else: buoyid = buoyid[0] # Info print('Found ' + np.str(len(years)) + ' files') print(buoyfld) # Create output netcdf file ------------------------------------------------ # Global attributes nc = netCDF4.Dataset(buoyfld + '/' + buoyid + '_spec.nc', 'w', format='NETCDF4') nc.Description = buoyid + ' NDBC Spectral Data' nc.Rawdata = 'National Data Buoy Center \nwww.ndbc.noaa.gov' nc.Author = getpass.getuser() nc.Created = time.ctime() nc.Software = 'Created with Python ' + sys.version nc.NetCDF_Lib = str(netCDF4.getlibversion()) nc.Script = os.path.realpath(__file__) nc.Notes = 'Nautical convention used for directions' # Reconstruct the spectrum ------------------------------------------------- # counter variable to create variables in the netcdf file masterCnt = 0 cnt_freq = 0 cnt_dir = 0 tstep_freq = 0 tstep_dir = 0 # This variable will change if the format changes formIdCnt = 0 formId = '0' # Frequency array to find if the reported frequencies changed freqArray = [] # Loop over years for aa in years: # Info print(' Working on year ' + aa) # Load spectral density files # Check if file exists tmpfile = buoyfld + buoyid + 'w' + aa + '.txt' if os.path.isfile(tmpfile) == False: # No spectral density found for the given year, go to next one continue # Info print(' Spectral density data') # Increase master counter variable masterCnt += 1 # Read spectral density data (frequency spectra) and identify the time # information given f_w = open(tmpfile, 'r') freq = f_w.readline().split() # Allocate the frequency array and determine if the format changed ---- freqArray.append(freq) if masterCnt > 1: if freq != freqArray[masterCnt - 2]: # Reset counter variables cnt_freq = 0 cnt_dir = 0 tstep_freq = 0 tstep_dir = 0 # Update form Id counter formIdCnt += 1 if formIdCnt > 9: print('\n10 Different Formats Found') print('Check your data, quitting ...') nc.close() sys.exit() # Update form Id text formId = '%01.0f' % formIdCnt # Message to user print(' Different format found') print(' New variables introduced') # Find if minutes are given if freq[4] == 'mm': freqInd0 = 5 else: freqInd0 = 4 # Read frequencies freq = np.array(freq[freqInd0:], dtype=float) f_w.close() # Load spectral density freq_spec = np.loadtxt(tmpfile, skiprows=1) # Allocate time and spectral density data freq_time = np.zeros((freq_spec.shape[0])) for bb in range(freq_time.shape[0]): tmpYear = np.int(freq_spec[bb, 0]) tmpMonth = np.int(freq_spec[bb, 1]) tmpDay = np.int(freq_spec[bb, 2]) tmpHour = np.int(freq_spec[bb, 3]) if freqInd0 == 4: tmpMin = np.int(0) else: tmpMin = np.int(freq_spec[bb, 4]) if tmpYear < 100: tmpYear = tmpYear + 1900 freq_time[bb] = ( datetime.datetime(tmpYear, tmpMonth, tmpDay, tmpHour, tmpMin) - basetime).total_seconds() freq_spec = freq_spec[:, freqInd0:] # No Data Filter (NDBC uses 999.00 when there is no data) goodDataInd = freq_spec[:, 1] < 990.00 freq_time = freq_time[goodDataInd] freq_spec = freq_spec[goodDataInd, :] # Create frequency spectra variables cnt_freq += 1 if cnt_freq == 1: # Create dimensions (NetCDF4 supports multiple unlimited dimensions) nc.createDimension('wave_time' + formId, None) # Create bulk parameter variables nc.createVariable('Hsig' + formId, 'f8', 'wave_time' + formId) nc.variables['Hsig' + formId].units = 'meter' nc.variables['Hsig' + formId].long_name = 'Significant wave height' # Create frequency dimension nc.createDimension('freq' + formId, freq.shape[0]) nc.createVariable('wave_time' + formId, 'f8', 'wave_time' + formId) nc.variables['wave_time'+formId].units = \ "seconds since 1900-01-01 00:00:00" nc.variables['wave_time' + formId].calendar = "julian" nc.createVariable('freq_spec' + formId, 'f8', ('wave_time' + formId, 'freq' + formId)) nc.variables['freq_spec' + formId].units = 'meter2 second' nc.variables['freq_spec' + formId].long_name = 'Frequency variance spectrum' nc.createVariable('frequency' + formId, 'f8', ('freq' + formId)) nc.variables['frequency' + formId].units = 'Hz' nc.variables['frequency' + formId].long_name = 'Spectral frequency' nc.variables['frequency' + formId][:] = freq # Information print(' Computing Bulk Parameters') # Compute bulk parameters moment0 = np.trapz(freq_spec.T, freq, axis=0) Hsig = 4.004 * (moment0)**0.5 # Write to NetCDF file if cnt_freq == 1: nc.variables['Hsig' + formId][:] = Hsig nc.variables['freq_spec' + formId][:] = freq_spec nc.variables['wave_time' + formId][:] = freq_time else: nc.variables['Hsig' + formId][tstep_freq:] = Hsig nc.variables['freq_spec' + formId][tstep_freq:, :] = freq_spec nc.variables['wave_time' + formId][tstep_freq:] = freq_time # Check if directional data exists ------------------------------------- tmp_alpha_1 = buoyfld + buoyid + 'd' + aa + '.txt' tmp_alpha_2 = buoyfld + buoyid + 'i' + aa + '.txt' tmp_r_1 = buoyfld + buoyid + 'j' + aa + '.txt' tmp_r_2 = buoyfld + buoyid + 'k' + aa + '.txt' if (os.path.isfile(tmp_alpha_1) and os.path.isfile(tmp_alpha_2) and os.path.isfile(tmp_r_1) and os.path.isfile(tmp_r_2)): # Information print(' Directional Data') # Read frequency of the directional spectra (not always agree with # the spectral densities) f_w2 = open(tmp_alpha_1, 'r') freqDirSpec = f_w2.readline().split() freqDirSpec = np.array(freqDirSpec[freqInd0:], dtype=float) f_w2.close() # Create directional spectra variables cnt_dir += 1 if cnt_dir == 1: nc.createDimension('dir_time' + formId, None) nc.createDimension('dir' + formId, angles.shape[0]) # Create frequency dimension nc.createDimension('freqDir' + formId, freqDirSpec.shape[0]) nc.createVariable('dir_time' + formId, 'f8', 'dir_time' + formId) nc.variables['dir_time'+formId].units = \ "seconds since 1900-01-01 00:00:00" nc.variables['dir_time' + formId].calendar = "julian" nc.createVariable( 'dir_spec' + formId, 'f8', ('dir_time' + formId, 'freqDir' + formId, 'dir' + formId)) nc.variables['dir_spec' + formId].units = 'meter2 second degree-1' nc.variables['dir_spec'+formId].long_name = \ 'Frequency-Direction variance spectrum' nc.createVariable('direction' + formId, 'f8', ('dir' + formId)) nc.variables['direction' + formId].units = 'degree' nc.variables['direction'+formId].long_name = \ 'Degrees from true north in oceanographic convention' nc.variables['direction' + formId][:] = angles nc.createVariable('frequencyDir' + formId, 'f8', ('freqDir' + formId)) nc.variables['frequencyDir' + formId].units = 'Hz' nc.variables[ 'frequencyDir' + formId].long_name = 'Spectral frequency for dir_spec' nc.variables['frequencyDir' + formId][:] = freqDirSpec # Read spectral data alpha_1 = np.loadtxt(tmp_alpha_1, skiprows=1) alpha_2 = np.loadtxt(tmp_alpha_2, skiprows=1) r_1 = np.loadtxt(tmp_r_1, skiprows=1) * 0.01 r_2 = np.loadtxt(tmp_r_2, skiprows=1) * 0.01 # Allocate date dir_time = np.zeros((alpha_1.shape[0])) for bb in range(dir_time.shape[0]): tmpYear = np.int(alpha_1[bb, 0]) tmpMonth = np.int(alpha_1[bb, 1]) tmpDay = np.int(alpha_1[bb, 2]) tmpHour = np.int(alpha_1[bb, 3]) if freqInd0 == 4: tmpMin = np.int(0) else: tmpMin = np.int(alpha_1[bb, 4]) if tmpYear < 100: tmpYear = tmpYear + 1900 dir_time[bb] = (datetime.datetime(tmpYear, tmpMonth, tmpDay, tmpHour, tmpMin) - basetime).total_seconds() # Read data alpha_1 = alpha_1[:, freqInd0:] alpha_2 = alpha_2[:, freqInd0:] r_1 = r_1[:, freqInd0:] r_2 = r_2[:, freqInd0:] # No Data Filter (NDBC uses 999.00 when there is no data) goodDataInd = np.logical_and(alpha_1[:, 1] != 999.00, alpha_1[:, 2] != 999.00) alpha_1 = alpha_1[goodDataInd, :] alpha_2 = alpha_2[goodDataInd, :] r_1 = r_1[goodDataInd, :] r_2 = r_2[goodDataInd, :] dir_time = dir_time[goodDataInd] # Find where dir_time and freq_time match and compute those values # only repInd = np.in1d(dir_time, freq_time) alpha_1 = alpha_1[repInd] alpha_2 = alpha_2[repInd] r_1 = r_1[repInd] r_2 = r_2[repInd] dir_time = dir_time[repInd] repInd = np.in1d(freq_time, dir_time) freq_spec = freq_spec[repInd] # Interpolate density spectrum into directional bins if not np.array_equal(freq, freqDirSpec): freqSpecAll = np.copy(freq_spec) freq_spec = np.zeros_like((r_1)) * np.NAN for bb in range(freq_spec.shape[0]): freq_spec[bb, :] = np.interp(freqDirSpec, freq, freqSpecAll[bb, :]) # Construct 2D spectra # See http://www.ndbc.noaa.gov/measdes.shtml wspec = np.NaN * np.zeros( (alpha_1.shape[0], alpha_1.shape[1], angles.shape[0])) # Time loop for bb in range(wspec.shape[0]): # Frequency loop for cc in range(wspec.shape[1]): # Direction loop for dd in range(wspec.shape[2]): wspec[bb, cc, dd] = ( freq_spec[bb, cc] * np.pi / 180.0 * (1.0 / np.pi) * (0.5 + r_1[bb, cc] * np.cos( (angles[dd] - alpha_1[bb, cc]) * np.pi / 180.0) + r_2[bb, cc] * np.cos(2 * np.pi / 180.0 * (angles[dd] - alpha_2[bb, cc])))) # CLEAN ME UP--------------- # # Get the positive energy # tmpSpec = spec.copy() # tmpSpec[tmpSpec<0] = 0.0 # tmpFreqSpec = np.sum(tmpSpec,axis=-1)*(dirs[2]-dirs[1]) # posEnergy = np.trapz(np.abs(tmpFreqSpec),freq,axis=-1) # # # Get the total energy # tmpFreqSpec = np.sum(spec,axis=-1)*(dirs[2]-dirs[1]) # totalEnergy = np.trapz(np.abs(tmpFreqSpec),freq,axis=-1) # # # Scale the spectrum # spec = np.array([spec[aa,...] * totalEnergy[aa]/posEnergy[aa] # for aa in range(spec.shape[0])]) # spec[spec<0] = 0.0 # Write to file if cnt_dir == 1: nc.variables['dir_spec' + formId][:] = wspec nc.variables['dir_time' + formId][:] = dir_time else: nc.variables['dir_spec' + formId][tstep_dir:, :, :] = wspec nc.variables['dir_time' + formId][tstep_dir:] = dir_time tstep_dir += dir_time.shape[0] # Update frequency time step and go to next year tstep_freq += freq_time.shape[0] # Wrap up ------------------------------------------------------------------ # Information print('Data stored as:') print(' ' + buoyfld + '/' + buoyid + '.nc') # Close NetCDF File nc.close()
def write_bathy(outfld, lon, lat, depth, spherical=True): ''' Function to generate bathymetry files to be used as input for WW3 v4.18 PARAMETERS: ----------- outfld : folder to write the files to lon : longitudes (or x for cartesian) at every grid point (I assume they have been meshgridded) lat : latitudes (or y for cartesian) at every grid point spherical : True for spherical grids and False for cartesian grids OUTPUT: ------- ww3_grid.bot : ASCII file containing the grid depths ww3_grid.lon : ASCII file containing the longitudes (or x locations) ww3_grid.lat : ASCII file containing the latitudes (or y locations) ww3_grid.nc : NetCDF file containing the grid information ww3_grid.inp : Input file template to be used for the grid preprocessor. You will need to fix many things it will probably not work out of the box. NOTES: ------ I assume that if the grid is in spherical coordiantes the latitude and longitudes are given in decimal degrees (east). On the other hand if the grid is cartesian I assume meters. ''' # Convert longitudes to degrees east lon = gangles.wrapto360(lon) # Write ascii files -------------------------------------------------------- # Bathymetry fid = open(outfld + 'ww3_grid.bot', 'w') for aa in range(depth.shape[0]): for bb in range(depth.shape[1]): fid.write('%12.4f' % depth[aa, bb]) fid.write('\n') fid.close() # Latitude File fid = open(outfld + 'ww3_grid.lat', 'w') for aa in range(lat.shape[0]): for bb in range(lat.shape[1]): fid.write('%12.4f' % lat[aa, bb]) fid.write('\n') fid.close() # Longitude File fid = open(outfld + 'ww3_grid.lon', 'w') for aa in range(lon.shape[0]): for bb in range(lon.shape[1]): fid.write('%12.4f' % lon[aa, bb]) fid.write('\n') fid.close() # Write netcdf file -------------------------------------------------------- # Global attributes nc = netCDF4.Dataset(outfld + 'ww3_grid.nc', 'w', format='NETCDF4') nc.Description = 'Wavewatch III Bathymetry' nc.Author = getpass.getuser() nc.Created = time.ctime() nc.Owner = 'Nearshore Modeling Group (http://ozkan.oce.orst.edu/nmg)' nc.Software = 'Created with Python ' + sys.version nc.NetCDF_Lib = str(netCDF4.getlibversion()) nc.Script = os.path.realpath(__file__) # Create dimensions nc.createDimension('xi_rho', lon.shape[1]) nc.createDimension('eta_rho', lon.shape[0]) # Write coordinates and depth to netcdf file if spherical: nc.createVariable('lat_rho', 'f8', ('eta_rho', 'xi_rho')) nc.variables['lat_rho'].units = 'degree_north' nc.variables['lat_rho'].long_name = 'latitude of RHO-points' nc.variables['lat_rho'][:] = lat else: nc.createVariable('y_rho', 'f8', ('eta_rho', 'xi_rho')) nc.variables['y_rho'].units = 'meter' nc.variables['y_rho'].long_name = 'y location of RHO-points' nc.variables['y_rho'][:] = lat # Write longitude if spherical: nc.createVariable('lon_rho', 'f8', ('eta_rho', 'xi_rho')) nc.variables['lon_rho'].units = 'degree_east' nc.variables['lon_rho'].long_name = 'latitude of RHO-points' nc.variables['lon_rho'][:] = lon else: nc.createVariable('x_rho', 'f8', ('eta_rho', 'xi_rho')) nc.variables['x_rho'].units = 'meter' nc.variables['x_rho'].long_name = 'x location of RHO-points' nc.variables['x_rho'][:] = lon # Write water depth nc.createVariable('h', 'f8', ('eta_rho', 'xi_rho')) nc.variables['h'].units = 'meter' nc.variables['h'].long_name = 'bathymetry at RHO-points' nc.variables['h'][:] = depth # Close NetCDF file nc.close() # Write input file for grid preprocessor ---------------------------------- # Create a generic input file fid = open(outfld + 'ww3_grid.inp', 'w') fid.write( '$ ----------------------------------------------------------$\n') fid.write( '$ WAVEWATCH III Grid preprocessor input file $\n') fid.write( '$ ----------------------------------------------------------$\n') fid.write('\'Grid Name\'\n') fid.write('$\n') fid.write('1.1 0.030 40 36 0.\n') fid.write('$\n') fid.write('F T T T T T\n') fid.write('$\n') fid.write('3600. 600. 3600. 300.\n') fid.write('$\n') fid.write('END OF NAMELISTS\n') fid.write('$\n') fid.write( '$ Define grid --------------------------------------------- $\n') fid.write('$ Five records containing :\n') fid.write( '$ 1 Type of grid, coordinate system and type of closure: GSTRG, FLAGLL,\n' ) fid.write( '$ CSTRG. Grid closure can only be applied in spherical coordinates.\n' ) fid.write('$ GSTRG : String indicating type of grid :\n') fid.write('$ ' 'RECT' ' : rectilinear\n') fid.write('$ ' 'CURV' ' : curvilinear\n') fid.write('$ FLAGLL : Flag to indicate coordinate system :\n') fid.write('$ T : Spherical (lon/lat in degrees)\n') fid.write('$ F : Cartesian (meters)\n') fid.write( '$ CSTRG : String indicating the type of grid index space closure :\n' ) fid.write('$ ' 'NONE' ' : No closure is applied\n') fid.write('$ ' 'SMPL' ' : Simple grid closure : Grid is periodic in the\n') fid.write( '$ : i-index and wraps at i=NX+1. In other words,\n' ) fid.write( '$ : (NX+1,J) => (1,J). A grid with simple closure\n' ) fid.write( '$ : may be rectilinear or curvilinear.\n') fid.write('$ ' 'TRPL' ' : Tripole grid closure : Grid is periodic in the\n') fid.write( '$ : i-index and wraps at i=NX+1 and has closure at\n' ) fid.write( '$ : j=NY+1. In other words, (NX+1,J<=NY) => (1,J)\n' ) fid.write( '$ : and (I,NY+1) => (MOD(NX-I+1,NX)+1,NY). Tripole\n' ) fid.write( '$ : grid closure requires that NX be even. A grid\n' ) fid.write( '$ : with tripole closure must be curvilinear.\n' ) fid.write( '$ 2 NX, NY. As the outer grid lines are always defined as land\n') fid.write('$ points, the minimum size is 3x3.\n') fid.write('$ 3 Unit number of file with x-coordinate.\n') fid.write( '$ Scale factor and add offset: x <= scale_fac * x_read + add_offset.\n' ) fid.write( '$ IDLA, IDFM, format for formatted read, FROM and filename.\n') fid.write('$ 4 Unit number of file with y-coordinate.\n') fid.write( '$ Scale factor and add offset: y <= scale_fac * y_read + add_offset.\n' ) fid.write( '$ IDLA, IDFM, format for formatted read, FROM and filename.\n') fid.write( '$ 5 Limiting bottom depth (m) to discriminate between land and sea\n' ) fid.write( '$ points, minimum water depth (m) as allowed in model, unit number\n' ) fid.write( '$ of file with bottom depths, scale factor for bottom depths (mult.),\n' ) fid.write( '$ IDLA, IDFM, format for formatted read, FROM and filename.\n') fid.write('$ IDLA : Layout indicator :\n') fid.write('$ 1 : Read line-by-line bottom to top.\n') fid.write('$ 2 : Like 1, single read statement.\n') fid.write('$ 3 : Read line-by-line top to bottom.\n') fid.write('$ 4 : Like 3, single read statement.\n') fid.write('$ IDFM : format indicator :\n') fid.write('$ 1 : Free format.\n') fid.write( '$ 2 : Fixed format with above format descriptor.\n' ) fid.write('$ 3 : Unformatted.\n') fid.write('$ FROM : file type parameter\n') fid.write('$ ' 'UNIT' ' : open file by unit number only.\n') fid.write('$ ' 'NAME' ' : open file by name and assign to unit.\n') fid.write( '$ If the Unit Numbers in above files is 10 then data is read from this file\n' ) fid.write('$\n') # I prefer considering only curvilinear grids. if spherical: fid.write('\'CURV\' T \'NONE\'\n') else: fid.write('\'CURV\' F \'NONE\'\n') # Grid size fid.write(np.str(lon.shape[1]) + ' ' + np.str(lon.shape[0]) + '\n') # Path to grid name fid.write( ' 11 1.0 0. 1 1 \'(....)\' \'NAME\' \'ww3_grid.lon\'\n') fid.write( ' 12 1.0 0. 1 1 \'(....)\' \'NAME\' \'ww3_grid.lat\'\n') # Bottom bathymetry information fid.write('$ Bottom bathymetry\n') fid.write( ' -0.5 0.05 13 1 1 \'(....)\' \'NAME\' \'ww3_grid.bot\'\n') fid.write('$ Subgrid Information\n') fid.write(' 10 1 1 \'(....)\' \'PART\' \'dummy\'\n') # Subgrid information fid.write('$\n') fid.write(' 0 0 F\n') fid.write('$\n') fid.write(' 0 0 F\n') fid.write(' 0 0\n') fid.write('$\n') fid.write(' 0. 0. 0. 0. 0\n') fid.write( '$ ----------------------------------------------------------$\n') fid.write( '$ End of input file $\n') fid.write( '$ ----------------------------------------------------------$\n') # Close input file fid.close()
def fort61_to_nc(fort61, staname, x, y, varname='zeta', longname='water surface elevation above geoid', varunits='m', ncdate='0000-00-00 00:00:00 UTC', **kwargs): """ Script to read fort.61-type (station scalar) files and store in a netcdf4 file PARAMETERS: ----------- fort61 : Path to fort61-type file x,y : Station coordinates ncdate : cold start date/time in CF standard: yyyy-MM-dd hh:mm:ss tz RETURNS: -------- Netcdf containing time : seconds since beginning of run variable : temporal variable (called 'varname') recorded at stations. Size: [time,station] """ fobj = open(fort61, 'r') # Create the file and add global attributes if 'savename' in kwargs: ncfile = kwargs['savename'] else: ncfile = fort61 + '.nc' nc = netCDF4.Dataset(ncfile, 'w', format='NETCDF4') # Global attributes nc.Author = getpass.getuser() nc.Created = time.ctime() tmpline = fobj.readline() nc.description = tmpline[2:34] nc.rundes = tmpline[2:34] nc.runid = tmpline[36:60] nc.model = 'ADCIRC' nc.Software = 'Created with Python ' + sys.version nc.NetCDF_Lib = str(netCDF4.getlibversion()) # Record number of time steps and station tmpline = fobj.readline().split() ntsteps = np.int(tmpline[0]) sta = np.int(tmpline[1]) # Create dimensions nc.createDimension('time', 0) # The unlimited dimension nc.createDimension('station', sta) # Number of stations nc.createDimension('namelen', 50) # Length of station names # Create time vector nc.createVariable('time', 'f8', ('time')) nc.variables['time'].long_name = 'model time' nc.variables['time'].standard_name = 'time' nc.variables['time'].units = 'seconds since ' + ncdate nc.variables['time'].base_date = ncdate # Create and store spatial variables nc.createVariable('station_name', 'S1', ('station', 'namelen')) nc.variables['station_name'].long_name = 'station name' nc.variables['station_name'][:] = netCDF4.stringtochar( np.array(staname, dtype='S50')) nc.createVariable('x', 'f8', 'station') nc.variables['x'].long_name = 'longitude' nc.variables['x'].units = 'degrees east' nc.variables['x'].positive = 'east' nc.variables['x'][:] = x nc.createVariable('y', 'f8', 'station') nc.variables['y'].long_name = 'latitude' nc.variables['y'].units = 'degrees north' nc.variables['y'].positive = 'north' nc.variables['y'][:] = y # Create station variable nc.createVariable(varname, 'f8', ('time', 'station')) nc.variables[varname].long_name = longname nc.variables[varname].units = varunits # Store time-series variables for tt in range(ntsteps): nc.variables['time'][tt] = np.float64(fobj.readline().split()[0]) for aa in range(sta): nc.variables[varname][tt, aa] = np.float64(fobj.readline().split()[1]) # All done here fobj.close() nc.close()
def fort64_to_nc(fort64, varname_xy=['u-vel', 'v-vel'], longname='water column vertically averaged', varunits='m s-1', ncdate='0000-00-00 00:00:00 UTC', **kwargs): """ Script to read fort.64-type (vector) files and store in a netcdf4 file PARAMETERS: ----------- fort64: Path to fort64-type file ncdate : cold start date/time in CF standard: yyyy-MM-dd hh:mm:ss tz RETURNS: -------- Netcdf containing time : seconds since beginning of run x,y variable : temporal variables (name provided in 'xy_varname') recorded at the nodes of an unstructured grid. Size: [time,nodes] """ fobj = open(fort64, 'r') # Create the file and add global attributes if 'savename' in kwargs: ncfile = kwargs['savename'] else: ncfile = fort64 + '.nc' nc = netCDF4.Dataset(ncfile, 'w', format='NETCDF4') # Global attributes nc.Author = getpass.getuser() nc.Created = time.ctime() tmpline = fobj.readline() nc.description = tmpline[2:34] nc.rundes = tmpline[2:34] nc.runid = tmpline[36:60] nc.model = 'ADCIRC' nc.Software = 'Created with Python ' + sys.version nc.NetCDF_Lib = str(netCDF4.getlibversion()) # Record number of time steps and nodes tmpline = fobj.readline().split() ntsteps = np.int(tmpline[0]) nodes = np.int(tmpline[1]) # Create dimensions nc.createDimension('time', 0) # The unlimited dimension nc.createDimension('node', nodes) # Number of nodes # Create time vector nc.createVariable('time', 'f8', ('time')) nc.variables['time'].long_name = 'model time' nc.variables['time'].standard_name = 'time' nc.variables['time'].units = 'seconds since ' + ncdate nc.variables['time'].base_date = ncdate # Create the rest of the variables nc.createVariable(varname_xy[0], 'f8', ('time', 'node')) nc.variables[varname_xy[0]].long_name = longname + ' e/w velocity' nc.variables[varname_xy[0]].units = varunits nc.createVariable(varname_xy[1], 'f8', ('time', 'node')) nc.variables[varname_xy[1]].long_name = longname + ' n/s velocity' nc.variables[varname_xy[1]].units = varunits for tt in range(ntsteps): # Store variables nc.variables['time'][tt] = np.float64(fobj.readline().split()[0]) for aa in range(nodes): tmpline = fobj.readline().split() nc.variables[varname_xy[0]][tt, aa] = np.float64(tmpline[1]) nc.variables[varname_xy[1]][tt, aa] = np.float64(tmpline[2]) # All done here fobj.close() nc.close()
def write_nc_spec(latitude, longitude, spectrum, frequency, direction, time1, station, fileout=None, spherical=True): """ Parameters ---------- latitude : Array of the latitudes of each spectra point [Degree] Dimension (time,station) longitude : Array of the longitudes of each spectra point [Degree east] Dimension (time,station) spectrum : Variance spectrum [m2/Hz/rad] Dimensions (time,station,frequency,direction) frequency : frequency at each bin center [Hz] direction : direction of propagation of each spectral bin [rad] time : vector with days from 1900-01-01 00:00:00 station : Array with station names (not longer than 16 characters) fileout : Output netCDF file spherical : Flag for metadata. For spherical coordinates True and False for cartesian coordiantes. Notes: ------ Direction of where waves are traveling to. Version: -------- v0.1 code created: Gabriel Garcia Medina, Saeed Moghimi, April 2015 """ # For testing purposes only ------------------------------------------------ # nctest = netCDF4.Dataset('/home/shusin2/shared/nmg/pycodes/' # 'ww3.basin.201401_spec.nc','r') # fileout = '/home/shusin2/shared/nmg/pycodes/test2.nc' # time1 = nctest.variables['time'][:] # station = nctest.variables['station'][:1] # latitude = nctest.variables['latitude'][:,:1] * 0.0 # longitude = nctest.variables['longitude'][:,:1] * 0.0+15.0 # frequency = nctest.variables['frequency'][:] # direction = nctest.variables['direction'][:] # spectrum = nctest.variables['efth'][:,:1,:,:] # ------------------------------------------------------------------------- # # Variable dictionary # varinfo = defaultdict(dict) # varinfo['frequency']['units'] = 's-1' # varinfo['frequency']['long_name'] = 'frequency of center band' # varinfo['frequency']['standard_name'] = 'sea_surface_wave_frequency' # varinfo['direction']['units'] = 'degree' # varinfo['direction']['long_name'] = 'sea surface wave to direction' # varinfo['direction']['standard_name'] = 'sea_surface_wave_to_direction' # varinfo['latitude']['units'] = 'degree_north' # varinfo['latitude']['long_name'] = 'latitude' # varinfo['latitude']['standard_name'] = 'latitude' # varinfo['longitude']['units'] = 'degree_east' # varinfo['longitude']['long_name'] = 'longitude' # varinfo['longitude']['standard_name'] = 'longitude' # varinfo['efth']['units'] = 'm2 s rad-1' # varinfo['efth']['long_name'] = ('sea surface wave directional variance' + # ' spectral density') # Create netcdf file if fileout: nc = netCDF4.Dataset(fileout, "w") else: print("Writing NetCDF file " + os.getcwd() + "/ww3_spec_inp.nc") nc = netCDF4.Dataset("./ww3_spec_inp.nc", "w") # Create general attributes nc.Description = "Wavewatch III 4.18 input spectra file" nc.Author = getpass.getuser() nc.Created = time.ctime() nc.Owner = "Nearshore Modeling Group (http://ozkan.oce.orst.edu/nmg)" nc.Software = "Created with Python " + sys.version nc.NetCDF_Lib = str(netCDF4.getlibversion()) nc.Script = os.path.realpath(__file__) # Create dimensions nc.createDimension("time", 0) nc.createDimension("frequency", frequency.shape[0]) nc.createDimension("direction", direction.shape[0]) nc.createDimension("string16", 16) nc.createDimension("station", len(station)) # Write time nc.createVariable("time", "f8", ("time")) nc.variables["time"].long_name = "julian day (UT)" nc.variables["time"].standard_time = "time" nc.variables["time"].units = "days since 1900-01-01T00:00:00Z" nc.variables["time"].conventions = "Relative julian days with decimal " + "part (as parts of the day)" nc.variables["time"][:] = time1 # Write station id and name nc.createVariable("station", "i8", ("station")) nc.variables["station"].long_name = "station id" nc.variables["station"].axis = "X" nc.variables["station"][:] = np.arange(0, len(station), 1) # IDK why they do this in WW3 so I am trying to mimic this behaviour nc.createVariable("string16", "i8", ("string16")) nc.variables["string16"].long_name = "station_name number of characters" nc.variables["string16"].axis = "W" nc.variables["string16"][:] = np.empty((16,), dtype=int) # Write station names nc.createVariable("station_name", "S1", ("station", "string16")) nc.variables["station_name"].long_name = "station name" nc.variables["station_name"].content = "XW" nc.variables["station_name"].associates = "station string16" for aa in range(len(station)): nc.variables["station_name"][aa] = station[aa] # Spatial dimensions nc.createVariable("latitude", "f8", ("time", "station")) nc.variables["latitude"].long_name = "latitude" nc.variables["latitude"].standard_name = "latitude" nc.variables["latitude"].units = "degree_north" nc.variables["latitude"].valid_min = -90.0 nc.variables["latitude"].valid_max = 90.0 nc.variables["latitude"].content = "TX" nc.variables["latitude"].associates = "time station" nc.variables["latitude"][:] = latitude nc.createVariable("longitude", "f8", ("time", "station")) nc.variables["longitude"].long_name = "longitude" nc.variables["longitude"].standard_name = "longitude" nc.variables["longitude"].units = "degree_east" nc.variables["longitude"].valid_min = -180.0 nc.variables["longitude"].valid_max = 180.0 nc.variables["longitude"].content = "TX" nc.variables["longitude"].associates = "time station" nc.variables["longitude"][:] = gangles.wrapto180(latitude) # Create frequency and direction vectors nc.createVariable("frequency", "f8", ("frequency")) nc.variables["frequency"].long_name = "frequency of center band" nc.variables["frequency"].standard_name = "sea_surface_wave_frequency" nc.variables["frequency"].globwave_name = "frequency" nc.variables["frequency"].units = "s-1" nc.variables["frequency"].valid_min = 0.0 nc.variables["frequency"].valid_max = 10.0 nc.variables["frequency"].axis = "Y" nc.variables["frequency"][:] = frequency nc.createVariable("direction", "f8", ("direction")) nc.variables["direction"].long_name = "sea surface wave to direction" nc.variables["direction"].standard_name = "sea_surface_wave_to_direction" nc.variables["direction"].globwave_name = "direction" nc.variables["direction"].units = "degree" nc.variables["direction"].valid_min = 0.0 nc.variables["direction"].valid_max = 360.0 nc.variables["direction"][:] = gangles.wrapto360(direction) # Write spectral data nc.createVariable("efth", "f8", ("time", "station", "frequency", "direction")) nc.variables["efth"].long_name = "sea surface wave directional variance" + " spectral density" nc.variables["efth"].standard_name = "sea_surface_wave_directional_" + "variance_spectral_density" nc.variables["efth"].globwave_name = "directional_variance_spectral_density" nc.variables["efth"].units = "m2 s rad-1" nc.variables["efth"].scale_factor = 1.0 nc.variables["efth"].add_offset = 0.0 nc.variables["efth"].valid_min = 0.0 nc.variables["efth"].valid_max = 1.0e20 nc.variables["efth"].content = "TXYZ" nc.variables["efth"].associates = "time station frequency direction" nc.variables["efth"][:] = spectrum nc.close()
def convert_output(workfld, outfile, time_int, bathyfile=None, inpfile=None): ''' Parameters: ----------- workfld : Path to the folder where output files reside outfile : Output NetCDF file time_int : Time interval between output files [s] (will be updated if input file is provided) bathyfile : Full path to input netcdf bathy file (optional) inpfile : Funwave input file used for metadata (optional) Output: ------- NetCDF File with the variables in the folder. Not all are supported so you may need to edit this file. ''' # For testing only #workfld = '/scratch/temp/ggarcia/spectralWidthFunwave/02-runs/results/' #outfile = '/scratch/temp/ggarcia/spectralWidthFunwave/02-runs/test.nc' #time_int = 0.1 #bathyfile = '/scratch/temp/ggarcia/spectralWidthFunwave/02-runs/depth.nc' #inpfile = '/scratch/temp/ggarcia/spectralWidthFunwave/02-runs/input.txt' # Get variable information ------------------------------------------------ archivos = os.listdir(workfld) # Get all files tmpvars = [x.split('_')[0] for x in archivos] # All variables tmpvars = list(set(tmpvars)) # Unique variables # If no variables found exit if not tmpvars: print('No files found in ' + workfld) print('Quitting ...') return None # Make sure variables are within the supported ones supported_vars_time = [ 'eta', 'etamean', 'havg', 'hmax', 'hmin', 'hrms', 'mask', 'mask9', 'MFmax', 'u', 'umax', 'umean', 'v', 'vmean', 'VORmax' ] vars_2d = [x for x in tmpvars if x in supported_vars_time] # Read input file if provided ---------------------------------------------- if inpfile: print("Reading data from input file:") print(" " + inpfile) # Open file tmpinpfile = open(inpfile, 'r') # Output dictionary inpinfo = {} # Extract information (need to add wavemaker support) for tmpline in tmpinpfile: # Skip blank lines if len(tmpline.strip()) == 0: continue if "TITLE" == tmpline.split()[0]: inpinfo['title'] = tmpline.split()[2] elif "PX" == tmpline.split()[0]: inpinfo['px'] = tmpline.split()[2] elif "PY" == tmpline.split()[0]: inpinfo["py"] = tmpline.split()[2] elif "Mglob" == tmpline.split()[0]: inpinfo['mglob'] = tmpline.split()[2] elif "Nglob" == tmpline.split()[0]: inpinfo['nglob'] = tmpline.split()[2] elif "TOTAL_TIME" == tmpline.split()[0]: inpinfo['total_time'] = tmpline.split()[2] elif "PLOT_INTV" == tmpline.split()[0]: inpinfo["plot_intv"] = tmpline.split()[2] time_int = np.double(tmpline.split()[2]) elif "DX" == tmpline.split()[0]: inpinfo['dx'] = tmpline.split()[2] dx = float(tmpline.split()[2]) elif "DY" == tmpline.split()[0]: inpinfo['dy'] = tmpline.split()[2] dy = float(tmpline.split()[2]) elif "WAVEMAKER" == tmpline.split()[0]: inpinfo['wavemaker'] = tmpline.split()[2] elif "PERIODIC" == tmpline.split()[0]: inpinfo['periodic'] = tmpline.split()[2] elif "SPONGE_ON" == tmpline.split()[0]: sponge = tmpline.split()[2] inpinfo['sponge'] = sponge elif "Sponge_west_width" == tmpline.split()[0] and sponge == 'T': inpinfo['sponge_west_width'] = tmpline.split()[2] elif "Sponge_east_width" == tmpline.split()[0] and sponge == 'T': inpinfo['sponge_east_width'] = tmpline.split()[2] elif "Sponge_south_width" == tmpline.split()[0] and sponge == 'T': inpinfo['sponge_south_width'] = tmpline.split()[2] elif "Sponge_north_width" == tmpline.split()[0] and sponge == 'T': inpinfo['sponge_north_width'] = tmpline.split()[2] elif "R_sponge" == tmpline.split()[0] and sponge == 'T': inpinfo['r_sponge'] = tmpline.split()[2] elif "A_sponge" == tmpline.split()[0] and sponge == 'T': inpinfo['a_sponge'] = tmpline.split()[2] elif "DISPERSION" == tmpline.split()[0]: inpinfo['dispersion'] = tmpline.split()[2] elif "Gamma1" == tmpline.split()[0]: inpinfo['gamma1'] = tmpline.split()[2] elif "Gamma2" == tmpline.split()[0]: inpinfo['gamma2'] = tmpline.split()[2] elif "Gamma3" == tmpline.split()[0]: inpinfo['gamma3'] = tmpline.split()[2] elif "Beta_ref" == tmpline.split()[0]: inpinfo['beta_ref'] = tmpline.split()[2] elif "SWE_ETA_DEP" == tmpline.split()[0]: inpinfo['swe_eta_dep'] = tmpline.split()[2] elif "Friction_Matrix" == tmpline.split()[0]: inpinfo['friction_matrix'] = tmpline.split()[2] elif "Cd_file" == tmpline.split()[0]: inpinfo['cd_file'] = tmpline.split()[2] elif "Cd" == tmpline.split()[0]: inpinfo['cd'] = tmpline.split()[2] elif "Time_Scheme" == tmpline.split()[0]: inpinfo['time_scheme'] = tmpline.split()[2] elif "HIGH_ORDER" == tmpline.split()[0]: inpinfo['spatial_scheme'] = tmpline.split()[2] elif "CONSTRUCTION" == tmpline.split()[0]: inpinfo['construction'] = tmpline.split()[2] elif "CFL" == tmpline.split()[0]: inpinfo['cfl'] = tmpline.split()[2] elif "MinDepth" == tmpline.split()[0]: inpinfo['min_depth'] = tmpline.split()[2] elif "MinDepthFrc" == tmpline.split()[0]: inpinfo['mindepthfrc'] = tmpline.split()[2] # Close file tmpinpfile.close() else: # Assume grid spacing to be 1 meter print("Input file not provided") dx = 1 dy = 1 inpinfo = False # Coordinates and depth --------------------------------------------------- # Bathymetry file provided if bathyfile: print("Reading coordinates and depth from:") print(" " + bathyfile) ncfile = netCDF4.Dataset(bathyfile, 'r') x_rho = ncfile.variables['x_rho'][:] if ncfile.variables.has_key('y_rho'): y_rho = ncfile.variables['y_rho'][:] else: y_rho = None h = ncfile.variables['h'][:] ncfile.close() # Bathymetry file not provided but have output file elif os.path.isfile(workfld + '/dep.out'): # Fix this h = np.loadtxt(workfld + '/dep.out') hdims = h.ndim if hdims == 1: x_rho = np.arange(0, h.shape[0], dx) elif hdims == 2: x_rho, y_rho = np.meshgrid(np.arange(0, h.shape[1], dx), np.arange(0, h.shape[0], dy)) else: print('Something is wrong with the depth file') return None # No bathymetry file provided (I am not capable of reading the input file) else: print("No bathymetry file provided") print("You could copy your input bathymetry text file to ") print(workfld + '/dep.out') return None # Get dimensions of variables hdims = h.ndim # Create NetCDF file ------------------------------------------------------- print("Creating " + outfile) # Global attributes nc = netCDF4.Dataset(outfile, 'w', format='NETCDF4') nc.Description = 'Funwave Output' nc.Author = '*****@*****.**' nc.Created = time.ctime() nc.Type = 'Funwave v2.1 snapshot output' nc.Owner = 'Nearshore Modeling Group' nc.Software = 'Created with Python ' + sys.version nc.NetCDF_Lib = str(netCDF4.getlibversion()) nc.Source = workfld nc.Script = os.path.realpath(__file__) # Add more global variables to output if inpinfo: for tmpatt in inpinfo.keys(): nc.__setattr__(tmpatt, inpinfo[tmpatt][:]) # Create dimensions if hdims == 2: eta_rho, xi_rho = h.shape nc.createDimension('eta_rho', eta_rho) else: xi_rho = h.shape[0] eta_rho = 1 nc.createDimension('xi_rho', xi_rho) nc.createDimension('ocean_time', 0) # Write coordinate axes ---------------------------------------------- if hdims == 2: nc.createVariable('x_rho', 'f8', ('eta_rho', 'xi_rho')) nc.variables['x_rho'].units = 'meter' nc.variables['x_rho'].longname = 'x-locations of RHO points' nc.variables['x_rho'][:] = x_rho nc.createVariable('y_rho', 'f8', ('eta_rho', 'xi_rho')) nc.variables['y_rho'].units = 'meter' nc.variables['y_rho'].longname = 'y-locations of RHO points' nc.variables['y_rho'][:] = y_rho nc.createVariable('h', 'f8', ('eta_rho', 'xi_rho')) nc.variables['h'].units = 'meter' nc.variables['h'].longname = 'bathymetry at RHO points' nc.variables['h'][:] = h else: nc.createVariable('x_rho', 'f8', ('xi_rho')) nc.variables['x_rho'].units = 'meter' nc.variables['x_rho'].longname = 'x-locations of RHO points' nc.variables['x_rho'][:] = x_rho nc.createVariable('h', 'f8', ('xi_rho')) nc.variables['h'].units = 'meter' nc.variables['h'].longname = 'bathymetry at RHO points' nc.variables['h'][:] = h # Create time vector ------------------------------------------- tmpruns = [x for x in archivos if x.split('_')[0] == vars_2d[0]] tmpruns.sort() time_max = float(tmpruns[-1].split('_')[-1]) time_min = float(tmpruns[0].split('_')[-1]) twave = np.arange(time_min - 1, time_int * (time_max - time_min + 1) + time_min - 1, time_int) if twave.shape[0] > len(tmpruns): twave = twave[:-1] nc.createVariable('ocean_time', 'f8', 'ocean_time') nc.variables['ocean_time'].units = 'seconds since 2000-01-01 00:00:00' nc.variables['ocean_time'].calendar = 'julian' nc.variables['ocean_time'].long_name = 'beach time' nc.variables['ocean_time'][:] = twave # Create variables -------------------------------------------------------- # Variable information varinfo = defaultdict(dict) varinfo['eta']['units'] = 'meter' varinfo['eta']['longname'] = 'water surface elevation' varinfo['etamean']['units'] = 'meter' varinfo['etamean']['longname'] = 'Mean wave induced setup' varinfo['u']['units'] = 'meter second-1' varinfo['u']['longname'] = 'Flow velocity in the xi direction' varinfo['v']['units'] = 'meter second-1' varinfo['v']['longname'] = 'Flow velocity in the eta direction' varinfo['umean']['units'] = 'meter second-1' varinfo['umean'][ 'longname'] = 'Time-averaged flow velocity in xi direction' varinfo['vmean']['units'] = 'meter second-1' varinfo['vmean'][ 'longname'] = 'Time-averaged flow velocity in eta direction' varinfo['umax']['units'] = 'meter second-1' varinfo['umax']['longname'] = 'Maximum flow velocity in xi direction' varinfo['vmax']['units'] = 'meter second-1' varinfo['vmax']['longname'] = 'Maximum flow velocity in eta direction' varinfo['hmax']['units'] = 'meter' varinfo['hmax']['longname'] = 'Maximum wave height' varinfo['hmin']['units'] = 'meter' varinfo['hmin']['longname'] = 'Minimum wave height' varinfo['havg']['units'] = 'meter' varinfo['havg']['longname'] = 'Average wave height' varinfo['hrms']['units'] = 'meter' varinfo['hrms']['longname'] = 'Root mean squared wave height' varinfo['mask']['units'] = 'Boolean' varinfo['mask']['longname'] = 'Logical parameter for output wetting-drying' varinfo['mask9']['units'] = 'Boolean' varinfo['mask9']['longname'] = 'Logical parameter for output MASK9' varinfo['VORmax']['units'] = 'second-1' varinfo['VORmax']['longname'] = 'Maximum vorticity' varinfo['MFmax']['units'] = 'meter second-s' varinfo['MFmax']['longname'] = 'Maximum momentum flux' # Create variables if hdims == 1: nc_dims = ('ocean_time', 'xi_rho') else: nc_dims = ('ocean_time', 'eta_rho', 'xi_rho') print("Creating variables") for aa in vars_2d: print(' ' + aa) # Create variable create_nc_var(nc, aa, nc_dims, varinfo[aa]['units'], varinfo[aa]['longname']) try: tmpvar = np.loadtxt(workfld + '/' + aa + '_' + '%05.0f' % time_min) except ValueError: tmpvar = np.zeros_like(h) * np.NAN nc.variables[aa][:] = np.expand_dims(tmpvar, axis=0) for bb in range(len(twave)): try: tmpvar = np.loadtxt(workfld + '/' + aa + '_' + '%05.0f' % (bb + time_min)) except ValueError: tmpvar = np.zeros_like(h) * np.NAN append_nc_var(nc, tmpvar, aa, bb - 1) # Close NetCDF file print('Closing ' + outfile) nc.close()
def write_bathy(x,y,h,path,ncsave=True): ''' Parameters: ---------- x,y : 2D arrays of coordinates h : Bathymetry path : Full path where the output will be saved ncsave : Save as NetCDF4 file (optional, defaults to True) Output: ------- bathy.nc : NetCDF4 file with the bathymetry bathy.txt : Text file with the depth information for Funwave input. ''' # Get bathymetry dimensions eta_rho, xi_rho = x.shape if ncsave: # Global attributes nc = netCDF4.Dataset(path + 'bathy.nc', 'w', format='NETCDF4') nc.Description = 'NHWAVE Bathymetry' nc.Author = getpass.getuser() nc.Created = time.ctime() nc.Owner = 'Nearshore Modeling Group (http://ozkan.oce.orst.edu/nmg)' nc.Software = 'Created with Python ' + sys.version nc.NetCDF_Lib = str(netCDF4.getlibversion()) nc.Script = os.path.realpath(__file__) # Create dimensions nc.createDimension('xi_rho', xi_rho) nc.createDimension('eta_rho', eta_rho) # Write coordinates and depth to netcdf file create_nc_var(nc, 'x_rho',('eta_rho', 'xi_rho'), 'meter','x-locations of RHO-points') nc.variables['x_rho'][:] = x create_nc_var(nc, 'y_rho', ('eta_rho', 'xi_rho'), 'meter','y-locations of RHO-points') nc.variables['y_rho'][:] = y create_nc_var(nc,'h',('eta_rho', 'xi_rho'), 'meter','bathymetry at RHO-points') nc.variables['h'][:] = h # Close NetCDF file nc.close() else: print("NetCDF file not requested") # Output the text file ----------------------------------------------------- fid = open(path + 'bathy.txt','w') for aa in range(x.shape[0]): for bb in range(x.shape[1]): fid.write('%12.3f' % h[aa,bb]) fid.write('\n') fid.close() #=========================================================================== # Print input file options #=========================================================================== print(' ') print('===================================================================') print('In your NHWAVE input file:') print('Mglob = ' + np.str(xi_rho)) print('Nglob = ' + np.str(eta_rho)) print('DX = ' + np.str(np.abs(x[0,1] - x[0,0]))) print('DY = ' + np.str(np.abs(y[1,0] - y[0,0]))) print('Ywidth_WK > ' + str(y.max() - y.min())) print('DEP_WK = ' + str(h.max())) print('Check sponge layer widths') print('===================================================================') print(' ')
def write_bathy_1d(x,h,path,ncsave=True): ''' Parameters: ---------- x : 1D array of x coordinates h : Bathymetry path : Full path where the output will be saved ncsave : Save bathy as NetCDF file Output: ------- bathy.txt : Text file with the depth information for Funwave input. bathy.nc : (Optional) NetCDF4 bathymetry file. Notes: ------ Variables are assumed to be on a regularly spaced grid. ''' # Output the text file ----------------------------------------------------- fid = open(path + 'depth.txt','w') for aa in range(len(h)): fid.write('%12.3f' % h[aa]) fid.write('\n') fid.close() if ncsave: # Global attributes nc = netCDF4.Dataset(path + 'depth.nc', 'w', format='NETCDF4') nc.Description = 'NHWAVE Bathymetry' nc.Author = getpass.getuser() nc.Created = time.ctime() nc.Owner = 'Nearshore Modeling Group (http://ozkan.oce.orst.edu/nmg)' nc.Software = 'Created with Python ' + sys.version nc.NetCDF_Lib = str(netCDF4.getlibversion()) nc.Script = os.path.realpath(__file__) # Create dimensions xi_rho = len(h) nc.createDimension('xi_rho', xi_rho) # Write coordinates and depth to netcdf file create_nc_var(nc,'x_rho',('xi_rho'),'meter','x-locations of RHO-points') nc.variables['x_rho'][:] = x create_nc_var(nc,'h',('xi_rho'),'meter','bathymetry at RHO-points') nc.variables['h'][:] = h # Close NetCDF file nc.close() else: print("NetCDF file not requested") #=========================================================================== # Print input file options #=========================================================================== print(' ') print('===================================================================') print('In your NHWAVE input file:') print('Mglob = ' + np.str(len(x))) print('Nglob = 1') print('DX = ' + np.str(np.abs(x[1] - x[0]))) print('DY = anything larger than DX works') print('DEP_WK = ' + str(h.max())) print('Check sponge layer widths') print('===================================================================') print(' ')
def convert_output(workfld,outfile,bathyfile=None,inpfile=None,verbose=False): ''' Tools to convert ASCII output from NHWAVE to NetCDF4 Parameters: ----------- workfld : Path to the folder where output files reside outfile : Output file bathyfile : Full path to input NetCDF bathy file (optional) inpfile : NHwave input files used to add metadata (optional) verbose : Display progress messages (optional) Output: ------- NetCDF File with the variables in the folder. Not all are supported so you may need to edit this file. Notes: ------ TODO: ----- 1. Need to test for 2DH simulations. 2. Add support for exponential vertical layers ''' # Get variable information ------------------------------------------------- archivos = os.listdir(workfld) # All files tmpvars = [x.split('_')[0] for x in archivos] # Variables tmpvars = list(set(tmpvars)) # Unique variables # If no variables found exit if not tmpvars: print('No files found in ' + workfld) print('Quitting ...') return None # Make sure variables are within the supported ones (exclude time here) supported_vars_2d_time = ['eta'] vars_2d_time = [x for x in tmpvars if x in supported_vars_2d_time] supported_vars_2d = ['setup','waveheight','umean','vmean'] vars_2d = [x for x in tmpvars if x in supported_vars_2d] supported_vars_3d_time = ['u','v','w'] vars_3d_time = [x for x in tmpvars if x in supported_vars_3d_time] supported_vars_3d = ['euler','lag'] vars_3d = [x for x in tmpvars if x in supported_vars_3d] # Read input file if provided ---------------------------------------------- if inpfile: if verbose: print("Reading data from input file:") print(" " + inpfile) # Open file tmpinpfile = open(inpfile,'r') # Output dictionary inpinfo = {} # Extract information (need to add wavemaker support) for tmpline in tmpinpfile: # Skip blank lines if len(tmpline.strip()) == 0: continue # Read selected keywords if "TITLE" == tmpline.split()[0]: inpinfo['title'] = tmpline.split()[2] elif "Mglob" == tmpline.split()[0]: inpinfo['mglob'] = tmpline.split()[2] elif "Nglob" == tmpline.split()[0]: inpinfo['nglob'] = tmpline.split()[2] elif "Kglob" == tmpline.split()[0]: inpinfo['kglob'] = tmpline.split()[2] elif "PX" == tmpline.split()[0]: inpinfo['px'] = tmpline.split()[2] elif "PY" == tmpline.split()[0]: inpinfo["py"] = tmpline.split()[2] elif "TOTAL_TIME" == tmpline.split()[0]: inpinfo['total_time'] = tmpline.split()[2] elif "PLOT_START" == tmpline.split()[0]: inpinfo['plot_start'] = tmpline.split()[2] elif "PLOT_INTV" == tmpline.split()[0]: inpinfo["plot_intv"] = tmpline.split()[2] elif "DX" == tmpline.split()[0]: inpinfo['dx'] = tmpline.split()[2] dx = float(tmpline.split()[2]) elif "DY" == tmpline.split()[0]: inpinfo['dy'] = tmpline.split()[2] dy = float(tmpline.split()[2]) elif "IVGRD" == tmpline.split()[0]: inpinfo['ivgrd'] = tmpline.split()[2] elif "DT_INI" == tmpline.split()[0]: inpinfo['dt_ini'] = tmpline.split()[2] elif "DT_MIN" == tmpline.split()[0]: inpinfo['dt_min'] = tmpline.split()[2] elif "DT_MAX" == tmpline.split()[0]: inpinfo['dt_max'] = tmpline.split()[2] elif "HIGH_ORDER" == tmpline.split()[0]: inpinfo['high_order'] = tmpline.split()[2] elif "TIME_ORDER" == tmpline.split()[0]: inpinfo['time_order'] = tmpline.split()[2] elif "CONVECTION" == tmpline.split()[0]: inpinfo['convection'] = tmpline.split()[2] elif "HLLC" == tmpline.split()[0]: inpinfo['hllc'] = tmpline.split()[2] elif "Ibot" == tmpline.split()[0]: inpinfo['ibot'] = tmpline.split()[2] ibot = int(tmpline.split()[2]) elif "Cd0" == tmpline.split()[0] and ibot == 1: inpinfo['cd0'] = tmpline.split()[2] elif "Zob" == tmpline.split()[0] and ibot == 2: inpinfo['zob'] = tmpline.split()[2] elif "Iws" == tmpline.split()[0]: inpinfo['Iws'] = tmpline.split()[2] iws = int(tmpline.split()[2]) elif "WindU" == tmpline.split()[0] and iws == 1: inpinfo['windu'] = tmpline.split()[2] elif "WindV" == tmpline.split()[0] and iws == 1: inpinfo['windv'] = tmpline.split()[2] elif "slat" == tmpline.split()[0]: inpinfo['slat'] = tmpline.split()[2] elif "BAROTROPIC" == tmpline.split()[0]: inpinfo['barotropic'] = tmpline.split()[2] elif "NON_HYDRO" == tmpline.split()[0]: inpinfo['non_hydro'] = tmpline.split()[2] elif "CFL" == tmpline.split()[0]: inpinfo['cfl'] = tmpline.split()[2] elif "TRAMP" == tmpline.split()[0]: inpinfo['tramp'] = tmpline.split()[2] elif "MinDep" == tmpline.split()[0]: inpinfo['min_dep'] = tmpline.split()[2] elif "ISOLVER" == tmpline.split()[0]: inpinfo['isolver'] = tmpline.split()[2] elif "PERIODIC_X" == tmpline.split()[0]: inpinfo['periodic_x'] = tmpline.split()[2] elif "PERIODIC_Y" == tmpline.split()[0]: inpinfo['periodic_y'] = tmpline.split()[2] elif "BC_X0" == tmpline.split()[0]: inpinfo['bc_x0'] = tmpline.split()[2] elif "BC_Xn" == tmpline.split()[0]: inpinfo['bc_xn'] = tmpline.split()[2] elif "BC_Y0" == tmpline.split()[0]: inpinfo['bc_y0'] = tmpline.split()[2] elif "BC_Yn" == tmpline.split()[0]: inpinfo['bc_yn'] = tmpline.split()[2] elif "BC_Z0" == tmpline.split()[0]: inpinfo['bc_z0'] = tmpline.split()[2] elif "BC_Zn" == tmpline.split()[0]: inpinfo['bc_zn'] = tmpline.split()[2] elif "WAVEMAKER" == tmpline.split()[0]: inpinfo['wavemaker'] = tmpline.split()[2] elif "Xsource_West" == tmpline.split()[0] and \ inpinfo['wavemaker'][0:3] == 'INT': inpinfo['xsource_west'] = tmpline.split()[2] elif "Xsource_East" == tmpline.split()[0] and \ inpinfo['wavemaker'][0:3] == 'INT': inpinfo['xsource_east'] = tmpline.split()[2] elif "Ysource_Suth" == tmpline.split()[0] and \ inpinfo['wavemaker'][0:3] == 'INT': inpinfo['ysource_suth'] = tmpline.split()[2] elif "Ysource_Nrth" == tmpline.split()[0] and \ inpinfo['wavemaker'][0:3] == 'INT': inpinfo['xsource_nrth'] = tmpline.split()[2] elif "SPONGE_ON" == tmpline.split()[0]: inpinfo['sponge'] = tmpline.split()[2] sponge = tmpline.split()[2] elif "Sponge_West_Width" == tmpline.split()[0] and sponge == 'T': inpinfo['sponge_west_width'] = tmpline.split()[2] elif "Sponge_East_Width" == tmpline.split()[0] and sponge == 'T': inpinfo['sponge_east_width'] = tmpline.split()[2] elif "Sponge_South_Width" == tmpline.split()[0] and sponge == 'T': inpinfo['sponge_south_width'] = tmpline.split()[2] elif "Sponge_North_Width" == tmpline.split()[0] and sponge == 'T': inpinfo['sponge_north_width'] = tmpline.split()[2] elif "Seed" == tmpline.split()[0]: inpinfo['Seed'] = tmpline.split()[2] # Close file tmpinpfile.close() else: inpinfo = None if verbose: print("Input file not provided") # If bathymetry file is given then the coordinates should be taken from # this file, otherwise unit coordinates will be assumed with the shape of # one of the output files. if bathyfile: ncfile = netCDF4.Dataset(bathyfile,'r') x_rho = ncfile.variables['x_rho'][:] if ncfile.variables.has_key('y_rho'): y_rho = ncfile.variables['y_rho'][:] h = ncfile.variables['h'][:] ncfile.close() hdims = h.ndim else: if not os.path.isfile(workfld + '/depth'): print('No depth file found in ' + workfld) return None h = np.loadtxt(workfld + '/depth') # Check if it is a 1D or 2D model hdims = h.ndim # Horizontal dimensions if hdims == 1: x_rho = np.arange(0,h.shape[0],1) elif hdims == 2: x_rho, y_rho = np.meshgrid(np.arange(0,h.shape[1],1), np.arange(0,h.shape[0],1)) else: print('Something is wrong with the depth file') print('Quitting...') return None # Load time vector if not os.path.isfile(workfld + '/time'): print("No time file found in " + workfld) print("Quitting ...") return None ocean_time = np.loadtxt(workfld + '/time') # Create NetCDF file ------------------------------------------------------ nc = netCDF4.Dataset(outfile, 'w', format='NETCDF4') nc.Description = 'NHWAVE Output' nc.Author = getpass.getuser() nc.Created = time.ctime() nc.Owner = 'Nearshore Modeling Group' nc.Software = 'Created with Python ' + sys.version nc.NetCDF_Lib = str(netCDF4.getlibversion()) nc.Source = workfld nc.Script = os.path.realpath(__file__) # Add more global variables to output (if input file is provided) if inpinfo: for tmpatt in inpinfo.keys(): nc.__setattr__(tmpatt,inpinfo[tmpatt][:]) # Create dimensions if verbose: print('Creating dimensions') if hdims == 2: eta_rho, xi_rho = h.shape nc.createDimension('eta_rho', eta_rho) else: xi_rho = h.shape[0] eta_rho = 1 nc.createDimension('xi_rho', xi_rho) nc.createDimension('ocean_time',0) # Get vertical layers if not vars_3d and not vars_3d_time: print("No 3D variables found") s_rho = False else: # Load any 3D variables if os.path.isfile(workfld + '/' + vars_3d_time[0] + '_00001'): tmpvar = np.loadtxt(workfld + '/' + vars_3d_time[0] + '_00001') elif os.path.isfile(workfld + '/' + vars_3d[0] + '_umean'): tmpvar = np.loadtxt(workfld + '/' + vars_3d[0] + '_umean') elif os.path.isfile(workfld + '/' + vars_3d[0] + '_vmean'): tmpvar = np.loadtxt(workfld + '/' + vars_3d[0] + '_vmean') else: tmpvar = np.loadtxt(workfld + '/' + vars_3d[0]) # Outputs are stacked on the first dimension of the file # I need to enhance this and will probably have to use the input file # if hdims == 2: # s_rho = tmpvar.shape[0]/h.shape[0] # else: # s_rho = tmpvar.shape[0] s_rho = tmpvar.size/h.shape[0] nc.createDimension('s_rho',s_rho) # Write coordinates, bathymetry and time ---------------------------------- if verbose: print("Saving coordinates and time") if hdims == 2: nc.createVariable('x_rho','f8',('eta_rho','xi_rho')) nc.variables['x_rho'].units = 'meter' nc.variables['x_rho'].longname = 'x-locations of RHO points' nc.variables['x_rho'][:] = x_rho nc.createVariable('y_rho','f8',('eta_rho','xi_rho')) nc.variables['y_rho'].units = 'meter' nc.variables['y_rho'].longname = 'y-locations of RHO points' nc.variables['y_rho'][:] = y_rho nc.createVariable('h','f8',('eta_rho','xi_rho')) nc.variables['h'].units = 'meter' nc.variables['h'].longname = 'bathymetry at RHO points' nc.variables['h'][:] = h else: nc.createVariable('x_rho','f8',('xi_rho')) nc.variables['x_rho'].units = 'meter' nc.variables['x_rho'].longname = 'x-locations of RHO points' nc.variables['x_rho'][:] = x_rho nc.createVariable('h','f8',('xi_rho')) nc.variables['h'].units = 'meter' nc.variables['h'].longname = 'bathymetry at RHO points' nc.variables['h'][:] = h # Create s_rho vector if s_rho: ds = 1.0/s_rho sigma = np.arange(ds/2.0,1-ds/2.0,ds) nc.createVariable('s_rho','f8',('s_rho')) nc.variables['s_rho'].longname = 's-coordinate at cell centers' nc.variables['s_rho'].positive = 'up' nc.variables['s_rho'].notes = 'small s_rho means close to bottom' nc.variables['s_rho'][:] = sigma # Create time vector nc.createVariable('ocean_time','f8','ocean_time') nc.variables['ocean_time'].units = 'seconds since 2000-01-01 00:00:00' nc.variables['ocean_time'].calendar = 'julian' nc.variables['ocean_time'].long_name = 'beach time since initialization' nc.variables['ocean_time'].notes = 'units are arbitrary' nc.variables['ocean_time'][:] = ocean_time # Create variables --------------------------------------------------------- # Variable information varinfo = defaultdict(dict) varinfo['eta']['units'] = 'meter' varinfo['eta']['longname'] = 'water surface elevation' varinfo['waveheight']['units'] = 'meter' varinfo['waveheight']['longname'] = 'Mean wave height' varinfo['setup']['units'] = 'meter' varinfo['setup']['longname'] = 'Mean wave induced setup' varinfo['u']['units'] = 'meter second-1' varinfo['u']['longname'] = 'Flow velocity in the xi direction' varinfo['v']['units'] = 'meter second-1' varinfo['v']['longname'] = 'Flow velocity in the eta direction' varinfo['w']['units'] = 'meter second-1' varinfo['w']['longname'] = 'Flow velocity in the vertical direction' varinfo['umean']['units'] = 'meter second-1' varinfo['umean']['longname'] = 'Depth-averaged flow velocity in xi direction' varinfo['vmean']['units'] = 'meter second-1' varinfo['vmean']['longname'] = 'Depth-averaged flow velocity in eta direction' varinfo['lag_umean']['units'] = 'meter second-1' varinfo['lag_umean']['longname'] = 'Lagrangian mean velocity in xi direction' varinfo['lag_vmean']['units'] = 'meter second-1' varinfo['lag_vmean']['longname'] = 'Lagrangian mean velocity in eta direction' varinfo['lag_wmean']['units'] = 'meter second-1' varinfo['lag_wmean']['longname'] = 'Lagrangian mean velocity in vertical direction' varinfo['euler_umean']['units'] = 'meter second-1' varinfo['euler_umean']['longname'] = 'Eulerian mean velocity in xi direction' varinfo['euler_vmean']['units'] = 'meter second-1' varinfo['euler_vmean']['longname'] = 'Eulerian mean velocity in eta direction' varinfo['euler_wmean']['units'] = 'meter second-1' varinfo['euler_wmean']['longname'] = 'Eulerian mean velocity in vertical direction' # Loop over 2D variables that have no time component ---------------------- if hdims == 1: nc_dims = ('xi_rho') else: nc_dims = ('eta_rho','xi_rho') for aa in vars_2d: if verbose: print(' Writing ' + aa) # Create variable create_nc_var(nc,aa,nc_dims,varinfo[aa]['units'], varinfo[aa]['longname']) nc.variables[aa][:] = np.loadtxt(workfld + '/' + aa) # Loop over 3D variables that have no time component ---------------------- if hdims == 1: nc_dims = ('s_rho','xi_rho') else: nc_dims = ('s_rho','eta_rho','xi_rho') for aa in vars_3d: if verbose: print(' Writing ' + aa) if aa == 'euler' or aa == 'lag': for bb in ['umean','vmean','wmean']: create_nc_var(nc,aa + '_' + bb,nc_dims, varinfo[aa + '_' + bb]['units'], varinfo[aa + '_' + bb]['longname']) if hdims == 1: nc.variables[aa + '_' + bb][:] = \ np.loadtxt(workfld + '/' + aa + '_' + bb) else: tmpvar = np.loadtxt(workfld + '/' + aa + '_' + bb) tmpvar2 = np.zeros((s_rho,eta_rho,xi_rho)) for cc in range(s_rho): tmpvar2[cc,:,:] = tmpvar[cc*eta_rho:(cc+1)*eta_rho,:] nc.variables[aa + '_' + bb][:] = tmpvar2 del tmpvar,tmpvar2 else: # Need to test this part with a full 3d code print("need to fix this") # Loop over 2D variables that have a time component ----------------------- if hdims == 1: nc_dims = ('ocean_time','xi_rho') else: nc_dims = ('ocean_time','eta_rho','xi_rho') for aa in vars_2d_time: if verbose: print(' Writing ' + aa) # Create variable create_nc_var(nc,aa,nc_dims,varinfo[aa]['units'], varinfo[aa]['longname']) tmpvar = np.loadtxt(workfld + '/' + aa + '_' + '%05.0f' % 1) nc.variables[aa][:] = np.expand_dims(tmpvar,axis=0) for bb in range(2,len(ocean_time)+1): tmpvar = np.loadtxt(workfld + '/' + aa + '_' + '%05.0f' % bb) append_nc_var(nc,tmpvar,aa,bb-1) # Loop over 3D variables that have a time component ----------------------- if hdims == 1: nc_dims = ('ocean_time','s_rho','xi_rho') else: nc_dims = ('ocean_time','s_rho','eta_rho','xi_rho') for aa in vars_3d_time: if verbose: print(' Writing ' + aa) # Create variable create_nc_var(nc,aa,nc_dims,varinfo[aa]['units'], varinfo[aa]['longname']) if hdims == 1: tmpvar = np.loadtxt(workfld + '/' + aa + '_' + '%05.0f' % 1) if s_rho == 1: nc.variables[aa][:] = np.expand_dims(np.expand_dims(tmpvar, axis=0), axis=0) else: nc.variables[aa][:] = np.expand_dims(tmpvar,axis=0) for bb in range(2,len(ocean_time)+1): tmpvar = np.loadtxt(workfld + '/' + aa + '_' + '%05.0f' % bb) append_nc_var(nc,tmpvar,aa,bb-1) else: for bb in range(1,len(ocean_time)+1): tmpvar = np.loadtxt(workfld + '/' + aa + '_' + '%05.0f' % bb) tmpvar2 = np.zeros((s_rho,eta_rho,xi_rho)) for cc in range(s_rho): tmpvar2[cc,:,:] = tmpvar[cc*eta_rho:(cc+1)*eta_rho,:] if bb == 1: nc.variables[aa][:] = np.expand_dims(tmpvar2,axis=0) else: append_nc_var(nc,tmpvar2,aa,bb-1) del tmpvar,tmpvar2 # Close NetCDF file ------------------------------------------------------- if verbose: print('Created: ' + outfile) nc.close()
def main(): # Parse arguments parse_cli_args() # Sanity checks # Check to make sure that the JSON resource file exists! try: resource_file_fh = open(args.resource_file, "r") except IOError: error_msg("Resource file '%s' is not accessible or does not exist!" % args.resource_file) exit(1) # Check to make sure that the JSON resource file is valid! try: resource_data = json.loads(resource_file_fh.read()) except KeyboardInterrupt: info_msg("CTRL-C detected, exiting.") exit(0) except: error_msg("Resource file '%s' is not a valid JSON file!" % args.resource_file) print(traceback.format_exc()) exit(1) # Close file - we got the data already! resource_file_fh.close() # Print verbose version information if args.verbose: info_msg("Using following versions:") info_msg(" netcdf4-python v%s" % netCDF4.__version__) info_msg(" NetCDF v%s" % getlibversion()) info_msg(" HDF5 v%s" % netCDF4.__hdf5libversion__) info_msg(" Python v%s\n" % sys.version.split("\n")[0].strip()) info_msg("Reading and validating NetCDF4 files...") # Check to make sure the NetCDF4 files are legitimate! nc4_files_root = [] init_counter(len(args.nc4_files), "Reading/verifying file") for nc4_file in args.nc4_files: try: open(nc4_file, "r").close() except KeyboardInterrupt: info_msg("CTRL-C detected, exiting.") exit(0) except IOError: error_msg("The NetCDF4 file '%s' does not exist!" % nc4_file) exit(1) progress_counter(nc4_file) try: rootgrp = Dataset(nc4_file, "a", format="NETCDF4") nc4_files_root.append({"file": nc4_file, "group": rootgrp}) except KeyboardInterrupt: info_msg("CTRL-C detected, exiting.") exit(0) except: error_msg("'%s' is not a valid NetCDF4 file!" % nc4_file) exit(1) line_msg_done() # Global attributes if args.global_attributes: # Check if we have a global attributes entry in the resource file if not "global_attributes" in resource_data: warning_msg( "Resource file '%s' does not have any global attributes, skipping." % args.resource_file) else: # Initialize our counter init_counter(len(nc4_files_root), "Applying global attributes to file") for nc4_entry in nc4_files_root: # Update progress counter progress_counter(nc4_entry["file"]) for global_attr_key in resource_data["global_attributes"]: global_attr_val = resource_data["global_attributes"][ global_attr_key] # We need to convert unicode to ASCII if type(global_attr_val) == unicode: global_attr_val = str(global_attr_val) # BUG fix - NetCDF really, really, REALLY does not like # 64-bit integers. We forcefully convert the value to a # 32-bit signed integer, with some help from numpy! if type(global_attr_val) == int: global_attr_val = numpy.int32(global_attr_val) setattr(nc4_entry["group"], global_attr_key, global_attr_val) line_msg_done() # Variable attributes if args.var_attributes: # Check if we have a variable attributes entry in the resource file if not "variable_attributes" in resource_data: warning_msg( "Resource file '%s' does not have any variable attributes, skipping." % args.resource_file) else: # Initialize our counter init_counter(len(nc4_files_root), "Applying variable attributes to file") for nc4_entry in nc4_files_root: # Update progress counter progress_counter(nc4_entry["file"]) # Iterate through all of our var_attr variables for var in resource_data["variable_attributes"]: if var in nc4_entry["group"].variables.keys(): for var_attr_key in resource_data[ "variable_attributes"][var]: var_attr_val = resource_data[ "variable_attributes"][var][var_attr_key] var_attr_key = str(var_attr_key) # We need to convert unicode to ASCII if type(var_attr_val) == unicode: var_attr_val = list(str(var_attr_val)) # BUG fix - NetCDF really, really, REALLY does not like # 64-bit integers. We forcefully convert the value to a # 32-bit signed integer, with some help from numpy! if type(var_attr_val) == int: var_attr_val = numpy.int32(var_attr_val) setattr(nc4_entry["group"].variables[var], var_attr_key, var_attr_val) else: warning_msg("Can't find variable %s in file %s!" % (var, nc4_entry["file"])) line_msg_done() # Close everything init_counter(len(nc4_files_root), "Saving changes to file") for nc4_entry in nc4_files_root: progress_counter(nc4_entry["file"]) nc4_entry["group"].close() line_msg_done() info_msg("Attribute appending complete!")
import sys import traceback import numpy try: import ujson as json except: import json # Version information __version__ = "0.9b" VERSION_STR = 'nc_diag_attr v' + __version__ + "\n\n" + \ "Using the following library/runtime versions:\n" + \ (" netcdf4-python v%s\n" % netCDF4.__version__) + \ (" NetCDF v%s\n" % getlibversion()) + \ (" HDF5 v%s\n" % netCDF4.__hdf5libversion__) + \ (" Python v%s\n" % sys.version.split("\n")[0].strip()) # CLI Arguments global args def parse_cli_args(): global args parser = argparse.ArgumentParser( #prog='ipush', formatter_class=argparse.RawDescriptionHelpFormatter, description= "Tool to add/modify global and variable attributes for NetCDF files", version=VERSION_STR)
def write_bathy(x, h, path, y=None, ncsave=True, dt=None): ''' Parameters: ---------- x : array of x coordinates y : array of x coordinates (optional) h : Bathymetry path : Full path where the output will be saved ncsave : Save bathy as NetCDF file dt : (Optional) informs about the stability for a chosen dt Output: ------- depth.txt : Text file with the depth information for Funwave input. depth.nc : (Optional) NetCDF4 bathymetry file. Notes: ------ 1. Variables are assumed to be on a regularly spaced grid. 2. If y is passed then 2D bathymetry is assumed. This means that x,y,h have to be 2D arrays. Otherwise the code will fail. ''' # Output the text file ----------------------------------------------------- fid = open(path + 'depth.txt', 'w') if y is None: for aa in range(len(h)): fid.write('%12.3f\n' % h[aa]) fid.close() else: for aa in range(h.shape[1]): for bb in range(h.shape[0]): fid.write('%12.3f' % h[bb, aa]) fid.write('\n') fid.close() if ncsave: # Global attributes nc = netCDF4.Dataset(path + 'depth.nc', 'w', format='NETCDF4') nc.Description = 'Funwave Bathymetry' nc.Author = getpass.getuser() nc.Created = time.ctime() nc.Owner = 'Nearshore Modeling Group (http://ozkan.oce.orst.edu/nmg)' nc.Software = 'Created with Python ' + sys.version nc.NetCDF_Lib = str(netCDF4.getlibversion()) nc.Script = os.path.realpath(__file__) # Create dimensions if y is None: xi_rho = len(h) nc.createDimension('xi_rho', xi_rho) varShape = ('xi_rho') else: eta_rho, xi_rho = np.shape(h) nc.createDimension('xi_rho', xi_rho) nc.createDimension('eta_rho', eta_rho) varShape = ('eta_rho', 'xi_rho') # Write y variable create_nc_var(nc, 'y_rho', varShape, 'meter', 'y-locations of RHO-points') nc.variables['y_rho'][:] = y # Write coordinates and depth to netcdf file create_nc_var(nc, 'x_rho', varShape, 'meter', 'x-locations of RHO-points') nc.variables['x_rho'][:] = x create_nc_var(nc, 'h', varShape, 'meter', 'bathymetry at RHO-points') nc.variables['h'][:] = h # Close NetCDF file nc.close() else: print("NetCDF file not requested") #=========================================================================== # Print input file options #=========================================================================== print(' ') print( '===================================================================') print('In your funwaveC init file:') if y is None: dx = np.abs(x[1] - x[0]) print('dimension ' + np.str(len(x) + 1) + ' 6 ' + np.str(dx) + ' 1') else: dx = np.abs(x[0, 1] - x[0, 0]) # For later use dy = np.abs(y[1, 0] - y[0, 0]) print('dimension ' + np.str(x.shape[1] + 1) + ' ' + np.str(x.shape[0]) + ' ' + np.str(dx) + ' ' + np.str(dy)) print( '===================================================================') print(' ') # Stability options stabilityCriteria(dx, h.max(), dt=dt, verbose=True)
def write_bathy(x,z,outfld,y=None,ncsave=True): """ Parameters: ----------- x : Vector or gridded x coordinates y : Vector or gridded y coordinates (optional) outfld : Full path to where the files will be written z : Vector or gridded depth ncsave : Save as netcdf file as well Output: ------- Writes two or three files depending on the configuration x.grd, y.grd, z.dep Notes: ------ Right now has been tested in 1d mode only """ # Output the text file ----------------------------------------------------- if y is not None: print("Writing 2D grids") fidx = open(outfld + 'x.grd','w') fidy = open(outfld + 'y.grd','w') fidz = open(outfld + 'z.dep','w') for aa in range(z.shape[0]): for bb in range(z.shape[1]): fidx.write('%16.4f' % x[aa,bb]) fidy.write('%16.4f' % y[aa,bb]) fidz.write('%16.4f' % z[aa,bb]) fidx.write('\n') fidy.write('\n') fidz.write('\n') fidx.close() fidy.close() fidz.close() else: print("Writing 1D grids") # Water depth fid = open(outfld + 'z.dep','w') for aa in range(len(z)): fid.write('%16.4f' % z[aa]) fid.write('\n') fid.close() # Coordinates fid = open(outfld + 'x.grd','w') for aa in range(len(x)): fid.write('%16.4f' % x[aa]) fid.write('\n') fid.close() # NetCDF File -------------------------------------------------------------- if ncsave: # Global attributes nc = netCDF4.Dataset(outfld + 'depth.nc', 'w', format='NETCDF4') nc.Description = 'Xbeach Bathymetry' nc.Author = getpass.getuser() nc.Created = time.ctime() nc.Owner = 'Nearshore Modeling Group (http://ozkan.oce.orst.edu/nmg)' nc.Software = 'Created with Python ' + sys.version nc.NetCDF_Lib = str(netCDF4.getlibversion()) nc.Script = os.path.realpath(__file__) # Create dimensions if y is not None: tmpDims = ('eta_rho','xi_rho') xi_rho = z.shape[1] eta_rho = z.shape[0] nc.createDimension('eta_rho',eta_rho) else: tmpDims = ('xi_rho') xi_rho = z.shape[-1] nc.createDimension('xi_rho', xi_rho) # Write coordinates and depth to netcdf file nc.createVariable('x_rho','f8',tmpDims) nc.variables['x_rho'].units = 'meter' nc.variables['x_rho'].long_name = 'x-locations of RHO-points' nc.variables['x_rho'][:] = x nc.createVariable('h','f8',tmpDims) nc.variables['h'].units = 'meter' nc.variables['h'].long_name = 'bathymetry at RHO-points' nc.variables['h'][:] = z if y is not None: nc.createVariable('y_rho','f8',tmpDims) nc.variables['y_rho'].units = 'meter' nc.variables['y_rho'].long_name = 'y-locations of RHO-points' nc.variables['y_rho'][:] = y # Close NetCDF file nc.close() #=========================================================================== # Print input file options #=========================================================================== print(' ') print('===================================================================') print('In your params.txt:') print(' nx = ' + np.str(xi_rho - 1)) if y is not None: print(' ny = ' + np.str(eta_rho - 1)) else: print(' ny = 0') print('===================================================================')
else: NC_RESOURCE = { 'transect': 'http://opendap.deltares.nl/thredds/dodsC/opendap/rijkswaterstaat/jarkus/profiles/transect.nc', # Use this if we break the deltares server: #'transect': 'http://opendap.tudelft.nl/thredds/dodsC/data2/deltares/rijkswaterstaat/jarkus/profiles/transect.nc', 'BKL_TKL_TND': 'http://opendap.deltares.nl/thredds/dodsC/opendap/rijkswaterstaat/BKL_TKL_MKL/BKL_TKL_TND.nc', 'DF': 'http://opendap.deltares.nl/thredds/dodsC/opendap/rijkswaterstaat/DuneFoot/DF.nc', # 'DF': 'http://dtvirt5.deltares.nl:8080/thredds/dodsC/opendap/rijkswaterstaat/DuneFoot/DF_r2011.nc', 'MKL': 'http://opendap.deltares.nl/thredds/dodsC/opendap/rijkswaterstaat/BKL_TKL_MKL/MKL.nc', 'strandbreedte': 'http://opendap.deltares.nl/thredds/dodsC/opendap/rijkswaterstaat/strandbreedte/strandbreedte.nc', 'strandlijnen': 'http://opendap.deltares.nl/thredds/dodsC/opendap/rijkswaterstaat/MHW_MLW/MHW_MLW.nc', 'suppleties': 'http://opendap.deltares.nl/thredds/dodsC/opendap/rijkswaterstaat/suppleties/suppleties.nc', 'faalkans': 'http://opendap.deltares.nl/thredds/dodsC/opendap/rijkswaterstaat/faalkans_PC-Ring/faalkans.nc', } if '4.1.3' in netCDF4.getlibversion(): logger.warn('There is a problem with the netCDF 4.1.3 library that causes performance issues for opendap queries, you are using netcdf version {0}'.format(netCDF4.getlibversion())) proj = pyproj.Proj('+proj=sterea +lat_0=52.15616055555555 +lon_0=5.38763888888889 +k=0.9999079 +x_0=155000 +y_0=463000 +ellps=bessel +towgs84=565.237,50.0087,465.658,-0.406857,0.350733,-1.87035,4.0812 +units=m +no_defs') class NoDataForTransect(Exception): def __init__(self, transect_id): message = "Could not find transect data for transect {0}".format(transect_id) super(NoDataForTransect, self).__init__(message) class Transect(object): """Transect that has coordinates and time""" def __init__(self, id): self.id = id
def fort14_to_nc(fort14, **kwargs): """ Script to read an unstructured grid in fort.14 format and store it in a netcdf4 file PARAMETERS: ----------- fort14: Path to fort14 file savepath(optional) RETURNS: -------- Netcdf containing x,y: node coordinates element: triangular elements nbdv: node numbers on each elevation specified boundary segment nbvv: node numbers on normal flow boundary segment depth: depth at each node """ grid = ustr.read_fort14(fort14) # Create the file and add global attributes if 'savepath' in kwargs: ncfile = kwargs['savepath'] else: ncfile = fort14 + '.nc' nc = netCDF4.Dataset(ncfile, 'w', format='NETCDF4') # Global attributes nc.Author = getpass.getuser() nc.Created = time.ctime() nc.Software = 'Created with Python ' + sys.version nc.NetCDF_Lib = str(netCDF4.getlibversion()) # Get record lengths node = grid['x'].size nele = grid['triang'].shape[0] nvertex = grid['triang'].shape[1] # nope = grid['nope'] neta = grid['neta'] # nbou = grid['nbou'] nvel = grid['nvel'] # Create dimensions nc.createDimension('node', node) # Number of nodes nc.createDimension('nele', nele) # Number of elements nc.createDimension('nvertex', nvertex) # Number of vertex nc.createDimension('neta', neta) # Number of elevation boundary nodes nc.createDimension('nvel', nvel) # Number of normal flow boundary nodes # Create variables nc.createVariable('x', 'f8', 'node') nc.variables['x'].long_name = 'longitude' nc.variables['x'].units = 'degrees_east' nc.variables['x'].positive = 'east' nc.variables['x'][:] = np.float64(grid['x']) nc.createVariable('y', 'f8', 'node') nc.variables['y'].long_name = 'latitude' nc.variables['y'].units = 'degrees_north' nc.variables['y'].positive = 'north' nc.variables['y'][:] = np.float64(grid['y']) nc.createVariable('element', 'i4', ('nele', 'nvertex')) nc.variables['element'].long_name = 'element' nc.variables['element'].units = 'nondimensional' # Add 1 back to node indexing to match standard adcirc files convention nc.variables['element'][:, :] = np.int32(grid['triang'] + 1) nc.createVariable('nbdv', 'i4', 'neta') nc.variables[ 'nbdv'].long_name = 'node numbers on each elevation specified boundary segment' nc.variables['nbdv'].units = 'nondimensional' nc.variables['nbdv'][:] = np.int32(np.hstack(grid['nbdv'])) nc.createVariable('nbvv', 'i4', 'nvel') nc.variables[ 'nbvv'].long_name = 'node numbers on normal flow boundary segment' nc.variables['nbvv'].units = 'nondimensional' nc.variables['nbvv'][:] = np.int32(np.hstack(grid['nbvv'])) nc.createVariable('depth', 'f8', 'node') nc.variables['depth'].long_name = 'distance below geoid' nc.variables['depth'].units = 'm' nc.variables['depth'][:] = np.float64(grid['z']) # All done here nc.close()
def write_bathy(x, z, outfld, y=None, ncsave=True): """ Parameters: ----------- x : Vector or gridded x coordinates y : Vector or gridded y coordinates (optional) outfld : Full path to where the files will be written z : Vector or gridded depth ncsave : Save as netcdf file as well Output: ------- Writes two or three files depending on the configuration x.grd, y.grd, z.dep Notes: ------ Right now has been tested in 1d mode only """ # Output the text file ----------------------------------------------------- if y is not None: print("Writing 2D grids") fidx = open(outfld + 'x.grd', 'w') fidy = open(outfld + 'y.grd', 'w') fidz = open(outfld + 'z.dep', 'w') for aa in range(z.shape[0]): for bb in range(z.shape[1]): fidx.write('%16.3f' % x[aa, bb]) fidy.write('%16.3f' % y[aa, bb]) fidz.write('%16.3f' % z[aa, bb]) fidx.write('\n') fidy.write('\n') fidz.write('\n') fidx.close() fidy.close() fidz.close() else: print("Writing 1D grids") # Water depth fid = open(outfld + 'z.dep', 'w') for aa in range(len(z)): fid.write('%16.3f' % z[aa]) fid.write('\n') fid.close() # Coordinates fid = open(outfld + 'x.grd', 'w') for aa in range(len(x)): fid.write('%16.3f' % x[aa]) fid.write('\n') fid.close() # NetCDF File -------------------------------------------------------------- if ncsave: # Global attributes nc = netCDF4.Dataset(outfld + 'depth.nc', 'w', format='NETCDF4') nc.Description = 'Xbeach Bathymetry' nc.Author = getpass.getuser() nc.Created = time.ctime() nc.Owner = 'Nearshore Modeling Group (http://ozkan.oce.orst.edu/nmg)' nc.Software = 'Created with Python ' + sys.version nc.NetCDF_Lib = str(netCDF4.getlibversion()) nc.Script = os.path.realpath(__file__) # Create dimensions if y is not None: tmpDims = ('eta_rho', 'xi_rho') xi_rho = z.shape[1] eta_rho = z.shape[0] nc.createDimension('eta_rho', eta_rho) else: tmpDims = ('xi_rho') xi_rho = z.shape[-1] nc.createDimension('xi_rho', xi_rho) # Write coordinates and depth to netcdf file nc.createVariable('x_rho', 'f8', tmpDims) nc.variables['x_rho'].units = 'meter' nc.variables['x_rho'].long_name = 'x-locations of RHO-points' nc.variables['x_rho'][:] = x nc.createVariable('h', 'f8', tmpDims) nc.variables['h'].units = 'meter' nc.variables['h'].long_name = 'bathymetry at RHO-points' nc.variables['h'][:] = z if y is not None: nc.createVariable('y_rho', 'f8', tmpDims) nc.variables['y_rho'].units = 'meter' nc.variables['y_rho'].long_name = 'y-locations of RHO-points' nc.variables['y_rho'][:] = y # Close NetCDF file nc.close() #=========================================================================== # Print input file options #=========================================================================== print(' ') print( '===================================================================') print('In your params.txt:') print(' nx = ' + np.str(xi_rho - 1)) if y is not None: print(' ny = ' + np.str(eta_rho - 1)) else: print(' ny = 0') print( '===================================================================')
fnc.variables['longitude'][:] = long_host fnc.variables['longitude'].long_name = 'Longitude E' fnc.variables['longitude'].units = 'degrees' fnc.createVariable('time', 'i', dimensions=['time']) fnc.variables['time'][:] = months_out fnc.variables['time'].units = 'months' fnc.variables[ 'time'].long_name = 'number of months that have elapsed since 2001-01-01' fnc.createVariable('ForestLoss', 'd', dimensions=['time', 'latitude', 'longitude'], zlib=True, complevel=1) fnc.variables['ForestLoss'][:, :, :] = GFW_monthly fnc.variables['ForestLoss'].long_name = 'GFL/FORMA fusion monthly forest loss' fnc.variables[ 'ForestLoss'].units = 'fraction of grid cell in which forest loss has occurred within that month' fnc.variables['ForestLoss'].missing_value = 0. fnc.production_date = '%s %s' % (time.asctime(), time.tzname[0]) fnc.production_software = 'Python %s - netCDF4 library %s' % ( sys.version, netCDF4.getlibversion()) fnc.production_source = 'UMD Global Forest Loss Dataset & FORMA' fnc.production_method = 'This file contains a forest loss product created by fusing Hansen and FORMA. Data are regridded to a %4.2fx%4.2f grid. Monthly forest loss are estimated by scaling annual GFL forest loss extents by ratio of FORMA disturbance for each month divided by annual FORMA disturbance in that year' % ( dX, dY) fnc.sync() fnc.close()
def unSWANCompToNetcdf(swanFile, swanGrid): """ Convert UnSWAN results over all the computational grid to NetCDF4 PARAMETERS: ----------- swanFile - Ascii file with bulk parameter output over all computational grid swanGrid - The fort.14 file (for now) RETURNS: -------- NetCDF file with the same name as swanFile with .nc extension NOTES: ------ 1. Only works with fort.14 files 2. It is assumed that the first three variables in swanFile are: Time Xp Yp ... TODO: ----- 1. Implement conversion from stationary conditions 2. Implement ability to read from Triangle """ # Read grid file ----------------------------------------------------------- fobj = open(swanGrid, 'r') fobj.readline() tmpline = fobj.readline().split() nele = np.int(tmpline[0]) npt = np.int(tmpline[1]) xp = np.zeros((npt, )) yp = np.zeros_like(xp) # Read the grid (just in case) for aa in range(npt): tmpline = fobj.readline().split() xp[aa] = np.float(tmpline[1]) yp[aa] = np.float(tmpline[2]) # Read triangles triang = np.zeros((nele, 3), dtype=np.int) for aa in range(nele): tmpline = fobj.readline().split() triang[aa, 0] = np.int(tmpline[2]) triang[aa, 1] = np.int(tmpline[3]) triang[aa, 2] = np.int(tmpline[4]) # All done here fobj.close() # Remember zero counting in python triang -= 1 # Read the computational grid output --------------------------------------- fobj = open(swanFile, 'r') # Discard the first two lines fobj.readline() fobj.readline() # Get the model information modInfo = fobj.readline().split(':') modInfo = { 'Run': modInfo[1].split(' ')[0], 'Table': modInfo[2].split(' ')[0], 'SWAN': modInfo[3][:-1] } # Empty line fobj.readline() # Variables varkeys = fobj.readline()[1:].split() # varkeys = fobj.readline()[1:-1] # varkeys = [item for item in filter(None,varkeys.split(' '))] # Find if the grid information is in the file gridFlag = 'Xp' in varkeys and 'Yp' in varkeys # Units units = fobj.readline()[1:].split()[1:] units[0] = '[UTC]' # Manually overwrite # Empty line fobj.readline() # Find all nodes in file tmpLine = fobj.readline().split() date0 = tmpLine[0] if gridFlag: xp = [] yp = [] xp.append(np.float64(tmpLine[1])) yp.append(np.float64(tmpLine[2])) outpnt = 1 for line in fobj: if line.split()[0] == date0: if gridFlag: xp.append(np.float64(line.split()[1])) yp.append(np.float64(line.split()[2])) outpnt += 1 else: break if gridFlag: xp = np.asarray(xp) yp = np.asarray(yp) # Close the file fobj.close() # Sanity check here #if outpnt != npt: # print("Dimensions of grid and output are different") # return # Read File and Prepare NetCDF File ---------------------------------------- print("Creating netCDF file") # Create the file and add global attributes outFile = swanFile + '.nc' nc = _netCDF4.Dataset(outFile, 'w', format='NETCDF4') nc.Description = 'UnSWAN Output' nc.Author = _getpass.getuser() nc.Created = _time.ctime() nc.Software = 'Created with Python ' + _sys.version nc.NetCDF_Lib = str(_netCDF4.getlibversion()) nc.Source = swanFile nc.Run = modInfo['Run'] nc.Version = modInfo['SWAN'] nc.Table = modInfo['Table'] # Create dimensions nc.createDimension('three', 3) nc.createDimension('nele', nele) # Number of elements nc.createDimension('npnt', npt) # Number of nodes nc.createDimension('time', 0) # The unlimited dimension # Create time vector nc.createVariable('ocean_time', 'f8', ('time')) nc.variables['ocean_time'].units = 'seconds since 1900-01-01 00:00:00' nc.variables['ocean_time'].calendar = 'julian' nc.createVariable('matlab_time', 'f8', ('time')) nc.variables['matlab_time'].units = 'Days since 0000-01-01 00:00:00' # Write coordinates nc.createVariable(varkeys[1], 'f8', ('npnt')) nc.variables[varkeys[1]].units = units[1][1:-1] nc.variables[varkeys[1]][:] = xp nc.createVariable(varkeys[2], 'f8', ('npnt')) nc.variables[varkeys[2]].units = units[2][1:-1] nc.variables[varkeys[2]][:] = yp # Write the elements nc.createVariable('elements', 'f8', ('nele', 'three')) nc.variables['elements'].long_name = 'Triangulation' nc.variables['elements'][:] = triang # Create the rest of the variables for aa in range(3, len(varkeys)): nc.createVariable(varkeys[aa], 'f8', ('time', 'npnt')) nc.variables[varkeys[aa]].units = units[aa][1:-1] # ============================================================================== # Read and write variables to netCDF file # ============================================================================== print(" Reading and writing the file contents ...") # First three variables are already considered varkeys = varkeys[3:] # Load the swan file again fobj = open(swanFile) # Ignore the first seven lines for aa in range(7): fobj.readline() # Preallocate variable container # If the grid is not crazy large this should be ok tmpvars = np.zeros((len(varkeys), npt)) cnt = 0 tstep = -1 # Time step counter (location in netcdf file) # Loop until the end of the file for line in fobj: # Increase counter variable cnt += 1 # Temporarily allocate variables aa = np.asarray([np.float64(aa) for aa in line.split()]) tmpvars[:, cnt - 1] = aa[3:] # Write variables if all nodes have been read for the current time if cnt == npt: # Quick update print(' Storing ' + line.split()[0]) # Increase time step variable tstep += 1 # Time management timePython = datetime.datetime.strptime(line.split()[0], "%Y%m%d.%H%M%S") nc.variables['matlab_time'][tstep] = _gtime.datetime_to_datenum( timePython) ocean_time = timePython - datetime.datetime(1900, 1, 1) nc.variables['ocean_time'][tstep] = ocean_time.total_seconds() # Write variables to netcdf file for aa in range(len(varkeys)): nc.variables[varkeys[aa]][tstep, ...] = tmpvars[aa, :] # Reset counter variable cnt = 0 # Reset variable container tmpvars *= np.NAN # All done here fobj.close() nc.close()
def spec2nc(buoyfld,dtheta=5): ''' Code to convert NDBC spectral data files to netCDF format. Usage: ------ spec2nc(buoyfld,dtheta) Input: ------ buoyfld : Folder where the text files reside. Those should be the only files in the folder. dtheta : Directional resolution for the reconstruction of the frequency- direction spectrum. Defaults to 5 degrees. Notes: 1. NetCDF4 file will be generated 2. Code is not optimized since this is not something you will want to be running often. Beware of slow performance for large datasets. References: Kuik, A.J., G.Ph. van Vledder, and L.H. Holthuijsen, 1998: "Method for the Routine Analysis of Pitch-and-Roll Buoy Wave Data", Journal of Physical Oceanography, 18, 1020-1034. TODO: Only works with newer formats (YY MM DD hh mm) ''' # For testing only --------------------------------------------------------- # buoyfld = '/home/shusin2/users/ggarcia/data/wave/b46029/spec/' # dtheta = 5 # -------------------------------------------------------------------------- # Construct directional angle angles = np.arange(0.0,360.0,dtheta) # Time reference basetime = datetime.datetime(1900,01,01,0,0,0) #=========================================================================== # Read file information #=========================================================================== # Get all files in folder archivos = os.listdir(buoyfld) # Year information years = [x.split('.')[0][-4:] for x in archivos] # Get all year stamps years = list(set(years)) # Find unique years years.sort() # Sort years # Get buoy ID information buoyid = [x[0:5] for x in archivos] # Find buoy ids buoyid = list(set(buoyid)) # Find unique ids if len(buoyid)>1: print('This code does not support conversion for multiple buoys') buoyid = buoyid[0] print(' ' + buoyid + ' will be processed') else: buoyid = buoyid[0] # Create output netcdf file ------------------------------------------------ # Global attributes nc = netCDF4.Dataset(buoyfld + '/' + buoyid + '_spec.nc', 'w',format='NETCDF4') nc.Description = buoyid + ' NDBC Spectral Data' nc.Rawdata = 'National Data Buoy Center \nwww.ndbc.noaa.gov' nc.Author = getpass.getuser() nc.Created = time.ctime() nc.Software = 'Created with Python ' + sys.version nc.NetCDF_Lib = str(netCDF4.getlibversion()) nc.Script = os.path.realpath(__file__) nc.Notes = 'Nautical convention used for directions' # Create dimensions (NetCDF4 supports multiple unlimited dimensions) nc.createDimension('wave_time',None) nc.createDimension('dir_time',None) # Create bulk parameter variables nc.createVariable('Hsig','f8','wave_time') nc.variables['Hsig'].units = 'meter' nc.variables['Hsig'].long_name = 'Significant wave height' # Reconstruct the spectrum ------------------------------------------------- # counter variable to create variables in the netcdf file cnt_freq = 0 cnt_dir = 0 tstep_freq = 0 tstep_dir = 0 # Loop over years for aa in years: # Load spectral density files # Check if file exists tmpfile = buoyfld + buoyid + 'w' + aa + '.txt' if os.path.isfile(tmpfile) == False: # No spectral density found for the given year, go to next one continue # Read spectral density data (frequency spectra) f_w = open(tmpfile,'r') freq = f_w.readline().split() # Read frequencies freq = np.array(freq[5:],dtype=float) f_w.close() # Load spectral density freq_spec = np.loadtxt(tmpfile,skiprows=1) # Allocate time and spectral density data freq_time = np.zeros((freq_spec.shape[0])) for bb in range(freq_time.shape[0]): freq_time[bb] = (datetime.datetime(np.int(freq_spec[bb,0]), np.int(freq_spec[bb,1]), np.int(freq_spec[bb,2]), np.int(freq_spec[bb,3]), np.int(freq_spec[bb,4])) - basetime).total_seconds() freq_spec = freq_spec[:,5:] # Create frequency spectra variables cnt_freq += 1 if cnt_freq == 1: nc.createDimension('freq',freq.shape[0]) nc.createVariable('wave_time','f8','wave_time') nc.variables['wave_time'].units = \ "seconds since 1900-01-01 00:00:00" nc.variables['wave_time'].calendar = "julian" nc.createVariable('freq_spec','f8',('wave_time','freq')) nc.variables['freq_spec'].units = 'meter2 second' nc.variables['freq_spec'].long_name = 'Frequency variance spectrum' nc.createVariable('frequency','f8',('freq')) nc.variables['frequency'].units = 'Hz' nc.variables['frequency'].long_name = 'Spectral frequency' nc.variables['frequency'][:] = freq # Check if directional data exists tmp_alpha_1 = buoyfld + buoyid + 'd' + aa + '.txt' tmp_alpha_2 = buoyfld + buoyid + 'i' + aa + '.txt' tmp_r_1 = buoyfld + buoyid + 'j' + aa + '.txt' tmp_r_2 = buoyfld + buoyid + 'k' + aa + '.txt' if (os.path.isfile(tmp_alpha_1) and os.path.isfile(tmp_alpha_2) and os.path.isfile(tmp_r_1) and os.path.isfile(tmp_r_2)): # Create directional spectra variables cnt_dir += 1 if cnt_dir == 1: nc.createDimension('dir',angles.shape[0]) nc.createVariable('dir_time','f8','dir_time') nc.variables['dir_time'].units = \ "seconds since 1900-01-01 00:00:00" nc.variables['dir_time'].calendar = "julian" nc.createVariable('dir_spec','f8',('dir_time','freq','dir')) nc.variables['dir_spec'].units = 'meter2 second degree-1' nc.variables['dir_spec'].long_name = \ 'Frequency-Direction variance spectrum' nc.createVariable('direction','f8',('dir')) nc.variables['direction'].units = 'degree' nc.variables['direction'].long_name = \ 'Degrees from true north in oceanographic convention' nc.variables['direction'][:] = angles # Read spectral data alpha_1 = np.loadtxt(tmp_alpha_1,skiprows=1) alpha_2 = np.loadtxt(tmp_alpha_1,skiprows=1) r_1 = np.loadtxt(tmp_alpha_1,skiprows=1) * 0.01 r_2 = np.loadtxt(tmp_alpha_1,skiprows=1) * 0.01 # Allocate data dir_time = np.zeros((alpha_1.shape[0])) for bb in range(dir_time.shape[0]): dir_time[bb] = (datetime.datetime(np.int(alpha_1[bb,0]), np.int(alpha_1[bb,1]), np.int(alpha_1[bb,2]), np.int(alpha_1[bb,3]), np.int(alpha_1[bb,4])) - basetime).total_seconds() alpha_1 = alpha_1[:,5:] alpha_2 = alpha_2[:,5:] r_1 = r_1[:,5:] r_2 = r_2[:,5:] # Construct 2D spectra # See http://www.ndbc.noaa.gov/measdes.shtml wspec = np.NaN * np.zeros((alpha_1.shape[0], freq.shape[0],angles.shape[0])) # Time loop for bb in range(wspec.shape[0]): # Frequency loop for cc in range(wspec.shape[1]): # Direction loop for dd in range(wspec.shape[2]): wspec[bb,cc,dd] = (freq_spec[bb,cc] * np.pi/180.0 * (1.0/np.pi) * (0.5 + r_1[bb,cc] * np.cos((angles[dd]-alpha_1[bb,cc])* np.pi/180.0) + r_2[bb,cc] * np.cos(2 * np.pi / 180.0 * (angles[dd]-alpha_2[bb,cc]))) ) # Write to file if cnt_dir == 1: nc.variables['dir_spec'][:] = wspec nc.variables['dir_time'][:] = dir_time else: nc.variables['dir_spec'][tstep_dir:,:,:] = wspec nc.variables['dir_time'][tstep_dir:] = dir_time tstep_dir += dir_time.shape[0] # Compute bulk parameters moment0 = np.trapz(freq_spec.T,freq,axis=0) Hsig = 4.004*(moment0)**0.5 # Write to NetCDF file if cnt_freq == 1: nc.variables['Hsig'][:] = Hsig nc.variables['freq_spec'][:] = freq_spec nc.variables['wave_time'][:] = freq_time else: nc.variables['Hsig'][tstep_freq:] = Hsig nc.variables['freq_spec'][tstep_freq:,:] = freq_spec nc.variables['wave_time'][tstep_freq:] = freq_time tstep_freq += freq_time.shape[0] # Wrap up ------------------------------------------------------------------ # Close NetCDF File nc.close()
def max63_to_nc(max63, varname='zeta', longname='water surface elevation above geoid', varunits='m', ncdate='0000-00-00 00:00:00 UTC', **kwargs): """ Script to read max63-type (max-min) files and store in a netcdf4 file PARAMETERS: ----------- max63: Path to max63-type file ncdate : cold start date/time in CF standard: yyyy-MM-dd hh:mm:ss tz RETURNS: -------- Netcdf containing time : seconds since beginning of run x,y variable : temporal variables (name provided in 'xy_varname') recorded at the nodes of an unstructured grid. Size: [time,nodes] """ fobj = open(max63, 'r') # Create the file and add global attributes if 'savename' in kwargs: ncfile = kwargs['savename'] else: ncfile = max63 + '.nc' nc = netCDF4.Dataset(ncfile, 'w', format='NETCDF4') # Global attributes nc.Author = getpass.getuser() nc.Created = time.ctime() tmpline = fobj.readline() nc.description = tmpline[2:34] nc.rundes = tmpline[2:34] nc.runid = tmpline[36:60] nc.model = 'ADCIRC' nc.Software = 'Created with Python ' + sys.version nc.NetCDF_Lib = str(netCDF4.getlibversion()) # Record number of time steps and nodes nodes = np.int(fobj.readline().split()[1]) # Create dimensions nc.createDimension('time', 0) # The unlimited dimension nc.createDimension('node', nodes) # Number of nodes # Create time vector nc.createVariable('time', 'f8', ('time')) nc.variables['time'].long_name = 'model time' nc.variables['time'].standard_name = 'time' nc.variables['time'].units = 'seconds since ' + ncdate nc.variables['time'].base_date = ncdate # Create the rest of the variables nc.createVariable(varname + '_max', 'f8', 'node') nc.variables[varname + '_max'].long_name = 'maximum ' + longname nc.variables[varname + '_max'].units = varunits nc.createVariable('time_of_' + varname + '_max', 'f8', 'node') nc.variables['time_of_' + varname + '_max'].long_name = 'time of maximum ' + longname nc.variables['time_of_' + varname + '_max'].units = 'sec' # Store last time-step in run for reference nc.variables['time'][0] = np.float64(fobj.readline().split()[0]) # Store max variable observations for aa in range(nodes): nc.variables[varname + '_max'][aa] = np.float64( fobj.readline().split()[1]) # Skip repeated time fobj.readline() for aa in range(nodes): nc.variables['time_of_' + varname + '_max'][aa] = np.float64( fobj.readline().split()[1]) # All done here fobj.close() nc.close()
def write_bathy(outfld, lon, lat, depth, spherical=True): """ Function to generate bathymetry files to be used as input for WW3 v4.18 PARAMETERS: ----------- outfld : folder to write the files to lon : longitudes (or x for cartesian) at every grid point (I assume they have been meshgridded) lat : latitudes (or y for cartesian) at every grid point spherical : True for spherical grids and False for cartesian grids OUTPUT: ------- ww3_grid.bot : ASCII file containing the grid depths ww3_grid.lon : ASCII file containing the longitudes (or x locations) ww3_grid.lat : ASCII file containing the latitudes (or y locations) ww3_grid.nc : NetCDF file containing the grid information ww3_grid.inp : Input file template to be used for the grid preprocessor. You will need to fix many things it will probably not work out of the box. NOTES: ------ I assume that if the grid is in spherical coordiantes the latitude and longitudes are given in decimal degrees (east). On the other hand if the grid is cartesian I assume meters. """ # Convert longitudes to degrees east lon = gangles.wrapto360(lon) # Write ascii files -------------------------------------------------------- # Bathymetry fid = open(outfld + "ww3_grid.bot", "w") for aa in range(depth.shape[0]): for bb in range(depth.shape[1]): fid.write("%12.4f" % depth[aa, bb]) fid.write("\n") fid.close() # Latitude File fid = open(outfld + "ww3_grid.lat", "w") for aa in range(lat.shape[0]): for bb in range(lat.shape[1]): fid.write("%12.4f" % lat[aa, bb]) fid.write("\n") fid.close() # Longitude File fid = open(outfld + "ww3_grid.lon", "w") for aa in range(lon.shape[0]): for bb in range(lon.shape[1]): fid.write("%12.4f" % lon[aa, bb]) fid.write("\n") fid.close() # Write netcdf file -------------------------------------------------------- # Global attributes nc = netCDF4.Dataset(outfld + "ww3_grid.nc", "w", format="NETCDF4") nc.Description = "Wavewatch III Bathymetry" nc.Author = getpass.getuser() nc.Created = time.ctime() nc.Owner = "Nearshore Modeling Group (http://ozkan.oce.orst.edu/nmg)" nc.Software = "Created with Python " + sys.version nc.NetCDF_Lib = str(netCDF4.getlibversion()) nc.Script = os.path.realpath(__file__) # Create dimensions nc.createDimension("xi_rho", lon.shape[1]) nc.createDimension("eta_rho", lon.shape[0]) # Write coordinates and depth to netcdf file if spherical: nc.createVariable("lat_rho", "f8", ("eta_rho", "xi_rho")) nc.variables["lat_rho"].units = "degree_north" nc.variables["lat_rho"].long_name = "latitude of RHO-points" nc.variables["lat_rho"][:] = lat else: nc.createVariable("y_rho", "f8", ("eta_rho", "xi_rho")) nc.variables["y_rho"].units = "meter" nc.variables["y_rho"].long_name = "y location of RHO-points" nc.variables["y_rho"][:] = lat # Write longitude if spherical: nc.createVariable("lon_rho", "f8", ("eta_rho", "xi_rho")) nc.variables["lon_rho"].units = "degree_east" nc.variables["lon_rho"].long_name = "latitude of RHO-points" nc.variables["lon_rho"][:] = lon else: nc.createVariable("x_rho", "f8", ("eta_rho", "xi_rho")) nc.variables["x_rho"].units = "meter" nc.variables["x_rho"].long_name = "x location of RHO-points" nc.variables["x_rho"][:] = lon # Write water depth nc.createVariable("h", "f8", ("eta_rho", "xi_rho")) nc.variables["h"].units = "meter" nc.variables["h"].long_name = "bathymetry at RHO-points" nc.variables["h"][:] = depth # Close NetCDF file nc.close() # Write input file for grid preprocessor ---------------------------------- # Create a generic input file fid = open(outfld + "ww3_grid.inp", "w") fid.write("$ ----------------------------------------------------------$\n") fid.write("$ WAVEWATCH III Grid preprocessor input file $\n") fid.write("$ ----------------------------------------------------------$\n") fid.write("'Grid Name'\n") fid.write("$\n") fid.write("1.1 0.030 40 36 0.\n") fid.write("$\n") fid.write("F T T T T T\n") fid.write("$\n") fid.write("3600. 600. 3600. 300.\n") fid.write("$\n") fid.write("END OF NAMELISTS\n") fid.write("$\n") fid.write("$ Define grid --------------------------------------------- $\n") fid.write("$ Five records containing :\n") fid.write("$ 1 Type of grid, coordinate system and type of closure: GSTRG, FLAGLL,\n") fid.write("$ CSTRG. Grid closure can only be applied in spherical coordinates.\n") fid.write("$ GSTRG : String indicating type of grid :\n") fid.write("$ " "RECT" " : rectilinear\n") fid.write("$ " "CURV" " : curvilinear\n") fid.write("$ FLAGLL : Flag to indicate coordinate system :\n") fid.write("$ T : Spherical (lon/lat in degrees)\n") fid.write("$ F : Cartesian (meters)\n") fid.write("$ CSTRG : String indicating the type of grid index space closure :\n") fid.write("$ " "NONE" " : No closure is applied\n") fid.write("$ " "SMPL" " : Simple grid closure : Grid is periodic in the\n") fid.write("$ : i-index and wraps at i=NX+1. In other words,\n") fid.write("$ : (NX+1,J) => (1,J). A grid with simple closure\n") fid.write("$ : may be rectilinear or curvilinear.\n") fid.write("$ " "TRPL" " : Tripole grid closure : Grid is periodic in the\n") fid.write("$ : i-index and wraps at i=NX+1 and has closure at\n") fid.write("$ : j=NY+1. In other words, (NX+1,J<=NY) => (1,J)\n") fid.write("$ : and (I,NY+1) => (MOD(NX-I+1,NX)+1,NY). Tripole\n") fid.write("$ : grid closure requires that NX be even. A grid\n") fid.write("$ : with tripole closure must be curvilinear.\n") fid.write("$ 2 NX, NY. As the outer grid lines are always defined as land\n") fid.write("$ points, the minimum size is 3x3.\n") fid.write("$ 3 Unit number of file with x-coordinate.\n") fid.write("$ Scale factor and add offset: x <= scale_fac * x_read + add_offset.\n") fid.write("$ IDLA, IDFM, format for formatted read, FROM and filename.\n") fid.write("$ 4 Unit number of file with y-coordinate.\n") fid.write("$ Scale factor and add offset: y <= scale_fac * y_read + add_offset.\n") fid.write("$ IDLA, IDFM, format for formatted read, FROM and filename.\n") fid.write("$ 5 Limiting bottom depth (m) to discriminate between land and sea\n") fid.write("$ points, minimum water depth (m) as allowed in model, unit number\n") fid.write("$ of file with bottom depths, scale factor for bottom depths (mult.),\n") fid.write("$ IDLA, IDFM, format for formatted read, FROM and filename.\n") fid.write("$ IDLA : Layout indicator :\n") fid.write("$ 1 : Read line-by-line bottom to top.\n") fid.write("$ 2 : Like 1, single read statement.\n") fid.write("$ 3 : Read line-by-line top to bottom.\n") fid.write("$ 4 : Like 3, single read statement.\n") fid.write("$ IDFM : format indicator :\n") fid.write("$ 1 : Free format.\n") fid.write("$ 2 : Fixed format with above format descriptor.\n") fid.write("$ 3 : Unformatted.\n") fid.write("$ FROM : file type parameter\n") fid.write("$ " "UNIT" " : open file by unit number only.\n") fid.write("$ " "NAME" " : open file by name and assign to unit.\n") fid.write("$ If the Unit Numbers in above files is 10 then data is read from this file\n") fid.write("$\n") # I prefer considering only curvilinear grids. if spherical: fid.write("'CURV' T 'NONE'\n") else: fid.write("'CURV' F 'NONE'\n") # Grid size fid.write(np.str(lon.shape[1]) + " " + np.str(lon.shape[0]) + "\n") # Path to grid name fid.write(" 11 1.0 0. 1 1 '(....)' 'NAME' 'ww3_grid.lon'\n") fid.write(" 12 1.0 0. 1 1 '(....)' 'NAME' 'ww3_grid.lat'\n") # Bottom bathymetry information fid.write("$ Bottom bathymetry\n") fid.write(" -0.5 0.05 13 1 1 '(....)' 'NAME' 'ww3_grid.bot'\n") fid.write("$ Subgrid Information\n") fid.write(" 10 1 1 '(....)' 'PART' 'dummy'\n") # Subgrid information fid.write("$\n") fid.write(" 0 0 F\n") fid.write("$\n") fid.write(" 0 0 F\n") fid.write(" 0 0\n") fid.write("$\n") fid.write(" 0. 0. 0. 0. 0\n") fid.write("$ ----------------------------------------------------------$\n") fid.write("$ End of input file $\n") fid.write("$ ----------------------------------------------------------$\n") # Close input file fid.close()
def write_nc_spec(latitude, longitude, spectrum, frequency, direction, time1, station, fileout=None, spherical=True): ''' Parameters ---------- latitude : Array of the latitudes of each spectra point [Degree] Dimension (time,station) longitude : Array of the longitudes of each spectra point [Degree east] Dimension (time,station) spectrum : Variance spectrum [m2/Hz/rad] Dimensions (time,station,frequency,direction) frequency : frequency at each bin center [Hz] direction : direction of propagation of each spectral bin [rad] time : vector with days from 1900-01-01 00:00:00 station : Array with station names (not longer than 16 characters) fileout : Output netCDF file spherical : Flag for metadata. For spherical coordinates True and False for cartesian coordiantes. Notes: ------ Direction of where waves are traveling to. Version: -------- v0.1 code created: Gabriel Garcia Medina, Saeed Moghimi, April 2015 ''' # For testing purposes only ------------------------------------------------ #nctest = netCDF4.Dataset('/home/shusin2/shared/nmg/pycodes/' # 'ww3.basin.201401_spec.nc','r') #fileout = '/home/shusin2/shared/nmg/pycodes/test2.nc' #time1 = nctest.variables['time'][:] #station = nctest.variables['station'][:1] #latitude = nctest.variables['latitude'][:,:1] * 0.0 #longitude = nctest.variables['longitude'][:,:1] * 0.0+15.0 #frequency = nctest.variables['frequency'][:] #direction = nctest.variables['direction'][:] #spectrum = nctest.variables['efth'][:,:1,:,:] # ------------------------------------------------------------------------- # # Variable dictionary # varinfo = defaultdict(dict) # varinfo['frequency']['units'] = 's-1' # varinfo['frequency']['long_name'] = 'frequency of center band' # varinfo['frequency']['standard_name'] = 'sea_surface_wave_frequency' # varinfo['direction']['units'] = 'degree' # varinfo['direction']['long_name'] = 'sea surface wave to direction' # varinfo['direction']['standard_name'] = 'sea_surface_wave_to_direction' # varinfo['latitude']['units'] = 'degree_north' # varinfo['latitude']['long_name'] = 'latitude' # varinfo['latitude']['standard_name'] = 'latitude' # varinfo['longitude']['units'] = 'degree_east' # varinfo['longitude']['long_name'] = 'longitude' # varinfo['longitude']['standard_name'] = 'longitude' # varinfo['efth']['units'] = 'm2 s rad-1' # varinfo['efth']['long_name'] = ('sea surface wave directional variance' + # ' spectral density') # Create netcdf file if fileout: nc = netCDF4.Dataset(fileout, 'w') else: print("Writing NetCDF file " + os.getcwd() + "/ww3_spec_inp.nc") nc = netCDF4.Dataset('./ww3_spec_inp.nc', 'w') # Create general attributes nc.Description = 'Wavewatch III 4.18 input spectra file' nc.Author = getpass.getuser() nc.Created = time.ctime() nc.Owner = 'Nearshore Modeling Group (http://ozkan.oce.orst.edu/nmg)' nc.Software = 'Created with Python ' + sys.version nc.NetCDF_Lib = str(netCDF4.getlibversion()) nc.Script = os.path.realpath(__file__) # Create dimensions nc.createDimension('time', 0) nc.createDimension('frequency', frequency.shape[0]) nc.createDimension('direction', direction.shape[0]) nc.createDimension('string16', 16) nc.createDimension('station', len(station)) # Write time nc.createVariable('time', 'f8', ('time')) nc.variables['time'].long_name = 'julian day (UT)' nc.variables['time'].standard_time = 'time' nc.variables['time'].units = 'days since 1900-01-01T00:00:00Z' nc.variables['time'].conventions = ('Relative julian days with decimal ' + 'part (as parts of the day)') nc.variables['time'][:] = time1 # Write station id and name nc.createVariable('station', 'i8', ('station')) nc.variables['station'].long_name = 'station id' nc.variables['station'].axis = 'X' nc.variables['station'][:] = np.arange(0, len(station), 1) # IDK why they do this in WW3 so I am trying to mimic this behaviour nc.createVariable('string16', 'i8', ('string16')) nc.variables['string16'].long_name = 'station_name number of characters' nc.variables['string16'].axis = 'W' nc.variables['string16'][:] = np.empty((16, ), dtype=int) # Write station names nc.createVariable('station_name', 'S1', ('station', 'string16')) nc.variables['station_name'].long_name = 'station name' nc.variables['station_name'].content = 'XW' nc.variables['station_name'].associates = 'station string16' for aa in range(len(station)): nc.variables['station_name'][aa] = station[aa] # Spatial dimensions nc.createVariable('latitude', 'f8', ('time', 'station')) nc.variables['latitude'].long_name = 'latitude' nc.variables['latitude'].standard_name = 'latitude' nc.variables['latitude'].units = 'degree_north' nc.variables['latitude'].valid_min = -90.0 nc.variables['latitude'].valid_max = 90.0 nc.variables['latitude'].content = 'TX' nc.variables['latitude'].associates = 'time station' nc.variables['latitude'][:] = latitude nc.createVariable('longitude', 'f8', ('time', 'station')) nc.variables['longitude'].long_name = 'longitude' nc.variables['longitude'].standard_name = 'longitude' nc.variables['longitude'].units = 'degree_east' nc.variables['longitude'].valid_min = -180.0 nc.variables['longitude'].valid_max = 180.0 nc.variables['longitude'].content = 'TX' nc.variables['longitude'].associates = 'time station' nc.variables['longitude'][:] = gangles.wrapto180(latitude) # Create frequency and direction vectors nc.createVariable('frequency', 'f8', ('frequency')) nc.variables['frequency'].long_name = 'frequency of center band' nc.variables['frequency'].standard_name = 'sea_surface_wave_frequency' nc.variables['frequency'].globwave_name = 'frequency' nc.variables['frequency'].units = 's-1' nc.variables['frequency'].valid_min = 0.0 nc.variables['frequency'].valid_max = 10.0 nc.variables['frequency'].axis = 'Y' nc.variables['frequency'][:] = frequency nc.createVariable('direction', 'f8', ('direction')) nc.variables['direction'].long_name = 'sea surface wave to direction' nc.variables['direction'].standard_name = 'sea_surface_wave_to_direction' nc.variables['direction'].globwave_name = 'direction' nc.variables['direction'].units = 'degree' nc.variables['direction'].valid_min = 0.0 nc.variables['direction'].valid_max = 360.0 nc.variables['direction'][:] = gangles.wrapto360(direction) # Write spectral data nc.createVariable('efth', 'f8', ('time', 'station', 'frequency', 'direction')) nc.variables['efth'].long_name = ('sea surface wave directional variance' + ' spectral density') nc.variables['efth'].standard_name = ('sea_surface_wave_directional_' + 'variance_spectral_density') nc.variables[ 'efth'].globwave_name = 'directional_variance_spectral_density' nc.variables['efth'].units = 'm2 s rad-1' nc.variables['efth'].scale_factor = 1.0 nc.variables['efth'].add_offset = 0.0 nc.variables['efth'].valid_min = 0.0 nc.variables['efth'].valid_max = 1.0e20 nc.variables['efth'].content = 'TXYZ' nc.variables['efth'].associates = 'time station frequency direction' nc.variables['efth'][:] = spectrum nc.close()
def _process(self, l1a_file, monitor): running = True surface_processing = False status = -1 self.beam_angles_list_size_prev = -1 self.beam_angles_trend_prev = -1 self.surfaces_count = 0 # find base name of input file l1a_base, _ = os.path.splitext(os.path.basename(l1a_file)) if l1a_base.startswith('L1A'): l1a_base = l1a_base[len('L1A'):] l1a_base_part = '' if l1a_base: l1a_base_part = '_%s' % l1a_base name_part = '' if self.name: name_part = '_%s' % self.name # create l1b-s output path l1bs_name = 'L1BS%s%s.nc' % (l1a_base_part, name_part) l1bs_path = os.path.join(self.out_path, l1bs_name) # create l1b output path l1b_name = 'L1B%s%s.nc' % (l1a_base_part, name_part) l1b_path = os.path.join(self.out_path, l1b_name) # create output file objects writerCls = L1BWriter if self.cnf.output_format == OutputFormat.s3 else L1BWriterExtended self.l1b_file = writerCls(filename=l1b_path, chd=self.chd, cnf=self.cnf, cst=self.cst) if not self.skip_l1bs: self.l1bs_file = L1BSWriter(filename=l1bs_path, chd=self.chd, cnf=self.cnf, cst=self.cst) else: self.l1bs_file = None # open output files self.l1b_file.open() if self.l1bs_file is not None: self.l1bs_file.open() prev_time = None gap_processing = False gap_resume = False sub_monitor = None index = -1 while running: index += 1 if monitor.is_cancelled(): running = False # if a gap has been encountered, then the current lists of input packets & surfaces need to be processed # before reading another input. if not gap_processing: # monitor.progress(1) # if this is the first iteration after finishing a gap, then the next packet has already been read # so another one should not be retrieved from the L1A if not gap_resume: # input_packet = next(self.l1a_file) try: input_packet = next(self.l1a_file) except StopIteration: input_packet = None if not surface_processing: raise Exception("insufficient input records") else: monitor.progress(1) if input_packet is not None: # apply calibrations self.cal1_algorithm(input_packet) self.cal2_algorithm(input_packet) # check if there is a gap (or if this is the first packet & prev_time has not been set) if prev_time is None or input_packet.time_sar_ku - prev_time < self.gap_threshold: prev_time = input_packet.time_sar_ku new_surface = self.surface_locations(input_packet, force_new=gap_resume) gap_resume = False if new_surface is None: continue else: gap_processing = True prev_time = None sub_monitor = monitor.child(1) sub_monitor.start("processing gap", len(self.surf_locs)) elif sub_monitor is not None: sub_monitor.progress(1, len(self.surf_locs)) if surface_processing or len(self.surf_locs) >= self.min_surfs or gap_processing: surface_processing = True working_loc = self.surf_locs[0] for processed_packet in self.source_isps: if not processed_packet.burst_processed: self.beam_angles(self.surf_locs, processed_packet, working_loc) self.azimuth_processing(processed_packet) processed_packet.burst_processed = True if not self.beam_angles_algorithm.work_location_seen: break self.stack_gathering(working_loc) # if the current surface doesn't have enough contributing bursts, then # it should not be written to the outputs - and so the rest of the processing # is not needed if working_loc.data_stack_size < (self.cnf.n_looks_stack // 2): del self.surf_locs[0] # remove this surface from the queue else: self.geometry_corrections(working_loc) self.range_compression(working_loc) self.stack_masking(working_loc) self.multilooking(working_loc) self.sigma_zero_scaling(working_loc) if self.l1b_file is not None: self.l1b_file.write_record(working_loc) if self.l1bs_file is not None: self.l1bs_file.write_record(working_loc) self.clear_old_records(working_loc) if not self.surf_locs: if gap_processing: # all the remaining surfaces & bursts before the gap have been processed gap_processing = False # end gap mode gap_resume = True # next iteration will be the first after the gap surface_processing = False # require min. number of surfaces again sub_monitor.done() else: # the end of the input has been reached running = False status = None l1a_globals = self.l1a_file.read_globals() ctime = iso_format() ftime = iso_format(self.l1a_file.first_time()) ltime = iso_format(self.l1a_file.last_time()) # close output files self.l1b_file.write_globals( title='DeDop SRAL Level 1 Measurement', mission_name=l1a_globals.mission_name, altimeter_sensor_name=l1a_globals.altimeter_sensor_name, gnss_sensor_name=l1a_globals.gnss_sensor_name, doris_sensor_name=l1a_globals.doris_sensor_name, references=l1a_globals.references, acq_station_name=l1a_globals.acq_station_name, xref_altimeter_level0=l1a_globals.xref_altimeter_level0, xref_navatt_level0=l1a_globals.xref_navatt_level0, xref_altimeter_orbit=l1a_globals.xref_altimeter_orbit, xref_doris_uso=l1a_globals.xref_doris_uso, xref_altimeter_ltm_lrm_cal1=l1a_globals.xref_altimeter_ltm_lrm_cal1, xref_altimeter_ltm_sar_cal1=l1a_globals.xref_altimeter_ltm_sar_cal1, xref_altimeter_ltm_ku_cal2=l1a_globals.xref_altimeter_ltm_ku_cal2, xref_altimeter_ltm_c_cal2=l1a_globals.xref_altimeter_ltm_c_cal2, xref_altimeter_characterisation=l1a_globals.xref_altimeter_characterisation, xref_time_correlation=l1a_globals.xref_time_correlation, semi_major_ellipsoid_axis=self.cst.semi_major_axis, ellipsoid_flattening=self.cst.flat_coeff, netcdf_version=getlibversion(), product_name=l1a_globals.get_l1b_product_name(), institution='isardSAT', source='DeDop {}'.format(__version__), history=l1a_globals.history, contact='http://www.dedop.org/', creation_time=ctime, first_meas_time=ftime, last_meas_time=ltime ) self.l1b_file.close() if self.l1bs_file is not None: self.l1bs_file.write_globals( title='DeDop SRAL Level 1BS Measurement', mission_name=l1a_globals.mission_name, altimeter_sensor_name=l1a_globals.altimeter_sensor_name, gnss_sensor_name=l1a_globals.gnss_sensor_name, doris_sensor_name=l1a_globals.doris_sensor_name, references=l1a_globals.references, acq_station_name=l1a_globals.acq_station_name, xref_altimeter_level0=l1a_globals.xref_altimeter_level0, xref_navatt_level0=l1a_globals.xref_navatt_level0, xref_altimeter_orbit=l1a_globals.xref_altimeter_orbit, xref_doris_uso=l1a_globals.xref_doris_uso, xref_altimeter_ltm_lrm_cal1=l1a_globals.xref_altimeter_ltm_lrm_cal1, xref_altimeter_ltm_sar_cal1=l1a_globals.xref_altimeter_ltm_sar_cal1, xref_altimeter_ltm_ku_cal2=l1a_globals.xref_altimeter_ltm_ku_cal2, xref_altimeter_ltm_c_cal2=l1a_globals.xref_altimeter_ltm_c_cal2, xref_altimeter_characterisation=l1a_globals.xref_altimeter_characterisation, xref_platform=l1a_globals.xref_platform, xref_time_correlation=l1a_globals.xref_time_correlation, semi_major_ellipsoid_axis=self.cst.semi_major_axis, ellipsoid_flattening=self.cst.flat_coeff, netcdf_version=getlibversion(), product_name=l1a_globals.get_l1bs_product_name(), institution='isardSAT', source='DeDop {}'.format(__version__), history=l1a_globals.history, contact='http://www.dedop.org/', creation_time=ctime, first_meas_time=ftime, last_meas_time=ltime ) self.l1bs_file.close() return status
def writeROMSGrid(outFile, variables, varinfo, timeinfo=None, verbose=False): """ Code to write roms grids based on input variables INPUT: ------ outFile : Full path to output netcdf file variables : Dictionary containing variables. (see notes) varinfo : Path to ROMS varinfo.dat. Usually under: /path/to/roms/trunk/ROMS/External/varinfo.dat timeinfo : Time vector in nested dictionary form (see example) verbose : some info displayed on the terminal RETURNS: -------- NOTES: ------ - variables need rho variables (x_rho,y_rho) TODO: ----- - Include a varinfo.dat with the pynmd package EXAMPLE: --------- >>> import numpy as np >>> from collections import defaultdict >>> import pynmd.models.roms.pre as groms >>> >>> x_rho,y_rho = np.meshgrid(np.arange(0,10,1),np.arange(0,10,1) >>> variables = {} >>> variables['x_rho'] = x_rho >>> variables['y_rho'] = y_rho >>> >>> variables['type'] = 'ROMS FORCING FILE' >>> >>> timeinfo = defaultdict(dict) >>> timeinfo['sms_time']['units'] = 'seconds since 1970-01-01 00:00:00 UTC' >>> timeinfo['sms_time']['data'] = np.arange(0,1000,10) >>> timeinfo['sms_time']['long_name'] = 'surface momentum stress time' >>> >>> groms.writeROMSGrid(outFile,...) """ # Testing only #outFile = ('/home/shusin3/users/ggarcia/projects/other/' + # 'columbiaRiverPlume/11-romsIdealized/03-extendedNR2/' + # 'orIdealizedExtStr.nc') #varinfo = ('/home/shusin3/users/ggarcia/projects/other/' + # 'columbiaRiverPlume/94-roms/trunk/ROMS/External/varinfo.dat') #verbose = True # Read varinfo ------------------------------------------------------------- if verbose: print('Reading Varinfo') print(' ' + varinfo) # Create dictionary to get information from varinfodict = defaultdict(dict) # Structure of the variables # hardcoded because I couldn't find a generalized description varStruct = ['long_name', 'units', 'field', 'time', 'id', 'dimensions'] # Read the varinfo with open(varinfo) as f: # Read into a list of lines lines = f.readlines() # Loop through lines for line in lines: #Skip lines starting with ! if line.startswith("!"): continue # Skip blank lines if line.isspace(): continue # Skip other non variable lines if line.startswith("'$"): continue # Read variables and allocate properties if line.startswith("'"): tmpVar = line.split(' ')[0][1:-1] cnt = -1 continue # Add counter variable and allocate only the necessary fields cnt += 1 if cnt > (len(varStruct) - 1): continue varinfodict[tmpVar][varStruct[cnt]] =\ line.split(' ')[1].split('\n')[0][1:-1] f.close() # Import grid variables and update the dictionary gridVariables = gridVars() varinfodict.update(gridVariables) # Create netCDF file ------------------------------------------------------- if verbose: print('Creating: ' + outFile) nc = netCDF4.Dataset(outFile, 'w', format='NETCDF4') nc.Author = getpass.getuser() nc.Created = time.ctime() #nc.Owner = 'Nearshore Modeling Group (http://ozkan.oce.orst.edu/nmg)' nc.Software = 'Created with Python ' + sys.version nc.NetCDF_Lib = str(netCDF4.getlibversion()) if 'type' in variables.keys(): nc.type = variables['type'] # Create dimensions -------------------------------------------------------- if verbose: print(" Creating Dimensions ...") # Horizontal dimensions nc.createDimension('xi_psi', np.size(variables['x_rho'], 1) - 1) nc.createDimension('xi_rho', np.size(variables['x_rho'], 1)) nc.createDimension('xi_u', np.size(variables['x_rho'], 1) - 1) nc.createDimension('xi_v', np.size(variables['x_rho'], 1)) nc.createDimension('eta_psi', np.size(variables['x_rho'], 0) - 1) nc.createDimension('eta_rho', np.size(variables['x_rho'], 0)) nc.createDimension('eta_u', np.size(variables['x_rho'], 0)) nc.createDimension('eta_v', np.size(variables['x_rho'], 0) - 1) # Vertical dimensions if 's_rho' in variables.keys(): nc.createDimension('s_rho', variables['s_rho'].size) if 's_w' in variables.keys(): nc.createDimension('s_w', variables['s_w'].size) # river variables if 'river' in variables.keys(): nc.createDimension('river', variables['river'].size) # Time dimension and variable (unlimited,netCDF4 supports multiple) if timeinfo: if verbose: print(' Writing Time Variables:') for aa in timeinfo.keys(): if verbose: print(' ' + aa) # Create dimension nc.createDimension(aa, 0) nc.createVariable(aa, 'f8', (aa)) # Write variable information for bb in timeinfo[aa].keys(): if bb == 'data': nc.variables[aa][:] = timeinfo[aa]['data'] else: nc.variables[aa].__setattr__(bb, timeinfo[aa][bb]) # Write other variables if verbose: print(' Writing variables:') # Loading dimensions dimInfo = gridDims() for aa in variables.keys(): # Determine dimensions try: tmpdims = dimInfo[varinfodict[aa]['dimensions']] if varinfodict[aa]['dimensions'] == 'nulvar': tmpdims = tmpdims[aa] except: if verbose: #print(' ' + aa + ': Not in varinfodict[aa][dimensions]') print(' ' + aa + ': skipped') continue if verbose: print(' ' + aa) if 'time' in varinfodict[aa].keys(): # Some variables have info on the time slot no time # See river_Xpoisition for example if 'time' in varinfodict[aa]['time']: tmpdims = (varinfodict[aa]['time'], ) + tmpdims else: # Get rid of the time variable varinfodict[aa].pop('time') # Create Variable nc.createVariable(aa, 'f8', tmpdims) # Write attributes for bb in varinfodict[aa].keys(): if bb == 'dimensions' or bb == 'id': continue nc.variables[aa].__setattr__(bb, varinfodict[aa][bb]) # Write data nc.variables[aa][:] = variables[aa] # Close netcdf file nc.close() if verbose: print('Done')
def write_bathy_1d(x,h,path,ncsave=True): ''' Parameters: ---------- x : 1D array of x coordinates h : Bathymetry path : Full path where the output will be saved ncsave : Save bathy as NetCDF file Output: ------- depth.txt : Text file with the depth information for Funwave input. depth.nc : (Optional) NetCDF4 bathymetry file. Notes: ------ Variables are assumed to be on a regularly spaced grid. ''' # Output the text file ----------------------------------------------------- fid = open(path + 'depth.txt','w') for aa in range(len(h)): fid.write('%12.3f' % h[aa]) fid.write('\n') fid.close() if ncsave: # Global attributes nc = netCDF4.Dataset(path + 'depth.nc', 'w', format='NETCDF4') nc.Description = 'Funwave Bathymetry' nc.Author = getpass.getuser() nc.Created = time.ctime() nc.Owner = 'Nearshore Modeling Group (http://ozkan.oce.orst.edu/nmg)' nc.Software = 'Created with Python ' + sys.version nc.NetCDF_Lib = str(netCDF4.getlibversion()) nc.Script = os.path.realpath(__file__) # Create dimensions xi_rho = len(h) nc.createDimension('xi_rho', xi_rho) # Write coordinates and depth to netcdf file create_nc_var(nc, 'x_rho',('xi_rho'), 'meter','x-locations of RHO-points') nc.variables['x_rho'][:] = x create_nc_var(nc,'h',('xi_rho'), 'meter','bathymetry at RHO-points') nc.variables['h'][:] = h # Close NetCDF file nc.close() else: print("NetCDF file not requested") #=========================================================================== # Print input file options #=========================================================================== print(' ') print('===================================================================') print('In your FUNWAVE input file:') print('Mglob = ' + np.str(len(x))) print('Nglob = 1') print('DX = ' + np.str(np.abs(x[1] - x[0]))) print('DY = anything larger than DX works') print('DEP_WK = ' + str(h.max())) print('Check sponge layer widths') print('===================================================================') print(' ')
def bulk2nc(buoyfld, buoyid, ncformat=4, verbose=True, suffix='.txt'): ''' Code to convert bulk parameter text files into netcdf file Usage: ------ bulk2nc(buoyfld,buoyid,ncformat) Input: ------ buoyfld = Folder where the bulk paramerter text files reside. buoyid = Netcdf buoy identifier (to figure out the file names) ncformat = set as 3 for netCDF3, set as 4 for netCDF4 (default) verbose = some extra information (True is default) Notes: Only the bulk parameter files must be present in that directory. The code is not smart enough (and I do not have the time to make it so) to figure out the bulk parameter files. ''' #=========================================================================== # Read and Clean Up Data #=========================================================================== # Get all files in folder archivos = os.listdir(buoyfld) archivos.sort() # Initialize variables wavetime = np.empty([ 1, ]) WDIR = np.empty([ 1, ]) #AKA WD WSPD = np.empty([ 1, ]) GST = np.empty([ 1, ]) WVHT = np.empty([ 1, ]) DPD = np.empty([ 1, ]) APD = np.empty([ 1, ]) MWD = np.empty([ 1, ]) PRES = np.empty([ 1, ]) #AKA BAR ATMP = np.empty([ 1, ]) WTMP = np.empty([ 1, ]) # Loop over files for tmpFile in archivos: if tmpFile.endswith(suffix): if verbose: print(tmpFile) # Read header lines to determine the location of variables with open(buoyfld + '/' + tmpFile, 'r') as f: header1 = f.readline() header2 = f.readline() # Determine the number of header lines (NDBC uses one or two) if header1.startswith('Y') or header1.startswith('#'): headcnt = 1 if header2.startswith('Y') or header2.startswith('#'): headcnt = 2 # Collapse multiple spaces into one header3 = ' '.join(header1.split()) header4 = header3.split() # Load buoy data tmpdata = pl.loadtxt(buoyfld + '/' + tmpFile, skiprows=headcnt) # ====================== Allocate variables ==================== # # Wind direction if any(tt == 'WD' for tt in header4): tind = header4.index('WD') WDIR = np.concatenate((WDIR, tmpdata[:, tind])) elif any(tt == 'WDIR' for tt in header4): tind = header4.index('WDIR') WDIR = np.concatenate((WDIR, tmpdata[:, tind])) else: tmparray = np.ones([tmpdata.shape[0], 1]) tmparray[:] = np.NaN WDIR = np.concatenate((WDIR, tmparray)) del tmparray # Wind Speed if any(tt == 'WSPD' for tt in header4): tind = header4.index('WSPD') WSPD = np.concatenate((WSPD, tmpdata[:, tind])) else: tmparray = np.ones([tmpdata.shape[0], 1]) tmparray[:] = np.NaN WSPD = np.concatenate((WSPD, tmparray)) del tmparray # Wind Gust if any(tt == 'GST' for tt in header4): tind = header4.index('GST') GST = np.concatenate((GST, tmpdata[:, tind])) else: tmparray = np.ones([tmpdata.shape[0], 1]) tmparray[:] = np.NaN GST = np.concatenate((GST, tmparray)) del tmparray # Wave Height if any(tt == 'WVHT' for tt in header4): tind = header4.index('WVHT') WVHT = np.concatenate((WVHT, tmpdata[:, tind])) else: tmparray = np.ones([tmpdata.shape[0], 1]) tmparray[:] = np.NaN WVHT = np.concatenate((WVHT, tmparray)) del tmparray # Dominant Wave Period if any(tt == 'DPD' for tt in header4): tind = header4.index('DPD') DPD = np.concatenate((DPD, tmpdata[:, tind])) else: tmparray = np.ones([tmpdata.shape[0], 1]) tmparray[:] = np.NaN DPD = np.concatenate((DPD, tmparray)) del tmparray # Average Wave Period if any(tt == 'APD' for tt in header4): tind = header4.index('APD') APD = np.concatenate((APD, tmpdata[:, tind])) else: tmparray = np.ones([tmpdata.shape[0], 1]) tmparray[:] = np.NaN APD = np.concatenate((APD, tmparray)) del tmparray # Mean Wave Direction if any(tt == 'MWD' for tt in header4): tind = header4.index('MWD') MWD = np.concatenate((MWD, tmpdata[:, tind])) else: tmparray = np.ones([tmpdata.shape[0], 1]) tmparray[:] = np.NaN MWD = np.concatenate((MWD, tmparray)) del tmparray # Sea Level Pressure if any(tt == 'PRES' for tt in header4): tind = header4.index('PRES') PRES = np.concatenate((PRES, tmpdata[:, tind])) elif any(tt == 'BAR' for tt in header4): tind = header4.index('BAR') PRES = np.concatenate((PRES, tmpdata[:, tind])) else: tmparray = np.ones([tmpdata.shape[0], 1]) tmparray[:] = np.NaN PRES = np.concatenate((PRES, tmparray)) del tmparray # Air temperature if any(tt == 'ATMP' for tt in header4): tind = header4.index('ATMP') ATMP = np.concatenate((ATMP, tmpdata[:, tind])) else: tmparray = np.ones([tmpdata.shape[0], 1]) tmparray[:] = np.NaN ATMP = np.concatenate((ATMP, tmparray)) del tmparray # Sea surface temperature if any(tt == 'WTMP' for tt in header4): tind = header4.index('WTMP') WTMP = np.concatenate((WTMP, tmpdata[:, tind])) else: tmparray = np.ones([tmpdata.shape[0], 1]) tmparray[:] = np.NaN WTMP = np.concatenate((WTMP, tmparray)) del tmparray # ================== Time management ================= # Years if any(tt == 'YY' for tt in header4): tind = header4.index('YY') years = tmpdata[:, tind] + 1900 elif any(tt == '#YY' for tt in header4): tind = header4.index('#YY') years = tmpdata[:, tind] else: tind = header4.index('YYYY') years = tmpdata[:, tind] # Minutes if any(tt == 'mm' for tt in header4): tind = header4.index('mm') mm = tmpdata[:, tind] else: mm = np.zeros([tmpdata.shape[0], 1]) # Create time vector # Seconds from 1900-01-01 will be used for aa in range(tmpdata.shape[0]): tmptime = datetime.datetime(int(years[aa]), int(tmpdata[aa, 1]), int(tmpdata[aa, 2]), int(tmpdata[aa, 3]), int(mm[aa]), 0) sectime = tmptime - datetime.datetime(1900, 1, 1, 0, 0, 0) secsecs = sectime.total_seconds() wavetime = np.concatenate([wavetime, np.array([secsecs])]) del tmptime, sectime, secsecs # ================ Clean up ================ del header1, header2, header3, header4, years, mm # Remove first term of each array wavetime = np.delete(wavetime, 0) WDIR = np.delete(WDIR, 0) WSPD = np.delete(WSPD, 0) GST = np.delete(GST, 0) WVHT = np.delete(WVHT, 0) DPD = np.delete(DPD, 0) APD = np.delete(APD, 0) MWD = np.delete(MWD, 0) PRES = np.delete(PRES, 0) ATMP = np.delete(ATMP, 0) WTMP = np.delete(WTMP, 0) # Clean up variables WDIR[WDIR == 999] = np.NaN WSPD[WSPD == 99] = np.NaN GST[GST == 99] = np.NaN WVHT[WVHT == 99] = np.NaN DPD[DPD == 99] = np.NaN APD[APD == 99] = np.NaN MWD[MWD == 999] = np.NaN PRES[PRES == 9999] = np.NaN ATMP[ATMP == 99] = np.NaN WTMP[WTMP == 99] = np.NaN # Order chronologically sorted_index = np.argsort(wavetime) wavetime = [wavetime[i] for i in sorted_index] WDIR = [WDIR[i] for i in sorted_index] WSPD = [WSPD[i] for i in sorted_index] GST = [GST[i] for i in sorted_index] WVHT = [WVHT[i] for i in sorted_index] DPD = [DPD[i] for i in sorted_index] APD = [APD[i] for i in sorted_index] MWD = [MWD[i] for i in sorted_index] PRES = [PRES[i] for i in sorted_index] ATMP = [ATMP[i] for i in sorted_index] WTMP = [WTMP[i] for i in sorted_index] #=========================================================================== # Save as NetCDF #=========================================================================== # Global attributes if ncformat == 4: print("Saving the buoy data with NetCDF4 format") nc = netCDF4.Dataset(buoyfld + '/' + buoyid + '.nc', 'w', format='NETCDF4') else: print("Saving the buoy data with NetCDF3 format") nc = netCDF4.Dataset(buoyfld + '/' + buoyid + '.nc', 'w', format='NETCDF3_CLASSIC') nc.Description = buoyid + ' NDBC Bulk Parameter Data' nc.rawdata = 'National Data Buoy Center \nwww.ndbc.noaa.gov' nc.Author = '[email protected] \nNearshore Modeling Group' nc.Created = time.ctime() nc.Software = 'Created with Python ' + sys.version nc.NetCDF_Lib = str(netCDF4.getlibversion()) nc.Script = os.path.realpath(__file__) # Create dimensions nc.createDimension('wave_time', None) # pyroms subroutine to write NetCDF fields def write_nc_var(var, name, dimensions, units=None, longname=None): nc.createVariable(name, 'f8', dimensions) if units is not None: nc.variables[name].units = units if longname is not None: nc.variables[name].long_name = longname nc.variables[name][:] = var # Write Variables To NetCDF file write_nc_var(wavetime, 'wave_time', 'wave_time', 'seconds since 1900-01-01 00:00:00', 'measurement time UTC') write_nc_var( WDIR, 'WDIR', 'wave_time', 'degrees', 'Wind direction (direction the wind is coming from in ' + 'degrees clockwise from true North') write_nc_var(WSPD, 'WSPD', 'wave_time', 'meter second-1', 'Wind speed averaged over an eight-minute period') write_nc_var(GST, 'GST', 'wave_time', 'meter second-1', 'Peak gust speed') write_nc_var( WVHT, 'WVHT', 'wave_time', 'meter', 'Significant wave height during the 20 minute sampling period') write_nc_var(DPD, 'DPD', 'wave_time', 'second', 'Dominant wave period (period with the maximum wave energy)') write_nc_var( APD, 'APD', 'wave_time', 'second', 'Average wave period of all waves during the 20 minute' + ' sampling period') write_nc_var( MWD, 'MWD', 'wave_time', 'degrees', 'The direction from which the waves at the dominant period ' + 'are coming in degrees from true North, increasing clockwise') write_nc_var(PRES, 'PRES', 'wave_time', 'hPa', 'Sea level pressure') write_nc_var(ATMP, 'ATMP', 'wave_time', 'Celsius', 'Air temperature') write_nc_var(WTMP, 'WTMP', 'wave_time', 'Celsius', 'Sea surface temperature') # Close NetCDF File nc.close()
def write_bathy(x,y,h,path,ncsave=True): ''' Parameters: ---------- x,y : 2D arrays of coordinates h : Bathymetry path : Full path where the output will be saved ncsave : Save as NetCDF4 file (optional, defaults to True) Output: ------- depth.nc : NetCDF4 file with the bathymetry depth.txt : Text file with the depth information for Funwave input. ''' # Get bathymetry dimensions eta_rho, xi_rho = x.shape if ncsave: # Global attributes nc = netCDF4.Dataset(path + 'depth.nc', 'w', format='NETCDF4') nc.Description = 'Funwave Bathymetry' nc.Author = getpass.getuser() nc.Created = time.ctime() nc.Owner = 'Nearshore Modeling Group (http://ozkan.oce.orst.edu/nmg)' nc.Software = 'Created with Python ' + sys.version nc.NetCDF_Lib = str(netCDF4.getlibversion()) nc.Script = os.path.realpath(__file__) # Create dimensions nc.createDimension('xi_rho', xi_rho) nc.createDimension('eta_rho', eta_rho) # Write coordinates and depth to netcdf file create_nc_var(nc, 'x_rho', ('eta_rho', 'xi_rho'), 'meter','x-locations of RHO-points') nc.variables['x_rho'][:] = x create_nc_var(nc, 'y_rho', ('eta_rho', 'xi_rho'), 'meter','y-locations of RHO-points') nc.variables['y_rho'][:] = y create_nc_var(nc, 'h', ('eta_rho', 'xi_rho'), 'meter','bathymetry at RHO-points') nc.variables['h'][:] = h # Close NetCDF file nc.close() else: print("NetCDF file not requested") # Output the text file ----------------------------------------------------- fid = open(path + 'depth.txt','w') for aa in range(x.shape[0]): for bb in range(x.shape[1]): fid.write('%12.3f' % h[aa,bb]) fid.write('\n') fid.close() #=========================================================================== # Print input file options #=========================================================================== print(' ') print('===================================================================') print('In your FUNWAVE input file:') print('Mglob = ' + np.str(xi_rho)) print('Nglob = ' + np.str(eta_rho)) print('DX = ' + np.str(np.abs(x[0,1] - x[0,0]))) print('DY = ' + np.str(np.abs(y[1,0] - y[0,0]))) print('Ywidth_WK > ' + str(y.max() - y.min())) print('DEP_WK = ' + str(h.max())) print('Check sponge layer widths') print('===================================================================') print(' ')
def main(): # Parse arguments parse_cli_args() # Sanity checks # Check to make sure that the JSON resource file exists! try: resource_file_fh = open(args.resource_file, "r") except IOError: error_msg("Resource file '%s' is not accessible or does not exist!" % args.resource_file) exit(1) # Check to make sure that the JSON resource file is valid! try: resource_data = json.loads(resource_file_fh.read()) except KeyboardInterrupt: info_msg("CTRL-C detected, exiting.") exit(0) except: error_msg("Resource file '%s' is not a valid JSON file!" % args.resource_file) print(traceback.format_exc()) exit(1) # Close file - we got the data already! resource_file_fh.close() # Print verbose version information if args.verbose: info_msg("Using following versions:") info_msg(" netcdf4-python v%s" % netCDF4.__version__) info_msg(" NetCDF v%s" % getlibversion()) info_msg(" HDF5 v%s" % netCDF4.__hdf5libversion__) info_msg(" Python v%s\n" % sys.version.split("\n")[0].strip()) info_msg("Reading and validating NetCDF4 files...") # Check to make sure the NetCDF4 files are legitimate! nc4_files_root = [] init_counter(len(args.nc4_files), "Reading/verifying file") for nc4_file in args.nc4_files: try: open(nc4_file, "r").close() except KeyboardInterrupt: info_msg("CTRL-C detected, exiting.") exit(0) except IOError: error_msg("The NetCDF4 file '%s' does not exist!" % nc4_file) exit(1) progress_counter(nc4_file) try: rootgrp = Dataset(nc4_file, "a", format="NETCDF4") nc4_files_root.append({"file": nc4_file, "group": rootgrp}) except KeyboardInterrupt: info_msg("CTRL-C detected, exiting.") exit(0) except: error_msg("'%s' is not a valid NetCDF4 file!" % nc4_file) exit(1) line_msg_done() # Global attributes if args.global_attributes: # Check if we have a global attributes entry in the resource file if not "global_attributes" in resource_data: warning_msg("Resource file '%s' does not have any global attributes, skipping." % args.resource_file) else: # Initialize our counter init_counter(len(nc4_files_root), "Applying global attributes to file") for nc4_entry in nc4_files_root: # Update progress counter progress_counter(nc4_entry["file"]) for global_attr_key in resource_data["global_attributes"]: global_attr_val = resource_data["global_attributes"][global_attr_key] # We need to convert unicode to ASCII if type(global_attr_val) == unicode: global_attr_val = str(global_attr_val) # BUG fix - NetCDF really, really, REALLY does not like # 64-bit integers. We forcefully convert the value to a # 32-bit signed integer, with some help from numpy! if type(global_attr_val) == int: global_attr_val = numpy.int32(global_attr_val) setattr(nc4_entry["group"], global_attr_key, global_attr_val) line_msg_done() # Variable attributes if args.var_attributes: # Check if we have a variable attributes entry in the resource file if not "variable_attributes" in resource_data: warning_msg("Resource file '%s' does not have any variable attributes, skipping." % args.resource_file) else: # Initialize our counter init_counter(len(nc4_files_root), "Applying variable attributes to file") for nc4_entry in nc4_files_root: # Update progress counter progress_counter(nc4_entry["file"]) # Iterate through all of our var_attr variables for var in resource_data["variable_attributes"]: if var in nc4_entry["group"].variables.keys(): for var_attr_key in resource_data["variable_attributes"][var]: var_attr_val = resource_data["variable_attributes"][var][var_attr_key] var_attr_key = str(var_attr_key) # We need to convert unicode to ASCII if type(var_attr_val) == unicode: var_attr_val = list(str(var_attr_val)) # BUG fix - NetCDF really, really, REALLY does not like # 64-bit integers. We forcefully convert the value to a # 32-bit signed integer, with some help from numpy! if type(var_attr_val) == int: var_attr_val = numpy.int32(var_attr_val) setattr(nc4_entry["group"].variables[var], var_attr_key, var_attr_val) else: warning_msg("Can't find variable %s in file %s!" % (var, nc4_entry["file"])) line_msg_done() # Close everything init_counter(len(nc4_files_root), "Saving changes to file") for nc4_entry in nc4_files_root: progress_counter(nc4_entry["file"]) nc4_entry["group"].close() line_msg_done() info_msg("Attribute appending complete!")
sys.path.append("build/temp.linux-x86_64-2.6") from netCDF4 import getlibversion,__hdf5libversion__,__netcdf4libversion__,__version__ __all__ = ['test'] # Find all test files. test_files = glob.glob('tst_*.py') py_path = os.environ.get('PYTHONPATH') if py_path is None: py_path = '.' else: py_path = os.pathsep.join(['.',py_path]) os.environ['PYTHONPATH'] = py_path # Build the test suite from the tests found in the test files. testsuite = unittest.TestSuite() version = getlibversion().split()[0] for f in test_files: m = __import__(os.path.splitext(f)[0]) testsuite.addTests(unittest.TestLoader().loadTestsFromModule(m)) # Run the test suite. def test(verbosity=1): runner = unittest.TextTestRunner(verbosity=verbosity) runner.run(testsuite) if __name__ == '__main__': test(verbosity=1) import sys sys.stdout.write('\n')
def convert_output(workfld,outfile,time_int,bathyfile=None,inpfile=None): ''' Parameters: ----------- workfld : Path to the folder where output files reside outfile : Output NetCDF file time_int : Time interval between output files [s] (will be updated if input file is provided) bathyfile : Full path to input netcdf bathy file (optional) inpfile : Funwave input file used for metadata (optional) Output: ------- NetCDF File with the variables in the folder. Not all are supported so you may need to edit this file. ''' # For testing only #workfld = '/scratch/temp/ggarcia/agate/out/' #outfile = '/scratch/temp/ggarcia/agate/tmpout.nc' #time_int = 0.5 #bathyfile = '/scratch/temp/ggarcia/agate/depth.nc' #inpfile = '/scratch/temp/ggarcia/agate/input.txt' # Get variable information ------------------------------------------------ archivos = os.listdir(workfld) # Get all files tmpvars = [x.split('_')[0] for x in archivos] # All variables tmpvars = list(set(tmpvars)) # Unique variables # If no variables found exit if not tmpvars: print('No files found in ' + workfld) print('Quitting ...') return None # Make sure variables are within the supported ones supported_vars_time = ['eta','etamean','havg','hmax','hmin','hrms', 'mask','mask9','MFmax','u','umax','umean','v', 'vmean','VORmax'] vars_2d = [x for x in tmpvars if x in supported_vars_time] # Read input file if provided ---------------------------------------------- if inpfile: print("Reading data from input file:") print(" " + inpfile) # Open file tmpinpfile = open(inpfile,'r') # Output dictionary inpinfo = {} # Extract information (need to add wavemaker support) for tmpline in tmpinpfile: # Skip blank lines if len(tmpline.strip()) == 0: continue if "TITLE" == tmpline.split()[0]: inpinfo['title'] = tmpline.split()[2] elif "PX" == tmpline.split()[0]: inpinfo['px'] = tmpline.split()[2] elif "PY" == tmpline.split()[0]: inpinfo["py"] = tmpline.split()[2] elif "Mglob" == tmpline.split()[0]: inpinfo['mglob'] = tmpline.split()[2] elif "Nglob" == tmpline.split()[0]: inpinfo['nglob'] = tmpline.split()[2] elif "TOTAL_TIME" == tmpline.split()[0]: inpinfo['total_time'] = tmpline.split()[2] elif "PLOT_INTV" == tmpline.split()[0]: inpinfo["plot_intv"] = tmpline.split()[2] time_int = np.double(tmpline.split()[2]) elif "DX" == tmpline.split()[0]: inpinfo['dx'] = tmpline.split()[2] dx = float(tmpline.split()[2]) elif "DY" == tmpline.split()[0]: inpinfo['dy'] = tmpline.split()[2] dy = float(tmpline.split()[2]) elif "WAVEMAKER" == tmpline.split()[0]: inpinfo['wavemaker'] = tmpline.split()[2] elif "PERIODIC" == tmpline.split()[0]: inpinfo['periodic'] = tmpline.split()[2] elif "SPONGE_ON" == tmpline.split()[0]: sponge = tmpline.split()[2] inpinfo['sponge'] = sponge elif "Sponge_west_width" == tmpline.split()[0] and sponge == 'T': inpinfo['sponge_west_width'] = tmpline.split()[2] elif "Sponge_east_width" == tmpline.split()[0] and sponge == 'T': inpinfo['sponge_east_width'] = tmpline.split()[2] elif "Sponge_wouth_width" == tmpline.split()[0] and sponge == 'T': inpinfo['sponge_south_width'] = tmpline.split()[2] elif "Sponge_worth_width" == tmpline.split()[0] and sponge == 'T': inpinfo['sponge_north_width'] = tmpline.split()[2] elif "R_sponge" == tmpline.split()[0] and sponge == 'T': inpinfo['r_sponge'] = tmpline.split()[2] elif "A_sponge" == tmpline.split()[0] and sponge == 'T': inpinfo['a_sponge'] = tmpline.split()[2] elif "DISPERSION" == tmpline.split()[0]: inpinfo['dispersion'] = tmpline.split()[2] elif "Gamma1" == tmpline.split()[0]: inpinfo['gamma1'] = tmpline.split()[2] elif "Gamma2" == tmpline.split()[0]: inpinfo['gamma2'] = tmpline.split()[2] elif "Gamma3" == tmpline.split()[0]: inpinfo['gamma3'] = tmpline.split()[2] elif "Beta_ref" == tmpline.split()[0]: inpinfo['beta_ref'] = tmpline.split()[2] elif "SWE_ETA_DEP" == tmpline.split()[0]: inpinfo['swe_eta_dep'] = tmpline.split()[2] elif "Friction_Matrix" == tmpline.split()[0]: inpinfo['friction_matrix'] = tmpline.split()[2] elif "Cd_file" == tmpline.split()[0]: inpinfo['cd_file'] = tmpline.split()[2] elif "Cd" == tmpline.split()[0]: inpinfo['cd'] = tmpline.split()[2] elif "Time_Scheme" == tmpline.split()[0]: inpinfo['time_scheme'] = tmpline.split()[2] elif "HIGH_ORDER" == tmpline.split()[0]: inpinfo['spatial_scheme'] = tmpline.split()[2] elif "CONSTRUCTION" == tmpline.split()[0]: inpinfo['construction'] = tmpline.split()[2] elif "CFL" == tmpline.split()[0]: inpinfo['cfl'] = tmpline.split()[2] elif "MinDepth" == tmpline.split()[0]: inpinfo['min_depth'] = tmpline.split()[2] elif "MinDepthFrc" == tmpline.split()[0]: inpinfo['mindepthfrc'] = tmpline.split()[2] # Close file tmpinpfile.close() else: # Assume grid spacing to be 1 meter print("Input file not provided") dx = 1 dy = 1 inpinfo = False # Coordinates and depth --------------------------------------------------- # Bathymetry file provided if bathyfile: print("Reading coordinates and depth from:") print(" " + bathyfile) ncfile = netCDF4.Dataset(bathyfile,'r') x_rho = ncfile.variables['x_rho'][:] if ncfile.variables.has_key('y_rho'): y_rho = ncfile.variables['y_rho'][:] else: y_rho = None h = ncfile.variables['h'][:] ncfile.close() # Bathymetry file not provided but have output file elif os.path.isfile(workfld + '/dep.out'): # Fix this h = np.loadtxt(workfld + '/dep.out') hdims = h.ndim if hdims == 1: x_rho = np.arange(0,h.shape[0],dx) elif hdims == 2: x_rho, y_rho = np.meshgrid(np.arange(0,h.shape[1],dx), np.arange(0,h.shape[0],dy)) else: print('Something is wrong with the depth file') return None # No bathymetry file provided (I am not capable of reading the input file) else: print("No bathymetry file provided") print("You could copy your input bathymetry text file to ") print(workfld + '/dep.out') return None # Get dimensions of variables hdims = h.ndim # Create NetCDF file ------------------------------------------------------- print("Creating " + outfile) # Global attributes nc = netCDF4.Dataset(outfile, 'w', format='NETCDF4') nc.Description = 'Funwave Output' nc.Author = '*****@*****.**' nc.Created = time.ctime() nc.Type = 'Funwave v2.1 snapshot output' nc.Owner = 'Nearshore Modeling Group' nc.Software = 'Created with Python ' + sys.version nc.NetCDF_Lib = str(netCDF4.getlibversion()) nc.Source = workfld nc.Script = os.path.realpath(__file__) # Add more global variables to output if inpinfo: for tmpatt in inpinfo.keys(): nc.__setattr__(tmpatt,inpinfo[tmpatt][:]) # Create dimensions if hdims == 2: eta_rho, xi_rho = h.shape nc.createDimension('eta_rho', eta_rho) else: xi_rho = h.shape[0] eta_rho = 1 nc.createDimension('xi_rho', xi_rho) nc.createDimension('ocean_time',0) # Write coordinate axes ---------------------------------------------- if hdims == 2: nc.createVariable('x_rho','f8',('eta_rho','xi_rho')) nc.variables['x_rho'].units = 'meter' nc.variables['x_rho'].longname = 'x-locations of RHO points' nc.variables['x_rho'][:] = x_rho nc.createVariable('y_rho','f8',('eta_rho','xi_rho')) nc.variables['y_rho'].units = 'meter' nc.variables['y_rho'].longname = 'y-locations of RHO points' nc.variables['y_rho'][:] = y_rho nc.createVariable('h','f8',('eta_rho','xi_rho')) nc.variables['h'].units = 'meter' nc.variables['h'].longname = 'bathymetry at RHO points' nc.variables['h'][:] = h else: nc.createVariable('x_rho','f8',('xi_rho')) nc.variables['x_rho'].units = 'meter' nc.variables['x_rho'].longname = 'x-locations of RHO points' nc.variables['x_rho'][:] = x_rho nc.createVariable('h','f8',('xi_rho')) nc.variables['h'].units = 'meter' nc.variables['h'].longname = 'bathymetry at RHO points' nc.variables['h'][:] = h # Create time vector ------------------------------------------- tmpruns = [x for x in archivos if x.split('_')[0] == vars_2d[0]] tmpruns.sort() time_max = float(tmpruns[-1].split('_')[-1]) time_min = float(tmpruns[0].split('_')[-1]) twave = np.arange(time_min-1,time_int*(time_max-time_min+1)+time_min-1, time_int) nc.createVariable('ocean_time','f8','ocean_time') nc.variables['ocean_time'].units = 'seconds since 2000-01-01 00:00:00' nc.variables['ocean_time'].calendar = 'julian' nc.variables['ocean_time'].long_name = 'beach time' nc.variables['ocean_time'][:] = twave # Create variables -------------------------------------------------------- # Variable information varinfo = defaultdict(dict) varinfo['eta']['units'] = 'meter' varinfo['eta']['longname'] = 'water surface elevation' varinfo['etamean']['units'] = 'meter' varinfo['etamean']['longname'] = 'Mean wave induced setup' varinfo['u']['units'] = 'meter second-1' varinfo['u']['longname'] = 'Flow velocity in the xi direction' varinfo['v']['units'] = 'meter second-1' varinfo['v']['longname'] = 'Flow velocity in the eta direction' varinfo['umean']['units'] = 'meter second-1' varinfo['umean']['longname'] = 'Time-averaged flow velocity in xi direction' varinfo['vmean']['units'] = 'meter second-1' varinfo['vmean']['longname'] = 'Time-averaged flow velocity in eta direction' varinfo['umax']['units'] = 'meter second-1' varinfo['umax']['longname'] = 'Maximum flow velocity in xi direction' varinfo['vmax']['units'] = 'meter second-1' varinfo['vmax']['longname'] = 'Maximum flow velocity in eta direction' varinfo['hmax']['units'] = 'meter' varinfo['hmax']['longname'] = 'Maximum wave height' varinfo['hmin']['units'] = 'meter' varinfo['hmin']['longname'] = 'Minimum wave height' varinfo['havg']['units'] = 'meter' varinfo['havg']['longname'] = 'Average wave height' varinfo['hrms']['units'] = 'meter' varinfo['hrms']['longname'] = 'Root mean squared wave height' varinfo['mask']['units'] = 'Boolean' varinfo['mask']['longname'] = 'Logical parameter for output wetting-drying' varinfo['mask9']['units'] = 'Boolean' varinfo['mask9']['longname'] = 'Logical parameter for output MASK9' varinfo['VORmax']['units'] = 'second-1' varinfo['VORmax']['longname'] = 'Maximum vorticity' varinfo['MFmax']['units'] = 'meter second-s' varinfo['MFmax']['longname'] = 'Maximum momentum flux' # Create variables if hdims == 1: nc_dims = ('ocean_time','xi_rho') else: nc_dims = ('ocean_time','eta_rho','xi_rho') print("Creating variables") for aa in vars_2d: print(' ' + aa) # Create variable create_nc_var(nc,aa,nc_dims,varinfo[aa]['units'], varinfo[aa]['longname']) try: tmpvar = np.loadtxt(workfld + '/' + aa + '_' + '%05.0f' % time_min) except ValueError: tmpvar = np.zeros_like(h) * np.NAN nc.variables[aa][:] = np.expand_dims(tmpvar,axis=0) for bb in range(len(twave)): try: tmpvar = np.loadtxt(workfld + '/' + aa + '_' + '%05.0f' % (bb + time_min)) except ValueError: tmpvar = np.zeros_like(h) * np.NAN append_nc_var(nc,tmpvar,aa,bb-1) # Close NetCDF file print('Closing ' + outfile) nc.close()
def convert_output(workfld, outfile, bathyfile=None, inpfile=None, verbose=False): ''' Tools to convert ASCII output from NHWAVE to NetCDF4 Parameters: ----------- workfld : Path to the folder where output files reside outfile : Output file bathyfile : Full path to input NetCDF bathy file (optional) inpfile : NHwave input files used to add metadata (optional) verbose : Display progress messages (optional) Output: ------- NetCDF File with the variables in the folder. Not all are supported so you may need to edit this file. Notes: ------ TODO: ----- 1. Need to test for 2DH simulations. 2. Add support for exponential vertical layers ''' # Get variable information ------------------------------------------------- archivos = os.listdir(workfld) # All files tmpvars = [x.split('_')[0] for x in archivos] # Variables tmpvars = list(set(tmpvars)) # Unique variables # If no variables found exit if not tmpvars: print('No files found in ' + workfld) print('Quitting ...') return None # Make sure variables are within the supported ones (exclude time here) supported_vars_2d_time = ['eta'] vars_2d_time = [x for x in tmpvars if x in supported_vars_2d_time] supported_vars_2d = ['setup', 'waveheight', 'umean', 'vmean'] vars_2d = [x for x in tmpvars if x in supported_vars_2d] supported_vars_3d_time = ['u', 'v', 'w'] vars_3d_time = [x for x in tmpvars if x in supported_vars_3d_time] supported_vars_3d = ['euler', 'lag'] vars_3d = [x for x in tmpvars if x in supported_vars_3d] # Read input file if provided ---------------------------------------------- if inpfile: if verbose: print("Reading data from input file:") print(" " + inpfile) # Open file tmpinpfile = open(inpfile, 'r') # Output dictionary inpinfo = {} # Extract information (need to add wavemaker support) for tmpline in tmpinpfile: # Skip blank lines if len(tmpline.strip()) == 0: continue # Read selected keywords if "TITLE" == tmpline.split()[0]: inpinfo['title'] = tmpline.split()[2] elif "Mglob" == tmpline.split()[0]: inpinfo['mglob'] = tmpline.split()[2] elif "Nglob" == tmpline.split()[0]: inpinfo['nglob'] = tmpline.split()[2] elif "Kglob" == tmpline.split()[0]: inpinfo['kglob'] = tmpline.split()[2] elif "PX" == tmpline.split()[0]: inpinfo['px'] = tmpline.split()[2] elif "PY" == tmpline.split()[0]: inpinfo["py"] = tmpline.split()[2] elif "TOTAL_TIME" == tmpline.split()[0]: inpinfo['total_time'] = tmpline.split()[2] elif "PLOT_START" == tmpline.split()[0]: inpinfo['plot_start'] = tmpline.split()[2] elif "PLOT_INTV" == tmpline.split()[0]: inpinfo["plot_intv"] = tmpline.split()[2] elif "DX" == tmpline.split()[0]: inpinfo['dx'] = tmpline.split()[2] dx = float(tmpline.split()[2]) elif "DY" == tmpline.split()[0]: inpinfo['dy'] = tmpline.split()[2] dy = float(tmpline.split()[2]) elif "IVGRD" == tmpline.split()[0]: inpinfo['ivgrd'] = tmpline.split()[2] elif "DT_INI" == tmpline.split()[0]: inpinfo['dt_ini'] = tmpline.split()[2] elif "DT_MIN" == tmpline.split()[0]: inpinfo['dt_min'] = tmpline.split()[2] elif "DT_MAX" == tmpline.split()[0]: inpinfo['dt_max'] = tmpline.split()[2] elif "HIGH_ORDER" == tmpline.split()[0]: inpinfo['high_order'] = tmpline.split()[2] elif "TIME_ORDER" == tmpline.split()[0]: inpinfo['time_order'] = tmpline.split()[2] elif "CONVECTION" == tmpline.split()[0]: inpinfo['convection'] = tmpline.split()[2] elif "HLLC" == tmpline.split()[0]: inpinfo['hllc'] = tmpline.split()[2] elif "Ibot" == tmpline.split()[0]: inpinfo['ibot'] = tmpline.split()[2] ibot = int(tmpline.split()[2]) elif "Cd0" == tmpline.split()[0] and ibot == 1: inpinfo['cd0'] = tmpline.split()[2] elif "Zob" == tmpline.split()[0] and ibot == 2: inpinfo['zob'] = tmpline.split()[2] elif "Iws" == tmpline.split()[0]: inpinfo['Iws'] = tmpline.split()[2] iws = int(tmpline.split()[2]) elif "WindU" == tmpline.split()[0] and iws == 1: inpinfo['windu'] = tmpline.split()[2] elif "WindV" == tmpline.split()[0] and iws == 1: inpinfo['windv'] = tmpline.split()[2] elif "slat" == tmpline.split()[0]: inpinfo['slat'] = tmpline.split()[2] elif "BAROTROPIC" == tmpline.split()[0]: inpinfo['barotropic'] = tmpline.split()[2] elif "NON_HYDRO" == tmpline.split()[0]: inpinfo['non_hydro'] = tmpline.split()[2] elif "CFL" == tmpline.split()[0]: inpinfo['cfl'] = tmpline.split()[2] elif "TRAMP" == tmpline.split()[0]: inpinfo['tramp'] = tmpline.split()[2] elif "MinDep" == tmpline.split()[0]: inpinfo['min_dep'] = tmpline.split()[2] elif "ISOLVER" == tmpline.split()[0]: inpinfo['isolver'] = tmpline.split()[2] elif "PERIODIC_X" == tmpline.split()[0]: inpinfo['periodic_x'] = tmpline.split()[2] elif "PERIODIC_Y" == tmpline.split()[0]: inpinfo['periodic_y'] = tmpline.split()[2] elif "BC_X0" == tmpline.split()[0]: inpinfo['bc_x0'] = tmpline.split()[2] elif "BC_Xn" == tmpline.split()[0]: inpinfo['bc_xn'] = tmpline.split()[2] elif "BC_Y0" == tmpline.split()[0]: inpinfo['bc_y0'] = tmpline.split()[2] elif "BC_Yn" == tmpline.split()[0]: inpinfo['bc_yn'] = tmpline.split()[2] elif "BC_Z0" == tmpline.split()[0]: inpinfo['bc_z0'] = tmpline.split()[2] elif "BC_Zn" == tmpline.split()[0]: inpinfo['bc_zn'] = tmpline.split()[2] elif "WAVEMAKER" == tmpline.split()[0]: inpinfo['wavemaker'] = tmpline.split()[2] elif "Xsource_West" == tmpline.split()[0] and \ inpinfo['wavemaker'][0:3] == 'INT': inpinfo['xsource_west'] = tmpline.split()[2] elif "Xsource_East" == tmpline.split()[0] and \ inpinfo['wavemaker'][0:3] == 'INT': inpinfo['xsource_east'] = tmpline.split()[2] elif "Ysource_Suth" == tmpline.split()[0] and \ inpinfo['wavemaker'][0:3] == 'INT': inpinfo['ysource_suth'] = tmpline.split()[2] elif "Ysource_Nrth" == tmpline.split()[0] and \ inpinfo['wavemaker'][0:3] == 'INT': inpinfo['xsource_nrth'] = tmpline.split()[2] elif "SPONGE_ON" == tmpline.split()[0]: inpinfo['sponge'] = tmpline.split()[2] sponge = tmpline.split()[2] elif "Sponge_West_Width" == tmpline.split()[0] and sponge == 'T': inpinfo['sponge_west_width'] = tmpline.split()[2] elif "Sponge_East_Width" == tmpline.split()[0] and sponge == 'T': inpinfo['sponge_east_width'] = tmpline.split()[2] elif "Sponge_South_Width" == tmpline.split()[0] and sponge == 'T': inpinfo['sponge_south_width'] = tmpline.split()[2] elif "Sponge_North_Width" == tmpline.split()[0] and sponge == 'T': inpinfo['sponge_north_width'] = tmpline.split()[2] elif "Seed" == tmpline.split()[0]: inpinfo['Seed'] = tmpline.split()[2] # Close file tmpinpfile.close() else: inpinfo = None if verbose: print("Input file not provided") # If bathymetry file is given then the coordinates should be taken from # this file, otherwise unit coordinates will be assumed with the shape of # one of the output files. if bathyfile: ncfile = netCDF4.Dataset(bathyfile, 'r') x_rho = ncfile.variables['x_rho'][:] if ncfile.variables.has_key('y_rho'): y_rho = ncfile.variables['y_rho'][:] h = ncfile.variables['h'][:] ncfile.close() hdims = h.ndim else: if not os.path.isfile(workfld + '/depth'): print('No depth file found in ' + workfld) return None h = np.loadtxt(workfld + '/depth') # Check if it is a 1D or 2D model hdims = h.ndim # Horizontal dimensions if hdims == 1: x_rho = np.arange(0, h.shape[0], 1) elif hdims == 2: x_rho, y_rho = np.meshgrid(np.arange(0, h.shape[1], 1), np.arange(0, h.shape[0], 1)) else: print('Something is wrong with the depth file') print('Quitting...') return None # Load time vector if not os.path.isfile(workfld + '/time'): print("No time file found in " + workfld) print("Quitting ...") return None ocean_time = np.loadtxt(workfld + '/time') # Create NetCDF file ------------------------------------------------------ nc = netCDF4.Dataset(outfile, 'w', format='NETCDF4') nc.Description = 'NHWAVE Output' nc.Author = getpass.getuser() nc.Created = time.ctime() nc.Owner = 'Nearshore Modeling Group' nc.Software = 'Created with Python ' + sys.version nc.NetCDF_Lib = str(netCDF4.getlibversion()) nc.Source = workfld nc.Script = os.path.realpath(__file__) # Add more global variables to output (if input file is provided) if inpinfo: for tmpatt in inpinfo.keys(): nc.__setattr__(tmpatt, inpinfo[tmpatt][:]) # Create dimensions if verbose: print('Creating dimensions') if hdims == 2: eta_rho, xi_rho = h.shape nc.createDimension('eta_rho', eta_rho) else: xi_rho = h.shape[0] eta_rho = 1 nc.createDimension('xi_rho', xi_rho) nc.createDimension('ocean_time', 0) # Get vertical layers if not vars_3d and not vars_3d_time: print("No 3D variables found") s_rho = False else: # Load any 3D variables if os.path.isfile(workfld + '/' + vars_3d_time[0] + '_00001'): tmpvar = np.loadtxt(workfld + '/' + vars_3d_time[0] + '_00001') elif os.path.isfile(workfld + '/' + vars_3d[0] + '_umean'): tmpvar = np.loadtxt(workfld + '/' + vars_3d[0] + '_umean') elif os.path.isfile(workfld + '/' + vars_3d[0] + '_vmean'): tmpvar = np.loadtxt(workfld + '/' + vars_3d[0] + '_vmean') else: tmpvar = np.loadtxt(workfld + '/' + vars_3d[0]) # Outputs are stacked on the first dimension of the file # I need to enhance this and will probably have to use the input file # if hdims == 2: # s_rho = tmpvar.shape[0]/h.shape[0] # else: # s_rho = tmpvar.shape[0] s_rho = tmpvar.size / h.shape[0] nc.createDimension('s_rho', s_rho) # Write coordinates, bathymetry and time ---------------------------------- if verbose: print("Saving coordinates and time") if hdims == 2: nc.createVariable('x_rho', 'f8', ('eta_rho', 'xi_rho')) nc.variables['x_rho'].units = 'meter' nc.variables['x_rho'].longname = 'x-locations of RHO points' nc.variables['x_rho'][:] = x_rho nc.createVariable('y_rho', 'f8', ('eta_rho', 'xi_rho')) nc.variables['y_rho'].units = 'meter' nc.variables['y_rho'].longname = 'y-locations of RHO points' nc.variables['y_rho'][:] = y_rho nc.createVariable('h', 'f8', ('eta_rho', 'xi_rho')) nc.variables['h'].units = 'meter' nc.variables['h'].longname = 'bathymetry at RHO points' nc.variables['h'][:] = h else: nc.createVariable('x_rho', 'f8', ('xi_rho')) nc.variables['x_rho'].units = 'meter' nc.variables['x_rho'].longname = 'x-locations of RHO points' nc.variables['x_rho'][:] = x_rho nc.createVariable('h', 'f8', ('xi_rho')) nc.variables['h'].units = 'meter' nc.variables['h'].longname = 'bathymetry at RHO points' nc.variables['h'][:] = h # Create s_rho vector if s_rho: ds = 1.0 / s_rho sigma = np.arange(ds / 2.0, 1 - ds / 2.0, ds) nc.createVariable('s_rho', 'f8', ('s_rho')) nc.variables['s_rho'].longname = 's-coordinate at cell centers' nc.variables['s_rho'].positive = 'up' nc.variables['s_rho'].notes = 'small s_rho means close to bottom' nc.variables['s_rho'][:] = sigma # Create time vector nc.createVariable('ocean_time', 'f8', 'ocean_time') nc.variables['ocean_time'].units = 'seconds since 2000-01-01 00:00:00' nc.variables['ocean_time'].calendar = 'julian' nc.variables['ocean_time'].long_name = 'beach time since initialization' nc.variables['ocean_time'].notes = 'units are arbitrary' nc.variables['ocean_time'][:] = ocean_time # Create variables --------------------------------------------------------- # Variable information varinfo = defaultdict(dict) varinfo['eta']['units'] = 'meter' varinfo['eta']['longname'] = 'water surface elevation' varinfo['waveheight']['units'] = 'meter' varinfo['waveheight']['longname'] = 'Mean wave height' varinfo['setup']['units'] = 'meter' varinfo['setup']['longname'] = 'Mean wave induced setup' varinfo['u']['units'] = 'meter second-1' varinfo['u']['longname'] = 'Flow velocity in the xi direction' varinfo['v']['units'] = 'meter second-1' varinfo['v']['longname'] = 'Flow velocity in the eta direction' varinfo['w']['units'] = 'meter second-1' varinfo['w']['longname'] = 'Flow velocity in the vertical direction' varinfo['umean']['units'] = 'meter second-1' varinfo['umean'][ 'longname'] = 'Depth-averaged flow velocity in xi direction' varinfo['vmean']['units'] = 'meter second-1' varinfo['vmean'][ 'longname'] = 'Depth-averaged flow velocity in eta direction' varinfo['lag_umean']['units'] = 'meter second-1' varinfo['lag_umean'][ 'longname'] = 'Lagrangian mean velocity in xi direction' varinfo['lag_vmean']['units'] = 'meter second-1' varinfo['lag_vmean'][ 'longname'] = 'Lagrangian mean velocity in eta direction' varinfo['lag_wmean']['units'] = 'meter second-1' varinfo['lag_wmean'][ 'longname'] = 'Lagrangian mean velocity in vertical direction' varinfo['euler_umean']['units'] = 'meter second-1' varinfo['euler_umean'][ 'longname'] = 'Eulerian mean velocity in xi direction' varinfo['euler_vmean']['units'] = 'meter second-1' varinfo['euler_vmean'][ 'longname'] = 'Eulerian mean velocity in eta direction' varinfo['euler_wmean']['units'] = 'meter second-1' varinfo['euler_wmean'][ 'longname'] = 'Eulerian mean velocity in vertical direction' # Loop over 2D variables that have no time component ---------------------- if hdims == 1: nc_dims = ('xi_rho') else: nc_dims = ('eta_rho', 'xi_rho') for aa in vars_2d: if verbose: print(' Writing ' + aa) # Create variable create_nc_var(nc, aa, nc_dims, varinfo[aa]['units'], varinfo[aa]['longname']) nc.variables[aa][:] = np.loadtxt(workfld + '/' + aa) # Loop over 3D variables that have no time component ---------------------- if hdims == 1: nc_dims = ('s_rho', 'xi_rho') else: nc_dims = ('s_rho', 'eta_rho', 'xi_rho') for aa in vars_3d: if verbose: print(' Writing ' + aa) if aa == 'euler' or aa == 'lag': for bb in ['umean', 'vmean', 'wmean']: create_nc_var(nc, aa + '_' + bb, nc_dims, varinfo[aa + '_' + bb]['units'], varinfo[aa + '_' + bb]['longname']) if hdims == 1: nc.variables[aa + '_' + bb][:] = \ np.loadtxt(workfld + '/' + aa + '_' + bb) else: tmpvar = np.loadtxt(workfld + '/' + aa + '_' + bb) tmpvar2 = np.zeros((s_rho, eta_rho, xi_rho)) for cc in range(s_rho): tmpvar2[cc, :, :] = tmpvar[cc * eta_rho:(cc + 1) * eta_rho, :] nc.variables[aa + '_' + bb][:] = tmpvar2 del tmpvar, tmpvar2 else: # Need to test this part with a full 3d code print("need to fix this") # Loop over 2D variables that have a time component ----------------------- if hdims == 1: nc_dims = ('ocean_time', 'xi_rho') else: nc_dims = ('ocean_time', 'eta_rho', 'xi_rho') for aa in vars_2d_time: if verbose: print(' Writing ' + aa) # Create variable create_nc_var(nc, aa, nc_dims, varinfo[aa]['units'], varinfo[aa]['longname']) tmpvar = np.loadtxt(workfld + '/' + aa + '_' + '%05.0f' % 1) nc.variables[aa][:] = np.expand_dims(tmpvar, axis=0) for bb in range(2, len(ocean_time) + 1): tmpvar = np.loadtxt(workfld + '/' + aa + '_' + '%05.0f' % bb) append_nc_var(nc, tmpvar, aa, bb - 1) # Loop over 3D variables that have a time component ----------------------- if hdims == 1: nc_dims = ('ocean_time', 's_rho', 'xi_rho') else: nc_dims = ('ocean_time', 's_rho', 'eta_rho', 'xi_rho') for aa in vars_3d_time: if verbose: print(' Writing ' + aa) # Create variable create_nc_var(nc, aa, nc_dims, varinfo[aa]['units'], varinfo[aa]['longname']) if hdims == 1: tmpvar = np.loadtxt(workfld + '/' + aa + '_' + '%05.0f' % 1) if s_rho == 1: nc.variables[aa][:] = np.expand_dims(np.expand_dims(tmpvar, axis=0), axis=0) else: nc.variables[aa][:] = np.expand_dims(tmpvar, axis=0) for bb in range(2, len(ocean_time) + 1): tmpvar = np.loadtxt(workfld + '/' + aa + '_' + '%05.0f' % bb) append_nc_var(nc, tmpvar, aa, bb - 1) else: for bb in range(1, len(ocean_time) + 1): tmpvar = np.loadtxt(workfld + '/' + aa + '_' + '%05.0f' % bb) tmpvar2 = np.zeros((s_rho, eta_rho, xi_rho)) for cc in range(s_rho): tmpvar2[cc, :, :] = tmpvar[cc * eta_rho:(cc + 1) * eta_rho, :] if bb == 1: nc.variables[aa][:] = np.expand_dims(tmpvar2, axis=0) else: append_nc_var(nc, tmpvar2, aa, bb - 1) del tmpvar, tmpvar2 # Close NetCDF file ------------------------------------------------------- if verbose: print('Created: ' + outfile) nc.close()
os.remove(self.file) #pass def runTest(self): """testing compound variables""" f = Dataset(self.file, 'r') v = f.variables[VAR_NAME] g = f.groups[GROUP_NAME] vv = g.variables[VAR_NAME] dataout = v[:] dataoutg = vv[:] # make sure data type is aligned assert (f.cmptypes['cmp4'] == dtype4a) assert(list(f.cmptypes.keys()) ==\ [TYPE_NAME1,TYPE_NAME2,TYPE_NAME3,TYPE_NAME4,TYPE_NAME5]) assert_array_equal(dataout['xxx']['xx']['i'],data['xxx']['xx']['i']) assert_array_equal(dataout['xxx']['xx']['j'],data['xxx']['xx']['j']) assert_array_almost_equal(dataout['xxx']['yy']['x'],data['xxx']['yy']['x']) assert_array_almost_equal(dataout['xxx']['yy']['y'],data['xxx']['yy']['y']) assert_array_almost_equal(dataout['yyy'],data['yyy']) assert_array_equal(dataoutg['x1']['i'],datag['x1']['i']) assert_array_equal(dataoutg['x1']['j'],datag['x1']['j']) assert_array_almost_equal(dataoutg['y1']['x'],datag['y1']['x']) assert_array_almost_equal(dataoutg['y1']['y'],datag['y1']['y']) f.close() if __name__ == '__main__': from netCDF4 import getlibversion version = getlibversion().split()[0] unittest.main()
try: import ujson as json except: import json # Version information __version__ = "0.9b" VERSION_STR = ( "nc_diag_attr v" + __version__ + "\n\n" + "Using the following library/runtime versions:\n" + (" netcdf4-python v%s\n" % netCDF4.__version__) + (" NetCDF v%s\n" % getlibversion()) + (" HDF5 v%s\n" % netCDF4.__hdf5libversion__) + (" Python v%s\n" % sys.version.split("\n")[0].strip()) ) # CLI Arguments global args def parse_cli_args(): global args parser = argparse.ArgumentParser( # prog='ipush', formatter_class=argparse.RawDescriptionHelpFormatter, description="Tool to add/modify global and variable attributes for NetCDF files", version=VERSION_STR, )
def spec2nc(buoyfld,dtheta=5): ''' Code to convert NDBC spectral data files to netCDF format. Usage: ------ spec2nc(buoyfld,dtheta) Input: ------ buoyfld : Folder where the text files reside. Those should be the only files in the folder. dtheta : Directional resolution for the reconstruction of the frequency- direction spectrum. Defaults to 5 degrees. Notes: 1. NetCDF4 file will be generated 2. Code is not optimized since this is not something you will want to be running often. Beware of slow performance for large datasets. References: Kuik, A.J., G.Ph. van Vledder, and L.H. Holthuijsen, 1998: "Method for the Routine Analysis of Pitch-and-Roll Buoy Wave Data", Journal of Physical Oceanography, 18, 1020-1034. TODO: Only works with newer formats (YY MM DD hh mm) ''' # For testing only --------------------------------------------------------- #buoyfld = '/home/shusin2/users/ggarcia/data/wave/b46029/spec/' #dtheta = 20 # -------------------------------------------------------------------------- # Construct directional angle angles = np.arange(0.0,360.0,dtheta) # Time reference basetime = datetime.datetime(1900,1,1,0,0,0) #=========================================================================== # Read file information #=========================================================================== # Get all files in folder archivos = glob.glob(buoyfld + '/*.txt') archivos = [x.split('/')[-1] for x in archivos] # Year information years = [x.split('.')[0][-4:] for x in archivos] # Get all year stamps years = list(set(years)) # Find unique years years.sort() # Sort years # Get buoy ID information buoyid = [x[0:5] for x in archivos] # Find buoy ids buoyid = list(set(buoyid)) # Find unique ids if len(buoyid)>1: print('This code does not support conversion for multiple buoys') buoyid = buoyid[0] print(' ' + buoyid + ' will be processed') else: buoyid = buoyid[0] # Info print('Found ' + np.str(len(years)) + ' files') print(buoyfld) # Create output netcdf file ------------------------------------------------ # Global attributes nc = netCDF4.Dataset(buoyfld + '/' + buoyid + '_spec.nc', 'w',format='NETCDF4') nc.Description = buoyid + ' NDBC Spectral Data' nc.Rawdata = 'National Data Buoy Center \nwww.ndbc.noaa.gov' nc.Author = getpass.getuser() nc.Created = time.ctime() nc.Software = 'Created with Python ' + sys.version nc.NetCDF_Lib = str(netCDF4.getlibversion()) nc.Script = os.path.realpath(__file__) nc.Notes = 'Nautical convention used for directions' # Reconstruct the spectrum ------------------------------------------------- # counter variable to create variables in the netcdf file masterCnt = 0 cnt_freq = 0 cnt_dir = 0 tstep_freq = 0 tstep_dir = 0 # This variable will change if the format changes formIdCnt = 0 formId = '0' # Frequency array to find if the reported frequencies changed freqArray = [] # Loop over years for aa in years: # Info print(' Working on year ' + aa) # Load spectral density files # Check if file exists tmpfile = buoyfld + buoyid + 'w' + aa + '.txt' if os.path.isfile(tmpfile) == False: # No spectral density found for the given year, go to next one continue # Info print(' Spectral density data') # Increase master counter variable masterCnt += 1 # Read spectral density data (frequency spectra) and identify the time # information given f_w = open(tmpfile,'r') freq = f_w.readline().split() # Allocate the frequency array and determine if the format changed ---- freqArray.append(freq) if masterCnt > 1: if freq != freqArray[masterCnt-2]: # Reset counter variables cnt_freq = 0 cnt_dir = 0 tstep_freq = 0 tstep_dir = 0 # Update form Id counter formIdCnt += 1 if formIdCnt > 9: print('\n10 Different Formats Found') print('Check your data, quitting ...') nc.close() sys.exit() # Update form Id text formId = '%01.0f' % formIdCnt # Message to user print(' Different format found') print(' New variables introduced') # Find if minutes are given if freq[4] == 'mm': freqInd0 = 5 else: freqInd0 = 4 # Read frequencies freq = np.array(freq[freqInd0:],dtype=float) f_w.close() # Load spectral density freq_spec = np.loadtxt(tmpfile,skiprows=1) # Allocate time and spectral density data freq_time = np.zeros((freq_spec.shape[0])) for bb in range(freq_time.shape[0]): tmpYear = np.int(freq_spec[bb,0]) tmpMonth = np.int(freq_spec[bb,1]) tmpDay = np.int(freq_spec[bb,2]) tmpHour = np.int(freq_spec[bb,3]) if freqInd0 == 4: tmpMin = np.int(0) else: tmpMin = np.int(freq_spec[bb,4]) if tmpYear < 100: tmpYear = tmpYear + 1900 freq_time[bb] = (datetime.datetime(tmpYear,tmpMonth,tmpDay, tmpHour,tmpMin) - basetime).total_seconds() freq_spec = freq_spec[:,freqInd0:] # No Data Filter (NDBC uses 999.00 when there is no data) goodDataInd = freq_spec[:,1] < 990.00 freq_time = freq_time[goodDataInd] freq_spec = freq_spec[goodDataInd,:] # Create frequency spectra variables cnt_freq += 1 if cnt_freq == 1: # Create dimensions (NetCDF4 supports multiple unlimited dimensions) nc.createDimension('wave_time'+formId,None) # Create bulk parameter variables nc.createVariable('Hsig'+formId,'f8','wave_time'+formId) nc.variables['Hsig'+formId].units = 'meter' nc.variables['Hsig'+formId].long_name = 'Significant wave height' # Create frequency dimension nc.createDimension('freq'+formId,freq.shape[0]) nc.createVariable('wave_time'+formId,'f8','wave_time'+formId) nc.variables['wave_time'+formId].units = \ "seconds since 1900-01-01 00:00:00" nc.variables['wave_time'+formId].calendar = "julian" nc.createVariable('freq_spec'+formId,'f8', ('wave_time'+formId,'freq'+formId)) nc.variables['freq_spec'+formId].units = 'meter2 second' nc.variables['freq_spec'+formId].long_name = 'Frequency variance spectrum' nc.createVariable('frequency'+formId,'f8',('freq'+formId)) nc.variables['frequency'+formId].units = 'Hz' nc.variables['frequency'+formId].long_name = 'Spectral frequency' nc.variables['frequency'+formId][:] = freq # Information print(' Computing Bulk Parameters') # Compute bulk parameters moment0 = np.trapz(freq_spec.T,freq,axis=0) Hsig = 4.004*(moment0)**0.5 # Write to NetCDF file if cnt_freq == 1: nc.variables['Hsig'+formId][:] = Hsig nc.variables['freq_spec'+formId][:] = freq_spec nc.variables['wave_time'+formId][:] = freq_time else: nc.variables['Hsig'+formId][tstep_freq:] = Hsig nc.variables['freq_spec'+formId][tstep_freq:,:] = freq_spec nc.variables['wave_time'+formId][tstep_freq:] = freq_time # Check if directional data exists ------------------------------------- tmp_alpha_1 = buoyfld + buoyid + 'd' + aa + '.txt' tmp_alpha_2 = buoyfld + buoyid + 'i' + aa + '.txt' tmp_r_1 = buoyfld + buoyid + 'j' + aa + '.txt' tmp_r_2 = buoyfld + buoyid + 'k' + aa + '.txt' if (os.path.isfile(tmp_alpha_1) and os.path.isfile(tmp_alpha_2) and os.path.isfile(tmp_r_1) and os.path.isfile(tmp_r_2)): # Information print(' Directional Data') # Read frequency of the directional spectra (not always agree with # the spectral densities) f_w2 = open(tmp_alpha_1,'r') freqDirSpec = f_w2.readline().split() freqDirSpec = np.array(freqDirSpec[freqInd0:],dtype=float) f_w2.close() # Create directional spectra variables cnt_dir += 1 if cnt_dir == 1: nc.createDimension('dir_time'+formId,None) nc.createDimension('dir'+formId,angles.shape[0]) # Create frequency dimension nc.createDimension('freqDir'+formId,freqDirSpec.shape[0]) nc.createVariable('dir_time'+formId,'f8','dir_time'+formId) nc.variables['dir_time'+formId].units = \ "seconds since 1900-01-01 00:00:00" nc.variables['dir_time'+formId].calendar = "julian" nc.createVariable('dir_spec'+formId,'f8', ('dir_time'+formId,'freqDir'+formId, 'dir'+formId)) nc.variables['dir_spec'+formId].units = 'meter2 second degree-1' nc.variables['dir_spec'+formId].long_name = \ 'Frequency-Direction variance spectrum' nc.createVariable('direction'+formId,'f8',('dir'+formId)) nc.variables['direction'+formId].units = 'degree' nc.variables['direction'+formId].long_name = \ 'Degrees from true north in oceanographic convention' nc.variables['direction'+formId][:] = angles nc.createVariable('frequencyDir'+formId,'f8',('freqDir'+formId)) nc.variables['frequencyDir'+formId].units = 'Hz' nc.variables['frequencyDir'+formId].long_name = 'Spectral frequency for dir_spec' nc.variables['frequencyDir'+formId][:] = freqDirSpec # Read spectral data alpha_1 = np.loadtxt(tmp_alpha_1,skiprows=1) alpha_2 = np.loadtxt(tmp_alpha_1,skiprows=1) r_1 = np.loadtxt(tmp_alpha_1,skiprows=1) * 0.01 r_2 = np.loadtxt(tmp_alpha_1,skiprows=1) * 0.01 # Allocate date dir_time = np.zeros((alpha_1.shape[0])) for bb in range(dir_time.shape[0]): tmpYear = np.int(alpha_1[bb,0]) tmpMonth = np.int(alpha_1[bb,1]) tmpDay = np.int(alpha_1[bb,2]) tmpHour = np.int(alpha_1[bb,3]) if freqInd0 == 4: tmpMin = np.int(0) else: tmpMin = np.int(alpha_1[bb,4]) if tmpYear < 100: tmpYear = tmpYear + 1900 dir_time[bb] = (datetime.datetime(tmpYear,tmpMonth,tmpDay, tmpHour,tmpMin) - basetime).total_seconds() # Read data alpha_1 = alpha_1[:,freqInd0:] alpha_2 = alpha_2[:,freqInd0:] r_1 = r_1[:,freqInd0:] r_2 = r_2[:,freqInd0:] # No Data Filter (NDBC uses 999.00 when there is no data) goodDataInd = np.logical_and(alpha_1[:,1] != 999.00, alpha_1[:,2] != 999.00) alpha_1 = alpha_1[goodDataInd,:] alpha_2 = alpha_2[goodDataInd,:] r_1 = r_1[goodDataInd,:] r_2 = r_2[goodDataInd,:] dir_time = dir_time[goodDataInd] # Find where dir_time and freq_time match and compute those values # only repInd = np.in1d(dir_time,freq_time) alpha_1 = alpha_1[repInd] alpha_2 = alpha_2[repInd] r_1 = r_1[repInd] r_2 = r_2[repInd] dir_time = dir_time[repInd] repInd = np.in1d(freq_time,dir_time) freq_spec = freq_spec[repInd] # Interpolate density spectrum into directional bins if not np.array_equal(freq,freqDirSpec): freqSpecAll = np.copy(freq_spec) freq_spec = np.zeros_like((r_1)) * np.NAN for bb in range(freq_spec.shape[0]): freq_spec[bb,:] = np.interp(freqDirSpec,freq, freqSpecAll[bb,:]) # Construct 2D spectra # See http://www.ndbc.noaa.gov/measdes.shtml wspec = np.NaN * np.zeros((alpha_1.shape[0], alpha_1.shape[1],angles.shape[0])) # Time loop for bb in range(wspec.shape[0]): # Frequency loop for cc in range(wspec.shape[1]): # Direction loop for dd in range(wspec.shape[2]): wspec[bb,cc,dd] = (freq_spec[bb,cc] * np.pi/180.0 * (1.0/np.pi) * (0.5 + r_1[bb,cc] * np.cos((angles[dd]-alpha_1[bb,cc])* np.pi/180.0) + r_2[bb,cc] * np.cos(2 * np.pi / 180.0 * (angles[dd]-alpha_2[bb,cc]))) ) # Write to file if cnt_dir == 1: nc.variables['dir_spec'+formId][:] = wspec nc.variables['dir_time'+formId][:] = dir_time else: nc.variables['dir_spec'+formId][tstep_dir:,:,:] = wspec nc.variables['dir_time'+formId][tstep_dir:] = dir_time tstep_dir += dir_time.shape[0] # Update frequency time step and go to next year tstep_freq += freq_time.shape[0] # Wrap up ------------------------------------------------------------------ # Information print('Data stored as:') print(' ' + buoyfld + '/' + buoyid + '.nc') # Close NetCDF File nc.close()
def spec2nc(buoyfld, dtheta=5): ''' Code to convert NDBC spectral data files to netCDF format. Usage: ------ spec2nc(buoyfld,dtheta) Input: ------ buoyfld : Folder where the text files reside. Those should be the only files in the folder. dtheta : Directional resolution for the reconstruction of the frequency- direction spectrum. Defaults to 5 degrees. Notes: 1. NetCDF4 file will be generated 2. Code is not optimized since this is not something you will want to be running often. Beware of slow performance for large datasets. References: Kuik, A.J., G.Ph. van Vledder, and L.H. Holthuijsen, 1998: "Method for the Routine Analysis of Pitch-and-Roll Buoy Wave Data", Journal of Physical Oceanography, 18, 1020-1034. TODO: Only works with newer formats (YY MM DD hh mm) ''' # For testing only --------------------------------------------------------- # buoyfld = '/home/shusin2/users/ggarcia/data/wave/b46029/spec/' # dtheta = 5 # -------------------------------------------------------------------------- # Construct directional angle angles = np.arange(0.0, 360.0, dtheta) # Time reference basetime = datetime.datetime(1900, 01, 01, 0, 0, 0) #=========================================================================== # Read file information #=========================================================================== # Get all files in folder archivos = os.listdir(buoyfld) # Year information years = [x.split('.')[0][-4:] for x in archivos] # Get all year stamps years = list(set(years)) # Find unique years years.sort() # Sort years # Get buoy ID information buoyid = [x[0:5] for x in archivos] # Find buoy ids buoyid = list(set(buoyid)) # Find unique ids if len(buoyid) > 1: print('This code does not support conversion for multiple buoys') buoyid = buoyid[0] print(' ' + buoyid + ' will be processed') else: buoyid = buoyid[0] # Create output netcdf file ------------------------------------------------ # Global attributes nc = netCDF4.Dataset(buoyfld + '/' + buoyid + '_spec.nc', 'w', format='NETCDF4') nc.Description = buoyid + ' NDBC Spectral Data' nc.Rawdata = 'National Data Buoy Center \nwww.ndbc.noaa.gov' nc.Author = getpass.getuser() nc.Created = time.ctime() nc.Software = 'Created with Python ' + sys.version nc.NetCDF_Lib = str(netCDF4.getlibversion()) nc.Script = os.path.realpath(__file__) nc.Notes = 'Nautical convention used for directions' # Create dimensions (NetCDF4 supports multiple unlimited dimensions) nc.createDimension('wave_time', None) nc.createDimension('dir_time', None) # Create bulk parameter variables nc.createVariable('Hsig', 'f8', 'wave_time') nc.variables['Hsig'].units = 'meter' nc.variables['Hsig'].long_name = 'Significant wave height' # Reconstruct the spectrum ------------------------------------------------- # counter variable to create variables in the netcdf file cnt_freq = 0 cnt_dir = 0 tstep_freq = 0 tstep_dir = 0 # Loop over years for aa in years: # Load spectral density files # Check if file exists tmpfile = buoyfld + buoyid + 'w' + aa + '.txt' if os.path.isfile(tmpfile) == False: # No spectral density found for the given year, go to next one continue # Read spectral density data (frequency spectra) f_w = open(tmpfile, 'r') freq = f_w.readline().split() # Read frequencies freq = np.array(freq[5:], dtype=float) f_w.close() # Load spectral density freq_spec = np.loadtxt(tmpfile, skiprows=1) # Allocate time and spectral density data freq_time = np.zeros((freq_spec.shape[0])) for bb in range(freq_time.shape[0]): freq_time[bb] = (datetime.datetime( np.int(freq_spec[bb, 0]), np.int(freq_spec[bb, 1]), np.int(freq_spec[bb, 2]), np.int(freq_spec[bb, 3]), np.int(freq_spec[bb, 4])) - basetime).total_seconds() freq_spec = freq_spec[:, 5:] # Create frequency spectra variables cnt_freq += 1 if cnt_freq == 1: nc.createDimension('freq', freq.shape[0]) nc.createVariable('wave_time', 'f8', 'wave_time') nc.variables['wave_time'].units = \ "seconds since 1900-01-01 00:00:00" nc.variables['wave_time'].calendar = "julian" nc.createVariable('freq_spec', 'f8', ('wave_time', 'freq')) nc.variables['freq_spec'].units = 'meter2 second' nc.variables['freq_spec'].long_name = 'Frequency variance spectrum' nc.createVariable('frequency', 'f8', ('freq')) nc.variables['frequency'].units = 'Hz' nc.variables['frequency'].long_name = 'Spectral frequency' nc.variables['frequency'][:] = freq # Check if directional data exists tmp_alpha_1 = buoyfld + buoyid + 'd' + aa + '.txt' tmp_alpha_2 = buoyfld + buoyid + 'i' + aa + '.txt' tmp_r_1 = buoyfld + buoyid + 'j' + aa + '.txt' tmp_r_2 = buoyfld + buoyid + 'k' + aa + '.txt' if (os.path.isfile(tmp_alpha_1) and os.path.isfile(tmp_alpha_2) and os.path.isfile(tmp_r_1) and os.path.isfile(tmp_r_2)): # Create directional spectra variables cnt_dir += 1 if cnt_dir == 1: nc.createDimension('dir', angles.shape[0]) nc.createVariable('dir_time', 'f8', 'dir_time') nc.variables['dir_time'].units = \ "seconds since 1900-01-01 00:00:00" nc.variables['dir_time'].calendar = "julian" nc.createVariable('dir_spec', 'f8', ('dir_time', 'freq', 'dir')) nc.variables['dir_spec'].units = 'meter2 second degree-1' nc.variables['dir_spec'].long_name = \ 'Frequency-Direction variance spectrum' nc.createVariable('direction', 'f8', ('dir')) nc.variables['direction'].units = 'degree' nc.variables['direction'].long_name = \ 'Degrees from true north in oceanographic convention' nc.variables['direction'][:] = angles # Read spectral data alpha_1 = np.loadtxt(tmp_alpha_1, skiprows=1) alpha_2 = np.loadtxt(tmp_alpha_1, skiprows=1) r_1 = np.loadtxt(tmp_alpha_1, skiprows=1) * 0.01 r_2 = np.loadtxt(tmp_alpha_1, skiprows=1) * 0.01 # Allocate data dir_time = np.zeros((alpha_1.shape[0])) for bb in range(dir_time.shape[0]): dir_time[bb] = (datetime.datetime( np.int(alpha_1[bb, 0]), np.int(alpha_1[bb, 1]), np.int(alpha_1[bb, 2]), np.int(alpha_1[bb, 3]), np.int(alpha_1[bb, 4])) - basetime).total_seconds() alpha_1 = alpha_1[:, 5:] alpha_2 = alpha_2[:, 5:] r_1 = r_1[:, 5:] r_2 = r_2[:, 5:] # Construct 2D spectra # See http://www.ndbc.noaa.gov/measdes.shtml wspec = np.NaN * np.zeros( (alpha_1.shape[0], freq.shape[0], angles.shape[0])) # Time loop for bb in range(wspec.shape[0]): # Frequency loop for cc in range(wspec.shape[1]): # Direction loop for dd in range(wspec.shape[2]): wspec[bb, cc, dd] = ( freq_spec[bb, cc] * np.pi / 180.0 * (1.0 / np.pi) * (0.5 + r_1[bb, cc] * np.cos( (angles[dd] - alpha_1[bb, cc]) * np.pi / 180.0) + r_2[bb, cc] * np.cos(2 * np.pi / 180.0 * (angles[dd] - alpha_2[bb, cc])))) # Write to file if cnt_dir == 1: nc.variables['dir_spec'][:] = wspec nc.variables['dir_time'][:] = dir_time else: nc.variables['dir_spec'][tstep_dir:, :, :] = wspec nc.variables['dir_time'][tstep_dir:] = dir_time tstep_dir += dir_time.shape[0] # Compute bulk parameters moment0 = np.trapz(freq_spec.T, freq, axis=0) Hsig = 4.004 * (moment0)**0.5 # Write to NetCDF file if cnt_freq == 1: nc.variables['Hsig'][:] = Hsig nc.variables['freq_spec'][:] = freq_spec nc.variables['wave_time'][:] = freq_time else: nc.variables['Hsig'][tstep_freq:] = Hsig nc.variables['freq_spec'][tstep_freq:, :] = freq_spec nc.variables['wave_time'][tstep_freq:] = freq_time tstep_freq += freq_time.shape[0] # Wrap up ------------------------------------------------------------------ # Close NetCDF File nc.close()
def convert_output(workfld,outfile,time_int=1.0,bathyfile=None, inpfile=None,verbose=False): ''' Parameters: ----------- workfld : Path to the folder where output files reside outfile : Output NetCDF file time_int : Time interval between output files [s] (will be updated if input file is provided) bathyfile : Full path to input netcdf bathy file (optional) inpfile : Funwave input file used for metadata (optional) verbose : Defaults to False Output: ------- NetCDF File with the variables in the folder. Not all are supported so you may need to edit this file. ''' # For testing only #workfld = '/scratch/temp/ggarcia/funwaveC_ensemble/r0/' #outfile = '/scratch/temp/ggarcia/funwaveC_ensemble/02-runs/tmp.nc' #time_int = 0.5 #bathyfile = '/scratch/temp/ggarcia/funwaveC_ensemble/r0/depth.nc' #inpfile = '/scratch/temp/ggarcia/funwaveC_ensemble/r0/input.init' # Get variable information ------------------------------------------------ # Need to generalize archivos = glob.glob(workfld + '*.dat') # All files tmpvars = [x.split('/')[-1].split('.')[0] for x in archivos] # All vars # If no variables found exit if not tmpvars: print('No files found in ' + workfld) print('Quitting ...') return None # Make sure variables are within the supported ones supported_vars_time = ['eta','u'] vars_2d = [x for x in tmpvars if x in supported_vars_time] # Read input file if provided ---------------------------------------------- if inpfile: if verbose: print("Reading data from input file:") print(" " + inpfile) # Open file tmpinpfile = open(inpfile,'r') # Output dictionary inpinfo = {} # funwaveC is very structured so this is a simple way of reading # Dynamics line tmpLine = tmpinpfile.readline().rstrip() inpinfo['dynamics'] = tmpLine.split(' ')[-1] # Dimensions tmpLine = tmpinpfile.readline().rstrip() dx = np.float64(tmpLine.split(' ')[3]) dy = np.float64(tmpLine.split(' ')[4]) # Bottom stress tmpLine = tmpinpfile.readline().rstrip() inpinfo['bottomstress'] = tmpLine.split(' ')[2] # Mixing tmpLine = tmpinpfile.readline().rstrip() inpinfo['mixing'] = tmpLine.split(' ')[1] + ' ' + tmpLine.split(' ')[2] # Bathymetry tmpinpfile.readline() # Tide tmpinpfile.readline() # Wavemaker tmpLine = tmpinpfile.readline().rstrip() inpinfo['eta_source'] = tmpLine[14:] # Wave breaking tmpLine = tmpinpfile.readline().rstrip() inpinfo['breaking'] = tmpLine[9:] # Sponge layer tmpLine = tmpinpfile.readline().rstrip() inpinfo['sponge'] = tmpLine[7:] # Forcing, initial conditions, tracers tmpinpfile.readline() tmpinpfile.readline() tmpinpfile.readline() tmpinpfile.readline() tmpinpfile.readline() tmpinpfile.readline() # Timing tmpLine = tmpinpfile.readline().rstrip() inpinfo['timing'] = tmpLine[7:] time_int = np.float64(tmpLine.split(' ')[5]) # Close me tmpinpfile.close() else: # Assume grid spacing to be 1 meter if verbose: print("Input file not provided") dx = 1.0 dy = 1.0 inpinfo = False # Coordinates and depth --------------------------------------------------- # Bathymetry file provided if bathyfile: if verbose: print("Reading coordinates and depth from:") print(" " + bathyfile) ncfile = netCDF4.Dataset(bathyfile,'r') x_rho = ncfile.variables['x_rho'][:] if ncfile.variables.has_key('y_rho'): y_rho = ncfile.variables['y_rho'][:] else: y_rho = None h = ncfile.variables['h'][:] ncfile.close() # Create u grid x_u = np.zeros((x_rho.shape[0]+1,)) x_u[0] = x_rho[0] - dx/2 x_u[-1] = x_rho[-1] + dx/2 x_u[1:-1] = (x_rho[1:] + x_rho[:-1])/2.0 # Bathymetry file not provided but have output file elif os.path.isfile(workfld + '/depth.txt'): # Fix this h = np.loadtxt(workfld + '/depth.txt') hdims = h.ndim if hdims == 1: x_rho = np.arange(0,h.shape[0],dx) elif hdims == 2: x_rho, y_rho = np.meshgrid(np.arange(0,h.shape[1],dx), np.arange(0,h.shape[0],dy)) else: if verbose: print('Something is wrong with the depth file') # No bathymetry file provided else: if verbose: print("No bathymetry file provided") # Get dimensions of variables hdims = h.ndim # Create NetCDF file ------------------------------------------------------- if verbose: print("Creating " + outfile) # Global attributes nc = netCDF4.Dataset(outfile, 'w', format='NETCDF4') nc.Description = 'FunwaveC Output' nc.Author = '*****@*****.**' nc.Created = time.ctime() nc.Type = 'FunwaveC snapshot output' nc.Owner = 'Nearshore Modeling Group' nc.Software = 'Created with Python ' + sys.version nc.NetCDF_Lib = str(netCDF4.getlibversion()) nc.Source = workfld nc.Script = os.path.realpath(__file__) # Add more global variables to output if inpinfo: for tmpatt in inpinfo.keys(): nc.__setattr__(tmpatt,inpinfo[tmpatt][:]) # Create dimensions if hdims == 2: eta_rho, xi_rho = h.shape nc.createDimension('eta_rho', eta_rho) else: xi_rho = h.shape[0] xi_u = xi_rho + 1 eta_rho = 1 nc.createDimension('xi_rho', xi_rho) nc.createDimension('xi_u',xi_u) nc.createDimension('ocean_time',0) # Write coordinate axes ---------------------------------------------- if hdims == 2: nc.createVariable('x_rho','f8',('eta_rho','xi_rho')) nc.variables['x_rho'].units = 'meter' nc.variables['x_rho'].longname = 'x-locations of RHO points' nc.variables['x_rho'][:] = x_rho nc.createVariable('y_rho','f8',('eta_rho','xi_rho')) nc.variables['y_rho'].units = 'meter' nc.variables['y_rho'].longname = 'y-locations of RHO points' nc.variables['y_rho'][:] = y_rho nc.createVariable('h','f8',('eta_rho','xi_rho')) nc.variables['h'].units = 'meter' nc.variables['h'].longname = 'bathymetry at RHO points' nc.variables['h'][:] = h else: nc.createVariable('x_rho','f8',('xi_rho')) nc.variables['x_rho'].units = 'meter' nc.variables['x_rho'].longname = 'x-locations of RHO points' nc.variables['x_rho'][:] = x_rho nc.createVariable('h','f8',('xi_rho')) nc.variables['h'].units = 'meter' nc.variables['h'].longname = 'bathymetry at RHO points' nc.variables['h'][:] = h nc.createVariable('x_u','f8',('xi_u')) nc.variables['x_u'].units = 'meter' nc.variables['x_u'].longname = 'x-locations of U points' nc.variables['x_u'][:] = x_u # Create time vector ------------------------------------------------------- tmpvar = np.loadtxt(workfld + vars_2d[0] + '.dat') twave = np.arange(time_int,time_int*tmpvar.shape[0]+time_int,time_int) nc.createVariable('ocean_time','f8','ocean_time') nc.variables['ocean_time'].units = 'seconds since 2000-01-01 00:00:00' nc.variables['ocean_time'].calendar = 'julian' nc.variables['ocean_time'].long_name = 'beach time' nc.variables['ocean_time'][:] = twave # Create variables -------------------------------------------------------- # Variable information varinfo = defaultdict(dict) varinfo['eta']['units'] = 'meter' varinfo['eta']['longname'] = 'water surface elevation' varinfo['eta']['dims'] = ('ocean_time','xi_rho') varinfo['u']['units'] = 'meter second-1' varinfo['u']['longname'] = 'Flow velocity in the xi direction' varinfo['u']['dims'] = ('ocean_time','xi_u') varinfo['v']['units'] = 'meter second-1' varinfo['v']['longname'] = 'Flow velocity in the eta direction' varinfo['v']['dims'] = ('ocean_time','xi_v') if verbose: print("Creating variables") for aa in vars_2d: if verbose: print(' ' + aa) # Load variable try: tmpvar = np.loadtxt(workfld + '/' + aa + '.dat') except: if verbose: print(" Could not create " + aa) print(" Input file error") continue # Create variable create_nc_var(nc,aa,varinfo[aa]['dims'],varinfo[aa]['units'], varinfo[aa]['longname']) # Write variable nc.variables[aa][:] = tmpvar # Close NetCDF file if verbose: print('Closing ' + outfile) nc.close()
def bulk2nc(buoyfld,buoyid,ncformat=4,verbose=True): ''' Code to convert bulk parameter text files into netcdf file Usage: ------ bulk2nc(buoyfld,buoyid,ncformat) Input: ------ buoyfld = Folder where the bulk paramerter text files reside. buoyid = Netcdf buoy identifier (to figure out the file names) ncformat = set as 3 for netCDF3, set as 4 for netCDF4 (default) verbose = some extra information (True is default) Notes: Only the bulk parameter files must be present in that directory. The code is not smart enough (and I do not have the time to make it so) to figure out the bulk parameter files. ''' #=========================================================================== # Read and Clean Up Data #=========================================================================== # Get all files in folder archivos = os.listdir(buoyfld) archivos.sort() # Initialize variables wavetime = np.empty([1,]) WDIR = np.empty([1,]) #AKA WD WSPD = np.empty([1,]) GST = np.empty([1,]) WVHT = np.empty([1,]) DPD = np.empty([1,]) APD = np.empty([1,]) MWD = np.empty([1,]) PRES = np.empty([1,]) #AKA BAR ATMP = np.empty([1,]) WTMP = np.empty([1,]) # Loop over files for tmpFile in archivos: if tmpFile.endswith('.txt'): if verbose: print(tmpFile) # Read header lines to determine the location of variables with open(buoyfld + '/' + tmpFile,'r') as f: header1 = f.readline() header2 = f.readline() # Determine the number of header lines (NDBC uses one or two) if header1.startswith('Y') or header1.startswith('#'): headcnt = 1 if header2.startswith('Y') or header2.startswith('#'): headcnt = 2 # Collapse multiple spaces into one header3 = ' '.join(header1.split()) header4 = header3.split() # Load buoy data tmpdata = pl.loadtxt(buoyfld + '/' + tmpFile,skiprows=headcnt) # ====================== Allocate variables ==================== # # Wind direction if any(tt == 'WD' for tt in header4): tind = header4.index('WD') WDIR = np.concatenate((WDIR,tmpdata[:,tind])) elif any(tt == 'WDIR' for tt in header4): tind = header4.index('WDIR') WDIR = np.concatenate((WDIR,tmpdata[:,tind])) else: tmparray = np.ones([tmpdata.shape[0],1]) tmparray[:] = np.NaN WDIR = np.concatenate((WDIR,tmparray)) del tmparray # Wind Speed if any(tt == 'WSPD' for tt in header4): tind = header4.index('WSPD') WSPD = np.concatenate((WSPD,tmpdata[:,tind])) else: tmparray = np.ones([tmpdata.shape[0],1]) tmparray[:] = np.NaN WSPD = np.concatenate((WSPD,tmparray)) del tmparray # Wind Gust if any(tt == 'GST' for tt in header4): tind = header4.index('GST') GST = np.concatenate((GST,tmpdata[:,tind])) else: tmparray = np.ones([tmpdata.shape[0],1]) tmparray[:] = np.NaN GST = np.concatenate((GST,tmparray)) del tmparray # Wave Height if any(tt == 'WVHT' for tt in header4): tind = header4.index('WVHT') WVHT = np.concatenate((WVHT,tmpdata[:,tind])) else: tmparray = np.ones([tmpdata.shape[0],1]) tmparray[:] = np.NaN WVHT = np.concatenate((WVHT,tmparray)) del tmparray # Dominant Wave Period if any(tt == 'DPD' for tt in header4): tind = header4.index('DPD') DPD = np.concatenate((DPD,tmpdata[:,tind])) else: tmparray = np.ones([tmpdata.shape[0],1]) tmparray[:] = np.NaN DPD = np.concatenate((DPD,tmparray)) del tmparray # Average Wave Period if any(tt == 'APD' for tt in header4): tind = header4.index('APD') APD = np.concatenate((APD,tmpdata[:,tind])) else: tmparray = np.ones([tmpdata.shape[0],1]) tmparray[:] = np.NaN APD = np.concatenate((APD,tmparray)) del tmparray # Mean Wave Direction if any(tt == 'MWD' for tt in header4): tind = header4.index('MWD') MWD = np.concatenate((MWD,tmpdata[:,tind])) else: tmparray = np.ones([tmpdata.shape[0],1]) tmparray[:] = np.NaN MWD = np.concatenate((MWD,tmparray)) del tmparray # Sea Level Pressure if any(tt == 'PRES' for tt in header4): tind = header4.index('PRES') PRES = np.concatenate((PRES,tmpdata[:,tind])) elif any(tt == 'BAR' for tt in header4): tind = header4.index('BAR') PRES = np.concatenate((PRES,tmpdata[:,tind])) else: tmparray = np.ones([tmpdata.shape[0],1]) tmparray[:] = np.NaN PRES = np.concatenate((PRES,tmparray)) del tmparray # Air temperature if any(tt == 'ATMP' for tt in header4): tind = header4.index('ATMP') ATMP = np.concatenate((ATMP,tmpdata[:,tind])) else: tmparray = np.ones([tmpdata.shape[0],1]) tmparray[:] = np.NaN ATMP = np.concatenate((ATMP,tmparray)) del tmparray # Sea surface temperature if any(tt == 'WTMP' for tt in header4): tind = header4.index('WTMP') WTMP = np.concatenate((WTMP,tmpdata[:,tind])) else: tmparray = np.ones([tmpdata.shape[0],1]) tmparray[:] = np.NaN WTMP = np.concatenate((WTMP,tmparray)) del tmparray # ================== Time management ================= # Years if any(tt == 'YY' for tt in header4): tind = header4.index('YY') years = tmpdata[:,tind] + 1900 elif any(tt == '#YY' for tt in header4): tind = header4.index('#YY') years = tmpdata[:,tind] else: tind = header4.index('YYYY') years = tmpdata[:,tind] # Minutes if any(tt == 'mm' for tt in header4): tind = header4.index('mm') mm = tmpdata[:,tind] else: mm = np.zeros([tmpdata.shape[0],1]) # Create time vector # Seconds from 1900-01-01 will be used for aa in range(tmpdata.shape[0]): tmptime = datetime.datetime(int(years[aa]), int(tmpdata[aa,1]), int(tmpdata[aa,2]), int(tmpdata[aa,3]), int(mm[aa]), 0) sectime = tmptime - datetime.datetime(1900,1,1,0,0,0) secsecs = sectime.total_seconds() wavetime = np.concatenate([wavetime,np.array([secsecs])]) del tmptime,sectime,secsecs # ================ Clean up ================ del header1,header2,header3,header4,years,mm # Remove first term of each array wavetime = np.delete(wavetime,0) WDIR = np.delete(WDIR,0) WSPD = np.delete(WSPD,0) GST = np.delete(GST,0) WVHT = np.delete(WVHT,0) DPD = np.delete(DPD,0) APD = np.delete(APD,0) MWD = np.delete(MWD,0) PRES = np.delete(PRES,0) ATMP = np.delete(ATMP,0) WTMP = np.delete(WTMP,0) # Clean up variables WDIR[WDIR==999] = np.NaN WSPD[WSPD==99] = np.NaN GST[GST==99] = np.NaN WVHT[WVHT==99] = np.NaN DPD[DPD==99] = np.NaN APD[APD==99] = np.NaN MWD[MWD==999] = np.NaN PRES[PRES==9999] = np.NaN ATMP[ATMP==99] = np.NaN WTMP[WTMP==99] = np.NaN # Order chronologically sorted_index = np.argsort(wavetime) wavetime = [wavetime[i] for i in sorted_index] WDIR = [WDIR[i] for i in sorted_index] WSPD = [WSPD[i] for i in sorted_index] GST = [GST[i] for i in sorted_index] WVHT = [WVHT[i] for i in sorted_index] DPD = [DPD[i] for i in sorted_index] APD = [APD[i] for i in sorted_index] MWD = [MWD[i] for i in sorted_index] PRES = [PRES[i] for i in sorted_index] ATMP = [ATMP[i] for i in sorted_index] WTMP = [WTMP[i] for i in sorted_index] #=========================================================================== # Save as NetCDF #=========================================================================== # Global attributes if ncformat == 4: print("Saving the buoy data with NetCDF4 format") nc = netCDF4.Dataset(buoyfld + '/' + buoyid + '.nc', 'w', format='NETCDF4') else: print("Saving the buoy data with NetCDF3 format") nc = netCDF4.Dataset(buoyfld + '/' + buoyid + '.nc', 'w', format='NETCDF3_CLASSIC') nc.Description = buoyid + ' NDBC Bulk Parameter Data' nc.rawdata = 'National Data Buoy Center \nwww.ndbc.noaa.gov' nc.Author = '[email protected] \nNearshore Modeling Group' nc.Created = time.ctime() nc.Software = 'Created with Python ' + sys.version nc.NetCDF_Lib = str(netCDF4.getlibversion()) nc.Script = os.path.realpath(__file__) # Create dimensions nc.createDimension('wave_time',None) # pyroms subroutine to write NetCDF fields def write_nc_var(var, name, dimensions, units=None, longname=None): nc.createVariable(name, 'f8', dimensions) if units is not None: nc.variables[name].units = units if longname is not None: nc.variables[name].long_name = longname nc.variables[name][:] = var # Write Variables To NetCDF file write_nc_var(wavetime,'wave_time','wave_time', 'seconds since 1900-01-01 00:00:00','measurement time UTC') write_nc_var(WDIR, 'WDIR', 'wave_time', 'degrees', 'Wind direction (direction the wind is coming from in ' + 'degrees clockwise from true North') write_nc_var(WSPD, 'WSPD', 'wave_time', 'meter second-1', 'Wind speed averaged over an eight-minute period') write_nc_var(GST, 'GST','wave_time','meter second-1','Peak gust speed') write_nc_var(WVHT,'WVHT','wave_time','meter', 'Significant wave height during the 20 minute sampling period') write_nc_var(DPD,'DPD','wave_time','second', 'Dominant wave period (period with the maximum wave energy)') write_nc_var(APD,'APD','wave_time','second', 'Average wave period of all waves during the 20 minute' + ' sampling period') write_nc_var(MWD,'MWD','wave_time','degrees', 'The direction from which the waves at the dominant period ' + 'are coming in degrees from true North, increasing clockwise') write_nc_var(PRES,'PRES','wave_time','hPa','Sea level pressure') write_nc_var(ATMP,'ATMP','wave_time','Celsius','Air temperature') write_nc_var(WTMP,'WTMP','wave_time','Celsius','Sea surface temperature') # Close NetCDF File nc.close()
def writeROMSGrid(outFile,variables,varinfo, timeinfo=None,verbose=False): """ Code to write roms grids based on input variables INPUT: ------ outFile : Full path to output netcdf file variables : Dictionary containing variables. (see notes) varinfo : Path to ROMS varinfo.dat. Usually under: /path/to/roms/trunk/ROMS/External/varinfo.dat timeinfo : Time vector in nested dictionary form (see example) verbose : some info displayed on the terminal RETURNS: -------- NOTES: ------ - variables need rho variables (x_rho,y_rho) TODO: ----- - Include a varinfo.dat with the pynmd package EXAMPLE: --------- >>> import numpy as np >>> from collections import defaultdict >>> import pynmd.models.roms.pre as groms >>> >>> x_rho,y_rho = np.meshgrid(np.arange(0,10,1),np.arange(0,10,1) >>> variables = {} >>> variables['x_rho'] = x_rho >>> variables['y_rho'] = y_rho >>> >>> variables['type'] = 'ROMS FORCING FILE' >>> >>> timeinfo = defaultdict(time) >>> timeinfo['sms_time']['units'] = 'seconds since 1970-01-01 00:00:00 UTC' >>> timeinfo['sms_time']['data'] = np.arange(0,1000,10) >>> timeinfo['sms_time']['long_name'] = 'surface momentum stress time' >>> >>> groms.writeROMSGrid(outFile,...) """ # Testing only #outFile = ('/home/shusin3/users/ggarcia/projects/other/' + # 'columbiaRiverPlume/11-romsIdealized/03-extendedNR2/' + # 'orIdealizedExtStr.nc') #varinfo = ('/home/shusin3/users/ggarcia/projects/other/' + # 'columbiaRiverPlume/94-roms/trunk/ROMS/External/varinfo.dat') #verbose = True # Read varinfo ------------------------------------------------------------- if verbose: print('Reading Varinfo') print(' ' + varinfo) # Create dictionary to get information from varinfodict = defaultdict(dict) # Structure of the variables # hardcoded because I couldn't find a generalized description varStruct = ['long_name','units','field','time','id','dimensions'] # Read the varinfo with open(varinfo) as f: # Read into a list of lines lines = f.readlines() # Loop through lines for line in lines: #Skip lines starting with ! if line.startswith("!"): continue # Skip blank lines if line.isspace(): continue # Skip other non variable lines if line.startswith("'$"): continue # Read variables and allocate properties if line.startswith("'"): tmpVar = line.split(' ')[0][1:-1] cnt = -1 continue # Add counter variable and allocate only the necessary fields cnt += 1 if cnt > (len(varStruct) - 1): continue varinfodict[tmpVar][varStruct[cnt]] =\ line.split(' ')[1].split('\n')[0][1:-1] f.close() # Import grid variables and update the dictionary gridVariables = gridVars() varinfodict.update(gridVariables) # Create netCDF file ------------------------------------------------------- if verbose: print('Creating: ' + outFile) nc = netCDF4.Dataset(outFile, 'w', format='NETCDF4') nc.Author = getpass.getuser() nc.Created = time.ctime() #nc.Owner = 'Nearshore Modeling Group (http://ozkan.oce.orst.edu/nmg)' nc.Software = 'Created with Python ' + sys.version nc.NetCDF_Lib = str(netCDF4.getlibversion()) if 'type' in variables.keys(): nc.type = variables['type'] # Create dimensions -------------------------------------------------------- if verbose: print(" Creating Dimensions ...") # Horizontal dimensions nc.createDimension('xi_psi',np.size(variables['x_rho'],1)-1) nc.createDimension('xi_rho',np.size(variables['x_rho'],1)) nc.createDimension('xi_u',np.size(variables['x_rho'],1)-1) nc.createDimension('xi_v',np.size(variables['x_rho'],1)) nc.createDimension('eta_psi',np.size(variables['x_rho'],0)-1) nc.createDimension('eta_rho',np.size(variables['x_rho'],0)) nc.createDimension('eta_u',np.size(variables['x_rho'],0)) nc.createDimension('eta_v',np.size(variables['x_rho'],0)-1) # Vertical dimensions if 's_rho' in variables.keys(): nc.createDimension('s_rho',variables['s_rho'].size) nc.createDimension('s_w',variables['s_w'].size) # Time dimension and variable (unlimited,netCDF4 supports multiple) if timeinfo: if verbose: print(' Writing Time Variables:') for aa in timeinfo.keys(): if verbose: print(' ' + aa) # Create dimension nc.createDimension(aa,0) nc.createVariable(aa,'f8',(aa)) # Write variable information for bb in timeinfo[aa].keys(): if bb == 'data': nc.variables[aa][:] = timeinfo[aa]['data'] else: nc.variables[aa].__setattr__(bb,timeinfo[aa][bb]) # Write other variables if verbose: print(' Writing variables:') # Loading dimensions dimInfo = gridDims() for aa in variables.keys(): # Determine dimensions try: tmpdims = dimInfo[varinfodict[aa]['dimensions']] if varinfodict[aa]['dimensions'] == 'nulvar': tmpdims = tmpdims[aa] except: continue if verbose: print(' ' + aa) if 'time' in varinfodict[aa].keys(): tmpdims = (varinfodict[aa]['time'],) + tmpdims # Create Variable nc.createVariable(aa,'f8',tmpdims) # Write attributes for bb in varinfodict[aa].keys(): if bb == 'dimensions' or bb == 'id': continue nc.variables[aa].__setattr__(bb,varinfodict[aa][bb]) # Write data nc.variables[aa][:] = variables[aa] # Close netcdf file nc.close() if verbose: print('Done')
def write_wind_nc(outfld,timeVec,lon,lat,uwnd,vwnd,temp=False): ''' Function to generate bathymetry files to be used as input for WW3 v4.18 PARAMETERS: ----------- outfld : folder to write the files to timeVec : Time vector (datetime array) lon : longitudes (or x for cartesian) at every grid point (I assume they have been meshgridded) lat : latitudes (or y for cartesian) at every grid point uwnd : zonal component of wind [m/s] vwnd : meridional component of wind [m/s] temp : (optional) Air-sea temperature differences [C] OUTPUT: ------- ww3_wind.nc : NetCDF file containing the grid information NOTES: ------ I assume that if the grid is in spherical coordiantes the latitude and longitudes are given in decimal degrees (east). On the other hand if the grid is cartesian I assume meters. ''' spherical = True # Placeholder for future expansion to cartesian # Convert longitudes to degrees east lon = _gangles.wrapto360(lon) # Write netcdf file -------------------------------------------------------- # Global attributes nc = _netCDF4.Dataset(outfld + '/ww3_wind.nc', 'w', format='NETCDF4') nc.Description = 'Wavewatch III Wind Input' nc.Author = _getpass.getuser() nc.Created = _time.ctime() nc.Software = 'Created with Python ' + _sys.version nc.NetCDF_Lib = str(_netCDF4.getlibversion()) nc.Script = _os.path.realpath(__file__) # Create dimensions nc.createDimension('longitude', lon.shape[1]) nc.createDimension('latitude',lon.shape[0]) nc.createDimension('time',0) # Write coordinates and depth to netcdf file if spherical: nc.createVariable('latitude','f8',('latitude','longitude')) nc.variables['latitude'].units = 'degree_north' nc.variables['latitude'].long_name = 'latitude of RHO-points' nc.variables['latitude'][:] = lat else: nc.createVariable('y_rho','f8',('eta_rho','xi_rho')) nc.variables['y_rho'].units = 'meter' nc.variables['y_rho'].long_name = 'y location of RHO-points' nc.variables['y_rho'][:] = lat # Write longitude if spherical: nc.createVariable('longitude','f8',('latitude','longitude')) nc.variables['longitude'].units = 'degree_east' nc.variables['longitude'].long_name = 'latitude of RHO-points' nc.variables['longitude'][:] = lon else: nc.createVariable('x_rho','f8',('eta_rho','xi_rho')) nc.variables['x_rho'].units = 'meter' nc.variables['x_rho'].long_name = 'x location of RHO-points' nc.variables['x_rho'][:] = lon # Time vector nc.createVariable('time','f8',('time')) nc.variables['time'].units = 'seconds since 1900-01-01 00:00:00' nc.variables['time'].conventions = 'relative julian seconds' baseTime = _datetime.datetime(1900,1,1) timeVec = _np.array([(aa - baseTime).total_seconds() for aa in timeVec]) nc.variables['time'][:] = timeVec # Write wind components nc.createVariable('UWND','f8',('time','latitude','longitude')) nc.variables['UWND'].units = 'meter second-1' nc.variables['UWND'].long_name = 'Zonal component of wind' nc.variables['UWND'][:] = uwnd nc.createVariable('VWND','f8',('time','latitude','longitude')) nc.variables['VWND'].units = 'meter second-1' nc.variables['VWND'].long_name = 'Meridional component of wind' nc.variables['VWND'][:] = vwnd if temp: nc.createVariable('temp','f8',('time','latitude','longitude')) nc.variables['temp'].units = 'degrees C' nc.variables['temp'].long_name = 'Air-sea temperature differences' nc.variables['temp'][:] = temp # Close NetCDF file nc.close()
def write_bathy(x,h,path,y=None,ncsave=True,dt=None): ''' Parameters: ---------- x : array of x coordinates y : array of x coordinates (optional) h : Bathymetry path : Full path where the output will be saved ncsave : Save bathy as NetCDF file dt : (Optional) informs about the stability for a chosen dt Output: ------- depth.txt : Text file with the depth information for Funwave input. depth.nc : (Optional) NetCDF4 bathymetry file. Notes: ------ 1. Variables are assumed to be on a regularly spaced grid. 2. If y is passed then 2D bathymetry is assumed. This means that x,y,h have to be 2D arrays. Otherwise the code will fail. ''' # Output the text file ----------------------------------------------------- fid = open(path + 'depth.txt','w') if y is None: for aa in range(len(h)): fid.write('%12.3f\n' % h[aa]) fid.close() else: for aa in range(h.shape[1]): for bb in range(h.shape[0]): fid.write('%12.3f' % h[bb,aa]) fid.write('\n') fid.close() if ncsave: # Global attributes nc = netCDF4.Dataset(path + 'depth.nc', 'w', format='NETCDF4') nc.Description = 'Funwave Bathymetry' nc.Author = getpass.getuser() nc.Created = time.ctime() nc.Owner = 'Nearshore Modeling Group (http://ozkan.oce.orst.edu/nmg)' nc.Software = 'Created with Python ' + sys.version nc.NetCDF_Lib = str(netCDF4.getlibversion()) nc.Script = os.path.realpath(__file__) # Create dimensions if y is None: xi_rho = len(h) nc.createDimension('xi_rho', xi_rho) varShape = ('xi_rho') else: eta_rho,xi_rho = np.shape(h) nc.createDimension('xi_rho', xi_rho) nc.createDimension('eta_rho',eta_rho) varShape = ('eta_rho','xi_rho') # Write y variable create_nc_var(nc, 'y_rho',varShape, 'meter','y-locations of RHO-points') nc.variables['y_rho'][:] = y # Write coordinates and depth to netcdf file create_nc_var(nc, 'x_rho',varShape, 'meter','x-locations of RHO-points') nc.variables['x_rho'][:] = x create_nc_var(nc,'h',varShape, 'meter','bathymetry at RHO-points') nc.variables['h'][:] = h # Close NetCDF file nc.close() else: print("NetCDF file not requested") #=========================================================================== # Print input file options #=========================================================================== print(' ') print('===================================================================') print('In your funwaveC init file:') if y is None: dx = np.abs(x[1] - x[0]) print('dimension ' + np.str(len(x)+1) + ' 6 ' + np.str(dx) + ' 1') else: dx = np.abs(x[0,1] - x[0,0]) # For later use dy = np.abs(y[1,0] - y[0,0]) print('dimension ' + np.str(x.shape[1]+1) + ' ' + np.str(x.shape[0]) + ' ' + np.str(dx) + ' ' + np.str(dy)) print('===================================================================') print(' ') # Stability options stabilityCriteria(dx,h.max(),dt=dt,verbose=True)
def convert_output(workfld,outfile,time_int=1.0,bathyfile=None, inpfile=None,verbose=False): ''' Parameters: ----------- workfld : Path to the folder where output files reside outfile : Output NetCDF file time_int : Time interval between output files [s] (will be updated if input file is provided) bathyfile : Full path to input netcdf bathy file (optional) inpfile : Funwave input file used for metadata (optional) verbose : Defaults to False Output: ------- NetCDF File with the variables in the folder. Not all are supported so you may need to edit this file. ''' # For testing only #workfld = '/scratch/temp/ggarcia/funwaveC_ensemble/r0/' #outfile = '/scratch/temp/ggarcia/funwaveC_ensemble/02-runs/tmp.nc' #time_int = 0.5 #bathyfile = '/scratch/temp/ggarcia/funwaveC_ensemble/r0/depth.nc' #inpfile = '/scratch/temp/ggarcia/funwaveC_ensemble/r0/input.init' # Get variable information ------------------------------------------------ # Need to generalize archivos = glob.glob(workfld + '*.dat') # All files tmpvars = [x.split('/')[-1].split('.')[0] for x in archivos] # All vars # If no variables found exit if not tmpvars: print('No files found in ' + workfld) print('Quitting ...') return None # Make sure variables are within the supported ones supported_vars_time = ['eta','u'] vars_2d = [x for x in tmpvars if x in supported_vars_time] # Read input file if provided ---------------------------------------------- if inpfile: if verbose: print("Reading data from input file:") print(" " + inpfile) # Open file tmpinpfile = open(inpfile,'r') # Output dictionary inpinfo = {} # funwaveC is very structured so this is a simple way of reading # Dynamics line tmpLine = tmpinpfile.readline().rstrip() inpinfo['dynamics'] = tmpLine.split(' ')[-1] # Dimensions tmpLine = tmpinpfile.readline().rstrip() dx = np.float64(tmpLine.split(' ')[3]) dy = np.float64(tmpLine.split(' ')[4]) # Bottom stress tmpLine = tmpinpfile.readline().rstrip() inpinfo['bottomstress'] = tmpLine.split(' ')[2] # Mixing tmpLine = tmpinpfile.readline().rstrip() inpinfo['mixing'] = tmpLine.split(' ')[1] + ' ' + tmpLine.split(' ')[2] # Bathymetry tmpinpfile.readline() # Tide tmpinpfile.readline() # Wavemaker tmpLine = tmpinpfile.readline().rstrip() inpinfo['eta_source'] = tmpLine[14:] # Wave breaking tmpLine = tmpinpfile.readline().rstrip() inpinfo['breaking'] = tmpLine[9:] # Sponge layer tmpLine = tmpinpfile.readline().rstrip() inpinfo['sponge'] = tmpLine[7:] # Forcing, initial conditions, tracers tmpinpfile.readline() tmpinpfile.readline() tmpinpfile.readline() tmpinpfile.readline() tmpinpfile.readline() tmpinpfile.readline() # Timing tmpLine = tmpinpfile.readline().rstrip() inpinfo['timing'] = tmpLine[7:] time_int = np.float64(tmpLine.split(' ')[5]) # Close me tmpinpfile.close() else: # Assume grid spacing to be 1 meter if verbose: print("Input file not provided") dx = 1.0 dy = 1.0 inpinfo = False # Coordinates and depth --------------------------------------------------- # Bathymetry file provided if bathyfile: if verbose: print("Reading coordinates and depth from:") print(" " + bathyfile) ncfile = netCDF4.Dataset(bathyfile,'r') x_rho = ncfile.variables['x_rho'][:] if ncfile.variables.has_key('y_rho'): y_rho = ncfile.variables['y_rho'][:] else: y_rho = None h = ncfile.variables['h'][:] ncfile.close() # Create u grid x_u = np.zeros((x_rho.shape[0]+1,)) x_u[0] = x_rho[0] - dx/2 x_u[-1] = x_rho[-1] + dx/2 x_u[1:-1] = (x_rho[1:] + x_rho[:-1])/2.0 # Bathymetry file not provided but have output file elif os.path.isfile(workfld + '/depth.txt'): # Fix this h = np.loadtxt(workfld + '/depth.txt') hdims = h.ndim if hdims == 1: x_rho = np.arange(1,h.shape[0]+dx,dx) # Create u grid x_u = np.zeros((x_rho.shape[0]+1,)) x_u[0] = x_rho[0] - dx/2 x_u[-1] = x_rho[-1] + dx/2 x_u[1:-1] = (x_rho[1:] + x_rho[:-1])/2.0 elif hdims == 2: x_rho, y_rho = np.meshgrid(np.arange(0,h.shape[1],dx), np.arange(0,h.shape[0],dy)) else: if verbose: print('Something is wrong with the depth file') # No bathymetry file provided else: if verbose: print("No bathymetry file provided") # Get dimensions of variables hdims = h.ndim # Create NetCDF file ------------------------------------------------------- if verbose: print("Creating " + outfile) # Global attributes nc = netCDF4.Dataset(outfile, 'w', format='NETCDF4') nc.Description = 'FunwaveC Output' nc.Author = '*****@*****.**' nc.Created = time.ctime() nc.Type = 'FunwaveC snapshot output' nc.Owner = 'Nearshore Modeling Group' nc.Software = 'Created with Python ' + sys.version nc.NetCDF_Lib = str(netCDF4.getlibversion()) nc.Source = workfld nc.Script = os.path.realpath(__file__) # Add more global variables to output if inpinfo: for tmpatt in inpinfo.keys(): nc.__setattr__(tmpatt,inpinfo[tmpatt][:]) # Create dimensions if hdims == 2: eta_rho, xi_rho = h.shape nc.createDimension('eta_rho', eta_rho) else: xi_rho = h.shape[0] xi_u = xi_rho + 1 eta_rho = 1 nc.createDimension('xi_rho', xi_rho) nc.createDimension('xi_u',xi_u) nc.createDimension('ocean_time',0) # Write coordinate axes ---------------------------------------------- if hdims == 2: nc.createVariable('x_rho','f8',('eta_rho','xi_rho')) nc.variables['x_rho'].units = 'meter' nc.variables['x_rho'].longname = 'x-locations of RHO points' nc.variables['x_rho'][:] = x_rho nc.createVariable('y_rho','f8',('eta_rho','xi_rho')) nc.variables['y_rho'].units = 'meter' nc.variables['y_rho'].longname = 'y-locations of RHO points' nc.variables['y_rho'][:] = y_rho nc.createVariable('h','f8',('eta_rho','xi_rho')) nc.variables['h'].units = 'meter' nc.variables['h'].longname = 'bathymetry at RHO points' nc.variables['h'][:] = h else: nc.createVariable('x_rho','f8',('xi_rho')) nc.variables['x_rho'].units = 'meter' nc.variables['x_rho'].longname = 'x-locations of RHO points' nc.variables['x_rho'][:] = x_rho nc.createVariable('h','f8',('xi_rho')) nc.variables['h'].units = 'meter' nc.variables['h'].longname = 'bathymetry at RHO points' nc.variables['h'][:] = h nc.createVariable('x_u','f8',('xi_u')) nc.variables['x_u'].units = 'meter' nc.variables['x_u'].longname = 'x-locations of U points' nc.variables['x_u'][:] = x_u # Create time vector ------------------------------------------------------- tmpvar = np.loadtxt(workfld + vars_2d[0] + '.dat') twave = np.arange(time_int,time_int*tmpvar.shape[0]+time_int,time_int) nc.createVariable('ocean_time','f8','ocean_time') nc.variables['ocean_time'].units = 'seconds since 2000-01-01 00:00:00' nc.variables['ocean_time'].calendar = 'julian' nc.variables['ocean_time'].long_name = 'beach time' nc.variables['ocean_time'][:] = twave # Create variables -------------------------------------------------------- # Variable information varinfo = defaultdict(dict) varinfo['eta']['units'] = 'meter' varinfo['eta']['longname'] = 'water surface elevation' varinfo['eta']['dims'] = ('ocean_time','xi_rho') varinfo['u']['units'] = 'meter second-1' varinfo['u']['longname'] = 'Flow velocity in the xi direction' varinfo['u']['dims'] = ('ocean_time','xi_u') varinfo['v']['units'] = 'meter second-1' varinfo['v']['longname'] = 'Flow velocity in the eta direction' varinfo['v']['dims'] = ('ocean_time','xi_v') if verbose: print("Creating variables") for aa in vars_2d: if verbose: print(' ' + aa) # Load variable try: tmpvar = np.loadtxt(workfld + '/' + aa + '.dat') except: if verbose: print(" Could not create " + aa) print(" Input file error") continue # Create variable create_nc_var(nc,aa,varinfo[aa]['dims'],varinfo[aa]['units'], varinfo[aa]['longname']) # Write variable nc.variables[aa][:] = tmpvar # Close NetCDF file if verbose: print('Closing ' + outfile) nc.close()