/* iapi.c */ /* * Vis5D system for visualizing five dimensional gridded data sets. * Copyright (C) 1990 - 2000 Bill Hibbard, Johan Kellum, Brian Paul, * Dave Santek, and Andre Battaiola. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * As a special exception to the terms of the GNU General Public * License, you are permitted to link Vis5D with (and distribute the * resulting source and executables) the LUI library (copyright by * Stellar Computer Inc. and licensed for distribution with Vis5D), * the McIDAS library, and/or the NetCDF library, where those * libraries are governed by the terms of their own licenses. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "../config.h" /***************************************************************/ /***************************************************************/ /* This file contains a set of functions that will act as an */ /* interface for reading and obtaining various nessecary info */ /* about a NetCDF file. */ /* The functions in 'file.c' will use these. */ /***************************************************************/ /***************************************************************/ #include #include #include #include #ifdef HAVE_LIBNETCDF #ifdef HAVE_NETCDF_H # include #else # include "netcdf.h" #endif #include "iapi.h" #include "igui.h" NetCDF_Format_Info UNIDATA_METAR; NetCDF_Format_Info FSL_METAR; NetCDF_Format_Info FSL_PROFILE; /************************/ /* Close a NetCDF file */ /************************/ /* Input: fid - File ID */ /************************/ int Close_NetCDF( int fid ) { int status; status = nc_close(fid); if (status != NC_NOERR){ return 0; } return 1; } /*****************************************************/ /* This will initialize the structures which contain */ /* the needed information, such as var names, for the*/ /* different NetCDF file types */ /* When adding the ability to read more NetCDF files */ /* more formats will have to be added here */ /*****************************************************/ void Initialize_NetCDF_Format_Info( void ) { /************************************************/ /* go through the list of formats and init them */ /************************************************/ /*************/ /* FSL_METAR */ /*************/ FSL_METAR = (NetCDF_Format_Info) calloc( 1, sizeof(struct netcdf_format_info)); if (!FSL_METAR){ printf("Error in creating FSL_METAR struct\n"); exit(0); } { strcpy(FSL_METAR->METAR_REPORT_TYPE_LENGTH, "maxRepLen"); strcpy(FSL_METAR->METAR_CLD_LAYERS, "maxSkyCover"); strcpy(FSL_METAR->METAR_REPORT_TYPE, "reportType"); strcpy(FSL_METAR->TIME, "timeNominal"); strcpy(FSL_METAR->LAT, "latitude"); strcpy(FSL_METAR->LON, "longitude"); strcpy(FSL_METAR->HGT, "elevation"); strcpy(FSL_METAR->METAR_CLD_TYPE, "skyCover"); strcpy(FSL_METAR->METAR, "METAR"); strcpy(FSL_METAR->SPECI, "SPECI"); strcpy(FSL_METAR->REC_NUM, "recNum"); strcpy(FSL_METAR->LOCATION_FILL, "_FillValue"); } /*****************/ /* UNIDATA_METAR */ /*****************/ UNIDATA_METAR = (NetCDF_Format_Info) calloc( 1, sizeof(struct netcdf_format_info)); if (!UNIDATA_METAR){ printf("Error in creating UNIDATA_METAR struct\n"); exit(0); } { strcpy(UNIDATA_METAR->METAR_REPORT_TYPE_LENGTH, "rep_type_len"); strcpy(UNIDATA_METAR->METAR_CLD_LAYERS, "cloud_layers"); strcpy(UNIDATA_METAR->METAR_REPORT_TYPE, "rep_type"); strcpy(UNIDATA_METAR->TIME, "time_nominal"); strcpy(UNIDATA_METAR->LAT, "lat"); strcpy(UNIDATA_METAR->LON, "lon"); strcpy(UNIDATA_METAR->HGT, "elev"); strcpy(UNIDATA_METAR->METAR_CLD_TYPE, "cloud_type"); strcpy(UNIDATA_METAR->METAR, "METAR"); strcpy(UNIDATA_METAR->SPECI, "SPECI"); strcpy(UNIDATA_METAR->REC_NUM, "recNum"); strcpy(UNIDATA_METAR->LOCATION_FILL, "_FillValue"); } /***************/ /* FSL PROFILE */ /***************/ FSL_PROFILE = (NetCDF_Format_Info) calloc( 1, sizeof(struct netcdf_format_info)); if (!FSL_PROFILE){ printf("Error in creating FSL_PROFILEstruct\n"); exit(0); } { strcpy(FSL_PROFILE->LEVELDIM, "level"); strcpy(FSL_PROFILE->LEVELVAR, "levels"); strcpy(FSL_PROFILE->LAT, "staLat"); strcpy(FSL_PROFILE->LON, "staLon"); strcpy(FSL_PROFILE->HGT, "staElev"); strcpy(FSL_PROFILE->TIME, "timeObs"); strcpy(FSL_PROFILE->REC_NUM, "recNum"); strcpy(FSL_PROFILE->LOCATION_FILL, "_FillValue"); } } /****************************************************/ /* This helper function goes through a list of data */ /* and finds the min and max values, and disregards */ /* any values matching fillvalue */ /****************************************************/ /* Input: numdata - the size of the data array */ /* data - array containing the number data */ /* fillvalue - values which are considered */ /* missing */ /* Output: min, max - the min and max values */ /****************************************************/ void get_min_and_max( int numdata, double *data, double fillvalue, double *min, double *max) { int i, j; double tmin, tmax; /*************************************/ /* first get first min and max since */ /* first data value may be fillvalue */ /*************************************/ j = 0; do{ tmin = tmax = data[j]; j++; } while(tmin == fillvalue && j < numdata); for (i = j; i < numdata; i++){ if (data[i] != fillvalue){ if (data[i] < tmin){ tmin = data[i]; } else if (data[i] > tmax){ tmax = data[i]; } } } *min = tmin; *max = tmax; } /*************************************************/ /* This opens a NetCDF file and gets it's file ID*/ /*************************************************/ /* Input: filename - the name of the file to open*/ /* Output: fid - NetCDF file ID */ /*************************************************/ int Open_NetCDF( char *filename, int *fid ) { int status, nc_id; /********************************************/ /* open file and see if it is a netCDF file */ /********************************************/ status = nc_open( filename, NC_NOWRITE, &nc_id); if(status != NC_NOERR){ return 0; } *fid = nc_id; return 1; } /***************************************************/ /* This opens a NetCDF file and returns the type */ /* It is fairly general right now and may need to */ /* be altered when more types need to be */ /* distinguished */ /***************************************************/ /* Input: filename - the name of the file to open */ /* Output: general_type - one of NETCDF_SURFACE or */ /* NETCDF_SOUNDING */ /* specific_type- one of fsl_netcdf_metar */ /* fsl_netcdf_bouy */ /* fsl_netcdf_profile */ /* unidata_netcdf_metar */ /* unidata_netcdf_upperair */ /* fid - NetCDF file ID */ /***************************************************/ int Read_NetCDF( char *filename, int *general_type, int *specific_type, int *fid ) { int id1, id2; int status, status2, status3, status4; size_t len1; int nc_id; char *text1; *general_type = -1; *specific_type = -1; /********************************************/ /* open file and see if it is a netCDF file */ /********************************************/ status = nc_open( filename, NC_NOWRITE, &nc_id); if(status != NC_NOERR){ printf("Error: can't open netcdf file\n"); return 0; } *fid = nc_id; /****************************/ /* Try FSL_NETCDF_METAR 1st */ /****************************/ status = nc_inq_dimid( nc_id, FSL_METAR->METAR_REPORT_TYPE_LENGTH, &id1); if(status != NC_NOERR){ status = nc_inq_varid( nc_id, FSL_METAR->TIME, &id1); } if (status == NC_NOERR){ /* 28-10-2000 this test doesn't work on my my FSL-like synop files */ /* If you see some reason that this test should be required please contact me and I will happily seek to resolve the problem in a mutually suitable manner. Jim Edwards jedwards@fsl.noaa.gov jedwards@inmet.gov.br */ /* status = nc_inq_dimlen( nc_id, id1, &len1); if (status != NC_NOERR){ nc_close(nc_id); return 0; } status = nc_inq_varid( nc_id, FSL_METAR->METAR_REPORT_TYPE, &id2); if (status != NC_NOERR){ nc_close(nc_id); return 0; } text1 = (char *) malloc(len1+1); memset(text1, 0, len1+1); { size_t temp[] = {0,0}; int i; for (i = 0; i < len1; i++){ nc_get_var1_text(nc_id, id2, temp, &text1[i]); temp[1]++; } } if (strcmp(FSL_METAR->METAR, text1)==0 || strcmp(FSL_METAR->SPECI, text1)==0){ free(text1); */ *general_type = NETCDF_SURFACE; *specific_type = fsl_netcdf_metar; return 1; /* } else{ printf("Looks like an FSL type file but %s doesn't match %s or %s\n", text1, FSL_METAR->METAR, FSL_METAR->SPECI); free(text1); nc_close(nc_id); return 0; } */ } /*********************************/ /* Try UNIDATA_NETCDF_METAR next */ /*********************************/ status = nc_inq_dimid( nc_id, UNIDATA_METAR->METAR_REPORT_TYPE_LENGTH, &id1); if (status == NC_NOERR){ status = nc_inq_dimlen( nc_id, id1, &len1); if (status != NC_NOERR){ nc_close(nc_id); return 0; } status = nc_inq_varid( nc_id, UNIDATA_METAR->METAR_REPORT_TYPE, &id2); if (status != NC_NOERR){ nc_close(nc_id); return 0; } text1 = (char *) malloc(len1+1); memset(text1, 0, len1+1); { size_t temp[] = {0,0}; int i; for (i = 0; i < len1; i++){ nc_get_var1_text(nc_id, id2, temp, &text1[i]); temp[1]++; } } if (strcmp(UNIDATA_METAR->METAR, text1)==0 || strcmp(UNIDATA_METAR->SPECI, text1)==0){ free(text1); *general_type = NETCDF_SURFACE; *specific_type = unidata_netcdf_metar; return 1; } else{ free(text1); nc_close(nc_id); return 0; } } /**************************************/ /* now check to see if it's a PROFILE */ /**************************************/ /* for now the only way i'm assuming */ /* it's a wind profile file, is if its*/ /* got LEVELVAR as one of it's variables*/ /* this should change later */ /**************************************/ status = nc_inq_varid( nc_id, FSL_PROFILE->LEVELVAR, &id1); status2 = nc_inq_varid( nc_id, FSL_PROFILE->LAT, &id1); status3 = nc_inq_varid( nc_id, FSL_PROFILE->LON, &id1); status4 = nc_inq_varid( nc_id, FSL_PROFILE->HGT, &id1); if (status == NC_NOERR && status2 == NC_NOERR && status3== NC_NOERR && status4 == NC_NOERR){ *general_type = NETCDF_SOUNDING; *specific_type = fsl_netcdf_profile; return 1; } printf("Error: unrecognized file type\n"); return 0; } /***************************************************/ /* This reads a NetCDF location for a given record */ /***************************************************/ /* Input: finfo - the NetCDF format info */ /* nc_id - NetCDF file ID */ /* recid - Record number or ID for desired */ /* location */ /* Output: lat, lon, hgt - Latitude, Longitude and */ /* Altitude for record */ /***************************************************/ int Read_NetCDF_Location( NetCDF_Format_Info finfo, int nc_id, int recid, float *lat, float *lon, float *hgt) { int latid, lonid, hgtid; static size_t index[1]; int status; index[0] = recid; status = nc_inq_varid( nc_id, finfo->LAT, &latid); if(status != NC_NOERR){ printf("error in int Read_NetCDF_Location\n"); return 0; } status = nc_inq_varid( nc_id, finfo->LON, &lonid); if(status != NC_NOERR){ printf("error in int Read_NetCDF_Location\n"); return 0; } status = nc_inq_varid( nc_id, finfo->HGT, &hgtid); if(status != NC_NOERR){ printf("error in int Read_NetCDF_Location\n"); return 0; } status = nc_get_var1_float( nc_id, latid, index, lat); if(status != NC_NOERR){ printf("error in int Read_NetCDF_Location\n"); return 0; } status = nc_get_var1_float( nc_id, lonid, index, lon); if(status != NC_NOERR){ printf("error in int Read_NetCDF_Location\n"); return 0; } status = nc_get_var1_float( nc_id, hgtid, index, hgt); if(status != NC_NOERR){ printf("error in int Read_NetCDF_Location\n"); return 0; } return 1; } /****************************************************************/ /* This reads a 1 Dimensional interger value from a NetCDF file */ /****************************************************************/ /* Input: nc_id - NetCDF file ID */ /* recid - Record ID */ /* varid - Variable ID */ /* Output: data - the integer data */ /****************************************************************/ int Read_1D_NetCDF_Var_Int_Data( int nc_id, int recid, int varid, int *data) { static size_t index[1]; int status; index[0] = recid; status = nc_get_var1_int( nc_id, varid, index, data); if (status != NC_NOERR){ printf("error in int int Read_NetCDF_METAR_Var_int_Data\n"); return 0; } return 1; } /***************************************************/ /* This reads the sounding data from a NetCDF file */ /***************************************************/ /* Input: nc_id - NetCDF file ID */ /* recid - Record ID */ /* varid - Variable ID */ /* levels - the number of sounding levels */ /* Output: data - sounding data */ /***************************************************/ int Read_Sounding_NetCDF_Var_Data( int nc_id, int recid, int varid, int levels, double *data) { static size_t start[2], end[2]; int status; start[0] = recid; start[1] = 0; end[0] = 1; end[1] = levels; status = nc_get_vara_double(nc_id, varid, start, end, data); if (status != NC_NOERR){ printf("error in Read_Sounding_NetCDF_Var_Data\n"); return 0; } return 1; } /****************************************************************/ /* This Reads a 1 Dimensional double value from a NetCDF file */ /****************************************************************/ /* Input: nc_id - NetCDF file ID */ /* recid - Record ID */ /* varid - Variable ID */ /* Output: data - the double data */ /****************************************************************/ int Read_1D_NetCDF_Var_Double_Data( int nc_id, int recid, int varid, double *data) { static size_t index[1]; int status; index[0] = recid; status = nc_get_var1_double( nc_id, varid, index, data); if (status != NC_NOERR){ printf("error in int int Read_NetCDF_METAR_Var_Double_Data\n"); return 0; } return 1; } /****************************************************************/ /* This reads a 1 Dimensional string from a NetCDF file */ /****************************************************************/ /* Input: nc_id - NetCDF file ID */ /* recid - Record ID */ /* varid - Variable ID */ /* len - length of character string to be read */ /* Output: data - char data */ /****************************************************************/ int Read_1D_NetCDF_Var_Char_Data( int nc_id, int recid, int varid, int len, char *data) { size_t index[2]; int i; int status; index[0] = recid; index[1] = 0; for (i=0; iREC_NUM, &numrecsid); if(status != NC_NOERR){ return 0; } status = nc_inq_dimlen(nc_id, numrecsid, &numrecs); if(status != NC_NOERR){ return 0; } /*************/ /* get times */ /*************/ status = nc_inq_varid( nc_id, finfo->TIME, &tnid); if(status != NC_NOERR){ return 0; } times = (int *) malloc(sizeof(int)*numrecs); if (!times){ return 0; } status = nc_get_var_int( nc_id, tnid, times); if(status != NC_NOERR){ free(times); return 0; } /**********************************************/ /* get the station rec num matching the time */ /* assume no duplicates for now */ /**********************************************/ idcount = 0; for (i = 0; i < numrecs; i++){ if (times[i] == thetime){ ids[idcount] = i; idcount++; } } /* *rpt = idcount; for (i = idcount; i < num_ids; i++){ ids[i] = -1; } */ free(times); return 1; } /*********************************************************/ /* This will determine how many time steps there are and */ /* how many record for each time step. */ /*********************************************************/ /* Input: finfo - the NetCDF format info */ /* nc_id - the NetCDF file ID */ /* Output: num_times - the number of time steps for the */ /* file */ /* ts - array of time stamps,size [0..num_times] */ /* in HHMMSS */ /* ds - array of date stamps,size [0..num_times] */ /* in YYDDD */ /* time - array of times, size [ 0..num_times] */ /* is seconds since 1970-01-01 00 UTC */ /* trecs - array containing number of records */ /* per time step */ /*********************************************************/ int Read_NetCDF_Times_and_Recs( NetCDF_Format_Info finfo, int nc_id, int *num_times, int *ts, int *ds, int time[], int trecs[]) { int numrecsid; int nt, ntimes[MAXTIMES], uniquetimes[MAXTIMES]; int numuniquetimes; int status, tnid, *times, temp, i, j, t; int year, day, hour, minute, second; size_t numrecs; *num_times = 0; /*************************/ /* get number of records */ /*************************/ status = nc_inq_dimid(nc_id, finfo->REC_NUM, &numrecsid); if(status != NC_NOERR){ return 0; } status = nc_inq_dimlen(nc_id, numrecsid, &numrecs); if(status != NC_NOERR){ return 0; } /****************/ /* get numtimes */ /****************/ for (i = 0; i < MAXTIMES; i++){ uniquetimes[i] = -1; } status = nc_inq_varid( nc_id, finfo->TIME, &tnid); if(status != NC_NOERR){ return 0; } times = (int *) malloc(sizeof(int)*numrecs); if (!times){ return 0; } status = nc_get_var_int( nc_id, tnid, times); if(status != NC_NOERR){ free(times); return 0; } numuniquetimes = 1; uniquetimes[0] = times[0]; ntimes[0] = 1; for (i = 1; i < numrecs; i++){ for (j = 0; j < numuniquetimes; j++){ if (times[i] == uniquetimes[j]){ ntimes[j]++; break; } } if (j == numuniquetimes){ uniquetimes[j] = times[i]; ntimes[j] = 1; numuniquetimes++; } } *num_times = numuniquetimes; nt = numuniquetimes; /***********************************************/ /* get the largest number of record for a time */ /***********************************************/ /* nrecs = 0; for (i = 0; i < nt; i++){ if (ntimes[i] > nrecs){ nrecs = ntimes[i]; } } *mrecs = nrecs; */ /****************************/ /* bubble sort unique times */ /****************************/ for (i = 0; i < numuniquetimes; i++){ for (j = 0; j < numuniquetimes-1-i; j++){ if (uniquetimes[j+1] < uniquetimes[j]){ temp = uniquetimes[j]; uniquetimes[j] = uniquetimes[j+1]; uniquetimes[j+1] = temp; temp = ntimes[j]; ntimes[j] = ntimes[j+1]; ntimes[j+1] = temp; } } } for (i = 0; i < numuniquetimes; i++){ trecs[i] = ntimes[i]; } /***********************/ /* get day/time stamps */ /***********************/ for (i=0; i < nt; i++){ t = uniquetimes[i]; time[i] = t; day = t/86400; t -= 86400 * day; if (day > 730){ day -= 730; year = (4*day)/1461; day = day - (365*year+(year-1)/4); year += 72; } else{ year = day / 365; day = day - (365*year); } hour = t/3600; t -= 3600*hour; minute = t/60; t -= 60*minute; second = t; ts[i] = 10000*hour+100*minute+second; ds[i] = 1000*year+day; } free(times); return 1; } /****************************************************/ /* This will get the number of levels from a NetCDF */ /* file containing 2D or sounding data */ /****************************************************/ /* Input: finfo - the NetCDF format info */ /* nc_id - NetCDF file ID */ /* Output: numlevels - the number of levels each */ /* record will have */ /****************************************************/ int Read_NetCDF_Num_of_Levels( NetCDF_Format_Info finfo, int nc_id, int *numlevels) { int status; int levelid; size_t nl; status = nc_inq_dimid( nc_id, finfo->LEVELDIM, &levelid); if(status != NC_NOERR){ return 0; } status = nc_inq_dimlen(nc_id, levelid, &nl); if(status != NC_NOERR){ return 0; } *numlevels = (int) nl; return 1; } /****************************************************/ /* This will read the height for each of the levels */ /* in a 2D or sounding NetCDF file in meters */ /****************************************************/ /* Input: finfo - the NetCDF format info */ /* nc_id - NetCDF file ID */ /* recid - the record number of ID */ /* numlevels - the number of levels to get */ /* the height for */ /* Output: data - an array containing the height */ /* in meters for each level */ /****************************************************/ int Read_NetCDF_Levels( NetCDF_Format_Info finfo, int nc_id, int recid, int numlevels, float *data) { int status; int levelid; static size_t tstart[2], tend[2]; status = nc_inq_varid( nc_id, finfo->LEVELVAR, &levelid); if(status != NC_NOERR){ return 0; } tstart[0] = recid; tstart[1] = 0; tend[0] = 1; tend[1] = numlevels; status = nc_get_vara_float(nc_id, levelid, tstart, tend, data); if(status != NC_NOERR){ return 0; } return 1; } /****************************************************/ /* This will look through all the records in a */ /* NetCDF file and determine the bounding region */ /* which will be used to determine the vis5dboudries*/ /****************************************************/ /* Input: finfo - the NetCDF format info */ /* nc_id - NetCDF file ID */ /* Output: west, east, north, south - the horizontal*/ /* boundries in degrees */ /* top, bottom - the vertical boundries in */ /* kilometers above sea level */ /****************************************************/ int Read_NetCDF_Bounds( NetCDF_Format_Info finfo, int nc_id, float *west, float *east, float *north, float *south, float *top, float *bottom) { int i, status, latid, lonid, hgtid, numrecsid; size_t numrecs; float nb, sb, wb, eb, tb, bb; float *latdata, *londata, *hgtdata; float fill_value; /*************************/ /* get number of records */ /*************************/ status = nc_inq_dimid(nc_id, finfo->REC_NUM, &numrecsid); if(status != NC_NOERR){ return 0; } status = nc_inq_dimlen(nc_id, numrecsid, &numrecs); if(status != NC_NOERR){ return 0; } /*****************************/ /* malloc lat, lon, hgt data */ /*****************************/ latdata = (float *) malloc(numrecs * sizeof(float)); if (!latdata){ printf("couldn't allocate enough memory\n"); return 0; } londata = (float *) malloc(numrecs * sizeof(float)); if (!londata){ printf("couldn't allocate enough memory\n"); free(latdata); return 0; } hgtdata = (float *) malloc(numrecs * sizeof(float)); if (!hgtdata){ printf("couldn't allocate enough memory\n"); free(latdata); free(londata); return 0; } status = nc_inq_varid( nc_id, finfo->LAT, &latid); if(status != NC_NOERR){ free(latdata); free(londata); free(hgtdata); return 0; } status = nc_inq_varid( nc_id, finfo->LON, &lonid); if(status != NC_NOERR){ free(latdata); free(londata); free(hgtdata); return 0; } status = nc_inq_varid( nc_id, finfo->HGT, &hgtid); if(status != NC_NOERR){ free(latdata); free(londata); free(hgtdata); return 0; } status = nc_get_att_float( nc_id, latid, finfo->LOCATION_FILL, &fill_value); if(status != NC_NOERR){ free(latdata); free(londata); free(hgtdata); return 0; } /************************************************/ /* get the lat, lon, hgt data in one big chunck */ /************************************************/ status = nc_get_var_float( nc_id, latid, latdata); if(status != NC_NOERR){ printf("error getting bounds\n"); free(latdata); free(londata); free(hgtdata); return 0; } status = nc_get_var_float( nc_id, lonid, londata); if(status != NC_NOERR){ printf("error getting bounds\n"); free(latdata); free(londata); free(hgtdata); return 0; } status = nc_get_var_float( nc_id, hgtid, hgtdata); if(status != NC_NOERR){ printf("error getting bounds\n"); free(latdata); free(londata); free(hgtdata); return 0; } nb = -180.0; sb = 180.0; eb = -180.0; wb = 180.0; tb = -10000.0; bb = 10000.0; for (i = 0; i < numrecs; i++){ if (latdata[i] != fill_value){ if (latdata[i] > nb){ nb = latdata[i]; } if (latdata[i] < sb){ sb = latdata[i]; } } } for (i = 0; i < numrecs; i++){ if (londata[i] != fill_value){ if (londata[i] > eb){ eb = londata[i]; } if (londata[i] < wb){ wb = londata[i]; } } } for (i = 0; i < numrecs; i++){ if (hgtdata[i] != fill_value){ if (hgtdata[i] > tb){ tb = hgtdata[i]; } if (hgtdata[i] < bb){ bb = hgtdata[i]; } } } *west = -wb; *east = -eb; *north = nb; *south = sb; *top = tb/1000.0; *bottom = bb/1000.0; free(latdata); free(londata); free(hgtdata); return 1; } /****************************************************/ /* This will get information about the variables in */ /* a NetCDF file */ /****************************************************/ /* Input: finfo - the NetCDF format info */ /* nc_id - NetCDF file ID */ /* Output: numvars - the number of variable */ /* varname - an array of the variable names */ /* vartype - this array of size [0..numvars */ /* contains the variable type, */ /* one of... */ /* CHAR_VAR */ /* INT_VAR */ /* FLOAT_VAR */ /* DOUBLE_VAR */ /* vardim - this array of size [0..numvars] */ /* contains the dimension of the variable */ /* which is used to determine how */ /* to read it from the NetCDF file */ /* later. One of... */ /* VAR_1D */ /* VAR_2D */ /* VAR_3D */ /* VAR_4D */ /* charvarlength - this array of size */ /* [0..num_vars] contains the */ /* length of the char string for */ /* each of the variables. If the */ /* vartype is CHAR_VAR it will be */ /* > 0 if vartype != CHAR_VAR then */ /* it will be 0 length */ /* varmin, varmax - this array of size */ /* [0..num_vars] contains the */ /* variable min and max for each of */ /* the variables if vartype !=CHAR_VAR*/ /****************************************************/ int Read_NetCDF_Vars( NetCDF_Format_Info finfo, int nc_id, int *num_vars, char varname[MAXVARS][MAX_VAR_LENGTH], int vartype[], int vardim[], int charvarlength[], double varmin[MAXVARS], double varmax[MAXVARS]) { int status, numvars, var_offset ; int numdims, cloud_layer_id; int numrecsid; int s, i, k, c, latid, lonid, hgtid; int dimids[10]; nc_type type; size_t numrecs, stringsize, num_cloud_layers; char vname[1000]; double *mmdata; double fillvalue; static size_t start[2]; status = nc_inq_nvars( nc_id, &numvars); if(status != NC_NOERR){ return 0; } /*************************/ /* get number of records */ /*************************/ status = nc_inq_dimid(nc_id, finfo->REC_NUM, &numrecsid); if(status != NC_NOERR){ return 0; } status = nc_inq_dimlen(nc_id, numrecsid, &numrecs); if(status != NC_NOERR){ return 0; } /***********************************/ /* allocate min max data array now */ /***********************************/ mmdata = (double *) malloc(numrecs * sizeof(double)); if (!mmdata){ printf("couldn't allocate min max data array\n"); return 0; } /*****************************************************/ /* check to make sure lat, lon and hgt are there */ /*****************************************************/ status = nc_inq_varid( nc_id, finfo->LAT, &latid); if(status != NC_NOERR){ printf("Could not find lat var\n"); return 0; } status = nc_inq_varid( nc_id, finfo->LON, &lonid); if(status != NC_NOERR){ printf("Could not find lon var\n"); return 0; } status = nc_inq_varid( nc_id, finfo->HGT, &hgtid); if(status != NC_NOERR){ printf("Could not find hgt var\n"); return 0; } var_offset = 0; /******************************/ /* get cloud layers if needed */ /******************************/ if (finfo == FSL_METAR || finfo == UNIDATA_METAR){ num_cloud_layers = 0; cloud_layer_id = -1; status = nc_inq_dimid(nc_id, finfo->METAR_CLD_LAYERS, &cloud_layer_id); if(status != NC_NOERR){ printf("no cloud_layers dimension\n"); } else{ status = nc_inq_dimlen(nc_id, cloud_layer_id, &num_cloud_layers); if(status != NC_NOERR){ printf("no cloud_layers dimension\n"); return 0; } if (num_cloud_layers < 1 || num_cloud_layers > 9){ printf("number of cloud layers must be between 1..9\n"); return 0; } } } if (finfo == FSL_METAR || finfo == UNIDATA_METAR){ for (i = 0; i < numvars; i++){ k = i - var_offset; /****************/ /* get var name */ /****************/ status = nc_inq_varname( nc_id, i, vname); if(status != NC_NOERR){ return 0; } /****************/ /* get var type */ /****************/ status = nc_inq_vartype( nc_id, i, &type); if(status != NC_NOERR){ return 0; } if (strncmp(finfo->LAT, vname, strlen(finfo->LAT)) != 0 && strncmp(finfo->LON, vname, strlen(finfo->LON)) != 0 && strncmp(finfo->HGT, vname, strlen(finfo->HGT)) != 0){ if (strlen(vname) < MAX_VAR_LENGTH){ strncpy(varname[k], vname, MAX_VAR_LENGTH); /********************************/ /* get number of var dimensions */ /********************************/ status = nc_inq_varndims( nc_id, i, &numdims); if(status != NC_NOERR){ printf("error getting numdims\n"); return 0; } /**************************/ /* get var dimension id's */ /**************************/ status = nc_inq_vardimid( nc_id, i, dimids); if(status != NC_NOERR){ printf("error getting dimids\n"); return 0; } /************/ /* char var */ /************/ if (type == NC_CHAR){ /****************/ /* 3 dimensions */ /****************/ if (numdims == 3){ /*************************************/ /* Must be cloud layers, create vars */ /*************************************/ varname[k][strlen(varname[k])] = '0'; for (c = 1; c < num_cloud_layers; c++){ strncpy(varname[k+c], vname, MAX_VAR_LENGTH); varname[k+c][strlen(varname[k+c])] = c + '0'; var_offset--; } status = nc_inq_dimlen( nc_id, dimids[2], &stringsize); if(status != NC_NOERR){ printf("error getting stringsize\n"); return 0; } for (c = 0; c < num_cloud_layers; c++){ charvarlength[k+c] = stringsize; vartype[k+c] = CHAR_VAR; vardim[k+c] = VAR_2D; } } /****************/ /* 2 dimensions */ /****************/ else if (numdims == 2){ status = nc_inq_dimlen( nc_id, dimids[1], &stringsize); if(status != NC_NOERR){ printf("error getting stringsize\n"); return 0; } charvarlength[k] = (int) stringsize; vartype[k] = CHAR_VAR; vardim[k] = VAR_1D; } /***************************/ /* 1, 4 or more dimensions */ /***************************/ else{ printf("don't know what to do with a char %d dimensional var\n", numdims); return 0; } } /***********/ /* num var */ /***********/ else{ if (type == NC_BYTE || type == NC_SHORT || type == NC_INT){ vartype[k] = INT_VAR; } else if (type == NC_FLOAT){ vartype[k] = FLOAT_VAR; } else if (type == NC_DOUBLE){ vartype[k] = DOUBLE_VAR; } else{ printf("something wrong with the type\n"); exit(0); } /******************/ /* get fill value */ /******************/ status = nc_get_att_double( nc_id, i, finfo->LOCATION_FILL, &fillvalue); if(status != NC_NOERR){ printf("ccouldn't get fill value\n"); return 0; } /****************/ /* 2 dimensions */ /****************/ if (numdims == 2){ /************************/ /* must be cloud height */ /************************/ if (dimids[1] != cloud_layer_id){ printf("error with var second dimension\n"); return 0; } varname[k][strlen(varname[k])] = '0'; vardim[k] = VAR_2D; for (c = 1; c < num_cloud_layers; c++){ strncpy(varname[k+c], vname, MAX_VAR_LENGTH); varname[k+c][strlen(varname[k+c])] = c + '0'; var_offset--; charvarlength[k+c] = 0; vartype[k+c] = vartype[k]; vardim[k+c] = vardim[k]; } /*******************/ /* get min and max */ /*******************/ for (c = 0; c < num_cloud_layers; c++){ for (s = 0; s < numrecs; s++){ start[0] = s; start[1] = 0; nc_get_var1_double( nc_id, i, start, mmdata+s); } get_min_and_max( numrecs, mmdata, fillvalue, &varmin[k+c], &varmax[k+c]); } } /****************/ /* 1 dimension */ /****************/ else if (numdims == 1){ vardim[k] = VAR_1D; charvarlength[k] = 0; for (s = 0; s < numrecs; s++){ start[0] = s; nc_get_var1_double( nc_id, i, start, mmdata+s); } get_min_and_max( numrecs, mmdata, fillvalue, &varmin[k], &varmax[k]); } /******************************/ /* other number of dimesnions */ /******************************/ else{ printf("don't know what to do with an number %d dimesional var\n", numdims); return 0; } } } /******************************************/ /* var is too long excluding the variable */ /******************************************/ else{ printf("variable %s is too long, ommitting it\n", vname); var_offset++; } } else{ var_offset++; } } *num_vars = k; return 1; } else if (finfo == FSL_PROFILE){ for (i = 0; i < numvars; i++){ k = i - var_offset; /****************/ /* get var name */ /****************/ status = nc_inq_varname( nc_id, i, vname); if(status != NC_NOERR){ return 0; } /****************/ /* get var type */ /****************/ status = nc_inq_vartype( nc_id, i, &type); if(status != NC_NOERR){ return 0; } if (strncmp(finfo->LAT, vname, strlen(finfo->LAT)) != 0 && strncmp(finfo->LON, vname, strlen(finfo->LON)) != 0 && strncmp(finfo->HGT, vname, strlen(finfo->HGT)) != 0 && strncmp(finfo->LEVELVAR, vname, strlen(finfo->LEVELVAR)) != 0){ if (strlen(vname) < MAX_VAR_LENGTH){ strncpy(varname[k], vname, MAX_VAR_LENGTH); /********************************/ /* get number of var dimensions */ /********************************/ status = nc_inq_varndims( nc_id, i, &numdims); if(status != NC_NOERR){ printf("error getting numdims\n"); return 0; } /**************************/ /* get var dimension id's */ /**************************/ status = nc_inq_vardimid( nc_id, i, dimids); if(status != NC_NOERR){ printf("error getting dimids\n"); return 0; } /************/ /* char var */ /************/ if (type == NC_CHAR){ /****************/ /* 2 dimensions */ /****************/ if (numdims == 2){ status = nc_inq_dimlen( nc_id, dimids[1], &stringsize); if(status != NC_NOERR){ printf("error getting stringsize\n"); return 0; } charvarlength[k] = (int) stringsize; vartype[k] = CHAR_VAR; vardim[k] = VAR_1D; } /******************************/ /* 1, 3, 4 or more dimensions */ /******************************/ else{ printf("don't know what to do with a char %d dimensional var\n", numdims); return 0; } } /***********/ /* num var */ /***********/ else{ if (type == NC_BYTE || type == NC_SHORT || type == NC_INT){ vartype[k] = INT_VAR; } else if (type == NC_FLOAT){ vartype[k] = FLOAT_VAR; } else if (type == NC_DOUBLE){ vartype[k] = DOUBLE_VAR; } else{ printf("something wrong with the type\n"); exit(0); } /****************/ /* 2 dimensions */ /****************/ if (numdims == 2){ /*******************************/ /* must be a sounding data var */ /*******************************/ vardim[k] = VAR_2D; charvarlength[k] = 0; } /****************/ /* 1 dimension */ /****************/ else if (numdims == 1){ vardim[k] = VAR_1D; charvarlength[k] = 0; } /******************************/ /* other number of dimesnions */ /******************************/ else{ printf("don't know what to do with an number %d dimesional var\n", numdims); return 0; } } } /******************************************/ /* var is too long excluding the variable */ /******************************************/ else{ printf("variable %s is too long, ommitting it\n", vname); var_offset++; } } else{ var_offset++; } } *num_vars = k; free(mmdata); return 1; } return 0; } #endif /* HAVE_LIBNETCDF */