Exemple #1
0
def lapse_rate(lower, upper, prof, pres=1):
    '''
    Calculates the lapse rate (C/km) from a profile object

    Inputs
    ------
        lower       (float)             Lower Bound of lapse rate
        upper       (float)             Upper Bound of lapse rate
        prof        (profile object)    Profile Object
        pres        (int 0/1)           Flag to know to convert pres to height

    Returns
    -------
        lapse rate  (float [C/km])
    '''
    if pres:
        p1 = lower
        p2 = upper
        z1 = interp.hght(lower, prof)
        z2 = interp.hght(upper, prof)
    else:
        z1 = interp.msl(lower, prof)
        z2 = interp.msl(upper, prof)
        p1 = interp.pres(z1, prof)
        p2 = interp.pres(z2, prof)

    tv1 = interp.vtmp(p1, prof)
    tv2 = interp.vtmp(p2, prof)
    if not QC(tv1) or not QC(tv2): return RMISSD
    return (tv2 - tv1) / (z2 - z1) * -1000.
Exemple #2
0
def lapse_rate(lower, upper, prof, pres=1):
    '''
    Calculates the lapse rate (C/km) from a profile object

    Inputs
    ------
        lower       (float)             Lower Bound of lapse rate
        upper       (float)             Upper Bound of lapse rate
        prof        (profile object)    Profile Object
        pres        (int 0/1)           Flag to know to convert pres to height

    Returns
    -------
        lapse rate  (float [C/km])
    '''
    if pres:
        p1 = lower
        p2 = upper
        z1 = interp.hght(lower, prof)
        z2 = interp.hght(upper, prof)
    else:
        z1 = interp.msl(lower, prof)
        z2 = interp.msl(upper, prof)
        p1 = interp.pres(z1, prof)
        p2 = interp.pres(z2, prof)

    tv1 = interp.vtmp(p1, prof)
    tv2 = interp.vtmp(p2, prof)
    if not QC(tv1) or not QC(tv2): return RMISSD
    return (tv2 - tv1) / (z2 - z1) * -1000.
Exemple #3
0
def non_parcel_bunkers_motion(prof):
    '''
    Compute the Bunkers Storm Motion for a Right Moving Supercell

    Inputs
    ------
        prof         (profile object)    Profile Object

    Returns
    -------
        rstu         (float)            Right Storm Motion U-component
        rstv         (float)            Right Storm Motion V-component
        lstu         (float)            Left Storm Motion U-component
        lstv         (float)            Left Storm Motion V-component
    '''
    d = MS2KTS(7.5)  # Deviation value emperically derived as 7.5 m/s
    msl6km = interp.msl(6000., prof)
    p6km = interp.pres(msl6km, prof)

    # SFC-6km Mean Wind
    mnu6, mnv6 = mean_wind_npw(prof.gSndg[prof.sfc][prof.pind], p6km, prof, 20)

    # SFC-6km Shear Vector
    shru6, shrv6 = wind_shear(prof.gSndg[prof.sfc][prof.pind], p6km, prof)

    # Bunkers Right Motion
    tmp = d / vector.comp2vec(shru6, shrv6)[1]
    rstu = mnu6 + (tmp * shrv6)
    rstv = mnv6 - (tmp * shru6)
    lstu = mnu6 - (tmp * shrv6)
    lstv = mnv6 + (tmp * shru6)

    return rstu, rstv, lstu, lstv
Exemple #4
0
def corfidi_mcs_motion(prof):
    '''
    Calculated the Meso-beta Elements (Corfidi) Vectors

    Inputs
    ------
        prof        (profile object)    Profile Object

    Returns
    -------
        upu         (float)             U-component of the upshear vector
        upv         (float)             V-component of the upshear vector
        dnu         (float)             U-component of the downshear vector
        dnv         (float)             V-component of the downshear vector
    '''
    # Compute the tropospheric (850hPa-300hPa) mean wind
    mnu1, mnv1 = mean_wind_npw(850., 300., prof)

    # Compute the low-level (SFC-1500m) mean wind
    p_1p5km = interp.pres(interp.msl(1500., prof), prof)
    mnu2, mnv2 = mean_wind_npw(prof.gSndg[prof.sfc][prof.pind], p_1p5km, prof)

    # Compute the upshear vector
    upu = mnu1 - mnu2
    upv = mnv1 - mnv2

    # Compute the downshear vector
    dnu = mnu1 + upu
    dnv = mnv1 + upv

    return upu, upv, dnu, dnv
Exemple #5
0
def non_parcel_bunkers_motion(prof):
    '''
    Compute the Bunkers Storm Motion for a Right Moving Supercell

    Inputs
    ------
        prof         (profile object)    Profile Object

    Returns
    -------
        rstu         (float)            Right Storm Motion U-component
        rstv         (float)            Right Storm Motion V-component
        lstu         (float)            Left Storm Motion U-component
        lstv         (float)            Left Storm Motion V-component
    '''
    d = MS2KTS(7.5)         # Deviation value emperically derived as 7.5 m/s
    msl6km = interp.msl(6000., prof)
    p6km = interp.pres(msl6km, prof)

    # SFC-6km Mean Wind
    mnu6, mnv6 = mean_wind_npw(prof.gSndg[prof.sfc][prof.pind],
        p6km, prof, 20)

    # SFC-6km Shear Vector
    shru6, shrv6 = wind_shear(prof.gSndg[prof.sfc][prof.pind],
        p6km, prof)

    # Bunkers Right Motion
    tmp = d / vector.comp2vec(shru6, shrv6)[1]
    rstu = mnu6 + (tmp * shrv6)
    rstv = mnv6 - (tmp * shru6)
    lstu = mnu6 - (tmp * shrv6)
    lstv = mnv6 + (tmp * shru6)

    return rstu, rstv, lstu, lstv
Exemple #6
0
def corfidi_mcs_motion(prof):
    '''
    Calculated the Meso-beta Elements (Corfidi) Vectors

    Inputs
    ------
        prof        (profile object)    Profile Object

    Returns
    -------
        upu         (float)             U-component of the upshear vector
        upv         (float)             V-component of the upshear vector
        dnu         (float)             U-component of the downshear vector
        dnv         (float)             V-component of the downshear vector
    '''
    # Compute the tropospheric (850hPa-300hPa) mean wind
    mnu1, mnv1 = mean_wind_npw(850., 300., prof)

    # Compute the low-level (SFC-1500m) mean wind
    p_1p5km = interp.pres(interp.msl(1500., prof), prof)
    mnu2, mnv2 = mean_wind_npw(prof.gSndg[prof.sfc][prof.pind], p_1p5km, prof)

    # Compute the upshear vector
    upu = mnu1 - mnu2
    upv = mnv1 - mnv2

    # Compute the downshear vector
    dnu = mnu1 + upu
    dnv = mnv1 + upv

    return upu, upv, dnu, dnv
