cs_wl_subs.py 12.7 KB
Newer Older
sbiri's avatar
sbiri committed
1
import numpy as np
sbiri's avatar
sbiri committed
2 3
from util_subs import (CtoK, kappa)

sbiri's avatar
sbiri committed
4 5

def cs_C35(sst, rho, Rs, Rnl, cp, lv, delta, usr, tsr, qsr, grav):
sbiri's avatar
sbiri committed
6
    """
sbiri's avatar
sbiri committed
7 8 9
    Compute cool skin.

    Based on COARE3.5 (Fairall et al. 1996, Edson et al. 2013)
sbiri's avatar
sbiri committed
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34

    Parameters
    ----------
    sst : float
        sea surface temperature      [K]
    qsea : float
        specific humidity over sea   [g/kg]
    rho : float
        density of air               [kg/m^3]
    Rs : float
        downward shortwave radiation [Wm-2]
    Rnl : float
        net upwelling IR radiation       [Wm-2]
    cp : float
       specific heat of air at constant pressure [J/K/kg]
    lv : float
       latent heat of vaporization   [J/kg]
    delta : float
       cool skin thickness           [m]
    usr : float
       friction velocity             [m/s]
    tsr : float
       star temperature              [K]
    qsr : float
       star humidity                 [g/kg]
sbiri's avatar
sbiri committed
35
    grav : float
sbiri's avatar
sbiri committed
36 37 38 39 40 41 42 43 44 45 46 47
       gravity                      [ms^-2]

    Returns
    -------
    dter : float
        cool skin correction         [K]
    dqer : float
       humidity corrction            [g/kg]
    delta : float
       cool skin thickness           [m]
    """
    # coded following Saunders (1967) with lambda = 6
sbiri's avatar
sbiri committed
48
    if np.nanmin(sst) > 200:  # if sst in Kelvin convert to Celsius
sbiri's avatar
sbiri committed
49 50 51 52 53 54 55
        sst = sst-CtoK
    # ************  cool skin constants  *******
    # density of water, specific heat capacity of water, water viscosity,
    # thermal conductivity of water
    rhow, cpw, visw, tcw = 1022, 4000, 1e-6, 0.6
    for i in range(4):
        aw = 2.1e-5*np.power(np.maximum(sst+3.2, 0), 0.79)
sbiri's avatar
sbiri committed
56
        bigc = 16*grav*cpw*np.power(rhow*visw, 3)/(np.power(tcw, 2)*np.power(
sbiri's avatar
sbiri committed
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
            rho, 2))
        Rns = 0.945*Rs  # albedo correction
        shf = rho*cp*usr*tsr
        lhf = rho*lv*usr*qsr
        Qnsol = shf+lhf+Rnl
        fs = 0.065+11*delta-6.6e-5/delta*(1-np.exp(-delta/8.0e-4))
        qcol = Qnsol+Rns*fs
        alq = aw*qcol+0.026*np.minimum(lhf, 0)*cpw/lv
        xlamx = 6*np.ones(sst.shape)
        xlamx = np.where(alq > 0, 6/(1+(bigc*alq/usr**4)**0.75)**0.333, 6)
        delta = np.minimum(xlamx*visw/(np.sqrt(rho/rhow)*usr), 0.01)
        delta = np.where(alq > 0, xlamx*visw/(np.sqrt(rho/rhow)*usr), delta)
    dter = qcol*delta/tcw
    return dter, delta
# ---------------------------------------------------------------------


sbiri's avatar
sbiri committed
74
def delta(aw, Q, usr, grav):
sbiri's avatar
sbiri committed
75
    """
sbiri's avatar
sbiri committed
76 77
    Compute the thickness (m) of the viscous skin layer.

sbiri's avatar
sbiri committed
78 79 80 81 82 83 84 85 86 87 88
    Based on Fairall et al., 1996 and cited in IFS Documentation Cy46r1
    eq. 8.155 p. 164

    Parameters
    ----------
    aw : float
        thermal expansion coefficient of sea-water  [1/K]
    Q : float
        part of the net heat flux actually absorbed in the warm layer [W/m^2]
    usr : float
        friction velocity in the air (u*) [m/s]
sbiri's avatar
sbiri committed
89
    grav : float
sbiri's avatar
sbiri committed
90 91 92 93 94 95 96 97 98 99 100
       gravity                      [ms^-2]

    Returns
    -------
    delta : float
        the thickness (m) of the viscous skin layer

    """
    rhow, visw, tcw = 1025, 1e-6, 0.6
    # u* in the water
    usr_w = np.maximum(usr, 1e-4)*np.sqrt(1.2/rhow)  # rhoa=1.2
sbiri's avatar
sbiri committed
101
    rcst_cs = 16*grav*np.power(visw, 3)/np.power(tcw, 2)
