def _update_eos(self): assert hasattr(self, 'd_depth'), \ 'You need to run clean_and_depth_bin first' d = self.d_depth d['SA'] = gsw.SA_from_SP(d.salinity, d.index, d.longitude, d.latitude) d['CT'] = gsw.CT_from_t(d.SA, d.temperature, d.index) d['sound_speed'] = gsw.sound_speed(d.SA, d.CT, d.index)
def water_properties(sp, t, p, lon=0.0, lat=0.0): """ Calculates seawater density and sound speed using the TEOS-10 equations. Uses the gsw toolbox, which is an implementation of the TEOS-10 equations. Args: :sp: Practical salinity [PSU] :t: Temperature [degC] :p: Pressure [dbar] :lon: Longitude (optional - use named parameters) [decimal degrees] :lat: Latitude (optional - use named parameters) [decimal degrees] Returns: :c: speed of sound in water [m/s] :rho: density of water [kg/m^3] Notes: The accuracy of sound speed and density that we need is such that it doesn't matter what latitude and longitude is used. """ sa = gsw.SA_from_SP(sp, p, lon, lat) ct = gsw.CT_from_t(sa, t, p) c = gsw.sound_speed(sa, ct, p) rho = gsw.rho(sa, ct, p) return c, rho
def comp_rhostar(Si, Ti, lat): pi = gsw.p_from_z(-zref, lat) cs = gsw.sound_speed(Si, Ti, pi) Ri = gsw.rho(Si, Ti, pi) g = gsw.grav(lat, pi[0]) E = np.zeros((len(zref), )) #plt.plot(Ri, -zref) f = interpolate.interp1d(zref, cs) def e(x): return -g / f(x)**2 if True: for k, z in enumerate(zref): if k == 0: r, E[k] = 0., 1. else: #r1,p = integrate.quad(e,zref[k-1],z,epsrel=1e-1) x = np.linspace(zref[k - 1], z, 10) dx = x[1] - x[0] r1 = integrate.trapz(e(x), dx=dx) r += r1 E[k] = np.exp(r) return Ri * E, E
def get_soundc(t, s, z, lon, lat): ''' compute sound velocity ''' import gsw p = gsw.p_from_z(z, lat.mean()) SA = gsw.SA_from_SP(s, p, lon, lat) CT = gsw.CT_from_pt(SA, t) c = gsw.sound_speed(s, t, p) # inputs are: SA (absolute salinity) and CT (conservative temperature) return c
def calculate_svp(self, lat, lon): salinity = self.hycom_salinity_data temperature = self.hycom_temperature_data output_svp = [] #list of tuples(depth, sv) for count, (sal, temp) in enumerate(zip(salinity[0][0], temperature[0][0])): if sal == -30000 or temp == -30000: return output_svp else: sal = (int(sal) * 0.001) + 20 #convert from hycom value to real value temp = (int(temp) * 0.001) + 20 #convert from hycom value to real value depth = self.hycom_depth_array[count] s_abs = gsw.SA_from_SP( sal, depth, lon, lat ) #absolute salinity from practical salinity, pressure, lon, lat print 'converted SA from SP successfully' sv = gsw.sound_speed(s_abs, temp, depth) print 'calculated sound speed using TEOS-10 successfully' output_svp.append((depth, sv))
def ctd_data(self): # Open/read CTD cast file ctd_fname = 'h306a0202.ctd' with open(ctd_fname, 'r') as ctd_file: ctd_contents = np.loadtxt(ctd_file, skiprows=6) # Extract Presseure, Temperature, and Salinity pres = [] # (dbars) temp = [] # (Celsius from ITS-90) sal = [] # (Sp converted to Sa) for line in ctd_contents: pres.append(line[0]) temp.append(line[1]) sal.append(SA_from_SP(line[2], pres[-1], self.rx_lon, self.rx_lat)) # Convert the pressure into a depth (m) N_mean = 2.32 # WGS84 avg geoid height over area z_CTD = -(z_from_p(pres, self.rx_lat) + N_mean) # Truncate CTD to fit range between source and receiver: # Remove layers above where transmission occurred rm_ind_up = [i for i, x in enumerate(z_CTD) if x <= self.tx_z] z_CTD = np.delete(z_CTD, rm_ind_up[:-1]) temp = np.delete(temp, rm_ind_up[:-1]) sal = np.delete(sal, rm_ind_up[:-1]) # Set first depth to be the transducer depth and interpolate z_diff = self.tx_z - z_CTD[0] temp[0] = temp[0] + ((temp[1] - temp[0]) * (z_diff / (z_CTD[1] - z_CTD[0]))) sal[0] = sal[0] + ((sal[1] - sal[0]) * (z_diff / (z_CTD[1] - z_CTD[0]))) z_CTD[0] = self.tx_z # Remove layers if below where reception occurred if z_CTD[-1] > self.rx_z: rm_ind_dn = [i for i, x in enumerate(z_CTD) if x > self.rx_z] z_CTD = np.delete(z_CTD, rm_ind_dn[:]) temp = np.delete(temp, rm_ind_dn[:]) sal = np.delete(sal, rm_ind_dn[:]) # Add layers if above where reception occurred else: lyr_thck = -np.mean(z_CTD[-5:-1] - z_CTD[-4:]) add_lyr = int(np.floor((self.rx_z - z_CTD[-1]) / lyr_thck)) z_CTD = np.concatenate([ z_CTD, z_CTD[-1] + [lyr_thck] * np.linspace(1, add_lyr, add_lyr) ]) z_CTD = np.append(z_CTD, self.rx_z) # Interpolate and add layers for temp and sal temp_grad = temp[-2] - temp[-1] temp = np.concatenate([ temp, temp[-1] + [temp_grad] * np.linspace(1, add_lyr + 1, add_lyr + 1) ]) sal_grad = sal[-2] - sal[-1] sal = np.concatenate([ sal, sal[-1] + [sal_grad] * np.linspace(1, add_lyr + 1, add_lyr + 1) ]) # Create SS profile pres = p_from_z(-z_CTD, self.rx_lat) # updated pressure SS_pro = sound_speed(sal, temp, pres) return SS_pro, z_CTD
P = mat['P_slow'] JAC_C = mat['JAC_C'] JAC_T = mat['JAC_T'] W = mat['W_slow'] Turb = mat['Turbidity'] Chla = mat['Chlorophyll'] lat = 54 lon = -60 SP = gsw.SP_from_C(JAC_C, JAC_T, P) SA = gsw.SA_from_SP(SP, P, lon, lat) CT = gsw.CT_from_pt(SA, JAC_T) sig0 = gsw.sigma0(SA, CT) Z = gsw.z_from_p(P, lat) SS = gsw.sound_speed(SA, CT, P) # Bring Chla / Turb to resolution of CTD bin_size = len(Turb) / len(P) Turb = Turb.reshape(-1, int(bin_size)).mean(axis=1) Chla = Chla.reshape(-1, int(bin_size)).mean(axis=1) Turb = Turb.reshape(len(Turb), 1) Chla = Chla.reshape(len(Chla), 1) df = pd.DataFrame(np.concatenate( (JAC_C, JAC_T, P, Z, SP, SS, sig0, W, Turb, Chla), axis=1), columns=[ 'Conductivity', 'Temperature', 'Sea pressure', 'Depth', 'salinity', 'Speed of sound', 'Density anomaly', 'vert_vel', 'Turbidity', 'Chlorophyll'
def teos10( self, vlist: list = ["SA", "CT", "SIG0", "N2", "PV", "PTEMP"], inplace: bool = True, ): """ Add TEOS10 variables to the dataset By default, adds: 'SA', 'CT' Other possible variables: 'SIG0', 'N2', 'PV', 'PTEMP', 'SOUND_SPEED' Relies on the gsw library. If one exists, the correct CF standard name will be added to the attrs. Parameters ---------- vlist: list(str) List with the name of variables to add. Must be a list containing one or more of the following string values: * `"SA"` Adds an absolute salinity variable * `"CT"` Adds a conservative temperature variable * `"SIG0"` Adds a potential density anomaly variable referenced to 0 dbar * `"N2"` Adds a buoyancy (Brunt-Vaisala) frequency squared variable. This variable has been regridded to the original pressure levels in the Dataset using a linear interpolation. * `"PV"` Adds a planetary vorticity variable calculated from :math:`\\frac{f N^2}{\\text{gravity}}`. This is not a TEOS-10 variable from the gsw toolbox, but is provided for convenience. This variable has been regridded to the original pressure levels in the Dataset using a linear interpolation. * `"PTEMP"` Adds a potential temperature variable * `"SOUND_SPEED"` Adds a sound speed variable inplace: boolean, True by default If True, return the input :class:`xarray.Dataset` with new TEOS10 variables added as a new :class:`xarray.DataArray` If False, return a :class:`xarray.Dataset` with new TEOS10 variables Returns ------- :class:`xarray.Dataset` """ if not with_gsw: raise ModuleNotFoundError( "This functionality requires the gsw library") allowed = ['SA', 'CT', 'SIG0', 'N2', 'PV', 'PTEMP', 'SOUND_SPEED'] if any(var not in allowed for var in vlist): raise ValueError( f"vlist must be a subset of {allowed}, instead found {vlist}") warnings.warn( "Default variables will be reduced to 'SA' and 'CT' in 0.1.9", category=FutureWarning) this = self._obj to_profile = False if self._type == "profile": to_profile = True this = this.argo.profile2point() # Get base variables as numpy arrays: psal = this['PSAL'].values temp = this['TEMP'].values pres = this['PRES'].values lon = this['LONGITUDE'].values lat = this['LATITUDE'].values # Coriolis f = gsw.f(lat) # Absolute salinity sa = gsw.SA_from_SP(psal, pres, lon, lat) # Conservative temperature ct = gsw.CT_from_t(sa, temp, pres) # Potential Temperature if "PTEMP" in vlist: pt = gsw.pt_from_CT(sa, ct) # Potential density referenced to surface if "SIG0" in vlist: sig0 = gsw.sigma0(sa, ct) # N2 if "N2" in vlist or "PV" in vlist: n2_mid, p_mid = gsw.Nsquared(sa, ct, pres, lat) # N2 on the CT grid: ishallow = (slice(0, -1), Ellipsis) ideep = (slice(1, None), Ellipsis) def mid(x): return 0.5 * (x[ideep] + x[ishallow]) n2 = np.zeros(ct.shape) * np.nan n2[1:-1] = mid(n2_mid) # PV: if "PV" in vlist: pv = f * n2 / gsw.grav(lat, pres) # Sound Speed: if 'SOUND_SPEED' in vlist: cs = gsw.sound_speed(sa, ct, pres) # Back to the dataset: that = [] if 'SA' in vlist: SA = xr.DataArray(sa, coords=this['PSAL'].coords, name='SA') SA.attrs['long_name'] = 'Absolute Salinity' SA.attrs['standard_name'] = 'sea_water_absolute_salinity' SA.attrs['unit'] = 'g/kg' that.append(SA) if 'CT' in vlist: CT = xr.DataArray(ct, coords=this['TEMP'].coords, name='CT') CT.attrs['long_name'] = 'Conservative Temperature' CT.attrs['standard_name'] = 'sea_water_conservative_temperature' CT.attrs['unit'] = 'degC' that.append(CT) if 'SIG0' in vlist: SIG0 = xr.DataArray(sig0, coords=this['TEMP'].coords, name='SIG0') SIG0.attrs[ 'long_name'] = 'Potential density anomaly with reference pressure of 0 dbar' SIG0.attrs['standard_name'] = 'sea_water_sigma_theta' SIG0.attrs['unit'] = 'kg/m^3' that.append(SIG0) if 'N2' in vlist: N2 = xr.DataArray(n2, coords=this['TEMP'].coords, name='N2') N2.attrs['long_name'] = 'Squared buoyancy frequency' N2.attrs['unit'] = '1/s^2' that.append(N2) if 'PV' in vlist: PV = xr.DataArray(pv, coords=this['TEMP'].coords, name='PV') PV.attrs['long_name'] = 'Planetary Potential Vorticity' PV.attrs['unit'] = '1/m/s' that.append(PV) if 'PTEMP' in vlist: PTEMP = xr.DataArray(pt, coords=this['TEMP'].coords, name='PTEMP') PTEMP.attrs['long_name'] = 'Potential Temperature' PTEMP.attrs['standard_name'] = 'sea_water_potential_temperature' PTEMP.attrs['unit'] = 'degC' that.append(PTEMP) if 'SOUND_SPEED' in vlist: CS = xr.DataArray(cs, coords=this['TEMP'].coords, name='SOUND_SPEED') CS.attrs['long_name'] = 'Speed of sound' CS.attrs['standard_name'] = 'speed_of_sound_in_sea_water' CS.attrs['unit'] = 'm/s' that.append(CS) # Create a dataset with all new variables: that = xr.merge(that) # Add to the dataset essential Argo variables (allows to keep using the argo accessor): that = that.assign({ k: this[k] for k in [ "TIME", " LATITUDE", "LONGITUDE", "PRES", "PRES_ADJUSTED", "PLATFORM_NUMBER", "CYCLE_NUMBER", "DIRECTION", ] if k in this }) # Manage output: if inplace: # Merge previous with new variables for v in that.variables: this[v] = that[v] if to_profile: this = this.argo.point2profile() for k in this: if k not in self._obj: self._obj[k] = this[k] return self._obj else: if to_profile: return that.argo.point2profile() else: return that