Ejemplo n.º 1
0
def zmld_so(s, t, p, threshold=0.05, smooth=None):
    """
    Computes mixed layer depth of Southern Ocean waters.

    Parameters
    ----------
    s : array_like
        salinity [psu (PSS-78)]
    t : array_like
        temperature [℃ (ITS-90)]
    p : array_like
        pressure [db].
    smooth : int
        size of running mean window, to smooth data.

    References
    ----------
    Mitchell B. G., Holm-Hansen, O., 1991. Observations of modeling of the
        Antartic phytoplankton crop in relation to mixing depth. Deep Sea
        Research, 38(89):981-1007. doi:10.1016/0198-0149(91)90093-U
    """
    sigma_t = sw.dens0(s, t) - 1000.
    depth = p
    if smooth is not None:
        sigma_t = rolling_mean(sigma_t, smooth, min_periods=1)

    sublayer = np.where(depth[(depth >= 5) & (depth <= 10)])[0]
    sigma_x = np.nanmean(sigma_t[sublayer])
    nan_sigma = np.where(sigma_t > sigma_x + threshold)[0]
    sigma_t[nan_sigma] = np.nan
    der = np.divide(np.diff(sigma_t), np.diff(depth))
    mld = np.where(der == np.nanmax(der))[0]
    zmld = depth[mld]

    return zmld
Ejemplo n.º 2
0
def tsplot(sobs,tobs):
    smin=sobs.min()
    smax=sobs.max()
    tmin=tobs.min()
    tmax=tobs.max()
    s_inc=(smax-smin)/8.
    t_inc=(tmax-tmin)/8.
    t = np.arange(tmin,tmax+t_inc,t_inc)
    s = np.arange(smin,smax+s_inc,s_inc)
    S, T = np.meshgrid(s, t)
    st = sw.dens0(S, T) - 1000
    st_inc=(st.max()-st.min())/8.
    levels = np.arange(st.min(),st.max()+st_inc,st_inc)
    from matplotlib import rcParams
    from matplotlib.ticker import MultipleLocator
    rcParams['xtick.direction'] = 'out'
    rcParams['ytick.direction'] = 'out'
    fig, ax = plt.subplots(figsize=(6, 4))
 #   ax.xaxis.set_major_locator(MultipleLocator(0.5))
 #   ax.xaxis.set_minor_locator(MultipleLocator(0.1))
 #   ax.yaxis.set_major_locator(MultipleLocator(5))
 #   ax.yaxis.set_minor_locator(MultipleLocator(1))
    ax.set_ylabel(u"Temperature \u00b0C")
    ax.set_xlabel(r"Salinity [g kg$^{-1}$]")
    ax.axis([smin,smax,tmin,tmax])

    cs = ax.contour(s, t, st, colors='black', levels=levels)
    ax.clabel(cs, fontsize=9, inline=1, fmt='%3.2f')
    #sg = ax.contour(s, t, sigma_theta, linestyle='--', colors='grey', levels=[0, line])
    #ax.clabel(sg, fontsize=9, inline=1, fmt='%2.1f')
    ax.plot(sobs,tobs,'o')
Ejemplo n.º 3
0
def convert_oxygen(self):
    if hasattr(  self.data, 'sbe63_oxygen' ) & \
        hasattr( self.data, 'prwl_salt'   ) & \
        hasattr( self.data, 'prwl_temp'   ):
        self.StatusBar.SetStatusText('Converting Oxygen')
        # conversion from mL/L to umol/L
        self.data.sbe63_oxygen = self.data.sbe63_oxygen * .7 * 44.661

        # conversion to umol/kg
        density = dens0(self.data.prwl_salt, self.data.prwl_temp)
        self.data.sbe63_oxygen = self.data.sbe63_oxygen / density * 1000.

        # calculating saturation potential
        i = np.where(
            [key.startswith('sbe63_oxygen')
             for key in self.data.keys()])[0].max() + 1
        sbe63_oxygen_sat = Series(None, index=self.data.index)
        sbe63_oxygen_sat[:] = satO2(self.data.prwl_salt, self.data.prwl_temp)
        sbe63_oxygen_sat = sbe63_oxygen_sat * 44.661
        sbe63_oxygen_sat = sbe63_oxygen_sat / density * 1000.
        self.data.insert(i, 'sbe63_oxygen_sat', sbe63_oxygen_sat)

        # calculating saturation %
        sbe63_oxygen_sat_precent = Series(None, index=self.data.index)
        sbe63_oxygen_sat_precent = self.data.sbe63_oxygen / self.data.sbe63_oxygen_sat * 100.
        self.data.insert(i + 1, 'sbe63_oxygen_sat_precent',
                         sbe63_oxygen_sat_precent)

    else:
        pass
Ejemplo n.º 4
0
def tsplot(sobs, tobs):
    smin = sobs.min()
    smax = sobs.max()
    tmin = tobs.min()
    tmax = tobs.max()
    s_inc = (smax - smin) / 8.
    t_inc = (tmax - tmin) / 8.
    t = np.arange(tmin, tmax + t_inc, t_inc)
    s = np.arange(smin, smax + s_inc, s_inc)
    S, T = np.meshgrid(s, t)
    st = sw.dens0(S, T) - 1000
    st_inc = (st.max() - st.min()) / 8.
    levels = np.arange(st.min(), st.max() + st_inc, st_inc)
    from matplotlib import rcParams
    from matplotlib.ticker import MultipleLocator
    rcParams['xtick.direction'] = 'out'
    rcParams['ytick.direction'] = 'out'
    fig, ax = plt.subplots(figsize=(6, 4))
    #   ax.xaxis.set_major_locator(MultipleLocator(0.5))
    #   ax.xaxis.set_minor_locator(MultipleLocator(0.1))
    #   ax.yaxis.set_major_locator(MultipleLocator(5))
    #   ax.yaxis.set_minor_locator(MultipleLocator(1))
    ax.set_ylabel(u"Temperature \u00b0C")
    ax.set_xlabel(r"Salinity [g kg$^{-1}$]")
    ax.axis([smin, smax, tmin, tmax])

    cs = ax.contour(s, t, st, colors='black', levels=levels)
    ax.clabel(cs, fontsize=9, inline=1, fmt='%3.2f')
    #sg = ax.contour(s, t, sigma_theta, linestyle='--', colors='grey', levels=[0, line])
    #ax.clabel(sg, fontsize=9, inline=1, fmt='%2.1f')
    ax.plot(sobs, tobs, 'o')
Ejemplo n.º 5
0
def mix5(t, s, d, u, v, j):

    #This subroutine mixes the arrays t, s, u, v down to level j.
    j = j + 1  #so that the j-th layer is included in the mixing
    t[:j] = np.mean(t[:j])
    s[:j] = np.mean(s[:j])
    d[:j] = sw.dens0(s[:j], t[:j])
    u[:j] = np.mean(u[:j])
    v[:j] = np.mean(v[:j])

    return t, s, d, u, v
Ejemplo n.º 6
0
def mix5(t, s, d, u, v, j):
    
    #This subroutine mixes the arrays t, s, u, v down to level j.
    j = j+1 #so that the j-th layer is included in the mixing
    t[:j] = np.mean(t[:j])
    s[:j] = np.mean(s[:j])
    d[:j] = sw.dens0(s[:j], t[:j])
    u[:j] = np.mean(u[:j])
    v[:j] = np.mean(v[:j])
    
    return t, s, d, u, v
