diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index e8d97644217e..0294c950a40c 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -5,17 +5,30 @@ #============================================================================== find_package(Doxygen) + +# This supports the build with/witout async code. Once async code is +# fully merged, remove the definition of C_SRC_FILES and its mention +# in Doxyfile.in for simplicity. +if (PIO_ENABLE_ASYNC) + SET(C_SRC_FILES "@CMAKE_CURRENT_SOURCE_DIR@/../src/clib/bget.c @CMAKE_CURRENT_SOURCE_DIR@/../src/clib/pioc.c @CMAKE_CURRENT_SOURCE_DIR@/../src/clib/pioc_sc.c @CMAKE_CURRENT_SOURCE_DIR@/../src/clib/pio_darray_async.c @CMAKE_CURRENT_SOURCE_DIR@/../src/clib/pio_get_nc_async.c @CMAKE_CURRENT_SOURCE_DIR@/../src/clib/pio_internal.h @CMAKE_CURRENT_SOURCE_DIR@/../src/clib/pio_nc4.c @CMAKE_CURRENT_SOURCE_DIR@/../src/clib/pio_put_nc_async.c @CMAKE_CURRENT_SOURCE_DIR@/../src/clib/pio_spmd.c @CMAKE_CURRENT_SOURCE_DIR@/../src/clib/bget.h @CMAKE_CURRENT_SOURCE_DIR@/../src/clib/pioc_support.c @CMAKE_CURRENT_SOURCE_DIR@/../src/clib/pio_lists.c @CMAKE_CURRENT_SOURCE_DIR@/../src/clib/pio_nc_async.c @CMAKE_CURRENT_SOURCE_DIR@/../src/clib/pio_varm.c @CMAKE_CURRENT_SOURCE_DIR@/../src/clib/dtypes.h @CMAKE_CURRENT_SOURCE_DIR@/../src/clib/pio_file.c @CMAKE_CURRENT_SOURCE_DIR@/../src/clib/pio.h @CMAKE_CURRENT_SOURCE_DIR@/../src/clib/pio_msg.c @CMAKE_CURRENT_SOURCE_DIR@/../src/clib/pio_rearrange.c @CMAKE_CURRENT_SOURCE_DIR@/../src/clib/topology.c") +else () + SET(C_SRC_FILES "@CMAKE_CURRENT_SOURCE_DIR@/../src/clib/bget.c @CMAKE_CURRENT_SOURCE_DIR@/../src/clib/pioc.c @CMAKE_CURRENT_SOURCE_DIR@/../src/clib/pioc_sc.c @CMAKE_CURRENT_SOURCE_DIR@/../src/clib/pio_internal.h @CMAKE_CURRENT_SOURCE_DIR@/../src/clib/pio_nc4.c @CMAKE_CURRENT_SOURCE_DIR@/../src/clib/pio_spmd.c @CMAKE_CURRENT_SOURCE_DIR@/../src/clib/bget.h @CMAKE_CURRENT_SOURCE_DIR@/../src/clib/pioc_support.c @CMAKE_CURRENT_SOURCE_DIR@/../src/clib/pio_darray.c @CMAKE_CURRENT_SOURCE_DIR@/../src/clib/pio_get_nc.c @CMAKE_CURRENT_SOURCE_DIR@/../src/clib/pio_lists.c @CMAKE_CURRENT_SOURCE_DIR@/../src/clib/pio_put_nc.c @CMAKE_CURRENT_SOURCE_DIR@/../src/clib/pio_varm.c @CMAKE_CURRENT_SOURCE_DIR@/../src/clib/dtypes.h @CMAKE_CURRENT_SOURCE_DIR@/../src/clib/pio_file.c @CMAKE_CURRENT_SOURCE_DIR@/../src/clib/pio.h @CMAKE_CURRENT_SOURCE_DIR@/../src/clib/pio_msg.c @CMAKE_CURRENT_SOURCE_DIR@/../src/clib/pio_nc.c @CMAKE_CURRENT_SOURCE_DIR@/../src/clib/pio_rearrange.c @CMAKE_CURRENT_SOURCE_DIR@/../src/clib/topology.c") +endif () + if(DOXYGEN_FOUND) - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in - ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY) - add_custom_target(doc - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/customdoxygen.css - ${CMAKE_CURRENT_BINARY_DIR} - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/DoxygenLayout.xml - ${CMAKE_CURRENT_BINARY_DIR} - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/doxygen.sty - ${CMAKE_CURRENT_BINARY_DIR} - COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMENT "Generating API documentation with Doxygen" VERBATIM) + # Process the Doxyfile using options set during configure. + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in + ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY) + + # Copy necessary files. + add_custom_target(doc + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/customdoxygen.css + ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/DoxygenLayout.xml + ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/doxygen.sty + ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Generating API documentation with Doxygen" VERBATIM) endif(DOXYGEN_FOUND) diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index 31dc3ffd1138..c39e69b13d28 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -769,11 +769,15 @@ WARN_LOGFILE = # Note: If this tag is empty the current directory is searched. INPUT = @CMAKE_CURRENT_SOURCE_DIR@/source \ - @CMAKE_CURRENT_SOURCE_DIR@/../src/clib \ @CMAKE_CURRENT_SOURCE_DIR@/../src/flib \ @CMAKE_CURRENT_SOURCE_DIR@/../examples/c \ @CMAKE_CURRENT_SOURCE_DIR@/../examples/f03 \ - @CMAKE_BINARY_DIR@/src/flib + @CMAKE_BINARY_DIR@/src/clib \ + @CMAKE_BINARY_DIR@/src/flib \ + @C_SRC_FILES@ + +# Uncomment this after the async code is fully merged into PIO. +# @CMAKE_CURRENT_SOURCE_DIR@/../src/clib # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses diff --git a/src/clib/pio.h b/src/clib/pio.h index c6c0a1332fa8..07f4b8b20c55 100644 --- a/src/clib/pio.h +++ b/src/clib/pio.h @@ -325,6 +325,7 @@ enum PIO_ERROR_HANDLERS PIO_RETURN_ERROR = (-53) }; +/** Define the netCDF-based error codes. */ #if defined( _PNETCDF) || defined(_NETCDF) #define PIO_GLOBAL NC_GLOBAL #define PIO_UNLIMITED NC_UNLIMITED @@ -417,25 +418,29 @@ enum PIO_ERROR_HANDLERS #define PIO_EBADCHUNK NC_EBADCHUNK #define PIO_ENOTBUILT NC_ENOTBUILT #define PIO_EDISKLESS NC_EDISKLESS - #define PIO_FILL_DOUBLE NC_FILL_DOUBLE #define PIO_FILL_FLOAT NC_FILL_FLOAT #define PIO_FILL_INT NC_FILL_INT #define PIO_FILL_CHAR NC_FILL_CHAR +#endif /* defined( _PNETCDF) || defined(_NETCDF) */ -#endif +/** Define the extra error codes for the parallel-netcdf library. */ #ifdef _PNETCDF #define PIO_EINDEP NC_EINDEP -#else +#else /* _PNETCDF */ #define PIO_EINDEP (-203) -#endif +#endif /* _PNETCDF */ +/** Define error codes for PIO. */ #define PIO_EBADIOTYPE -255 + +/** ??? */ #define PIO_REQ_NULL (NC_REQ_NULL-1) #if defined(__cplusplus) extern "C" { #endif + int PIOc_strerror(int pioerr, char *errstr); int PIOc_freedecomp(int iosysid, int ioid); int PIOc_inq_att (int ncid, int varid, const char *name, nc_type *xtypep, PIO_Offset *lenp); int PIOc_inq_format (int ncid, int *formatp); diff --git a/src/clib/pio_darray_async.c b/src/clib/pio_darray_async.c index cf66c6433325..d9e41a8340ea 100644 --- a/src/clib/pio_darray_async.c +++ b/src/clib/pio_darray_async.c @@ -1577,15 +1577,15 @@ int pio_read_darray_nc(file_desc_t *file, io_desc_t *iodesc, const int vid, } /** Read an array of data from a file to the (serial) IO library. - * @ingroup PIO_read_darray * * @param file a pointer to the open file descriptor for the file * that will be written to * @param iodesc a pointer to the defined iodescriptor for the buffer * @param vid the variable id to be read. - * @param IOBUF + * @param IOBUF the buffer to be read into from this mpi task * * @returns + * @ingroup PIO_read_darray */ int pio_read_darray_nc_serial(file_desc_t *file, io_desc_t *iodesc, const int vid, void *IOBUF) @@ -1813,7 +1813,7 @@ int pio_read_darray_nc_serial(file_desc_t *file, io_desc_t *iodesc, * processor. * * @return 0 for success, error code otherwise. - * @ingroup PIO_write_darray + * @ingroup PIO_read_darray */ int PIOc_read_darray(const int ncid, const int vid, const int ioid, const PIO_Offset arraylen, void *array) diff --git a/src/clib/pioc_support.c b/src/clib/pioc_support.c index d4d7a2920684..c60f4047a49d 100644 --- a/src/clib/pioc_support.c +++ b/src/clib/pioc_support.c @@ -17,6 +17,55 @@ int pio_log_level = 0; int my_rank; #endif /* PIO_ENABLE_LOGGING */ +/** Return a string description of an error code. If zero is passed, a + * null is returned. + * + * @param pioerr the error code returned by a PIO function call. + * @param errmsg Pointer that will get the error message. It will be + * PIO_MAX_NAME chars or less. + * + * @return 0 on success + */ +int +PIOc_strerror(int pioerr, char *errmsg) +{ + + /* System error? */ + if(pioerr > 0) + { + const char *cp = (const char *)strerror(pioerr); + if (cp) + strncpy(errmsg, cp, PIO_MAX_NAME); + else + strcpy(errmsg, "Unknown Error"); + } + else if (pioerr == PIO_NOERR) + { + strcpy(errmsg, "No error"); + } + else if (pioerr <= NC2_ERR && pioerr >= NC4_LAST_ERROR) /* NetCDF error? */ + { +#if defined( _PNETCDF) || defined(_NETCDF) + strncpy(errmsg, nc_strerror(pioerr), NC_MAX_NAME); +#else /* defined( _PNETCDF) || defined(_NETCDF) */ + strcpy(errmsg, "NetCDF error code, PIO not built with netCDF."); +#endif /* defined( _PNETCDF) || defined(_NETCDF) */ + } + else + { + /* Handle PIO errors. */ + switch(pioerr) { + case PIO_EBADIOTYPE: + strcpy(errmsg, "Bad IO type"); + break; + default: + strcpy(errmsg, "unknown PIO error"); + } + } + + return PIO_NOERR; +} + /** Set the logging level. Set to -1 for nothing, 0 for errors only, 1 * for important logging, and so on. Log levels below 1 are only * printed on the io/component root. If the library is not built with diff --git a/src/flib/pio.F90 b/src/flib/pio.F90 index c415f7a6fb30..739c0f8441e1 100644 --- a/src/flib/pio.F90 +++ b/src/flib/pio.F90 @@ -59,7 +59,8 @@ module pio PIO_set_chunk_cache, & PIO_get_chunk_cache, & PIO_set_var_chunk_cache, & - PIO_get_var_chunk_cache + PIO_get_var_chunk_cache, & + PIO_strerror use pionfatt_mod, only : PIO_put_att => put_att, & PIO_get_att => get_att diff --git a/src/flib/pio_nf.F90 b/src/flib/pio_nf.F90 index 8aa74d06f9f1..4db50a2a51df 100644 --- a/src/flib/pio_nf.F90 +++ b/src/flib/pio_nf.F90 @@ -37,7 +37,8 @@ module pio_nf pio_set_var_chunk_cache , & pio_get_var_chunk_cache , & pio_redef , & - pio_set_log_level + pio_set_log_level , & + pio_strerror ! pio_copy_att to be done interface pio_def_var @@ -194,6 +195,11 @@ module pio_nf set_log_level end interface pio_set_log_level + interface pio_strerror + module procedure & + strerror + end interface pio_strerror + interface pio_inquire module procedure & inquire_desc , & @@ -678,6 +684,34 @@ end function PIOc_set_log_level end interface ierr = PIOc_set_log_level(log_level) end function set_log_level + + !> + !! @defgroup PIO_strerror + !< + !> + !! @ingroup PIO_strerror + !! Returns a descriptive string for an error code. + !! + !! @param errcode the error code + !! @retval a description of the error + !< + integer function strerror(errcode, errmsg) result(ierr) + integer, intent(in) :: errcode + character(len=*), intent(out) :: errmsg + interface + integer(C_INT) function PIOc_strerror(errcode, errmsg) & + bind(C, name="PIOc_strerror") + use iso_c_binding + integer(C_INT), value :: errcode + character(C_CHAR) :: errmsg(*) + end function PIOc_strerror + end interface + errmsg = C_NULL_CHAR + ierr = PIOc_strerror(errcode, errmsg) + call replace_c_null(errmsg) + + end function strerror + !> !! @public !! @ingroup PIO_redef diff --git a/tests/unit/driver.F90 b/tests/unit/driver.F90 index d12d1d29cc2c..92af6cec3eb7 100644 --- a/tests/unit/driver.F90 +++ b/tests/unit/driver.F90 @@ -27,6 +27,9 @@ Program pio_unit_test_driver integer, external :: nc_set_log_level2 #endif integer ret_val + character(len=80) :: errmsg + character(len=80) :: expected + ! Set up MPI call MPI_Init(ierr) call MPI_Comm_rank(MPI_COMM_WORLD, my_rank, ierr) @@ -122,6 +125,16 @@ Program pio_unit_test_driver fail_cnt = 0 test_cnt = 0 + ! Test pio_strerror. + ret_val = PIO_strerror(-33, errmsg); + print *, 'errcode =', -33, ' strerror = ', errmsg + expected = 'NetCDF: Not a valid ID' + if (trim(errmsg) .ne. expected) then + err_msg = 'expected ' // trim(expected) // ' and got ' // trim(errmsg) + print *, err_msg + call parse(err_msg, fail_cnt) + end if + do test_id=1,ntest if (ltest(test_id)) then ! Make sure i is a valid test number @@ -146,6 +159,7 @@ Program pio_unit_test_driver #if defined( _NETCDF4) && defined(LOGGING) if(master_task) ierr = nc_set_log_level2(3) #endif + ! test_create() if (master_task) write(*,"(3x,A,1x)") "testing PIO_createfile..." call test_create(test_id, err_msg) diff --git a/tests/unit/test_names.c b/tests/unit/test_names.c index ea493ddc0f5d..b9684d03628d 100644 --- a/tests/unit/test_names.c +++ b/tests/unit/test_names.c @@ -1,6 +1,6 @@ /** - * @file - * Tests for names of vars, atts, and dims. + * @file Tests for names of vars, atts, and dims. Also test the + * PIOc_strerror() function. * */ #include @@ -148,6 +148,52 @@ check_att_name(int my_rank, int ncid, int verbose) return 0; } +/** Check the PIOc_strerror() function. + * + * @param my_rank the rank of this process. + * @param verbose true to get printfs on stdout. + * + * @return 0 for success, error code otherwise. + */ +int +check_strerror(int my_rank, int verbose) { + +#define NUM_TRIES 6 + char errstr[PIO_MAX_NAME + 1]; + int errcode[NUM_TRIES] = {PIO_EBADID, + NC_ENOTNC3, NC4_LAST_ERROR - 1, 0, 1, + PIO_EBADIOTYPE}; + const char *expected[NUM_TRIES] = {"NetCDF: Not a valid ID", + "NetCDF: Attempting netcdf-3 operation on netcdf-4 file", + "unknown PIO error", "No error", + nc_strerror(1), "Bad IO type"}; + int ret = PIO_NOERR; + + for (int try = 0; try < NUM_TRIES; try++) + { + char result[PIO_MAX_NAME]; + + /* Get the error string for this errcode. */ + PIOc_strerror(errcode[try], errstr); + + /* Check that it was as expected. */ + if (strcmp(errstr, expected[try])) + ret = ERR_AWFUL; + + /* Print some output to stdout if required. */ + if (verbose) + { + printf("%d: PIO strerror(%d) = %s\n", my_rank, errcode[try], + errstr); + strcpy(errstr, nc_strerror(errcode[try])); + printf("%d: netCDF strerror(%d) = %s\n", my_rank, errcode[try], + errstr); + } + } + + return ret; +} + /** Run Tests for NetCDF-4 Functions. * * @param argc argument count @@ -289,6 +335,10 @@ main(int argc, char **argv) printf("%d: ParallelIO Library example1 running on %d processors.\n", my_rank, ntasks); + /* Check the error string function. */ + if ((ret = check_strerror(my_rank, verbose))) + ERR(ret); + /* keep things simple - 1 iotask per MPI process */ niotasks = ntasks;