def test_bad_tol_grid_key(self): with pytest.raises(KeyError): # Should raise a key error because the value # for grid is not a key in 'tols' geo_tools.find_closest_model_point(-124.5, 48.5, self.model_lons, self.model_lats, grid="NotAKey")
def test_no_water_pt_found(self): lon, lat = -124.5, 48.555 all_land_land_mask = np.full(self.land_mask.shape, True, dtype=bool) with pytest.raises(ValueError): geo_tools.find_closest_model_point(lon, lat, self.model_lons, self.model_lats, land_mask=all_land_land_mask)
def test_no_land_mask_closest_grid_pt_found(self): lon = -124.5 lat = 48.555 expected = (3, 2) j, i = geo_tools.find_closest_model_point(lon, lat, self.model_lons, self.model_lats) assert (j, i) == expected
def build_GEM_mask(grid_GEM, grid_NEMO, mask_NEMO): """ """ # Preallocate ngrid_GEM = grid_GEM['gridX'].shape[0] * grid_GEM['gridY'].shape[0] mask_GEM = np.zeros(ngrid_GEM, dtype=int) # Evaluate each point on GEM grid bar = utilities.statusbar('Building GEM mask', width=90, maxval=ngrid_GEM) for index, coords in enumerate( bar( zip( grid_GEM['longitude'].values.reshape(ngrid_GEM) - 360, grid_GEM['latitude'].values.reshape(ngrid_GEM), ))): j, i = geo_tools.find_closest_model_point( coords[0], coords[1], grid_NEMO['longitude'], grid_NEMO['latitude'], ) if j is np.nan or i is np.nan: mask_GEM[index] = 0 else: mask_GEM[index] = mask_NEMO[j, i].values # Reshape mask_GEM = mask_GEM.reshape(grid_GEM['longitude'].shape) return mask_GEM
def test_find_water_point(self, lon, lat, expected): j, i = geo_tools.find_closest_model_point(lon, lat, self.model_lons, self.model_lats, land_mask=self.land_mask) assert (j, i) == expected
def retrieve_hindcast_data(lon, lat, date, obs_depth, field, grid_B, mesh_mask): """Gather nowcast field daily mean, min and max at lat, lon on date, interpolated to obs_depth. :arg lon: longitude point :type lon: real number :arg lat: latitude point :type lat: real number :arg date: simulation date :type date: datetime :arg obs_depth: array of depths to be interpolated to :type obs_depth: numpy array :arg field: name of variable to load, e.g 'vosaline' or 'votemper' :type field: string :arg grid_B: model bathymetry :type grid_B: netCDF4 object :arg mesh_mask: model mesh mask :type mesh_mask: netCDF4 object :returns: model_d_interp, model_max, model_min - numpy arrays """ # look up model grid point bathy, lons, lats = tidetools.get_bathy_data(grid_B) j, i = geo_tools.find_closest_model_point(lon, lat, lons, lats, land_mask = bathy.mask) # loading grid_d = results_dataset2('1d', 'grid_T', date) grid_h = results_dataset2('1h', 'grid_T', date) model_d = grid_d.variables[field][0, :, j, i] model_h = grid_h.variables[field][:, :, j, i] if 'gdept' in mesh_mask.variables.keys(): gdep = mesh_mask.variables['gdept'][0, :, j, i] else: gdep = mesh_mask.variables['gdept_0'][0, :, j, i] # masking tmask = mesh_mask.variables['tmask'][:, :, j, i] tmask = 1 - tmask + np.zeros(model_h.shape) model_d = np.ma.array(model_d, mask=tmask[0, :]) gdep_mask = np.ma.array(gdep, mask=tmask[0, :]) model_h = np.ma.array(model_h, mask=tmask) # interpolate to observed depth model_d_interp = comparisons.interpolate_depth(model_d, gdep_mask, obs_depth) model_h_interp = np.zeros((model_h.shape[0], len(obs_depth))) for t in np.arange(model_h.shape[0]): model_h_interp[t, :] = comparisons.interpolate_depth(model_h[t, :], gdep_mask, obs_depth) # daily max and min model_max = np.max(model_h_interp, axis=0) model_min = np.min(model_h_interp, axis=0) return model_d_interp, model_max, model_min
def dothetest(): for j in range(glamt.shape[0]): for i in range(glamt.shape[1]): jfast, ifast = fast_ll2ij_SalishSea201702(glamt[j, i], gphit[j, i], glamt, gphit) jgeo, igeo = find_closest_model_point(glamt[j, i], gphit[j, i], glamt, gphit) if jfast != jgeo or ifast != igeo: print("Mismatch:", ifast, jfast, igeo, jgeo)
def still_inside(time, number): number_of_particles = np.zeros(time) for n in range(time): for m in range(number): if (mask[n,m]) == False: y,x = geo_tools.find_closest_model_point(lont[n,m],latt[n,m],lons, lats, land_mask=bathy.mask) if (598<y<658) and (118<x<134): number_of_particles[n] = number_of_particles[n] + 1 return number_of_particles
def _model_IDW(obs, bathy, grid_T_hr, sal_a, sal_b): """Perform a inverse distance weighted (IDW) interpolation with 8 nearest points to the model value that is nearest to a ferry observation point. :arg obs: Array containing time, lon, lat and salinity or a single point :type obs: numpy array :arg bathy: model bathymetry :type bathy: numpy array :arg grid_T_hr: Hourly tracer results dataset from NEMO. :type grid_T_hr: :class:`netCDF4.Dataset` :arg sal_a: 1.5 m depth for 3 am (if TWDP route, 2am) :type sal_a: numpy array :arg sal_b: 1.5 m depth for 4 am (if TWDP route, 3am) :arg sal_b: numpy array :returns: integral of model salinity values divided by weights for sal_a and sal_b. """ lats = grid_T_hr.variables['nav_lat'][:, :] lons = grid_T_hr.variables['nav_lon'][:, :] depths = bathy.variables['Bathymetry'][:] x1, y1 = geo_tools.find_closest_model_point( obs[1], obs[2], lons, lats) # Removed 'lat_tol=0.00210' # Inverse distance weighted interpolation with the 8 nearest model values. val_a_sum = 0 val_b_sum = 0 weight_sum = 0 # Some ferry model routes go over land, replace locations when 4 or # more of the surrounding grid point are land with NaN. interp_area = sal_a[x1 - 1:x1 + 2, y1 - 1:y1 + 2] if interp_area.size - np.count_nonzero(interp_area) >= 4: sal_a_idw = np.NaN sal_b_idw = np.NaN else: for i in np.arange(x1 - 1, x1 + 2): for j in np.arange(y1 - 1, y1 + 2): # Some adjacent points are land we don't count them into the # salinity average. if depths[i, j] > 0: dist = geo_tools.haversine(obs[1], obs[2], lons[i, j], lats[i, j]) weight = 1.0 / dist weight_sum += weight val_a = sal_a[i, j] * weight val_b = sal_b[i, j] * weight val_a_sum += val_a val_b_sum += val_b sal_a_idw = val_a_sum / weight_sum sal_b_idw = val_b_sum / weight_sum return sal_a_idw, sal_b_idw
def go(): #for j in range(glamt.shape[0]): # for i in range(glamt.shape[1]): for j in range(380, 450): for i in range(280, 350): jfast, ifast = fast_ll2ij_SalishSea201702(glamt[j, i], gphit[j, i], glamt, gphit) jgeo, igeo = find_closest_model_point(glamt[j, i], gphit[j, i], glamt, gphit) if jfast != jgeo or ifast != igeo: print(ifast, jfast, igeo, jgeo)
def test_no_land_mask_1_grid_pt_found(self): lon, lat = -124.49885559, 48.54185486 expected = (1, 1) j, i = geo_tools.find_closest_model_point( lon, lat, self.model_lons, self.model_lats, grid='test', tols={'test': { 'tol_lon': 0.000001, 'tol_lat': 0.000001 }}) assert (j, i) == expected
def load_model_data(sdt, edt, grid_B, results_home, period, variable, lat, lon): """Load the model data in date range of interest and at the location. :arg sdt: the start date :type sdt: datetime object :arg edt: the end date :type edt: datetime object :arg grid_B: the model bathymetry :type grid_B: netCDF4 handle :arg results_home: directory for model results :type restuls_home: string :arg period: the model avergaing period eg '1h' or '1d' :time period: string :arg variable: the variable to be loaded, eg 'vosaline' or 'votemper' :type variable: string. :arg lat: the latitude :type lat: float :arg lon: the longitude :type lon: float :returns: var, times, mdepths - the array of data, the times associated and the model depth array """ files = analyze.get_filenames(sdt, edt, period, 'grid_T', results_home) ftmp = nc.Dataset(files[0]) mdepths = ftmp.variables['deptht'][:] # Model grid X = grid_B.variables['nav_lon'][:] Y = grid_B.variables['nav_lat'][:] bathy = grid_B.variables['Bathymetry'][:] # Look up grid coordinates j, i = geo_tools.find_closest_model_point(lon, lat, X, Y) # Grab model data var, times = analyze.combine_files(files, variable, np.arange(mdepths.shape[0]), j, i) print('Model bathymetry:', bathy[j, i]) return var, times, mdepths
def get_model_time_series(station, fnames, grid_B, mesh_mask, nemo_36=True): """Retrieve the density, salinity and temperature time series at a station. Time series is created from files listed in fnames""" if nemo_36: depth_var = 'gdept_0' depth_var_w = 'gdepw_0' else: depth_var = 'gdept' depth_var_w = 'gdepw' # station info lon = places.PLACES[station]['lon lat'][0] lat = places.PLACES[station]['lon lat'][1] depth = places.PLACES[station]['depth'] # model corresponding locations and variables bathy, X, Y = tidetools.get_bathy_data(grid_B) j, i = geo_tools.find_closest_model_point(lon, lat, X, Y, land_mask=bathy.mask) model_depths = mesh_mask.variables[depth_var][0, :, j, i] tmask = mesh_mask.variables['tmask'][0, :, j, i] wdeps = mesh_mask.variables[depth_var_w][0, :, j, i] sal, time = analyze.combine_files(fnames, 'vosaline', 'None', j, i) temp, time = analyze.combine_files(fnames, 'votemper', 'None', j, i) # interpolate: sal_interp = np.array([ shared.interpolate_tracer_to_depths(sal[d, :], model_depths, depth, tmask, wdeps) for d in range(sal.shape[0]) ]) temp_interp = np.array([ shared.interpolate_tracer_to_depths(temp[d, :], model_depths, depth, tmask, wdeps) for d in range(temp.shape[0]) ]) # convert to psu for using density function return sal_interp, temp_interp, time
def loadDataFRP_SSGrid( exp='all', sel='narrow', meshPath='/ocean/eolson/MEOPAR/NEMO-forcing/grid/mesh_mask201702.nc'): import gsw # only in this function; use to convert p to z if exp not in {'exp1', 'exp2', 'all'}: print('option exp=' + exp + ' is not defined.') raise if sel not in {'narrow', 'wide'}: print('option sel=' + sel + ' is not defined.') raise df0, clist, tcor, cast19, cast25 = loadDataFRP_init(exp=exp) # load mesh mesh = nc.Dataset(meshPath, 'r') tmask = mesh.variables['tmask'][0, :, :, :] gdept = mesh.variables['gdept_0'][0, :, :, :] gdepw = mesh.variables['gdepw_0'][0, :, :, :] nav_lat = mesh.variables['nav_lat'][:, :] nav_lon = mesh.variables['nav_lon'][:, :] mesh.close() zCasts = dict() for nn in clist: ip = np.argmax(cast25[nn].df['prSM'].values) ilag = df0.loc[df0.Station == nn, 'ishift_sub19'].values[0] pS_pr = df0.loc[df0.Station == nn, 'pS_pr'].values[0] pE_pr = df0.loc[df0.Station == nn, 'pE_pr'].values[0] pS_tur = df0.loc[df0.Station == nn, 'pStart25'].values[0] pE_tur = df0.loc[df0.Station == nn, 'pEnd25'].values[0] if sel == 'narrow': pS = pS_tur pE = pE_tur prebin = False elif sel == 'wide': pS = pS_pr pE = pE_pr prebin = True jj, ii = geo_tools.find_closest_model_point( df0.loc[df0.Station == nn]['LonDecDeg'].values[0], df0.loc[df0.Station == nn]['LatDecDeg'].values[0], nav_lon, nav_lat) zmax = -1 * gsw.z_from_p(cast25[nn].df.loc[ip, 'prSM'], df0.loc[df0.Station == nn]['LatDecDeg']) edges = gdepw[:, jj, ii] targets = gdept[:, jj, ii] edges = edges[edges < zmax] targets = targets[:(len(edges) - 1)] parDZ = .78 xmisDZ = .36 turbDZ = .67 zshiftdict = { 'gsw_ctA0': 0.0, 'gsw_srA0': 0.0, 'xmiss': xmisDZ, 'seaTurbMtr': turbDZ, 'par': parDZ, 'wetStar': 0.0, 'sbeox0ML_L': 0.0 } dCast = pd.DataFrame() uCast = pd.DataFrame() for var in ('gsw_ctA0', 'gsw_srA0', 'xmiss', 'par', 'wetStar', 'sbeox0ML_L'): if not nn == 14.2: #downcast inP = -1 * gsw.z_from_p( cast25[nn].df.loc[pS:ip]['prSM'].values, df0.loc[df0.Station == nn]['LatDecDeg']) - zshiftdict[ var] # down z inV = cast25[nn].df.loc[pS:ip][var].values # down var if sel == 'wide': inV[inP < .1] = np.nan p, out = bindepth(inP, inV, edges=edges, targets=targets, prebin=prebin) if var == 'gsw_ctA0': dCast = pd.DataFrame(p, columns=['depth_m']) dCast['indk'] = np.arange(0, len(p)) dCast[var] = out else: # special case where there is no downcast if var == 'gsw_ctA0': dCast = pd.DataFrame(np.nan * np.ones(10), columns=['depth_m']) dCast['indk'] = np.nan * np.ones(10) dCast[var] = np.nan * np.ones(10) if not nn == 14.1: #upcast inP = -1 * gsw.z_from_p( cast25[nn].df.loc[ip:pE]['prSM'].values, df0.loc[df0.Station == nn]['LatDecDeg']) - zshiftdict[ var] # down z inV = cast25[nn].df.loc[ip:pE][var].values # down var if sel == 'wide': inV[inP < .1] = np.nan p, out = bindepth(inP, inV, edges=edges, targets=targets, prebin=prebin) if var == 'gsw_ctA0': uCast = pd.DataFrame(p, columns=['depth_m']) uCast['indk'] = np.arange(0, len(p)) uCast[var] = out else: # special case where there is no upcast if var == 'gsw_ctA0': uCast = pd.DataFrame(np.nan * np.ones(10), columns=['depth_m']) uCast['indk'] = np.nan * np.ones(10) uCast[var] = np.nan * np.ones(10) if not nn == 14.2: #turbidity downcast inP = -1 * gsw.z_from_p( cast25[nn].df.loc[pS:ip]['prSM'].values, df0.loc[df0.Station == nn]['LatDecDeg']) - turbDZ # down z inV0 = cast19[nn].df.loc[(pS + ilag):( ip + ilag)]['seaTurbMtr'].values # down var if sel == 'wide': # additional QC for broader data selection ii1 = amp(rolling_window_padded(inV0, 5), -1) > .5 * np.nanmax(inV0) # get rid of near-zero turbidity values; seem to be dropped signal ii2 = np.nanmin(rolling_window_padded(inV0, 5), -1) < .3 inV0[np.logical_or(ii1, ii2)] = np.nan inV = ssig.medfilt(inV0, 3) # down var if sel == 'wide': # exclude above surface data with np.errstate(invalid='ignore'): inV[inP < .1] = np.nan p, tur = bindepth(inP, inV, edges=edges, targets=targets, prebin=prebin) dCast['turb'] = tur * 1.0 / tcor else: # special case where there is no downcast dCast['turb'] = np.nan * np.ones(10) if not nn == 14.1: #turbidity upcast inP = -1 * gsw.z_from_p( cast25[nn].df.loc[ip:pE]['prSM'].values, df0.loc[df0.Station == nn]['LatDecDeg']) - turbDZ # up z inV0 = cast19[nn].df.loc[(ip + ilag):( pE + ilag)]['seaTurbMtr'].values # up var if sel == 'wide': # additional QC for broader data selection ii1 = amp(rolling_window_padded(inV0, 5), -1) > .5 * np.nanmax(inV0) # get rid of near-zero turbidity values; seem to be dropped signal ii2 = np.nanmin(rolling_window_padded(inV0, 5), -1) < .3 inV0[np.logical_or(ii1, ii2)] = np.nan inV = ssig.medfilt(inV0, 3) # down var if sel == 'wide': # exclude above surface data with np.errstate(invalid='ignore'): inV[inP < .1] = np.nan p, tur = bindepth(inP, inV, edges=edges, targets=targets, prebin=prebin) uCast['turb'] = tur * 1.0 / tcor else: # special case where there is no upcasts uCast['turb'] = np.nan * np.ones(10) zCasts[nn] = zCast(uCast, dCast) # fix first 2 casts for which sb25 pump did not turn on. use sb19 if (exp == 'exp1' or exp == 'all'): for nn in range(1, 3): uCast = zCasts[nn].uCast dCast = zCasts[nn].dCast ip = np.argmax(cast25[nn].df['prSM'].values) ilag = df0.loc[df0.Station == nn, 'ishift_sub19'].values[0] pS_pr = df0.loc[df0.Station == nn, 'pS_pr'].values[0] pE_pr = df0.loc[df0.Station == nn, 'pE_pr'].values[0] pS_tur = df0.loc[df0.Station == nn, 'pStart25'].values[0] pE_tur = df0.loc[df0.Station == nn, 'pEnd25'].values[0] if sel == 'narrow': pS = pS_tur pE = pE_tur elif sel == 'wide': pS = pS_pr pE = pE_pr jj, ii = geo_tools.find_closest_model_point( df0.loc[df0.Station == nn]['LonDecDeg'].values[0], df0.loc[df0.Station == nn]['LatDecDeg'].values[0], nav_lon, nav_lat) zmax = -1 * gsw.z_from_p(cast25[nn].df.loc[ip, 'prSM'], df0.loc[df0.Station == nn]['LatDecDeg']) edges = gdepw[:, jj, ii] targets = gdept[:, jj, ii] edges = edges[edges < zmax] targets = targets[:(len(edges) - 1)] ##temperature #downcast inP = -1 * gsw.z_from_p( cast25[nn].df.loc[pS:ip]['prSM'].values, df0.loc[df0.Station == nn]['LatDecDeg']) # down z inV = cast19[nn].df.loc[(pS + ilag):( ip + ilag)]['gsw_ctA0'].values # down var if sel == 'wide': inV[inP < .1] = np.nan p, out = bindepth(inP, inV, edges=edges, targets=targets, prebin=prebin) dCast['gsw_ctA0'] = out #upcast inP = -1 * gsw.z_from_p( cast25[nn].df.loc[ip:pE]['prSM'].values, df0.loc[df0.Station == nn]['LatDecDeg']) # up z inV = cast19[nn].df.loc[(ip + ilag):(pE + ilag)]['gsw_ctA0'].values # up var if sel == 'wide': inV[inP < .1] = np.nan p, out = bindepth(inP, inV, edges=edges, targets=targets, prebin=prebin) uCast['gsw_ctA0'] = out ##sal #downcast inP = -1 * gsw.z_from_p( cast25[nn].df.loc[pS:ip]['prSM'].values, df0.loc[df0.Station == nn]['LatDecDeg']) # down z inV = cast19[nn].df.loc[(pS + ilag):( ip + ilag)]['gsw_srA0'].values # down var if sel == 'wide': inV[inP < .1] = np.nan p, out = bindepth(inP, inV, edges=edges, targets=targets, prebin=prebin) dCast['gsw_srA0'] = out #upcast inP = -1 * gsw.z_from_p( cast25[nn].df.loc[ip:pE]['prSM'].values, df0.loc[df0.Station == nn]['LatDecDeg']) # up z inV = cast19[nn].df.loc[(ip + ilag):(pE + ilag)]['gsw_srA0'].values # up var if sel == 'wide': inV[inP < .1] = np.nan p, out = bindepth(inP, inV, edges, prebin=prebin) uCast['gsw_srA0'] = out ##xmiss: xmis25=1.14099414691*xmis19+-1.6910134322 #downcast inP = -1 * gsw.z_from_p( cast25[nn].df.loc[pS:ip]['prSM'].values, df0.loc[df0.Station == nn]['LatDecDeg']) - xmisDZ # down z inV = 1.14099414691 * cast19[nn].df.loc[(pS + ilag):( ip + ilag)]['CStarTr0'].values - 1.6910134322 # down var if sel == 'wide': inV[inP < .1] = np.nan p, out = bindepth(inP, inV, edges=edges, targets=targets, prebin=prebin) dCast['xmiss'] = out #upcast inP = -1 * gsw.z_from_p( cast25[nn].df.loc[ip:pE]['prSM'].values, df0.loc[df0.Station == nn]['LatDecDeg']) - xmisDZ # up p inV = 1.14099414691 * cast19[nn].df.loc[(ip + ilag):( pE + ilag)]['CStarTr0'].values - 1.6910134322 # up var if sel == 'wide': inV[inP < .1] = np.nan p, out = bindepth(inP, inV, edges=edges, targets=targets, prebin=prebin) uCast['xmiss'] = out uCast['wetStar'] = np.nan dCast['wetStar'] = np.nan uCast['sbeox0ML_L'] = np.nan dCast['sbeox0ML_L'] = np.nan zCasts[nn] = zCast(uCast, dCast) return df0, zCasts
def find_model_dat(w, fname, datname): model_dat = np.nan #if the stn has lat, lons not findable in model (ie, out of model domain) this will change to the # of the station stn_with_nans = 9999 #if the observations have data but the model has a 0, these (_f = faulty) record model lat,lon,depth w_f = 9999 d_f = 9999 i_f = 9999 j_f = 9999 #find closest model point, check that it's not nan, if it is, record it j, i = geo_tools.find_closest_model_point(lon[w], lat[w], nav_lon, nav_lat) j_ref = j i_ref = i if (np.isnan(i) | np.isnan(j)): stn_with_nans = stn[w] #extract model depths from model, for comparison with obs q2 = nc.Dataset( '/results2/SalishSea/nowcast-green.201806/01jan18/SalishSea_1h_20180101_20180101_grid_T.nc' ) dep = q2.variables['deptht'] d_mod = dep[:] #months, to make a path to model data mons = [ 'jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec' ] month = mon[w] #TJ check for month in may or later, findable station, and good quality flag, and dic>0 (should be redundant) if ((month >= 5) & (~np.isnan(j)) & (~np.isnan(i)) & ((dic_qf[w] == 2) | (dic_qf[w] == 6)) & (dic[w] > 0)): #from month and day, make string to mon_name = str(mons[int(month) - 1]) day_name = str(int(day[w])) if len(day_name) == 1: day_name = '0' + day_name modpath = day_name + mon_name + '17/' bigpath = '/results2/SalishSea/hindcast.201812_annex/' if datname == 'carp': ncpath = 'SalishSea_1d_*_carp_T.nc' if datname == 'ptrc': ncpath = 'SalishSea_1d_*_ptrc_T.nc' else: ncpath = 'SalishSea_1d_*_grid_T.nc' q = glob.glob(bigpath + modpath + ncpath) #depths of observations dtt = P[w] #find closest depth in model - print if necesary close = np.abs(d_mod - dtt) t_depth = np.argmin(close) depth_mod = d_mod[t_depth] # print('DEPTH IND: '+str(t_depth)) # print('DEPTH : '+str(depth_mod)) #open dataset, record relevant model DIC qnc = nc.Dataset(q[0]) model_dat = qnc.variables[fname][0, t_depth, j, i] # flag spots where model gives 0s. if (model_dat == 0): # we have # print('*******') # print('index of grl data: '+str(w)) # print('depth in grl data: '+str(P[w])) # print('j index: '+str(j)) # print('i index: '+str(i)) # print('DEPTH IND: '+str(t_depth)) # print('DEPTH : '+str(depth_mod)) w_f = w j_f = j i_f = i d_f = t_depth # print('Data dic: '+str( dic[w])) # print('Data dic qf: '+str( dic_qf[w])) # print('Model dic '+str(model_dat)) return model_dat, stn_with_nans, j_f, i_f, d_f, w_f, j_ref, i_ref
def plot_files(ax, grid_B, files, var, depth, t_orig, t_final, name, label, colour): """Plots values of variable over multiple files covering a certain period of time. :arg ax: The axis where the variable is plotted. :type ax: axis object :arg grid_B: Bathymetry dataset for the Salish Sea NEMO model. :type grid_B: :class:`netCDF4.Dataset` :arg files: Multiple result files in chronological order. :type files: list :arg var: Name of variable (sossheig = sea surface height, vosaline = salinity, votemper = temperature, vozocrtx = Velocity U-component, vomecrty = Velocity V-component). :type var: string :arg depth: Depth of model results ('None' if var=sossheig). :type depth: integer or string :arg t_orig: The beginning of the date range of interest. :type t_orig: datetime object :arg t_final: The end of the date range of interest. :type t_final: datetime object :arg name: The name of the station. :type name: string :arg label: Label for plot line. :type label: string :arg colour: Colour of plot lines. :type colour: string :returns: matplotlib figure object instance (fig) and axis object (ax). """ # Stations information lat = figures.SITES[name]['lat'] lon = figures.SITES[name]['lon'] # Bathymetry bathy, X, Y = tidetools.get_bathy_data(grid_B) # Get index [j, i] = geo_tools.find_closest_model_point(lon, lat, X, Y, land_mask=bathy.mask) # Call function var_ary, time = combine_files(files, var, depth, j, i) # Plot ax.plot(time, var_ary, label=label, color=colour, linewidth=2.5) # Figure format ax_start = t_orig ax_end = t_final + datetime.timedelta(days=1) ax.set_xlim(ax_start, ax_end) hfmt = mdates.DateFormatter('%m/%d %H:%M') ax.xaxis.set_major_formatter(hfmt) return ax
def get_error_model(names, runs_list, grid_B, t_orig): """ Sets up the calculation for the model residual error. :arg names: Names of station. :type names: list of strings :arg runs_list: Runs that have been verified as complete. :type runs_list: list :arg grid_B: Bathymetry dataset for the Salish Sea NEMO model. :type grid_B: :class:`netCDF4.Dataset` :arg t_orig: Date being considered. :type t_orig: datetime object :returns: error_mod_dict, t_mod_dict, t_orig_dict """ bathy, X, Y = tidetools.get_bathy_data(grid_B) t_orig_obs = t_orig + datetime.timedelta(days=-1) t_final_obs = t_orig + datetime.timedelta(days=1) # truncation times sdt = t_orig.replace(tzinfo=tz.tzutc()) edt = sdt + datetime.timedelta(days=1) error_mod_dict = {} t_mod_dict = {} for name in names: error_mod_dict[name] = {} t_mod_dict[name] = {} # Look up model grid lat = figures.SITES[name]['lat'] lon = figures.SITES[name]['lon'] j, i = geo_tools.find_closest_model_point(lon, lat, X, Y, land_mask=bathy.mask) # Observed residuals and wlevs and tides ttide = figures.shared.get_tides(name, path=paths['tides']) res_obs, wlev_meas = obs_residual_ssh(name, ttide, t_orig_obs, t_final_obs) res_obs_trun, time_obs_trun = analyze.truncate_data( np.array(res_obs), np.array(wlev_meas.time), sdt, edt) for mode in runs_list: filename, run_date = analyze.create_path( mode, t_orig, 'SalishSea_1h_*_grid_T.nc') grid_T = nc.Dataset(filename) res_mod, t_model, ssh_corr, ssh_mod = model_residual_ssh( grid_T, j, i, ttide) # Truncate res_mod_trun, t_mod_trun = analyze.truncate_data( res_mod, t_model, sdt, edt) # Error error_mod = analyze.calculate_error(res_mod_trun, t_mod_trun, res_obs_trun, time_obs_trun) error_mod_dict[name][mode] = error_mod t_mod_dict[name][mode] = t_mod_trun return error_mod_dict, t_mod_dict
def plot_residual_model(axs, names, runs_list, grid_B, t_orig): """ Plots the observed sea surface height residual against the sea surface height model residual (calculate_residual) at specified stations. Function may produce none, any, or all (nowcast, forecast, forecast 2) model residuals depending on availability for specified date (runs_list). :arg ax: The axis where the residuals are plotted. :type ax: list of axes :arg names: Names of station. :type names: list of names :arg runs_list: Runs that have been verified as complete. :type runs_list: list :arg grid_B: Bathymetry dataset for the Salish Sea NEMO model. :type grid_B: :class:`netCDF4.Dataset` :arg t_orig: Date being considered. :type t_orig: datetime object """ bathy, X, Y = tidetools.get_bathy_data(grid_B) t_orig_obs = t_orig + datetime.timedelta(days=-1) t_final_obs = t_orig + datetime.timedelta(days=1) # truncation times sdt = t_orig.replace(tzinfo=tz.tzutc()) edt = sdt + datetime.timedelta(days=1) for ax, name in zip(axs, names): # Identify model grid point lat = figures.SITES[name]['lat'] lon = figures.SITES[name]['lon'] j, i = geo_tools.find_closest_model_point(lon, lat, X, Y, land_mask=bathy.mask) # Observed residuals and wlevs and tides ttide = figures.shared.get_tides(name, path=paths['tides']) res_obs, wlev_meas = obs_residual_ssh(name, ttide, t_orig_obs, t_final_obs) # truncate and plot res_obs_trun, time_obs_trun = analyze.truncate_data( np.array(res_obs), np.array(wlev_meas.time), sdt, edt) ax.plot(time_obs_trun, res_obs_trun, c=colours['observed'], lw=2.5, label='observed') for mode in runs_list: filename, run_date = analyze.create_path( mode, t_orig, 'SalishSea_1h_*_grid_T.nc') grid_T = nc.Dataset(filename) res_mod, t_model, ssh_corr, ssh_mod = model_residual_ssh( grid_T, j, i, ttide) # truncate and plot res_mod_trun, t_mod_trun = analyze.truncate_data( res_mod, t_model, sdt, edt) ax.plot(t_mod_trun, res_mod_trun, label=mode, c=colours[mode], lw=2.5) ax.set_title('Comparison of modelled sea surface height residuals at' ' {station}: {t:%d-%b-%Y}'.format(station=name, t=t_orig))
def compare_VENUS(station, grid_T, grid_B, figsize=(6, 10)): """Compares the model's temperature and salinity with observations from VENUS station. :arg station: Name of the station ('East' or 'Central') :type station: string :arg grid_T: Hourly tracer results dataset from NEMO. :type grid_T: :class:`netCDF4.Dataset` :arg grid_B: Bathymetry dataset for the Salish Sea NEMO model. :type grid_B: :class:`netCDF4.Dataset` :arg figsize: Figure size (width, height) in inches. :type figsize: 2-tuple :returns: matplotlib figure object instance (fig). """ # Time range t_orig, t_end, t = figures.get_model_time_variables(grid_T) # Bathymetry bathy, X, Y = tt.get_bathy_data(grid_B) # VENUS data fig, (ax_sal, ax_temp) = plt.subplots(2, 1, figsize=figsize, sharex=True) fig.patch.set_facecolor('#2B3E50') fig.autofmt_xdate() lon = SITES['VENUS'][station]['lon'] lat = SITES['VENUS'][station]['lat'] depth = SITES['VENUS'][station]['depth'] # Plotting observations plot_VENUS(ax_sal, ax_temp, station, t_orig, t_end) # Grid point of VENUS station [j, i] = geo_tools.find_closest_model_point( lon, lat, X, Y) # Model data sal = grid_T.variables['vosaline'][:, :, j, i] temp = grid_T.variables['votemper'][:, :, j, i] ds = grid_T.variables['deptht'] # Interpolating data salc = [] tempc = [] for ind in np.arange(0, sal.shape[0]): salc.append(figures.interpolate_depth(sal[ind, :], ds, depth)) tempc.append(figures.interpolate_depth(temp[ind, :], ds, depth)) # Plot model data ax_sal.plot(t, salc, '-b', label='Model') ax_temp.plot(t, tempc, '-b', label='Model') # Axis ax_sal.set_title(f'VENUS {station} - {t[0].strftime("%d-%b-%Y")}') ax_sal.set_ylim([29, 32]) ax_sal.set_ylabel('Practical Salinity [psu]', **axis_font) ax_sal.legend(loc=0) ax_temp.set_ylim([7, 13]) ax_temp.set_xlabel('Time [UTC]', **axis_font) ax_temp.set_ylabel('Temperature [deg C]', **axis_font) figures.axis_colors(ax_sal, 'gray') figures.axis_colors(ax_temp, 'gray') # Text box ax_temp.text(0.25, -0.3, 'Observations from Ocean Networks Canada', transform=ax_temp.transAxes, color='white') return fig
def test_raises_value_error(self): with pytest.raises(ValueError): # lat and lon values that aren't on this grid (0, 0) geo_tools.find_closest_model_point(0, 0, self.model_lons, self.model_lats)
def compare_model(to, tf, lighthouse, mode, period, grid_B, smin=28, smax=33, tmin=6, tmax=14): """Compare model surface salinity with lighthouse observations in a date range. :arg to: the beginning of the date range :type to: datetime object :arg tf: the end of the date range :type tf: datetime object :arg lighthouse: the name of the lighthouse :type lighthouse: string :arg mode: the model simulation mode - nowcast or spinup or nowcast-green :type mode: string :arg period: the averaging period for model results - 1h or 1d :type period: string :arg grid_B: NEMO bathymetry grid :type grid_B: netCDF4 handle :arg smin: minumum salinity for axis limits :type smin: float :arg smax: maximium salinity for axis limits :type smax: float :arg tmin: minumum temperature for axis limits :type tmin: float :arg tmax: maximium temperature for axis limits :type tmax: float :returns: fig, a figure object """ # Load observations data, lat, lon = load_lighthouse(LIGHTHOUSES[lighthouse]) # Look up modle grid point X = grid_B.variables['nav_lon'][:] Y = grid_B.variables['nav_lat'][:] j, i = geo_tools.find_closest_model_point(lon, lat, X, Y) # load model files = analyze.get_filenames(to, tf, period, 'grid_T', MODEL_PATHS[mode]) sal, time = analyze.combine_files(files, 'vosaline', 0, j, i) if mode == 'nowcast-green': sal = teos_tools.teos_psu(sal) temp, time = analyze.combine_files(files, 'votemper', 0, j, i) if period == '1h': # look up times of high tides ssh, times = analyze.combine_files(files, 'sossheig', 'None', j, i) max_inds = daytime_hightide(ssh, times) sal = sal[max_inds] temp = temp[max_inds] time = time[max_inds] title_str = 'max daytime tides' else: title_str = 'daily average' # plotting fig, axs = plt.subplots(1, 2, figsize=(15, 5)) # plot time series # salinity ax = axs[0] ax.plot(time, sal, label=mode) ax.plot(data['date'], data['Salinity(psu)'], label='observations') ax.legend(loc=0) ax.set_title('{} Salinity - {}'.format(lighthouse, title_str)) ax.set_xlim([to, tf]) ax.set_ylim([smin, smax]) ax.set_ylabel('Salinity [psu]') # temperature ax = axs[1] ax.plot(time, temp, label=mode) ax.plot(data['date'], data['Temperature(C)'], label='observations') ax.legend(loc=0) ax.set_title('{} Temperature - {}'.format(lighthouse, title_str)) ax.set_xlim([to, tf]) ax.set_ylim([tmin, tmax]) ax.set_ylabel('Temperature [deg C]') fig.autofmt_xdate() return fig
def find_model_dat(w, fname, datname, firstmo, yr, path_to_ncs): "Usage: " model_dat = np.nan #if the stn has lat, lons not findable in model (ie, out of model domain) this will change to the # of the station stn_with_nans = 9999 #if the observations have data but the model has a 0, these (_f = faulty) record model lat,lon,depth w_f = 9999 d_f = 9999 i_f = 9999 j_f = 9999 #find closest model point, check that it's not nan, if it is, record it j, i = geo_tools.find_closest_model_point(lon[w], lat[w], nav_lon, nav_lat) j_ref = j i_ref = i if (np.isnan(i) | np.isnan(j)): stn_with_nans = stn[w] #extract model depths from model, for comparison with obs q2 = nc.Dataset( '/results2/SalishSea/hindcast.201905/07apr10/SalishSea_1h_20100407_20100407_grid_T.nc' ) dep = q2.variables['deptht'] d_mod = dep[:] month = mon[w] #TJ check for month in first month or later, findable station, and good quality flag, and dic>0 (should be redundant) if ((month >= firstmo) & (~np.isnan(j)) & (~np.isnan(i)) & ((dic_qf[w] == 2) | (dic_qf[w] == 6)) & (dic[w] > 0)): #from month and day, make string to #mon_name = str(mons[int(month)-1]) mon_name = str(int(mon[w])) if len(mon_name) == 1: mon_name = '0' + mon_name day_name = str(int(day[w])) if len(day_name) == 1: day_name = '0' + day_name #modpath = day_name+mon_name+ yr+'/' start = '20' + yr + '-' + mon_name + '-' + day_name tdate = arrow.get(start) ymd = tdate.format('YYYYMMDD') print(ymd) bigpath = path_to_ncs #print(datname) ncpath = '/' + datname + '_1d_' + ymd + '.nc' q = glob.glob(bigpath + ncpath) #depths of observations dtt = P[w] #find closest depth in model - print if necesary close = np.abs(d_mod - dtt) t_depth = np.argmin(close) depth_mod = d_mod[t_depth] # print('DEPTH IND: '+str(t_depth)) # print('DEPTH : '+str(depth_mod)) #open dataset, record relevant model DIC qnc = nc.Dataset(q[0]) #print(qnc) #print(fname) model_dat = qnc['model_output'][fname][t_depth, j, i] # flag spots where model gives 0s. if (model_dat == 0): # we have # print('*******') # print('index of grl data: '+str(w)) # print('depth in grl data: '+str(P[w])) # print('j index: '+str(j)) # print('i index: '+str(i)) # print('DEPTH IND: '+str(t_depth)) # print('DEPTH : '+str(depth_mod)) w_f = w j_f = j i_f = i d_f = t_depth # print('Data dic: '+str( dic[w])) # print('Data dic qf: '+str( dic_qf[w])) # print('Model dic '+str(model_dat)) return model_dat, stn_with_nans, j_f, i_f, d_f, w_f, j_ref, i_ref