Ejemplo n.º 7
0
def plot_salvtemp(salt, temp, press, srange=[28,34], trange=[-2,15], ptitle=""): 
    plt.style.use('ggplot')
    
    # Figure out boudaries (mins and maxs)
    smin = srange[0]
    smax = srange[1]
    tmin = trange[0]
    tmax = trange[1]

    # Calculate how many gridcells we need in the x and y dimensions
    xdim = int(round((smax-smin)/0.1+1,0))
    ydim = int(round((tmax-tmin)+1,0))
    
    #print 'ydim: ' + str(ydim) + ' xdim: ' + str(xdim) + ' \n'
    if (xdim > 10000) or (ydim > 10000): 
        print('To many dimensions for grid in {cruise} {cast} file. \
              Likely  missing data \n'.format(cruise=cruise,cast=cast))
        return
 
    # Create empty grid of zeros
    dens = np.zeros((ydim,xdim))
 
    # Create temp and salt vectors of appropiate dimensions
    ti = np.linspace(0,ydim-1,ydim)+tmin
    si = np.linspace(0,xdim-1,xdim)*0.1+smin
 
    # Loop to fill in grid with densities
    for j in range(0,int(ydim)):
        for i in range(0, int(xdim)):
            dens[j,i]=sw.dens0(si[i],ti[j])
 
    # Substract 1000 to convert to sigma-t
    dens = dens - 1000
 
    # Plot data ***********************************************
    fig, ax1 = plt.subplots(figsize=(8, 8), facecolor='w', edgecolor='w')
    CS = plt.contour(si,ti,dens, linestyles='dashed', colors='gray')
    plt.clabel(CS, fontsize=12, inline=1, fmt='%1.1f') # Label every second level
 
    ts = ax1.scatter(salt,temp, c=press, cmap='gray', s=10)
    cbar = plt.colorbar(ts)
    cbar.ax.tick_params(labelsize=14) 

    plt.ylim(tmin,tmax)
    plt.xlim(smin,smax)
    plt.tick_params(axis='both', which='major', labelsize=14)
 
    ax1.set_xlabel('Salinity (PSU)',fontsize=16)
    ax1.set_ylabel('Temperature (C)',fontsize=16)

    
    t = fig.suptitle(ptitle, fontsize=18, fontweight='bold')
    return fig  
Ejemplo n.º 8
0
def dens_back(smin, smax, tmin, tmax):
    """Calculate density for TS diagram."""
    xdim = round((smax - smin) / 0.1 + 1, 0)
    ydim = round((tmax - tmin) + 1, 0)

    ti_size = np.linspace(tmin, tmax, int(ydim * 10))
    si_size = np.linspace(smin, smax, int(xdim * 10))

    si2d, ti2d = np.meshgrid(si_size, ti_size)

    dens = sw.dens0(si2d, ti2d) - 1000
    return si2d, ti2d, dens
Ejemplo n.º 9
0
def plot_s0_line(tmin,smin,tmax,smax,siglvl=[27.88, 27.8, 27.68, 27.55]):
# Create empty grid of zeros
    ydim=xdim=100
    dens = np.zeros((ydim,xdim))
# Create temp and salt vectors of appropiate dimensions
    ti = np.linspace(tmin,tmax,ydim)
    si = np.linspace(smin,smax,xdim)
# Loop to fill in grid with densities
    for j in range(0,int(ydim)):
        for i in range(0, int(xdim)):
            dens[j,i]=seawater.dens0(si[i],ti[j])
# Substract 1000 to convert to sigma-t
    dens = dens - 1000
# Plot data ***********************************************
    CS = plt.contour(si, ti, dens, levels=siglvl, linestyles='dashed', colors='k')
    plt.clabel(CS, fontsize=12, inline=1, fmt='%4.2f', inline_spacing=1, use_clabeltext=1) # Label every second level
Ejemplo n.º 10
0
def stir(t, s, d, u, v, rc, r, j,n):
    
    #copied from source script:
    
    # %  This subroutine mixes cells j and j+1 just enough so that
    # %  the Richardson number after the mixing is brought up to
    # %  the value rnew. In order to have this mixing process
    # %  converge, rnew must exceed the critical value of the
    # %  richardson number where mixing is presumed to start. If
    # %  r critical = rc = 0.25 (the nominal value), and r = 0.20, then
    # %  rnew = 0.3 would be reasonable. If r were smaller, then a
    # %  larger value of rnew - rc is used to hasten convergence.
    #
    # %  This subroutine was modified by JFP in Sep 93 to allow for an
    # %  aribtrary rc and to achieve faster convergence.
    
    #TODO: This needs better commenting
    rcon = 0.02+(rc-r)/2
    rnew = rc+rcon/5.
    f = 1-r/rnew
    
    #mix temp
    dt = (t[j+1]-t[j])*f/2.
    t[j+1] = t[j+1]-dt
    t[j] = t[j]+dt
    
    #mix sal
    ds = (s[j+1]-s[j])*f/2.
    s[j+1] = s[j+1]-ds
    s[j] = s[j]+ds
    
    #recompute density 
    #d[j:j+1] = sw.dens0(s[j:j+1], t[j:j+1]) 
    #have to be careful here. x[j:j+1] in python is not the same as x[[j,j+1]]. We want the latter
    #ipdb.set_trace(context=9,cond=n>=12)
    d[[j,j+1]] = sw.dens0(s[[j,j+1]], t[[j,j+1]])
    
    du = (u[j+1]-u[j])*f/2
    u[j+1] = u[j+1]-du
    u[j] = u[j]+du
    
    dv = (v[j+1]-v[j])*f/2
    v[j+1] = v[j+1]-dv
    v[j] = v[j]+dv
    
    return t, s, d, u, v
Ejemplo n.º 11
0
def stir(t, s, d, u, v, rc, r, j):
    
    #copied from source script:
    
    # %  This subroutine mixes cells j and j+1 just enough so that
    # %  the Richardson number after the mixing is brought up to
    # %  the value rnew. In order to have this mixing process
    # %  converge, rnew must exceed the critical value of the
    # %  richardson number where mixing is presumed to start. If
    # %  r critical = rc = 0.25 (the nominal value), and r = 0.20, then
    # %  rnew = 0.3 would be reasonable. If r were smaller, then a
    # %  larger value of rnew - rc is used to hasten convergence.
    #
    # %  This subroutine was modified by JFP in Sep 93 to allow for an
    # %  aribtrary rc and to achieve faster convergence.
    
    #TODO: This needs better commenting
    rcon = 0.02+(rc-r)/2
    rnew = rc+rcon/5.
    f = 1-r/rnew
    
    #mix temp
    dt = (t[j+1]-t[j])*f/2.
    t[j+1] = t[j+1]-dt
    t[j] = t[j]+dt
    
    #mix sal
    ds = (s[j+1]-s[j])*f/2.
    s[j+1] = s[j+1]-ds
    s[j] = s[j]+ds
    
    #recompute density 
    #d[j:j+1] = sw.dens0(s[j:j+1], t[j:j+1]) 
    #have to be careful here. x[j:j+1] in python is not the same as x[[j,j+1]]. We want the latter
    d[[j,j+1]] = sw.dens0(s[[j,j+1]], t[[j,j+1]])
    
    du = (u[j+1]-u[j])*f/2
    u[j+1] = u[j+1]-du
    u[j] = u[j]+du
    
    dv = (v[j+1]-v[j])*f/2
    v[j+1] = v[j+1]-dv
    v[j] = v[j]+dv
    
    return t, s, d, u, v
