예제 #1
0
def write_les_profiles(les):
    U, V, T, SH, QL, QI, Pf, Ph, A, Zgfull, Zghalf = (getattr(
        les, varname, None) for varname in gcm_vars)

    Zf = les.gcm_Zf  # note: gcm Zf varies in time and space - must get it again after every step, for every column
    h = les.get_zf()
    u_d = les.get_profile_U()
    v_d = les.get_profile_V()
    sp_d = les.get_presf()
    thl_d = les.get_profile_THL()
    qt_d = les.get_profile_QT()
    ql_d = les.get_profile_QL()
    ql_ice_d = les.get_profile_QL_ice()  # ql_ice is the ice part of QL
    ql_water_d = ql_d - ql_ice_d  # ql_water is the water part of ql
    qr_d = les.get_profile_QR()
    A_d = get_cloud_fraction(les)
    # dales state
    # dales.cdf.variables['presh'][gcm.step] = dales.get_presh().value_in(units.Pa) # todo associate with zh in netcdf

    # calculate real temperature from Dales' thl, qt, using the pressures from openIFS
    pf = sputils.interp(h, Zf[::-1], Pf[::-1])
    t = thl_d * sputils.exner(pf) + sputils.rlv * ql_d / sputils.cp

    # get real temperature from Dales - note it is calculated internally from thl and ql
    t_d = les.get_profile_T()

    spio.write_les_data(les,
                        u=u_d.value_in(units.m / units.s),
                        v=v_d.value_in(units.m / units.s),
                        presf=sp_d.value_in(units.Pa),
                        qt=qt_d.value_in(units.mfu),
                        ql=ql_d.value_in(units.mfu),
                        ql_ice=ql_ice_d.value_in(units.mfu),
                        ql_water=ql_water_d.value_in(units.mfu),
                        thl=thl_d.value_in(units.K),
                        t=t.value_in(units.K),
                        t_=t_d.value_in(units.K),
                        qr=qr_d.value_in(units.mfu))
예제 #2
0
def variability_nudge(les, gcm, write=True):
    # this cannot be used before the LES has been stepped - otherwise qsat and ql are not defined.

    qsat = les.get_field("Qsat")
    qt = les.get_field("QT")
    ql2 = les.get_profile("QL")

    qt_av = les.get_profile("QT")

    itot, jtot = les.get_itot(), les.get_jtot()

    ql = (qt - qsat).maximum(0 | units.mfu).sum(axis=(0, 1)) / (itot * jtot)

    # strangely, this doesn't have a unit
    # the part before / has the unit mfu
    # mfu is dimensionless - might be the reason.
    # use mean instead of sum / size  ?

    # ql_ref has unit mfu

    # print('---', les.lat, les.lon, '---')
    # print(les.QL)
    # print(les.ql_ref)
    # print(ql)
    # print(ql2)
    # print(les.get_itot(), les.get_jtot())
    # print ('---------')

    # get ql difference
    # note the implicit k, qt, qt_av, qsat variables
    def get_ql_diff(beta):
        result = (beta *
                  (qt[:, :, k] - qt_av[k]) + qt_av[k] - qsat[:, :, k]).maximum(
                      0 | units.mfu).sum() / (itot * jtot) - les.ql_ref[k]
        return result.number

    beta_min = 0  # search interval
    beta_max = 2000

    beta = numpy.ones(les.k)
    for k in range(0, les.k):
        current_ql_diff = get_ql_diff(1)

        if les.ql_ref[
                k] > 1e-9:  # significant amount of clouds in the GCM. Nudge towards this amount.
            # print (k, 'significant ql_ref')
            q_min = get_ql_diff(beta_min)
            q_max = get_ql_diff(beta_max)
            if q_min > 0 or q_max < 0:
                log.info(
                    "k:%d didn't bracket a zero. qmin:%f, qmax:%f, qt_avg:%f, stdev(qt):%f "
                    % (k, q_min, q_max, numpy.mean(
                        qt[:, :, k]).number, numpy.std(qt[:, :, k]).number))
                # seems to happen easily in the sponge layer, where the variability is kept small
                continue
            beta[k] = brentq(get_ql_diff, beta_min, beta_max)

        elif ql[k] > les.ql_ref[
                k]:  # The GCM says no clouds, or very little, and the LES has more than this.
            # Nudge towards barely unsaturated.
            i, j = numpy.unravel_index(
                numpy.argmax(qt[:, :, k] - qsat[:, :, k]), qt[:, :, k].shape)
            beta[k] = (qsat[i, j, k] - qt_av[k]) / (qt[i, j, k] - qt_av[k])
            # print (qt[i,j,k].value_in(units.mfu))
            # print (qsat[i,j,k].value_in(units.mfu))
            # print(qt_av[k].value_in(units.mfu))
            # print(ql[k].value_in(units.mfu))
            # print(les.ql_ref[k].value_in(units.mfu))
            log.info(
                '%d nudging towards non-saturation. Max at (%d,%d). qt:%f, qsat:%f, qt_av[k]:%f, beta:%f, ql_avg:%f, '
                'ql_ref:%f' % (k, i, j, qt[i, j, k].value_in(
                    units.mfu), qsat[i, j, k].value_in(
                        units.mfu), qt_av[k].value_in(units.mfu), beta[k],
                               ql[k], les.ql_ref[k].value_in(units.mfu)))
            if beta[k] < 0:
                # this happens when qt_av > qsat
                log.info('  beta<0, setting beta=1 ')
                beta[k] = 1
        else:
            continue  # no nudge - don't print anything

        # print (k, current_ql_diff, les.ql_ref[k], beta[k])

    alpha = numpy.log(beta) / gcm.get_timestep()
    les.set_qt_variability_factor(alpha)

    qt_std = qt.std(axis=(0, 1))

    if write:
        spio.write_les_data(les, qt_alpha=alpha.value_in(1 / units.s))
        spio.write_les_data(les,
                            qt_beta=beta,
                            qt_std=qt_std.value_in(units.mfu))
