From b79e26467e4525ac1a643a880c867635cf1fc43a Mon Sep 17 00:00:00 2001 From: thopri <thopri@144-148.noc.soton.ac.uk> Date: Mon, 16 Mar 2020 13:49:27 +0000 Subject: [PATCH] added bathy and mask generation tools and got running with orthoganal test grid --- pynemo/nemo_bdy_extr_tm3.py | 2 +- pynemo/reader/ncml.py | 2 +- unit_tests/gen_tools.py | 210 ++++++++++++++++++++++------ unit_tests/namelist_unit_test.bdy | 10 +- unit_tests/src_data_unit_tests.ncml | 6 - unit_tests/test_gen.py | 24 ++-- 6 files changed, 192 insertions(+), 62 deletions(-) diff --git a/pynemo/nemo_bdy_extr_tm3.py b/pynemo/nemo_bdy_extr_tm3.py index 9c457b7..4d7c745 100644 --- a/pynemo/nemo_bdy_extr_tm3.py +++ b/pynemo/nemo_bdy_extr_tm3.py @@ -831,7 +831,7 @@ class Extract: del_t = time_counter[1] - time_counter[0] dstep = 86400 / np.int(del_t) - + dstep = int(dstep) # TODO: put in a test to check all deltaT are the same otherwise throw # an exception diff --git a/pynemo/reader/ncml.py b/pynemo/reader/ncml.py index 6a7b323..aba198d 100644 --- a/pynemo/reader/ncml.py +++ b/pynemo/reader/ncml.py @@ -280,7 +280,7 @@ class Variable(object): attr = dvar.findAttributeIgnoreCase(attr_name) if attr is not None: retval = attr.getValue(0) - return retval + return retval except KeyError: self.logger.error('Cannot find the requested variable '+self.variable) return None diff --git a/unit_tests/gen_tools.py b/unit_tests/gen_tools.py index 80e1abe..38ba686 100644 --- a/unit_tests/gen_tools.py +++ b/unit_tests/gen_tools.py @@ -2,20 +2,17 @@ """ Created on Wed Mar 11 11:16:57 2020 -example grid set up +unit test grid generation tools -@author: jdha -""" +@author: thopri and jdha (for example code) -import numpy as np +""" from netCDF4 import Dataset from math import cos,sin,radians import numpy as np -#import xarray as xr import matplotlib.pyplot as plt from math import radians -#import cartopy -#import cartopy.crs as ccrs + def set_hgrid(dx, dy, jpi, jpj, zoffx=0, zoffy=0,sf=1): if sf > 1: @@ -79,6 +76,8 @@ def set_zgrid(grid_h,jpk,max_dep,min_dep,z_dim): dept_1d = np.linspace(min_dep,max_dep,jpk) e3t_1d = np.linspace(1.0,z_dim,jpk) e3w_1d = np.linspace(1.0,z_dim,jpk) + gdept_0 = np.linspace(min_dep,max_dep,jpk) + gdepw_0 = np.linspace(min_dep,max_dep,jpk) e3t = np.zeros((jpi, jpj, len(e3t_1d))) e3u = np.zeros((jpi, jpj, len(e3t_1d))) @@ -87,6 +86,8 @@ def set_zgrid(grid_h,jpk,max_dep,min_dep,z_dim): e3f = np.zeros((jpi, jpj, len(e3t_1d))) e3uw = np.zeros((jpi, jpj, len(e3t_1d))) e3vw = np.zeros((jpi, jpj, len(e3t_1d))) + gdept = np.zeros((jpi,jpj,len(gdept_0))) + gdepw = np.zeros((jpi,jpj,len(gdepw_0))) e3t[:] = e3t_1d e3u[:] = e3t_1d @@ -95,9 +96,11 @@ def set_zgrid(grid_h,jpk,max_dep,min_dep,z_dim): e3f[:] = e3t_1d e3uw[:] = e3t_1d e3vw[:] = e3t_1d + gdept[:] = gdept_0 + gdepw[:] = gdepw_0 grid_z = {'dept_1d':dept_1d,'e3t_1d':e3t_1d,'e3w_1d':e3w_1d,'e3t':e3t,'e3u':e3u,'e3v':e3v,'e3w':e3w,'e3f':e3f, \ - 'e3uw':e3uw,'e3vw':e3vw} + 'e3uw':e3uw,'e3vw':e3vw,'gdept_0':gdept_0,'gdept':gdept,'gdepw_0':gdepw_0,'gdepw':gdepw} return grid_z @@ -121,33 +124,37 @@ def write_coord_H(fileout, grid_h): # Get input size and create appropriate dimensions # TODO: add some sort of error handling nx, ny = np.shape(grid_h['lont']) + nt = 1 dataset.createDimension('x', nx) dataset.createDimension('y', ny) + dataset.createDimension('t', nt) # Create Variables nav_lon = dataset.createVariable('nav_lon', np.float32, ('y', 'x')) nav_lat = dataset.createVariable('nav_lat', np.float32, ('y', 'x')) - - glamt = dataset.createVariable('glamt', np.float64, ('y', 'x')) - glamu = dataset.createVariable('glamu', np.float64, ('y', 'x')) - glamv = dataset.createVariable('glamv', np.float64, ('y', 'x')) - glamf = dataset.createVariable('glamf', np.float64, ('y', 'x')) - gphit = dataset.createVariable('gphit', np.float64, ('y', 'x')) - gphiu = dataset.createVariable('gphiu', np.float64, ('y', 'x')) - gphiv = dataset.createVariable('gphiv', np.float64, ('y', 'x')) - gphif = dataset.createVariable('gphif', np.float64, ('y', 'x')) - - ge1t = dataset.createVariable('e1t', np.float64, ('y', 'x')) - ge1u = dataset.createVariable('e1u', np.float64, ('y', 'x')) - ge1v = dataset.createVariable('e1v', np.float64, ('y', 'x')) - ge1f = dataset.createVariable('e1f', np.float64, ('y', 'x')) - ge2t = dataset.createVariable('e2t', np.float64, ('y', 'x')) - ge2u = dataset.createVariable('e2u', np.float64, ('y', 'x')) - ge2v = dataset.createVariable('e2v', np.float64, ('y', 'x')) - ge2f = dataset.createVariable('e2f', np.float64, ('y', 'x')) + time_counter = dataset.createVariable('time_counter',np.float32,('t')) + + glamt = dataset.createVariable('glamt', np.float64, ('t','y', 'x')) + glamu = dataset.createVariable('glamu', np.float64, ('t','y', 'x')) + glamv = dataset.createVariable('glamv', np.float64, ('t','y', 'x')) + glamf = dataset.createVariable('glamf', np.float64, ('t','y', 'x')) + gphit = dataset.createVariable('gphit', np.float64, ('t','y', 'x')) + gphiu = dataset.createVariable('gphiu', np.float64, ('t','y', 'x')) + gphiv = dataset.createVariable('gphiv', np.float64, ('t','y', 'x')) + gphif = dataset.createVariable('gphif', np.float64, ('t','y', 'x')) + + ge1t = dataset.createVariable('e1t', np.float64, ('t','y', 'x')) + ge1u = dataset.createVariable('e1u', np.float64, ('t','y', 'x')) + ge1v = dataset.createVariable('e1v', np.float64, ('t','y', 'x')) + ge1f = dataset.createVariable('e1f', np.float64, ('t','y', 'x')) + ge2t = dataset.createVariable('e2t', np.float64, ('t','y', 'x')) + ge2u = dataset.createVariable('e2u', np.float64, ('t','y', 'x')) + ge2v = dataset.createVariable('e2v', np.float64, ('t','y', 'x')) + ge2f = dataset.createVariable('e2f', np.float64, ('t','y', 'x')) nav_lon.units, nav_lon.long_name = 'km', 'X' nav_lat.units, nav_lat.long_name = 'km', 'Y' + time_counter.units, time_counter.long_name = 'seconds','time_counter' # Populate file with input data # TODO: do we need to transpose? @@ -192,29 +199,38 @@ def write_coord_Z(fileout, grid_h,grid_z): # Get input size and create appropriate dimensions # TODO: add some sort of error handling nx, ny, nz = np.shape(grid_z['e3t']) + nt = 1 dataset.createDimension('x', nx) dataset.createDimension('y', ny) dataset.createDimension('z', nz) + dataset.createDimension('t', nt) # Create Variables nav_lon = dataset.createVariable('nav_lon', np.float32, ('y', 'x')) nav_lat = dataset.createVariable('nav_lat', np.float32, ('y', 'x')) nav_lev = dataset.createVariable('nav_lev', np.float32, 'z') - - ge3t1d = dataset.createVariable('e3t_1d', np.float64, 'z') - ge3w1d = dataset.createVariable('e3w_1d', np.float64, 'z') - gbat = dataset.createVariable('mbathy', np.float64, ('y', 'x')) - ge3t = dataset.createVariable('e3t', np.float64, ('z','y', 'x')) - ge3u = dataset.createVariable('e3u', np.float64, ('z','y', 'x')) - ge3v = dataset.createVariable('e3v', np.float64, ('z','y', 'x')) - ge3f = dataset.createVariable('e3f', np.float64, ('z','y', 'x')) - ge3uw = dataset.createVariable('e3uw', np.float64, ('z', 'y', 'x')) - ge3vw = dataset.createVariable('e3vw', np.float64, ('z', 'y', 'x')) + time_counter = dataset.createVariable('time_counter', np.float32, ('t')) + + ge3t1d = dataset.createVariable('e3t_0', np.float64, ('t','z')) + ge3w1d = dataset.createVariable('e3w_0', np.float64, ('t','z')) + gdept_0 = dataset.createVariable('gdept_0', np.float64, ('t','z')) + gdepw_0 = dataset.createVariable('gdepw_0', np.float64, ('t','z')) + gbat = dataset.createVariable('mbathy', np.float64, ('t','y', 'x')) + ge3t = dataset.createVariable('e3t', np.float64, ('t','z','y', 'x')) + ge3u = dataset.createVariable('e3u', np.float64, ('t','z','y', 'x')) + ge3v = dataset.createVariable('e3v', np.float64, ('t','z','y', 'x')) + ge3w = dataset.createVariable('e3w', np.float64, ('t', 'z', 'y', 'x')) + ge3f = dataset.createVariable('e3f', np.float64, ('t','z','y', 'x')) + ge3uw = dataset.createVariable('e3uw', np.float64, ('t','z', 'y', 'x')) + ge3vw = dataset.createVariable('e3vw', np.float64, ('t','z', 'y', 'x')) + gdept = dataset.createVariable('gdept', np.float64, ('t','z', 'y', 'x')) + gdepw = dataset.createVariable('gdepw', np.float64, ('t','z', 'y', 'x')) nav_lon.units, nav_lon.long_name = 'km', 'X' nav_lat.units, nav_lat.long_name = 'km', 'Y' nav_lev.units, nav_lev.long_name = 'm', 'Z' + time_counter.units, time_counter.long_name = 'seconds', 'time_counter' # Populate file with input data # TODO: do we need to transpose? @@ -226,12 +242,17 @@ def write_coord_Z(fileout, grid_h,grid_z): ge3u[:, :, :] = grid_z['e3u'].T ge3v[:, :, :] = grid_z['e3v'].T ge3f[:, :, :] = grid_z['e3f'].T + ge3w[:, :, :] = grid_z['e3w'].T ge3uw[:, :, :] = grid_z['e3uw'].T ge3vw[:, :, :] = grid_z['e3vw'].T ge3t1d[:] = grid_z['e3t_1d'] ge3w1d[:] = grid_z['e3w_1d'] gbat[:,:] = grid_h['batt'].T + gdept[:,:,:] = grid_z['gdept'].T + gdept_0[:] = grid_z['gdept_0'] + gdepw[:,:,:] = grid_z['gdepw'].T + gdepw_0[:] = grid_z['gdepw_0'] # Close off pointer @@ -446,11 +467,73 @@ def plot_grids(lat_in,lon_in,new_lat,new_lon,off_lat,off_lon,src_lat,src_lon): ax1.plot(src_lon,src_lat, color='green',marker='o',linestyle="") ax2.plot(off_lon,off_lat, color='yellow',marker='.',linestyle="") ax2.plot(src_lon, src_lat, color='green', marker='o', linestyle="") - # tweak margins of subplots as tight layout doesn't work + # tweak margins of subplots as tight layout doesn't work for some reason? plt.subplots_adjust(left=0.01, right=1, top=0.9, bottom=0.05,wspace=0.01) plt.show() +def write_mask(fileout,grid_h,grid_z): + ''' + Writes out a + + Args: + + Returns: + ''' + # Open pointer to netcdf file + dataset = Dataset(fileout, 'w', format='NETCDF4_CLASSIC') + + # Get input size and create appropriate dimensions + # TODO: add some sort of error handling + nt = 1 + nx, ny, nz = np.shape(grid_z['e3t']) + dataset.createDimension('x', nx) + dataset.createDimension('y', ny) + dataset.createDimension('z', nz) + dataset.createDimension('t', nt) + # Create Variables + nav_lon = dataset.createVariable('nav_lon', np.float32, ('y', 'x')) + nav_lat = dataset.createVariable('nav_lat', np.float32, ('y', 'x')) + nav_lev = dataset.createVariable('nav_lev', np.float32, 'z') + time_counter = dataset.createVariable('time_counter', np.float32, ('t')) + + fmaskutil = dataset.createVariable('fmaskutil', np.float64, ('t','y', 'x')) + tmaskutil = dataset.createVariable('tmaskutil', np.float64, ('t','y', 'x')) + umaskutil = dataset.createVariable('umaskutil', np.float64, ('t','y', 'x')) + vmaskutil = dataset.createVariable('vmaskutil', np.float64, ('t','y', 'x')) + + fmask = dataset.createVariable('fmask', np.float64, ('t','z','y', 'x')) + tmask = dataset.createVariable('tmask', np.float64, ('t','z','y', 'x')) + umask = dataset.createVariable('umask', np.float64, ('t','z','y', 'x')) + vmask = dataset.createVariable('vmask', np.float64, ('t','z','y', 'x')) + + nav_lon.units, nav_lon.long_name = 'km', 'X' + nav_lat.units, nav_lat.long_name = 'km', 'Y' + nav_lev.units, nav_lev.long_name = 'm', 'Z' + time_counter.units, time_counter.long_name = 'seconds', 'time_counter' + + # Populate file with input data + # TODO: do we need to transpose? + nav_lon[:, :] = grid_h['lont'].T + nav_lat[:, :] = grid_h['latt'].T + nav_lev[:] = grid_z['dept_1d'] + + threeD_mask = np.zeros(np.shape(grid_z['e3t'])) + twoD_mask = np.zeros(np.shape(grid_h['e1t'])) + + fmask[:,:,:] = threeD_mask.T + fmaskutil[:,:] = twoD_mask.T + tmask[:,:,:] = threeD_mask.T + tmaskutil[:,:] = twoD_mask.T + umask[:,:,:] = threeD_mask.T + umaskutil[:,:] = twoD_mask.T + vmask[:,:,:] = threeD_mask.T + vmaskutil[:,:] = twoD_mask.T + + dataset.close() + + return 0 + def write_parameter(fileout, grid_h,grid_z,params): ''' Writes out a @@ -460,31 +543,41 @@ def write_parameter(fileout, grid_h,grid_z,params): Returns: ''' - #TODO: implement multiple parameters using dicts. + #TODO: implement multiple parameters using params dict. # Open pointer to netcdf file dataset = Dataset(fileout, 'w', format='NETCDF4_CLASSIC') # Get input size and create appropriate dimensions # TODO: add some sort of error handling + nt = 2 nx, ny, nz = np.shape(grid_z['e3t']) dataset.createDimension('x', nx) dataset.createDimension('y', ny) dataset.createDimension('z', nz) + dataset.createDimension('time', nt) + # Create Variables longitude = dataset.createVariable('longitude', np.float32, ('y', 'x')) latitude = dataset.createVariable('latitude', np.float32, ('y', 'x')) depth = dataset.createVariable('depth', np.float32, 'z') + time_counter = dataset.createVariable('time', np.float32, ('time')) longitude.units, longitude.long_name = 'km', 'X' latitude.units, latitude.long_name = 'km', 'Y' depth.units, depth.long_name = 'm', 'Z' + time_counter.units = 'hours since 1950-01-01 00:00:00' + time_counter.long_name = 'Time (hours since 1950-01-01)' + time_counter.axis = 'T' + time_counter._CoordinateAxisType = "Time" + time_counter.calendar = 'gregorian' + time_counter.standard_name = 'time' # Populate file with input data longitude[:, :] = grid_h['lont'].T latitude[:, :] = grid_h['latt'].T depth[:] = grid_z['dept_1d'] - - parameter = dataset.createVariable(str(params['name']), np.float64, ('z', 'y', 'x')) + time_counter[:] = (587340.00,588060.00) + parameter = dataset.createVariable(str(params['name']), np.float64, ('time','z', 'y', 'x')) parameter.units, parameter.long_name = str(params['units']), str(params['longname']) value_fill = np.ones(np.shape(grid_z['e3t'])) value_fill = value_fill*params['const_value'] @@ -492,5 +585,42 @@ def write_parameter(fileout, grid_h,grid_z,params): # Close off pointer dataset.close() + return 0 + +def write_bathy(fileout, grid_h,grid_z): + ''' + Writes out a + + Args: + Returns: + ''' + # Open pointer to netcdf file + dataset = Dataset(fileout, 'w', format='NETCDF4_CLASSIC') + + # Get input size and create appropriate dimensions + # TODO: add some sort of error handling + nx, ny = np.shape(grid_h['e1t']) + dataset.createDimension('x', nx) + dataset.createDimension('y', ny) + + + # Create Variables + nav_lon = dataset.createVariable('nav_lon', np.float32, ('y', 'x')) + + nav_lat = dataset.createVariable('nav_lat', np.float32, ('y', 'x')) + nav_lon.units, nav_lon.long_name = 'km', 'X' + nav_lat.units, nav_lat.long_name = 'km', 'Y' + + Bathymetry = dataset.createVariable('Bathymetry', np.float64,('y','x')) + Bathymetry.units,Bathymetry.long_name = 'meters','Median depth by area' + nav_lon[:, :] = grid_h['lont'].T + nav_lat[:, :] = grid_h['latt'].T + + Bathy = np.ones((nx,ny)) + Bathy = Bathy * grid_z['dept_1d'][-1] + + Bathymetry[:,:] = Bathy + + dataset.close() return 0 \ No newline at end of file diff --git a/unit_tests/namelist_unit_test.bdy b/unit_tests/namelist_unit_test.bdy index b536895..68539ce 100644 --- a/unit_tests/namelist_unit_test.bdy +++ b/unit_tests/namelist_unit_test.bdy @@ -30,11 +30,11 @@ !------------------------------------------------------------------------------ ! grid information !------------------------------------------------------------------------------ - sn_src_hgr = '/Users/thopri/Projects/PyNEMO/unit_tests/test_data/src_coordinates.nc' - sn_src_zgr = '/Users/thopri/Projects/PyNEMO/unit_tests/test_data/src_coordinates.nc' - sn_dst_hgr = '/Users/thopri/Projects/PyNEMO/unit_tests/test_data/dst_hgr_zps.nc' - sn_dst_zgr = '/Users/thopri/Projects/PyNEMO/unit_tests/test_data/dst_zgr_zps.nc' - sn_src_msk = '/Users/thopri/Projects/PyNEMO/unit_tests/test_data/src_bathy.nc' + sn_src_hgr = '/Users/thopri/Projects/PyNEMO/unit_tests/test_data/test_src_hgr_zps.nc' + sn_src_zgr = '/Users/thopri/Projects/PyNEMO/unit_tests/test_data/test_src_zgr_zps.nc' + sn_dst_hgr = '/Users/thopri/Projects/PyNEMO/unit_tests/test_data/test_dst_hgr_zps.nc' + sn_dst_zgr = '/Users/thopri/Projects/PyNEMO/unit_tests/test_data/test_dst_zgr_zps.nc' + sn_src_msk = '/Users/thopri/Projects/PyNEMO/unit_tests/test_data/mask.nc' sn_bathy = '/Users/thopri/Projects/PyNEMO/unit_tests/test_data/dst_bathy.nc' !------------------------------------------------------------------------------ diff --git a/unit_tests/src_data_unit_tests.ncml b/unit_tests/src_data_unit_tests.ncml index 2b91153..3016c52 100644 --- a/unit_tests/src_data_unit_tests.ncml +++ b/unit_tests/src_data_unit_tests.ncml @@ -5,12 +5,6 @@ <ns0:scan location="file://Users/thopri/Projects/PyNEMO/unit_tests/test_data/" regExp=".*T\.nc$" /> </ns0:aggregation> </ns0:netcdf> - <ns0:netcdf> - <ns0:aggregation dimName="time" name="sea_surface_height" type="joinExisting"> - <ns0:scan location="file://Users/thopri/Projects/PyNEMO/unit_tests/test_data/" regExp=".*T\.nc$" /> - </ns0:aggregation> - </ns0:netcdf> </ns0:aggregation> <ns0:variable name="thetao" orgName="thetao" /> - <ns0:variable name="zos" orgName="zos" /> </ns0:netcdf> diff --git a/unit_tests/test_gen.py b/unit_tests/test_gen.py index 95c2984..15ec96e 100644 --- a/unit_tests/test_gen.py +++ b/unit_tests/test_gen.py @@ -90,22 +90,28 @@ def _main(): if write_coord_H + write_coord_Z == 0: print("Success!") - # plot orginal, rotatated and source lat and lon gt.plot_grids(grid_h2['latt'],grid_h2['lont'],grid_rot['latt'],grid_rot['lont'],grid_h3['latt'], \ grid_h3['lont'],grid_h1['latt'],grid_h1['lont']) - # save new lat lon to dataset - #ds.nav_lat.values[:], ds.nav_lon.values[:] = new_lat,new_lon - # save dataset to netcdf - #ds.to_netcdf('unit_tests/test_data/rot_'+str(rot)+'_dst_hgr_zps.nc') - # close data files - #ds.close() - #src.close() - out_fname = 'unit_tests/test_data/output_boundary.nc' + + # write bathy files (constant bathy) + bathy_fname = 'unit_tests/test_data/dst_bathy.nc' + bathy = gt.write_bathy(bathy_fname,grid_h2,grid_z2) + if bathy == 0: + print('Success!') + + # write boundary files (constant parameters) + out_fname = 'unit_tests/test_data/output_boundary_T.nc' params = {'name':'thetao','const_value':15.0,'longname':'temperature','units':'degreesC'} boundary = gt.write_parameter(out_fname,grid_h1,grid_z1,params) if boundary == 0: print('Success!') + #write_mask + mask_fname = 'unit_tests/test_data/mask.nc' + mask = gt.write_mask(mask_fname,grid_h1,grid_z1) + if mask == 0: + print('Success!') + if __name__ == '__main__': _main() \ No newline at end of file -- GitLab