Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Confirmed.

...

Code Block
languagepy
titlecompute_wind_speed_height.py
#!/usr/bin/env python
#'''
# Copyright 20152019 ECMWF.
# 
# This software is licensed under the terms of the Apache Licence Version 2.0
# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0
# 
# In applying this licence, ECMWF does not waive the privileges and immunities 
granted to it by
# virtue of its status as an intergovernmental organisation 
nor does it submit to any jurisdiction.
# 
# **************************************************************************
# Function      : compute_wind_speed_height
#
# Author (date) : Cristian Simarro (20/11/2015)
#
# modified:       Xavi Abellan     (03/12/2018) - compatibilty with Python 3

Category      : COMPUTATION
#
# OneLineDesc   : Computes the u/v components of the wind at certain height
#
# Description   : Computes computes the u/v components of the wind at certain height.
#                height. First, it calculates the geopotential of each model
                level. Once the requested height 
#is found between two model
             is found between two model levels, the program will vertically interpolate the u/v
                component values.
#                 Based on code from Nils Wedi, the IFS documentation:
#https://www.ecmwf.int/en/forecasts/documentation-and-support/changes-ecmwf-model/ifs-documentation
                part https://software.ecmwf.int/wiki/display/IFS/CY41R1+Official+IFS+Documentation
#                 part III. III. Dynamics and numerical procedures
#                 optimised implementation by Dominique Lucas.
#                 ported to Python by Cristian Simarro
#
# Parameters    : -w wind                - height in meters you want to know u/v components
#                 tq.grib                - grib file with all the levelist of t and q
#u/v components
                 uvtq.grib                - grib file with all the levelistslevelist of u/v
#
                    zlnsp.grib             - grib file with levelist 1 for params zt and lnspq
#                uv.grib -o output   (optional) - name of the output file (default='uv_out_<wind>.grib')
#
# Return Value  : output (default='uv_out_<wind>.grib')
#      - grib file with all the levelists of
           A fieldset the u/v components values for at the specified height
#
# Dependencies  : None
#
# Example Usage : 
#                                  u/v
             python compute_wind_speed_height.py tq_ml_20151116_0.grib zlnsp_ml_20151116_0.grib uv_ml_20151116_0.grib -w 100

from numpy import * 
import sys,math,os
import argparse 
from gribapi import *

PARAMS = ["u","v"]

def main(t_q,z_lnsp,u_v,out_name,h):

       - grib file with levelist 1 for
      #some checks and information printing
    print "Using as input files:\n   ",t_q,z_lnsp,u_v
     print "The result will be stored in:\n   ",out_name

    if os.path.exists(out_name):
     params z and lnsp
    os.remove(out_name)
    fout = open(out_name,'w')
    ftmp = open(t_q)
  -o output   ftmp.close(optional)
 - name of Rdthe =output 287.06file
     RG = 9.80665
    index_keys = ["date","time","shortName","level","step"]

    values= {}
    pv = {}
    out = {}
    gid_out = {}
    values_plev = {}
    values_lev = {}
(default='uv_out_<wind>.grib')

Return Value  : output (default='uv_out_<wind>.grib')
       
    h=int(h)
    zlnsp = grib_index_new_from_file(z_lnsp,index_keys)
    iidtq = grib_index_new_from_file(t_q,index_keys)
A fieldset the u/v components values for at the specified
      iiduv = grib_index_new_from_file(u_v,index_keys)
    
    counter=0height

Dependencies  : None

Example #Usage iterate:
 date
    for date in grib_index_get(zlnsp,'date'):
        gribcompute_wind_index_select(zlnsp,'date',date)
        grib_index_select(iidtq,'date',date)speed_height.py tq.grib zlnsp.grib uv.grib -w 100
