SeaWinds on QuikSCAT

Herein we detail how we obtained and processed SeaWinds/QuikSCAT surface wind fields for use with the ROMS ocean circulation model. We start by providing a description of the fields and how they're stored that's sufficient to proceed to the processing stage.

SeaWinds on QuikSCAT measures backscatter from the ocean surface (sigma0) used to derive vector wind stress as well as wind speed and direction. Launched in June 19, 1999, QuikSCAT was originally intended to be a 'quick recovery' mission to fill the gap created by the unexpected failure of the NASA scatterometer (NSCAT). Fortunately, QuikSCAT has surpassed its life expectancy and continues to provide reliable and valuable ocean surface wind vector measurements.


DESCRIPTION


L3 Daily Gridded OWV

The SeaWinds on QuikSCAT Level 3 data set consists of gridded values of scalar wind speed, meridional and zonal components of wind velocity, wind speed squared and time given in fraction of a day. Rain probability determined using the Multidimensional Histogram (MUDH) Rain Flagging technique is also included as an indicator of wind values that may have degraded accuracy due to the presence of rain. Data are currently available in Hierarchical Data Format (HDF) and exist from 19 July 1999 to present.

The data set characteristics include:

Each HDF datafile contains 16 datasets:

  1. wind speed for the ascending pass
  2. wind speed for the descending pass
  3. u-component of wind velocity for the ascending pass
  4. u-component of wind velocity for the descending pass
  5. v-component of wind velocity for the ascending pass
  6. v-component of wind-velocity for the descending pass
  7. square of the wind speed for the ascending pass
  8. square of the wind speed for the descending pass
  9. distinguishes NULL from zero values in the ascending pass data
  10. distinguishes NULL from zero values in the descending pass data
  11. time in fraction of day ascending pass measurement taken
  12. time in fraction of day descending pass measurement taken
  13. probability of columnar rain rate greater than 2 km*mm/hr for ascending pass
  14. probability of columnar rain rate greater than 2 km*mm/hr for descending pass
  15. presence of rain detected in ascending pass wind vector cell
  16. presence of rain detected in descending pass wind vector cell


Data FTP Site


Sample Output Using read_qscat3.c

 ASCENDING PASS (DAYTIME)
LON       LAT      SPD   U    V      SPD2 COUNT TIME   PROB FLAG
200.12500 -9.87500 7.00 -6.77 -1.78  49.00 1   0.71562 0.311 6
200.12500 -9.62500 7.25 -6.99 -1.88  52.63 1   0.71568 0.591 6
200.12500 -9.37500 6.00 -5.98 -0.47  36.00 1   0.71570 0.508 6
200.12500 -9.12500 7.50 -7.50 -0.02  56.50 1   0.71576 0.501 6
200.12500 -8.87500 8.51 -8.51 -0.27  72.42 1   0.71582 1.000 6
...
DESCENDING PASS (NIGHTIME)
LON       LAT       SPD    U     V    SPD2 COUNT  TIME   PROB FLAG
200.12500 -9.87500 11.27 -11.27 -0.17 127.55 1   0.19340 0.596 2
200.12500 -9.62500  9.77  -9.72 -0.80  97.07 1   0.19334 0.093 2
200.12500 -9.37500  8.50  -8.31 -1.77  72.25 1   0.19328 0.003 0
200.12500 -9.12500  9.50  -9.46 -0.90  90.25 1   0.19324 0.006 0
200.12500 -8.87500 10.50 -10.48 -0.60 110.25 1   0.19320 0.150 2
...


PROCESSING


Herein we outline the steps to convert the QuikScat surface wind fields stored in HDF files into ROMS-ready wind field files in NetCDF format using Python/Numpy tools designed to perform just such tasks. While your mileage will indeed vary if your endpoint isn't ROMS, the procedure using these tools will mostly likely be very similar to what you see below. Once you've installed the appropriate modules and prerequisites and spent a little time familiarizing yourself with the Python/Numpy syntax, you'll find these tools provide an elegant and flexible way to perform all sorts of tasks involving NetCDF and/or HDF files.


Tools


