def extract_GOT_constants(ilon, ilat, model_files, METHOD=None, EXTRAPOLATE=False, GZIP=True, SCALE=1.0): """ Reads files for Richard Ray's Global Ocean Tide (GOT) models Makes initial calculations to run the tide program Spatially interpolates tidal constituents to input coordinates Arguments --------- ilon: longitude to interpolate ilat: latitude to interpolate model_files: list of model files for each constituent Keyword arguments ----------------- METHOD: interpolation method bilinear: quick bilinear interpolation spline: scipy bivariate spline interpolation linear, nearest: scipy regular grid interpolations EXTRAPOLATE: extrapolate model using nearest-neighbors GZIP: input files are compressed SCALE: scaling factor for converting to output units Returns ------- amplitude: amplitudes of tidal constituents phase: phases of tidal constituents constituents: list of model constituents """ #-- adjust dimensions of input coordinates to be iterable ilon = np.atleast_1d(ilon) ilat = np.atleast_1d(ilat) #-- adjust longitudinal convention of input latitude and longitude #-- to fit tide model convention if (np.min(ilon) < 0.0): lt0, = np.nonzero(ilon < 0) ilon[lt0] += 360.0 #-- number of points npts = len(ilon) #-- amplitude and phase constituents = [] nc = len(model_files) amplitude = np.ma.zeros((npts, nc)) amplitude.mask = np.zeros((npts, nc), dtype=bool) ph = np.ma.zeros((npts, nc)) ph.mask = np.zeros((npts, nc), dtype=bool) #-- read and interpolate each constituent for i, model_file in enumerate(model_files): #-- read constituent from elevation file hc, lon, lat, cons = read_GOT_grid(os.path.expanduser(model_file), GZIP=GZIP) #-- append to the list of constituents constituents.append(cons) #-- grid step size of tide model dlon = np.abs(lon[1] - lon[0]) dlat = np.abs(lat[1] - lat[0]) #-- replace original values with extend matrices lon = extend_array(lon, dlon) hc = extend_matrix(hc) #-- interpolated complex form of constituent oscillation hci = np.ma.zeros((npts), dtype=hc.dtype, fill_value=hc.fill_value) hci.mask = np.zeros((npts), dtype=bool) #-- interpolate amplitude and phase of the constituent if (METHOD == 'bilinear'): #-- replace invalid values with nan hc[hc.mask] = np.nan #-- use quick bilinear to interpolate values hci.data[:] = bilinear_interp(lon, lat, hc, ilon, ilat, dtype=hc.dtype) #-- replace nan values with fill_value hci.mask[:] |= np.isnan(hci.data) hci.data[hci.mask] = hci.fill_value elif (METHOD == 'spline'): #-- interpolate complex form of the constituent with scipy f1 = scipy.interpolate.RectBivariateSpline(lon, lat, hc.data.real.T, kx=1, ky=1) f2 = scipy.interpolate.RectBivariateSpline(lon, lat, hc.data.imag.T, kx=1, ky=1) f3 = scipy.interpolate.RectBivariateSpline(lon, lat, hc.mask.T, kx=1, ky=1) hci.data.real[:] = f1.ev(ilon, ilat) hci.data.imag[:] = f2.ev(ilon, ilat) hci.mask[:] = f3.ev(ilon, ilat).astype(bool) #-- replace invalid values with fill_value hci.data[hci.mask] = hci.fill_value else: #-- use scipy regular grid to interpolate values for a given method r1 = scipy.interpolate.RegularGridInterpolator( (lat, lon), hc.data, method=METHOD, bounds_error=False, fill_value=hci.fill_value) r2 = scipy.interpolate.RegularGridInterpolator((lat, lon), hc.mask, method=METHOD, bounds_error=False, fill_value=1) hci.data[:] = r1.__call__(np.c_[ilat, ilon]) hci.mask[:] = np.ceil(r2.__call__(np.c_[ilat, ilon])).astype(bool) #-- replace invalid values with fill_value hci.mask[:] |= (hci.data == hci.fill_value) hci.data[hci.mask] = hci.fill_value #-- extrapolate data using nearest-neighbors if EXTRAPOLATE and np.any(hci.mask): #-- find invalid data points inv, = np.nonzero(hci.mask) #-- replace invalid values with nan hc[hc.mask] = np.nan #-- extrapolate points within 10km of valid model points hci.data[inv] = nearest_extrap(lon, lat, hc, ilon[inv], ilat[inv], dtype=hc.dtype, cutoff=10.0) #-- replace nan values with fill_value hci.mask[inv] = np.isnan(hci.data[inv]) hci.data[hci.mask] = hci.fill_value #-- convert amplitude from input units to meters amplitude.data[:, i] = np.abs(hci.data) * SCALE amplitude.mask[:, i] = np.copy(hci.mask) #-- phase of the constituent in radians ph.data[:, i] = np.arctan2(-np.imag(hci.data), np.real(hci.data)) ph.mask[:, i] = np.copy(hci.mask) #-- convert phase to degrees phase = ph * 180.0 / np.pi phase.data[phase.data < 0] += 360.0 #-- replace data for invalid mask values amplitude.data[amplitude.mask] = amplitude.fill_value phase.data[phase.mask] = phase.fill_value #-- return the interpolated values return (amplitude, phase, constituents)
def check_tide_points(x,y,DIRECTORY=None,MODEL=None,EPSG=3031,METHOD='spline'): """ Check if points are within a tide model domain Arguments --------- x: x-coordinates in projection EPSG y: y-coordinates in projection EPSG Keyword arguments ----------------- DIRECTORY: working data directory for tide models MODEL: Tide model to use in correction EPSG: input coordinate system default: 3031 Polar Stereographic South, WGS84 METHOD: interpolation method bilinear: quick bilinear interpolation spline: scipy bivariate spline interpolation linear, nearest: scipy regular grid interpolations Returns ------- valid: array describing if input coordinate is within model domain """ # select between tide models if (MODEL == 'CATS0201'): grid_file = os.path.join(DIRECTORY,'cats0201_tmd','grid_CATS') model_format = 'OTIS' model_EPSG = '4326' elif (MODEL == 'CATS2008'): grid_file = os.path.join(DIRECTORY,'CATS2008','grid_CATS2008') model_format = 'OTIS' model_EPSG = 'CATS2008' elif (MODEL == 'TPXO9-atlas'): grid_file = os.path.join(DIRECTORY,'TPXO9_atlas','grid_tpxo9_atlas.nc.gz') model_format = 'netcdf' elif (MODEL == 'TPXO9-atlas-v2'): grid_file = os.path.join(DIRECTORY,'TPXO9_atlas_v2','grid_tpxo9_atlas_30_v2.nc.gz') model_format = 'netcdf' elif (MODEL == 'TPXO9-atlas-v3'): grid_file = os.path.join(DIRECTORY,'TPXO9_atlas_v3','grid_tpxo9_atlas_30_v3.nc.gz') model_format = 'netcdf' elif (MODEL == 'TPXO9-atlas-v4'): grid_file = os.path.join(DIRECTORY,'TPXO9_atlas_v4','grid_tpxo9_atlas_30_v4') model_format = 'OTIS' model_EPSG = '4326' elif (MODEL == 'TPXO9.1'): grid_file = os.path.join(DIRECTORY,'TPXO9.1','DATA','grid_tpxo9') model_format = 'OTIS' model_EPSG = '4326' elif (MODEL == 'TPXO8-atlas'): grid_file = os.path.join(DIRECTORY,'tpxo8_atlas','grid_tpxo8atlas_30_v1') model_format = 'ATLAS' model_EPSG = '4326' elif (MODEL == 'TPXO7.2'): grid_file = os.path.join(DIRECTORY,'TPXO7.2_tmd','grid_tpxo7.2') model_format = 'OTIS' model_EPSG = '4326' elif (MODEL == 'AODTM-5'): grid_file = os.path.join(DIRECTORY,'aodtm5_tmd','grid_Arc5km') model_format = 'OTIS' model_EPSG = 'PSNorth' elif (MODEL == 'AOTIM-5'): grid_file = os.path.join(DIRECTORY,'aotim5_tmd','grid_Arc5km') model_format = 'OTIS' model_EPSG = 'PSNorth' elif (MODEL == 'AOTIM-5-2018'): grid_file = os.path.join(DIRECTORY,'Arc5km2018','grid_Arc5km2018') model_format = 'OTIS' model_EPSG = 'PSNorth' elif (MODEL == 'GOT4.7'): model_directory = os.path.join(DIRECTORY,'GOT4.7','grids_oceantide') model_files = ['q1.d.gz','o1.d.gz','p1.d.gz','k1.d.gz','n2.d.gz', 'm2.d.gz','s2.d.gz','k2.d.gz','s1.d.gz','m4.d.gz'] model_format = 'GOT' elif (MODEL == 'GOT4.8'): model_directory = os.path.join(DIRECTORY,'got4.8','grids_oceantide') model_files = ['q1.d.gz','o1.d.gz','p1.d.gz','k1.d.gz','n2.d.gz', 'm2.d.gz','s2.d.gz','k2.d.gz','s1.d.gz','m4.d.gz'] model_format = 'GOT' elif (MODEL == 'GOT4.10'): model_directory = os.path.join(DIRECTORY,'GOT4.10c','grids_oceantide') model_files = ['q1.d.gz','o1.d.gz','p1.d.gz','k1.d.gz','n2.d.gz', 'm2.d.gz','s2.d.gz','k2.d.gz','s1.d.gz','m4.d.gz'] model_format = 'GOT' elif (MODEL == 'FES2014'): model_directory = os.path.join(DIRECTORY,'fes2014','ocean_tide') model_files = ['2n2.nc.gz','eps2.nc.gz','j1.nc.gz','k1.nc.gz', 'k2.nc.gz','l2.nc.gz','la2.nc.gz','m2.nc.gz','m3.nc.gz','m4.nc.gz', 'm6.nc.gz','m8.nc.gz','mf.nc.gz','mks2.nc.gz','mm.nc.gz', 'mn4.nc.gz','ms4.nc.gz','msf.nc.gz','msqm.nc.gz','mtm.nc.gz', 'mu2.nc.gz','n2.nc.gz','n4.nc.gz','nu2.nc.gz','o1.nc.gz','p1.nc.gz', 'q1.nc.gz','r2.nc.gz','s1.nc.gz','s2.nc.gz','s4.nc.gz','sa.nc.gz', 'ssa.nc.gz','t2.nc.gz'] model_format = 'FES' # input shape of data idim = np.shape(x) # converting x,y from EPSG to latitude/longitude try: # EPSG projection code string or int crs1 = pyproj.CRS.from_string("epsg:{0:d}".format(int(EPSG))) except (ValueError,pyproj.exceptions.CRSError): # Projection SRS string crs1 = pyproj.CRS.from_string(EPSG) crs2 = pyproj.CRS.from_string("epsg:{0:d}".format(4326)) transformer = pyproj.Transformer.from_crs(crs1, crs2, always_xy=True) lon,lat = transformer.transform(np.atleast_1d(x).flatten(), np.atleast_1d(y).flatten()) # read tidal constants and interpolate to grid points if model_format in ('OTIS','ATLAS'): # if reading a single OTIS solution xi,yi,hz,mz,iob,dt = pyTMD.read_tide_model.read_tide_grid(grid_file) # invert model mask mz = np.logical_not(mz) # adjust dimensions of input coordinates to be iterable # run wrapper function to convert coordinate systems of input lat/lon X,Y = pyTMD.convert_ll_xy(lon,lat,model_EPSG,'F') elif (model_format == 'netcdf'): # if reading a netCDF OTIS atlas solution xi,yi,hz = pyTMD.read_netcdf_model.read_netcdf_grid(grid_file, GZIP=True, TYPE='z') # copy bathymetry mask mz = np.copy(hz.mask) # copy latitude and longitude and adjust longitudes X,Y = np.copy([lon,lat]).astype(np.float64) lt0, = np.nonzero(X < 0) X[lt0] += 360.0 elif (model_format == 'GOT'): # if reading a NASA GOT solution input_file = os.path.join(model_directory,model_files[0]) hc,xi,yi,c = pyTMD.read_GOT_model.read_GOT_grid(input_file, GZIP=True) # copy tidal constituent mask mz = np.copy(hc.mask) # copy latitude and longitude and adjust longitudes X,Y = np.copy([lon,lat]).astype(np.float64) lt0, = np.nonzero(X < 0) X[lt0] += 360.0 elif (model_format == 'FES'): # if reading a FES netCDF solution input_file = os.path.join(model_directory,model_files[0]) hc,xi,yi = pyTMD.read_FES_model.read_netcdf_file(input_file,GZIP=True, TYPE='z',VERSION='FES2014') # copy tidal constituent mask mz = np.copy(hc.mask) # copy latitude and longitude and adjust longitudes X,Y = np.copy([lon,lat]).astype(np.float64) lt0, = np.nonzero(X < 0) X[lt0] += 360.0 # interpolate masks if (METHOD == 'bilinear'): # replace invalid values with nan mz1 = bilinear_interp(xi,yi,mz,X,Y) mask = np.floor(mz1).astype(mz.dtype) elif (METHOD == 'spline'): f1=scipy.interpolate.RectBivariateSpline(xi,yi,mz.T,kx=1,ky=1) mask = np.floor(f1.ev(X,Y)).astype(mz.dtype) else: # use scipy regular grid to interpolate values r1 = scipy.interpolate.RegularGridInterpolator((yi,xi),mz, method=METHOD,bounds_error=False,fill_value=1) mask = np.floor(r1.__call__(np.c_[y,x])).astype(mz.dtype) # reshape to original dimensions valid = np.logical_not(mask).reshape(idim).astype(mz.dtype) # replace points outside model domain with invalid valid &= (X >= xi.min()) & (X <= xi.max()) valid &= (Y >= yi.min()) & (Y <= yi.max()) # return the valid mask return valid
def extract_FES_constants(ilon, ilat, directory, model_files, TYPE='z', VERSION=None, METHOD='spline', GZIP=True, SCALE=1): """ Reads files for an ascii or netCDF4 tidal model Makes initial calculations to run the tide program Spatially interpolates tidal constituents to input coordinates Arguments --------- ilon: longitude to interpolate ilat: latitude to interpolate directory: data directory for tide data files grid_file: grid file for model (can be gzipped) model_files: list of model files for each constituent (can be gzipped) Keyword arguments ----------------- TYPE: tidal variable to run z: heights u: horizontal transport velocities v: vertical transport velocities VERSION: model version to run FES1999 FES2004 FES2012 FES2014 METHOD: interpolation method bilinear: quick bilinear interpolation spline: scipy bivariate spline interpolation linear, nearest: scipy regular grid interpolations GZIP: input files are compressed SCALE: scaling factor for converting to output units Returns ------- amplitude: amplitudes of tidal constituents phase: phases of tidal constituents """ #-- adjust dimensions of input coordinates to be iterable ilon = np.atleast_1d(ilon) ilat = np.atleast_1d(ilat) #-- adjust longitudinal convention of input latitude and longitude #-- to fit tide model convention if (np.min(ilon) < 0.0): lt0, = np.nonzero(ilon < 0) ilon[lt0] += 360.0 #-- number of points npts = len(ilon) #-- number of constituents nc = len(model_files) #-- amplitude and phase amplitude = np.ma.zeros((npts, nc)) amplitude.mask = np.zeros((npts, nc), dtype=np.bool) phase = np.ma.zeros((npts, nc)) phase.mask = np.zeros((npts, nc), dtype=np.bool) #-- read and interpolate each constituent for i, fi in enumerate(model_files): #-- read constituent from elevation file if VERSION in ('FES1999', 'FES2004'): hc, lon, lat = read_ascii_file(os.path.join(directory, fi), GZIP=GZIP, TYPE=TYPE, VERSION=VERSION) elif VERSION in ('FES2012', 'FES2014'): hc, lon, lat = read_netcdf_file(os.path.join(directory, fi), GZIP=GZIP, TYPE=TYPE, VERSION=VERSION) #-- interpolated complex form of constituent oscillation hci = np.ma.zeros((npts), dtype=hc.dtype, fill_value=hc.fill_value) hci.mask = np.zeros((npts), dtype=np.bool) #-- interpolate amplitude and phase of the constituent if (METHOD == 'bilinear'): #-- replace invalid values with nan hc[hc.mask] = np.nan #-- use quick bilinear to interpolate values hci.data[:] = bilinear_interp(lon, lat, hc, ilon, ilat, dtype=hc.dtype) #-- replace nan values with fill_value hci.mask[:] |= np.isnan(hci.data) hci.data[hci.mask] = hci.fill_value elif (METHOD == 'spline'): #-- interpolate complex form of the constituent with scipy f1 = scipy.interpolate.RectBivariateSpline(lon, lat, hc.data.real.T, kx=1, ky=1) f2 = scipy.interpolate.RectBivariateSpline(lon, lat, hc.data.imag.T, kx=1, ky=1) f3 = scipy.interpolate.RectBivariateSpline(lon, lat, hc.mask.T, kx=1, ky=1) hci.data.real[:] = f1.ev(ilon, ilat) hci.data.imag[:] = f2.ev(ilon, ilat) hci.mask[:] = f3.ev(ilon, ilat).astype(np.bool) #-- replace invalid values with fill_value hci.data[hci.mask] = hci.fill_value else: #-- use scipy regular grid to interpolate values for a given method r1 = scipy.interpolate.RegularGridInterpolator( (lat, lon), hc.data, method=METHOD, bounds_error=False, fill_value=hci.fill_value) r2 = scipy.interpolate.RegularGridInterpolator((lat, lon), hc.mask, method=METHOD, bounds_error=False, fill_value=1) hci.data[:] = r1.__call__(np.c_[ilat, ilon]) hci.mask[:] = np.ceil(r2.__call__(np.c_[ilat, ilon])).astype(np.bool) #-- replace invalid values with fill_value hci.mask[:] |= (hci.data == hci.fill_value) hci.data[hci.mask] = hci.fill_value #-- convert amplitude from input units to meters amplitude.data[:, i] = np.abs(hci) * SCALE amplitude.mask[:, i] = np.copy(hci.mask) #-- convert phase to degrees phase.data[:, i] = np.arctan2(-np.imag(hci), np.real(hci)) * 180.0 / np.pi phase.mask[:, i] = np.copy(hci.mask) phase.data[phase.data < 0] += 360.0 #-- replace data for invalid mask values amplitude.data[amplitude.mask] = amplitude.fill_value phase.data[phase.mask] = phase.fill_value #-- return the interpolated values return (amplitude, phase)
def check_tide_points(x, y, DIRECTORY=None, MODEL=None, ATLAS_FORMAT='netcdf', GZIP=False, DEFINITION_FILE=None, EPSG=3031, METHOD='spline'): """ Check if points are within a tide model domain Parameters ---------- x: float x-coordinates in projection EPSG y: float y-coordinates in projection EPSG DIRECTORY: str or NoneType, default None working data directory for tide models MODEL: str or NoneType, default None Tide model to use ATLAS_FORMAT: str, default 'netcdf' ATLAS tide model format - ``'OTIS'`` - ``'netcdf'`` GZIP: bool, default False Tide model files are gzip compressed DEFINITION_FILE: str or NoneType, default None Tide model definition file for use EPSG: int, default: 3031 (Polar Stereographic South, WGS84) Input coordinate system METHOD: str interpolation method - ```bilinear```: quick bilinear interpolation - ```spline```: scipy bivariate spline interpolation - ```linear```, ```nearest```: scipy regular grid interpolations Returns ------- valid: bool array describing if input coordinate is within model domain """ #-- check that tide directory is accessible try: os.access(DIRECTORY, os.F_OK) except: raise FileNotFoundError("Invalid tide directory") #-- get parameters for tide model if DEFINITION_FILE is not None: model = pyTMD.model(DIRECTORY).from_file(DEFINITION_FILE) else: model = pyTMD.model(DIRECTORY, format=ATLAS_FORMAT, compressed=GZIP).elevation(MODEL) # input shape of data idim = np.shape(x) # converting x,y from EPSG to latitude/longitude try: # EPSG projection code string or int crs1 = pyproj.CRS.from_string("epsg:{0:d}".format(int(EPSG))) except (ValueError,pyproj.exceptions.CRSError): # Projection SRS string crs1 = pyproj.CRS.from_string(EPSG) crs2 = pyproj.CRS.from_string("epsg:{0:d}".format(4326)) transformer = pyproj.Transformer.from_crs(crs1, crs2, always_xy=True) lon,lat = transformer.transform(np.atleast_1d(x).flatten(), np.atleast_1d(y).flatten()) # read tidal constants and interpolate to grid points if model.format in ('OTIS','ATLAS'): # if reading a single OTIS solution xi,yi,hz,mz,iob,dt = pyTMD.read_tide_model.read_tide_grid(model.grid_file) # invert model mask mz = np.logical_not(mz) # adjust dimensions of input coordinates to be iterable # run wrapper function to convert coordinate systems of input lat/lon X,Y = pyTMD.convert_ll_xy(lon,lat,model.projection,'F') elif (model.format == 'netcdf'): # if reading a netCDF OTIS atlas solution xi,yi,hz = pyTMD.read_netcdf_model.read_netcdf_grid(model.grid_file, GZIP=model.compressed, TYPE=model.type) # copy bathymetry mask mz = np.copy(hz.mask) # copy latitude and longitude and adjust longitudes X,Y = np.copy([lon,lat]).astype(np.float64) lt0, = np.nonzero(X < 0) X[lt0] += 360.0 elif (model.format == 'GOT'): # if reading a NASA GOT solution hc,xi,yi,c = pyTMD.read_GOT_model.read_GOT_grid(model.model_file[0], GZIP=model.compressed) # copy tidal constituent mask mz = np.copy(hc.mask) # copy latitude and longitude and adjust longitudes X,Y = np.copy([lon,lat]).astype(np.float64) lt0, = np.nonzero(X < 0) X[lt0] += 360.0 elif (model.format == 'FES'): # if reading a FES netCDF solution hc,xi,yi = pyTMD.read_FES_model.read_netcdf_file(model.model_file[0], GZIP=model.compressed, TYPE=model.type, VERSION=model.version) # copy tidal constituent mask mz = np.copy(hc.mask) # copy latitude and longitude and adjust longitudes X,Y = np.copy([lon,lat]).astype(np.float64) lt0, = np.nonzero(X < 0) X[lt0] += 360.0 # interpolate masks if (METHOD == 'bilinear'): # replace invalid values with nan mz1 = bilinear_interp(xi,yi,mz,X,Y) mask = np.floor(mz1).astype(mz.dtype) elif (METHOD == 'spline'): f1=scipy.interpolate.RectBivariateSpline(xi,yi,mz.T,kx=1,ky=1) mask = np.floor(f1.ev(X,Y)).astype(mz.dtype) else: # use scipy regular grid to interpolate values r1 = scipy.interpolate.RegularGridInterpolator((yi,xi),mz, method=METHOD,bounds_error=False,fill_value=1) mask = np.floor(r1.__call__(np.c_[y,x])).astype(mz.dtype) # reshape to original dimensions valid = np.logical_not(mask).reshape(idim).astype(mz.dtype) # replace points outside model domain with invalid valid &= (X >= xi.min()) & (X <= xi.max()) valid &= (Y >= yi.min()) & (Y <= yi.max()) # return the valid mask return valid
def extract_FES_constants(ilon, ilat, model_files, TYPE='z', VERSION=None, METHOD='spline', EXTRAPOLATE=False, CUTOFF=10.0, GZIP=True, SCALE=1.0): """ Reads files for an ascii or netCDF4 tidal model Makes initial calculations to run the tide program Spatially interpolates tidal constituents to input coordinates Parameters ---------- ilon: float longitude to interpolate ilat: float latitude to interpolate grid_file: str grid file for model model_files: list list of model files for each constituent TYPE: str, default 'z' Tidal variable to read - ``'z'``: heights - ``'u'``: horizontal transport velocities - ``'v'``: vertical transport velocities VERSION: str or NoneType, default None Model version to read - ``'FES1999'`` - ``'FES2004'`` - ``'FES2012'`` - ``'FES2014'`` - ``'EOT20'`` METHOD: str, default 'spline' Interpolation method - ``'bilinear'``: quick bilinear interpolation - ``'spline'``: scipy bivariate spline interpolation - ``'linear'``, ``'nearest'``: scipy regular grid interpolations EXTRAPOLATE: bool, default False Extrapolate model using nearest-neighbors CUTOFF: float, default 10.0 Extrapolation cutoff in kilometers Set to np.inf to extrapolate for all points GZIP: bool, default False Input files are compressed SCALE: float, default 1.0 Scaling factor for converting to output units Returns ------- amplitude: float amplitudes of tidal constituents phase: float phases of tidal constituents """ #-- raise warning if model files are entered as a string if isinstance(model_files,str): warnings.warn("Tide model is entered as a string") model_files = [model_files] #-- adjust dimensions of input coordinates to be iterable ilon = np.atleast_1d(ilon) ilat = np.atleast_1d(ilat) #-- number of points npts = len(ilon) #-- number of constituents nc = len(model_files) #-- amplitude and phase amplitude = np.ma.zeros((npts,nc)) amplitude.mask = np.zeros((npts,nc),dtype=bool) ph = np.ma.zeros((npts,nc)) ph.mask = np.zeros((npts,nc),dtype=bool) #-- read and interpolate each constituent for i,fi in enumerate(model_files): #-- check that model file is accessible if not os.access(os.path.expanduser(fi), os.F_OK): raise FileNotFoundError(os.path.expanduser(fi)) #-- read constituent from elevation file if VERSION in ('FES1999','FES2004'): #-- FES ascii constituent files hc,lon,lat = read_ascii_file(os.path.expanduser(fi), GZIP=GZIP, TYPE=TYPE, VERSION=VERSION) elif VERSION in ('FES2012','FES2014','EOT20'): #-- FES netCDF4 constituent files hc,lon,lat = read_netcdf_file(os.path.expanduser(fi), GZIP=GZIP, TYPE=TYPE, VERSION=VERSION) #-- adjust longitudinal convention of input latitude and longitude #-- to fit tide model convention if (np.min(ilon) < 0.0) & (np.max(lon) > 180.0): #-- input points convention (-180:180) #-- tide model convention (0:360) ilon[ilon<0.0] += 360.0 elif (np.max(ilon) > 180.0) & (np.min(lon) < 0.0): #-- input points convention (0:360) #-- tide model convention (-180:180) ilon[ilon>180.0] -= 360.0 #-- interpolated complex form of constituent oscillation hci = np.ma.zeros((npts),dtype=hc.dtype,fill_value=hc.fill_value) hci.mask = np.zeros((npts),dtype=bool) #-- interpolate amplitude and phase of the constituent if (METHOD == 'bilinear'): #-- replace invalid values with nan hc[hc.mask] = np.nan #-- use quick bilinear to interpolate values hci.data[:] = bilinear_interp(lon,lat,hc,ilon,ilat,dtype=hc.dtype) #-- replace nan values with fill_value hci.mask[:] |= np.isnan(hci.data) hci.data[hci.mask] = hci.fill_value elif (METHOD == 'spline'): #-- interpolate complex form of the constituent with scipy f1=scipy.interpolate.RectBivariateSpline(lon,lat, hc.data.real.T,kx=1,ky=1) f2=scipy.interpolate.RectBivariateSpline(lon,lat, hc.data.imag.T,kx=1,ky=1) f3=scipy.interpolate.RectBivariateSpline(lon,lat, hc.mask.T,kx=1,ky=1) hci.data.real[:] = f1.ev(ilon,ilat) hci.data.imag[:] = f2.ev(ilon,ilat) hci.mask[:] = f3.ev(ilon,ilat).astype(bool) #-- replace invalid values with fill_value hci.data[hci.mask] = hci.fill_value else: #-- use scipy regular grid to interpolate values for a given method r1 = scipy.interpolate.RegularGridInterpolator((lat,lon), hc.data, method=METHOD, bounds_error=False, fill_value=hci.fill_value) r2 = scipy.interpolate.RegularGridInterpolator((lat,lon), hc.mask, method=METHOD, bounds_error=False, fill_value=1) hci.data[:] = r1.__call__(np.c_[ilat,ilon]) hci.mask[:] = np.ceil(r2.__call__(np.c_[ilat,ilon])).astype(bool) #-- replace invalid values with fill_value hci.mask[:] |= (hci.data == hci.fill_value) hci.data[hci.mask] = hci.fill_value #-- extrapolate data using nearest-neighbors if EXTRAPOLATE and np.any(hci.mask): #-- find invalid data points inv, = np.nonzero(hci.mask) #-- replace invalid values with nan hc[hc.mask] = np.nan #-- extrapolate points within cutoff of valid model points hci[inv] = nearest_extrap(lon,lat,hc,ilon[inv],ilat[inv], dtype=hc.dtype,cutoff=CUTOFF) #-- convert amplitude from input units to meters amplitude.data[:,i] = np.abs(hci.data)*SCALE amplitude.mask[:,i] = np.copy(hci.mask) #-- phase of the constituent in radians ph.data[:,i] = np.arctan2(-np.imag(hci.data),np.real(hci.data)) ph.mask[:,i] = np.copy(hci.mask) #-- convert phase to degrees phase = ph*180.0/np.pi phase.data[phase.data < 0] += 360.0 #-- replace data for invalid mask values amplitude.data[amplitude.mask] = amplitude.fill_value phase.data[phase.mask] = phase.fill_value #-- return the interpolated values return (amplitude,phase)
def extract_netcdf_constants(ilon, ilat, directory, grid_file, model_files, TYPE='z', METHOD='spline', GZIP=True, SCALE=1): """ Reads files for a netCDF4 tidal model Makes initial calculations to run the tide program Spatially interpolates tidal constituents to input coordinates Arguments --------- ilon: longitude to interpolate ilat: latitude to interpolate directory: data directory for tide data files grid_file: grid file for model (can be gzipped) model_files: list of model files for each constituent (can be gzipped) TYPE: tidal variable to run z: heights u: horizontal transport velocities U: horizontal depth-averaged transport v: vertical transport velocities V: vertical depth-averaged transport Keyword arguments ----------------- METHOD: interpolation method bilinear: quick bilinear interpolation spline: scipy bivariate spline interpolation linear, nearest: scipy regular grid interpolations GZIP: input netCDF4 files are compressed SCALE: scaling factor for converting to output units Returns ------- amplitude: amplitudes of tidal constituents phase: phases of tidal constituents D: bathymetry of tide model constituents: list of model constituents """ #-- read the netcdf format tide grid file #-- reading a combined global solution with localized solutions if GZIP: #-- open remote file with netCDF4 #-- read GZIP file f = gzip.open(os.path.join(directory,grid_file),'rb') fileID = netCDF4.Dataset(grid_file,'r',memory=f.read()) else: fileID = netCDF4.Dataset(os.path.join(directory,grid_file),'r') #-- variable dimensions nx = fileID.dimensions['nx'].size ny = fileID.dimensions['ny'].size #-- allocate numpy masked array for bathymetry bathymetry = np.ma.zeros((ny,nx)) #-- read bathmetry and coordinates for variable type if (TYPE == 'z'): #-- get bathymetry at nodes bathymetry.data[:,:] = fileID.variables['hz'][:,:].T #-- read latitude and longitude at z-nodes lon = fileID.variables['lon_z'][:].copy() lat = fileID.variables['lat_z'][:].copy() elif TYPE in ('U','u'): #-- get bathymetry at u-nodes bathymetry.data[:,:] = fileID.variables['hu'][:,:].T #-- read latitude and longitude at u-nodes lon = fileID.variables['lon_u'][:].copy() lat = fileID.variables['lat_u'][:].copy() elif TYPE in ('V','v'): #-- get bathymetry at v-nodes bathymetry.data[:,:] = fileID.variables['hv'][:,:].T #-- read latitude and longitude at v-nodes lon = fileID.variables['lon_v'][:].copy() lat = fileID.variables['lat_v'][:].copy() #-- close the grid file fileID.close() f.close() if GZIP else None #-- grid step size of tide model dlon = lon[1] - lon[0] dlat = lat[1] - lat[0] #-- replace original values with extend arrays/matrices lon = extend_array(lon, dlon) bathymetry = extend_matrix(bathymetry) #-- create masks bathymetry.mask = (bathymetry.data == 0) #-- create meshes from latitude and longitude gridlon,gridlat = np.meshgrid(lon,lat) #-- adjust dimensions of input coordinates to be iterable ilon = np.atleast_1d(ilon) ilat = np.atleast_1d(ilat) #-- adjust longitudinal convention of input latitude and longitude #-- to fit tide model convention lt0, = np.nonzero(ilon < 0) ilon[lt0] += 360.0 #-- number of points npts = len(ilon) #-- interpolate bathymetry and mask to output points D = np.ma.zeros((npts)) D.mask = np.zeros((npts),dtype=np.bool) if (METHOD == 'bilinear'): #-- replace invalid values with nan bathymetry[bathymetry.mask] = np.nan #-- use quick bilinear to interpolate values D.data[:] = bilinear_interp(lon,lat,bathymetry,ilon,ilat) #-- replace nan values with fill_value D.mask[:] = np.isnan(D.data) D.data[D.mask] = D.fill_value elif (METHOD == 'spline'): #-- use scipy bivariate splines to interpolate values f1 = scipy.interpolate.RectBivariateSpline(lon,lat, bathymetry.data.T,kx=1,ky=1) f2 = scipy.interpolate.RectBivariateSpline(lon,lat, bathymetry.mask.T,kx=1,ky=1) D.data[:] = f1.ev(ilon,ilat) D.mask[:] = np.ceil(f2.ev(ilon,ilat).astype(np.bool)) else: #-- use scipy regular grid to interpolate values for a given method r1 = scipy.interpolate.RegularGridInterpolator((lat,lon), bathymetry.data, method=METHOD, bounds_error=False) r2 = scipy.interpolate.RegularGridInterpolator((lat,lon), bathymetry.mask, method=METHOD, bounds_error=False, fill_value=1) D.data[:] = r1.__call__(np.c_[ilat,ilon]) D.mask[:] = np.ceil(r2.__call__(np.c_[ilat,ilon])).astype(np.bool) #-- u and v are velocities in cm/s if TYPE in ('v','u'): unit_conv = (D.data/100.0) #-- U and V are transports in m^2/s elif TYPE in ('V','U'): unit_conv = 1.0 #-- number of constituents nc = len(model_files) #-- list of constituents constituents = [] #-- amplitude and phase ampl = np.ma.zeros((npts,nc)) ampl.mask = np.zeros((npts,nc),dtype=np.bool) phase = np.ma.zeros((npts,nc)) phase.mask = np.zeros((npts,nc),dtype=np.bool) #-- read and interpolate each constituent for i,fi in enumerate(model_files): if (TYPE == 'z'): #-- read constituent from elevation file z,con = read_elevation_file(os.path.join(directory,fi),GZIP) #-- append constituent to list constituents.append(con) #-- replace original values with extend matrices z = extend_matrix(z) #-- interpolate amplitude and phase of the constituent z1 = np.ma.zeros((npts),dtype=z.dtype) z1.mask = np.zeros((npts),dtype=np.bool) if (METHOD == 'bilinear'): z1.data[:] = bilinear_interp(lon,lat,z,ilon,ilat,dtype=z.dtype) #-- mask invalid values z1.mask[:] |= np.copy(D.mask) z1.data[z1.mask] = z1.fill_value elif (METHOD == 'spline'): f1 = scipy.interpolate.RectBivariateSpline(lon,lat, z.data.real.T,kx=1,ky=1) f2 = scipy.interpolate.RectBivariateSpline(lon,lat, z.data.imag.T,kx=1,ky=1) z1.data.real = f1.ev(ilon,ilat) z1.data.imag = f2.ev(ilon,ilat) #-- mask invalid values z1.mask[:] |= np.copy(D.mask) z1.data[z1.mask] = z1.fill_value else: #-- use scipy regular grid to interpolate values r1 = scipy.interpolate.RegularGridInterpolator((lat,lon), z.data, method=METHOD, bounds_error=False, fill_value=z1.fill_value) z1.data[:] = r1.__call__(np.c_[ilat,ilon]) #-- mask invalid values z1.mask[:] |= np.copy(D.mask) z1.data[z1.mask] = z1.fill_value #-- amplitude and phase of the constituent ampl[:,i] = np.abs(z1) phase[:,i] = np.arctan2(-np.imag(z1),np.real(z1)) elif TYPE in ('U','u','V','v'): #-- read constituent from transport file tr,con = read_transport_file(os.path.join(directory,fi),TYPE,GZIP) #-- append constituent to list constituents.append(con) #-- replace original values with extend matrices tr = extend_matrix(tr) #-- interpolate amplitude and phase of the constituent tr1 = np.ma.zeros((npts),dtype=tr.dtype) tr1.mask = np.zeros((npts),dtype=np.bool) if (METHOD == 'bilinear'): tr1.data[:]=bilinear_interp(lon,lat,tr,ilon,ilat,dtype=tr.dtype) #-- mask invalid values tr1.mask[:] |= np.copy(D.mask) tr1.data[tr1.mask] = tr1.fill_value elif (METHOD == 'spline'): f1 = scipy.interpolate.RectBivariateSpline(lon,lat, tr.data.real.T,kx=1,ky=1) f2 = scipy.interpolate.RectBivariateSpline(lon,lat, tr.data.imag.T,kx=1,ky=1) tr1.data.real = f1.ev(ilon,ilat) tr1.data.imag = f2.ev(ilon,ilat) #-- mask invalid values tr1.mask[:] |= np.copy(D.mask) tr1.data[tr1.mask] = z1.fill_value else: #-- use scipy regular grid to interpolate values r1 = scipy.interpolate.RegularGridInterpolator((lat,lon), tr.data, method=METHOD, bounds_error=False, fill_value=tr1.fill_value) tr1.data[:] = r1.__call__(np.c_[ilat,ilon]) #-- mask invalid values tr1.mask[:] |= np.copy(D.mask) tr1.data[tr1.mask] = tr1.fill_value #-- convert units tr1 = tr1/unit_conv #-- amplitude and phase of the constituent ampl[:,i] = np.abs(tr1) phase[:,i] = np.arctan2(-np.imag(tr1),np.real(tr1)) #-- convert amplitude from input units to meters amplitude = ampl*SCALE #-- convert phase to degrees phase = phase*180.0/np.pi phase[phase < 0] += 360.0 #-- return the interpolated values return (amplitude,phase,D,constituents)
def extract_netcdf_constants(ilon, ilat, grid_file, model_files, TYPE='z', METHOD='spline', EXTRAPOLATE=False, CUTOFF=10.0, GZIP=True, SCALE=1.0): """ Reads files for ATLAS netCDF4 tidal models Makes initial calculations to run the tide program Spatially interpolates tidal constituents to input coordinates Parameters ---------- ilon: float longitude to interpolate ilat: float latitude to interpolate grid_file: str grid file for model model_files: list list of model files for each constituent TYPE: str, default 'z' Tidal variable to read - ``'z'``: heights - ``'u'``: horizontal transport velocities - ``'U'``: horizontal depth-averaged transport - ``'v'``: vertical transport velocities - ``'V'``: vertical depth-averaged transport METHOD: str, default 'spline' Interpolation method - ``'bilinear'``: quick bilinear interpolation - ``'spline'``: scipy bivariate spline interpolation - ``'linear'``, ``'nearest'``: scipy regular grid interpolations EXTRAPOLATE: bool, default False Extrapolate model using nearest-neighbors CUTOFF: float, default 10.0 Extrapolation cutoff in kilometers Set to np.inf to extrapolate for all points GZIP: bool, default False Input files are compressed SCALE: float, default 1.0 Scaling factor for converting to output units Returns ------- amplitude: float amplitudes of tidal constituents phase: float phases of tidal constituents D: float bathymetry of tide model constituents: list list of model constituents """ #-- raise warning if model files are entered as a string if isinstance(model_files,str): warnings.warn("Tide model is entered as a string") model_files = [model_files] #-- check that grid file is accessible if not os.access(os.path.expanduser(grid_file), os.F_OK): raise FileNotFoundError(os.path.expanduser(grid_file)) #-- read the tide grid file for bathymetry and spatial coordinates lon,lat,bathymetry = read_netcdf_grid(grid_file, TYPE, GZIP=GZIP) #-- adjust dimensions of input coordinates to be iterable ilon = np.atleast_1d(ilon) ilat = np.atleast_1d(ilat) #-- adjust longitudinal convention of input latitude and longitude #-- to fit tide model convention if (np.min(ilon) < 0.0) & (np.max(lon) > 180.0): #-- input points convention (-180:180) #-- tide model convention (0:360) ilon[ilon<0.0] += 360.0 elif (np.max(ilon) > 180.0) & (np.min(lon) < 0.0): #-- input points convention (0:360) #-- tide model convention (-180:180) ilon[ilon>180.0] -= 360.0 #-- grid step size of tide model dlon = lon[1] - lon[0] dlat = lat[1] - lat[0] #-- replace original values with extend arrays/matrices lon = extend_array(lon, dlon) bathymetry = extend_matrix(bathymetry) #-- create masks bathymetry.mask = (bathymetry.data == 0) #-- number of points npts = len(ilon) #-- interpolate bathymetry and mask to output points D = np.ma.zeros((npts)) D.mask = np.zeros((npts),dtype=bool) if (METHOD == 'bilinear'): #-- replace invalid values with nan bathymetry[bathymetry.mask] = np.nan #-- use quick bilinear to interpolate values D.data[:] = bilinear_interp(lon,lat,bathymetry,ilon,ilat) #-- replace nan values with fill_value D.mask[:] = np.isnan(D.data) D.data[D.mask] = D.fill_value elif (METHOD == 'spline'): #-- use scipy bivariate splines to interpolate values f1 = scipy.interpolate.RectBivariateSpline(lon,lat, bathymetry.data.T,kx=1,ky=1) f2 = scipy.interpolate.RectBivariateSpline(lon,lat, bathymetry.mask.T,kx=1,ky=1) D.data[:] = f1.ev(ilon,ilat) D.mask[:] = np.ceil(f2.ev(ilon,ilat).astype(bool)) else: #-- use scipy regular grid to interpolate values for a given method r1 = scipy.interpolate.RegularGridInterpolator((lat,lon), bathymetry.data, method=METHOD, bounds_error=False) r2 = scipy.interpolate.RegularGridInterpolator((lat,lon), bathymetry.mask, method=METHOD, bounds_error=False, fill_value=1) D.data[:] = r1.__call__(np.c_[ilat,ilon]) D.mask[:] = np.ceil(r2.__call__(np.c_[ilat,ilon])).astype(bool) #-- u and v are velocities in cm/s if TYPE in ('v','u'): unit_conv = (D.data/100.0) #-- U and V are transports in m^2/s elif TYPE in ('V','U'): unit_conv = 1.0 #-- number of constituents nc = len(model_files) #-- list of constituents constituents = [] #-- amplitude and phase ampl = np.ma.zeros((npts,nc)) ampl.mask = np.zeros((npts,nc),dtype=bool) ph = np.ma.zeros((npts,nc)) ph.mask = np.zeros((npts,nc),dtype=bool) #-- read and interpolate each constituent for i,model_file in enumerate(model_files): #-- check that model file is accessible if not os.access(os.path.expanduser(model_file), os.F_OK): raise FileNotFoundError(os.path.expanduser(model_file)) if (TYPE == 'z'): #-- read constituent from elevation file z,con = read_elevation_file(model_file, GZIP=GZIP) #-- append constituent to list constituents.append(con) #-- replace original values with extend matrices z = extend_matrix(z) #-- update constituent mask with bathymetry mask z.mask[:] |= bathymetry.mask[:] #-- interpolate amplitude and phase of the constituent z1 = np.ma.zeros((npts),dtype=z.dtype) z1.mask = np.zeros((npts),dtype=bool) if (METHOD == 'bilinear'): #-- replace invalid values with nan z[z.mask] = np.nan z1.data[:] = bilinear_interp(lon,lat,z,ilon,ilat,dtype=z.dtype) #-- mask invalid values z1.mask[:] |= np.copy(D.mask) z1.data[z1.mask] = z1.fill_value elif (METHOD == 'spline'): f1 = scipy.interpolate.RectBivariateSpline(lon,lat, z.data.real.T,kx=1,ky=1) f2 = scipy.interpolate.RectBivariateSpline(lon,lat, z.data.imag.T,kx=1,ky=1) z1.data.real = f1.ev(ilon,ilat) z1.data.imag = f2.ev(ilon,ilat) #-- mask invalid values z1.mask[:] |= np.copy(D.mask) z1.data[z1.mask] = z1.fill_value else: #-- use scipy regular grid to interpolate values r1 = scipy.interpolate.RegularGridInterpolator((lat,lon), z.data, method=METHOD, bounds_error=False, fill_value=z1.fill_value) z1.data[:] = r1.__call__(np.c_[ilat,ilon]) #-- mask invalid values z1.mask[:] |= np.copy(D.mask) z1.data[z1.mask] = z1.fill_value #-- extrapolate data using nearest-neighbors if EXTRAPOLATE and np.any(z1.mask): #-- find invalid data points inv, = np.nonzero(z1.mask) #-- replace invalid values with nan z[z.mask] = np.nan #-- extrapolate points within cutoff of valid model points z1[inv] = nearest_extrap(lon,lat,z,ilon[inv],ilat[inv], dtype=z.dtype,cutoff=CUTOFF) #-- amplitude and phase of the constituent ampl.data[:,i] = np.abs(z1.data) ampl.mask[:,i] = np.copy(z1.mask) ph.data[:,i] = np.arctan2(-np.imag(z1.data),np.real(z1.data)) ph.mask[:,i] = np.copy(z1.mask) elif TYPE in ('U','u','V','v'): #-- read constituent from transport file tr,con = read_transport_file(model_file, TYPE, GZIP=GZIP) #-- append constituent to list constituents.append(con) #-- replace original values with extend matrices tr = extend_matrix(tr) #-- update constituent mask with bathymetry mask tr.mask[:] |= bathymetry.mask[:] #-- interpolate amplitude and phase of the constituent tr1 = np.ma.zeros((npts),dtype=tr.dtype) tr1.mask = np.zeros((npts),dtype=bool) if (METHOD == 'bilinear'): tr1.data[:]=bilinear_interp(lon,lat,tr,ilon,ilat,dtype=tr.dtype) #-- mask invalid values tr1.mask[:] |= np.copy(D.mask) tr1.data[tr1.mask] = tr1.fill_value elif (METHOD == 'spline'): f1 = scipy.interpolate.RectBivariateSpline(lon,lat, tr.data.real.T,kx=1,ky=1) f2 = scipy.interpolate.RectBivariateSpline(lon,lat, tr.data.imag.T,kx=1,ky=1) tr1.data.real = f1.ev(ilon,ilat) tr1.data.imag = f2.ev(ilon,ilat) #-- mask invalid values tr1.mask[:] |= np.copy(D.mask) tr1.data[tr1.mask] = z1.fill_value else: #-- use scipy regular grid to interpolate values r1 = scipy.interpolate.RegularGridInterpolator((lat,lon), tr.data, method=METHOD, bounds_error=False, fill_value=tr1.fill_value) tr1.data[:] = r1.__call__(np.c_[ilat,ilon]) #-- mask invalid values tr1.mask[:] |= np.copy(D.mask) tr1.data[tr1.mask] = tr1.fill_value #-- extrapolate data using nearest-neighbors if EXTRAPOLATE and np.any(tr1.mask): #-- find invalid data points inv, = np.nonzero(tr1.mask) #-- replace invalid values with nan tr[tr.mask] = np.nan #-- extrapolate points within cutoff of valid model points tr1[inv] = nearest_extrap(lon,lat,tr,ilon[inv],ilat[inv], dtype=tr.dtype,cutoff=CUTOFF) #-- convert units #-- amplitude and phase of the constituent ampl.data[:,i] = np.abs(tr1.data)/unit_conv ampl.mask[:,i] = np.copy(tr1.mask) ph.data[:,i] = np.arctan2(-np.imag(tr1.data),np.real(tr1.data)) ph.mask[:,i] = np.copy(tr1.mask) #-- convert amplitude from input units to meters amplitude = ampl*SCALE #-- convert phase to degrees phase = ph*180.0/np.pi phase[phase < 0] += 360.0 #-- return the interpolated values return (amplitude,phase,D,constituents)
def extract_netcdf_constants(ilon, ilat, grid_file, model_files, TYPE='z', METHOD='spline', EXTRAPOLATE=False, GZIP=True, SCALE=1.0): """ Reads files for a netCDF4 tidal model Makes initial calculations to run the tide program Spatially interpolates tidal constituents to input coordinates Arguments --------- ilon: longitude to interpolate ilat: latitude to interpolate grid_file: grid file for model (can be gzipped) model_files: list of model files for each constituent (can be gzipped) Keyword arguments ----------------- TYPE: tidal variable to read z: heights u: horizontal transport velocities U: horizontal depth-averaged transport v: vertical transport velocities V: vertical depth-averaged transport METHOD: interpolation method bilinear: quick bilinear interpolation spline: scipy bivariate spline interpolation linear, nearest: scipy regular grid interpolations EXTRAPOLATE: extrapolate model using nearest-neighbors GZIP: input netCDF4 files are compressed SCALE: scaling factor for converting to output units Returns ------- amplitude: amplitudes of tidal constituents phase: phases of tidal constituents D: bathymetry of tide model constituents: list of model constituents """ #-- read the tide grid file for bathymetry and spatial coordinates lon, lat, bathymetry = read_netcdf_grid(grid_file, TYPE, GZIP=GZIP) #-- grid step size of tide model dlon = lon[1] - lon[0] dlat = lat[1] - lat[0] #-- replace original values with extend arrays/matrices lon = extend_array(lon, dlon) bathymetry = extend_matrix(bathymetry) #-- create masks bathymetry.mask = (bathymetry.data == 0) #-- adjust dimensions of input coordinates to be iterable ilon = np.atleast_1d(ilon) ilat = np.atleast_1d(ilat) #-- adjust longitudinal convention of input latitude and longitude #-- to fit tide model convention lt0, = np.nonzero(ilon < 0) ilon[lt0] += 360.0 #-- number of points npts = len(ilon) #-- interpolate bathymetry and mask to output points D = np.ma.zeros((npts)) D.mask = np.zeros((npts), dtype=bool) if (METHOD == 'bilinear'): #-- replace invalid values with nan bathymetry[bathymetry.mask] = np.nan #-- use quick bilinear to interpolate values D.data[:] = bilinear_interp(lon, lat, bathymetry, ilon, ilat) #-- replace nan values with fill_value D.mask[:] = np.isnan(D.data) D.data[D.mask] = D.fill_value elif (METHOD == 'spline'): #-- use scipy bivariate splines to interpolate values f1 = scipy.interpolate.RectBivariateSpline(lon, lat, bathymetry.data.T, kx=1, ky=1) f2 = scipy.interpolate.RectBivariateSpline(lon, lat, bathymetry.mask.T, kx=1, ky=1) D.data[:] = f1.ev(ilon, ilat) D.mask[:] = np.ceil(f2.ev(ilon, ilat).astype(bool)) else: #-- use scipy regular grid to interpolate values for a given method r1 = scipy.interpolate.RegularGridInterpolator((lat, lon), bathymetry.data, method=METHOD, bounds_error=False) r2 = scipy.interpolate.RegularGridInterpolator((lat, lon), bathymetry.mask, method=METHOD, bounds_error=False, fill_value=1) D.data[:] = r1.__call__(np.c_[ilat, ilon]) D.mask[:] = np.ceil(r2.__call__(np.c_[ilat, ilon])).astype(bool) #-- u and v are velocities in cm/s if TYPE in ('v', 'u'): unit_conv = (D.data / 100.0) #-- U and V are transports in m^2/s elif TYPE in ('V', 'U'): unit_conv = 1.0 #-- number of constituents nc = len(model_files) #-- list of constituents constituents = [] #-- amplitude and phase ampl = np.ma.zeros((npts, nc)) ampl.mask = np.zeros((npts, nc), dtype=bool) ph = np.ma.zeros((npts, nc)) ph.mask = np.zeros((npts, nc), dtype=bool) #-- read and interpolate each constituent for i, model_file in enumerate(model_files): if (TYPE == 'z'): #-- read constituent from elevation file z, con = read_elevation_file(model_file, GZIP=GZIP) #-- append constituent to list constituents.append(con) #-- replace original values with extend matrices z = extend_matrix(z) #-- interpolate amplitude and phase of the constituent z1 = np.ma.zeros((npts), dtype=z.dtype) z1.mask = np.zeros((npts), dtype=bool) if (METHOD == 'bilinear'): #-- replace invalid values with nan z[z.mask] = np.nan z1.data[:] = bilinear_interp(lon, lat, z, ilon, ilat, dtype=z.dtype) #-- mask invalid values z1.mask[:] |= np.copy(D.mask) z1.data[z1.mask] = z1.fill_value elif (METHOD == 'spline'): f1 = scipy.interpolate.RectBivariateSpline(lon, lat, z.data.real.T, kx=1, ky=1) f2 = scipy.interpolate.RectBivariateSpline(lon, lat, z.data.imag.T, kx=1, ky=1) z1.data.real = f1.ev(ilon, ilat) z1.data.imag = f2.ev(ilon, ilat) #-- mask invalid values z1.mask[:] |= np.copy(D.mask) z1.data[z1.mask] = z1.fill_value else: #-- use scipy regular grid to interpolate values r1 = scipy.interpolate.RegularGridInterpolator( (lat, lon), z.data, method=METHOD, bounds_error=False, fill_value=z1.fill_value) z1.data[:] = r1.__call__(np.c_[ilat, ilon]) #-- mask invalid values z1.mask[:] |= np.copy(D.mask) z1.data[z1.mask] = z1.fill_value #-- extrapolate data using nearest-neighbors if EXTRAPOLATE and np.any(z1.mask): #-- find invalid data points inv, = np.nonzero(z1.mask) #-- replace invalid values with nan z[z.mask] = np.nan #-- extrapolate points within 10km of valid model points z1.data[inv] = nearest_extrap(lon, lat, z, ilon[inv], ilat[inv], dtype=z.dtype, cutoff=10.0) #-- replace nan values with fill_value z1.mask[inv] = np.isnan(z1.data[inv]) z1.data[z1.mask] = z1.fill_value #-- amplitude and phase of the constituent ampl.data[:, i] = np.abs(z1.data) ampl.mask[:, i] = np.copy(z1.mask) ph.data[:, i] = np.arctan2(-np.imag(z1.data), np.real(z1.data)) ph.mask[:, i] = np.copy(z1.mask) elif TYPE in ('U', 'u', 'V', 'v'): #-- read constituent from transport file tr, con = read_transport_file(model_file, TYPE, GZIP=GZIP) #-- append constituent to list constituents.append(con) #-- replace original values with extend matrices tr = extend_matrix(tr) #-- interpolate amplitude and phase of the constituent tr1 = np.ma.zeros((npts), dtype=tr.dtype) tr1.mask = np.zeros((npts), dtype=bool) if (METHOD == 'bilinear'): tr1.data[:] = bilinear_interp(lon, lat, tr, ilon, ilat, dtype=tr.dtype) #-- mask invalid values tr1.mask[:] |= np.copy(D.mask) tr1.data[tr1.mask] = tr1.fill_value elif (METHOD == 'spline'): f1 = scipy.interpolate.RectBivariateSpline(lon, lat, tr.data.real.T, kx=1, ky=1) f2 = scipy.interpolate.RectBivariateSpline(lon, lat, tr.data.imag.T, kx=1, ky=1) tr1.data.real = f1.ev(ilon, ilat) tr1.data.imag = f2.ev(ilon, ilat) #-- mask invalid values tr1.mask[:] |= np.copy(D.mask) tr1.data[tr1.mask] = z1.fill_value else: #-- use scipy regular grid to interpolate values r1 = scipy.interpolate.RegularGridInterpolator( (lat, lon), tr.data, method=METHOD, bounds_error=False, fill_value=tr1.fill_value) tr1.data[:] = r1.__call__(np.c_[ilat, ilon]) #-- mask invalid values tr1.mask[:] |= np.copy(D.mask) tr1.data[tr1.mask] = tr1.fill_value #-- extrapolate data using nearest-neighbors if EXTRAPOLATE and np.any(tr1.mask): #-- find invalid data points inv, = np.nonzero(tr1.mask) #-- replace invalid values with nan tr[tr.mask] = np.nan #-- extrapolate points within 10km of valid model points tr1.data[inv] = nearest_extrap(lon, lat, tr, ilon[inv], ilat[inv], dtype=tr.dtype, cutoff=10.0) #-- replace nan values with fill_value tr1.mask[inv] = np.isnan(tr1.data[inv]) tr1.data[tr1.mask] = tr1.fill_value #-- convert units #-- amplitude and phase of the constituent ampl.data[:, i] = np.abs(tr1.data) / unit_conv ampl.mask[:, i] = np.copy(tr1.mask) ph.data[:, i] = np.arctan2(-np.imag(tr1.data), np.real(tr1.data)) ph.mask[:, i] = np.copy(tr1.mask) #-- convert amplitude from input units to meters amplitude = ampl * SCALE #-- convert phase to degrees phase = ph * 180.0 / np.pi phase[phase < 0] += 360.0 #-- return the interpolated values return (amplitude, phase, D, constituents)
def extract_tidal_constants(ilon, ilat, grid_file, model_file, EPSG, TYPE='z', METHOD='spline', GRID='OTIS'): """ Reads files for an OTIS-formatted tidal model Makes initial calculations to run the tide program Spatially interpolates tidal constituents to input coordinates Arguments --------- ilon: longitude to interpolate ilat: latitude to interpolate grid_file: grid file for model model_file: model file containing each constituent EPSG: projection of tide model data TYPE: tidal variable to run z: heights u: horizontal transport velocities v: vertical transport velocities Keyword arguments ----------------- METHOD: interpolation method bilinear: quick bilinear interpolation spline: scipy bivariate spline interpolation linear, nearest: scipy regular grid interpolations GRID: binary file type to read ATLAS: reading a global solution with localized solutions OTIS: combined global solution Returns ------- amplitude: amplitudes of tidal constituents phase: phases of tidal constituents D: bathymetry of tide model constituents: list of model constituents """ #-- read the OTIS-format tide grid file if (GRID == 'ATLAS'): #-- if reading a global solution with localized solutions x0, y0, hz0, mz0, iob, dt, pmask, local = read_atlas_grid(grid_file) xi, yi, hz = combine_atlas_model(x0, y0, hz0, pmask, local, VARIABLE='depth') mz = create_atlas_mask(x0, y0, mz0, local, VARIABLE='depth') else: #-- if reading a single OTIS solution xi, yi, hz, mz, iob, dt = read_tide_grid(grid_file) #-- adjust dimensions of input coordinates to be iterable #-- run wrapper function to convert coordinate systems of input lat/lon x, y = convert_ll_xy(np.atleast_1d(ilon), np.atleast_1d(ilat), EPSG, 'F') invalid = (x < xi.min()) | (x > xi.max()) | (y < yi.min()) | (y > yi.max()) #-- grid step size of tide model dx = xi[1] - xi[0] dy = yi[1] - yi[0] if (TYPE != 'z'): mz, mu, mv = Muv(hz) hu, hv = Huv(hz) #-- if global: extend limits GLOBAL = False #-- replace original values with extend arrays/matrices if ((xi[-1] - xi[0]) == (360.0 - dx)) & (EPSG == '4326'): xi = extend_array(xi, dx) hz = extend_matrix(hz) mz = extend_matrix(mz) #-- set global flag GLOBAL = True #-- adjust longitudinal convention of input latitude and longitude #-- to fit tide model convention if (np.min(x) < np.min(xi)) & (EPSG == '4326'): lt0, = np.nonzero(x < 0) x[lt0] += 360.0 if (np.max(x) > np.max(xi)) & (EPSG == '4326'): gt180, = np.nonzero(x > 180) x[gt180] -= 360.0 #-- masks zero values hz = np.ma.array(hz, mask=(hz == 0)) if (TYPE != 'z'): #-- replace original values with extend matrices if GLOBAL: hu = extend_matrix(hu) hv = extend_matrix(hv) mu = extend_matrix(mu) mv = extend_matrix(mv) #-- masks zero values hu = np.ma.array(hu, mask=(hu == 0)) hv = np.ma.array(hv, mask=(hv == 0)) #-- interpolate depth and mask to output points if (METHOD == 'bilinear'): #-- use quick bilinear to interpolate values D = bilinear_interp(xi, yi, hz, x, y) mz1 = bilinear_interp(xi, yi, mz, x, y) mz1 = np.ceil(mz1).astype(mz.dtype) if (TYPE != 'z'): mu1 = bilinear_interp(xi, yi, mu, x, y) mu1 = np.ceil(mu1).astype(mu.dtype) mv1 = bilinear_interp(xi, yi, mv, x, y) mv1 = np.ceil(mv1).astype(mz.dtype) elif (METHOD == 'spline'): #-- use scipy bivariate splines to interpolate values f1 = scipy.interpolate.RectBivariateSpline(xi, yi, hz.T, kx=1, ky=1) f2 = scipy.interpolate.RectBivariateSpline(xi, yi, mz.T, kx=1, ky=1) D = f1.ev(x, y) mz1 = np.ceil(f2.ev(x, y)).astype(mz.dtype) if (TYPE != 'z'): f3 = scipy.interpolate.RectBivariateSpline(xi, yi, mu.T, kx=1, ky=1) f4 = scipy.interpolate.RectBivariateSpline(xi, yi, mv.T, kx=1, ky=1) mu1 = np.ceil(f3.ev(x, y)).astype(mu.dtype) mv1 = np.ceil(f4.ev(x, y)).astype(mv.dtype) else: #-- use scipy regular grid to interpolate values for a given method r1 = scipy.interpolate.RegularGridInterpolator((yi, xi), hz, method=METHOD, bounds_error=False) r2 = scipy.interpolate.RegularGridInterpolator((yi, xi), mz, method=METHOD, bounds_error=False, fill_value=0) D = r1.__call__(np.c_[y, x]) mz1 = np.ceil(r2.__call__(np.c_[y, x])).astype(mz.dtype) if (TYPE != 'z'): r3 = scipy.interpolate.RegularGridInterpolator((yi, xi), mu, method=METHOD, bounds_error=False, fill_value=0) r4 = scipy.interpolate.RegularGridInterpolator((yi, xi), mv, method=METHOD, bounds_error=False, fill_value=0) mu1 = np.ceil(r3.__call__(np.c_[y, x])).astype(mu.dtype) mv1 = np.ceil(r4.__call__(np.c_[y, x])).astype(mv.dtype) #-- u and v are velocities in cm/s if TYPE in ('v', 'u'): unit_conv = (D / 100.0) #-- U and V are transports in m^2/s elif TYPE in ('V', 'U'): unit_conv = 1.0 #-- read and interpolate each constituent constituents, nc = read_constituents(model_file) npts = len(D) amplitude = np.ma.zeros((npts, nc)) amplitude.mask = np.zeros((npts, nc), dtype=np.bool) ph = np.ma.zeros((npts, nc)) ph.mask = np.zeros((npts, nc), dtype=np.bool) for i, c in enumerate(constituents): if (TYPE == 'z'): #-- read constituent from elevation file if (GRID == 'ATLAS'): z0, zlocal = read_atlas_elevation(model_file, i, c) xi, yi, z = combine_atlas_model(x0, y0, z0, pmask, zlocal, VARIABLE='z') else: z = read_elevation_file(model_file, i) #-- replace original values with extend matrices if GLOBAL: z = extend_matrix(z) #-- interpolate amplitude and phase of the constituent z1 = np.ma.zeros((npts), dtype=z.dtype) if (METHOD == 'bilinear'): #-- replace zero values with nan z[z == 0] = np.nan #-- use quick bilinear to interpolate values z1.data[:] = bilinear_interp(xi, yi, z, x, y, dtype=np.complex128) #-- replace nan values with fill_value z1.mask = (np.isnan(z1.data) | (~mz1.astype(np.bool))) z1.data[z1.mask] = z1.fill_value elif (METHOD == 'spline'): #-- use scipy bivariate splines to interpolate values f1 = scipy.interpolate.RectBivariateSpline(xi, yi, z.real.T, kx=1, ky=1) f2 = scipy.interpolate.RectBivariateSpline(xi, yi, z.imag.T, kx=1, ky=1) z1.data.real = f1.ev(x, y) z1.data.imag = f2.ev(x, y) #-- replace zero values with fill_value z1.mask = (~mz1.astype(np.bool)) z1.data[z1.mask] = z1.fill_value else: #-- use scipy regular grid to interpolate values r1 = scipy.interpolate.RegularGridInterpolator( (yi, xi), z, method=METHOD, bounds_error=False, fill_value=z1.fill_value) z1 = np.ma.zeros((npts), dtype=z.dtype) z1.data[:] = r1.__call__(np.c_[y, x]) #-- replace invalid values with fill_value z1.mask = (z1.data == z1.fill_value) | (~mz1.astype(np.bool)) z1.data[z1.mask] = z1.fill_value #-- amplitude and phase of the constituent amplitude.data[:, i] = np.abs(z1.data) amplitude.mask[:, i] = np.copy(z1.mask) ph.data[:, i] = np.arctan2(-np.imag(z1.data), np.real(z1.data)) ph.mask[:, i] = np.copy(z1.mask) elif TYPE in ('U', 'u'): #-- read constituent from transport file if (GRID == 'ATLAS'): u0, v0, uvlocal = read_atlas_transport(model_file, i, c) xi, yi, u = combine_atlas_model(x0, y0, u0, pmask, uvlocal, VARIABLE='u') else: u, v = read_transport_file(model_file, i) #-- replace original values with extend matrices if GLOBAL: u = extend_matrix(u) #-- x coordinates for u transports xu = xi - dx / 2.0 #-- interpolate amplitude and phase of the constituent u1 = np.ma.zeros((npts), dtype=u.dtype) if (METHOD == 'bilinear'): #-- replace zero values with nan u[u == 0] = np.nan #-- use quick bilinear to interpolate values u1.data[:] = bilinear_interp(xu, yi, u, x, y, dtype=np.complex128) #-- replace nan values with fill_value u1.mask = (np.isnan(u1.data) | (~mu1.astype(np.bool))) u1.data[u1.mask] = u1.fill_value elif (METHOD == 'spline'): f1 = scipy.interpolate.RectBivariateSpline(xu, yi, u.real.T, kx=1, ky=1) f2 = scipy.interpolate.RectBivariateSpline(xu, yi, u.imag.T, kx=1, ky=1) u1.data.real = f1.ev(x, y) u1.data.imag = f2.ev(x, y) #-- replace zero values with fill_value u1.mask = (~mu1.astype(np.bool)) u1.data[u1.mask] = u1.fill_value else: #-- use scipy regular grid to interpolate values r1 = scipy.interpolate.RegularGridInterpolator( (yi, xu), u, method=METHOD, bounds_error=False, fill_value=u1.fill_value) u1.data[:] = r1.__call__(np.c_[y, x]) #-- replace invalid values with fill_value u1.mask = (u1.data == u1.fill_value) | (~mu1.astype(np.bool)) u1.data[u1.mask] = u1.fill_value #-- convert units u1 = u1 / unit_conv #-- amplitude and phase of the constituent amplitude.data[:, i] = np.abs(u1) amplitude.mask[:, i] = np.copy(u1.mask) ph.data[:, i] = np.arctan2(-np.imag(u1), np.real(u1)) ph.mask[:, i] = np.copy(u1.mask) elif TYPE in ('V', 'v'): #-- read constituent from transport file if (GRID == 'ATLAS'): u0, v0, uvlocal = read_atlas_transport(model_file, i, c) xi, yi, v = combine_atlas_model(x0, y0, v0, pmask, local, VARIABLE='v') else: u, v = read_transport_file(model_file, i) #-- replace original values with extend matrices if GLOBAL: v = extend_matrix(v) #-- y coordinates for v transports yv = yi - dy / 2.0 #-- interpolate amplitude and phase of the constituent v1 = np.ma.zeros((npts), dtype=v.dtype) if (METHOD == 'bilinear'): #-- replace zero values with nan v[v == 0] = np.nan #-- use quick bilinear to interpolate values v1.data = bilinear_interp(xi, yv, v, x, y, dtype=np.complex128) #-- replace nan values with fill_value v1.mask = (np.isnan(v1.data) | (~mv1.astype(np.bool))) v1.data[v1.mask] = v1.fill_value elif (METHOD == 'spline'): f1 = scipy.interpolate.RectBivariateSpline(xi, yv, v.real.T, kx=1, ky=1) f2 = scipy.interpolate.RectBivariateSpline(xi, yv, v.imag.T, kx=1, ky=1) v1.data.real = f1.ev(x, y) v1.data.imag = f2.ev(x, y) #-- replace zero values with fill_value v1.mask = (~mv1.astype(np.bool)) v1.data[v1.mask] = v1.fill_value else: #-- use scipy regular grid to interpolate values r1 = scipy.interpolate.RegularGridInterpolator( (yv, xi), v, method=METHOD, bounds_error=False, fill_value=v1.fill_value) v1.data[:] = r1.__call__(np.c_[y, x]) #-- replace invalid values with fill_value v1.mask = (v1.data == v1.fill_value) | (~mv1.astype(np.bool)) v1.data[v1.mask] = v1.fill_value #-- convert units v1 = v1 / unit_conv #-- amplitude and phase of the constituent amplitude.data[:, i] = np.abs(v1) amplitude.mask[:, i] = np.copy(v1.mask) ph.data[:, i] = np.arctan2(-np.imag(v1), np.real(v1)) ph.mask[:, i] = np.copy(v1.mask) #-- update mask to invalidate points outside model domain ph.mask[:, i] |= invalid amplitude.mask[:, i] |= invalid #-- convert phase to degrees phase = ph * 180.0 / np.pi phase.data[phase.data < 0] += 360.0 #-- replace data for invalid mask values amplitude.data[amplitude.mask] = amplitude.fill_value phase.data[phase.mask] = phase.fill_value #-- return the interpolated values return (amplitude, phase, D, constituents)
def extract_GOT_constants(ilon, ilat, model_files, METHOD=None, EXTRAPOLATE=False, CUTOFF=10.0, GZIP=True, SCALE=1.0): """ Reads files for Richard Ray's Global Ocean Tide (GOT) models Makes initial calculations to run the tide program Spatially interpolates tidal constituents to input coordinates Parameters ---------- ilon: float longitude to interpolate ilat: float latitude to interpolate model_files: list list of model files for each constituent METHOD: str, default 'spline' Interpolation method - ``'bilinear'``: quick bilinear interpolation - ``'spline'``: scipy bivariate spline interpolation - ``'linear'``, ``'nearest'``: scipy regular grid interpolations EXTRAPOLATE: bool, default False Extrapolate model using nearest-neighbors CUTOFF: float, default 10.0 Extrapolation cutoff in kilometers Set to np.inf to extrapolate for all points GZIP: bool, default False Input files are compressed SCALE: float, default 1.0 Scaling factor for converting to output units Returns ------- amplitude: float amplitudes of tidal constituents phase: float phases of tidal constituents constituents: list list of model constituents """ #-- raise warning if model files are entered as a string if isinstance(model_files, str): warnings.warn("Tide model is entered as a string") model_files = [model_files] #-- adjust dimensions of input coordinates to be iterable ilon = np.atleast_1d(ilon) ilat = np.atleast_1d(ilat) #-- number of points npts = len(ilon) #-- number of constituents nc = len(model_files) constituents = [] #-- amplitude and phase amplitude = np.ma.zeros((npts, nc)) amplitude.mask = np.zeros((npts, nc), dtype=bool) ph = np.ma.zeros((npts, nc)) ph.mask = np.zeros((npts, nc), dtype=bool) #-- read and interpolate each constituent for i, model_file in enumerate(model_files): #-- check that model file is accessible if not os.access(os.path.expanduser(model_file), os.F_OK): raise FileNotFoundError(os.path.expanduser(model_file)) #-- read constituent from elevation file hc, lon, lat, cons = read_GOT_grid(os.path.expanduser(model_file), GZIP=GZIP) #-- append to the list of constituents constituents.append(cons) #-- adjust longitudinal convention of input latitude and longitude #-- to fit tide model convention if (np.min(ilon) < 0.0) & (np.max(lon) > 180.0): #-- input points convention (-180:180) #-- tide model convention (0:360) ilon[ilon < 0.0] += 360.0 elif (np.max(ilon) > 180.0) & (np.min(lon) < 0.0): #-- input points convention (0:360) #-- tide model convention (-180:180) ilon[ilon > 180.0] -= 360.0 #-- grid step size of tide model dlon = np.abs(lon[1] - lon[0]) dlat = np.abs(lat[1] - lat[0]) #-- replace original values with extend matrices lon = extend_array(lon, dlon) hc = extend_matrix(hc) #-- interpolated complex form of constituent oscillation hci = np.ma.zeros((npts), dtype=hc.dtype, fill_value=hc.fill_value) hci.mask = np.zeros((npts), dtype=bool) #-- interpolate amplitude and phase of the constituent if (METHOD == 'bilinear'): #-- replace invalid values with nan hc[hc.mask] = np.nan #-- use quick bilinear to interpolate values hci.data[:] = bilinear_interp(lon, lat, hc, ilon, ilat, dtype=hc.dtype) #-- replace nan values with fill_value hci.mask[:] |= np.isnan(hci.data) hci.data[hci.mask] = hci.fill_value elif (METHOD == 'spline'): #-- interpolate complex form of the constituent with scipy f1 = scipy.interpolate.RectBivariateSpline(lon, lat, hc.data.real.T, kx=1, ky=1) f2 = scipy.interpolate.RectBivariateSpline(lon, lat, hc.data.imag.T, kx=1, ky=1) f3 = scipy.interpolate.RectBivariateSpline(lon, lat, hc.mask.T, kx=1, ky=1) hci.data.real[:] = f1.ev(ilon, ilat) hci.data.imag[:] = f2.ev(ilon, ilat) hci.mask[:] = f3.ev(ilon, ilat).astype(bool) #-- replace invalid values with fill_value hci.data[hci.mask] = hci.fill_value else: #-- use scipy regular grid to interpolate values for a given method r1 = scipy.interpolate.RegularGridInterpolator( (lat, lon), hc.data, method=METHOD, bounds_error=False, fill_value=hci.fill_value) r2 = scipy.interpolate.RegularGridInterpolator((lat, lon), hc.mask, method=METHOD, bounds_error=False, fill_value=1) hci.data[:] = r1.__call__(np.c_[ilat, ilon]) hci.mask[:] = np.ceil(r2.__call__(np.c_[ilat, ilon])).astype(bool) #-- replace invalid values with fill_value hci.mask[:] |= (hci.data == hci.fill_value) hci.data[hci.mask] = hci.fill_value #-- extrapolate data using nearest-neighbors if EXTRAPOLATE and np.any(hci.mask): #-- find invalid data points inv, = np.nonzero(hci.mask) #-- replace invalid values with nan hc[hc.mask] = np.nan #-- extrapolate points within cutoff of valid model points hci[inv] = nearest_extrap(lon, lat, hc, ilon[inv], ilat[inv], dtype=hc.dtype, cutoff=CUTOFF) #-- convert amplitude from input units to meters amplitude.data[:, i] = np.abs(hci.data) * SCALE amplitude.mask[:, i] = np.copy(hci.mask) #-- phase of the constituent in radians ph.data[:, i] = np.arctan2(-np.imag(hci.data), np.real(hci.data)) ph.mask[:, i] = np.copy(hci.mask) #-- convert phase to degrees phase = ph * 180.0 / np.pi phase.data[phase.data < 0] += 360.0 #-- replace data for invalid mask values amplitude.data[amplitude.mask] = amplitude.fill_value phase.data[phase.mask] = phase.fill_value #-- return the interpolated values return (amplitude, phase, constituents)