ecmwf netcdf to vapor vdf conversion, and missing value handling

2 posts / 0 new
Last post
bpicard_659234
ecmwf netcdf to vapor vdf conversion, and missing value handling
Hi,

I would like to share my experience on the visualization of ECMWF netcdf analysis with vapor. It works but it certainly could be improved so feel free to comment!

I convert both surfaces and 3D parameters.

First, my python script (see below) that convert ECMWF netcdf file in a new netcdf format more suitable for VAPOR conversion. Mainly, the latitudes are flipped, and the level as well. Not that an ELEVATION parameter seems to be required, I computed by other means and appended it to the ECMWF netcdf source file.

Then, the creation and population of the vdf file is easy through ncdfvdfcreate and ncdf2vdf (see below).

My only concern is about the handling of missing value / fill value.

As you can see in the python script, I use the fill_value argument in the createVariable method.

I tried many things, including using default_fillvals method of netCDF4, in combination with the -miss_attr option of ncdfvdfcreate but any values are interpreted by vaporgui as valid.

Eventually, I fixed the fill_value at 1.10 the maximum value and I play with the histogramm opacity in DVR tab of vaporgui, but it's not totally satisfactory.

#!/usr/bin/python # -*- coding: utf-8 -*- import numpy as np import netCDF4 as nc from netCDF4 import Dataset,default_fillvals #------------------------------------------------------------------------- #------------------------------------------------------------------------- # # Read surfaces outputs from ECMWF #------------------------------------------------------------------------- fname = 'classes/filtre_SURF01_0d25_20150601_00-06-12-18_region_Lon.-140.-100_Lat.10.40.nc' hdle = nc.Dataset(fname) # lat/lon coord lat_coord = hdle.variables['latitude'][:] lon_coord = hdle.variables['longitude'][:] time_coord = hdle.variables['time'][:] # time,nlev,lat,lon sp = hdle.variables['sp'][:,:,:] st = hdle.variables['stl1'][:,:,:] t2m = hdle.variables['t2m'][:,:,:] d2m = hdle.variables['d2m'][:,:,:] u10 = hdle.variables['u10'][:,:,:] v10 = hdle.variables['v10'][:,:,:] # # Write new format #------------------------------------------------------------------------- fname_out = 'classes/VAPOR_filtre_SURF01_0d25_20150601_00-06-12-18_region_Lon.-140.-100_Lat.10.40.nc' hdle_out = nc.Dataset(fname_out,'w') hdle_out.createDimension("lat",lat_coord.size) hdle_out.createDimension("lon",lon_coord.size) hdle_out.createDimension("time",time_coord.size) fval = default_fillvals['u8'] #hdle_out._FillValue = fval #hdle_out.missingvalue = fval lat = hdle_out.createVariable("lat",'f',("lat")) lat.long_name="Latitude" lat.units="degrees_north" lat._CoordinateAxisType = "Lat"; # WARNING: latitudes are flipped lat[:] = lat_coord[::-1] lon = hdle_out.createVariable("lon",'f',("lon")) lon.long_name="Longitude" lon.units="degrees_east" lon._CoordinateAxisType = "Lon"; lon[:] = lon_coord[:] time = hdle_out.createVariable("time",'i',("time")) time.long_name="time" time.units="hours since 1900-01-01 00:00:0.0" time._CoordinateAxisType = "Time"; time[:] = time_coord[:] # WARNING: latitudes are flipped fval = st.max()*1.1 stout = hdle_out.createVariable('stl1', 'f',("time","lat","lon"),fill_value=fval) stout[:,:,:] = st[:,::-1,:] stout.missing_value = fval fval = t2m.max()*1.1 tout = hdle_out.createVariable('t2m', 'f',("time","lat","lon"),fill_value=fval) tout[:,:,:] = t2m[:,::-1,:] fval = d2m.max()*1.1 dout = hdle_out.createVariable('d2m', 'f',("time","lat","lon"),fill_value=fval) dout[:,:,:] = d2m[:,::-1,:] fval = u10.max()*1.1 uout = hdle_out.createVariable('u10', 'f',("time","lat","lon"),fill_value=fval) uout[:,:,:] = u10[:,::-1,:] fval = v10.max()*1.1 vout = hdle_out.createVariable('v10', 'f',("time","lat","lon"),fill_value=fval) vout[:,:,:] = v10[:,::-1,:] hdle_out.close() #------------------------------------------------------------------------- #------------------------------------------------------------------------- # # Read profiles outputs from ECMWF #------------------------------------------------------------------------- fname = 'classes/filtre_PROF01_0d25_20150601_00-06-12-18_region_Lon.-140.-100_Lat.10.40.nc' hdle = nc.Dataset(fname) # lat/lon coord lat_coord = hdle.variables['latitude'][:] lon_coord = hdle.variables['longitude'][:] time_coord = hdle.variables['time'][:] level_coord = hdle.variables['level'][:] # time,nlev,lat,lon t = hdle.variables['t'][:,:,:,:] q = hdle.variables['q'][:,:,:,:] clwc = hdle.variables['clwc'][:,:,:,:] # REQUIRED but not a direct ouput from ecmwf ELEV = hdle.variables['ELEVATION'][:,:,:,:] # # Write new format #------------------------------------------------------------------------- fname_out = 'classes/VAPOR_filtre_PROF01_0d25_20150601_00-06-12-18_region_Lon.-140.-100_Lat.10.40.nc' hdle_out = nc.Dataset(fname_out,'w') # dimensions hdle_out.createDimension("lat",lat_coord.size) hdle_out.createDimension("lon",lon_coord.size) hdle_out.createDimension("time",time_coord.size) fval = default_fillvals['u8'] #hdle_out._FillValue = fval #hdle_out.missingvalue = fval # Warning: latitudes are flipped lat = hdle_out.createVariable("lat",'f',("lat")) lat.long_name="Latitude" lat.units="degrees_north" lat._CoordinateAxisType = "Lat"; lat[:] = lat_coord[::-1] lon = hdle_out.createVariable("lon",'f',("lon")) lon.long_name="Longitude" lon.units="degrees_east" lon._CoordinateAxisType = "Lon"; lon[:] = lon_coord[:] time = hdle_out.createVariable("time",'i',("time")) time.long_name="time" time.units="hours since 1900-01-01 00:00:0.0" time._CoordinateAxisType = "Time"; time[:] = time_coord[:] # sub sampling of levels subsample = 1 levmax = 60 sublev = level_coord[:levmax:subsample] hdle_out.createDimension("hybrid",sublev.size) level = hdle_out.createVariable("hybrid",'f',("hybrid")) level.long_name="Levels" level._CoordinateAxisType = "GeoZ"; level._CoordinateZisPositive = "down"; level.units = 'sigma' level[:] = sublev[:] #print "Liste des niveaux" #print level[:] nlev = level.size # Warning: latitudes are flipped # Warning: levels are flipped fval = t.max()*1.1 tout = hdle_out.createVariable('t', 'f',("time","hybrid","lat","lon"),fill_value=fval) for klev,lev in enumerate(np.arange(nlev)[:levmax:subsample]): tout[:,nlev-klev-1,:,:] = t[:,lev,::-1,:] fval = q.max()*1.1 qout = hdle_out.createVariable('q', 'f',("time","hybrid","lat","lon"),fill_value=fval) for klev,lev in enumerate(np.arange(nlev)[:levmax:subsample]): qout[:,nlev-klev-1,:,:] = q[:,lev,::-1,:] fval = clwc.max()*1.1 clout = hdle_out.createVariable('clwc', 'f',("time","hybrid","lat","lon"),fill_value=fval) for klev,lev in enumerate(np.arange(nlev)[:levmax:subsample]): clout[:,nlev-klev-1,:,:] = clwc[:,lev,::-1,:] fval = ELEV.max()*1.1 elout = hdle_out.createVariable('ELEVATION','f',("time","hybrid","lat","lon"),fill_value=fval) for klev,lev in enumerate(np.arange(nlev)[:levmax:subsample]): elout[:,nlev-klev-1,:,:] = ELEV[:,lev,::-1,:] hdle_out.close() # NCDFCREATE ncdfvdfcreate -vdc2 -missattr _Fillvalue -mapprojection "+proj=latlong +ellps=sphere" -extents -15400000:1100000:0:-11000000:4000000:16000 -timedims time classes/VAPOR_filtre_PROF01_0d25_20150601_00-06-12-18_region_Lon.-140.-100_Lat.10.40.nc classes/VAPOR_filtre_SURF01_0d25_20150601_00-06-12-18_region_Lon.-140.-100_Lat.10.40.nc ecmwf.vdf # POPULATE ncdf2vdf -timedims time -vars stl1:t2m:d2m:u10:v10 classes/VAPOR_filtre_SURF01_0d25_20150601_00-06-12-18_region_Lon.-140.-100_Lat.10.40.nc ecwmf.vdf ncdf2vdf -timedims time -vars t:q:clwc classes/VAPOR_filtre_PROF01_0d25_20150601_00-06-12-18_region_Lon.-140.-100_Lat.10.40.nc ecmwf.vdf
clyne

Can you post an 'ncdump -h' of one of your source NetCDF files?