[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
20011102: satellite winds to netCDF converter
- Subject: 20011102: satellite winds to netCDF converter
- Date: Fri, 02 Nov 2001 15:49:15 -0700
>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( ¤t_day, ¤t_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