Exemple #7
0
def bulk_rich(pcl, prof):
    '''
    Calculates the Bulk Richardson Number for a given parcel.

    Inputs
    ------
        pcl         (parcel object)         Parcel Object
        prof        (profile object)        Profile Object

    Returns
    -------
        Bulk Richardson Number
    '''
    # Make sure parcel is initialized
    if pcl.lplvals.flag == RMISSD:
        pbot = RMISSD
    elif pcl.lplvals.flag > 0 and pcl.lplvals.flag < 4:
        ptop = interp.pres(interp.msl(6000., prof), prof)
        pbot = prof.gSndg[prof.sfc][prof.pind]
    else:
        h0 = interp.hght(pcl.pres, prof)
        try:
            pbot = interp.pres(h0 - 500., prof)
        except:
            pbot = RMISSD
        if not QC(pbot): pbot = prof.gSndg[prof.sfc][prof.pind]
        h1 = interp.hght(pbot, prof)
        ptop = interp.pres(h1 + 6000., prof)

    if not QC(pbot) or not QC(ptop):
        pcl.brnshear = RMISSD
        pcl.brn = RMISSD
        return pcl

    # Calculate lowest 500m mean wind
    p = interp.pres(interp.hght(pbot, prof) + 500., prof)
    mnlu, mnlv = winds.mean_wind(pbot, p, prof)

    # Calculate the 6000m mean wind
    mnuu, mnuv = winds.mean_wind(pbot, ptop, prof)

    # Make sure CAPE and Shear are available
    if not QC(pcl.bplus) or not QC(mnlu) or not QC(mnuu):
        pcl.brnshear = RMISSD
        pcl.brn = RMISSD
        return pcl

    # Calculate shear between levels
    dx = mnuu - mnlu
    dy = mnuv - mnlv

    pcl.brnshear = KTS2MS(vector.comp2vec(dx, dy)[1])
    pcl.brnshear = pcl.brnshear**2 / 2.
    pcl.brn = pcl.bplus / pcl.brnshear
    return pcl
Exemple #8
0
def bunkers_storm_motion(prof, pbot=None, **kwargs):
    '''
    Compute the Bunkers Storm Motion for a Right Moving Supercell using
    a parcel based approach.

    Inputs
    ------
        prof        (profile object)    Profile Object
        pbot        (float)             Base of effective-inflow layer (hPa)

    Returns
    -------
        rstu        (float)             Right Storm Motion U-component
        rstv        (float)             Right Storm Motion V-component
        lstu        (float)             Left Storm Motion U-component
        lstv        (float)             Left Storm Motion V-component
    '''
    d = MS2KTS(7.5)  # Deviation value emperically derived as 7.5 m/s

    # If MUPCL provided, use it, otherwise create MUPCL
    if 'mupcl' in kwargs:
        mupcl = kwargs.get('mupcl')
    else:
        mulplvals = params.DefineParcel(3, prof, pres=400)
        mupcl = params.parcelx(-1,
                               -1,
                               mulplvals.pres,
                               mulplvals.temp,
                               mulplvals.dwpt,
                               prof,
                               lplvals=mulplvals)

    mucape = mupcl.bplus
    mucinh = mupcl.bminus
    muel = mupcl.elhght
    if not pbot:
        pbot, ptop = effective_inflow_layer(100, -250, prof)
    base = interp.agl(interp.hght(pbot, prof), prof)
    if mucape > 100. and QC(muel) and base >= 750:
        depth = muel - base
        htop = base + depth / 2.
        ptop = interp.pres(interp.msl(base + htop, prof), prof)
        mnu, mnv = winds.mean_wind_npw(pbot, ptop, prof)
        sru, srv = winds.wind_shear(pbot, ptop, prof)
        srmag = vector.mag(sru, srv)
        uchg = d / srmag * srv
        vchg = d / srmag * sru
        rstu = mnu + uchg
        rstv = mnv - vchg
        lstu = mnu - uchg
        lstv = mnv + vchg
    else:
        rstu, rstv, lstu, lstv = winds.non_parcel_bunkers_motion(prof)

    return rstu, rstv, lstu, lstv
Exemple #9
0
def bulk_rich(pcl, prof):
    '''
    Calculates the Bulk Richardson Number for a given parcel.

    Inputs
    ------
        pcl         (parcel object)         Parcel Object
        prof        (profile object)        Profile Object

    Returns
    -------
        Bulk Richardson Number
    '''
    # Make sure parcel is initialized
    if pcl.lplvals.flag == RMISSD:
        pbot = RMISSD
    elif pcl.lplvals.flag > 0 and pcl.lplvals.flag < 4:
        ptop = interp.pres(interp.msl(6000., prof), prof)
        pbot = prof.gSndg[prof.sfc][prof.pind]
    else:
        h0 = interp.hght(pcl.pres, prof)
        try:
            pbot = interp.pres(h0 - 500., prof)
        except:
            pbot = RMISSD
        if not QC(pbot): pbot = prof.gSndg[prof.sfc][prof.pind]
        h1 = interp.hght(pbot, prof)
        ptop = interp.pres(h1 + 6000., prof)

    if not QC(pbot) or not QC(ptop):
        pcl.brnshear = RMISSD
        pcl.brn = RMISSD
        return pcl

    # Calculate lowest 500m mean wind
    p = interp.pres(interp.hght(pbot, prof) + 500., prof)
    mnlu, mnlv = winds.mean_wind(pbot, p, prof)

    # Calculate the 6000m mean wind
    mnuu, mnuv = winds.mean_wind(pbot, ptop, prof)

    # Make sure CAPE and Shear are available
    if not QC(pcl.bplus) or not QC(mnlu) or not QC(mnuu):
        pcl.brnshear = RMISSD
        pcl.brn = RMISSD
        return pcl

    # Calculate shear between levels
    dx = mnuu - mnlu
    dy = mnuv - mnlv

    pcl.brnshear = KTS2MS(vector.comp2vec(dx, dy)[1])
    pcl.brnshear = pcl.brnshear**2 / 2.
    pcl.brn = pcl.bplus / pcl.brnshear
    return pcl
Exemple #10
0
def bunkers_storm_motion(prof, pbot=None, **kwargs):
    '''
    Compute the Bunkers Storm Motion for a Right Moving Supercell using
    a parcel based approach.

    Inputs
    ------
        prof        (profile object)    Profile Object
        pbot        (float)             Base of effective-inflow layer (hPa)

    Returns
    -------
        rstu        (float)             Right Storm Motion U-component
        rstv        (float)             Right Storm Motion V-component
        lstu        (float)             Left Storm Motion U-component
        lstv        (float)             Left Storm Motion V-component
    '''
    d = MS2KTS(7.5)     # Deviation value emperically derived as 7.5 m/s

    # If MUPCL provided, use it, otherwise create MUPCL
    if 'mupcl' in kwargs:
        mupcl = kwargs.get('mupcl')
    else:
        mulplvals = params.DefineParcel(3, prof, pres=400)
        mupcl = params.parcelx(-1, -1, mulplvals.pres, mulplvals.temp,
            mulplvals.dwpt, prof, lplvals=mulplvals)

    mucape = mupcl.bplus
    mucinh = mupcl.bminus
    muel = mupcl.elhght
    if not pbot:
        pbot, ptop = effective_inflow_layer(100, -250, prof)
    base = interp.agl(interp.hght(pbot, prof), prof)
    if mucape > 100. and QC(muel) and base >= 750:
        depth = muel - base
        htop = base + depth / 2.
        ptop = interp.pres(interp.msl(base + htop, prof), prof)
        mnu, mnv = winds.mean_wind_npw(pbot, ptop, prof)
        sru, srv = winds.wind_shear(pbot, ptop, prof)
        srmag = vector.mag(sru, srv)
        uchg = d / srmag * srv
        vchg = d / srmag * sru
        rstu = mnu + uchg
        rstv = mnv - vchg
        lstu = mnu - uchg
        lstv = mnv + vchg
    else:
        rstu, rstv, lstu, lstv =  winds.non_parcel_bunkers_motion(prof)

    return rstu, rstv, lstu, lstv
