[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

20011102: satellite winds to netCDF converter



>From: Unidata User Support <address@hidden>
>Organization: Unidata Program Center/UCAR
>Keywords: McIDAS-X ADDE netCDF satellite winds

Gail (with CC to Russ),

I am including the McIDAS application that I wrote that reads CIMSS
satellite retrieved winds by ADDE and writes them into a netCDF.  As
promised, I am including a blow-by-blow on how the application was
created.

First, I took Gail's minimum list of useful parameters in the winds MD
file as the list of things to write to the output netCDF:

  From: Gail Dengel <address@hidden>
  Date: Wed, 24 Oct 2001 17:53:00 +0000

  Here's the minimum list of useful parameters in the winds MD files I
  promised (or threatened) to send you:

      DAY1
      HMS1
      SATD
      PROD
      SID

      FLAG
      TYPE
      LAT
      LON
      DIR
      SPD
      PW
      TC
      CH

I turned this into a CDL for the eventual output netCDF (a CDL is the
netCDF equivalent of an MD file schema).  The CDL I created is:

------ snip --------- satwinds.cdl ------------------------------------------

netcdf satwinds {
dimensions:
        recNum = UNLIMITED ;
        nameLen = 5 ;
variables:
        // DAY1 and HMS1
        double timeObs(recNum) ;
                timeObs:long_name = "Date/Time of observation" ;
                timeObs:units = "seconds since 1970-1-1 00:00:00.0" ;
                timeObs:_FillValue = 1.e+38 ;
        // SATD
        char satName(recNum, nameLen) ;
                satName:long_name = "Satellite ID name" ;
        // PROD
        char windProd(recNum, nameLen);
                windProd:long_name = "Wind vector product (WV or CDFT)" ;
        // SID
        int satIdn(recNum) ;
                satIdn:long_name = "Satellite ID number" ;
        // FLAG
        int errFlag(recNum);
                errFlag:long_name = "Error flag" ;
        // TYPE
        char windType(recNum, nameLen) ;
                windType:long_name = "Satellite ID name" ;
        // LAT
        float windLat(recNum) ;
                windLat:long_name = "Latitude location" ;
                windLat:units = "degree_N" ;
                windLat:_FillValue = 1.e+38f ;
                windLat:valid_range = -90.f, 90.f ;
        // LON
        float windLon(recNum) ;
                windLon:long_name = "Longitude location" ;
                windLon:units = "degree_E" ;
                windLon:_FillValue = 1.e+38f ;
                windLon:valid_range = -180.f, 180.f ;
        // DIR
        float windDir(recNum) ;
                windDir:long_name = "Final wind direction" ;
                windDir:units = "degree" ;
                windDir:_FillValue = 1.e+38f ;
                windDir:valid_range = 0.f, 360.f ;
        // SPD
        float windSpeed(recNum) ;
                windSpeed:long_name = "Final wind speed" ;
                windSpeed:units = "meter/sec" ;
                windSpeed:_FillValue = 1.e+38f ;
                windSpeed:valid_range = -150.f, 150.f ;
        // PW
        float windPress(recNum) ;
                windPress:long_name = "Final height assignment" ;
                windPress:units = "meter/sec" ;
                windPress:_FillValue = 1.e+38f ;
                windPress:valid_range = 0.f, 1050.f;
        // TC
        float cloudTemp(recNum) ;
                cloudTemp:long_name = "Cloud temperature at final height" ;
                cloudTemp:units = "kelvin" ;
                cloudTemp:_FillValue = 1.e+38f ;
                cloudTemp:valid_range = 0.f, 400.f;
        // CH
        char hgtAssignMethod(recNum, nameLen) ;
                hgtAssignMethod:long_name = "Height assignment method" ;

// global attributes:
                :title = "CIMSS SatWinds retrieval" ;
}

------ snip --------- satwinds.cdl ------------------------------------------


Next, I used the CDL to generate C source code for the netCDF writer:

ncgen -c satwinds.cdl > swnd2cdf.c

After that, the job consisted of adding:

o #include <string.h>
  #include <mcidas.h>

o documentation (so one can generate a McIDAS .hlp file

o additional variable definitions for netCDF code (5 definitions)

o McIDAS code that allows a user to specify:

  SWND2CDF output <keywords>
  Parameters:
    output - netCDF file name
  Keywords:
    DATaset= ADDE dataset to read
    DAY= keyword to specify DAY/DAYs to read
    TIME= keyword to specify range of times to read

  -- side note: the McIDAS code was the hardest part of this whole exercise!

o just before the ncgen generated C code (an nc_close that closes the output
  netCDF), I added a section that is a mixture of McIDAS ADDE read and
  parameter convert code and netCDF write code.

o at the very end, I announce how many data records were written, and
  a notice that the program is done

I also tried to indicate, by comments in the code, what code was added
by me "by hand" and what code was written by ncgen.

The only changes I had to make to the ncgen generated code were:

o move the declaration 'int   stat' up to the top of the program

o replace the hardwired output netCDF name in the nc_open call with
  the variable populated by the Mccmdstr call that allows the user
  to specify what s/he wants to call the output

So, here is the source for the new application:

------ snip --------- swnd2cdf.c --------------------------------------------

/*
*? SWND2CDF -- Copy CIMSS satellite wind retrieval values to a netCDF
*?   SWND2CDF output
*?
*? Parameter:
*?   output  | netCDF file to write to (def=satwinds.nc)
*?
*? Keywords:
*?   DAY= begday endday | DAY range for input (def=current begday)
*?   TIME= begtim endtim | TIME range for input (def=current begtim)
*?   TRACE= 0,1 | Send TRACE directive to server (def=0 (no))
*?
*? Remarks:
*?   A small subset of parameters from the wind retrieval files
*?   are saved to the output netCDF.  The parameters copied are:
*?
*?   Parameter    Unit   Description
*?   ---------  -------  ----------------------------
*?     DAY1     ccyyddd  winds DAY
*?     HMS1       hms    winds TIME
*?     SATD      text    satellite ID
*?     PROD      text    product type
*?     SID        I2     satellite ID
*?     FLAG       I2     data error flag
*?     TYPE      text    retrieval type
*?     LAT        deg    latitude
*?     LON        deg    longitude (West positive)
*?     DIR        deg    wind direction
*?     SPD        m/s    wind speed
*?     PW         mb     pressure at retrieved wind level
*?     TC         K      temperature at retrieved wind level
*?     CH        text    height assignment method
*?
*?   The date and time of the retrieval is saved in the netCDF as
*?   seconds since 1970-1-1 00:00:00.0
*?
*? Example:
*?   SWND2CDF satwinds.nc DAY=2001306 TIME=12:00 17:30
*?
*? ----------
*
*  History: 20011102 - Written for UW-CIMSS satellite winds team (TCY)
*/

#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <netcdf.h>
#include <mcidas.h>                  /* McIDAS code added to ncgen .c file */

void
check_err(const int stat, const int line, const char *file) {
    if (stat != NC_NOERR) {
           (void) fprintf(stderr, "line %d of %s: %s\n", line, file, 
nc_strerror(stat));
        exit(1);
    }
}

int
main(int argc, char **argv) {                   /* create satwinds.nc */

   /*
   ** netCDF stuff automatically included by ncgen
   */
   int  ncid;                   /* netCDF id */

   /* dimension ids */
   int recNum_dim;
   int nameLen_dim;

   /* dimension lengths */
   size_t recNum_len = NC_UNLIMITED;
   size_t nameLen_len = 5;

   /* variable ids */
   int timeObs_id;
   int satName_id;
   int windProd_id;
   int satIdn_id;
   int errFlag_id;
   int windType_id;
   int windLat_id;
   int windLon_id;
   int windDir_id;
   int windSpeed_id;
   int windPress_id;
   int cloudTemp_id;
   int hgtAssignMethod_id;

   /* rank (number of dimensions) for each variable */
#  define RANK_timeObs 1
#  define RANK_satName 2
#  define RANK_windProd 2
#  define RANK_satIdn 1
#  define RANK_errFlag 1
#  define RANK_windType 2
#  define RANK_windLat 1
#  define RANK_windLon 1
#  define RANK_windDir 1
#  define RANK_windSpeed 1
#  define RANK_windPress 1
#  define RANK_cloudTemp 1
#  define RANK_hgtAssignMethod 2

   /* variable shapes */
   int timeObs_dims[RANK_timeObs];
   int satName_dims[RANK_satName];
   int windProd_dims[RANK_windProd];
   int satIdn_dims[RANK_satIdn];
   int errFlag_dims[RANK_errFlag];
   int windType_dims[RANK_windType];
   int windLat_dims[RANK_windLat];
   int windLon_dims[RANK_windLon];
   int windDir_dims[RANK_windDir];
   int windSpeed_dims[RANK_windSpeed];
   int windPress_dims[RANK_windPress];
   int cloudTemp_dims[RANK_cloudTemp];
   int hgtAssignMethod_dims[RANK_hgtAssignMethod];

   /* attribute vectors */
   double timeObs__FillValue[1];
   float windLat__FillValue[1];
   float windLat_valid_range[2];
   float windLon__FillValue[1];
   float windLon_valid_range[2];
   float windDir__FillValue[1];
   float windDir_valid_range[2];
   float windSpeed__FillValue[1];
   float windSpeed_valid_range[2];
   float windPress__FillValue[1];
   float windPress_valid_range[2];
   float cloudTemp__FillValue[1];
   float cloudTemp_valid_range[2];

   /*
   ** netCDF stuff included by hand
   */

   int   stat;

   size_t               start[1];           /* start array for non-text vars */
   size_t               count[1];           /* count array for non-text vars */
   size_t               sstart[2];          /* start array for text vars */
   size_t               scount[2];          /* count array for non-text vars */

   /*
   ** McIDAS stuff included by hand
   */

   int                  current_day;        /* current system day */
   int                  current_hms;        /* current system time */
   int                  data_record[20];    /* data record from server */
   int                  beg_day;            /* beginning day for copy */
   int                  beg_time;           /* beginning hour for copy */
   int                  end_day;            /* ending day for copy */
   int                  end_time;           /* ending hour for copy */
   int                  ihr, min, sec;      /* hour, minute, and second */
   int                  i;                  /* generic counter */
   int                  gotbytes;           /* number of bytes from server */
   int                  nparms;             /* number of parameters requested */
   int                  nsorts;             /* number of selection clauses */
   int                  rc;                 /* function return value */
   int                  return_val = 1;     /* main() return value */
   int                  trace_val;          /* value to set for trace flag */

   char                 cschema[5];         /* schema of MD file*/
   char                 ctextid[33];        /* text ID of MD file */
   char                 creatid[5];         /* creator MD file ID */
   char                 cname[9];           /* name of MD file */

   char                *p = NULL;           /* generic character pointer */
   char                 ctemp[256];         /* working string buffer */
   char                 cpos[5];            /* dataset position */
   char                *csplit;             /* split dataset group descriptor */
   char                 dsname[255];        /* group/descriptor part of dset */
   const char          *cdfname;            /* name of output netCDF */
   const char          *dset;               /* ADDE data set name */

   char                 ctim1[9], ctim2[9]; /* time in HH:MM:SS format */
   int                  header[64];         /* header back from point server */
   char                *sorts[256] = {0};   /* selection character array */
   char                *parms[256] = {0};   /* parameters requested */
   char                *units[256] = {0};   /* units for parameters */
   char                *forms[256] = {0};   /* formats for parameters */
   int                  scales[20] = {0};   /* scales for parameters */

   int                  day1;               /* DAY read from server [ccyyddd] */
   int                  hms1;               /* TIME read from server [hms] */
   int                  sid;                /* Satellite ID */
   int                  flag;               /* data flag */
   double               dlat;               /* Latitude [deg] */
   double               dlon;               /* Longitude [deg] */
   int                  dir;                /* Wind direction [deg] */
   double               dspd;               /* Wind speed [m/s] */
   int                  pw;                 /* Pressure at wind level [mb] */
   double               dtc;                /* Temperature at wind level [K] */
   char                *satd ={0};          /* Satellite (text) */
   char                *prod ={0};          /* Product (text) */
   char                *type ={0};          /* Type (text) */
   char                *ch   ={0};          /* Height assignment method (text)*/

   time_t               seconds;            /* date/time seconds since 1970 */
   double               dsecs;              /* double equivalent of seconds */
   float                alat;               /* real equivalent of dlat */
   float                alon;               /* real equivalent of dlon */
   float                aspd;               /* real equivalent of dspd */
   float                atc;                /* real equivalent of dtc */

   /*
   ** Initialize McIDAS environment
   */

   if ( Mcinit (argc, argv) < 0 ) {
     fprintf( stderr, "%s\n", Mciniterr () );
     return ( return_val );
   }

   /*
   ** Announce start of program
   */

   Mcprintf( "SWND2CDF: Begin\n" );

   /*
   ** Get the name of the output netCDF.  Default to 'satwinds.nc'.
   */

   if ( Mccmdstr( " ", 1, "satwinds.nc", &cdfname ) < 0 ) {
     return ( return_val );
   }

   /*
   ** Get the dataset; default is CIMSSP/WNDGOESE.ALL
   */

   if ( Mccmdstr( "DAT.ASET", 1, "CIMSSP/WNDGOESE.ALL", &dset ) < 0 ) {
     return ( return_val );
   }
   strcpy( dsname, dset );

   p = strstr( dsname, "." );
   if ( p != (char *)NULL ) {
     strcpy( cpos, p+1 );
     *p = '\0';
   } else {
     strcpy( cpos, "ALL" );
   }

   Mcdprintf( "Data Set Name = '%s' cpos = '%s'\n", dsname, cpos );

   rc = M0split( dsname, &csplit );
   if ( rc ) {
     Mceprintf( "ERROR splitting dataset name: %s\n", dsname );
     return ( return_val );
   }

   /*
   ** Get the TRACE flag value
   */

   if ( Mccmdint( "TRA.CE", 1, "", 0, 1, 0, &trace_val ) < 0 ) {
     return ( return_val );
   }

   (void) sprintf( ctemp, "%s POS=%s BPOS=1 EPOS=9 MAX=1 TRACE=%d VERSION=1",
                   csplit, cpos, trace_val );
   Mcdprintf( "selection clause: %s\n", ctemp );

   /*
   ** Get the schema for this dataset.  Abort if it is not GWIN.
   */

   rc = M0cxreq( "MDFH", ctemp, 0, 0, &gotbytes );
   if ( gotbytes > 256 ) gotbytes = 256;

   rc = m0cxread_( &gotbytes, (Fint *)header );
   if ( rc ) {
     Mceprintf( "ERROR reading MD file header from server" );
     return ( return_val );
   }

   strncpy( cschema, (char *)&header[ 0],  4 );
   cschema[4] = '\0';

   strncpy( ctextid, (char *)&header[16], 32 );
   ctextid[32] = '\0';

   strncpy( creatid, (char *)&header[26],  4 );
   creatid[4] = '\0';

   strncpy( cname,   (char *)&header[61],  8 );
   cname[8] = '\0';

   Mcdprintf( "header[ 0] = '%s'\n", cschema );

   for ( i = 1; i < 16; i++ ) {
     Mcdprintf( "header[%2d] = %8d\n", i, header[i] );
   }

   Mcdprintf( "header[16] = '%s'\n", ctextid );

   for ( i = 24; i < 26; i++ ) {
     Mcdprintf( "header[%2d] = %8d\n", i, header[i] );
   }

   Mcdprintf( "header[26] = '%s'\n", creatid );

   for ( i = 27; i < 61; i++ ) {
     Mcdprintf( "header[%2d] = %8d\n", i, header[i] );
   }

   Mcdprintf( "header[61] = '%s'\n", cname );

   Mcdprintf( "header[63] = %8d\n", header[63] );

   if ( strcmp( cschema, "GWIN" ) ) {
     Mceprintf( "ERROR: dataset schema %s is not GWIN\n", cschema );
     return ( return_val );
   }
   
   /*
   ** Get the current system day and time
   */

   rc = Mcgetdaytime( &current_day, &current_hms );

   /*
   ** Get the day and time of the first data to copy
   */

   rc = Mccmdiyd( "DAY",1,"Begin day",current_day,1990001,2100001,&beg_day );
   if ( rc < 0 ) {
     return ( return_val );
   }

   rc = Mccmdihr( "TIM.E",1,"Begin time",current_hms,0,235959,&beg_time);
   if (rc < 0) {
     return ( return_val );
   }

   ihr = beg_time / 10000;
   min = (beg_time/100) % 100;
   sec = beg_time % 100;
   
   (void) sprintf( ctim1, "%2d:%02d:%02d", ihr, min, sec );

   /*
   ** Get the day and time of the last data to copy
   */

   rc = Mccmdiyd( "DAY",2,"End day",beg_day,beg_day,2100001,&end_day );
   if ( rc < 0 ) {
     return ( return_val );
   }

   rc = Mccmdihr( "TIM.E",2,"End time",beg_time,0,235959,&end_time );
   if ( rc < 0 ) {
     return ( return_val );
   }

   ihr = end_time / 10000;
   min = (end_time/100) % 100;
   sec = end_time % 100;
   
   (void) sprintf( ctim2, "%2d:%02d:%02d", ihr, min, sec );

   if ( end_day == beg_day && end_time < beg_time ) {
     Mceprintf( "Ending time %s must be greater than beginning time %s\n", 
                ctim2, ctim1 );
     return ( return_val );
   }

   /*
   ** Build selection arrays
   */

   sorts[0] = strdup( "MAX=ALL" );
   sorts[1] = strdup( "POS=ALL" );
   sorts[2] = strdup( "PARM=DAY1 HMS1 PROD SID FLAG TYPE LAT LON DIR SPD PW TC 
CH" );
   (void) sprintf( ctemp, "TRACE=%d", trace_val );
   sorts[3] = strdup( ctemp );
   (void) sprintf( ctemp, "SELECT='DAY1 %d TO %d' 'HMS1 %s TO %s'",
                   beg_day, end_day, ctim1, ctim2 );
   sorts[4] = strdup( ctemp );
   nsorts = 5;

   for ( i = 0; i < nsorts; i++ ) {
     Mcdprintf( "sorts[%1d]: %s\n", i, sorts[i] );
   }

   /*
   ** Specify parameters to be returned from server
   */

   parms[0]  = strdup( "DAY1" );
   parms[1]  = strdup( "HMS1" );
   parms[2]  = strdup( "SATD" );
   parms[3]  = strdup( "PROD" );
   parms[4]  = strdup( "SID " );
   parms[5]  = strdup( "FLAG" );
   parms[6]  = strdup( "TYPE" );
   parms[7]  = strdup( "LAT " );
   parms[8]  = strdup( "LON " );
   parms[9]  = strdup( "DIR " );
   parms[10] = strdup( "SPD " );
   parms[11] = strdup( "PW  " );
   parms[12] = strdup( "TC  " );
   parms[13] = strdup( "CH  " );
   nparms = 14;

   for ( i = 0; i < nparms; i++ ) {
     Mcdprintf( "parms[%1d]: %s\n", i, parms[i] );
   }

   /*
   ** Initialize POINT data request
   */

   rc = McPtGet( dsname,nsorts,sorts,&nparms,parms,units,forms,scales,0 );
   if ( rc < 0 ) {
     Mceprintf( "ERROR initializing POINT server data request" );
     return ( return_val );
   }

   for ( i = 0; i < nparms; i++ ){
     Mcdprintf( "%4s units[%2d] = %4s forms[%2d] = %4s scales[%2d] = %d\n",
                parms[i], i, units[i], i, forms[i], i, scales[i] );
   }

   /*
   ** Initialize subsystem for future McPtBuf calls
   */

   rc = McPtBufInit( nparms, forms, scales );
   if ( rc < 0 ) {
     Mceprintf( "ERROR initializing POINT server data request" );
     return ( return_val );
   }

   /*
   ** netCDF section created by ncgen.
   **
   ** Create the file, define dimensions, variables, and attributes.
   */

   /* enter define mode */
   stat = nc_create(cdfname, NC_CLOBBER, &ncid);
   check_err(stat,__LINE__,__FILE__);

   /* define dimensions */
   stat = nc_def_dim(ncid, "recNum", recNum_len, &recNum_dim);
   check_err(stat,__LINE__,__FILE__);
   stat = nc_def_dim(ncid, "nameLen", nameLen_len, &nameLen_dim);
   check_err(stat,__LINE__,__FILE__);

   /* define variables */

   timeObs_dims[0] = recNum_dim;
   stat = nc_def_var(ncid, "timeObs", NC_DOUBLE, RANK_timeObs, timeObs_dims, 
&timeObs_id);
   check_err(stat,__LINE__,__FILE__);

   satName_dims[0] = recNum_dim;
   satName_dims[1] = nameLen_dim;
   stat = nc_def_var(ncid, "satName", NC_CHAR, RANK_satName, satName_dims, 
&satName_id);
   check_err(stat,__LINE__,__FILE__);

   windProd_dims[0] = recNum_dim;
   windProd_dims[1] = nameLen_dim;
   stat = nc_def_var(ncid, "windProd", NC_CHAR, RANK_windProd, windProd_dims, 
&windProd_id);
   check_err(stat,__LINE__,__FILE__);

   satIdn_dims[0] = recNum_dim;
   stat = nc_def_var(ncid, "satIdn", NC_INT, RANK_satIdn, satIdn_dims, 
&satIdn_id);
   check_err(stat,__LINE__,__FILE__);

   errFlag_dims[0] = recNum_dim;
   stat = nc_def_var(ncid, "errFlag", NC_INT, RANK_errFlag, errFlag_dims, 
&errFlag_id);
   check_err(stat,__LINE__,__FILE__);

   windType_dims[0] = recNum_dim;
   windType_dims[1] = nameLen_dim;
   stat = nc_def_var(ncid, "windType", NC_CHAR, RANK_windType, windType_dims, 
&windType_id);
   check_err(stat,__LINE__,__FILE__);

   windLat_dims[0] = recNum_dim;
   stat = nc_def_var(ncid, "windLat", NC_FLOAT, RANK_windLat, windLat_dims, 
&windLat_id);
   check_err(stat,__LINE__,__FILE__);

   windLon_dims[0] = recNum_dim;
   stat = nc_def_var(ncid, "windLon", NC_FLOAT, RANK_windLon, windLon_dims, 
&windLon_id);
   check_err(stat,__LINE__,__FILE__);

   windDir_dims[0] = recNum_dim;
   stat = nc_def_var(ncid, "windDir", NC_FLOAT, RANK_windDir, windDir_dims, 
&windDir_id);
   check_err(stat,__LINE__,__FILE__);

   windSpeed_dims[0] = recNum_dim;
   stat = nc_def_var(ncid, "windSpeed", NC_FLOAT, RANK_windSpeed, 
windSpeed_dims, &windSpeed_id);
   check_err(stat,__LINE__,__FILE__);

   windPress_dims[0] = recNum_dim;
   stat = nc_def_var(ncid, "windPress", NC_FLOAT, RANK_windPress, 
windPress_dims, &windPress_id);
   check_err(stat,__LINE__,__FILE__);

   cloudTemp_dims[0] = recNum_dim;
   stat = nc_def_var(ncid, "cloudTemp", NC_FLOAT, RANK_cloudTemp, 
cloudTemp_dims, &cloudTemp_id);
   check_err(stat,__LINE__,__FILE__);

   hgtAssignMethod_dims[0] = recNum_dim;
   hgtAssignMethod_dims[1] = nameLen_dim;
   stat = nc_def_var(ncid, "hgtAssignMethod", NC_CHAR, RANK_hgtAssignMethod, 
hgtAssignMethod_dims, &hgtAssignMethod_id);
   check_err(stat,__LINE__,__FILE__);

   /* assign attributes */
   stat = nc_put_att_text(ncid, timeObs_id, "long_name", 24, "Date/Time of 
observation");
   check_err(stat,__LINE__,__FILE__);
   stat = nc_put_att_text(ncid, timeObs_id, "units", 33, "seconds since 
1970-1-1 00:00:00.0");
   check_err(stat,__LINE__,__FILE__);
   timeObs__FillValue[0] = 1e+38;
   stat = nc_put_att_double(ncid, timeObs_id, "_FillValue", NC_DOUBLE, 1, 
timeObs__FillValue);
   check_err(stat,__LINE__,__FILE__);
   stat = nc_put_att_text(ncid, satName_id, "long_name", 17, "Satellite ID 
name");
   check_err(stat,__LINE__,__FILE__);
   stat = nc_put_att_text(ncid, windProd_id, "long_name", 32, "Wind vector 
product (WV or CDFT)");
   check_err(stat,__LINE__,__FILE__);
   stat = nc_put_att_text(ncid, satIdn_id, "long_name", 19, "Satellite ID 
number");
   check_err(stat,__LINE__,__FILE__);
   stat = nc_put_att_text(ncid, errFlag_id, "long_name", 10, "Error flag");
   check_err(stat,__LINE__,__FILE__);
   stat = nc_put_att_text(ncid, windType_id, "long_name", 17, "Satellite ID 
name");
   check_err(stat,__LINE__,__FILE__);
   stat = nc_put_att_text(ncid, windLat_id, "long_name", 17, "Latitude 
location");
   check_err(stat,__LINE__,__FILE__);
   stat = nc_put_att_text(ncid, windLat_id, "units", 8, "degree_N");
   check_err(stat,__LINE__,__FILE__);
   windLat__FillValue[0] = 9.9999997e+37;
   stat = nc_put_att_float(ncid, windLat_id, "_FillValue", NC_FLOAT, 1, 
windLat__FillValue);
   check_err(stat,__LINE__,__FILE__);
   windLat_valid_range[0] = -90;
   windLat_valid_range[1] = 90;
   stat = nc_put_att_float(ncid, windLat_id, "valid_range", NC_FLOAT, 2, 
windLat_valid_range);
   check_err(stat,__LINE__,__FILE__);
   stat = nc_put_att_text(ncid, windLon_id, "long_name", 18, "Longitude 
location");
   check_err(stat,__LINE__,__FILE__);
   stat = nc_put_att_text(ncid, windLon_id, "units", 8, "degree_E");
   check_err(stat,__LINE__,__FILE__);
   windLon__FillValue[0] = 9.9999997e+37;
   stat = nc_put_att_float(ncid, windLon_id, "_FillValue", NC_FLOAT, 1, 
windLon__FillValue);
   check_err(stat,__LINE__,__FILE__);
   windLon_valid_range[0] = -180;
   windLon_valid_range[1] = 180;
   stat = nc_put_att_float(ncid, windLon_id, "valid_range", NC_FLOAT, 2, 
windLon_valid_range);
   check_err(stat,__LINE__,__FILE__);
   stat = nc_put_att_text(ncid, windDir_id, "long_name", 20, "Final wind 
direction");
   check_err(stat,__LINE__,__FILE__);
   stat = nc_put_att_text(ncid, windDir_id, "units", 6, "degree");
   check_err(stat,__LINE__,__FILE__);
   windDir__FillValue[0] = 9.9999997e+37;
   stat = nc_put_att_float(ncid, windDir_id, "_FillValue", NC_FLOAT, 1, 
windDir__FillValue);
   check_err(stat,__LINE__,__FILE__);
   windDir_valid_range[0] = 0;
   windDir_valid_range[1] = 360;
   stat = nc_put_att_float(ncid, windDir_id, "valid_range", NC_FLOAT, 2, 
windDir_valid_range);
   check_err(stat,__LINE__,__FILE__);
   stat = nc_put_att_text(ncid, windSpeed_id, "long_name", 16, "Final wind 
speed");
   check_err(stat,__LINE__,__FILE__);
   stat = nc_put_att_text(ncid, windSpeed_id, "units", 9, "meter/sec");
   check_err(stat,__LINE__,__FILE__);
   windSpeed__FillValue[0] = 9.9999997e+37;
   stat = nc_put_att_float(ncid, windSpeed_id, "_FillValue", NC_FLOAT, 1, 
windSpeed__FillValue);
   check_err(stat,__LINE__,__FILE__);
   windSpeed_valid_range[0] = -150;
   windSpeed_valid_range[1] = 150;
   stat = nc_put_att_float(ncid, windSpeed_id, "valid_range", NC_FLOAT, 2, 
windSpeed_valid_range);
   check_err(stat,__LINE__,__FILE__);
   stat = nc_put_att_text(ncid, windPress_id, "long_name", 23, "Final height 
assignment");
   check_err(stat,__LINE__,__FILE__);
   stat = nc_put_att_text(ncid, windPress_id, "units", 9, "meter/sec");
   check_err(stat,__LINE__,__FILE__);
   windPress__FillValue[0] = 9.9999997e+37;
   stat = nc_put_att_float(ncid, windPress_id, "_FillValue", NC_FLOAT, 1, 
windPress__FillValue);
   check_err(stat,__LINE__,__FILE__);
   windPress_valid_range[0] = 0;
   windPress_valid_range[1] = 1050;
   stat = nc_put_att_float(ncid, windPress_id, "valid_range", NC_FLOAT, 2, 
windPress_valid_range);
   check_err(stat,__LINE__,__FILE__);
   stat = nc_put_att_text(ncid, cloudTemp_id, "long_name", 33, "Cloud 
temperature at final height");
   check_err(stat,__LINE__,__FILE__);
   stat = nc_put_att_text(ncid, cloudTemp_id, "units", 6, "kelvin");
   check_err(stat,__LINE__,__FILE__);
   cloudTemp__FillValue[0] = 9.9999997e+37;
   stat = nc_put_att_float(ncid, cloudTemp_id, "_FillValue", NC_FLOAT, 1, 
cloudTemp__FillValue);
   check_err(stat,__LINE__,__FILE__);
   cloudTemp_valid_range[0] = 0;
   cloudTemp_valid_range[1] = 400;
   stat = nc_put_att_float(ncid, cloudTemp_id, "valid_range", NC_FLOAT, 2, 
cloudTemp_valid_range);
   check_err(stat,__LINE__,__FILE__);
   stat = nc_put_att_text(ncid, hgtAssignMethod_id, "long_name", 24, "Height 
assignment method");
   check_err(stat,__LINE__,__FILE__);
   stat = nc_put_att_text(ncid, NC_GLOBAL, "title", 24, "CIMSS SatWinds 
retrieval");
   check_err(stat,__LINE__,__FILE__);

   /* leave define mode */
   stat = nc_enddef (ncid);
   check_err(stat,__LINE__,__FILE__);

   /*
   ** ADDE read and netCDF write code included by hand
   */

   /*
   ** Read retrieved winds from ADDE Server and write values to file.
   */

   Mcdprintf( "  DAY1   HMS1  SATD PROD  SID FLAG TYPE   LAT     LON  DIR  SPD  
 PW   TC    CH\n" );
   Mcdprintf( " ------ ------ ---- ----  --- ---- ---- ------ ------- --- ----- 
--- ------ ----\n" );

   /*
   ** For all data types EXCEPT text (strings), we will write one item
   ** at a time.  The index of the write is represented by the array
   ** start[] and its value is the record number (zero based) of the write.
   ** The number of writes (one) is represented by the array count[]
   ** and its value is always 1 (one).
   **
   ** For text (strings) writes, we are also writing one item, but that
   ** item's length may vary.  The CDL for the output netCDF fixes the
   ** maximum length of the string as 5 (length of 4 plus a NULL byte),
   ** so one should make sure that the strings really are small enough
   ** to fit.
   ** 
   ** For text writes, the index of the write is represented by the array
   ** sstart[] which is two elements long.  The number of writes is
   ** represented by the array scount[] which is also two elements long.
   **
   ** The first element of sstart[] will vary in the exact same way as
   ** start[]: it will be the record number of the unlimited dimension.
   ** The second element of sstart[] will always be 0 (zero) as we
   ** always write at the beginning.
   **
   ** The first element of the number of writes array, scount[], will
   ** always be 1, we are always writing one item.  The second element
   ** of scount[] will be the length of the string being written.
   ** In our case, this would always be a maximum of 4 characters PLUS
   ** the trailing NULL byte.
   */

   start[0] = 0;
   count[0] = 1;

   sstart[0] = 0;
   sstart[1] = 0;
   scount[0] = 1;

   while ( 1 ) {

     rc = McPtRead( (void *) data_record );

     if ( rc < 0 ) {
       Mceprintf( "ERROR reading point data" );
     }

     if ( rc == 1 ) {
       break;
     }

     /* DAY1 and HMS1 */
     rc = McPtBufInt(  0, data_record, &day1 );
     rc = McPtBufInt(  1, data_record, &hms1 );

     /* Turn DAY [ccyyddd] and time [hhmmss] into seconds since 1970 */
     rc = Mcdaytimetosec( day1, hms1, &seconds );
     dsecs = (double) seconds;
     rc = nc_put_vara_double( ncid, timeObs_id, (const size_t *) start,
                              (const size_t *) count, (const double *) &dsecs );

     /* SATD */
     if ( satd ) free( satd );
     rc = McPtBufStr(  2, data_record, &satd );
     scount[1] = strlen( satd ) + 1;
     rc = nc_put_vara_text( ncid, satName_id, (const size_t *) sstart,
                            (const size_t *) scount, (const char *) satd);

     /* PROD */
     if ( prod ) free( prod );
     rc = McPtBufStr(  3, data_record, &prod );
     scount[1] = strlen( prod ) + 1;
     rc = nc_put_vara_text( ncid, windProd_id, (const size_t *) sstart,
                            (const size_t *) scount, (const char *) prod);

     /* SID */
     rc = McPtBufInt(  4, data_record, &sid );
     rc = nc_put_vara_int( ncid, satIdn_id, (const size_t *) start,
                           (const size_t *) count, (const int *) &sid);

     /* FLAG */
     rc = McPtBufInt(  5, data_record, &flag );
     rc = nc_put_vara_int( ncid, errFlag_id, (const size_t *) start,
                           (const size_t *) count, (const int *) &flag);

     /* TYPE */
     if ( type ) free( type );
     rc = McPtBufStr(  6, data_record, &type );
     scount[1] = strlen( type ) + 1;
     rc = nc_put_vara_text( ncid, windType_id, (const size_t *) sstart,
                            (const size_t *) scount, (const char *) type);

     /* LAT */
     rc = McPtBufDbl(  7, data_record, &dlat );
     alat = (float) dlat;
     rc = nc_put_vara_float( ncid, windLat_id, (const size_t *) start,
                             (const size_t *) count, (const float *) &alat);

     /* LON */
     rc = McPtBufDbl(  8, data_record, &dlon );
     alon = (float) dlon;
     rc = nc_put_vara_float( ncid, windLon_id, (const size_t *) start,
                             (const size_t *) count, (const float *) &alon);

     /* DIR */
     rc = McPtBufInt(  9, data_record, &dir );
     rc = nc_put_vara_int( ncid, windDir_id, (const size_t *) start,
                           (const size_t *) count, (const int *) &dir);

     /* SPD */
     rc = McPtBufDbl( 10, data_record, &dspd );
     aspd = (float) dspd;
     rc = nc_put_vara_float( ncid, windSpeed_id, (const size_t *) start,
                             (const size_t *) count, (const float *) &aspd);

     /* PW */
     rc = McPtBufInt( 11, data_record, &pw );
     rc = nc_put_vara_int( ncid, windPress_id, (const size_t *) start,
                           (const size_t *) count, (const int *) &pw);

     /* TC */
     rc = McPtBufDbl( 12, data_record, &dtc );
     atc = (float) dtc;
     rc = nc_put_vara_float( ncid, cloudTemp_id, (const size_t *) start,
                             (const size_t *) count, (const float *) &atc);

     /* CH */
     if ( ch ) free( ch );
     rc = McPtBufStr( 13, data_record, &ch );
     scount[1] = strlen( ch ) + 1;
     rc = nc_put_vara_text( ncid, hgtAssignMethod_id, (const size_t *) sstart,
                            (const size_t *) scount, (const char *) ch);

     start[0]  += 1;
     sstart[0] += 1;

     Mcdprintf( "%6d %6d %4s %4s %3d %4d %4s  %6.2f %7.2f %3d %5.2f %3d %6.2f 
%4s\n",
                 day1, hms1, satd, prod, sid, flag, type, alat, alon, dir, aspd,
                 pw, atc, ch );
   }

   /*
   ** Done writing, close the netCDF.
   */

   stat = nc_close(ncid);
   check_err(stat,__LINE__,__FILE__);

   /*
   ** Announce end of program
   */

   Mcprintf( "SWND2CDF: %d data records written to %s\n", start[0], cdfname );
   Mcprintf( "SWND2CDF: End\n" );

   return 0;
}

------ snip --------- satwinds.c --------------------------------------------

This code gets compiled with the following (from Sun Solaris SPARC using
SC5.0 C and Fortran compilers):

cc -c -I. -I../netcdf/libsrc -I/usr/dt/include -I/usr/openwin/include swnd2cdf.c

f77 -o swnd2cdf.k swnd2cdf.o -L. -L../netcdf/libsrc -R/usr/dt/lib -L/usr/dt/lib 
-R/usr/openwin/lib -L/usr/openwin/lib -R/opt/SUNWspro/lib -L/opt/SUNWspro/lib 
-lmcidas -lnetcdf -lgen -lsocket -lnsl -lm

Please let me know if you have questions.

Tom

>From address@hidden Mon Nov  5 07:31:32 2001
>Subject: Re: 20011102: satellite winds to netCDF converter

Many thanks, Tom!  I haven't had time to look this over yet, but we'll have at 
it some time this week.

-- G