Blame | Last modification | View Log | Download | RSS feed
#!/usr/bin/python
# =============================================================================
# Quick Viewer for meteorological fields from ECMWF
# Michael Sprenger, Sebastian Limbach [ based on IWAL], Winter 2012/13
# =============================================================================
# Imports
import os
import sys
from optparse import OptionParser
import subprocess
import datetime
# The absolute path of the test-scripts
SCRIPT_PATH = os.getenv('DYN_TOOLS') + '/quickview/'
# ----------------------------------------------------------------------------
# Help page / show colorbar only
# ----------------------------------------------------------------------------
# Write the help page on demand
if ( sys.argv[1] == 'help' ):
print ( '--------------------------------------------------------------------------------------------------------' )
print ( 'Usage: [1] qv help ' )
print ( ' [2] qv data field [options] -> horizontal and vertical cross sections ' )
print ( ' [3] qv data [options] -> skew-T/log-P diagram and satellite imagery ' )
print ( ' [4] qv colorbar -> show colorbar only ' )
print ( ' ' )
print ( 'Arguments: ' )
print ( ' ' )
print ( ' data = P{date} : explicit filename ' )
print ( ' data = an.{date} : operational ECMWF analysis ' )
print ( ' data = fc.{date} : most recent operational ECMWF analysis for {date} ' )
print ( ' data = fc.{date0}.{date} : operational ECMWF initialized at {date0} analysis for {date} ' )
print ( ' data = ir|wv.date : IR and WV satellite imagery ' )
print ( ' ' )
print ( ' field = Q@200hPa : e.g. specific humidity (Q) at 200 hPa ' )
print ( ' field = PV@320K : e.g. potential vorticity (PV) at 320 K ' )
print ( ' field = T@15 : e.g. temperature (T) at model level 15 ' )
print ( ' field = SLP : e.. reduced surface pressure ' )
print ( ' ' )
print ( 'Options: ' )
print (' ' )
print (' -o figname : name of output figure ' )
print (' -d lonmin,lonmax,latmin,latmax|region : horizontal domain (region:europe,natlantic,nhem,shem) ' )
print (' -g np|sp|latlon : geographic projection (np:north pole, sp:south pole, latlon (default)')
print (' -v lon1,lat1,lon2,lat2[,lev1,lev2,type] : vertical cross section (pype:gc,linear,ns,ew) ' )
print (' -p lon,lat[,lev1,lev2] : vertical profile (skew-T/log-P) ' )
print (' -c cmin,cmax[,mode,#cols|colname] : specification of colortable ' )
print (' -n npixel : pixel size of figure (default=512) ' )
print (' -s : show figure ' )
print (' -r : remove figure after showing it ' )
print (' -l : show label/color bar ' )
print ( '--------------------------------------------------------------------------------------------------------' )
quit()
elif ( sys.argv[1] == 'colorbar' ):
figname = 'quickview.color'
figpath = os.getcwd() + '/'
print figname, figpath
wsname = 'testws'
npixel = 512
os.system('python ' + SCRIPT_PATH + '/ext_scripts/colorbar.py ' +
' '.join([str(npixel), wsname, figpath, figname]))
cmd = 'xv ' + figpath + '/quickview.color.png;'
subprocess.Popen(cmd,stdout=subprocess.PIPE,shell=True)
quit()
# ----------------------------------------------------------------------------
# Set ERA-Interim dictionary
# ----------------------------------------------------------------------------
erai = { 'T' : [ 'P', 'dansgaard'],
'OMEGA' : [ 'P', 'dansgaard'],
'U' : [ 'P', 'dansgaard'],
'V' : [ 'P', 'dansgaard'],
'SLP' : [ 'P', 'dansgaard'],
'PS' : [ 'P', 'dansgaard'],
'Q' : [ 'P', 'dansgaard'],
'LWC' : [ 'P', 'dansgaard'],
'IWC' : [ 'P', 'dansgaard'],
'U10M' : [ 'B', 'dansgaard'],
'V10M' : [ 'B', 'dansgaard'],
'TD2M' : [ 'P', 'dansgaard'],
'T2M' : [ 'P', 'dansgaard'],
'SKT' : [ 'B', 'dansgaard'],
'G10M' : [ 'G', 'dansgaard'],
'T2MAX' : [ 'G', 'dansgaard'],
'T2MIN' : [ 'G', 'dansgaard'],
'RTOT' : [ 'R', 'dansgaard'],
'LSP' : [ 'R', 'dansgaard'],
'CP' : [ 'R', 'dansgaard'],
'SF' : [ 'R', 'dansgaard'],
'SSHF' : [ 'R', 'dansgaard'],
'O3' : [ 'O', 'litho' ],
'TROPO' : [ 'L', 'litho' ],
'LABEL' : [ 'L', 'litho' ],
'CAPE_MU' : [ 'C', 'litho' ],
'CIN_MU' : [ 'C', 'litho' ],
'CAPE_ML' : [ 'C', 'litho' ],
'CIN_ML' : [ 'C', 'litho' ],
'Z' : [ 'Z', 'dansgaard'],
'TH' : [ 'S', 'thermo' ],
'PV' : [ 'S', 'thermo' ],
'RH' : [ 'S', 'thermo' ],
'THE' : [ 'S', 'thermo' ]
}
# ----------------------------------------------------------------------------
# Get the arguments
# ----------------------------------------------------------------------------
# Parse optional parameters
parser = OptionParser()
parser.add_option("-o", "--outfile", type='string', dest="outfile", default = 'NONE' )
parser.add_option("-d", "--domain", type='string', dest="domain", default = 'NONE' )
parser.add_option("-p", "--profile", type='string', dest="profile", default = 'NONE' )
parser.add_option("-v", "--vertical", type='string', dest="vertical", default = 'NONE' )
parser.add_option("-c", "--color", type='string', dest="color", default = 'NONE' )
parser.add_option("-n", "--npixel", type='int', dest="npixel", default = 512 )
parser.add_option("-s", "--show", action="store_true", dest="show", default = False )
parser.add_option("-r", "--showremove", action="store_true", dest="showremove", default = False )
parser.add_option("-l", "--labelbar", action="store_true", dest="labelbar", default = False )
parser.add_option("-g", "--geoproj", type='string', dest="projection", default = 'latlon')
(options, args) = parser.parse_args()
# Get mandatory arguments (inpfile / field)
inpfile = args[0]
if ( len(args) == 2 ) :
field = args[1]
else:
field = 'T'
# Adjusts defaults
if options.outfile == 'NONE' :
outfile = inpfile
else:
outfile = options.outfile
# Set some internal parameters
wsname = 'testws'
# Set name of output figures
figname = outfile
figpath = os.getcwd()+'/'
# Decide about the plotting mode
if any( elem == '-d' for elem in sys.argv ):
print "Mode : horizontal cross scection"
mode = 'horizontal'
elif any( elem == '-v' for elem in sys.argv ):
print "Mode : vertical cross scection"
mode = 'vertical'
elif any( elem == '-p' for elem in sys.argv ):
print "Mode : vertical profile"
mode = 'profile'
else:
print "Mode : horizontal cross section (default)"
mode = 'horizontal'
# Check that the number of pixel is reasonable
if ( options.npixel > 2000 ):
sys.exit('number of pixels too large');
# ----------------------------------------------------------------------------
# Set the meteorological field
# ----------------------------------------------------------------------------
field_split = field.split('@')
if len(field_split) == 1 :
field_fieldname = field_split[0]
field_level = 0
field_unit = 'nil'
elif len(field_split) == 2 :
field_fieldname = field_split[0]
field_level = field_split[1]
i0 = field_level.find('hPa')
i1 = field_level.find('K' )
if ( i0 != -1 ):
field_unit = 'hPa'
field_level = field_level[0:i0]
elif ( i1 != -1 ):
field_unit = 'K'
field_level = field_level[0:i1]
else:
field_unit = 'ML'
field_level = field_level
print field_unit
# ----------------------------------------------------------------------------
# Set the data source + check whether field is available
# ----------------------------------------------------------------------------
inpfile_split = inpfile.split('.')
if len(inpfile_split) == 1 :
inpfile_filename = os.path.split(inpfile_split[0])[1]
inpfile_folder = os.path.split(inpfile_split[0])[0]
if inpfile_folder == '':
inpfile_folder = os.getcwd()
inpfile_folder = inpfile_folder + '/'
elif ( inpfile_split[0] == 'an' ) & ( len(inpfile_split) == 2 ):
inpfile_filename = 'P'+inpfile_split[1]
inpfile_folder = '/net/litho/atmosdyn/ec.analysis/'
elif ( inpfile_split[0] == 'fc' ) & ( len(inpfile_split) == 2 ):
inpfile_filename = 'P'+inpfile_split[1]
today = datetime.date.today()
weekday = today.weekday()
if ( weekday == 0 ):
weekday = 6
else:
weekday = weekday -1
daynames = ( 'Mon','Tue','Wed','Thu','Fri','Sat','Sun' )
inpfile_folder = '/net/litho/atmosdyn/ec.forecast/' + daynames[weekday] + '/'
elif ( inpfile_split[0] == 'fc' ) & ( len(inpfile_split) == 3 ):
inpfile_filename = 'P'+inpfile_split[2]
inpfile_folder = '/net/litho/atmosdyn/ec.forecast/' + inpfile_split[1] + '/'
elif ( inpfile_split[0] == 'ei' ) & ( len(inpfile_split) == 2 ):
inpfile_filename = erai[field_fieldname][0]+inpfile_split[1]
yyyy = inpfile_filename[1:5]
mm = inpfile_filename[5:7]
inpfile_folder = '/net/'+erai[field_fieldname][1]+'/atmosdyn/erainterim/cdf/'+yyyy+'/'+mm+'/'
else:
sys.exit('Unsupported input file ' + inpfile);
# Check whether the input file is available
if os.path.exists(inpfile_folder+inpfile_filename):
print 'input file found: ' + inpfile_folder + inpfile_filename
else:
sys.exit( 'input file is missing : ' + inpfile_folder + inpfile_filename )
# Check whether field is available on input file
cmd = 'getvars ' + inpfile_folder + '/' + inpfile_filename
proc = subprocess.Popen(cmd,stdout=subprocess.PIPE,shell=True)
(out, err) = proc.communicate()
ok = any( (elem.strip() == field_fieldname) for elem in out.split('\n') )
# If not available, try to calculate it with p2s
if ( ok == False ):
print 'Try to calculate '+field_fieldname+' with p2s'
cmd = 'p2s ' + inpfile_folder + '/' + inpfile_filename
print 'NOT YET IMPLEMTED'
if ok == False:
sys.exit('variable '+field_fieldname+' missing on '+inpfile_filename);
# ----------------------------------------------------------------------------
# Set the color table
# ----------------------------------------------------------------------------
color_split = options.color.split(',')
if len(color_split) == 5:
color_cmin = color_split[0]
color_cmax = color_split[1]
color_mode = color_split[2]
color_ncol = color_split[3]
color_name = color_split[4]
elif len(color_split) == 4:
color_cmin = color_split[0]
color_cmax = color_split[1]
color_mode = color_split[2]
color_ncol = color_split[3]
color_name = 'adjust'
elif len(color_split) == 3:
color_cmin = color_split[0]
color_cmax = color_split[1]
color_mode = color_split[2]
color_ncol = 18
color_name = 'hotcold_18lev'
elif len(color_split) == 2:
color_cmin = color_split[0]
color_cmax = color_split[1]
color_mode = 'fill'
color_ncol = '18'
color_name = 'hotcold_18lev'
elif (color_split[0] == 'PV.default') | ( color_split[0] == 'NONE' ) & ( field_fieldname == 'PV' ):
color_cmin = '-0.5'
color_cmax = '10.'
color_mode = 'fill'
color_ncol = 'adjust'
color_name = 'PV.default'
elif color_split[0] == 'NONE':
color_cmin = 'p95'
color_cmax = 'p05'
color_mode = 'fill'
color_ncol = '18'
color_name = 'hotcold_18lev'
# ----------------------------------------------------------------------------
# Set the horizontal domain
# ----------------------------------------------------------------------------
# Set the geographical projection
projection = options.projection
print projection
domain_split = options.domain.split(',')
print domain_split
if len(domain_split) == 4:
domain_xmin = domain_split[0]
domain_xmax = domain_split[1]
domain_ymin = domain_split[2]
domain_ymax = domain_split[3]
elif ( len(domain_split) == 1 ) & (options.domain == 'europe' ):
domain_xmin = -20
domain_xmax = 40
domain_ymin = 30
domain_ymax = 75
elif ( len(domain_split) == 1 ) & (options.domain == 'natlantic' ):
domain_xmin = -100
domain_xmax = 10
domain_ymin = 10
domain_ymax = 75
elif ( len(domain_split) == 1 ) & (options.domain == 'global' ):
domain_xmin = -180
domain_xmax = 180
domain_ymin = -90
domain_ymax = 90
elif ( len(domain_split) == 1 ) & (options.domain == 'nhem' ):
domain_xmin = -180
domain_xmax = 180
domain_ymin = 0
domain_ymax = 90
elif ( len(domain_split) == 1 ) & (options.domain == 'shem' ):
domain_xmin = -180
domain_xmax = 180
domain_ymin = -90
domain_ymax = 0
elif ( len(domain_split) == 2 ):
domain_xmin = -180
domain_xmax = 180
domain_ymin = domain_split[0]
domain_ymax = domain_split[1]
elif ( projection == 'np' ):
domain_xmin = -180
domain_xmax = 180
domain_ymin = 30
domain_ymax = 90
elif ( projection == 'sp' ):
domain_xmin = -180
domain_xmax = 180
domain_ymin = -90
domain_ymax = -30
else:
domain_xmin = 'adjust'
domain_xmax = 'adjust'
domain_ymin = 'adjust'
domain_ymax = 'adjust'
# Check that the geographical domain is reasonable
if ( domain_xmin != 'adjust' ):
if (domain_xmin >= domain_xmax) | (domain_ymin >= domain_ymax):
sys.exit('domain problem:')
# ----------------------------------------------------------------------------
# Set the settings for vertical cross section
# ----------------------------------------------------------------------------
vertical_split = options.vertical.split(',')
if len(vertical_split) == 7:
vertical_lon1 = vertical_split[0]
vertical_lat1 = vertical_split[1]
vertical_lon2 = vertical_split[2]
vertical_lat2 = vertical_split[3]
vertical_lev1 = vertical_split[4]
vertical_lev2 = vertical_split[5]
vertical_type = vertical_split[6]
if len(vertical_split) == 6:
vertical_lon1 = vertical_split[0]
vertical_lat1 = vertical_split[1]
vertical_lon2 = vertical_split[2]
vertical_lat2 = vertical_split[3]
vertical_lev1 = vertical_split[4]
vertical_lev2 = vertical_split[5]
vertical_type = 'linear'
if len(vertical_split) == 4:
vertical_lon1 = vertical_split[0]
vertical_lat1 = vertical_split[1]
vertical_lon2 = vertical_split[2]
vertical_lat2 = vertical_split[3]
vertical_lev1 = 1030
vertical_lev2 = 100
vertical_type = 'linear'
elif ( len(vertical_split) == 1 ) & (options.vertical == 'zurich.ns' ):
vertical_lon1 = 8.538
vertical_lat1 = 47.3690 - 7.5
vertical_lon2 = 8.538
vertical_lat2 = 47.3690 + 7.5
vertical_lev1 = 1030
vertical_lev2 = 100
vertical_type = 'linear'
# ----------------------------------------------------------------------------
# Set the profile settings
# ----------------------------------------------------------------------------
profile_split = options.profile.split(',')
if len(profile_split) == 4:
profile_lon = profile_split[0]
profile_lat = profile_split[1]
profile_lev1 = profile_split[2]
profile_lev2 = profile_split[3]
elif len(profile_split) == 2:
profile_lon = profile_split[0]
profile_lat = profile_split[1]
profile_lev1 = 1030
profile_lev2 = 100
# ----------------------------------------------------------------------------
# Horizontal cross section
# ----------------------------------------------------------------------------
if ( mode == 'horizontal' ):
os.system('python ' + SCRIPT_PATH + '/ext_scripts/horizontal.py ' +
' '.join([inpfile_filename,
inpfile_folder,
field_fieldname,
str(field_level),
str(domain_xmin),str(domain_xmax),str(domain_ymin),str(domain_ymax),
str(options.npixel),
wsname,
figpath,figname,
str(color_cmin), str(color_ncol), str(color_cmax), color_name,
field_unit,projection,color_mode]))
# ----------------------------------------------------------------------------
# Vertical cross section
# ----------------------------------------------------------------------------
if ( mode == 'vertical' ) :
os.system('python ' + SCRIPT_PATH + '/ext_scripts/vertical.py ' +
' '.join([inpfile_filename,
inpfile_folder,
field_fieldname,
str(vertical_lon1), str(vertical_lon2),
str(vertical_lat1), str(vertical_lat2),
str(vertical_lev1), str(vertical_lev2),
vertical_type,
str(options.npixel),
wsname,
figpath, figname,
str(color_cmin), str(color_ncol), str(color_cmax),
color_name,color_mode ]))
# ----------------------------------------------------------------------------
# Skew-T/log-P (skewtlogp)
# ----------------------------------------------------------------------------
if ( mode == 'profile' ):
os.system('python ' + SCRIPT_PATH + '/ext_scripts/skewtlogp.py ' +
' '.join([inpfile_filename,inpfile_folder,
str(profile_lon), str(profile_lat), str(profile_lev1), str(profile_lev2),
str(options.npixel), wsname, figpath, figname ]))
# ----------------------------------------------------------------------------
# Show the figure if requested
# ----------------------------------------------------------------------------
if options.show:
cmd = 'xv ' + figpath + '/' + figname + '.png'
subprocess.Popen(cmd,stdout=subprocess.PIPE,shell=True)
if options.showremove:
cmd = 'xv ' + figpath + '/' + figname + '.png; rm ' + figpath + '/' + figname + '.png'
subprocess.Popen(cmd,stdout=subprocess.PIPE,shell=True)
if options.labelbar | ( mode == 'colorbar' ):
figname = 'quickview.color'
os.system('python ' + SCRIPT_PATH + '/ext_scripts/colorbar.py ' +
' '.join([str(options.npixel), wsname, figpath, figname]))
if options.showremove:
cmd = 'xv ' + figpath + '/quickview.color.png;' + 'rm ' + figpath + '/quickview.color.png'
subprocess.Popen(cmd,stdout=subprocess.PIPE,shell=True)
else:
cmd = 'xv ' + figpath + '/quickview.color.png;'
subprocess.Popen(cmd,stdout=subprocess.PIPE,shell=True)