Exemple #11
0
def parcelx(lower, upper, pres, temp, dwpt, prof, **kwargs):
    '''
    Lifts the specified parcel, calculated various levels and parameters from
    the profile object. B+/B- are calculated based on the specified layer.

    !! All calculations use the virtual temperature correction unless noted. !!

    Inputs
    ------
        lower       (float)                 Lower-bound lifting level (hPa)
        upper       (float)                 Upper-bound lifting level
        pres        (float)                 Pressure of parcel to lift (hPa)
        temp        (float)                 Temperature of parcel to lift (C)
        dwpt        (float)                 Dew Point of parcel to lift (C)
        prof        (profile object)        Profile Object

    Returns
    -------
        pcl         (parcel object)         Parcel Object
    '''
    pcl = Parcel(-1, -1, pres, temp, dwpt)
    if 'lplvals' in kwargs: pcl.lplvals = kwargs.get('lplvals')
    else:
        lplvals = DefineParcel(prof, 5, pres=pres, temp=temp, dwpt=dwpt)
        pcl.lplvals = lplvals

    if prof.gNumLevels < 1: return pcl

    lyre = -1
    cap_strength = RMISSD
    cap_strengthpres = RMISSD
    li_max = RMISSD
    li_maxpres = RMISSD
    totp = 0.
    totn = 0.
    tote = 0.
    cinh_old = 0.

    # See if default layer is specified
    if lower == -1:
        lower = prof.gSndg[prof.sfc][prof.pind]
        pcl.blayer = lower
    if upper == -1:
        upper = prof.gSndg[prof.gNumLevels - 1][prof.pind]
        pcl.tlayer = upper

    # Make sure that this is a valid layer
    if lower > pres:
        lower = pres
        pcl.blayer = lower
    if not QC(interp.vtmp(lower, prof)) or \
       not QC(interp.vtmp(upper, prof)):
        return RMISSD

    # Begin with the Mixing Layer
    te1 = interp.vtmp(pres, prof)
    pe1 = lower
    h1 = interp.hght(pe1, prof)
    tp1 = thermo.virtemp(pres, temp, dwpt)
    # te1 = tp1

    # Lift parcel and return LCL pres (hPa) and LCL temp (c)
    pe2, tp2 = thermo.drylift(pres, temp, dwpt)
    blupper = pe2  # Define top of layer as LCL pres
    h2 = interp.hght(pe2, prof)
    te2 = interp.vtmp(pe2, prof)
    pcl.lclpres = pe2
    pcl.lclhght = interp.agl(h2, prof)

    # Calculate lifted parcel theta for use in iterative CINH loop below
    # RECALL: lifted parcel theta is CONSTANT from LPL to LCL
    theta_parcel = thermo.theta(pe2, tp2, 1000.)

    # Environmental theta and mixing ratio at LPL
    bltheta = thermo.theta(pres, interp.temp(pres, prof), 1000.)
    blmr = thermo.mixratio(pres, dwpt)

    # ACCUMULATED CINH IN MIXING LAYER BELOW THE LCL
    # This will be done in 10mb increments, and will use the virtual
    # temperature correction where possible
    pinc = -10
    a = int(lower)
    b = int(blupper)
    for pp in range(a, b, int(pinc)):
        pp1 = pp
        pp2 = pp + pinc
        if pp2 < blupper: pp2 = blupper
        dz = interp.hght(pp2, prof) - interp.hght(pp1, prof)

        # Calculate difference between Tv_parcel and Tv_environment at top
        # and bottom of 10mb layers. Make use of constant lifted parcel
        # theta and mixing ratio from LPL to LCL
        tv_env_bot = thermo.virtemp(
            pp1, thermo.theta(pp1, interp.temp(pp1, prof), 1000.),
            interp.dwpt(pp1, prof))
        tdef1 = (thermo.virtemp(pp1, theta_parcel,
            thermo.temp_at_mixrat(blmr, pp1)) - tv_env_bot) / \
            (thermo.ctok(tv_env_bot))

        tv_env_top = thermo.virtemp(
            pp2, thermo.theta(pp2, interp.temp(pp2, prof), 1000.),
            interp.dwpt(pp2, prof))
        tdef2 = (thermo.virtemp(pp2, theta_parcel,
            thermo.temp_at_mixrat(blmr, pp2)) - tv_env_top) / \
            (thermo.ctok(tv_env_bot))

        lyre = G * (tdef1 + tdef2) / 2. * dz
        if lyre < 0: totn += lyre

    # Move the bottom layer to the top of the boundary layer
    if lower > pe2:
        lower = pe2
        pcl.blayer = lower

    # Calculate height of various temperature levels
    p0c = temp_lvl(0., prof)
    pm10c = temp_lvl(-10., prof)
    pm20c = temp_lvl(-20., prof)
    pm30c = temp_lvl(-30., prof)
    hgt0c = interp.hght(p0c, prof)
    hgtm10c = interp.hght(pm10c, prof)
    hgtm20c = interp.hght(pm20c, prof)
    hgtm30c = interp.hght(pm30c, prof)
    pcl.p0c = p0c
    pcl.pm10c = pm10c
    pcl.pm20c = pm20c
    pcl.pm30c = pm30c
    pcl.hght0c = hgt0c
    pcl.hghtm10c = hgtm10c
    pcl.hghtm20c = hgtm20c
    pcl.hghtm30c = hgtm30c

    # Find lowest observation in layer
    i = 0
    while prof.gSndg[i][prof.pind] > lower:
        if i == prof.gNumLevels - 1: break
        i += 1
    while not QC(prof.gSndg[i][prof.tdind]):
        if i == prof.gNumLevels - 1: break
        i += 1
    lptr = i
    if prof.gSndg[i][prof.pind] == lower:
        if i != prof.gNumLevels - 1: lptr += 1

    # Find highest observation in layer
    i = prof.gNumLevels - 1
    while prof.gSndg[i][prof.pind] < upper:
        if i < lptr: break
        i -= 1
    uptr = i
    if prof.gSndg[i][prof.pind] == upper:
        if i > lptr: uptr -= 1

    # START WITH INTERPOLATED BOTTOM LAYER
    # Begin moist ascent from lifted parcel LCL (pe2, tp2)
    pe1 = lower
    h1 = interp.hght(pe1, prof)
    te1 = interp.vtmp(pe1, prof)
    tp1 = thermo.wetlift(pe2, tp2, pe1)
    lyre = 0
    lyrlast = 0
    for i in range(lptr, prof.gNumLevels):
        if not QC(prof.gSndg[i][prof.tind]): continue
        pe2 = prof.gSndg[i][prof.pind]
        h2 = prof.gSndg[i][prof.zind]
        te2 = interp.vtmp(pe2, prof)
        tp2 = thermo.wetlift(pe1, tp1, pe2)
        tdef1 = (thermo.virtemp(pe1, tp1, tp1) - te1) / thermo.ctok(te1)
        tdef2 = (thermo.virtemp(pe2, tp2, tp2) - te2) / thermo.ctok(te2)
        lyrlast = lyre
        lyre = G * (tdef1 + tdef2) / 2. * (h2 - h1)

        # Add layer energy to total positive if lyre > 0
        if lyre > 0:
            totp += lyre
            # Add layer energy to total negative if lyre < 0, only up to EL
        else:
            if pe2 > 500.: totn += lyre

        # Check for Max LI
        mli = thermo.virtemp(pe2, tp2, tp2) - te2
        if mli > li_max:
            li_max = mli
            li_maxpres = pe2

        # Check for Max Cap Strength
        mcap = te2 - mli
        if mcap > cap_strength:
            cap_strength = mcap
            cap_strengthpres = pe2

        tote += lyre
        pelast = pe1
        pe1 = pe2
        h1 = h2
        te1 = te2
        tp1 = tp2

        # Is this the top of the specified layer
        if i >= uptr and not QC(pcl.bplus):
            pe3 = pe1
            h3 = h1
            te3 = te1
            tp3 = tp1
            lyrf = lyre
            if lyrf > 0:
                pcl.bplus = totp - lyrf
                pcl.bminus = totn
            else:
                pcl.bplus = totp
                if pe2 > 500.: pcl.bminus = totn + lyrf
                else: pcl.bminus = totn
            pe2 = upper
            h2 = interp.hght(pe2, prof)
            te2 = interp.vtmp(pe2, prof)
            tp2 = thermo.wetlift(pe3, tp3, pe2)
            tdef3 = (thermo.virtemp(pe3, tp3, tp3) - te3) / thermo.ctok(te3)
            tdef2 = (thermo.virtemp(pe2, tp2, tp2) - te2) / thermo.ctok(te2)
            lyrf = G * (tdef3 + tdef2) / 2. * (h2 - h3)
            if lyrf > 0: pcl.bplus += lyrf
            else:
                if pe2 > 500.: pcl.bminus += lyrf
            if pcl.bplus == 0: pcl.bminus = 0.

        # Is this the freezing level
        if te2 < 0. and not QC(pcl.bfzl):
            pe3 = pelast
            h3 = interp.hght(pe3, prof)
            te3 = interp.vtmp(pe3, prof)
            tp3 = thermo.wetlift(pe1, tp1, pe3)
            lyrf = lyre
            if lyrf > 0.: pcl.bfzl = totp - lyrf
            else: pcl.bfzl = totp
            if not QC(p0c) or p0c > pe3:
                pcl.bfzl = 0
            elif QC(pe2):
                te2 = interp.vtmp(pe2, prof)
                tp2 = thermo.wetlift(pe3, tp3, pe2)
                tdef3 = (thermo.virtemp(pe3, tp3, tp3) - te3) / \
                    thermo.ctok(te3)
                tdef2 = (thermo.virtemp(pe2, tp2, tp2) - te2) / \
                    thermo.ctok(te2)
                lyrf = G * (tdef3 + tdef2) / 2. * (hgt0c - h3)
                if lyrf > 0: pcl.bfzl += lyrf

        # Is this the -10C level
        if te2 < -10. and not QC(pcl.wm10c):
            pe3 = pelast
            h3 = interp.hght(pe3, prof)
            te3 = interp.vtmp(pe3, prof)
            tp3 = thermo.wetlift(pe1, tp1, pe3)
            lyrf = lyre
            if lyrf > 0.: pcl.wm10c = totp - lyrf
            else: pcl.wm10c = totp
            if not QC(pm10c) or pm10c > pcl.lclpres:
                pcl.wm10c = 0
            elif QC(pe2):
                te2 = interp.vtmp(pe2, prof)
                tp2 = thermo.wetlift(pe3, tp3, pe2)
                tdef3 = (thermo.virtemp(pe3, tp3, tp3) - te3) / \
                    thermo.ctok(te3)
                tdef2 = (thermo.virtemp(pe2, tp2, tp2) - te2) / \
                    thermo.ctok(te2)
                lyrf = G * (tdef3 + tdef2) / 2. * (hgtm10c - h3)
                if lyrf > 0: pcl.wm10c += lyrf

        # Is this the -20C level
        if te2 < -20. and not QC(pcl.wm20c):
            pe3 = pelast
            h3 = interp.hght(pe3, prof)
            te3 = interp.vtmp(pe3, prof)
            tp3 = thermo.wetlift(pe1, tp1, pe3)
            lyrf = lyre
            if lyrf > 0.: pcl.wm20c = totp - lyrf
            else: pcl.wm20c = totp
            if not QC(pm20c) or pm20c > pcl.lclpres:
                pcl.wm20c = 0
            elif QC(pe2):
                te2 = interp.vtmp(pe2, prof)
                tp2 = thermo.wetlift(pe3, tp3, pe2)
                tdef3 = (thermo.virtemp(pe3, tp3, tp3) - te3) / \
                    thermo.ctok(te3)
                tdef2 = (thermo.virtemp(pe2, tp2, tp2) - te2) / \
                    thermo.ctok(te2)
                lyrf = G * (tdef3 + tdef2) / 2. * (hgtm20c - h3)
                if lyrf > 0: pcl.wm20c += lyrf

        # Is this the -30C level
        if te2 < -30. and not QC(pcl.wm30c):
            pe3 = pelast
            h3 = interp.hght(pe3, prof)
            te3 = interp.vtmp(pe3, prof)
            tp3 = thermo.wetlift(pe1, tp1, pe3)
            lyrf = lyre
            if lyrf > 0.: pcl.wm30c = totp - lyrf
            else: pcl.wm30c = totp
            if not QC(pm30c) or pm30c > pcl.lclpres:
                pcl.wm30c = 0
            elif QC(pe2):
                te2 = interp.vtmp(pe2, prof)
                tp2 = thermo.wetlift(pe3, tp3, pe2)
                tdef3 = (thermo.virtemp(pe3, tp3, tp3) - te3) / \
                    thermo.ctok(te3)
                tdef2 = (thermo.virtemp(pe2, tp2, tp2) - te2) / \
                    thermo.ctok(te2)
                lyrf = G * (tdef3 + tdef2) / 2. * (hgtm30c - h3)
                if lyrf > 0: pcl.wm30c += lyrf

        # Is this the 3km level
        if pcl.lclhght < 3000.:
            h = interp.agl(interp.hght(pe2, prof), prof)
            if h >= 3000. and not QC(pcl.b3km):
                pe3 = pelast
                h3 = interp.hght(pe3, prof)
                te3 = interp.vtmp(pe3, prof)
                tp3 = thermo.wetlift(pe1, tp1, pe3)
                lyrf = lyre
                if lyrf > 0: pcl.b3km = totp - lyrf
                else: pcl.b3km = totp
                h2 = interp.msl(3000., prof)
                pe2 = interp.pres(h2, prof)
                if QC(pe2):
                    te2 = interp.vtmp(pe2, prof)
                    tp2 = thermo.wetlift(pe3, tp3, pe2)
                    tdef3 = (thermo.virtemp(pe3, tp3, tp3) - te3) / \
                        thermo.ctok(te3)
                    tdef2 = (thermo.virtemp(pe2, tp2, tp2) - te2) / \
                        thermo.ctok(te2)
                    lyrf = G * (tdef3 + tdef2) / 2. * (h2 - h3)
                    if lyrf > 0: pcl.b3km += lyrf
        else: pcl.b3km = 0.

        # Is this the 6km level
        if pcl.lclhght < 6000.:
            h = interp.agl(interp.hght(pe2, prof), prof)
            if h >= 6000. and not QC(pcl.b6km):
                pe3 = pelast
                h3 = interp.hght(pe3, prof)
                te3 = interp.vtmp(pe3, prof)
                tp3 = thermo.wetlift(pe1, tp1, pe3)
                lyrf = lyre
                if lyrf > 0: pcl.b6km = totp - lyrf
                else: pcl.b6km = totp
                h2 = interp.msl(6000., prof)
                pe2 = interp.pres(h2, prof)
                if QC(pe2):
                    te2 = interp.vtmp(pe2, prof)
                    tp2 = thermo.wetlift(pe3, tp3, pe2)
                    tdef3 = (thermo.virtemp(pe3, tp3, tp3) - te3) / \
                        thermo.ctok(te3)
                    tdef2 = (thermo.virtemp(pe2, tp2, tp2) - te2) / \
                        thermo.ctok(te2)
                    lyrf = G * (tdef3 + tdef2) / 2. * (h2 - h3)
                    if lyrf > 0: pcl.b6km += lyrf
        else: pcl.b6km = 0.

        # LFC Possibility
        if lyre >= 0. and lyrlast <= 0.:
            tp3 = tp1
            te3 = te1
            pe2 = pe1
            pe3 = pelast
            while interp.vtmp(pe3, prof) > thermo.virtemp(
                    pe3, thermo.wetlift(pe2, tp3, pe3),
                    thermo.wetlift(pe2, tp3, pe3)):
                pe3 -= 5
            pcl.lfcpres = pe3
            pcl.lfchght = interp.agl(interp.hght(pe3, prof), prof)
            cinh_old = totn
            tote = 0.
            pcl.elpres = RMISSD
            li_max = RMISSD

            if cap_strength < 0.: cap_strength = 0.
            pcl.cap = cap_strength
            pcl.cappres = cap_strengthpres
            # Hack to force LFC to be at least at the LCL
            if pcl.lfcpres > pcl.lclpres:
                pcl.lfcpres = pcl.lclpres
                pcl.lfchght = pcl.lclhght

        # EL Possibility
        if lyre <= 0. and lyrlast >= 0.:
            tp3 = tp1
            te3 = te1
            pe2 = pe1
            pe3 = pelast
            while interp.vtmp(pe3, prof) < thermo.virtemp(
                    pe3, thermo.wetlift(pe2, tp3, pe3),
                    thermo.wetlift(pe2, tp3, pe3)):
                pe3 -= 5
            pcl.elpres = pe3
            pcl.elhght = interp.agl(interp.hght(pe3, prof), prof)
            pcl.mplpres = RMISSD
            pcl.limax = -li_max
            pcl.limaxpress = li_maxpres

        # MPL Possibility
        if tote < 0. and not QC(pcl.mplpres) and QC(pcl.elpres):
            pe3 = pelast
            h3 = interp.hght(pe3, prof)
            te3 = interp.vtmp(pe3, prof)
            tp3 = thermo.wetlift(pe1, tp1, pe3)
            totx = tote - lyre
            pe2 = pelast
            while totx > 0:
                pe2 -= 1
                te2 = interp.vtmp(pe2, prof)
                tp2 = thermo.wetlift(pe3, tp3, pe2)
                h2 = interp.hght(pe2, prof)
                tdef3 = (thermo.virtemp(pe3, tp3, tp3) - te3) / \
                    thermo.ctok(te3)
                tdef2 = (thermo.virtemp(pe2, tp2, tp2) - te2) / \
                    thermo.ctok(te2)
                lyrf = G * (tdef3 + tdef2) / 2. * (h2 - h3)
                totx += lyrf
                tp3 = tp2
                te3 = te2
                pe3 = pe2
            pcl.mplpres = pe2
            pcl.mplhght = interp.agl(interp.hght(pe2, prof), prof)

        # 500 hPa Lifted Index
        if prof.gSndg[i][prof.pind] <= 500. and pcl.li5 == RMISSD:
            a = interp.vtmp(500., prof)
            b = thermo.wetlift(pe1, tp1, 500.)
            pcl.li5 = a - thermo.virtemp(500, b, b)

        # 300 hPa Lifted Index
        if prof.gSndg[i][prof.pind] <= 300. and pcl.li3 == RMISSD:
            a = interp.vtmp(300., prof)
            b = thermo.wetlift(pe1, tp1, 300.)
            pcl.li3 = a - thermo.virtemp(300, b, b)

    # Calculate BRN if available
    pcl = bulk_rich(pcl, prof)

    pcl.bminus = cinh_old
    if pcl.bplus == 0: pcl.bminus = 0.
    return pcl
