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 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 spec_bulk_params(freq, dirs, spec, IGBand=[0.005, 0.05], zeroth=True): """ Function to compute bulk wave parameters from frequency-direction spectrum Parameters: ----------- freq : Vector of spectral frequencies [Hz] dirs : Vector of directions (nautical convention) [Deg or Rad] spec : Wave spectrum [m2/Hz/Deg or m2/Hz/Deg] The shape must be [freq,dirs] IGBand : Infragravity wave frequency cutoff defaults to 0.005-0.05 Hz zeroth : If true will remove the first frequency from the analysis Returns: -------- Dictionary containing bulk wave parameters Hs : Significant wave height [m] H1 : Mean wave height [m] Tp : Peak wave period [s] Tp_fit : Peak wave period computed from second order polynomial fit near Tp[s] Tm01 : First moment wave period [s] Tm02 : Second moment wave period [s] Te : Energy period [s] Sw : Spectral width (m0*m2/m1/m1 - 1)**2 Tm01IG : First moment wave period over the infragravity frequency band TpIG : Peak wave period over the infragravity frequency band [s] HsIG : Significant wave height in the infragravity frequency band [m] Dm : Mean wave direction, second moment (Kuik et al. 1988) Dp : Peak wave direction (computed from directional spectrum) Notes: ------ - mn are the different spectral moments - First frequency will be discarded from the analysis. It is assumed to be the zeroth-frequency. REFERENCES: ----------- Kuik, A.J., G.P. Van Vledder, and L.H. Holthuijsen, 1988: A method for the routine analysis of pitch-and-roll buoy wave data. Journal of Physical Oceanography, 18(7), pp.1020-1034. """ # Get directional properties dirSpec = np.trapz(spec, freq, axis=0) # Find peak wave directon Dp = np.argmax(dirSpec) Dp = dirs[Dp] dirDict = dict(Dp=Dp) # Find mean wave direction (Kuik et al 1988) a1 = np.trapz(dirSpec * np.cos((270.0 - dirs) * np.pi / 180), dirs) b1 = np.trapz(dirSpec * np.sin((270.0 - dirs) * np.pi / 180), dirs) # Mean wave direction in nautical coordinates Dm = _gangles.wrapto360(270.0 - np.arctan2(b1, a1) * 180.0 / np.pi) dirDict.update(Dm=Dm) # Get the parameter from the frequency spectrum #freqSpec = np.trapz(spec,dirs,axis=-1) dth = np.abs(dirs[2] - dirs[1]) freqSpec = np.sum(spec, axis=-1) * dth bp = fspec_bulk_params(freq, freqSpec, IGBand, zeroth=zeroth) bp.update(dirDict) return bp
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()