Ejemplo n.º 12
0
def add_den_usv(ds):
    import seawater as sw
    import numpy as np
    import xarray as xr
    ds['wspd']=np.sqrt(ds.UWND_MEAN**2+ds.VWND_MEAN**2)   
    tem=sw.dens0(ds.SAL_CTD_MEAN,ds.TEMP_CTD_MEAN)
    ds['density_mean']=xr.DataArray(tem,dims=('time'),coords={'time':ds.time})
    tem=sw.alpha(ds.SAL_CTD_MEAN,ds.TEMP_CTD_MEAN,ds.BARO_PRES_MEAN*0) #pressure =0 at surface
    ds['alpha_ME']=xr.DataArray(tem,dims=('time'),coords={'time':ds.time})
    tem=sw.beta(ds.SAL_CTD_MEAN,ds.TEMP_CTD_MEAN,ds.BARO_PRES_MEAN*0) #pressure =0 at surface
    ds['beta_MEAN']=xr.DataArray(tem,dims=('time'),coords={'time':ds.time})
    xlat=ds.lat
    xlon=ds.lon
    dkm2 = abs(np.abs((((xlon[1:].data-xlon[0:-1].data)**2+(xlat[1:].data-xlat[0:-1].data)**2)**.5)*110.567*np.cos(np.pi*xlat[1:].data/180)))
    dkm2=np.append(dkm2,dkm2[len(dkm2)-1]) #add on last point
    dkm3 = dkm2.cumsum()
    ds['dist_total']=xr.DataArray(dkm3,dims=('time'),coords={'time':ds.time})
    ds['dist_between']=xr.DataArray(dkm2,dims=('time'),coords={'time':ds.time})
    return ds
Ejemplo n.º 13
0
def pwpgo(forcing, params, pwp_out, diagnostics):
    """
    This is the main driver of the PWP module.
    """

    #unpack some of the variables
    #This is not necessary, but I don't want to update all the variable names just yet.
    q_in = forcing['q_in']
    q_out = forcing['q_out']
    emp = forcing['emp']
    taux = forcing['tx']
    tauy = forcing['ty']
    absrb = forcing['absrb']

    z = pwp_out['z']
    dz = pwp_out['dz']
    dt = pwp_out['dt']
    zlen = len(z)
    tlen = len(pwp_out['time'])

    rb = params['rb']
    rg = params['rg']
    f = params['f']
    cpw = params['cpw']
    g = params['g']
    ucon = params['ucon']

    printDragWarning = True

    print("Number of time steps: %s" % tlen)

    for n in range(1, tlen):
        percent_comp = 100 * n / float(tlen)
        print('Loop iter. %s (%.1f %%)' % (n, percent_comp))

        #select for previous profile data
        temp = pwp_out['temp'][:, n - 1]
        sal = pwp_out['sal'][:, n - 1]
        dens = pwp_out['dens'][:, n - 1]
        uvel = pwp_out['uvel'][:, n - 1]
        vvel = pwp_out['vvel'][:, n - 1]

        ### Absorb solar radiation and FWF in surf layer ###

        #save initial T,S (may not be necessary)
        temp_old = pwp_out['temp'][0, n - 1]
        sal_old = pwp_out['sal'][0, n - 1]

        #update layer 1 temp and sal
        temp[0] = temp[0] + (q_in[n - 1] * absrb[0] -
                             q_out[n - 1]) * dt / (dz * dens[0] * cpw)
        sal[0] = sal[0] / (1 - emp[n - 1] * dt / dz)

        #check if temp is less than freezing point
        T_fz = sw.fp(sal_old, 1)  #why use sal_old? Need to recheck
        if temp[0] < T_fz:
            temp[0] = T_fz

        ### Absorb rad. at depth ###
        temp[1:] = temp[1:] + q_in[n - 1] * absrb[1:] * dt / (dz * dens[1:] *
                                                              cpw)

        ### compute new density ###
        dens = sw.dens0(sal, temp)

        ### relieve static instability ###
        temp, sal, dens, uvel, vvel = remove_si(temp, sal, dens, uvel, vvel)

        ### Compute MLD ###
        #find ml index
        ml_thresh = params['mld_thresh']
        mld_idx = np.flatnonzero(dens - dens[0] > ml_thresh)[
            0]  #finds the first index that exceed ML threshold

        #check to ensure that ML is defined
        assert mld_idx.size is not 0, "Error: Mixed layer depth is undefined."

        #get surf MLD
        mld = z[mld_idx]

        ### Rotate u,v do wind input, rotate again, apply mixing ###
        ang = -f * dt / 2
        uvel, vvel = rot(uvel, vvel, ang)
        du = (taux[n - 1] / (mld * dens[0])) * dt
        dv = (tauy[n - 1] / (mld * dens[0])) * dt
        uvel[:mld_idx] = uvel[:mld_idx] + du
        vvel[:mld_idx] = vvel[:mld_idx] + dv

        ### Apply drag to current ###
        #Original comment: this is a horrible parameterization of inertial-internal wave dispersion
        if params['drag_ON']:
            if ucon > 1e-10:
                uvel = uvel * (1 - dt * ucon)
                vvel = vvel * (1 - dt * ucon)
        else:
            if printDragWarning:
                print(
                    "Warning: Parameterization for inertial-internal wave dispersion is turned off."
                )
                printDragWarning = False

        uvel, vvel = rot(uvel, vvel, ang)

        ### Apply Bulk Richardson number instability form of mixing (as in PWP) ###
        if rb > 1e-5:
            temp, sal, dens, uvel, vvel = bulk_mix(temp, sal, dens, uvel, vvel,
                                                   g, rb, zlen, z, mld_idx)

        ### Do the gradient Richardson number instability form of mixing ###
        if rg > 0:
            temp, sal, dens, uvel, vvel = grad_mix(temp, sal, dens, uvel, vvel,
                                                   dz, g, rg, zlen)

        ### Apply diffusion ###
        if params['rkz'] > 0:
            temp = diffus(params['dstab'], zlen, temp)
            sal = diffus(params['dstab'], zlen, sal)
            dens = sw.dens0(sal, temp)
            uvel = diffus(params['dstab'], zlen, uvel)
            vvel = diffus(params['dstab'], zlen, vvel)

        ### update output profile data ###
        pwp_out['temp'][:, n] = temp
        pwp_out['sal'][:, n] = sal
        pwp_out['dens'][:, n] = dens
        pwp_out['uvel'][:, n] = uvel
        pwp_out['vvel'][:, n] = vvel
        pwp_out['mld'][n] = mld

        #do diagnostics
        if diagnostics == 1:
            phf.livePlots(pwp_out, n)

    return pwp_out