'''
from __future__ import print_function
import sys
import argparse
import numpy as np
from eccodes import (codes_index_new_from_file, codes_index_get, codes_get,
        grib             codes_index_select(iiduv,'date',date), codes_new_from_index, codes_set,
        # iterate step
        for time in gribcodes_index_get(zlnsp,'time'):add_file, codes_get_array, codes_get_values,
            grib_index_select(zlnsp,'time',time)
            grib_index_select(iidtq,'time',time)codes_index_release, codes_release, codes_set_values,
            grib_index_select(iiduv,'time',time)
         codes_write)

R_D =  grib_index_select(zlnsp,'level',1)287.06
R_G = 9.80665


def parse_args():
    ''' Parse program arguments using ArgumentParser'''
   grib_index_select(zlnsp,'step',0) parser = argparse.ArgumentParser(
        description='Python tool to calculate the  grib_index_select(zlnsp,'shortName','z')wind at certain height')
    parser.add_argument('-w', '--height', required=True, type=int,
            gid = grib_new_from_index(zlnsp)

          help='height to #gridTypecalculate mustthe be gridded, not spectralwind components')
            if grib_get(gid,"gridType",str) == "sh":
         parser.add_argument('-o', '--output', help='name of the output file')
    parser.add_argument('t_q', metavar='tq.grib', type=str,
       print(sys.argv[0]+' [ERROR] fields must be gridded, not spectral')
          help=('grib file with temperature(t) and  sys.exit(1)

humidity(q)',
              # surface geopotential
            values["z"] = grib_get_values(gid)
     'for the model levels'))
    parser.add_argument('z_lnsp', metavar='zlnsp.grib', type=str,
        z_h  = values["z"]
            pv help= grib_get_array(gid,'pv')('grib file with geopotential(z) and Logarithm',
            levelSizeNV = grib_get(gid,'NV',int)/2 -1
            
   'of surface pressure(lnsp) for the ml=1'))
    gribparser.add_release(gid)argument('u_v', metavar='uv.grib', type=str,
           
            # iterate step all but geopotential z wich is always step 0 (an)help=('grib file with u and v component of wind for',
            for step in grib_index_get(iidtq,'step'):
               'the # we need to get z and lnsp from the first level to do the calculationsmodel levels'))
    args = parser.parse_args()
    if not args.output:
        args.output        z_h = values["z"]= 'uv_out_%sm.grib' % args.height
    return args


def main():
    '''Main function'''
    args # heigh in geopotential
      = parse_args()

    print('Arguments: %s' % ", ".join(
        ['%s: %s' my_z = h*RG + z_h
   % (k, v) for k, v in vars(args).items()]))

    fout = open(args.output, 'wb')
      z_f_previndex_keys = z_h
    ['date', 'time', 'shortName', 'level', 'step']

    idx        = codes_index_new_from_file(args.z_lnsp, index_keys)
    codes_index_add_file(idx, args.t_q)
    if 'u_v' in args:
         gribcodes_index_selectadd_file(iidtq,'step',stepidx, args.u_v)

    # iterate date
    for date in    gribcodes_index_selectget(iiduvidx, 'stepdate',step):

        codes_index_select(idx, 'date', date)
       for shortName# in ["lnsp"]:iterate step
        for time          gribin codes_index_selectget(zlnspidx, 'shortNametime',shortName):
                   gribcodes_index_select(zlnspidx, 'steptime',step time)
            values       gid = grib_new_from_index(zlnsp)
= get_initial_values(idx, keep_sample=True)
            if 'height' in args:
        if grib_get(gid,"gridType",str) == "sh":
     values['height'] = args.height
                print(sys.argv[0]+' [ERROR] fields must be gridded, not spectral')values['gh'] = args.height * R_G + values['z']
            if 'levelist' in args:
        sys.exit(1)
        values['levelist'] = args.levelist
           values[shortName] = grib_get_values(gid)
          # iterate step all but geopotential z which is always step 0 (an)
          pv = grib_get_array(gid,'pv') for step in codes_index_get(idx, 'step'):
                   levelSizeNV = grib_get(gid,'NV',int)/2 -1codes_index_select(idx, 'step', step)
                #   grib_release(gid)surface pressure
   
             try:
   # surface pressure
                values['sp'] = exp(values["lnsp"]get_surface_pressure(idx)

                # get the coefficients for computing the pressures
  production_step(idx, values, fout)
                except WrongStepError:
 # how many levels are we computing?
             if step  grib_index_select(iidtq,'shortName',"t")!= '0':
                levelSize=max(grib_index_get(iidtq,"level",int))
        raise

        try:
 if levelSize != levelSizeNV:
                    print(sys.argv[0]+' [WARN] total levels should be: '+str(levelSizeNV)+' but it is '+str(levelSize))codes_release(values['sample'])
        except KeyError:
            pass

    A = pv[0:levelSize+1]codes_index_release(idx)
    fout.close()


def get_initial_values(idx, keep_sample=False):
    '''Get the values of   B = pv[levelSize+1:]
     surface z, pv and number of levels '''
    codes_index_select(idx, 'level', 1)
     Ph_levplusone = A[levelSize] + (B[levelSize]*sp)

codes_index_select(idx, 'step', 0)
    codes_index_select(idx, 'shortName', 'z')
    gid = codes_new_from_index(idx)

    values = {}
    # Wesurface wantgeopotential
 to integrate up into the atmosphere, starting at the ground
                # so we start at the lowest level (highest number) and keep values['z'] = codes_get_values(gid)
    values['pv'] = codes_get_array(gid, 'pv')
    values['nlevels'] = codes_get(gid, 'NV', int) // 2 - 1
    check_max_level(idx, values)
    if keep_sample:
           # accumulating the height as we go.values['sample'] = gid
    else:
        codes_release(gid)
    return values


def check_max_level(idx,  # Seevalues):
    '''Make sure we have all the IFS documentation:levels required'''
    # how many levels are we computing?
    max_level  # https://software.ecmwf.int/wiki/display/IFS/CY41R1+Official+IFS+Documentation= max(codes_index_get(idx, 'level', int))
    if max_level != values['nlevels']:
         # part III
       print('%s [WARN] total levels should be: %d but it is %d' %
         # For speed and file I/O, we perform the computations with numpy vectors instead
 (sys.argv[0], values['nlevels'], max_level),
              file=sys.stderr)
        # of fieldsets.
 values['nlevels'] = max_level


def get_surface_pressure(idx):
    '''Get the surface pressure for date-time-step'''
    codes_index_select(idx, 'level', 1)
    codes_index_select(idx, 'shortName', 'lnsp')
    gid = codes_new_from_index(idx)
    #initializeif valuesgid for the outputis None:
        raise WrongStepError()
    if codes_get(gid,  for param in PARAMS'gridType', str) == 'sh':
        print('%s [ERROR] fields must be gridded, not spectral'     grib_index_select(iiduv,'level',1)% sys.argv[0],
                    grib_index_select(iiduv,'shortName',paramfile=sys.stderr)
        sys.exit(1)
    # surface pressure
      gidsfc_p = grib_new_from_index(iiduvnp.exp(codes_get_values(gid))
                    gid_out[param]=grib_clonecodes_release(gid)
    return sfc_p


def get_ph_levs(values, level):
    '''Return the presure at a given level and  grib_release(gid)the next'''
    a_coef = values['pv'][0:values['nlevels'] + 1]
    b_coef = values['pv'][values['nlevels'] + 1:]
    out[param]=zeros(sp.size)
                found = [False for i in range(sp.size)]ph_lev = a_coef[level - 1] + (b_coef[level - 1] * values['sp'])
    ph_levplusone = a_coef[level] + (b_coef[level] * values['sp'])
    return ph_lev, ph_levplusone


def compute_z_level(idx, lev, values, z_h):
    '''Compute z at half for& levfull in list(reversed(range(1,levelSize+1))):
                    level for the given level, based on t/q/sp'''
    # select the levelist and retrieve the vaules of t and q
                    # t_level: values for t
                    # q_level: values for q
    codes_index_select(idx, 'level', lev)
              gribcodes_index_select(iidtqidx, 'levelshortName',lev 't')
    gid = codes_new_from_index(idx)
    t_level = codes_get_values(gid)
    codes_release(gid)
    gribcodes_index_select(iidtqidx, 'shortName',"t" 'q')
    gid = codes_new_from_index(idx)
              gid = grib_new_from_index(iidtqq_level = codes_get_values(gid)
    codes_release(gid)

    # compute moist  temperature
        t_level = grib_get_values(gid)
      t_level * (1. + 0.609133 * q_level)

    # compute the pressures (on half-levels)
     grib_release(gid)
ph_lev, ph_levplusone = get_ph_levs(values, lev)

    if lev == 1:
        dlog_p = np.log(ph_levplusone   grib_index_select(iidtq,'shortName',"q"/ 0.1)
        alpha = np.log(2)
    else:
        giddlog_p = grib_new_from_index(iidtqnp.log(ph_levplusone / ph_lev)
        alpha = 1. - ((ph_lev / (ph_levplusone - ph_lev)) * dlog_p)

    qt_level = grib_get_values(gid)t_level * R_D

    # z_f is the geopotential of this full level
    # integrate from previous grib_release(gidlower)

 half-level z_h to the
    # full level
    z_f = z_h + (t_level * #alpha)

 compute moist temperature
 # z_h is the geopotential of 'half-levels'
    # integrate z_h to next half level
   t z_levelh = z_h + (t_level * (1.+0.609133*q_leveldlog_p)

    return      z_h, z_f


def production_step(idx, values, fout):
    '''Produce u/v interpolated from ML for #a compute the pressures (on half-levels)
            given height'''
    # We want to integrate up into the atmosphere, starting at the
    # ground so we Ph_levstart = A[lev-1] + (B[lev-1] * sp)

          at the lowest level (highest number) and
    # keep accumulating the height as we go.
    # See the IFS documentation, part ifIII
 lev == 1:
 # For speed and file I/O, we perform the computations with
    # numpy vectors instead of fieldsets.

    dlogPout = log(Ph_levplusone/0.1){}
    params = ('u', 'v')
    # we need to get z and lnsp from the first level to alpha = log(2)do the
    # calculations
    z_h = values['z']
    # height in geopotential
  else:
  z_f_prev = z_h
    # initialize values for the output
    for param in params:
      dlogP = log(Ph_levplusone/Ph_lev)
 out[param] = np.zeros(values['sp'].size)

    found = [False for i in range(values['sp'].size)]
    for lev in list(reversed(list(range(1, values['nlevels'] + 1)))):
    dP    = Ph_levplusone-Ph_lev
  z_h, z_f = compute_z_level(idx, lev, values, z_h)
        # retrieve u/v params for the current level
       alpha =for 1.param - ((Ph_lev/dP)*dlogP)

in params:
            codes_index_select(idx, 'level', lev)  # 136
   TRd = t_level*Rd

       codes_index_select(idx, 'shortName', param)
           # z_fgid is the geopotential of this full level
= codes_new_from_index(idx)
            values[param] = codes_get_values(gid)
           # integrate from previous (lower) half-level z_h to the full level
 codes_release(gid)
            if lev < values['nlevels']:
         z_f = z_h + (TRd*alpha)

   codes_index_select(idx, 'level', lev + 1)  # 137
          # z_h is the geopotential of 'half-levels'
   gid = codes_new_from_index(idx)
                values['prev' + #param] integrate= z_h to next half level
codes_get_values(gid)
                codes_release(gid)
         z_h=z_h+(TRd*dlogP)

   else:
                 Ph_levplusone = Ph_levvalues['prev' + param] = np.zeros(values['sp'].size)
        # search if the provided wind height converted to
    # retrieve u/v params for # geopotential (my_z) is between the current level (z_f)
        # and the previous one (z_f_prev)
        for parami in PARAMSrange(z_f_prev.size):
            if found[i]:
           grib_index_select(iiduv,'level',lev) #136
    continue
            if values['gh'][i] >= z_f_prev[i] and values['gh'][i] <  grib_index_select(iiduv,'shortName',param)z_f[i]:
                found[i] = True
      gidp=grib_new_from_index(iiduv)
          # when found, interpolate vertically to get the
         values_lev[param] = grib_get_values(gidp)
       # value and store it in out[param] to be written
            grib_release(gidp)
    #  at the end
                iffor (levparam <in levelSize)params:
                    res        grib_index_select(iiduv,'level',lev+1) #137= (((float(values[param][i]) *
                            gidp=grib_new_from_index(iiduv) (values['gh'][i] - z_f_prev[i])) +
                            (float(values_plev[param] = grib_get_values(gidp)['prev' + param][i]) *
                            grib_release(gidp)
                        else:
                            values_plev[param] = zeros(sp.size)
                    # search if the provided wind height converted to geopotential (my_z) is between
                    # the current level (z_f) and the previous one (z_f_prev)
                    for i in arange(z_f_prev.size):
                        if found[i]: continue
                        if my_z[i] >= z_f_prev[i] and my_z[i] < z_f[i]:
                            found[i]=True
                            # when found, interpolate vertically to get the value
                            # store it in out[param] to be written at the end
                            for param in PARAMS:
                                out[param][i] = ( (values_lev[param][i] * ( my_z[i]-z_f_prev[i])) + \
                                                 (values_plev[param][i] * (z_f[i] - my_z[i]) ) ) /  \
                                                 (z_f[i] - z_f_prev[i])
                    # update z_f_prev
                    z_f_prev=z_f

                # simple error check
                for i in arange(sp.size):
                    if not found[i]:
                        print "point ",i,"not found..."

                # write the values in the fout file
                for param in PARAMS:
                    grib_set_values(gid_out[param],out[param])
                    grib_write(gid_out[param],fout)
                    grib_release(gid_out[param])
    grib_index_release(iidtq)
    grib_index_release(iiduv)
    grib_index_release(zlnsp)
    fout.close() 
    print("Done")

if __name__ == "__main__":
    request_date=0
    request_time=0
    wind = 100
    parser = argparse.ArgumentParser(
        description='Python tool to calculate the Z of the model levels')
    parser.add_argument("-w","--wind", help="height to calculate the wind components",required=True)
    parser.add_argument("-o","--output", help="name of the output file")
    parser.add_argument('t_q', metavar='tq.grib', type=str, 
   (z_f[i] - values['gh'][i]))) /
              help='grib file with temperature(t) and humidity(q) for the model levels')
    parser.add_argument('z_lnsp', metavar='zlnsp.grib', type=str, 
f[i] - z_f_prev[i]))
                    help='grib file with geopotential(z) and Logarithm of surface pressure(lnsp) for the ml=1')
    parser.add_argument('u_v', metavar='uv.grib', type=str, out[param][i] = res
        # update z_f_prev
        z_f_prev = z_f

    # simple error  check
    for i in range(values['sp'].size):
    help='grib file with u andif v component of wind for the model levels')
not found[i]:
          args = parser.parse_args()
    for fname in (args.t_q,args.z_lnsp,args.u_v):print('point ', i, 'not found...')

    # write the values ifin the not os.path.isfile(fname):fout file
    for param in params:
     print "[ERROR] file %s does not exist" %(fname)
     codes_set(values['sample'], 'shortName', param)
        codes_set(values['sample'], 'typeOfLevel', 'heightAboveGround')
        codes_set(values['sample'],  sys.exit(1'level', values['height'])
    if args.wind:
   codes_set_values(values['sample'], out[param])
    wind = args.wind
    out_name = 'uv_out_'+wind+'m.grib'
    if args.output:
        out_name=args.output

    #calling main functioncodes_write(values['sample'], fout)


class WrongStepError(Exception):
    ''' Exception capturing wrong step'''
    pass


if __name__ == '__main__':
    main(args.t_q,args.z_lnsp,args.u_v,out_name,wind))