예제 #3
0
def set_gcm_tendencies(gcm, les, factor=1, write=True):
    U, V, T, SH, QL, QI, Pf, Ph, A, Zgfull, Zghalf = (getattr(
        les, varname, None) for varname in gcm_vars)

    Zf = les.gcm_Zf  # note: gcm Zf varies in time and space - must get it again after every step, for every column
    h = les.get_zf()
    u_d = les.get_profile_U()
    v_d = les.get_profile_V()
    sp_d = les.get_presf()
    rhof_d = les.get_rhof()
    rhobf_d = les.get_rhobf()
    thl_d = les.get_profile_THL()
    qt_d = les.get_profile_QT()
    ql_d = les.get_profile_QL()
    ql_ice_d = les.get_profile_QL_ice()  # ql_ice is the ice part of QL
    ql_water_d = ql_d - ql_ice_d  # ql_water is the water part of ql
    qr_d = les.get_profile_QR()
    A_d = get_cloud_fraction(les)
    # dales state
    # dales.cdf.variables['presh'][gcm.step] = dales.get_presh().value_in(units.Pa) # todo associate with zh in netcdf

    # calculate real temperature from Dales' thl, qt, using the pressures from openIFS
    pf = sputils.interp(h, Zf[::-1], Pf[::-1])
    t = thl_d * sputils.exner(pf) + sputils.rlv * ql_d / sputils.cp

    # get real temperature from Dales - note it is calculated internally from thl and ql
    t_d = les.get_profile_T()

    if write:
        spio.write_les_data(les,
                            u=u_d.value_in(units.m / units.s),
                            v=v_d.value_in(units.m / units.s),
                            presf=sp_d.value_in(units.Pa),
                            rhof=rhof_d.value_in(units.kg / units.m**3),
                            rhobf=rhobf_d.value_in(units.kg / units.m**3),
                            qt=qt_d.value_in(units.mfu),
                            ql=ql_d.value_in(units.mfu),
                            ql_ice=ql_ice_d.value_in(units.mfu),
                            ql_water=ql_water_d.value_in(units.mfu),
                            thl=thl_d.value_in(units.K),
                            t=t.value_in(units.K),
                            t_=t_d.value_in(units.K),
                            qr=qr_d.value_in(units.mfu))

    # forcing
    ft = gcm.get_timestep()  # should be the length of the NEXT time step

    # interpolate to GCM heights
    t_d = sputils.interp(Zf, h, t_d)
    qt_d = sputils.interp(Zf, h, qt_d)
    ql_d = sputils.interp(Zf, h, ql_d)
    ql_water_d = sputils.interp(Zf, h, ql_water_d)
    ql_ice_d = sputils.interp(Zf, h, ql_ice_d)
    u_d = sputils.interp(Zf, h, u_d)
    v_d = sputils.interp(Zf, h, v_d)

    # log.info("Height of LES system: %f" % h[-1])
    # first index in the openIFS colum which is inside the Dales system
    start_index = sputils.searchsorted(-Zf, -h[-1])

    # log.info("start_index: %d" % start_index)

    f_T = factor * (t_d - T) / ft
    f_SH = factor * (
        (qt_d - ql_d) - SH) / ft  # !!!!! -ql_d here - SH is vapour only.
    f_QL = factor * (ql_water_d - QL) / ft  # condensed liquid water
    f_QI = factor * (ql_ice_d - QI) / ft  # condensed water as ice
    # f_QL = factor * (ql_d - (QL+QI)) / ft dales QL is both liquid and ice - f_QL is liquid only. this conserves
    # water mass but makes an error in latent heat.
    f_U = factor * (u_d - U) / ft
    f_V = factor * (v_d - V) / ft
    f_A = factor * (A_d - A) / ft

    f_T[0:start_index] *= 0  # zero out the forcings above the Dales system
    f_SH[0:start_index] *= 0  # TODO : taper off smoothly instead
    f_QL[0:start_index] *= 0
    f_QI[0:start_index] *= 0
    f_U[0:start_index] *= 0
    f_V[0:start_index] *= 0
    f_A[0:start_index] *= 0

    # careful with double coriolis
    gcm.set_profile_tendency("U", les.grid_index, f_U)

    gcm.set_profile_tendency("V", les.grid_index, f_V)
    gcm.set_profile_tendency("T", les.grid_index, f_T)
    gcm.set_profile_tendency("SH", les.grid_index, f_SH)
    gcm.set_profile_tendency("QL", les.grid_index, f_QL)
    gcm.set_profile_tendency("QI", les.grid_index, f_QI)
    gcm.set_profile_tendency("A", les.grid_index, f_A)

    # store forcings on GCM in the statistics in the corresponding LES group
    if write:
        spio.write_les_data(les,
                            f_U=f_U.value_in(units.m / units.s**2),
                            f_V=f_V.value_in(units.m / units.s**2),
                            f_T=f_T.value_in(units.K / units.s),
                            f_SH=f_SH.value_in(units.shu / units.s),
                            A=A.value_in(units.ccu),
                            A_d=A_d.value_in(units.ccu),
                            f_QL=f_QL.value_in(units.mfu / units.s),
                            f_QI=f_QI.value_in(units.mfu / units.s),
                            f_A=f_A.value_in(units.ccu / units.s))