Using these fields to force ROMS requires that we transmogrify the HDF format in which they're available into ROMS-ready NetCDF format. The toolset used will consist of the following:

The prerequisites for both of these packages are the Python programming language and the Python linear algebra module Numpy. Most Linux distributions contain the former, but you may have to install the latter, a topic well covered elsewhere. It's also necessary to install the HDF4 and NetCDF libraries, although those tasks are described in great detail at their respective sites.

Installing PyHDF

Go to the home page at:

http://pysclint.sourceforge.net/pyhdf/

and proceed to either the Download Page or the Source Repository. We're going to the latter to check out the Subversion repository via:

svn co https://pysclint.svn.sourceforge.net/svnroot/pysclint pysclint

This will create a subdirectory pysclint in the directory in which you're currently working. Since pysclint - a collection of Python interfaces to major scientific libraries - is a superset of the HDF interface we desire, we'll burrow down into the directory hierarchy to find the specific subdirectory we need, i.e.

cd trunk/pyhdf

Before you continue, it might be a good idea to take a gander at the INSTALL file in this directory, especially if you're not compiling from source on a Linux box. On the other hand, if you are installing that way, then first identify the location of the include and library files of your HDF4 distribution via:

export INCLUDE_DIRS=/opt/HDF/hdf4.2r4/include
export INCLUDE_DIRS=/opt/HDF/hdf4.2r4/lib

where you'll replace the string /opt/HDF/hdf4.2r4 with the location of these files on your machine.

You can then build the module via:

python setup.py build [>& build.log &]

where the bits inside the square brackets are optional in the case that you want to keep a record of the compilation procedure. If this step works, then proceed to install the module via:

su
...
python setup.py install [>& inst.log &]

where the su indicates that the installation needs to be performed as root, and the square bracket bits are optional as in the previous step.

Installing netcdf4-python

Here you'll be shown how to install the minimal netcdf4-python configuration required to create ROMS-ready files, that is, the NetCDF3 subset. This can also be done for the NetCDF4 superset, with the details available in the README file.

Go to the home page at:

http://code.google.com/p/netcdf4-python/

and click on the Source tab near the top of the page. This will instruction you to download a copy of the source code via:

svn checkout http://netcdf4-python.googlecode.com/svn/trunk/ netcdf4-python

where the netcdf4-python can be renamed to something else if you so desire. Move to that directory via:

cd netcdf4-python

and set the location of your NetCDF3 library via:

export NETCDF3_DIR=/opt/NETCDF/netcdf-3.6.2

In a procedure identical to installing PyHDF, proceed via:

python setup.py build
su
...
python setup.py install


Reading Data with PyHDF


The documentation pertinent to our needs can be found in the documentation section describing the module implementing the SD (scientific dataset) API of the HDF4 library at:

http://pysclint.sourceforge.net/pyhdf/pyhdf.SD.html

A skeletal program is:

from numpy import *
from pyhdf import SD


Creating the Lon/Lat Grid

The HDF files do not contain lon/lat grids. These can be a calculated via the following instructions from the L3 report:

The QuikSCAT Level 3 data set is on a simple, rectangular grid of 1440 columns by 720 rows. Therefore, a grid element spans 0.25 degrees in longitude (360/1440) and latitude (180/720). Latitude and longitude coordinates are assigned to each grid element based on its center. To calculate the longitude and latitude of a grid point, the following equations can be used:

lon[i] = (360./XGRID) * (i+0.5) for i=0...XGRID-1
lat[j] = (180./YGRID) * (j+0.5) - 90. for j=0...YGRID-1

where:

XGRID = grid elements in the x-direction (1440)
YGRID = grid elements in the y-direction (720)

As shown by the above formulas, the latitude and longitude of the center of the first grid cell of each QuikSCAT Level 3 scientific data is -89.875° North (89.875° South) and 0.125° East. The latitude and longitude of the final grid cell of each data set is centered at 89.875° North and 359.875° East (0.125° West).


APPENDIX 1 - Sample HDF File Header

A sample file from 1999 called QS_XWGRD3_1999206.20070640437.gz has been downloaded from:

ftp://podaac.jpl.nasa.gov/pub/ocean_wind/quikscat/L3/data/1999/

and ASCII header information has been extracted using the ncdump program created from compiling the latest HDF4 library. The header information is:


netcdf QS_XWGRD3_1999206 {
dimensions:
        fakeDim0 = 720 ;
        fakeDim1 = 1440 ;
        fakeDim2 = 720 ;
        fakeDim3 = 1440 ;
        fakeDim4 = 720 ;
        fakeDim5 = 1440 ;
        fakeDim6 = 720 ;
        fakeDim7 = 1440 ;
        fakeDim8 = 720 ;
        fakeDim9 = 1440 ;
        fakeDim10 = 720 ;
        fakeDim11 = 1440 ;
        fakeDim12 = 720 ;
        fakeDim13 = 1440 ;
        fakeDim14 = 720 ;
        fakeDim15 = 1440 ;
        fakeDim16 = 720 ;
        fakeDim17 = 1440 ;
        fakeDim18 = 720 ;
        fakeDim19 = 1440 ;
        fakeDim20 = 720 ;
        fakeDim21 = 1440 ;
        fakeDim22 = 720 ;
        fakeDim23 = 1440 ;
        fakeDim24 = 720 ;
        fakeDim25 = 1440 ;
        fakeDim26 = 720 ;
        fakeDim27 = 1440 ;
        fakeDim28 = 720 ;
        fakeDim29 = 1440 ;
        fakeDim30 = 720 ;
        fakeDim31 = 1440 ;

variables:
        short asc_avg_wind_speed(fakeDim0, fakeDim1) ;
                asc_avg_wind_speed:scale_factor = 0.01 ;
                asc_avg_wind_speed:scale_factor_err = 0. ;
                asc_avg_wind_speed:add_offset = 0. ;
                asc_avg_wind_speed:add_offset_err = 0. ;
                asc_avg_wind_speed:calibrated_nt = 22 ;
                asc_avg_wind_speed:long_name = "asc_avg_wind_speed" ;
                asc_avg_wind_speed:units = "m/s" ;
        short des_avg_wind_speed(fakeDim2, fakeDim3) ;
                des_avg_wind_speed:scale_factor = 0.01 ;
                des_avg_wind_speed:scale_factor_err = 0. ;
                des_avg_wind_speed:add_offset = 0. ;
                des_avg_wind_speed:add_offset_err = 0. ;
                des_avg_wind_speed:calibrated_nt = 22 ;
                des_avg_wind_speed:long_name = "des_avg_wind_speed" ;
                des_avg_wind_speed:units = "m/s" ;
        short asc_avg_wind_vel_u(fakeDim4, fakeDim5) ;
                asc_avg_wind_vel_u:scale_factor = 0.01 ;
                asc_avg_wind_vel_u:scale_factor_err = 0. ;
                asc_avg_wind_vel_u:add_offset = 0. ;
                asc_avg_wind_vel_u:add_offset_err = 0. ;
                asc_avg_wind_vel_u:calibrated_nt = 22 ;
                asc_avg_wind_vel_u:long_name = "asc_avg_wind_vel_u" ;
                asc_avg_wind_vel_u:units = "m/s" ;
        short des_avg_wind_vel_u(fakeDim6, fakeDim7) ;
                des_avg_wind_vel_u:scale_factor = 0.01 ;
                des_avg_wind_vel_u:scale_factor_err = 0. ;
                des_avg_wind_vel_u:add_offset = 0. ;
                des_avg_wind_vel_u:add_offset_err = 0. ;
                des_avg_wind_vel_u:calibrated_nt = 22 ;
                des_avg_wind_vel_u:long_name = "des_avg_wind_vel_u" ;
                des_avg_wind_vel_u:units = "m/s" ;
        short asc_avg_wind_vel_v(fakeDim8, fakeDim9) ;
                asc_avg_wind_vel_v:scale_factor = 0.01 ;
                asc_avg_wind_vel_v:scale_factor_err = 0. ;
                asc_avg_wind_vel_v:add_offset = 0. ;
                asc_avg_wind_vel_v:add_offset_err = 0. ;
                asc_avg_wind_vel_v:calibrated_nt = 22 ;
                asc_avg_wind_vel_v:long_name = "asc_avg_wind_vel_v" ;
                asc_avg_wind_vel_v:units = "m/s" ;
        short des_avg_wind_vel_v(fakeDim10, fakeDim11) ;
                des_avg_wind_vel_v:scale_factor = 0.01 ;
                des_avg_wind_vel_v:scale_factor_err = 0. ;
                des_avg_wind_vel_v:add_offset = 0. ;
                des_avg_wind_vel_v:add_offset_err = 0. ;
                des_avg_wind_vel_v:calibrated_nt = 22 ;
                des_avg_wind_vel_v:long_name = "des_avg_wind_vel_v" ;
                des_avg_wind_vel_v:units = "m/s" ;
        long asc_avg_wind_speed_sq(fakeDim12, fakeDim13) ;
                asc_avg_wind_speed_sq:scale_factor = 0.01 ;
                asc_avg_wind_speed_sq:scale_factor_err = 0. ;
                asc_avg_wind_speed_sq:add_offset = 0. ;
                asc_avg_wind_speed_sq:add_offset_err = 0. ;
                asc_avg_wind_speed_sq:calibrated_nt = 22 ;
                asc_avg_wind_speed_sq:long_name = "asc_avg_wind_speed_sq" ;
                asc_avg_wind_speed_sq:units = "m^2/s^2" ;
        long des_avg_wind_speed_sq(fakeDim14, fakeDim15) ;
                des_avg_wind_speed_sq:scale_factor = 0.01 ;
                des_avg_wind_speed_sq:scale_factor_err = 0. ;
                des_avg_wind_speed_sq:add_offset = 0. ;
                des_avg_wind_speed_sq:add_offset_err = 0. ;
                des_avg_wind_speed_sq:calibrated_nt = 22 ;
                des_avg_wind_speed_sq:long_name = "des_avg_wind_speed_sq" ;
                des_avg_wind_speed_sq:units = "m^2/s^2" ;
        byte asc_wvc_count(fakeDim16, fakeDim17) ;
                asc_wvc_count:scale_factor = 1. ;
                asc_wvc_count:scale_factor_err = 0. ;
                asc_wvc_count:add_offset = 0. ;
                asc_wvc_count:add_offset_err = 0. ;
                asc_wvc_count:calibrated_nt = 22 ;
                asc_wvc_count:long_name = "asc_wvc_count" ;
                asc_wvc_count:units = "counts" ;
        byte des_wvc_count(fakeDim18, fakeDim19) ;
                des_wvc_count:scale_factor = 1. ;
                des_wvc_count:scale_factor_err = 0. ;
                des_wvc_count:add_offset = 0. ;
                des_wvc_count:add_offset_err = 0. ;
                des_wvc_count:calibrated_nt = 22 ;
                des_wvc_count:long_name = "des_wvc_count" ;
                des_wvc_count:units = "counts" ;
        short asc_time_frac(fakeDim20, fakeDim21) ;
                asc_time_frac:scale_factor = 2.e-05 ;
                asc_time_frac:scale_factor_err = 0. ;
                asc_time_frac:add_offset = 0. ;
                asc_time_frac:add_offset_err = 0. ;
                asc_time_frac:calibrated_nt = 22 ;
                asc_time_frac:long_name = "asc_time_frac" ;
                asc_time_frac:units = "day" ;
        short des_time_frac(fakeDim22, fakeDim23) ;
                des_time_frac:scale_factor = 2.e-05 ;
                des_time_frac:scale_factor_err = 0. ;
                des_time_frac:add_offset = 0. ;
                des_time_frac:add_offset_err = 0. ;
                des_time_frac:calibrated_nt = 22 ;
                des_time_frac:long_name = "des_time_frac" ;
                des_time_frac:units = "day" ;
        short asc_rain_prob(fakeDim24, fakeDim25) ;
                asc_rain_prob:scale_factor = 0.001 ;
                asc_rain_prob:scale_factor_err = 0. ;
                asc_rain_prob:add_offset = 0. ;
                asc_rain_prob:add_offset_err = 0. ;
                asc_rain_prob:calibrated_nt = 22 ;
                asc_rain_prob:long_name = "asc_rain_prob" ;
                asc_rain_prob:units = " " ;
        short des_rain_prob(fakeDim26, fakeDim27) ;
                des_rain_prob:scale_factor = 0.001 ;
                des_rain_prob:scale_factor_err = 0. ;
                des_rain_prob:add_offset = 0. ;
                des_rain_prob:add_offset_err = 0. ;
                des_rain_prob:calibrated_nt = 22 ;
                des_rain_prob:long_name = "des_rain_prob" ;
                des_rain_prob:units = " " ;
        byte asc_rain_flag(fakeDim28, fakeDim29) ;
                asc_rain_flag:scale_factor = 1. ;
                asc_rain_flag:scale_factor_err = 0. ;
                asc_rain_flag:add_offset = 0. ;
                asc_rain_flag:add_offset_err = 0. ;
                asc_rain_flag:calibrated_nt = 22 ;
                asc_rain_flag:long_name = "asc_rain_flag" ;
                asc_rain_flag:units = " " ;
        byte des_rain_flag(fakeDim30, fakeDim31) ;
                des_rain_flag:scale_factor = 1. ;
                des_rain_flag:scale_factor_err = 0. ;
                des_rain_flag:add_offset = 0. ;
                des_rain_flag:add_offset_err = 0. ;
                des_rain_flag:calibrated_nt = 22 ;
                des_rain_flag:long_name = "des_rain_flag" ;
                des_rain_flag:units = " " ;

// global attributes:
                :LongName = "char\n",
    "1\n",
    "QuikSCAT Level 3 Ocean Wind Vectors in 25km grid\n",
    "" ;
                :ShortName = "char\n",
    "1\n",
    "QSCATL3\n",
    "" ;
                :producer_agency = "char\n",
    "1\n",
    "NASA\n",
    "" ;
                :producer_institution = "char\n",
    "1\n",
    "JPL\n",
    "" ;
                :PlatformType = "char\n",
    "1\n",
    "spacecraft\n",
    "" ;
                :InstrumentShortName = "char\n",
    "1\n",
    "SeaWinds\n",
    "" ;
                :PlatformLongName = "char\n",
    "1\n",
    "NASA Quick Scatterometer\n",
    "" ;
                :PlatformShortName = "char\n",
    "1\n",
    "QuikSCAT\n",
    "" ;
                :project_id = "char\n",
    "1\n",
    "QuikSCAT\n",
    "" ;
                :data_format_type = "char\n",
    "1\n",
    "NCSA HDF\n",
    "" ;
                :ProductionDateTime = "char\n",
    "1\n",
    "2007-064T04:37:47.000\n",
    "" ;
                :HDF_version_id = "char\n",
    "1\n",
    "4.1r3\n",
    "" ;
                :date_of_average = "char\n",
    "1\n",
    "1999-206\n",
    "" ;
                :l3_rows = "int\n",
    "1\n",
    "720\n",
    "" ;
                :l3_columns = "int\n",
    "1\n",
    "1440\n",
    "" ;
                :l2b_input_files = "char\n",
    "15\n",
    "/QS_S2B00504.20070632141\n",
    "/QS_S2B00505.20070632135\n",
    "/QS_S2B00506.20070632139\n",
    "/QS_S2B00507.20070632130\n",
    "/QS_S2B00508.20070632131\n",
    "/QS_S2B00509.20070632126\n",
    "/QS_S2B00510.20070632127\n",
    "/QS_S2B00511.20070631656\n",
    "/QS_S2B00512.20070631658\n",
    "/QS_S2B00513.20070631700\n",
    "/QS_S2B00514.20070631700\n",
    "/QS_S2B00515.20070631703\n",
    "/QS_S2B00516.20070631705\n",
    "/QS_S2B00517.20070631647\n",
    "/QS_S2B00518.20070631647\n",
    "" ;

data:

 asc_avg_wind_speed =
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
...