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_geopotentialwind_onspeed_mlheight
#
# Author (date) : Cristian Simarro (0920/1011/2015)
#
#modified: Category      : COMPUTATION
#
# OneLineDescXavi Abellan    : Computes geopotential on model levels
#
# Description (03/12/2018) - compatibilty with Python 3

Category      : COMPUTATION

OneLineDesc   : Computes geopotentialthe onu/v model levels.
#     components of the wind at certain height

Description   : Computes computes the u/v components of the wind Basedat oncertain
 code from Nils Wedi, the IFS documentation:
#         height. First, it calculates the geopotential of  https://software.ecmwf.int/wiki/display/IFS/CY41R1+Official+IFS+Documentation
#each model
                level. partOnce III.the Dynamicsrequested andheight numericalis procedures
#found between two model
              optimised implementation bylevels, Dominique Lucas.
#     the program will vertically interpolate the u/v
            ported to Python by Cristiancomponent Simarro
#
# Parametersvalues.
       : tq.grib        Based on code from Nils Wedi, the IFS documentation:
https://www.ecmwf.int/en/forecasts/documentation-and-support/changes-ecmwf-model/ifs-documentation
 grib file with all the levelist of t and q
#      part III. Dynamics and numerical procedures
      zlnsp.grib          optimised implementation by -Dominique gribLucas.
 file with levelist 1 for params z and lnsp
#       ported to Python by Cristian Simarro

Parameters    : -ow outputwind   (optional) - name of the output file (default='z_out.grib')
#
# Return Value  : output (default='z_out.grib')
#        - height in meters you want to know
          A fieldset of geopotential on model levels
#
# Dependencies  : None
#
# Example Usage : 
#                 python compute_geopotential_on_ml.py tq.grib zlnsp.grib

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

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

    #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):
u/v components
                tq.grib                - grib file with all the levelist of
                     os.remove(out_name)
    fout = open(out_name,'w')
    ftmp = open(t_q)
    ftmp.close()
    Rdt =and 287.06q
    RG  = 9.80665
    index_keys = ["date","time","shortName","level","step"]

   uv.grib values= {}
    pv = {}
    out = {}   - grib file with all the levelists of
    gid_out = {}
               values_plev = {}
    values_lev = {}
    
    h=int(h)
    zlnsp = grib_index_new_from_file(z_lnsp,index_keys) u/v
    iidtq = grib_index_new_from_file(t_q,index_keys)
         iiduv = grib_index_new_from_file(u_v,index_keys)
zlnsp.grib     
    #we need to get z- andgrib lnspfile fromwith thelevelist first1 levelfor
 to do the calculations
    counter=0
    for date in grib_index_get(zlnsp,'date'):
          grib_index_select(zlnsp,'date',date)
        grib_index_select(iidtq,'date',date)
        grib_index_select(iiduv,'date',date)
     params z and lnsp
    for time in grib_index_get(zlnsp,'time'):
         -o output  grib_index_select(zlnsp,'time',time)
       (optional) - name of the output file
      grib_index_select(iidtq,'time',time)
            grib_index_select(iiduv,'time',time)
            grib_index_select(zlnsp,'level',1)
            grib_index_select(zlnsp,'step',0)
            grib_index_select(zlnsp,'shortName','z(default='uv_out_<wind>.grib')

Return Value  : output (default='uv_out_<wind>.grib')
            gid = grib_new_from_index(zlnsp)

  A fieldset the u/v components values for at the specified
 #gridType must be gridded, not spectral
          height

Dependencies  if grib_get(gid,"gridType",str) == "sh": None

Example Usage :
                print(sys.argv[0]+' [ERROR] fields must be gridded, not spectral')
                sys.exit(1)

compute_wind_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,
                # surface geopotential
   codes_index_select, codes_new_from_index, codes_set,
       values["z"] = grib_get_values(gid)
            z_h = values["z"]codes_index_add_file, codes_get_array, codes_get_values,
            pv = grib_get_array(gid,'pv')
       codes_index_release,     levelSizeNV = grib_get(gid,'NV',int)/2 -1codes_release, codes_set_values,
            
            grib_release(gid)

     codes_write)

R_D = 287.06
R_G = 9.80665