Exemple #12
0
def helicity(lower, upper, prof, stu=0, stv=0):
    '''
    Calculates the relative helicity (m2/s2) of a layer from lower to upper.
    If storm-motion vector is supplied, storm-relative helicity, both
    positve and negative, is returned.

    Inputs
    ------
        lower       (float)             Bottom level of layer (m, AGL)
        upper       (float)             Top level of layer (m, AGL)
        prof        (profile object)    Profile Object
        stu         (float; optional)   U-component of storm-motion
        stv         (float; optional)   V-component of storm-motion

    Returns
    -------
        phel+nhel   (float)             Combined Helicity (m2/s2)
        phel        (float)             Positive Helicity (m2/s2)
        nhel        (float)             Negative Helicity (m2/s2)
    '''
    lower = interp.msl(lower, prof)
    upper = interp.msl(upper, prof)
    plower = interp.pres(lower, prof)
    pupper = interp.pres(upper, prof)
    phel = 0
    nhel = 0

    # Find lower and upper ind bounds for looping
    i = 0
    while interp.msl(prof.gSndg[i][prof.zind], prof) < lower:
        i += 1
    lptr = i
    if interp.msl(prof.gSndg[i][prof.zind], prof) == lower: lptr += 1
    while interp.msl(prof.gSndg[i][prof.zind], prof) <= upper:
        i += 1
    uptr = i
    if interp.msl(prof.gSndg[i][prof.zind], prof) == upper: uptr -= 1

    # Integrate from interpolated bottom level to iptr level
    sru1, srv1 = interp.components(plower, prof)
    sru1 = KTS2MS(sru1 - stu)
    srv1 = KTS2MS(srv1 - stv)

    # Loop through levels
    for i in range(lptr, uptr + 1):
        if QC(prof.gSndg[i][prof.uind]) and QC(prof.gSndg[i][prof.vind]):
            sru2, srv2 = interp.components(prof.gSndg[i][prof.pind], prof)
            sru2 = KTS2MS(sru2 - stu)
            srv2 = KTS2MS(srv2 - stv)
            lyrh = (sru2 * srv1) - (sru1 * srv2)
            if lyrh > 0: phel += lyrh
            else: nhel += lyrh
            sru1 = sru2
            srv1 = srv2

    # Integrate from tptr level to interpolated top level
    sru2, srv2 = interp.components(pupper, prof)
    sru2 = KTS2MS(sru2 - stu)
    srv2 = KTS2MS(srv2 - stv)

    lyrh = (sru2 * srv1) - (sru1 * srv2)
    if lyrh > 0: phel += lyrh
    else: nhel += lyrh
    return phel + nhel, phel, nhel
