[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

NOTE: All email exchanges with Unidata User Support are recorded in the Unidata inquiry tracking system and then made publicly available through the web. If you do not want to have your interactions made available in this way, you must let us know in each email you send to us.