Example #1
0
File: ctd.py Project: laspg/cognac
 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)
Example #2
0
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
Example #3
0
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
Example #4
0
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
Example #5
0
 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))
Example #6
0
    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
Example #7
0
    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'
Example #8
0
    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