From 67a2500f47612846c25ece791e18ca0fde151218 Mon Sep 17 00:00:00 2001 From: Edward Hartnett <38856240+edwardhartnett@users.noreply.github.com> Date: Thu, 3 Aug 2023 10:03:53 -0600 Subject: [PATCH] better handling for lat/lon (#425) * handling dimension metadata * development of dimension code * trying dims * adding test file * adding test file * fixing doxygen * fixed warning * fixed warning * fixed warning * fixed leak * added extra testing to CMakeFiles * added extra testing to CMakeFiles * changes * fixing? * more testing * more testing * fixed warning --------- Co-authored-by: Ed --- .github/workflows/developer.yml | 2 +- CMakeLists.txt | 3 +- src/g2cdegrib2.c | 40 ++-- src/g2cfile.c | 79 +++++++- src/g2cinq.c | 80 ++++++++ src/grib2.h.in | 14 +- src/grib2_int.h | 21 +- tests/CMakeLists.txt | 35 +++- .../ref_fv3lam.t00z.prslev.f000.grib2.degrib2 | 182 ++++++++++++++++++ tests/tst_degrib2_ftp_all.c | 3 +- tests/tst_gdaswave.c | 54 ++++++ tests/tst_mrms.c | 71 +++++++ 12 files changed, 541 insertions(+), 43 deletions(-) create mode 100644 tests/data/ref_fv3lam.t00z.prslev.f000.grib2.degrib2 create mode 100644 tests/tst_gdaswave.c create mode 100644 tests/tst_mrms.c diff --git a/.github/workflows/developer.yml b/.github/workflows/developer.yml index 03d227a4..35e57f9a 100644 --- a/.github/workflows/developer.yml +++ b/.github/workflows/developer.yml @@ -57,7 +57,7 @@ jobs: uses: actions/cache@v3 with: path: ~/data - key: data-1 + key: data-2 - name: build run: | diff --git a/CMakeLists.txt b/CMakeLists.txt index 58ee3cef..d82815d0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,7 +23,8 @@ option(USE_OpenJPEG "Use OpenJPEG library" OFF) option(BUILD_SHARED_LIBS "Build shared libraries" ON) option(BUILD_STATIC_LIBS "Build static libraries" ON) option(FTP_TEST_FILES "Fetch and test with files on FTP site." OFF) -option(LARGE_FTP_TESTS "When testing with FTP files, include very large (> 2GB) test files - this is slow!" OFF) +option(FTP_LARGE_TEST_FILES "Fetch and test with very large files on FTP site." OFF) +option(FTP_EXTRA_TEST_FILES "Test with files not yet available via FTP." OFF) option(LOGGING "Turn on internal logging messages. Only useful to g2c developers." OFF) option(PTHREADS "Turn on thread-safty with pthreads." OFF) option(UTILS "Build and install some utility programs." ON) diff --git a/src/g2cdegrib2.c b/src/g2cdegrib2.c index a07b6e3d..c7518faa 100644 --- a/src/g2cdegrib2.c +++ b/src/g2cdegrib2.c @@ -611,8 +611,8 @@ g2c_degrib2(int g2cid, const char *fileout) char abbrev[G2C_MAX_NOAA_ABBREV_LEN + 1]; char level_desc[G2C_MAX_TYPE_OF_FIXED_SURFACE_LEN + 1]; char date_time[100 + 1]; - float *data; - float total, max, min; + float *data = NULL; + float total = 0.0, max = 0.0, min = 0.0; int t; fprintf(f, "\n"); @@ -726,31 +726,39 @@ g2c_degrib2(int g2cid, const char *fileout) /* Now read the data and find the min, max, and average values. */ - /* Allocate storage for the data. */ - if (!(data = malloc(sec5_info->num_data_points * sizeof(float)))) - return G2C_ERROR; - + LOG((5, "sec5_info->num_data_points %ld", sec5_info->num_data_points)); + if (sec5_info->num_data_points) + { + /* Allocate storage for the data. */ + if (!(data = malloc(sec5_info->num_data_points * sizeof(float)))) + return G2C_ERROR; + } + /* Get the data from message 0, product 0. */ if ((ret = g2c_get_prod(g2cid, msg->msg_num, fld, NULL, data))) return ret; /* Find min/max/avg. */ - max = data[0]; - min = data[0]; - total = data[0]; - for (i = 1; i < sec5_info->num_data_points; i++) + if (sec5_info->num_data_points) { - total += data[i]; - if (data[i] > max) - max = data[i]; - if (data[i] < min) - min = data[i]; + max = data[0]; + min = data[0]; + total = data[0]; + for (i = 1; i < sec5_info->num_data_points; i++) + { + total += data[i]; + if (data[i] > max) + max = data[i]; + if (data[i] < min) + min = data[i]; + } } fprintf(f, "( PARM= %s ) : MIN=%25.8f AVE=%25.8f MAX=%25.8f\n", abbrev, min, total/sec5_info->num_data_points, max); /* Free the data. */ - free(data); + if (sec5_info->num_data_points) + free(data); total_fields++; } diff --git a/src/g2cfile.c b/src/g2cfile.c index 341318c0..3ce0b65a 100644 --- a/src/g2cfile.c +++ b/src/g2cfile.c @@ -282,6 +282,67 @@ find_available_g2cid(int *g2cid) return ret; } + +/** + * Determine the dimension information from the section 3 metadata. + * + * See (GRIB2 - SECTION 3 GRID DEFINITION + * SECTION)[https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_sect3.shtml]. + * + * For a list of grid definitions see [GRIB2 - TABLE 3.1 Grid + * Definition Template + * Number](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_table3-1.shtml). + * + * @param sec G2C_SECTION3_INFO_T struct. + * + * @return + * - ::G2C_NOERROR No error. + * - ::G2C_EINVAL Invalid input. + * - ::G2C_ENOMEM Out of memory. + * + * @author Ed Hartnett @date Sep 15, 2022 + */ +static int +determine_dims(G2C_SECTION_INFO_T *sec) +{ + G2C_DIM_INFO_T *d0, *d1; + G2C_SECTION3_INFO_T *sec3_info; + int d; + + sec3_info = (G2C_SECTION3_INFO_T *)(sec->sec_info); + d0 = &(sec3_info->dim[0]); + d1 = &(sec3_info->dim[1]); + + /* Based on the grid definition template number, and the contents + * of the template, decide the len, name, and values of the two + * dimensions. */ + switch (sec3_info->grid_def) + { + case 0: + LOG((5, "determine_dim allocating storage for lat/lon values")); + d0->len = sec->template[8]; + strncpy(d0->name, LATITUDE, G2C_MAX_NAME); + if (!(d0->value = malloc(d0->len * sizeof(float)))) + return G2C_ENOMEM; + d0->value[0] = sec->template[11]; + for (d = 1; d < d0->len; d++) + d0->value[d] = d0->value[d - 1] - sec->template[16]; + + d1->len = sec->template[7]; + strncpy(d1->name, LONGITUDE, G2C_MAX_NAME); + if (!(d1->value = malloc(d1->len * sizeof(float)))) + return G2C_ENOMEM; + d1->value[0] = sec->template[12]; + for (d = 1; d < d1->len; d++) + d1->value[d] = d1->value[d - 1] - sec->template[17]; + break; + default: + break; + } + + return G2C_NOERROR; +} + /** * Read the metadata from section 3 (Grid Definition Section) of a * GRIB2 message. @@ -293,7 +354,7 @@ find_available_g2cid(int *g2cid) * * @param f FILE pointer to open GRIB2 file. * @param rw_flag ::G2C_FILE_WRITE if function should write, - * ::G2C_FILE_READ if it should read. + * ::G2C_FILE_READ (0) if it should read. * @param sec Pointer to the G2C_SECTION_INFO_T struct. * * @return @@ -369,6 +430,11 @@ g2c_rw_section3_metadata(FILE *f, int rw_flag, G2C_SECTION_INFO_T *sec) if (!rw_flag) sec->sec_info = sec3_info; + /* Figure out the dimensions, if we can. */ + if (!rw_flag) + if ((ret = determine_dims(sec))) + return ret; + LOG((6, "finished reading or writing section 3 at file position %ld", ftell(f))); return G2C_NOERROR; } @@ -1139,6 +1205,17 @@ free_metadata(int g2cid) stmp = sec->next; if (sec->template) free(sec->template); + /* Free dim info in section 3. */ + if (sec->sec_num == 3) + { + LOG((5, "free_metadata freeing storage for lat/lon values")); + float *v0 = ((G2C_SECTION3_INFO_T *)(sec->sec_info))->dim[0].value; + float *v1 = ((G2C_SECTION3_INFO_T *)(sec->sec_info))->dim[1].value; + if (v0) + free(v0); + if (v1) + free(v1); + } if (sec->sec_info) free(sec->sec_info); free(sec); diff --git a/src/g2cinq.c b/src/g2cinq.c index c644ed0c..d0e13ce8 100644 --- a/src/g2cinq.c +++ b/src/g2cinq.c @@ -300,3 +300,83 @@ g2c_inq_prod(int g2cid, int msg_num, int prod_num, int *pds_template_len, return ret; } + +/** + * Learn about the one of the dimensions of a GRIB2 product. + * + * @param g2cid ID of the opened file, as from g2c_open(). + * @param msg_num Number of the message in the file, starting with the + * first message as 0. + * @param prod_num Product number. + * @param dim_num Dimension number, with the first dimension as 0. + * @param len Pointer that gets the length of this dimension. Ignored if NULL. + * @param name Pointer that gets the name of this dimension. Must have + * memory of size G2C_MAX_NAME. Ignored if NULL. + * @param val Pointer that gets array of dimension values, of length + * len. Ignored if NULL. + * + * @return + * - ::G2C_NOERROR No error. + * - ::G2C_EBADID File ID not found. + * - ::G2C_ENOMSG Message not found. + * - ::G2C_ENOPRODUCT Product not found. + * - ::G2C_ENOSECTION GDS not found. + * + * @author Ed Hartnett @date 10/21/22 + */ +int +g2c_inq_dim(int g2cid, int msg_num, int prod_num, int dim_num, size_t *len, + char *name, float *val) +{ + G2C_MESSAGE_INFO_T *msg; + G2C_SECTION_INFO_T *sec4, *sec3; + G2C_DIM_INFO_T *dim; + int d; + int ret = G2C_NOERROR; + + /* Is this an open GRIB2 file? */ + if (g2cid < 0 || g2cid > G2C_MAX_FILES) + return G2C_EBADID; + + /* If using threading, lock the mutex. */ + MUTEX_LOCK(m); + + if (g2c_file[g2cid].g2cid != g2cid) + return G2C_EBADID; + + /* Find the message. */ + for (msg = g2c_file[g2cid].msg; msg; msg = msg->next) + if (msg->msg_num == msg_num) + break; + if (!msg) + return G2C_ENOMSG; + + /* Find the product. After this, sec4 will point to the + * appropropriate section 4 G2C_SECTION_INFO_T. */ + for (sec4 = msg->sec; sec4; sec4 = sec4->next) + if (sec4->sec_num == 4 && ((G2C_SECTION4_INFO_T *)sec4->sec_info)->field_num == prod_num) + break; + if (!sec4) + return G2C_ENOPRODUCT; + /* sec4_info = (G2C_SECTION4_INFO_T *)sec4->sec_info; */ + + /* Find the GDS. */ + for (sec3 = sec4->prev; sec3; sec3 = sec3->prev) + if (sec3->sec_num == 3) + break; + if (!sec3) + return G2C_ENOSECTION; + dim = &((G2C_SECTION3_INFO_T *)sec3->sec_info)->dim[dim_num]; + + /* Give the caller the info they want. */ + if (len) + *len = dim->len; + if (name) + strncpy(name, dim->name, G2C_MAX_NAME); + if (val) + for (d = 0; d < dim->len; d++) + val[d] = dim->value[d]; + + + return ret; +} diff --git a/src/grib2.h.in b/src/grib2.h.in index 432d5e5a..289707c0 100644 --- a/src/grib2.h.in +++ b/src/grib2.h.in @@ -322,18 +322,8 @@ int g2c_inq_msg_time(int g2cid, int msg_num, unsigned char *sig_ref_time, short int g2c_inq_prod(int g2cid, int msg_num, int prod_num, int *pds_template_len, int *pds_template, int *gds_template_len, int *gds_template, int *drs_template_len, int *drs_template); - -/* Inquiry functions. */ -int g2c_inq(int g2cid, int *num_msg); -int g2c_inq_msg(int g2cid, int msg_num, unsigned char *discipline, int *num_fields, - int *num_local, short *center, short *subcenter, unsigned char *master_version, - unsigned char *local_version); -int g2c_inq_msg_time(int g2cid, int msg_num, unsigned char *sig_ref_time, short *year, - unsigned char *month, unsigned char *day, unsigned char *hour, - unsigned char *minute, unsigned char *second); -int g2c_inq_prod(int g2cid, int msg_num, int prod_num, int *pds_template_len, - int *pds_template, int *gds_template_len, int *gds_template, - int *drs_template_len, int *drs_template); +int g2c_inq_dim(int g2cid, int msg_num, int prod_num, int dim_num, size_t *len, + char *name, float *val); /* Getting data. */ int g2c_get_prod(int g2cid, int msg_num, int prod_num, int *num_data_points, diff --git a/src/grib2_int.h b/src/grib2_int.h index 58310f89..ce799677 100644 --- a/src/grib2_int.h +++ b/src/grib2_int.h @@ -2,11 +2,6 @@ * @brief Header file with internal function prototypes NCEPLIBS-g2c * library. * - * ### Program History Log - * Date | Programmer | Comments - * -----|------------|--------- - * 2021-11-08 | Ed Hartnett | Initial - * * @author Ed Hartnett @date 2021-11-08 */ @@ -57,6 +52,12 @@ #define FOUR_BYTES 4 /**< Four bytes. */ #define EIGHT_BYTES 8 /**< Eight bytes. */ +/** Latitude */ +#define LATITUDE "Latitude" + +/** Longitude */ +#define LONGITUDE "Longitude" + /* For thread-safety, use these macros. */ #ifdef PTHREADS @@ -155,6 +156,15 @@ typedef struct g2c_section_info int template_len; /**< Number of entries in template. */ } G2C_SECTION_INFO_T; +/** Keep information about dimensions defined in section 3. */ +typedef struct g2c_dim_info +{ + int dimid; /**< Dimension ID. */ + size_t len; /**< Length of dimension. */ + char name[G2C_MAX_NAME + 1]; /**< Name of dimension. */ + float *value; /**< Array of dimension values. */ +} G2C_DIM_INFO_T; + /** Information about [Section 3 GRID DEFINITION * SECTION](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_sect3.shtml). */ typedef struct g2c_section3_info @@ -165,6 +175,7 @@ typedef struct g2c_section3_info unsigned char interp_list; /**< Interpetation of list of numbers defining number of points (See Table 3.11). */ unsigned short grid_def; /**< Grid definition template number (= N) (See Table 3.1). */ int *optional; /**< Optional list of numbers defining number of points. */ + G2C_DIM_INFO_T dim[2]; /**< Dimension information. */ } G2C_SECTION3_INFO_T; /** Information about [Section 4 PRODUCT DEFINITION diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 04d32d70..f5a6009a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -13,6 +13,7 @@ function(PULL_DATA THE_URL THE_FILE) # there before FTPing them. Developers can keep all test files on # their machines, and save the time of downloading them every time. if(NOT ${TEST_FILE_DIR} STREQUAL ".") + #message(STATUS "Checking for ${TEST_FILE_DIR}/${THE_FILE}.") if (EXISTS ${TEST_FILE_DIR}/${THE_FILE}) message(STATUS "Copying file ${TEST_FILE_DIR}/${THE_FILE} to test data directory.") FILE(COPY ${TEST_FILE_DIR}/${THE_FILE} @@ -67,8 +68,15 @@ set(REF_FILES "gdaswave.t00z.wcoast.0p16.f000.grib2.idx" "ref_WW3_Regional_US_West_Coast_20220718_0000.txt" "testgrib2.grb2" "ref_testgrib2.grb2.degrib2" - "ref_fv3lam.t00z.namerica.f00.grib2.degrib2" -) + ) + +# Copy extra files if needed. +if(FTP_EXTRA_TEST_FILES) + if(FTP_LARGE_TEST_FILES) + set(REF_FILES ${REF_FILES} "ref_fv3lam.t00z.prslev.f000.grib2.degrib2") + endif() +endif() + foreach(THE_FILE IN LISTS REF_FILES) FILE(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/${THE_FILE} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/data) @@ -126,12 +134,19 @@ if(FTP_TEST_FILES) PULL_DATA(${G2_FTP_URL} ${THE_FILE}) endforeach() - set(LARGE_FTP_FILES "fv3lam.t00z.namerica.f00.grib2") - if(LARGE_FTP_TESTS) - foreach(THE_FILE IN LISTS LARGE_FTP_FILES) + if(FTP_EXTRA_TEST_FILES) + if(FTP_LARGE_TEST_FILES) + set(LARGE_FTP_FILES "fv3lam.t00z.prslev.f000.grib2") + foreach(THE_FILE IN LISTS LARGE_FTP_FILES) + PULL_DATA(${G2_FTP_URL} ${THE_FILE}) + endforeach() + add_definitions(-DLARGE_FTP_TESTS) + endif() + + set(EXTRA_FTP_FILES "MRMS_MultiSensor_QPE_24H_Pass2_00.00_20230621-110000.grib2") + foreach(THE_FILE IN LISTS EXTRA_FTP_FILES) PULL_DATA(${G2_FTP_URL} ${THE_FILE}) endforeach() - add_definitions(-DLARGE_FTP_TESTS) endif() # Add this preprocessor definition so test files can conditionally @@ -194,3 +209,11 @@ if(USE_Jasper) endif() endif() +# Run these extra tests if you have the data files to do so. +if(FTP_EXTRA_TEST_FILES) + g2c_test(tst_mrms) +endif() + + + + diff --git a/tests/data/ref_fv3lam.t00z.prslev.f000.grib2.degrib2 b/tests/data/ref_fv3lam.t00z.prslev.f000.grib2.degrib2 new file mode 100644 index 00000000..f9c1623b --- /dev/null +++ b/tests/data/ref_fv3lam.t00z.prslev.f000.grib2.degrib2 @@ -0,0 +1,182 @@ + + GRIB MESSAGE 1 starts at 1 + + SECTION 0: 0 2 13342681 + SECTION 1: 7 0 2 1 1 2022 6 21 0 0 0 0 1 + Contains 0 Local Sections and 1 data fields. + + FIELD 1 + SECTION 0: 0 2 + SECTION 1: 7 0 2 1 1 2022 6 21 0 0 0 0 1 + SECTION 3: 0 14452641 0 0 1 + GRID TEMPLATE 3. 1 : 6 0 0 0 0 0 0 4881 2961 0 0 -37000000 299000000 48 37000000 61000000 25000 25000 64 -35000000 247000000 0 + NO Optional List Defining Number of Data Points. + PRODUCT TEMPLATE 4. 0: ( PARAMETER = PRMSL 0 3 1 ) 3 1 2 0 134 0 0 1 0 101 0 0 255 0 0 + FIELD: PRMSL Mean Sea Level valid 0 hour after 2022062100:00:00 + NO Optional Vertical Coordinate List. + Num. of Data Points = 12272728 with BIT-MAP 0 + DRS TEMPLATE 5. 3 : 1259828660 3 2 16 0 1 0 0 0 871108 0 5 1 1 12 5 2 2 + Data Values: + Num. of Data Points = 12272728 Num. of Data Undefined = 0 +( PARM= PRMSL ) : MIN= 99260.67968750 AVE= 116390.88281250 MAX= 104243.15625000 + + GRIB MESSAGE 2 starts at 13342682 + + SECTION 0: 0 2 10886183 + SECTION 1: 7 0 2 1 1 2022 6 21 0 0 0 0 1 + Contains 0 Local Sections and 1 data fields. + + FIELD 1 + SECTION 0: 0 2 + SECTION 1: 7 0 2 1 1 2022 6 21 0 0 0 0 1 + SECTION 3: 0 14452641 0 0 1 + GRID TEMPLATE 3. 1 : 6 0 0 0 0 0 0 4881 2961 0 0 -37000000 299000000 48 37000000 61000000 25000 25000 64 -35000000 247000000 0 + NO Optional List Defining Number of Data Points. + PRODUCT TEMPLATE 4. 0: ( PARAMETER = PRES 0 3 0 ) 3 0 2 0 134 0 0 1 0 105 0 1 255 0 0 + FIELD: PRES Mean Sea Level valid 0 hour after 2022062100:00:00 + NO Optional Vertical Coordinate List. + Num. of Data Points = 12272728 with BIT-MAP 0 + DRS TEMPLATE 5. 3 : 1225150805 3 1 16 0 1 0 0 0 706754 0 5 1 1 10 6 2 3 + Data Values: + Num. of Data Points = 12272728 Num. of Data Undefined = 0 +( PARM= PRES ) : MIN= 55016.53125000 AVE= 110768.10937500 MAX= 103871.73437500 + + GRIB MESSAGE 3 starts at 24228865 + + SECTION 0: 0 2 2729609 + SECTION 1: 7 0 2 1 1 2022 6 21 0 0 0 0 1 + Contains 0 Local Sections and 1 data fields. + + FIELD 1 + SECTION 0: 0 2 + SECTION 1: 7 0 2 1 1 2022 6 21 0 0 0 0 1 + SECTION 3: 0 14452641 0 0 1 + GRID TEMPLATE 3. 1 : 6 0 0 0 0 0 0 4881 2961 0 0 -37000000 299000000 48 37000000 61000000 25000 25000 64 -35000000 247000000 0 + NO Optional List Defining Number of Data Points. + PRODUCT TEMPLATE 4. 0: ( PARAMETER = CLWMR 0 1 22 ) 1 22 2 0 134 0 0 1 0 105 0 1 255 0 0 + FIELD: CLWMR Mean Sea Level valid 0 hour after 2022062100:00:00 + NO Optional Vertical Coordinate List. + Num. of Data Points = 12272728 with BIT-MAP 0 + DRS TEMPLATE 5. 3 : 0 0 5 9 0 1 0 0 0 138003 0 4 1 1 1024 10 2 2 + Data Values: + Num. of Data Points = 12272728 Num. of Data Undefined = 0 +( PARM= CLWMR ) : MIN= 0.00000000 AVE= 0.00002456 MAX= 0.00183000 + + GRIB MESSAGE 4 starts at 26958474 + + SECTION 0: 0 2 1985412 + SECTION 1: 7 0 2 1 1 2022 6 21 0 0 0 0 1 + Contains 0 Local Sections and 1 data fields. + + FIELD 1 + SECTION 0: 0 2 + SECTION 1: 7 0 2 1 1 2022 6 21 0 0 0 0 1 + SECTION 3: 0 14452641 0 0 1 + GRID TEMPLATE 3. 1 : 6 0 0 0 0 0 0 4881 2961 0 0 -37000000 299000000 48 37000000 61000000 25000 25000 64 -35000000 247000000 0 + NO Optional List Defining Number of Data Points. + PRODUCT TEMPLATE 4. 0: ( PARAMETER = ICMR 0 1 23 ) 1 23 2 0 134 0 0 1 0 105 0 1 255 0 0 + FIELD: ICMR Mean Sea Level valid 0 hour after 2022062100:00:00 + NO Optional Vertical Coordinate List. + Num. of Data Points = 12272728 with BIT-MAP 0 + DRS TEMPLATE 5. 3 : 0 2 10 16 0 1 0 0 0 15466 0 5 1 1 511 14 2 3 + Data Values: + Num. of Data Points = 12272728 Num. of Data Undefined = 0 +( PARM= ICMR ) : MIN= 0.00000000 AVE= 0.00000000 MAX= 0.00002068 + + GRIB MESSAGE 5 starts at 28943886 + + SECTION 0: 0 2 4547624 + SECTION 1: 7 0 2 1 1 2022 6 21 0 0 0 0 1 + Contains 0 Local Sections and 1 data fields. + + FIELD 1 + SECTION 0: 0 2 + SECTION 1: 7 0 2 1 1 2022 6 21 0 0 0 0 1 + SECTION 3: 0 14452641 0 0 1 + GRID TEMPLATE 3. 1 : 6 0 0 0 0 0 0 4881 2961 0 0 -37000000 299000000 48 37000000 61000000 25000 25000 64 -35000000 247000000 0 + NO Optional List Defining Number of Data Points. + PRODUCT TEMPLATE 4. 0: ( PARAMETER = RWMR 0 1 24 ) 1 24 2 0 134 0 0 1 0 105 0 1 255 0 0 + FIELD: RWMR Mean Sea Level valid 0 hour after 2022062100:00:00 + NO Optional Vertical Coordinate List. + Num. of Data Points = 12272728 with BIT-MAP 0 + DRS TEMPLATE 5. 3 : 0 1 7 16 0 1 0 0 0 320272 0 5 1 1 141 9 2 3 + Data Values: + Num. of Data Points = 12272728 Num. of Data Undefined = 0 +( PARM= RWMR ) : MIN= 0.00000000 AVE= 0.00000511 MAX= 0.01282600 + + GRIB MESSAGE 6 starts at 33491510 + + SECTION 0: 0 2 2171412 + SECTION 1: 7 0 2 1 1 2022 6 21 0 0 0 0 1 + Contains 0 Local Sections and 1 data fields. + + FIELD 1 + SECTION 0: 0 2 + SECTION 1: 7 0 2 1 1 2022 6 21 0 0 0 0 1 + SECTION 3: 0 14452641 0 0 1 + GRID TEMPLATE 3. 1 : 6 0 0 0 0 0 0 4881 2961 0 0 -37000000 299000000 48 37000000 61000000 25000 25000 64 -35000000 247000000 0 + NO Optional List Defining Number of Data Points. + PRODUCT TEMPLATE 4. 0: ( PARAMETER = SNMR 0 1 25 ) 1 25 2 0 134 0 0 1 0 105 0 1 255 0 0 + FIELD: SNMR Mean Sea Level valid 0 hour after 2022062100:00:00 + NO Optional Vertical Coordinate List. + Num. of Data Points = 12272728 with BIT-MAP 0 + DRS TEMPLATE 5. 3 : 0 3 8 15 0 1 0 0 0 33062 0 5 1 1 458 13 2 2 + Data Values: + Num. of Data Points = 12272728 Num. of Data Undefined = 0 +( PARM= SNMR ) : MIN= 0.00000000 AVE= 0.00000131 MAX= 0.00363072 + + GRIB MESSAGE 7 starts at 35662922 + + SECTION 0: 0 2 1850730 + SECTION 1: 7 0 2 1 1 2022 6 21 0 0 0 0 1 + Contains 0 Local Sections and 1 data fields. + + FIELD 1 + SECTION 0: 0 2 + SECTION 1: 7 0 2 1 1 2022 6 21 0 0 0 0 1 + SECTION 3: 0 14452641 0 0 1 + GRID TEMPLATE 3. 1 : 6 0 0 0 0 0 0 4881 2961 0 0 -37000000 299000000 48 37000000 61000000 25000 25000 64 -35000000 247000000 0 + NO Optional List Defining Number of Data Points. + PRODUCT TEMPLATE 4. 0: ( PARAMETER = GRMR 0 1 32 ) 1 32 2 0 134 0 0 1 0 105 0 1 255 0 0 + FIELD: GRMR Mean Sea Level valid 0 hour after 2022062100:00:00 + NO Optional Vertical Coordinate List. + Num. of Data Points = 12272728 with BIT-MAP 0 + DRS TEMPLATE 5. 3 : 0 0 5 8 0 1 0 0 0 10020 0 4 1 1 8192 13 2 2 + Data Values: + Num. of Data Points = 12272728 Num. of Data Undefined = 0 +( PARM= GRMR ) : MIN= 0.00000000 AVE= 0.00000006 MAX= 0.00170000 + + GRIB MESSAGE 8 starts at 37513652 + + SECTION 0: 0 2 3953198 + SECTION 1: 7 0 2 1 1 2022 6 21 0 0 0 0 1 + Contains 0 Local Sections and 1 data fields. + + FIELD 1 + SECTION 0: 0 2 + SECTION 1: 7 0 2 1 1 2022 6 21 0 0 0 0 1 + SECTION 3: 0 14452641 0 0 1 + GRID TEMPLATE 3. 1 : 6 0 0 0 0 0 0 4881 2961 0 0 -37000000 299000000 48 37000000 61000000 25000 25000 64 -35000000 247000000 0 + NO Optional List Defining Number of Data Points. + PRODUCT TEMPLATE 4. 0: ( PARAMETER = TCDC 0 6 1 ) 6 1 2 0 134 0 0 1 0 105 0 1 255 0 0 + FIELD: TCDC Mean Sea Level valid 0 hour after 2022062100:00:00 + NO Optional Vertical Coordinate List. + Num. of Data Points = 12272728 with BIT-MAP 0 + DRS TEMPLATE 5. 3 : 0 0 0 9 0 1 0 0 0 315285 0 4 1 1 71 8 2 2 + Data Values: + Num. of Data Points = 12272728 Num. of Data Undefined = 0 +( PARM= TCDC ) : MIN= 0.00000000 AVE= 14.06626606 MAX= 100.00000000 + + GRIB MESSAGE 9 starts at 41466850 + + SECTION 0: 0 2 8329533 + SECTION 1: 7 0 2 1 1 2022 6 21 0 0 0 0 1 + Contains 0 Local Sections and 1 data fields. + + FIELD 1 + SECTION 0: 0 2 + SECTION 1: 7 0 2 1 1 2022 6 21 0 0 0 0 1 + SECTION 3: 0 14452641 0 0 1 + GRID TEMPLATE 3. 1 : 6 0 0 0 0 0 0 4881 2961 0 0 -37000000 299000000 48 37000000 61000000 25000 25000 64 -35000000 247000000 0 + NO Optional List Defining Number of Data Points. + PRODUCT TEMPLATE 4. 0: ( PARAMETER = REFD 0 16 195 ) 16 195 2 0 134 \ No newline at end of file diff --git a/tests/tst_degrib2_ftp_all.c b/tests/tst_degrib2_ftp_all.c index bd4b9863..c3c6f480 100644 --- a/tests/tst_degrib2_ftp_all.c +++ b/tests/tst_degrib2_ftp_all.c @@ -86,7 +86,7 @@ main() { #define NUM_LARGE_FILES 1 char file[NUM_LARGE_FILES][MAX_FILENAME_LEN + 1] = { - "data/fv3lam.t00z.namerica.f00.grib2" + "data/fv3lam.t00z.prslev.f000.grib2" }; int g2cid; int num_msg; @@ -94,6 +94,7 @@ main() int t; int ret; + /* g2c_set_log_level(10); */ for (f = 0; f < NUM_LARGE_FILES; f++) { /* for (t = 0; t < 2; t++) */ diff --git a/tests/tst_gdaswave.c b/tests/tst_gdaswave.c new file mode 100644 index 00000000..928f4c0b --- /dev/null +++ b/tests/tst_gdaswave.c @@ -0,0 +1,54 @@ +/* This is a test for the NCEPLIBS-g2c project. This test is for the + * g2c file functions on the GRIB2 file that's included in the + * tests/data directory for testion, + * gdaswave.t00z.wcoast.0p16.f000.grib2. + * + * Ed Hartnett 7/5/23 + */ + +#include +#include +#include "grib2_int.h" + +#define GDAS_FILE "data/gdaswave.t00z.wcoast.0p16.f000.grib2" +#define LAT_LEN 241 +#define LON_LEN 151 + +int +main() +{ + printf("Testing g2c file functions with %s.\n", GDAS_FILE); + printf("Testing g2c_inq_dim()..."); + { + int g2cid; + int num_msg; + size_t len0; + char dimname0[G2C_MAX_NAME + 1]; + float lat[LAT_LEN]; + /* float lon[LON_LEN]; */ + int d; + + /* Open GRIB2 file. */ + g2c_set_log_level(10); + if (g2c_open(GDAS_FILE, 0, &g2cid)) + return G2C_ERROR; + + /* Find the number of messages. */ + if (g2c_inq(g2cid, &num_msg)) + return G2C_ERROR; + printf("Number of messages: %d\n", num_msg); + if (num_msg != 19) + return G2C_ERROR; + + /* Find the dimensions of the product in the first message. */ + if (g2c_inq_dim(g2cid, 0, 0, 0, &len0, dimname0, lat)) + return G2C_ERROR; + printf("len0 %ld dimname0 %s\n", len0, dimname0); + for (d = 0; d < len0; d++) + printf("lat[%d] = %f\n", d, lat[d]); + + } + printf("ok!\n"); + printf("SUCCESS!\n"); + return 0; +} diff --git a/tests/tst_mrms.c b/tests/tst_mrms.c new file mode 100644 index 00000000..73c37c11 --- /dev/null +++ b/tests/tst_mrms.c @@ -0,0 +1,71 @@ +/* This is a test for the NCEPLIBS-g2c project. This test is for the + * g2c file functions on the GRIB2 file that's included in the + * tests/data directory for testion, + * gdaswave.t00z.wcoast.0p16.f000.grib2. + * + * Ed Hartnett 7/5/23 + */ + +#include +#include +#include "grib2_int.h" + +#define MRMS_FILE "data/MRMS_MultiSensor_QPE_24H_Pass2_00.00_20230621-110000.grib2" +#define LAT_LEN 3500 +#define LON_LEN 7000 +#define LATITUDE "Latitude" +#define LONGITUDE "Longitude" + +int +main() +{ + printf("Testing g2c file functions with %s.\n", MRMS_FILE); + printf("Testing g2c_inq_dim()..."); + { + int g2cid; + int num_msg; + size_t len0; + char dimname0[G2C_MAX_NAME + 1]; + size_t len1; + char dimname1[G2C_MAX_NAME + 1]; + float lat[LAT_LEN]; + float lon[LON_LEN]; + /* int d; */ + + /* Open GRIB2 file. */ + g2c_set_log_level(10); + if (g2c_open(MRMS_FILE, 0, &g2cid)) + return G2C_ERROR; + + /* Find the number of messages. */ + if (g2c_inq(g2cid, &num_msg)) + return G2C_ERROR; + printf("Number of messages: %d\n", num_msg); + if (num_msg != 1) + return G2C_ERROR; + + /* Find the dimensions of the product in the first message. */ + if (g2c_inq_dim(g2cid, 0, 0, 0, &len0, dimname0, lat)) + return G2C_ERROR; + printf("len0 %ld dimname0 %s\n", len0, dimname0); + printf("lat[0] = %f lat[%ld] = %f\n", lat[0], len0 - 1, lat[len0 - 1]); + if (len0 != LAT_LEN || strcmp(dimname0, LATITUDE)) + return G2C_ERROR; + if (lat[0] != 54995000 || lat[len0 - 1] != 20005000) + return G2C_ERROR; + + if (g2c_inq_dim(g2cid, 0, 0, 1, &len1, dimname1, lon)) + return G2C_ERROR; + if (len1 != LON_LEN || strcmp(dimname1, LONGITUDE)) + return G2C_ERROR; + printf("len1 %ld dimname1 %s\n", len1, dimname1); + printf("lon[0] = %f lon[%ld] = %f\n", lon[0], len1 - 1, lon[len1 - 1]); + if (len1 != LON_LEN || strcmp(dimname1, LONGITUDE)) + return G2C_ERROR; + if (lon[0] != 230004992 || lon[len1 - 1] != 160014992) + return G2C_ERROR; + } + printf("ok!\n"); + printf("SUCCESS!\n"); + return 0; +}