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

[netCDF #YFO-861586]: nc_inq crashes



Yes, attached is the modified program. One gotcha-
I used a local .nc file since I did not have your original file.

=Dennis Heimbigner
  Unidata


Ticket Details
===================
Ticket ID: YFO-861586
Department: Support netCDF
Priority: Normal
Status: Open
===================
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.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#include <string.h>

#include "netcdf.h"
#if 0
#include "hdf.h"
#include "mfhdf.h"
#else
#define int32 int
#define int16 short
#endif

/* Defines for processing */
#define CLIMATE_NDIMS 3
#define CLIMATE_NVARS 4
#define CLIMATE_XDIM_NAME "lon"
#define CLIMATE_YDIM_NAME "lat"
#define CLIMATE_TDIM_NAME "time"

/* Prototypes for accessory functions */
int copy_sds (int ncid, int nvars, size_t dimsizes[], char *var_name,
    int32 first_time_index, int32 sdout_id, int verbose);
int get_size (nc_type data_type);
char *get_dt_string (nc_type data_type);
int32 get_hdf_dt (nc_type data_type);


/******************************************************************************
METHOD: main

PURPOSE: Handles the end to end processing of the annual NCEP input files and
repackages them to output daily HDF files (for the user-specified DOY),
containing multiple NCEP variables (air temp, precipitable water,
surface pressure).  Global attributes are copied to the new HDF file.  The
lat/long dimensions are also copied, along with their attributes.

RETURN VALUE:
Type = int
Value  Description
-----  -----------
-1     Error processing
-99    Error reading the input NCEP file
0      Successful processing

HISTORY:
Date        Programmer       Reason
----------  ---------------  -------------------------------------
10/27/2014  Gail Schmidt     Modified original application to read the new
                             netCDF4 files (vs. netCDF3 files) from NOAA/NCEP.
                             Modifications also included the need to handle
                             new data types for the NCEP variables.

NOTES:
******************************************************************************/
int main(int argc,char **argv) {
    int32 sdout_id;          /* HDF ID for output file */
    int verbose;             /* should status messages be written? */
    int index;               /* index for variables and attributes */
    size_t start[MAX_VAR_DIMS], cnt[MAX_VAR_DIMS];
    int32 first_time_index;  /* location in the time dimension for the 3D
                                variable to start reading (-1 if this isn't
                                one of the 3D variables) */
    char name[MAX_NC_NAME];  /* attribute name */
    void *buffer = NULL;     /* buffer for reading attribute values */
    double *timebuff = NULL; /* array of time values */
    int write_metadata;      /* should the global metadata and lat/long
                                dimensions be written to the output HDF file? */
    int doy;                 /* DOY for the current run */
    int base_date[3];        /* base date for NCEP file (year, month, day) */

    /* netCDF input vars */
    char varname[MAX_NC_NAME+1]; /* var names as read from netCDF file */
    char dimname[MAX_NC_NAME+1]; /* dim names as read from netCDF file */
    int ncid;                /* netCDF ID */
    int ndims;               /* number of input dimensions in netCDF file */
    int nvars;               /* number of variables in the netCDF file */
    int primary_index;       /* index of the primary variable (time) */
    int nb_globattrs;        /* number of global attributes in netCDF file */
    int var_ndims;           /* num dims for each var */
    int var_dimids[MAX_VAR_DIMS]; /* array for the dimension IDs */
    int var_natts;           /* number of var attributes */
    nc_type data_type;       /* data type for each variable */
    size_t dimsizes[MAX_VAR_DIMS]; /* dimension sizes */
    size_t count;            /* count of the attributes */

    if (argc != 4) {
        fprintf (stderr, "usage: %s <input> <output> <doy>\n", argv[0]);
        exit(-1);
    }
    verbose = 1;

/****
    open input netCDF4 file
****/
    if (nc_open (argv[1], NC_NOWRITE, &ncid)) {
        fprintf (stderr, "Error opening netCDF file: %s\n", argv[1]);
        exit(-99);
    }

/****
    check and open output, if the file doesn't exist then create it and
    set the write metadata flag so that the file attributes and lat/long
    dimensions are written
****/
    write_metadata = 0;
    sdout_id = 0;
#if 0
    if ((sdout_id = SDstart(argv[2], DFACC_RDONLY)) < 0) {
        if ((sdout_id = SDstart(argv[2], DFACC_CREATE)) < 0) {
           fprintf (stderr, "can't create output %s\n", argv[2]);
           exit(-1);
        }
        write_metadata = 1;
    } else {
        SDend (sdout_id);
        if ((sdout_id = SDstart (argv[2], DFACC_WRITE)) < 0) {
           fprintf (stderr, "can't open output %s\n", argv[2]);
           exit(-1);
        }
    }
    doy = (int16) atoi (argv[3]);        
#endif
    doy = 0;
    
/****
    determine how many netCDF variables, dimensions, and global attributes
    are in the file; also the dimension id of the unlimited dimension, if
    there is one.
****/
    if (nc_inq (ncid, &ndims, &nvars, &nb_globattrs, NULL)) {
        fprintf (stderr, "Error inquiring about the variables, dimensions, "
            "global attributes, etc. for the netCDF file: %s\n", argv[1]);
        exit(-1);
    }

    if (verbose) {
        printf ("Number of global attributes = %d\n",nb_globattrs);
        printf ("Number of variables = %d\n", nvars);
        printf ("Number of dimensions = %d\n", ndims);
    }

/****
    Get information about each of the dimensions
****/
    for (index = 0; index < ndims; index++) {
        if (nc_inq_dim (ncid, index, dimname, &dimsizes[index])) {
            fprintf (stderr, "Error inquiring about dimension %d", index);
            exit(-1);
        }
        printf ("Dimension %d: %s - %d\n", index, dimname,
            (int) dimsizes[index]);
    }

/****
    Copy global attributes and lat/long dimensions to output if creating
    a new file
****/
    if (write_metadata) {
        for (index = 0; index < nb_globattrs; index++) {
            if (nc_inq_attname (ncid, NC_GLOBAL, index, name)) {
                fprintf (stderr, "Error inquiring about global attribute "
                    "%d (0-based)\n", index);
                exit(-1);
            }

            if (nc_inq_att (ncid, NC_GLOBAL, name, &data_type, &count) == -1) {
                fprintf (stderr, "Error inquiring about global attribute "
                    "%s\n", name);
                exit(-1);
            }

#ifdef DEBUG
            if (verbose)
                printf ("attribute #%d = %s (%s - %d bytes) size = %d\n",
                    index, name, get_dt_string (data_type),
                    get_size (data_type), (int) count);
#endif

            /* Allocate a buffer to hold the attribute data. */
            buffer = malloc ((int) count * get_size(data_type));
            if (buffer == NULL) {
                fprintf (stderr, "Error allocating memory for global attr "
                    "%s\n", name);
                exit(-1);
            }

            /* Read the attribute data. */
            if (nc_get_att (ncid, NC_GLOBAL, name, buffer) != NC_NOERR) {
                fprintf (stderr, "Error getting global attribute %s\n", name);
                exit(-1);
            }

            /* Write the attribute data. */
#if 0
            if (SDsetattr (sdout_id, name, get_hdf_dt (data_type), (int) count,
                buffer) < 0) {
                fprintf (stderr, "Error writing global attribute %s\n", name);
                exit(-1);
            }
#endif
            /* Free buffer */
            free (buffer);
        } /* end for */

        /* Get information about the variables in the file */
        primary_index = -1;     /* initialize index to invalid value */
        for (index = 0; index < nvars; index++) {
            if (nc_inq_var (ncid, index, varname, &data_type, &var_ndims,
                var_dimids, &var_natts)) {
                fprintf (stderr, "Error inquiring about variable %d\n", index);
                exit(-1);
            }

            if (verbose) {
                printf ("Variable %d: %s\n", index, varname);
                printf ("  ndims - %d\n", var_ndims); 
                printf ("  natts - %d\n", var_natts); 
            }

            /* If this variable is the time variable, then store the index */
            if (!strcmp (varname, CLIMATE_TDIM_NAME))
                primary_index = index;
        }

        /* Make sure the "time" variable was found */
        if (primary_index == -1) {
            fprintf (stderr, "%s variable was not found in the netCDF "
                "dataset.\n", CLIMATE_TDIM_NAME);
            exit(-1);
        }

/****
        Determine the base_date of this file by reading the time variable
        this is a double variable.
****/
        if (nc_inq_var (ncid, primary_index, varname, &data_type, &var_ndims,
            var_dimids, &var_natts)) {
            fprintf (stderr, "Error inquiring about variable %d\n",
                primary_index);
            exit(-1);
        }
        if (data_type != NC_DOUBLE) {
            fprintf (stderr, "Error: the %s variable is expected to be "
                "a double, but it's %s\n", CLIMATE_TDIM_NAME,
                get_dt_string (data_type));
            exit(-1);
        }

        timebuff = malloc (dimsizes[var_dimids[0]] * sizeof (double));
        if (timebuff == NULL) {
            fprintf (stderr, "Error allocating memory for timebuff\n");
            exit(-1);
        }

        start[0] = 0;
        cnt[0] = var_dimids[0];
        if (nc_get_vara_double (ncid, primary_index, start, cnt, timebuff)) {
            fprintf (stderr, "Error reading data from %s variable\n",
                CLIMATE_TDIM_NAME);
            exit(-1);
        }

        /* compute the year using the first time value in the file; these
           values represent hours since 1800-01-01 00:00:0.0 */
        base_date[0] = (int16) (timebuff[0] / 8765.81277) + 1800;
        printf ("year %d\n", base_date[0]);
        base_date[1] = 1;
        base_date[2] = 1;

/****
        Write base_date and Day Of Year to output
****/
#if 0
        if (SDsetattr (sdout_id, "base_date", DFNT_INT16, 3, &base_date) < 0) {
            fprintf (stderr, "Error writing global attribute base_date\n");
            exit(-1);
        }
        if (SDsetattr (sdout_id, "Day Of Year", DFNT_INT16, 1, &doy) < 0) {
            fprintf (stderr, "Error writing global attribute Day of Year\n");
            exit(-1);
        }
#endif
        
/****
        Copy lat/lon SDS
****/
#if 0
        if (copy_sds (ncid, nvars, dimsizes, CLIMATE_YDIM_NAME, -1, sdout_id,
            verbose)) {
            fprintf (stderr, "ERROR: couldn't copy SDS %s ... ABORT\n",
                CLIMATE_YDIM_NAME);
            exit(-1);
        }

        if (copy_sds (ncid, nvars, dimsizes, CLIMATE_XDIM_NAME, -1, sdout_id,
            verbose)) {
            fprintf (stderr, "ERROR: couldn't copy SDS %s ... ABORT\n",
                CLIMATE_XDIM_NAME);
            exit(-1);
        }        
#endif
    }  /* end write metadata */

    if (verbose)      
        printf ("Number of variables = %d\n", nvars);

/****
    Loop over variables, get name and number of attributes for each one
****/
    for (index = 0; index < nvars; index++) {
        if (nc_inq_var (ncid, index, varname, &data_type, &var_ndims,
            var_dimids, &var_natts)) {
            fprintf (stderr, "Error inquiring about variable %d\n", index);
            exit(-1);
        }

        if (!strcmp (varname, "pres") || !strcmp (varname, "pr_wtr") ||
            !strcmp (varname, "slp") || !strcmp (varname, "air")) {
            if (verbose) {
                printf ("SDS #%d = %s (%s - %d bytes) Rank = %d "
                    "Nb Attrs = %d\n", index, varname,
                    get_dt_string (data_type), get_size (data_type),
                    var_ndims, var_natts);

                printf("\tDims = ");
                for (index = 0; index < var_ndims; index++) {
                    if (index == 0)
                        printf ("%d", (int) dimsizes[var_dimids[index]]);
                    else
                        printf ("x%d", (int) dimsizes[var_dimids[index]]);
                }
                printf ("\n");
            }

            /* Copy this SDS, starting at the specified index position within
               the netCDF file for the time dimension */
            first_time_index = (doy - 1) * 4;
            if (copy_sds (ncid, nvars, dimsizes, varname, first_time_index,
                sdout_id, verbose)) {
                fprintf (stderr, "ERROR: couldn't copy SDS %s ... ABORT\n",
                    varname);
                exit(-1);
            }        
        }
    }  /* end for */

/****
    Close input & output
****/
    nc_close (ncid);
#if 0
    SDend (sdout_id);
#endif
    return 0;
}   


/******************************************************************************
METHOD: copy_sds

PURPOSE: Copies the specified netCDF variable to the output HDF file as a
new SDS.  Copies the attributes to the SDS as well as sets the dimension
names.

RETURN VALUE:
Type = int
Value  Description
-----  -----------
-1     Error processing
0      Successful processing

HISTORY:
Date        Programmer       Reason
----------  ---------------  -------------------------------------
10/27/2014  Gail Schmidt     Modified original application to read the new
                             netCDF4 files (vs. netCDF3 files) from NOAA/NCEP.
                             Modifications also included the need to handle
                             new data types for the NCEP variables.
11/13/2014  Gail Schmidt     Added a check to the variable data type to make
                             sure it is a floating point, just to make sure the
                             old NCEP int16 products aren't being processed.

NOTES:
1. The NCEP variables are global datasets.  The starting point for the
   longitudinal values is 0 degrees.  The output HDF files need these variables
   to start at -180.  So, some minor data manipulation is done after reading
   the NCEP variables and before writing them to the output HDF file.
******************************************************************************/
int copy_sds
(
    int ncid,                 /* I: netCDF file ID for input */
    int nvars,                /* I: number of variables in netCDF file */
    size_t dimsizes[],        /* I: dimension sizes for netCDF file */
    char *var_name,           /* I: name of the variable to be copied to the
                                    output file */
    int32 first_time_index,   /* I: location in the time dimension for the 3D
                                    variable to start reading */
    int32 sdout_id,           /* I: HDF file ID for output */
    int verbose               /* I: should status messages be written? */
)
{
    int32 sdsout_id, start_hdf[MAX_VAR_DIMS], edge_hdf[MAX_VAR_DIMS];
    int32 dimout_id;
    int32 hdf_dim_sizes[MAX_VAR_DIMS];
    int buf_size;
    int il;

    int index;               /* index for variables and attributes */
    size_t start[MAX_VAR_DIMS], cnt[MAX_VAR_DIMS];
    char name[MAX_NC_NAME];  /* attribute name */
    char *buffer = NULL;     /* buffer for reading attribute values */
    char *oneline = NULL;    /* one line of input data */

    /* netCDF input vars */
    char varname[MAX_NC_NAME+1]; /* var names as read from netCDF file */
    int primary_index;       /* index of the primary variable (time) */
    int var_ndims;           /* num dims for each var */
    int var_dimids[MAX_VAR_DIMS]; /* array for the dimension IDs */
    int var_natts;           /* number of var attributes */
    nc_type data_type;       /* data type for each variable */
    size_t count;            /* count of the attributes */

    /* Get information about the variables in the file */
    primary_index = -1;     /* initialize index to invalid value */
    for (index = 0; index < nvars; index++) {
        if (nc_inq_var (ncid, index, varname, &data_type, &var_ndims,
            var_dimids, &var_natts)) {
            fprintf (stderr, "Error inquiring about variable %d\n", index);
            return (-1);
        }

        /* If this variable is the specified variable, then store the index */
        if (!strcmp (varname, var_name)) {
            primary_index = index;
            break;
        }
    }

    /* Make sure the variable was found */
    if (primary_index == -1) {
        fprintf (stderr, "%s variable was not found in the netCDF "
            "dataset.\n", var_name);
        return (-1);
    }

    /* If this is not one of the lat/long dimensions, then it's our NCEP
       variable.  In that case, we need to make sure this is a floating point
       data type and not int16 as the previous NCEP products were. */
    if (strcmp (var_name, CLIMATE_XDIM_NAME) &&
        strcmp (var_name, CLIMATE_YDIM_NAME) && 
        strcmp (var_name, CLIMATE_TDIM_NAME)) {
        if (data_type != NC_FLOAT) {
            fprintf (stderr, "Error: Non-dimensional variable (%s) should be "
                "floating point.\n", var_name);
            return -1;
        }
    }

    /* Set up the dimensions of the output HDF SDS */
    for (index = 0; index < var_ndims; index++)
        hdf_dim_sizes[index] = dimsizes[var_dimids[index]];

    /* If this is not one of the lat/long dimensions, then it's our NCEP
       variable.  In that case, we are only pulling data for the current DOY
       which is 4 values which represent data once every 6 hours. */
    if (strcmp (var_name, CLIMATE_XDIM_NAME) &&
        strcmp (var_name, CLIMATE_YDIM_NAME) && 
        strcmp (var_name, CLIMATE_TDIM_NAME))
        hdf_dim_sizes[0] = 4; 

    /* Create an SDS in the output file for this variable */
#if 0
    if ((sdsout_id = SDcreate (sdout_id, var_name, get_hdf_dt (data_type),
        var_ndims, hdf_dim_sizes)) < 0) {
        fprintf (stderr, "Error creating SDS in output HDF file for %s\n",
            var_name);
        return -1;
    }
#endif
    
/****
    Read and write the data.  Dimensions get read and written in whole.
    The NCEP variables only read and write the four hours pertaining to the
    specified DOY.
****/
    if (first_time_index < 0) {
        /* Determine the size of the buffer needed for all the dimensions
           and data type */
        buf_size = 1;
        for (index = 0; index < var_ndims; index++) {
            buf_size *= hdf_dim_sizes[index];
            start[index] = 0;
            start_hdf[index] = 0;
            cnt[index] = hdf_dim_sizes[index];
            edge_hdf[index] = hdf_dim_sizes[index];
        }
        buf_size *= get_size (data_type);

        /* Allocate memory */
        buffer = malloc (buf_size);
        if (buffer == NULL) {
            fprintf (stderr, "Error allocating memory for %s\n", var_name);
            return (-1);
        }

        /* Read the data from the netCDF file */
        if (nc_get_vara (ncid, primary_index, start, cnt, buffer)) {
            fprintf (stderr, "Error reading data from %s variable\n", var_name);
            return (-1);
        }

        /* Write the data to the HDF file */
#if 0
        if (SDwritedata (sdsout_id, start_hdf, NULL, edge_hdf, buffer) < 0) {
            fprintf (stderr, "Error writing %s data to SDS\n", var_name);
            return (-1);
        }
#endif

        /* Free the memory */
        free(buffer);
    } else {
        /* Determine the size of the buffer needed for the lat/long dimensions
           and data type */
        buf_size = hdf_dim_sizes[1] * hdf_dim_sizes[2] * get_size (data_type);

        /* Allocate memory */
        buffer = malloc (buf_size);
        if (buffer == NULL) {
            fprintf (stderr, "Error allocating memory for %s\n", var_name);
            return (-1);
        }

        /* Allocate memory for one line */
        oneline = malloc (hdf_dim_sizes[2] * get_size (data_type));
        if (oneline == NULL) {
            fprintf (stderr, "Error allocating memory for %s\n", var_name);
            return (-1);
        }

        /* Set up the start and edge arrays for reading and writing one line
           of time data at a time */
        start[0] = first_time_index;
        start_hdf[0] = 0;
        cnt[0] = 1;
        edge_hdf[0] = 1;
        start[1] = 0;
        start_hdf[1] = 0;
        cnt[1] = hdf_dim_sizes[1];
        edge_hdf[1] = hdf_dim_sizes[1];
        start[2] = 0;
        start_hdf[2] = 0;
        cnt[2] = hdf_dim_sizes[2];
        edge_hdf[2] = hdf_dim_sizes[2];

        /* Loop through the four time datasets for the specified DOY, using
           the first_time_index as the start of the current DOY */
        for (index = 0; index < 4; index++) {
            /* Read the data from the netCDF file */
            if (nc_get_vara (ncid, primary_index, start, cnt, buffer)) {
                fprintf (stderr, "Error reading data from %s variable for time "
                    "%d\n", var_name, index);
                return (-1);
            }

            /* Rearrange the NCEP variable data values since they start at
               0 degrees and we want to write the global values starting at
               -180 degrees */
            for (il = 0; il < hdf_dim_sizes[1]; il++) {
                memcpy (oneline,
                   
&buffer[(il*hdf_dim_sizes[2]+hdf_dim_sizes[2]/2)*get_size(data_type)],
                   (hdf_dim_sizes[2]/2)*get_size(data_type));

                memcpy(&oneline[(hdf_dim_sizes[2]/2)*get_size(data_type)],
                    &buffer[il*hdf_dim_sizes[2]*get_size(data_type)],
                    (hdf_dim_sizes[2]-hdf_dim_sizes[2]/2)*get_size(data_type));

                memcpy(&buffer[il*hdf_dim_sizes[2]*get_size(data_type)],
                    oneline, hdf_dim_sizes[2]*get_size(data_type));
            }

            /* Write the data to the HDF file */
#if 0
            if (SDwritedata (sdsout_id, start_hdf, NULL, edge_hdf, buffer)
                < 0) {
                fprintf (stderr, "Error writing %s data to SDS\n", var_name);
                return (-1);
            }
#endif
            /* Increment the start pointers for time dimension */
            start[0]++;
            start_hdf[0]++;
        }

        /* Free the memory */
        free (buffer);
        free (oneline);
    }

/****
    Loop over SDS attributes and copy
****/
    for (index = 0; index < var_natts; index++) {
        if (nc_inq_attname (ncid, primary_index, index, name)) {
            fprintf (stderr, "Error inquiring about variable attribute %d "
                "(0-based)\n", index);
            return (-1);
        }

        if (nc_inq_att (ncid, primary_index, name, &data_type, &count) == -1) {
            fprintf (stderr, "Error inquiring about variable attribute %s\n",
                name);
            return (-1);
        }

#ifdef DEBUG
        if (verbose)
            printf ("attribute #%d = %s (%s - %d bytes) size = %d\n",
                index, name, get_dt_string (data_type),
                get_size (data_type), (int) count);
#endif

        /* Allocate a buffer to hold the attribute data. */
        buffer = malloc ((int) count * get_size(data_type));
        if (buffer == NULL) {
            fprintf (stderr, "Error allocating memory for attr %s\n", name);
            return (-1);
        }

        /* Read the attribute data. */
        if (nc_get_att (ncid, primary_index, name, buffer) != NC_NOERR) {
            fprintf (stderr, "Error getting variable attribute %s\n", name);
            return (-1);
        }

#if 0
        /* Write the attribute data. */
        if (SDsetattr (sdsout_id, name, get_hdf_dt (data_type), (int) count,
            buffer) < 0) {
            fprintf (stderr, "Error writing SDS attribute %s\n", name);
            return (-1);
        }
#endif
        /* Free buffer */
        free (buffer);
    } /* end for */

/****
    Set the SDS dimensions.  The XDIM, YDIM, and TDIM variables are 1D.
    The others are 3D.
****/
#if 0
    if (!strcmp (var_name, CLIMATE_XDIM_NAME)) {
        dimout_id = SDgetdimid (sdsout_id, 0);
        SDsetdimname (dimout_id, CLIMATE_XDIM_NAME); 
    }
    else if (!strcmp (var_name, CLIMATE_YDIM_NAME)) {
        dimout_id = SDgetdimid (sdsout_id, 0);
        SDsetdimname (dimout_id, CLIMATE_YDIM_NAME); 
    }
    else if (!strcmp (var_name, CLIMATE_TDIM_NAME)) {
        dimout_id = SDgetdimid (sdsout_id, 0);
        SDsetdimname (dimout_id, CLIMATE_TDIM_NAME); 
    }
    else {
        dimout_id = SDgetdimid (sdsout_id, 0);
        SDsetdimname (dimout_id, CLIMATE_TDIM_NAME); 
        dimout_id = SDgetdimid (sdsout_id, 1);
        SDsetdimname (dimout_id, CLIMATE_YDIM_NAME); 
        dimout_id = SDgetdimid (sdsout_id, 2);
        SDsetdimname (dimout_id, CLIMATE_XDIM_NAME); 
    }
#endif
/****
    Close SDS
****/
#if 0
    SDendaccess(sdsout_id);
#endif
    return 0;
}


/******************************************************************************
METHOD: get_size

PURPOSE: Determine the size (in bytes) of the netCDF data type specified

RETURN VALUE:
Type = int
Value  Description
-----  -----------
-99    Data type isn't supported or it was NAT (Not a Type)
Else   Size of the dataype (in bytes)

HISTORY:
Date        Programmer       Reason
----------  ---------------  -------------------------------------
10/27/2014  Gail Schmidt     Original development

NOTES:
******************************************************************************/
int get_size
(
    nc_type data_type       /* I: netCDF data type for each variable */
)
{
    switch (data_type)
    {
        case NC_BYTE:
        case NC_UBYTE:
        case NC_CHAR:
            return 1;

        case NC_SHORT:
        case NC_USHORT:
            return 2;

        case NC_INT:   /* covers NC_LONG which is deprecated */
        case NC_UINT:
            return 4;

        case NC_INT64:
        case NC_UINT64:
            return 8;

        case NC_FLOAT:
            return 4;

        case NC_DOUBLE:
            return 8;

        default:
            return -99;
    }
}


/******************************************************************************
METHOD: get_size

PURPOSE: Determine the data type string of the netCDF data type specified

RETURN VALUE:
Type = int
Value                    Description
-----                    -----------
"Unsupported data type"  Data type not supported
Else                     String for the input data type

HISTORY:
Date        Programmer       Reason
----------  ---------------  -------------------------------------
10/27/2014  Gail Schmidt     Original development

NOTES:
******************************************************************************/
char *get_dt_string
(
    nc_type data_type       /* I: netCDF data type for each variable */
)
{
    switch (data_type)
    {
        case NC_BYTE:
            return "NC_BYTE";
        case NC_UBYTE:
            return "NC_UBYTE";
        case NC_CHAR:
            return "NC_CHAR";
        case NC_SHORT:
            return "NC_SHORT";
        case NC_USHORT:
            return "NC_USHORT";
        case NC_INT:   /* covers NC_LONG which is deprecated */
            return "NC_INT";
        case NC_UINT:
            return "NC_UINT";
        case NC_INT64:
            return "NC_INT64";
        case NC_UINT64:
            return "NC_UINT64";
        case NC_FLOAT:
            return "NC_FLOAT";
        case NC_DOUBLE:
            return "NC_DOUBLE";
        case NC_NAT:
            return "NC_NAT";
        default:
            return "Unsupported data type";
    }
}


/******************************************************************************
METHOD: get_size

PURPOSE: Determine the HDF data type for the netCDF data type specified

RETURN VALUE:
Type = int
Value  Description
-----  -----------
-99    Data type isn't supported or it was NAT (Not a Type)
Else   HDF data type

HISTORY:
Date        Programmer       Reason
----------  ---------------  -------------------------------------
10/27/2014  Gail Schmidt     Original development

NOTES:
******************************************************************************/
int32 get_hdf_dt
(
    nc_type data_type       /* I: netCDF data type for each variable */
)
{
    switch (data_type)
    {
        case NC_BYTE:
            return NC_BYTE;
        case NC_UBYTE:
            return NC_UBYTE;
        case NC_CHAR:
            return NC_CHAR;
        case NC_SHORT:
            return NC_SHORT;
        case NC_USHORT:
            return NC_USHORT;
        case NC_INT:   /* covers NC_LONG which is deprecated */
            return NC_INT;
        case NC_UINT:
            return NC_UINT;
        case NC_INT64:
            return NC_INT64;
        case NC_UINT64:
            return NC_UINT64;
        case NC_FLOAT:
            return NC_FLOAT;
        case NC_DOUBLE:
            return NC_DOUBLE;
        default:
            return -99;
    }
}