예제 #4
0
def set_les_forcings(les,
                     gcm,
                     dt_gcm,
                     factor,
                     couple_surface,
                     qt_forcing='sp',
                     write=True):
    u, v, thl, qt, ps, ql = convert_profiles(les)

    # get dales slab averages
    u_d = les.get_profile_U()
    v_d = les.get_profile_V()
    thl_d = les.get_profile_THL()
    qt_d = les.get_profile_QT()
    ql_d = les.get_profile_QL()
    ps_d = les.get_surface_pressure()

    try:
        rain_last = les.rain
    except:
        rain_last = 0 | units.kg / units.m**2
    rain = les.get_rain()
    les.rain = rain
    rainrate = (rain - rain_last) / dt_gcm

    # ft = dt  # forcing time constant

    # forcing
    f_u = factor * (u - u_d) / dt_gcm
    f_v = factor * (v - v_d) / dt_gcm
    f_thl = factor * (thl - thl_d) / dt_gcm
    f_qt = factor * (qt - qt_d) / dt_gcm
    f_ps = factor * (ps - ps_d) / dt_gcm
    f_ql = factor * (ql - ql_d) / dt_gcm

    # log.info("RMS forcings at %d during time step" % les.grid_index)
    # dt_gcm = gcm.get_timestep().value_in(units.s)
    # log.info("  u  : %f" % (sputils.rms(f_u)*dt_gcm))
    # log.info("  v  : %f" % (sputils.rms(f_v)*dt_gcm))
    # log.info("  thl: %f" % (sputils.rms(f_thl)*dt_gcm))
    # log.info("  qt : %f" % (sputils.rms(f_qt)*dt_gcm))

    # store forcings on dales in the statistics
    if write:
        spio.write_les_data(
            les,
            f_u=f_u.value_in(units.m / units.s**2),
            f_v=f_v.value_in(units.m / units.s**2),
            f_thl=f_thl.value_in(units.K / units.s),
            f_qt=f_qt.value_in(units.mfu / units.s),
            rain=rain.value_in(units.kg / units.m**2),
            rainrate=rainrate.value_in(units.kg / units.m**2 / units.s) * 3600)

    # set tendencies for Dales
    les.set_tendency_U(f_u)
    les.set_tendency_V(f_v)
    les.set_tendency_THL(f_thl)
    les.set_tendency_QT(f_qt)
    les.set_tendency_surface_pressure(f_ps)
    les.set_tendency_QL(f_ql)  # used in experimental local qt nudging
    les.set_ref_profile_QL(ql)  # used in experimental variability nudging

    les.ql_ref = ql  # store ql profile from GCM, interpolated to the LES levels
    # for another variant of variability nudging

    # transfer surface quantities
    if couple_surface:
        z0m, z0h, wt, wq = convert_surface_fluxes(les)
        les.set_z0m_surf(z0m)
        les.set_z0h_surf(z0h)
        les.set_wt_surf(wt)
        les.set_wq_surf(wq)
        if write:
            spio.write_les_data(les,
                                z0m=z0m.value_in(units.m),
                                z0h=z0h.value_in(units.m),
                                wthl=wt.value_in(units.m * units.s**-1 *
                                                 units.K),
                                wqt=wq.value_in(units.m / units.s))

            spio.write_les_data(
                les,
                TLflux=les.TLflux.value_in(units.W / units.m**2),
                TSflux=les.TSflux.value_in(units.W / units.m**2),
                SHflux=les.SHflux.value_in(units.kg / units.m**2 / units.s),
                QLflux=les.QLflux.value_in(units.kg / units.m**2 / units.s),
                QIflux=les.QIflux.value_in(units.kg / units.m**2 / units.s))

    if qt_forcing == 'variance':
        if les.get_model_time() > 0 | units.s:
            starttime = time.time()
            variability_nudge(les, gcm)
            walltime = time.time() - starttime
            log.info("variability nudge took %6.2f s" % walltime)