Ejemplo n.º 14
0
def zmld_boyer(s, t, p):
    """
    Computes mixed layer depth, based on de Boyer Montégut et al., 2004.

    Parameters
    ----------
    s : array_like
        salinity [psu (PSS-78)]
    t : array_like
        temperature [℃ (ITS-90)]
    p : array_like
        pressure [db].

    Notes
    -----
    Based on density with fixed threshold criteria
    de Boyer Montégut et al., 2004. Mixed layer depth over the global ocean:
        An examination of profile data and a profile-based climatology.
        doi:10.1029/2004JC002378

    dataset for test and more explanation can be found at:
    http://www.ifremer.fr/cerweb/deboyer/mld/Surface_Mixed_Layer_Depth.php

    Codes based on : http://mixedlayer.ucsd.edu/

    """
    m = len(s)
    # starti = min(find((pres-10).^2==min((pres-10).^2)));
    starti = np.min(np.where(((p - 10.)**2 == np.min((p - 10.)**2)))[0])
    pres = p[starti:m]
    sal = s[starti:m]
    temp = t[starti:m]
    starti = 0
    m = len(sal)
    pden = sw.dens0(sal, temp)-1000

    mldepthdens_mldindex = m
    for i, pp in enumerate(pden):
        if np.abs(pden[starti] - pp) > .03:
            mldepthdens_mldindex = i
            break

    # Interpolate to exactly match the potential density threshold
    presseg = [pres[mldepthdens_mldindex-1], pres[mldepthdens_mldindex]]
    pdenseg = [pden[starti] - pden[mldepthdens_mldindex-1], pden[starti] -
               pden[mldepthdens_mldindex]]
    P = np.polyfit(presseg, pdenseg, 1)
    presinterp = np.linspace(presseg[0], presseg[1], 3)
    pdenthreshold = np.polyval(P, presinterp)

    # The potential density threshold MLD value:
    ix = np.max(np.where(np.abs(pdenthreshold) < 0.03)[0])
    mldepthdens_mldindex = presinterp[ix]

    # Search for the first level that exceeds the temperature threshold
    mldepthptmp_mldindex = m
    for i, tt in enumerate(temp):
        if np.abs(temp[starti] - tt) > 0.2:
            mldepthptmp_mldindex = i
            break

    # Interpolate to exactly match the temperature threshold
    presseg = [pres[mldepthptmp_mldindex-1], pres[mldepthptmp_mldindex]]
    tempseg = [temp[starti] - temp[mldepthptmp_mldindex-1],
               temp[starti] - temp[mldepthptmp_mldindex]]
    P = np.polyfit(presseg, tempseg, 1)
    presinterp = np.linspace(presseg[0], presseg[1], 3)
    tempthreshold = np.polyval(P, presinterp)

    # The temperature threshold MLD value:
    ix = np.max(np.where(np.abs(tempthreshold) < 0.2)[0])
    mldepthptemp_mldindex = presinterp[ix]

    return mldepthdens_mldindex, mldepthptemp_mldindex
def buoyancy_func(T, C):
    return -9.8 * 100 * (sw.dens0(C_B * C['g'], T_B * T['g']) - rho0) / rho0
    ):
        super().__init__(
            domain,
            layout,
            func,
            args=[],
            kw={},
            out=None,
        )
        self._parities = parity

    def meta_parity(self, axis):
        return self._parities.get(axis, 1)  # by default, even parity


rho0 = sw.dens0(20, 20)


def buoyancy_func(T, C):
    return -9.8 * 100 * (sw.dens0(C_B * C['g'], T_B * T['g']) - rho0) / rho0


buoyancy = ParityFunction(
    domain,
    layout='g',
    func=buoyancy_func,
)

# Buoyancy multiplier for parity constraints
par = domain.new_field()
par.set_scales(domain.dealias)
Ejemplo n.º 17
0
def tscomp(secref):
    '''
    This function creates T-S plots for CTD stations
    and referred climatology from WOA (NOAA).
    '''
    path = '/home/iury/Copy/TCC/dados/CLIMAT/WOA'

    woa = sio.loadmat(os.path.join(path, 'woa.mat'))

    tclim = woa['tclim']
    sclim = woa['sclim']

    lons = np.round(secref.minor_xs('lon').mean()).values + 360
    lats = np.round(secref.minor_xs('lat').mean()).values + 90

    tt = tclim[lats.tolist(), lons.tolist(), :].ravel()
    ss = sclim[lats.tolist(), lons.tolist(), :].ravel()

    fig, ax = plt.subplots()

    colors = cm.rainbow(np.linspace(0, 1, len(secref.items)))

    ax.plot(ss,
            tt,
            label='WOA',
            marker='o',
            color='k',
            linewidth=0,
            markersize=5)
    for i, c in zip(secref.items, colors):
        ax.scatter(secref.minor_xs('sp')[i],
                   secref.minor_xs('pt')[i],
                   label=i,
                   alpha=0.8,
                   edgecolor='None',
                   color=c,
                   s=7)

    ax.legend(fontsize=10, loc=4)

    clev = [20, 25.6, 26.9, 27.38, 27.53, 28]

    sal, temp = np.meshgrid(np.arange(33, 39), np.arange(0, 31))
    dens = sw.dens0(sal, temp) - 1000
    dens1 = sw.dens(sal, temp, 1000) - 1000
    dens2 = sw.dens(sal, temp, 2000) - 1000
    #    dens4 = sw.dens(sal,temp,4000)-1000

    #    c1 = ax.contourf(sal,temp,dens,levels=clev,alpha=0.5,
    #        colors=('#ff0000', '#ff9900', '#00c4ff', '#4fda66', '#0000ff'))

    c2 = ax.contour(sal, temp, dens, levels=[24.5, 26.8], colors='k')
    plt.clabel(c2, fontsize=10)
    c2 = ax.contour(sal, temp, dens1, levels=[32.15], colors='k')
    plt.clabel(c2, fontsize=10)
    c2 = ax.contour(sal, temp, dens2, levels=[37], colors='k')
    plt.clabel(c2, fontsize=10)

    plt.xlim([sal.min().min(), sal.max().max()])
    plt.ylim([temp.min().min(), temp.max().max()])
    plt.xlabel('Salinidade')
    plt.ylabel('Temperatura')
    #    c2 = ax.contour(sal,temp,dens4,levels=[45.83,45.9],colors='k')
    #    plt.clabel(c2, fontsize=10)

    #    position=fig.add_axes([0.11,0.06,0.8,0.02])
    #    fig.colorbar(c1,orientation='horizontal',cax = position)
    #
    #    position.text(x=0.1,y=-1.5,ha='center',s='AT')
    #    position.text(x=0.3,y=-1.5,ha='center',s='ACAS')
    #    position.text(x=0.5,y=-1.5,ha='center',s='AIA')
    #    position.text(x=0.7,y=-1.5,ha='center',s='ACS')
    #    position.text(x=0.9,y=-1.5,ha='center',s='APAN')

    pos = np.array(ax.get_position().bounds)
    pos[1] += pos[1] * 0.35
    ax.set_position(pos)
    ax.set_title('Diagrama TS')

    return fig, ax
Ejemplo n.º 18
0
fn = indir + infile

ds = nc.Dataset(fn)
lon = ds['lon_rho'][:]
lat = ds['lat_rho'][:]