sbiri's avatar
sbiri committed
102 103 104 105 106 107 108 109
    lm = 6*(1+np.maximum(Q*aw*rcst_cs/np.power(usr_w, 4), 0)**0.75)**(-1/3)
    ztmp = visw/usr_w
    delta = np.where(Q > 0, np.minimum(6*ztmp, 0.007), lm*ztmp)
    return delta
# ---------------------------------------------------------------------

# version that doesn't output dqer or import/output delta
# should be very similar to cs_ecmwf
sbiri's avatar
sbiri committed
110
# def cs_C35(sst, rho, Rs, Rnl, cp, lv, usr, tsr, qsr, grav):
sbiri's avatar
sbiri committed
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
#     """
#     Compute cool skin.

#     Based on COARE3.5 (Fairall et al. 1996, Edson et al. 2013)

#     Parameters
#     ----------
#     sst : float
#         sea surface temperature      [K]
#     rho : float
#         density of air               [kg/m^3]
#     Rs : float
#         downward shortwave radiation [Wm-2]
#     Rnl : float
#         net upwelling IR radiation       [Wm-2]
#     cp : float
#         specific heat of air at constant pressure [J/K/kg]
#     lv : float
#         latent heat of vaporization   [J/kg]
#     delta : float
#         cool skin thickness           [m]
#     usr : float
#         friction velocity             [ms^-1]
#     tsr : float
#         star temperature              [K]
#     qsr : float
#         star humidity                 [g/kg]
sbiri's avatar
sbiri committed
138
#     grav : float
sbiri's avatar
sbiri committed
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
#         gravity                      [ms^-2]

#     Returns
#     -------
#     dter : float
#         cool skin correction         [K]
#     delta : float
#         cool skin thickness           [m]
#     """
#     # coded following Saunders (1967) with lambda = 6
#     if (np.nanmin(sst) > 200):  # if sst in Kelvin convert to Celsius
#         sst = sst-CtoK
#     # ************  cool skin constants  *******
#     # density of water, specific heat capacity of water, water viscosity,
#     # thermal conductivity of water
#     rhow, cpw, visw, tcw = 1022, 4000, 1e-6, 0.6
#     aw = 2.1e-5*np.power(np.maximum(sst+3.2, 0), 0.79)
sbiri's avatar
sbiri committed
156
#     bigc = 16*grav*cpw*np.power(rhow*visw, 3)/(np.power(tcw, 2)*np.power(
sbiri's avatar
sbiri committed
157 158 159 160 161
#         rho, 2))
#     Rns = 0.945*Rs  # albedo correction
#     shf = rho*cp*usr*tsr
#     lhf = rho*lv*usr*qsr
#     Qnsol = shf+lhf+Rnl
sbiri's avatar
sbiri committed
162
#     d = delta(aw, Qnsol, usr, grav)
sbiri's avatar
sbiri committed
163 164 165 166 167 168 169 170 171 172 173 174 175
#     for i in range(4):
#         fs = 0.065+11*d-6.6e-5/d*(1-np.exp(-d/8.0e-4))
#         qcol = Qnsol+Rns*fs
#         alq = aw*qcol+0.026*np.minimum(lhf, 0)*cpw/lv
#         xlamx = 6*np.ones(sst.shape)
#         xlamx = np.where(alq > 0, 6/(1+(bigc*alq/usr**4)**0.75)**0.333, 6)
#         d = np.minimum(xlamx*visw/(np.sqrt(rho/rhow)*usr), 0.01)
#         d = np.where(alq > 0, xlamx*visw/(np.sqrt(rho/rhow)*usr), d)
#     dter = qcol*d/tcw
#     return dter
# ---------------------------------------------------------------------


sbiri's avatar
sbiri committed
176
def cs_ecmwf(rho, Rs, Rnl, cp, lv, usr, tsr, qsr, sst, grav):
sbiri's avatar
sbiri committed
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
    """
    cool skin adjustment based on IFS Documentation cy46r1

    Parameters
    ----------
    rho : float
        density of air               [kg/m^3]
    Rs : float
        downward solar radiation [Wm-2]
    Rnl : float
        net thermal radiation     [Wm-2]
    cp : float
       specific heat of air at constant pressure [J/K/kg]
    lv : float
       latent heat of vaporization   [J/kg]
    usr : float
       friction velocity         [m/s]
    tsr : float
       star temperature              [K]
    qsr : float
       star humidity                 [g/kg]
    sst : float
        sea surface temperature  [K]
sbiri's avatar
sbiri committed
200
    grav : float
sbiri's avatar
sbiri committed
201 202 203 204 205 206 207 208
       gravity                      [ms^-2]

    Returns
    -------
    dtc : float
        cool skin temperature correction [K]

    """