예제 #5
0
def convert_profiles(les, write=True):
    U, V, T, SH, QL, QI, Pf, Ph, A, Zgfull, Zghalf = (getattr(
        les, varname, None) for varname in gcm_vars)

    # virtual temperature - used to get heights
    c = sputils.rv / sputils.rd - 1  # epsilon^(-1) -1  = 0.61
    Tv = T * (1 + c * SH - (QL + QI))
    # is it correct to include QI here?
    # like liquid water, ice contributes to the density but not (much) to pressure

    # dP = Ph[1:] - Ph[:-1]  # dP - pressure difference over one cell
    # dZ = sputils.rd * Tv / (sputils.grav * Pf) * dP  # dZ - height of one cell

    # sum up dZ to get Z at half-levels.
    # 0 is at the end of the list, therefore reverse lists before and after.
    # Zh_local = numpy.cumsum(dZ[::-1])[::-1]

    # Zh_local.append(0 | units.m)  # append a 0 for ground

    # height of full levels - simply average half levels (for now)
    # better: use full level pressure to calculate height?
    # Zf_local = (Zh[1:] + Zh[:-1]) * .5

    # use Zgfull, Zghalf from IFS directly instead of calculating from pressure
    # these values seem close to what we used before.
    # 2% difference at top, 0.2% difference close to ground.
    Zh = (Zghalf - Zghalf[-1]) / sputils.grav
    Zf = (Zgfull - Zghalf[-1]) / sputils.grav

    les.gcm_Zf = Zf  # save height levels in the les object for re-use
    les.gcm_Zh = Zh

    #print ('Zf ', Zf[-5:])
    #print ('Zf_local', Zf_local[-5:])
    #print ('Zh ', Zh[-5:])
    #print ('Zh_local', Zh_local[-5:])
    #print ('Zf relative diff\n', (Zf_local-Zf)/Zf)
    #print ('Zh relative diff\n', (Zh_local[:-1]-Zh[:-1])/Zh[:-1])

    # Convert from OpenIFS quantities to les
    # note - different from modtestbed - iexner multiplied with both terms
    # could include QI as well.
    thl_ = (T - (sputils.rlv * (QL + QI)) / sputils.cp) * sputils.iexner(Pf)
    qt_ = SH + QL + QI

    # interpolate to les' heights
    # quirks:
    #   Zf must be increasing, so reverse the gcm arrays
    #   outside the range of Zf, interp returns the first or the last point of the range

    h = les.get_zf()

    thl = sputils.interp(h, Zf[::-1], thl_[::-1])
    qt = sputils.interp(h, Zf[::-1], qt_[::-1])
    ql = sputils.interp(h, Zf[::-1], QL[::-1])
    u = sputils.interp(h, Zf[::-1], U[::-1])
    v = sputils.interp(h, Zf[::-1], V[::-1])

    if write:
        spio.write_les_data(
            les,
            U=U.value_in(units.m / units.s),
            V=V.value_in(units.m / units.s),
            T=T.value_in(units.K),
            SH=SH.value_in(units.shu),
            QL=QL.value_in(units.mfu),
            QI=QI.value_in(units.mfu),  # A.value_in(units.ccu)
            Pf=Pf.value_in(units.Pa),
            Ph=Ph[1:].value_in(units.Pa),
            Zf=Zf.value_in(units.m),
            Zh=Zh[1:].value_in(units.m),
            Psurf=Ph[-1].value_in(units.Pa),
            Tv=Tv.value_in(units.K),
            THL=thl_.value_in(units.K),
            QT=qt_.value_in(units.mfu))

    return u, v, thl, qt, Ph[-1], ql