def parse_args():
    ''' Parse program forarguments step in grib_index_get(iidtq,'step'):using ArgumentParser'''
    parser = argparse.ArgumentParser(
          z_h = values["z"]
                # heigh in geopotential
description='Python tool to calculate the wind at certain height')
    parser.add_argument('-w', '--height', required=True, type=int,
                     my_z = h*RG + z_h
     help='height to calculate the wind components')
    parser.add_argument('-o', '--output', help='name of the output file')
  z_f_prev = z_h  parser.add_argument('t_q', metavar='tq.grib', type=str,
                
        help=('grib file with temperature(t)     grib_index_select(iidtq,'step',step)and humidity(q)',
                grib_index_select(iiduv,'step',step)

              'for the  for shortName in ["lnsp"]:
model levels'))
    parser.add_argument('z_lnsp', metavar='zlnsp.grib', type=str,
                     grib_index_select(zlnsp,'shortName',shortName)
   help=('grib file with geopotential(z) and Logarithm',
                       grib_index_select(zlnsp,'step',step)
       'of surface pressure(lnsp) for the ml=1'))
    parser.add_argument('u_v', metavar='uv.grib', type=str,
 gid = grib_new_from_index(zlnsp)
                   if grib_get(gid,"gridType",str) == "sh":
         help=('grib file with u and v component of wind for',
               print(sys.argv[0]+' [ERROR] fields must be gridded, not spectral')
               'the model levels'))
    args = sysparser.exitparse_args(1)
    if not args.output:
        args.output     values[shortName] = grib_get_values(gid)= 'uv_out_%sm.grib' % args.height
    return args


def main():
    '''Main function'''
     args   pv = gribparse_get_array(gid,'pv'args()

    print('Arguments: %s' % ", ".join(
        ['%s:   levelSizeNV = grib_get(gid,'NV',int)/2 -1
                   grib_release(gid)
   %s' % (k, v) for k, v in vars(args).items()]))

    fout = open(args.output, 'wb')
    index_keys = ['date', 'time',  # surface pressure'shortName', 'level', 'step']

    idx = codes_index_new_from_file(args.z_lnsp, index_keys)
    codes_index_add_file(idx, args.t_q)
    if sp = exp(values["lnsp"])

'u_v' in args:
        codes_index_add_file(idx, args.u_v)

    # iterate date
 # get the coefficientsfor fordate computing the pressuresin codes_index_get(idx, 'date'):
        codes_index_select(idx, 'date', date)
      # how many# levels are we computing?iterate step
        for time       gribin codes_index_get(idx, 'time'):
            codes_index_select(iidtqidx, 'shortNametime',"t" time)
            values    levelSize=max(grib_index_get(iidtq,"level",int))= get_initial_values(idx, keep_sample=True)
                if levelSize != levelSizeNV'height' in args:
                values['height'] = args.height
  print(sys.argv[0]+' [WARN] total levels should be: '+str(levelSizeNV)+' but it is '+str(levelSize))
    values['gh'] = args.height * R_G + values['z']
      A = pv[0:levelSize+1]
    if 'levelist' in args:
         B = pv[levelSize+1:]
                Ph_levplusone = A[levelSize] + (B[levelSize]*sp)

values['levelist'] = args.levelist
                # Weiterate wantstep toall integratebut upgeopotential intoz thewhich atmosphere,is startingalways atstep the0 ground(an)
            for step in  # so we start at the lowest level (highest number) and keep
codes_index_get(idx, 'step'):
                codes_index_select(idx, 'step', step)
         # accumulating the height as we go.
 # surface  pressure
            # See the IFS documentationtry:
                # https://software.ecmwf.int/wiki/display/IFS/CY41R1+Official+IFS+Documentation
      values['sp'] = get_surface_pressure(idx)
              # part III
    production_step(idx, values,  fout)
         # For speed and file I/O, we performexcept theWrongStepError:
 computations with numpy vectors instead
               if #step of fieldsets.!= '0':
                
        raise

        #initializetry:
 values for the output
        codes_release(values['sample'])
        for param in ["u","v"]except KeyError:
            pass

    codes_index_release(idx)
     grib_index_select(iiduv,'level',1)fout.close()


def get_initial_values(idx, keep_sample=False):
    '''Get the values of surface z, pv and number of levels '''
     gribcodes_index_select(iiduvidx, 'shortNamelevel',param 1)
    codes_index_select(idx, 'step', 0)
    codes_index_select(idx,    'shortName', 'z')
      gid = gribcodes_new_from_index(iiduvidx)

    values = {}
    # surface geopotential
    values['z'] =   gid_out[param]=grib_clonecodes_get_values(gid)
    values['pv'] = codes_get_array(gid, 'pv')
    values['nlevels'] = codes_get(gid, 'NV', int) // 2   grib_release(gid)- 1
    check_max_level(idx, values)
    if keep_sample:
          out[param]=zeros(sp.size)values['sample'] = gid
    else:
        codes_release(gid)
    found = [False for i in range(sp.size)]return values


def check_max_level(idx, values):
    '''Make sure we have all the levels required'''
    # how formany levlevels in list(reversed(range(1,levelSize+1))):are we computing?
    max_level = max(codes_index_get(idx, 'level', int))
    if max_level != values['nlevels']:
        print('%s [WARN] total levels should #be: select%d thebut levelistit andis retrieve%d' the%
 vaules of t and q
         (sys.argv[0],           # t_level: values for t
values['nlevels'], max_level),
              file=sys.stderr)
         # q_level: values for q
                    gribvalues['nlevels'] = max_level


def get_surface_pressure(idx):
    '''Get the surface pressure for date-time-step'''
    codes_index_select(iidtqidx, 'level',lev 1)
                    gribcodes_index_select(iidtqidx, 'shortName',"t" 'lnsp')
                    gid = gribcodes_new_from_index(iidtqidx)
    if gid is None:
        raise WrongStepError()
    t_level = gribif codes_get_values(gid, 'gridType', str) == 'sh':
        print('%s [ERROR] fields must be gridded, not spectral' % sys.argv[0],
     grib_release(gid)
         file=sys.stderr)
        sys.exit(1)
   grib_index_select(iidtq,'shortName',"q")
    # surface pressure
    sfc_p = np.exp(codes_get_values(gid))
    codes_release(gid)
    return   gid = grib_new_from_index(iidtq)sfc_p


def get_ph_levs(values, level):
    '''Return the presure at a given level and the  next'''
      qa_levelcoef = grib_get_values(gid)
  values['pv'][0:values['nlevels'] + 1]
    b_coef = values['pv'][values['nlevels'] + 1:]
    ph_lev = a_coef[level - 1] + grib_release(gid)

   (b_coef[level - 1] * values['sp'])
    ph_levplusone = a_coef[level] + (b_coef[level] * values['sp'])
    return ph_lev,  # compute moist temperatureph_levplusone


def compute_z_level(idx, lev, values, z_h):
    '''Compute z at half & full level for the given level, based on    t_level = t_level * (1.+0.609133*q_level)
t/q/sp'''
    # select the levelist and retrieve the vaules of t and q
     # compute the pressures (on half-levels)t_level: values for t
    # q_level: values for q
    codes_index_select(idx, 'level', lev)
      Ph_lev = A[lev-1] + (B[lev-1] * sp)

codes_index_select(idx, 'shortName', 't')
    gid = codes_new_from_index(idx)
    t_level = codes_get_values(gid)
        if lev == 1:codes_release(gid)
    codes_index_select(idx, 'shortName', 'q')
    gid = codes_new_from_index(idx)
    q_level = codes_get_values(gid)
      dlogP = log(Ph_levplusone/0.1)codes_release(gid)

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

    # alphacompute the =pressures log(2on half-levels)
    ph_lev, ph_levplusone = get_ph_levs(values, lev)

    if lev       else== 1:
        dlog_p = np.log(ph_levplusone /  0.1)
        alpha   dlogP = np.log(Ph_levplusone/Ph_lev2)
    else:
        dlog_p = np.log(ph_levplusone / ph_lev)
        alpha dP= 1. - ((ph_lev =/ Ph(ph_levplusone -Ph ph_lev
)) * dlog_p)

    t_level = t_level * R_D

    # z_f is the geopotential of this full level
  alpha  # =integrate 1.from -previous ((Ph_lev/dP)*dlogP)

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

    # z_h is the geopotential of 'half-levels'
    # integrate z_h to next half #level
 z_f is the geopotentialz_h of= thisz_h full+ (t_level
 * dlog_p)

    return z_h, z_f


def production_step(idx, values, fout):
    '''Produce u/v interpolated from ML #for integratea from previous (lower) half-level z_h to the full level
    given height'''
    # We want to integrate up into the atmosphere, starting at the
    # ground so we start at the lowest level (highest number) and
 z_f = z_h + (TRd*alpha)

      # keep accumulating the height as we go.
    # See the IFS documentation, part III
    # z_hFor isspeed theand geopotential of 'half-levels'
    file I/O, we perform the computations with
    # numpy vectors instead of fieldsets.

    out = {}
 # integrate z_h toparams next half level= ('u', 'v')
    # we need to get z and lnsp from the first level to do the
    z_h=z_h+(TRd*dlogP)

# calculations
    z_h = values['z']
    # height in geopotential
       Ph_levplusonez_f_prev = Phz_levh
    # initialize values for the output
    for param in params:
    # store the result (z_f) in a field and add to the output fieldset
      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)))):
     # (add it to the front, not the end, because we are going 'backwards' z_h, z_f = compute_z_level(idx, lev, values, z_h)
        # retrieve u/v params for the       # through the fields)current level
        for param in params:
         for param in ["u","v"]:
      codes_index_select(idx, 'level', lev)  # 136
                   gribcodes_index_select(iiduvidx, 'levelshortName',lev param) #136
            gid            grib_index_select(iiduv,'shortName',param= codes_new_from_index(idx)
            values[param] = codes_get_values(gid)
          gidp=grib_new_from_index(iiduv  codes_release(gid)
            if lev           values_lev[param] = grib_get_values(gidp)< values['nlevels']:
                        grib_release(gidp)
       codes_index_select(idx, 'level', lev + 1)  # 137
                gid if (lev < levelSize):= codes_new_from_index(idx)
                values['prev' + param]          grib_index_select(iiduv,'level',lev+1) #137= codes_get_values(gid)
                            gidp=grib_new_from_index(iiduvcodes_release(gid)
            else:
                values_plev[['prev' + param] = grib_get_values(gidpnp.zeros(values['sp'].size)
        # search if the provided wind height converted to
        # geopotential (my_z)  grib_release(gidpis between the current level (z_f)
        # and the previous one (z_f_prev)
        for i  elsein range(z_f_prev.size):
            if found[i]:
               values_plev[param] = zeros(sp.size) continue
                    for i in arange(z_f_prev.size)if values['gh'][i] >= z_f_prev[i] and values['gh'][i] < z_f[i]:
                found[i] = True
      if found[i]: continue
        # when found, interpolate vertically to get the
         if my_z[i] >= z_f_prev[i] and my_z[i] < z_f[i]:
       # value and store it in out[param] to be written
                #  at the  end
    found[i]=True
            for param in params:
             #print "wind %d for point %d found betweenres ml %d(%lf) and %d(%lf)\n" %(my_z[i],i,lev+1,z_f_prev[i],lev,z_f[i])
= (((float(values[param][i]) *
                             (values['gh'][i]  for param in ["u","v"]:- z_f_prev[i])) +
                            (float(values['prev' +   out[paramparam][i] = ((values_lev[param][i] * ( my_z[i]-z_f_prev[i])) + (values_plev[param][i] *) *
                             (z_f[i] - my_zvalues['gh'][i]) )) /
                           (z_f[i] - z_f_prev[i]))
                    z_f_prev=z_f out[param][i] = res
        # update z_f_prev
      for i in arange(sp.size):  z_f_prev = z_f

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

    # write the values in the fout file
     for param in ["u","v"]params:
        codes_set(values['sample'], 'shortName', param)
          gribcodes_set_(values(gid_out[param],out[param]['sample'], 'typeOfLevel', 'heightAboveGround')
        codes_set(values['sample'], 'level', values['height'])
          grib_write(gid_codes_set_values(values['sample'], 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, 
                   help='grib file with temperature(t) and humidity(q) for the model levels')
    parser.add_argument('z_lnsp', metavar='zlnsp.grib', type=str, 
                   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, 
                   help='grib file with u and v component of wind for the model levels')
    args = parser.parse_args()
    for fname in (args.t_q,args.z_lnsp,args.u_v):
        if not os.path.isfile(fname):
            print "[ERROR] file %s does not exist" %(fname)
            sys.exit(1)
    if args.wind:
        wind = args.wind
    out_name = 'uv_out_'+wind+'m.grib'
    if args.output:
        out_name=args.output

    #calling main function
    main(args.t_q,args.z_lnsp,args.u_v,out_name,wind)

codes_write(values['sample'], fout)


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


if __name__ == '__main__':
    main()