Exemple #13
0
def parcelx(lower, upper, pres, temp, dwpt, prof, **kwargs):
    '''
    Lifts the specified parcel, calculated various levels and parameters from
    the profile object. B+/B- are calculated based on the specified layer.

    !! All calculations use the virtual temperature correction unless noted. !!

    Inputs
    ------
        lower       (float)                 Lower-bound lifting level (hPa)
        upper       (float)                 Upper-bound lifting level
        pres        (float)                 Pressure of parcel to lift (hPa)
        temp        (float)                 Temperature of parcel to lift (C)
        dwpt        (float)                 Dew Point of parcel to lift (C)
        prof        (profile object)        Profile Object

    Returns
    -------
        pcl         (parcel object)         Parcel Object
    '''
    pcl = Parcel(-1, -1, pres, temp, dwpt)
    if 'lplvals' in kwargs: pcl.lplvals = kwargs.get('lplvals')
    else:
        lplvals = DefineParcel(prof, 5, pres=pres, temp=temp, dwpt=dwpt)
        pcl.lplvals = lplvals

    if prof.gNumLevels < 1: return pcl

    lyre = -1
    cap_strength = RMISSD
    cap_strengthpres = RMISSD
    li_max = RMISSD
    li_maxpres = RMISSD
    totp = 0.
    totn = 0.
    tote = 0.
    cinh_old = 0.

    # See if default layer is specified
    if lower == -1:
        lower = prof.gSndg[prof.sfc][prof.pind]
        pcl.blayer = lower
    if upper == -1:
        upper = prof.gSndg[prof.gNumLevels-1][prof.pind]
        pcl.tlayer = upper

    # Make sure that this is a valid layer
    if lower > pres:
        lower = pres
        pcl.blayer = lower
    if not QC(interp.vtmp(lower, prof)) or \
       not QC(interp.vtmp(upper, prof)):
        return RMISSD

    # Begin with the Mixing Layer
    te1 = interp.vtmp(pres, prof)
    pe1 = lower
    h1 = interp.hght(pe1, prof)
    tp1 = thermo.virtemp(pres, temp, dwpt)
    # te1 = tp1

    # Lift parcel and return LCL pres (hPa) and LCL temp (c)
    pe2, tp2 = thermo.drylift(pres, temp, dwpt)
    blupper = pe2       # Define top of layer as LCL pres
    h2 = interp.hght(pe2, prof)
    te2 = interp.vtmp(pe2, prof)
    pcl.lclpres = pe2
    pcl.lclhght = interp.agl(h2, prof)

    # Calculate lifted parcel theta for use in iterative CINH loop below
    # RECALL: lifted parcel theta is CONSTANT from LPL to LCL
    theta_parcel = thermo.theta(pe2, tp2, 1000.)

    # Environmental theta and mixing ratio at LPL
    bltheta = thermo.theta(pres, interp.temp(pres, prof), 1000.)
    blmr = thermo.mixratio(pres, dwpt)

    # ACCUMULATED CINH IN MIXING LAYER BELOW THE LCL
    # This will be done in 10mb increments, and will use the virtual
    # temperature correction where possible
    pinc = -10
    a = int(lower)
    b = int(blupper)
    for pp in range(a, b, int(pinc)):
        pp1 = pp
        pp2 = pp + pinc
        if pp2 < blupper: pp2 = blupper
        dz = interp.hght(pp2, prof) - interp.hght(pp1, prof)

        # Calculate difference between Tv_parcel and Tv_environment at top
        # and bottom of 10mb layers. Make use of constant lifted parcel
        # theta and mixing ratio from LPL to LCL
        tv_env_bot = thermo.virtemp(pp1, thermo.theta(pp1,
            interp.temp(pp1, prof), 1000.), interp.dwpt(pp1, prof))
        tdef1 = (thermo.virtemp(pp1, theta_parcel,
            thermo.temp_at_mixrat(blmr, pp1)) - tv_env_bot) / \
            (thermo.ctok(tv_env_bot))

        tv_env_top = thermo.virtemp(pp2, thermo.theta(pp2,
            interp.temp(pp2, prof), 1000.), interp.dwpt(pp2, prof))
        tdef2 = (thermo.virtemp(pp2, theta_parcel,
            thermo.temp_at_mixrat(blmr, pp2)) - tv_env_top) / \
            (thermo.ctok(tv_env_bot))

        lyre = G * (tdef1 + tdef2) / 2. * dz
        if lyre < 0: totn += lyre

    # Move the bottom layer to the top of the boundary layer
    if lower > pe2:
        lower = pe2
        pcl.blayer = lower

    # Calculate height of various temperature levels
    p0c = temp_lvl(0., prof)
    pm10c = temp_lvl(-10., prof)
    pm20c = temp_lvl(-20., prof)
    pm30c = temp_lvl(-30., prof)
    hgt0c = interp.hght(p0c, prof)
    hgtm10c = interp.hght(pm10c, prof)
    hgtm20c = interp.hght(pm20c, prof)
    hgtm30c = interp.hght(pm30c, prof)
    pcl.p0c = p0c
    pcl.pm10c = pm10c
    pcl.pm20c = pm20c
    pcl.pm30c = pm30c
    pcl.hght0c = hgt0c
    pcl.hghtm10c = hgtm10c
    pcl.hghtm20c = hgtm20c
    pcl.hghtm30c = hgtm30c

    # Find lowest observation in layer
    i = 0
    while prof.gSndg[i][prof.pind] > lower:
        if i == prof.gNumLevels-1: break
        i += 1
    while not QC(prof.gSndg[i][prof.tdind]):
        if i == prof.gNumLevels-1: break
        i += 1
    lptr = i
    if prof.gSndg[i][prof.pind] == lower:
        if i != prof.gNumLevels-1: lptr += 1

    # Find highest observation in layer
    i = prof.gNumLevels-1
    while prof.gSndg[i][prof.pind] < upper:
        if i < lptr: break
        i -= 1
    uptr = i
    if prof.gSndg[i][prof.pind] == upper:
        if i > lptr: uptr -= 1

    # START WITH INTERPOLATED BOTTOM LAYER
    # Begin moist ascent from lifted parcel LCL (pe2, tp2)
    pe1 = lower
    h1 = interp.hght(pe1, prof)
    te1 = interp.vtmp(pe1, prof)
    tp1 = thermo.wetlift(pe2, tp2, pe1)
    lyre = 0
    lyrlast = 0
    for i in range(lptr, prof.gNumLevels):
        if not QC(prof.gSndg[i][prof.tind]): continue
        pe2 = prof.gSndg[i][prof.pind]
        h2 = prof.gSndg[i][prof.zind]
        te2 = interp.vtmp(pe2, prof)
        tp2 = thermo.wetlift(pe1, tp1, pe2)
        tdef1 = (thermo.virtemp(pe1, tp1, tp1) - te1) / thermo.ctok(te1)
        tdef2 = (thermo.virtemp(pe2, tp2, tp2) - te2) / thermo.ctok(te2)
        lyrlast = lyre
        lyre = G * (tdef1 + tdef2) / 2. * (h2 - h1)

        # Add layer energy to total positive if lyre > 0
        if lyre > 0: totp += lyre
        # Add layer energy to total negative if lyre < 0, only up to EL
        else:
            if pe2 > 500.: totn += lyre

        # Check for Max LI
        mli = thermo.virtemp(pe2, tp2, tp2) - te2
        if  mli > li_max:
            li_max = mli
            li_maxpres = pe2

        # Check for Max Cap Strength
        mcap = te2 - mli
        if mcap > cap_strength:
            cap_strength = mcap
            cap_strengthpres = pe2

        tote += lyre
        pelast = pe1
        pe1 = pe2
        h1 = h2
        te1 = te2
        tp1 = tp2

        # Is this the top of the specified layer
        if i >= uptr and not QC(pcl.bplus):
            pe3 = pe1
            h3 = h1
            te3 = te1
            tp3 = tp1
            lyrf = lyre
            if lyrf > 0:
                pcl.bplus = totp - lyrf
                pcl.bminus = totn
            else:
                pcl.bplus = totp
                if pe2 > 500.: pcl.bminus = totn + lyrf
                else: pcl.bminus = totn
            pe2 = upper
            h2 = interp.hght(pe2, prof)
            te2 = interp.vtmp(pe2, prof)
            tp2 = thermo.wetlift(pe3, tp3, pe2)
            tdef3 = (thermo.virtemp(pe3, tp3, tp3) - te3) / thermo.ctok(te3)
            tdef2 = (thermo.virtemp(pe2, tp2, tp2) - te2) / thermo.ctok(te2)
            lyrf = G * (tdef3 + tdef2) / 2. * (h2 - h3)
            if lyrf > 0: pcl.bplus += lyrf
            else:
                if pe2 > 500.: pcl.bminus += lyrf
            if pcl.bplus == 0: pcl.bminus = 0.

        # Is this the freezing level
        if te2 < 0. and not QC(pcl.bfzl):
            pe3 = pelast
            h3 = interp.hght(pe3, prof)
            te3 = interp.vtmp(pe3, prof)
            tp3 = thermo.wetlift(pe1, tp1, pe3)
            lyrf = lyre
            if lyrf > 0.: pcl.bfzl = totp - lyrf
            else: pcl.bfzl = totp
            if not QC(p0c) or p0c > pe3:
                pcl.bfzl = 0
            elif QC(pe2):
                te2 = interp.vtmp(pe2, prof)
                tp2 = thermo.wetlift(pe3, tp3, pe2)
                tdef3 = (thermo.virtemp(pe3, tp3, tp3) - te3) / \
                    thermo.ctok(te3)
                tdef2 = (thermo.virtemp(pe2, tp2, tp2) - te2) / \
                    thermo.ctok(te2)
                lyrf = G * (tdef3 + tdef2) / 2. * (hgt0c - h3)
                if lyrf > 0: pcl.bfzl += lyrf

        # Is this the -10C level
        if te2 < -10. and not QC(pcl.wm10c):
            pe3 = pelast
            h3 = interp.hght(pe3, prof)
            te3 = interp.vtmp(pe3, prof)
            tp3 = thermo.wetlift(pe1, tp1, pe3)
            lyrf = lyre
            if lyrf > 0.: pcl.wm10c = totp - lyrf
            else: pcl.wm10c = totp
            if not QC(pm10c) or pm10c > pcl.lclpres:
                pcl.wm10c = 0
            elif QC(pe2):
                te2 = interp.vtmp(pe2, prof)
                tp2 = thermo.wetlift(pe3, tp3, pe2)
                tdef3 = (thermo.virtemp(pe3, tp3, tp3) - te3) / \
                    thermo.ctok(te3)
                tdef2 = (thermo.virtemp(pe2, tp2, tp2) - te2) / \
                    thermo.ctok(te2)
                lyrf = G * (tdef3 + tdef2) / 2. * (hgtm10c - h3)
                if lyrf > 0: pcl.wm10c += lyrf

        # Is this the -20C level
        if te2 < -20. and not QC(pcl.wm20c):
            pe3 = pelast
            h3 = interp.hght(pe3, prof)
            te3 = interp.vtmp(pe3, prof)
            tp3 = thermo.wetlift(pe1, tp1, pe3)
            lyrf = lyre
            if lyrf > 0.: pcl.wm20c = totp - lyrf
            else: pcl.wm20c = totp
            if not QC(pm20c) or pm20c > pcl.lclpres:
                pcl.wm20c = 0
            elif QC(pe2):
                te2 = interp.vtmp(pe2, prof)
                tp2 = thermo.wetlift(pe3, tp3, pe2)
                tdef3 = (thermo.virtemp(pe3, tp3, tp3) - te3) / \
                    thermo.ctok(te3)
                tdef2 = (thermo.virtemp(pe2, tp2, tp2) - te2) / \
                    thermo.ctok(te2)
                lyrf = G * (tdef3 + tdef2) / 2. * (hgtm20c - h3)
                if lyrf > 0: pcl.wm20c += lyrf

        # Is this the -30C level
        if te2 < -30. and not QC(pcl.wm30c):
            pe3 = pelast
            h3 = interp.hght(pe3, prof)
            te3 = interp.vtmp(pe3, prof)
            tp3 = thermo.wetlift(pe1, tp1, pe3)
            lyrf = lyre
            if lyrf > 0.: pcl.wm30c = totp - lyrf
            else: pcl.wm30c = totp
            if not QC(pm30c) or pm30c > pcl.lclpres:
                pcl.wm30c = 0
            elif QC(pe2):
                te2 = interp.vtmp(pe2, prof)
                tp2 = thermo.wetlift(pe3, tp3, pe2)
                tdef3 = (thermo.virtemp(pe3, tp3, tp3) - te3) / \
                    thermo.ctok(te3)
                tdef2 = (thermo.virtemp(pe2, tp2, tp2) - te2) / \
                    thermo.ctok(te2)
                lyrf = G * (tdef3 + tdef2) / 2. * (hgtm30c - h3)
                if lyrf > 0: pcl.wm30c += lyrf

        # Is this the 3km level
        if pcl.lclhght < 3000.:
            h = interp.agl(interp.hght(pe2, prof), prof)
            if h >= 3000. and not QC(pcl.b3km):
                pe3 = pelast
                h3 = interp.hght(pe3, prof)
                te3 = interp.vtmp(pe3, prof)
                tp3 = thermo.wetlift(pe1, tp1, pe3)
                lyrf = lyre
                if lyrf > 0: pcl.b3km = totp - lyrf
                else: pcl.b3km = totp
                h2 = interp.msl(3000., prof)
                pe2 = interp.pres(h2, prof)
                if QC(pe2):
                    te2 = interp.vtmp(pe2, prof)
                    tp2 = thermo.wetlift(pe3, tp3, pe2)
                    tdef3 = (thermo.virtemp(pe3, tp3, tp3) - te3) / \
                        thermo.ctok(te3)
                    tdef2 = (thermo.virtemp(pe2, tp2, tp2) - te2) / \
                        thermo.ctok(te2)
                    lyrf = G * (tdef3 + tdef2) / 2. * (h2 - h3)
                    if lyrf > 0: pcl.b3km += lyrf
        else: pcl.b3km = 0.

        # Is this the 6km level
        if pcl.lclhght < 6000.:
            h = interp.agl(interp.hght(pe2, prof), prof)
            if h >= 6000. and not QC(pcl.b6km):
                pe3 = pelast
                h3 = interp.hght(pe3, prof)
                te3 = interp.vtmp(pe3, prof)
                tp3 = thermo.wetlift(pe1, tp1, pe3)
                lyrf = lyre
                if lyrf > 0: pcl.b6km = totp - lyrf
                else: pcl.b6km = totp
                h2 = interp.msl(6000., prof)
                pe2 = interp.pres(h2, prof)
                if QC(pe2):
                    te2 = interp.vtmp(pe2, prof)
                    tp2 = thermo.wetlift(pe3, tp3, pe2)
                    tdef3 = (thermo.virtemp(pe3, tp3, tp3) - te3) / \
                        thermo.ctok(te3)
                    tdef2 = (thermo.virtemp(pe2, tp2, tp2) - te2) / \
                        thermo.ctok(te2)
                    lyrf = G * (tdef3 + tdef2) / 2. * (h2 - h3)
                    if lyrf > 0: pcl.b6km += lyrf
        else: pcl.b6km = 0.

        # LFC Possibility
        if lyre >= 0. and lyrlast <= 0.:
            tp3 = tp1
            te3 = te1
            pe2 = pe1
            pe3 = pelast
            while interp.vtmp(pe3, prof) > thermo.virtemp(pe3,
                thermo.wetlift(pe2, tp3, pe3), thermo.wetlift(pe2, tp3, pe3)):
                    pe3 -= 5
            pcl.lfcpres = pe3
            pcl.lfchght = interp.agl(interp.hght(pe3, prof), prof)
            cinh_old = totn
            tote = 0.
            pcl.elpres = RMISSD
            li_max = RMISSD

            if cap_strength < 0.: cap_strength = 0.
            pcl.cap = cap_strength
            pcl.cappres = cap_strengthpres
            # Hack to force LFC to be at least at the LCL
            if pcl.lfcpres > pcl.lclpres:
                pcl.lfcpres = pcl.lclpres
                pcl.lfchght = pcl.lclhght

        # EL Possibility
        if lyre <= 0. and lyrlast >= 0.:
            tp3 = tp1
            te3 = te1
            pe2 = pe1
            pe3 = pelast
            while interp.vtmp(pe3, prof) < thermo.virtemp(pe3,
                thermo.wetlift(pe2, tp3, pe3), thermo.wetlift(pe2, tp3, pe3)):
                    pe3 -= 5
            pcl.elpres = pe3
            pcl.elhght = interp.agl(interp.hght(pe3, prof), prof)
            pcl.mplpres = RMISSD
            pcl.limax = -li_max
            pcl.limaxpress = li_maxpres

        # MPL Possibility
        if tote < 0. and not QC(pcl.mplpres) and QC(pcl.elpres):
            pe3 = pelast
            h3 = interp.hght(pe3, prof)
            te3 = interp.vtmp(pe3, prof)
            tp3 = thermo.wetlift(pe1, tp1, pe3)
            totx = tote - lyre
            pe2 = pelast
            while totx > 0:
                pe2 -= 1
                te2 = interp.vtmp(pe2, prof)
                tp2 = thermo.wetlift(pe3, tp3, pe2)
                h2 = interp.hght(pe2, prof)
                tdef3 = (thermo.virtemp(pe3, tp3, tp3) - te3) / \
                    thermo.ctok(te3)
                tdef2 = (thermo.virtemp(pe2, tp2, tp2) - te2) / \
                    thermo.ctok(te2)
                lyrf = G * (tdef3 + tdef2) / 2. * (h2 - h3)
                totx += lyrf
                tp3 = tp2
                te3 = te2
                pe3 = pe2
            pcl.mplpres = pe2
            pcl.mplhght = interp.agl(interp.hght(pe2, prof), prof)

        # 500 hPa Lifted Index
        if prof.gSndg[i][prof.pind] <= 500. and pcl.li5 == RMISSD:
            a = interp.vtmp(500., prof)
            b = thermo.wetlift(pe1, tp1, 500.)
            pcl.li5 = a - thermo.virtemp(500, b, b)

        # 300 hPa Lifted Index
        if prof.gSndg[i][prof.pind] <= 300. and pcl.li3 == RMISSD:
            a = interp.vtmp(300., prof)
            b = thermo.wetlift(pe1, tp1, 300.)
            pcl.li3 = a - thermo.virtemp(300, b, b)

    # Calculate BRN if available
    pcl = bulk_rich(pcl, prof)

    pcl.bminus = cinh_old
    if pcl.bplus == 0: pcl.bminus = 0.
    return pcl