sbiri's avatar
sbiri committed
209
    if np.nanmin(sst) < 200:  # if sst in Celsius convert to Kelvin
sbiri's avatar
sbiri committed
210 211 212 213 214 215
        sst = sst+CtoK
    aw = np.maximum(1e-5, 1e-5*(sst-CtoK))
    Rns = 0.945*Rs  # (net solar radiation (albedo correction)
    shf = rho*cp*usr*tsr
    lhf = rho*lv*usr*qsr
    Qnsol = shf+lhf+Rnl  # eq. 8.152
sbiri's avatar
sbiri committed
216
    d = delta(aw, Qnsol, usr, grav)
sbiri's avatar
sbiri committed
217 218 219 220 221
    for jc in range(4):  # because implicit in terms of delta...
        # # fraction of the solar radiation absorbed in layer delta eq. 8.153
        # and Eq.(5) Zeng & Beljaars, 2005
        fs = 0.065+11*d-6.6e-5/d*(1-np.exp(-d/8e-4))
        Q = Qnsol+fs*Rns
sbiri's avatar
sbiri committed
222
        d = delta(aw, Q, usr, grav)
sbiri's avatar
sbiri committed
223 224 225 226 227
    dtc = Q*d/0.6  # (rhow*cw*kw)eq. 8.151
    return dtc
# ---------------------------------------------------------------------


sbiri's avatar
sbiri committed
228
def wl_ecmwf(rho, Rs, Rnl, cp, lv, usr, tsr, qsr, sst, skt, dtc, grav):
sbiri's avatar
sbiri committed
229
    """
sbiri's avatar
sbiri committed
230
    Calculate warm layer correction following IFS Documentation cy46r1.
sbiri's avatar
sbiri committed
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
    and aerobulk (Brodeau et al., 2016)

    Parameters
    ----------
    rho : float
        density of air               [kg/m^3]
    Rs : float
        downward solar radiation    [Wm-2]
    Rnl : float
        net thermal radiation  [Wm-2]
    cp : float
       specific heat of air at constant pressure [J/K/kg]
    lv : float
       latent heat of vaporization   [J/kg]
    usr : float
        friction velocity           [m/s]
    tsr : float
       star temperature              [K]
    qsr : float
       star humidity                 [g/kg]
    sst : float
        bulk sst                    [K]
    skt : float
        skin sst from previous step [K]
    dtc : float
        cool skin correction        [K]
sbiri's avatar
sbiri committed
257
    grav : float
sbiri's avatar
sbiri committed
258 259 260 261 262 263 264 265
       gravity                      [ms^-2]

    Returns
    -------
    dtwl : float
        warm layer correction       [K]

    """
sbiri's avatar
sbiri committed
266
    if np.nanmin(sst) < 200:  # if sst in Celsius convert to Kelvin
sbiri's avatar
sbiri committed
267 268 269 270
        sst = sst+CtoK
    rhow, cpw, visw, rd0 = 1025, 4190, 1e-6, 3
    Rns = 0.945*Rs
    #  Previous value of dT / warm-layer, adapted to depth:
sbiri's avatar
sbiri committed
271 272
    # thermal expansion coefficient of sea-water (SST accurate enough#)
    aw = 2.1e-5*np.power(np.maximum(sst-CtoK+3.2, 0), 0.79)
sbiri's avatar
sbiri committed
273 274 275 276 277 278 279 280
    # *** Rd = Fraction of solar radiation absorbed in warm layer (-)
    a1, a2, a3 = 0.28, 0.27, 0.45
    b1, b2, b3 = -71.5, -2.8, -0.06  # [m-1]
    Rd = 1-(a1*np.exp(b1*rd0)+a2*np.exp(b2*rd0)+a3*np.exp(b3*rd0))
    shf = rho*cp*usr*tsr
    lhf = rho*lv*usr*qsr
    Qnsol = shf+lhf+Rnl
    usrw = np.maximum(usr, 1e-4)*np.sqrt(1.2/rhow)   # u* in the water
sbiri's avatar
sbiri committed
281
    zc3 = rd0*kappa*grav/np.power(1.2/rhow, 3/2)
sbiri's avatar
sbiri committed
282 283
    zc4 = (0.3+1)*kappa/rd0
    zc5 = (0.3+1)/(0.3*rd0)
sbiri's avatar
sbiri committed
284
    for jwl in range(10):  # iteration to solve implicitely eq. for warm layer