예제 #6
0
def set_gcm_tendencies(gcm, les, factor=1):
    U, V, T, SH, QL, QI, Pf, Ph, A = (getattr(les, varname, None)
                                      for varname in gcm_vars)

    Zf = les.gcm_Zf  # note: gcm Zf varies in time and space - must get it again after every step, for every column
    h = les.zf.value_in(units.m)
    u_d = les.get_profile_U().value_in(units.m / units.s)
    v_d = les.get_profile_V().value_in(units.m / units.s)
    sp_d = les.get_presf().value_in(units.Pa)
    thl_d = les.get_profile_THL().value_in(units.K)
    qt_d = les.get_profile_QT()
    ql_d = les.get_profile_QL()
    ql_ice_d = les.get_profile_QL_ice()  # ql_ice is the ice part of QL
    ql_water_d = ql_d - ql_ice_d  # ql_water is the water part of ql
    qr_d = les.get_profile_QR()
    A_d = get_cloud_fraction(les)
    # dales state
    # dales.cdf.variables['presh'][gcm.step] = dales.get_presh().value_in(units.Pa) # todo associate with zh in netcdf

    # calculate real temperature from Dales' thl, qt, using the pressures from openIFS
    pf = numpy.interp(h, Zf[::-1], Pf[::-1])
    t = thl_d * sputils.exner(pf) + sputils.rlv * ql_d / sputils.cp

    # get real temperature from Dales - note it is calculated internally from thl and ql
    t_d = les.get_profile_T().value_in(units.K)

    spio.write_les_data(les,
                        u=u_d,
                        v=v_d,
                        presf=sp_d,
                        qt=qt_d,
                        ql=ql_d,
                        ql_ice=ql_ice_d,
                        ql_water=ql_water_d,
                        thl=thl_d,
                        t=t,
                        t_=t_d,
                        qr=qr_d)

    # forcing
    ft = gcm.get_timestep().value_in(
        units.s)  # should be the length of the NEXT time step

    # interpolate to GCM heights
    t_d = numpy.interp(Zf, h, t_d)
    qt_d = numpy.interp(Zf, h, qt_d)
    ql_d = numpy.interp(Zf, h, ql_d)
    ql_water_d = numpy.interp(Zf, h, ql_water_d)
    ql_ice_d = numpy.interp(Zf, h, ql_ice_d)
    u_d = numpy.interp(Zf, h, u_d)
    v_d = numpy.interp(Zf, h, v_d)

    les_height = h[-1]
    # log.info("Height of LES system: %f" % les_height)
    i = 0
    for i in range(0, len(Zf)):
        if Zf[i] < les_height:
            break
    start_index = i  # first index in the openIFS column which is inside the Dales system
    # log.info("start_index: %d" % start_index)

    f_T = factor * (t_d - T) / ft
    f_SH = factor * (
        (qt_d - ql_d) - SH) / ft  # !!!!! -ql_d here - SH is vapour only.
    f_QL = factor * (ql_water_d - QL) / ft  # condensed liquid water
    f_QI = factor * (ql_ice_d - QI) / ft  # condensed water as ice
    # f_QL = factor * (ql_d - (QL+QI)) / ft dales QL is both liquid and ice - f_QL is liquid only. this conserves
    # water mass but makes an error in latent heat.
    f_U = factor * (u_d - U) / ft
    f_V = factor * (v_d - V) / ft
    f_A = factor * (A_d - A) / ft

    f_T[0:start_index] = 0  # zero out the forcings above the Dales system
    f_SH[0:start_index] = 0  # TODO : taper off smoothly instead
    f_QL[0:start_index] = 0
    f_QI[0:start_index] = 0
    f_U[0:start_index] = 0
    f_V[0:start_index] = 0
    f_A[0:start_index] = 0

    gcm.set_profile_tendency("U", les.grid_index, f_U)
    gcm.set_profile_tendency("V", les.grid_index, f_V)
    gcm.set_profile_tendency("T", les.grid_index, f_T)
    gcm.set_profile_tendency("SH", les.grid_index, f_SH)
    gcm.set_profile_tendency("QL", les.grid_index, f_QL)
    gcm.set_profile_tendency("QI", les.grid_index, f_QI)
    gcm.set_profile_tendency("A", les.grid_index, f_A)

    # store forcings on GCM in the statistics in the corresponding LES group
    spio.write_les_data(les,
                        f_U=f_U,
                        f_V=f_V,
                        f_T=f_T,
                        f_SH=f_SH,
                        A=A,
                        f_QL=f_QL,
                        f_QI=f_QI)