dsg = nc.Dataset(Ldir['grid'] + 'grid.nc')

# get fields
ubar = ds['ubar'][:]
vbar = ds['vbar'][:]
u = ds['u'][:]
v = ds['v'][:]
salt = ds['salt'][:]
temp = ds['temp'][:]
pdens = sw.dens0(salt, temp)
z_w = ds['z_w'][:]
z_rho = ds['z_rho'][:]
ot = ds['ocean_time'][:]
t_md = Lfun.modtime_to_mdate_vec(ot)
t_dt = []
for t in ot:
    t_dt.append(Lfun.modtime_to_datetime(t))


def rot_vec(u, v, theta):
    ur = u * np.cos(theta) + v * np.sin(theta)
    vr = v * np.cos(theta) - u * np.sin(theta)
    return ur, vr

Ejemplo n.º 19
0
 def plotTSdiagram(self, sxps):
     fig = plt.figure(figsize=(8 * 2.5, 10))
     ax1 = plt.axes([0.10, 0.1, .2, .8])
     ax2 = plt.axes([0.40, 0.1, .2, .8])
     ax3 = plt.axes([0.70, 0.1, .2, .8])
     texps, sexps = self.exps, sxps.exps
     # Calculate how many gridcells we need in the x and y dimensions
     tdata = np.ma.hstack([np.ma.array(e.data) for e in texps])
     sdata = np.ma.hstack([np.ma.array(e.data) for e in sexps])
     tmin, tmax = np.ma.min(tdata), np.ma.max(tdata)
     smin, smax = np.ma.min(sdata), np.ma.max(sdata)
     xdim, ydim = round((smax - smin) / 0.1 + 1, 0), round(
         (tmax - tmin) / 0.1 + 1, 0)
     # Create empty grid of zeros
     dens = np.zeros((ydim, xdim))
     # Create temp and salt vectors of appropiate dimensions
     ti = np.linspace(1, ydim - 1, ydim) * 0.1 + tmin
     si = np.linspace(1, xdim - 1, xdim) * 0.1 + smin
     # Loop to fill in grid with densities
     for j in range(0, int(ydim)):
         for i in range(0, int(xdim)):
             dens[j, i] = dens0(si[i], ti[j])
     # Substract 1000 to convert to sigma-t
     dens -= 1000
     for ia, ax in enumerate([ax1, ax2, ax3]):
         CS = ax.contour(si, ti, dens, linestyles='dashed', colors='k')
         ax.clabel(CS, fontsize=12, inline=1,
                   fmt='%2.1f')  # Label every second level
         pnts, lgnds = [], []
         lastidx = -2
         # observed climatology 1
         t = np.ma.hstack((texps[0].data, texps[0].data[lastidx]))
         s = np.ma.hstack((sexps[0].data[1:], sexps[0].data[lastidx]))
         pnts.append(ax.scatter(s, t, lw=3, color='black'))
         lgnds.append(texps[0].dset)
         # observed climatology 2
         t = np.ma.hstack((texps[1].data, texps[1].data[lastidx]))
         s = np.ma.hstack((sexps[1].data[1:], sexps[1].data[lastidx]))
         pnts.append(ax.scatter(s, t, lw=3, color='lightgrey'))
         lgnds.append(texps[1].dset)
         # multi-model mean
         t = np.ma.hstack((texps[-1].data, texps[-1].data[lastidx]))
         s = np.ma.hstack((sexps[-1].data[1:], sexps[-1].data[lastidx]))
         pnts.append(ax.scatter(s, t, lw=3, color='darkgrey'))
         lgnds.append(texps[-1].dset)
         # then individual models
         for ename in self.ProductPanel[ia][self.vname]:
             texp = [e for e in texps if e.dset == ename][0]
             if ename == 'EN3':
                 sexp = [e for e in sexps if e.dset == 'EN3v2a'][0]
             else:
                 sexp = [e for e in sexps if e.dset == ename][0]
             t = np.ma.hstack((texp.data, texp.data[lastidx]))
             s = np.ma.hstack((sexp.data[1:], sexp.data[lastidx]))
             pnts.append(
                 ax.scatter(s, t, lw=3, color=ModelLineColors[texp.dset]))
             if texp.dset == 'GSOP_GLORYS2V4':
                 lgnds.append('GLORYS2V4')
             elif texp.dset == 'GSOP_GLORYS2V3':
                 lgnds.append('GLORYS2V3')
             elif texp.dset == 'GloSea5_GO5':
                 lgnds.append('GloSea5')
             elif texp.dset == 'EN4.2.0.g10':
                 lgnds.append('EN4')
             else:
                 lgnds.append(texp.dset)
         if ia == 0:
             ax.set_ylabel("temperature ($^\circ$C)")
         ax.set_title("%s) %s" % (Alphabets[ia], self.title))
         ax.set_xlabel('salinity (ppm)')
         ax.legend(pnts, tuple(lgnds), ncol=1, bbox_to_anchor=(0.65, 1.0))
     #plt.show()
     plt.savefig("S" + self.figfile)
Ejemplo n.º 20
0
#ax[0].plot(sw.dens0(df['s'],df['t']),df['z'])
ax[0].plot(df['t'],df['z'])
for i in range(N):
    df['t'] = filters.convolve1d(df['t'], ker)
df['t'][start:] = m_t*df['z'][start:]+t_t
df['t'][:end] = m_t2*df['z'][:end]+t_t2
ax[0].plot(df['t'],df['z'])
ax[0].set_title("temp")
ax[1].plot(df['s'],df['z'])
for i in range(N):
    df['s'] = filters.convolve1d(df['s'], ker)
df['s'][start:] = m_s*df['z'][start:]+t_s
df['s'][:end] = m_s*df['z'][:end]+t_s2
ax[1].plot(df['s'],df['z'])
ax[1].set_title("sal")
ax[2].plot(sw.dens0(df['s'],df['s']),df['z'])
ax[2].set_title("denS")
ax[3].plot(np.diff(sw.dens0(df['s'],df['s'])),df['z'][:-1])
ax[3].axvline(0,color="black")
ax[3].set_title("dens diff")
print(length)

for i in range(4):
    ax[i].invert_yaxis()
    ax[i].grid(linewidth=.3)

plt.savefig('../plots/testtest.pdf',bbox_inches='tight')
plt.show()
############################################################################