sbiri's avatar
sbiri committed
285 286 287 288 289
        dsst = skt-sst-dtc
        # Buoyancy flux and stability parameter (zdl = -z/L) in water
        ZSRD = (Qnsol+Rns*Rd)/(rhow*cpw)
        ztmp = np.maximum(dsst, 0)
        zdl = np.where(ZSRD > 0, 2*(np.power(usrw, 2) *
sbiri's avatar
sbiri committed
290 291 292
                                    np.sqrt(ztmp/(5*rd0*grav*aw/visw)))+ZSRD,
                       np.power(usrw, 2)*np.sqrt(ztmp/(5*rd0*grav*aw/visw)))
        usr = np.maximum(usr, 1e-4)
sbiri's avatar
sbiri committed
293 294 295 296 297 298 299 300 301 302 303 304 305
        zdL = zc3*aw*zdl/np.power(usr, 3)
        # Stability function Phi_t(-z/L) (zdL is -z/L) :
        zphi = np.where(zdL > 0, (1+(5*zdL+4*np.power(zdL, 2)) /
                                  (1+3*zdL+0.25*np.power(zdL, 2)) +
                                  2/np.sqrt(1-16*(-np.abs(zdL)))),
                        1/np.sqrt(1-16*(-np.abs(zdL))))
        zz = zc4*(usrw)/zphi
        zz = np.maximum(np.abs(zz), 1e-4)*np.sign(zz)
        dtwl = np.maximum(0, (zc5*ZSRD)/zz)
    return dtwl
# ----------------------------------------------------------------------


sbiri's avatar
sbiri committed
306
def cs_Beljaars(rho, Rs, Rnl, cp, lv, usr, tsr, qsr, grav, Qs):
sbiri's avatar
sbiri committed
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
    """
    cool skin adjustment based on Beljaars (1997)
    air-sea interaction in the ECMWF model

    Parameters
    ----------
    rho : float
        density of air           [kg/m^3]
    Rs : float
        downward solar radiation [Wm-2]
    Rnl : float
        net thermal radiaion     [Wm-2]
    cp : float
       specific heat of air at constant pressure [J/K/kg]
    lv : float
       latent heat of vaporization   [J/kg]
    usr : float
       friction velocity         [m/s]
    tsr : float
       star temperature              [K]
    qsr : float
       star humidity                 [g/kg]
sbiri's avatar
sbiri committed
329
    grav : float
sbiri's avatar
sbiri committed
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350
       gravity                      [ms^-2]
    Qs : float
      radiation balance

    Returns
    -------
    Qs : float
      radiation balance
    dtc : float
        cool skin temperature correction [K]

    """
    tcw = 0.6       # thermal conductivity of water (at 20C) [W/m/K]
    visw = 1e-6     # kinetic viscosity of water [m^2/s]
    rhow = 1025     # Density of sea-water [kg/m^3]
    cpw = 4190      # specific heat capacity of water
    aw = 3e-4       # thermal expansion coefficient [K-1]
    Rns = 0.945*Rs  # net solar radiation (albedo correction)
    shf = rho*cp*usr*tsr
    lhf = rho*lv*usr*qsr
    Q = Rnl+shf+lhf+Qs
sbiri's avatar
sbiri committed
351 352
    xt = 16*Q*grav*aw*cpw*np.power(rhow*visw, 3)/(
        np.power(usr, 4)*np.power(rho*tcw, 2))
sbiri's avatar
sbiri committed
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
    xt1 = 1+np.power(xt, 3/4)
    # Saunders const  eq. 22
    ls = np.where(Q > 0, 6/np.power(xt1, 1/3), 6)
    delta = np.where(Q > 0, (ls*visw)/(np.sqrt(rho/rhow)*usr),
                     np.where((ls*visw)/(np.sqrt(rho/rhow)*usr) > 0.01, 0.01,
                              (ls*visw)/(np.sqrt(rho/rhow)*usr)))  # eq. 21
    # fraction of the solar radiation absorbed in layer delta
    fc = 0.065+11*delta-6.6e-5*(1-np.exp(-delta/0.0008))/delta
    Qs = fc*Rns
    Q = Rnl+shf+lhf+Qs
    dtc = Q*delta/tcw
    return Qs, dtc
# ----------------------------------------------------------------------


def get_dqer(dter, sst, qsea, lv):
    """
    Calculate humidity correction.

    Parameters
    ----------
    dter : float
        cool skin correction         [K]
    sst : float
        sea surface temperature      [K]
    qsea : float
        specific humidity over sea   [g/kg]
    lv : float
       latent heat of vaporization   [J/kg]

    Returns
    -------
    dqer : float
       humidity correction            [g/kg]

    """
sbiri's avatar
sbiri committed
389
    if np.nanmin(sst) < 200:  # if sst in Celsius convert to Kelvin
sbiri's avatar
sbiri committed
390 391 392 393
        sst = sst+CtoK
    wetc = 0.622*lv*qsea/(287.1*np.power(sst, 2))
    dqer = wetc*dter
    return dqer
sbiri's avatar
sbiri committed
394