예제 #7
0
def convert_profiles(les, write=True):
    U, V, T, SH, QL, QI, Pf, Ph, A = (getattr(les, varname, None)
                                      for varname in gcm_vars)

    # virtual temperature - used to get heights
    c = sputils.rv / sputils.rd - 1  # epsilon^(-1) -1  = 0.61
    Tv = T * (1 + c * SH - (QL + QI))
    # is it correct to include QI here?
    # like liquid water, ice contributes to the density but not (much) to pressure
    dP = Ph[1:] - Ph[:-1]  # dP - pressure difference over one cell
    dZ = sputils.rd * Tv / (sputils.grav * Pf) * dP  # dZ - height of one cell

    # sum up dZ to get Z at half-levels.
    # 0 is at the end of the list, therefore reverse lists before and after.
    Zh = numpy.cumsum(dZ[::-1])[::-1]

    Zh = numpy.append(Zh, 0)  # append a 0 for ground

    # height of full levels - simply average half levels (for now)
    # better: use full level pressure to calculate height?
    Zf = (Zh[1:] + Zh[:-1]) * .5

    les.gcm_Zf = Zf  # save height levels in the les object for re-use
    les.gcm_Zh = Zh

    # Convert from OpenIFS quantities to les
    # note - different from modtestbed - iexner multiplied with both terms
    # could include QI as well.
    thl_ = (T - (sputils.rlv * (QL + QI)) / sputils.cp) * sputils.iexner(Pf)
    qt_ = SH + QL + QI

    # interpolate to les' heights
    # quirks:
    #   Zf must be increasing, so reverse the gcm arrays
    #   outside the range of Zf, interp returns the first or the last point of the range

    h = les.zf.value_in(units.m)

    thl = numpy.interp(h, Zf[::-1], thl_[::-1])
    qt = numpy.interp(h, Zf[::-1], qt_[::-1])
    ql = numpy.interp(h, Zf[::-1], QL[::-1])
    u = numpy.interp(h, Zf[::-1], U[::-1])
    v = numpy.interp(h, Zf[::-1], V[::-1])

    if write:
        spio.write_les_data(les,
                            U=U,
                            V=V,
                            T=T,
                            SH=SH,
                            QL=QL,
                            QI=QI,
                            Pf=Pf,
                            Ph=Ph[1:],
                            Zf=Zf,
                            Zh=Zh[1:],
                            Psurf=Ph[-1],
                            Tv=Tv,
                            THL=thl_,
                            QT=qt_)

    return u, v, thl, qt, Ph[-1] | units.Pa, ql