df.info()
Ejemplo n.º 21
0
def prep_data(met_dset, prof_dset, params):
    
    """
    This function prepares the forcing and profile data for the model run.
    
    Below, the surface forcing and profile data are interpolated to the user defined time steps
    and vertical resolutions, respectively. Secondary quantities are also computed and packaged 
    into dictionaries. The code also checks that the time and vertical increments meet the 
    necessary stability requirements.
    
    Lastly, this function initializes the numpy arrays to collect the model's output.
    
    INPUT:
    met_data: dictionary-like object with forcing data. Fields should include: 
            ['time', 'sw', 'lw', 'qlat', 'qsens', 'tx', 'ty', 'precip']. These fields should 
            store 1-D time series of the same length. 
            
            The model expects positive heat flux values to represent ocean warming. The time
            data field should contain a 1-D array representing fraction of day. For example, 
            for 6 hourly data, met_data['time'] should contain a number series that increases
            in steps of 0.25, such as np.array([1.0, 1.25, 1.75, 2.0, 2.25...]).

            See https://github.com/earlew/pwp_python#input-data for more info about the
            expect intput data. 
    
            TODO: Modify code to accept met_data['time'] as an array of datetime objects
    
            
    prof_data: dictionary-like object with initial profile data. Fields should include:
            ['z', 't', 's', 'lat']. These represent 1-D vertical profiles of temperature,
            salinity and density. 'lat' is expected to be a length=1 array-like object. e.g. 
            prof_data['lat'] = [25.0]
            
    params: dictionary-like object with fields defined by set_params function
    
    OUTPUT:
    
    forcing: dictionary with interpolated surface forcing data. 
    pwp_out: dictionary with initialized variables to collect model output.
    """
    
    import warnings
    
    #create new time vector with time step dt_d
    #time_vec = np.arange(met_dset['time'][0], met_dset['time'][-1]+params['dt_d'], params['dt_d']) 
    time_vec = np.arange(met_dset['time'][0], met_dset['time'][-1], params['dt_d']) 
    tlen = len(time_vec)
    
    #debug_here()
    
    #interpolate surface forcing data to new time vector
    from scipy.interpolate import interp1d
    forcing = {} 
    for vname in met_dset:
        p_intp = interp1d(met_dset['time'], met_dset[vname], axis=0)
        forcing[vname] = p_intp(time_vec)
        
    #interpolate E-P to dt resolution (not sure why this has to be done separately)
    evap_intp = interp1d(met_dset['time'], met_dset['qlat'], axis=0, kind='nearest', bounds_error=False)
    evap = (0.03456/(86400*1000))*evap_intp(np.floor(time_vec)) #(meters per second?)
    emp = evap-forcing['precip']
    emp[np.isnan(emp)] = 0.
    forcing['emp'] = emp  
    
    if params['emp_ON'] == False:
        print("WARNING: E-P is turned OFF.")
        forcing['emp'][:] = 0.0
        
    if params['heat_ON'] == False:
        print("WARNING: Surface heating is turned OFF.")
        forcing['sw'][:] = 0.0
        forcing['lw'][:] = 0.0
        forcing['qlat'][:] = 0.0
        forcing['qsens'][:] = 0.0
          
    
    #define q_in and q_out (positive values should mean ocean warming)
    forcing['q_in'] = forcing['sw'] #heat flux into ocean
    forcing['q_out'] = -(forcing['lw'] + forcing['qlat'] + forcing['qsens']) 
    
    #add time_vec to forcing
    forcing['time'] = time_vec
    
    if params['winds_ON'] == False:
        print("Winds are set to OFF.")
        forcing['tx'][:] = 0.0
        forcing['ty'][:] = 0.0
           
    #define depth coordinate, but first check to see if profile max depth
    #is greater than user defined max depth
    zmax = max(prof_dset.z)
    if zmax < params['max_depth']:
        depth = zmax
        print('Profile input shorter than depth selected, truncating to %sm' %depth)
        
    
    #define new z-coordinates
    init_prof = {}
    init_prof['z'] = np.arange(0, params['max_depth']+params['dz'], params['dz'])
    zlen = len(init_prof['z'])
    
    #compute absorption and incoming radiation (function defined in PWP_model.py)
    absrb = PWP.absorb(params['beta1'], params['beta2'], zlen, params['dz']) #(units unclear)
    dstab = params['dt']*params['rkz']/params['dz']**2 #courant number  
    if dstab > 0.5:
        print("WARNING: unstable CFL condition for diffusion! dt*rkz/dz**2 > 0.5.")
        print("To fix this, try to reduce the time step or increase the depth increment.")
        inpt = eval(input("Proceed with simulation? Enter 'y'or 'n'. "))
        if inpt is 'n':
            raise ValueError("Please restart PWP.m with a larger dz and/or smaller dt. Exiting...")
        
    forcing['absrb'] = absrb
    params['dstab'] = dstab
    
    #check depth resolution of profile data
    prof_incr = np.diff(prof_dset['z']).mean()
    if params['dz'] < prof_incr/5.:
        message = "Specified depth increment (%s m), is much smaller than mean profile resolution (%s m)." %(params['dz'], prof_incr)
        warnings.warn(message)
        
        
        # inpt = input("Depth increment, dz, is much smaller than profile resolution. Is this okay? (Enter 'y'or 'n')")
        # if inpt is 'n':
        #     raise ValueError("Please restart PWP.m with a new dz >= %s Exiting..." %prof_incr/5.)
    
    #debug_here()
    #interpolate profile data to new z-coordinate
    from scipy.interpolate import InterpolatedUnivariateSpline 
    for vname in prof_dset:
        if vname == 'lat' or vname=='lon':
            continue
        else:
            #first strip nans
            not_nan = np.logical_not(np.isnan(prof_dset[vname]))
            indices = np.arange(len(prof_dset[vname]))
            #p_intp = interp1d(prof_dset['z'], prof_dset[vname], axis=0, kind='linear', bounds_error=False)
            #interp1d doesn't work here because it doesn't extrapolate. Can't have Nans in interpolated profile
            p_intp = InterpolatedUnivariateSpline(prof_dset['z'][not_nan], prof_dset[vname][not_nan], k=1)
            init_prof[vname] = p_intp(init_prof['z'])    
        
    #get profile variables
    temp0 = init_prof['t'] #initial profile temperature
    sal0 = init_prof['s'] #intial profile salinity
    dens0 = sw.dens0(sal0, temp0) #intial profile density       
    
    #initialize variables for output
    pwp_out = {}
    pwp_out['time'] = time_vec
    pwp_out['dt'] = params['dt']
    pwp_out['dz'] = params['dz']
    pwp_out['lat'] = params['lat']
    pwp_out['z'] = init_prof['z']
    
    tlen = int(np.floor(tlen/params['dt_save']))
    arr_sz = (zlen, tlen)
    pwp_out['temp'] = np.zeros(arr_sz)
    pwp_out['sal'] = np.zeros(arr_sz)
    pwp_out['dens'] = np.zeros(arr_sz)
    pwp_out['uvel'] = np.zeros(arr_sz)
    pwp_out['vvel'] = np.zeros(arr_sz)
    pwp_out['mld'] = np.zeros((tlen,))
    
    #use temp, sal and dens profile data for the first time step
    pwp_out['sal'][:,0] = sal0
    pwp_out['temp'][:,0] = temp0
    pwp_out['dens'][:,0] = dens0
    
    return forcing, pwp_out, params
Ejemplo n.º 22
0
oklonGOFS = np.where(
    np.logical_and(lonGOFS >= lon_limGOFS[0], lonGOFS <= lon_limGOFS[1]))[0]
oklatGOFS = np.where(
    np.logical_and(latGOFS >= lat_limGOFS[0], latGOFS <= lat_limGOFS[1]))[0]

#%% NPEA GOFS 100

## Limit the depths to 100m
okdGOFS = np.where(depthGOFS <= 100)[0]
depthGOFS_100 = depthGOFS[okdGOFS]

tempGOFS_100 = np.asarray(GOFS.variables['water_temp'][oktimeGOFS[4], okdGOFS,
                                                       oklatGOFS, oklonGOFS])