Exemple #14
0
def helicity(lower, upper, prof, stu=0, stv=0):
    '''
    Calculates the relative helicity (m2/s2) of a layer from lower to upper.
    If storm-motion vector is supplied, storm-relative helicity, both
    positve and negative, is returned.

    Inputs
    ------
        lower       (float)             Bottom level of layer (m, AGL)
        upper       (float)             Top level of layer (m, AGL)
        prof        (profile object)    Profile Object
        stu         (float; optional)   U-component of storm-motion
        stv         (float; optional)   V-component of storm-motion

    Returns
    -------
        phel+nhel   (float)             Combined Helicity (m2/s2)
        phel        (float)             Positive Helicity (m2/s2)
        nhel        (float)             Negative Helicity (m2/s2)
    '''
    lower = interp.msl(lower, prof)
    upper = interp.msl(upper, prof)
    plower = interp.pres(lower, prof)
    pupper = interp.pres(upper, prof)
    phel = 0
    nhel = 0

    # Find lower and upper ind bounds for looping
    i = 0
    while interp.msl(prof.gSndg[i][prof.zind], prof) < lower: i+=1
    lptr = i
    if interp.msl(prof.gSndg[i][prof.zind], prof) == lower: lptr+=1
    while interp.msl(prof.gSndg[i][prof.zind], prof) <= upper: i+=1
    uptr = i
    if interp.msl(prof.gSndg[i][prof.zind], prof) == upper: uptr-=1


    # Integrate from interpolated bottom level to iptr level
    sru1, srv1 = interp.components(plower, prof)
    sru1 = KTS2MS(sru1 - stu)
    srv1 = KTS2MS(srv1 - stv)

    # Loop through levels
    for i in range(lptr, uptr+1):
        if QC(prof.gSndg[i][prof.uind]) and QC(prof.gSndg[i][prof.vind]):
            sru2, srv2 = interp.components(prof.gSndg[i][prof.pind], prof)
            sru2 = KTS2MS(sru2 - stu)
            srv2 = KTS2MS(srv2 - stv)
            lyrh = (sru2 * srv1) - (sru1 * srv2)
            if lyrh > 0: phel += lyrh
            else: nhel += lyrh
            sru1 = sru2
            srv1 = srv2

    # Integrate from tptr level to interpolated top level
    sru2, srv2 = interp.components(pupper, prof)
    sru2 = KTS2MS(sru2 - stu)
    srv2 = KTS2MS(srv2 - stv)

    lyrh = (sru2 * srv1) - (sru1 * srv2)
    if lyrh > 0: phel += lyrh
    else: nhel += lyrh
    return phel+nhel, phel, nhel