saltGOFS_100 = np.asarray(GOFS.variables['salinity'][oktimeGOFS[4], okdGOFS,
                                                     oklatGOFS, oklonGOFS])
densGOFS_100 = seawater.dens0(saltGOFS_100, tempGOFS_100)

NPEA_GOFS_100 = Non_Dim_PEA(tempGOFS_100, saltGOFS_100, densGOFS_100,
                            depthGOFS_100)

#%% load RTOFS nc files
'''
print('Loading 6 hourly RTOFS nc files from FTP server')
for t in np.arange(len(nc_files_RTOFS)):
    #file = out_dir + '/' + nc_files_RTOFS[t]
    file = nc_files_RTOFS[t]

    # Login to ftp file
    ftp = FTP('ftp.ncep.noaa.gov')
    ftp.login()
    ftp.cwd('pub/data/nccf/com/rtofs/prod/')
Ejemplo n.º 23
0
def pwpgo(forcing, params, pwp_out, diagnostics):

    """
    This is the main driver of the PWP module.
    """
    
    #unpack some of the variables (I could probably do this more elegantly)
    q_in = forcing['q_in']
    q_out = forcing['q_out']
    emp = forcing['emp']
    taux = forcing['tx']
    tauy = forcing['ty']
    absrb = forcing['absrb']
    
    z = pwp_out['z']
    dz = pwp_out['dz']
    dt = pwp_out['dt']
    zlen = len(z)
    tlen = len(pwp_out['time'])
    
    rb = params['rb']
    rg = params['rg']
    f = params['f']
    cpw = params['cpw']
    g = params['g']
    ucon = params['ucon']
    
    for n in xrange(1,tlen):
        print 'Loop iter. %s' %n
        
        #select for previous profile data
        temp = pwp_out['temp'][:, n-1]
        sal = pwp_out['sal'][:, n-1]
        dens = pwp_out['dens'][:, n-1]
        uvel = pwp_out['uvel'][:, n-1]
        vvel = pwp_out['vvel'][:, n-1]
    
        ### Absorb solar radiation and FWF in surf layer ###
        
        #save initial T,S (may not be necessary)
        temp_old = pwp_out['temp'][0, n-1]
        sal_old = pwp_out['sal'][0, n-1] 
    
        #update layer 1 temp and sal
        temp[0] = temp[0] + (q_in[n-1]*absrb[0]-q_out[n-1])*dt/(dz*dens[0]*cpw)
        sal[0] = sal[0]/(1-emp[n-1]*dt/dz)
    
        #check if temp is less than freezing point
        T_fz = sw.fp(sal_old, 1) #why use sal_old? Need to recheck
        if temp[0] < T_fz:
            temp[0] = T_fz
        
        ### Absorb rad. at depth ###
        temp[1:] = temp[1:] + q_in[n-1]*absrb[1:]*dt/(dz*dens[1:]*cpw)
    
        ### compute new density ###
        dens = sw.dens0(sal, temp)
    
        ### relieve static instability ###
        temp, sal, dens, uvel, vvel = remove_si(temp, sal, dens, uvel, vvel)
    
        ### Compute MLD ###       
        #find ml index
        ml_thresh = params['mld_thresh']
        ml_idx = np.flatnonzero(np.diff(dens)>ml_thresh)[0] #finds the first index that exceed ML threshold
        ml_idx = ml_idx+1
    
        #check to ensure that ML is defined
        assert ml_idx.size is not 0, "Error: Mixed layer depth is undefined."
    
        #get surf MLD
        mld = z[ml_idx]    
        
        ### Rotate u,v do wind input, rotate again, apply mixing ###
        ang = -f*dt/2
        uvel, vvel = rot(uvel, vvel, ang)
        du = (taux[n-1]/(mld*dens[0]))*dt
        dv = (tauy[n-1]/(mld*dens[0]))*dt
        uvel[:ml_idx] = uvel[:ml_idx]+du
        vvel[:ml_idx] = vvel[:ml_idx]+dv
    

        ### Apply drag to current ###
        #Original comment: this is a horrible parameterization of inertial-internal wave dispersion
        if ucon > 1e-10:
            uvel = uvel*(1-dt*ucon) 
            vvel = vvel*(1-dt*ucon) 
    
        uvel, vvel = rot(uvel, vvel, ang)
    
        ### Apply Bulk Richardson number instability form of mixing (as in PWP) ###
        if rb > 1e-5:
            temp, sal, dens, uvel, vvel = bulk_mix(temp, sal, dens, uvel, vvel, dz, g, rb, zlen, z, ml_idx)
    
        ### Do the gradient Richardson number instability form of mixing ###
        if rg > 0:
            temp, sal, dens, uvel, vvel = grad_mix(temp, sal, dens, uvel, vvel, dz, g, rg, zlen)
            
        
        ### Apply diffusion ###
        if params['rkz'] > 0:
            temp = diffus(params['dstab'], zlen, temp) 
            sal = diffus(params['dstab'], zlen, sal) 
            dens = sw.dens0(sal, temp)
            uvel = diffus(params['dstab'], zlen, uvel)
            vvel = diffus(params['dstab'], zlen, vvel)
        
        ### update output profile data ###
        pwp_out['temp'][:, n] = temp 
        pwp_out['sal'][:, n] = sal 
        pwp_out['dens'][:, n] = dens
        pwp_out['uvel'][:, n] = uvel
        pwp_out['vvel'][:, n] = vvel
        pwp_out['mld'][n] = mld
    
        #do diagnostics
        if diagnostics==1:
            phf.livePlots(pwp_out, n)
        
    return pwp_out
Ejemplo n.º 24
0
def zmld_boyer(s, t, p):
    """
    Computes mixed layer depth, based on de Boyer Montégut et al., 2004.

    Parameters
    ----------
    s : array_like
        salinity [psu (PSS-78)]
    t : array_like
        temperature [℃ (ITS-90)]
    p : array_like
        pressure [db].

    Notes
    -----
    Based on density with fixed threshold criteria
    de Boyer Montégut et al., 2004. Mixed layer depth over the global ocean:
        An examination of profile data and a profile-based climatology.
        doi:10.1029/2004JC002378

    dataset for test and more explanation can be found at:
    http://www.ifremer.fr/cerweb/deboyer/mld/Surface_Mixed_Layer_Depth.php

    Codes based on : http://mixedlayer.ucsd.edu/

    """
    m = len(s)
    # starti = min(find((pres-10).^2==min((pres-10).^2)));
    starti = np.min(np.where(((p - 10.)**2 == np.min((p - 10.)**2)))[0])
    pres = p[starti:m]
    sal = s[starti:m]
    temp = t[starti:m]
    starti = 0
    m = len(sal)
    pden = sw.dens0(sal, temp) - 1000

    mldepthdens_mldindex = m
    for i, pp in enumerate(pden):
        if np.abs(pden[starti] - pp) > .03:
            mldepthdens_mldindex = i
            break

    # Interpolate to exactly match the potential density threshold
    presseg = [pres[mldepthdens_mldindex - 1], pres[mldepthdens_mldindex]]
    pdenseg = [
        pden[starti] - pden[mldepthdens_mldindex - 1],
        pden[starti] - pden[mldepthdens_mldindex]
    ]
    P = np.polyfit(presseg, pdenseg, 1)
    presinterp = np.linspace(presseg[0], presseg[1], 3)
    pdenthreshold = np.polyval(P, presinterp)

    # The potential density threshold MLD value:
    ix = np.max(np.where(np.abs(pdenthreshold) < 0.03)[0])
    mldepthdens_mldindex = presinterp[ix]

    # Search for the first level that exceeds the temperature threshold
    mldepthptmp_mldindex = m
    for i, tt in enumerate(temp):
        if np.abs(temp[starti] - tt) > 0.2:
            mldepthptmp_mldindex = i
            break

    # Interpolate to exactly match the temperature threshold
    presseg = [pres[mldepthptmp_mldindex - 1], pres[mldepthptmp_mldindex]]
    tempseg = [
        temp[starti] - temp[mldepthptmp_mldindex - 1],
        temp[starti] - temp[mldepthptmp_mldindex]
    ]
    P = np.polyfit(presseg, tempseg, 1)
    presinterp = np.linspace(presseg[0], presseg[1], 3)
    tempthreshold = np.polyval(P, presinterp)

    # The temperature threshold MLD value:
    ix = np.max(np.where(np.abs(tempthreshold) < 0.2)[0])
    mldepthptemp_mldindex = presinterp[ix]

    return mldepthdens_mldindex, mldepthptemp_mldindex
Ejemplo n.º 25
0
def prep_data(met_dset, prof_dset, params):
    
    """
    This function prepares the forcing and profile data for the model run.
    
    Below, the surface forcing and profile data are interpolated to the user defined time steps
    and vertical resolutions, respectively. Secondary quantities are also computed and packaged 
    into dictionaries. The code also checks that the time and vertical increments meet the 
    necessary stability requirements.
    
    Lastly, this function initializes the numpy arrays to collect the model's output.
    
    INPUT:
    met_data: dictionary-like object with forcing data. Fields should include: 
            ['time', 'sw', 'lw', 'qlat', 'qsens', 'tx', 'ty', 'precip'].
            These fields should store 1-D time series of the respective quantities.
            
    prof_data: dictionary-like object with initial profile data. Fields should include:
            ['z', 't', 's', 'd']. These represent 1-D vertical profiles of temperature,
            salinity and density.
            
    params: dictionary-like object with fields defined by set_params function
    
    OUTPUT:
    
    forcing: dictionary with interpolated surface forcing data. 
    pwp_out: dictionary with initialized variables to collect model output.
    """
    
    
    #create new time vector with time step dt_d
    time_vec = np.arange(met_dset['time'][0], met_dset['time'][-1]+params['dt_d'], params['dt_d']) 
    tlen = len(time_vec)
    
    #interpolate surface forcing data to new time vector
    from scipy.interpolate import interp1d
    forcing = {} 
    for vname in met_dset:
        p_intp = interp1d(met_dset['time'], met_dset[vname], axis=0)
        forcing[vname] = p_intp(time_vec)
        
    #interpolate E-P to dt resolution (not sure why this has to be done separately)
    evap_intp = interp1d(met_dset['time'], met_dset['qlat'], axis=0, kind='nearest', bounds_error=False)
    evap = (0.03456/(86400*1000))*evap_intp(np.floor(time_vec)) #(meters per second?)
    emp = evap-forcing['precip']
    emp[np.isnan(emp)] = 0.
    forcing['emp'] = emp    
    
    #define q_in and q_out
    forcing['q_in'] = forcing['sw'] #heat flux into ocean
    forcing['q_out'] = forcing['lw'] + forcing['qlat'] + forcing['qsens'] 
    
    #add time_vec to forcing
    forcing['time'] = time_vec
           
    #define depth coordinate, but first check to see if profile max depth
    #is greater than user defined max depth
    zmax = max(prof_dset.z)
    if zmax < params['max_depth']:
        depth = zmax
        print 'Profile input shorter than depth selected, truncating to %sm' %depth
        
    
    #define new z-coordinates
    init_prof = {}
    init_prof['z'] = np.arange(0, params['max_depth']+params['dz'], params['dz'])
    zlen = len(init_prof['z'])
    
    #compute absorption and incoming radiation (function defined in PWP_model.py)
    absrb = pwp.absorb(params['beta1'], params['beta2'], zlen, params['dz']) #(units unclear)
    dstab = params['dt']*params['rkz']/params['dz']**2 #courant number  
    if dstab > 0.5:
        print "WARNING: unstable CFL condition for diffusion! dt*rkz/dz**2 > 0.5."
        print "To fix this, try to reduce the time step or increase the depth increment."
        inpt = input("Proceed with simulation? Enter 'y'or 'n'. ")
        if inpt is 'n':
            raise ValueError("Please restart PWP.m with a larger dz and/or smaller dt. Exiting...")
        
    forcing['absrb'] = absrb
    params['dstab'] = dstab
    
    #check depth resolution of profile data
    prof_incr = np.diff(prof_dset['z']).mean()
    if params['dz'] < prof_incr/5.:
        inpt = input("Depth increment, dz, is much smaller than profile resolution. Is this okay? (Enter 'y'or 'n')")
        if inpt is 'n':
            raise ValueError("Please restart PWP.m with a new dz >= %s Exiting..." %prof_incr/5.)
    
    #debug_here()
    #interpolate profile data to new z-coordinate
    from scipy.interpolate import InterpolatedUnivariateSpline 
    for vname in prof_dset:
        #first strip nans
        not_nan = np.logical_not(np.isnan(prof_dset[vname]))
        indices = np.arange(len(prof_dset[vname]))
        #p_intp = interp1d(prof_dset['z'], prof_dset[vname], axis=0, kind='linear', bounds_error=False)
        #interp1d doesn't work here because it doesn't extrapolate. Can't have Nans in interpolated profile
        p_intp = InterpolatedUnivariateSpline(prof_dset['z'][not_nan], prof_dset[vname][not_nan], k=1)
        init_prof[vname] = p_intp(init_prof['z'])    
        
    #get profile variables
    temp0 = init_prof['t'] #initial profile temperature
    sal0 = init_prof['s'] #intial profile salinity
    dens0 = sw.dens0(sal0, temp0) #intial profile density
       
    
    #initialize variables for output
    pwp_out = {}
    pwp_out['time'] = time_vec
    pwp_out['dt'] = params['dt']
    pwp_out['dz'] = params['dz']
    pwp_out['lat'] = params['lat']
    pwp_out['z'] = init_prof['z']
    
    tlen = int(np.floor(tlen/params['dt_save']))
    arr_sz = (zlen, tlen)
    pwp_out['temp'] = np.zeros(arr_sz)
    pwp_out['sal'] = np.zeros(arr_sz)
    pwp_out['dens'] = np.zeros(arr_sz)
    pwp_out['uvel'] = np.zeros(arr_sz)
    pwp_out['vvel'] = np.zeros(arr_sz)
    pwp_out['mld'] = np.zeros((tlen,))
    
    #use temp, sal and dens profile data for the first time step
    pwp_out['sal'][:,0] = sal0
    pwp_out['temp'][:,0] = temp0
    pwp_out['dens'][:,0] = dens0
    
    return forcing, pwp_out, params