From fd6150019d6d4695684ebbee8a095aee2f7fbd24 Mon Sep 17 00:00:00 2001 From: Michael Long Date: Thu, 4 Jan 2024 17:37:03 -0500 Subject: [PATCH 1/5] Clean import of code for GDAL in ESMF. Compiles/runs in ESMF MSL --- src/clib/CMakeLists.txt | 10 + src/clib/pio.h | 22 +- src/clib/pio_darray.c | 6 +- src/clib/pio_file.c | 4 + src/clib/pio_gdal.c | 791 ++++++++++++++++++++++++++++++++++++++++ src/clib/pioc_support.c | 3 + 6 files changed, 834 insertions(+), 2 deletions(-) create mode 100644 src/clib/pio_gdal.c diff --git a/src/clib/CMakeLists.txt b/src/clib/CMakeLists.txt index 609de6f575..c592c5f96f 100644 --- a/src/clib/CMakeLists.txt +++ b/src/clib/CMakeLists.txt @@ -28,6 +28,8 @@ set (src topology.c pio_file.c pioc_support.c pio_lists.c if (NETCDF_INTEGRATION) set (src ${src} ../ncint/nc_get_vard.c ../ncint/ncintdispatch.c ../ncint/ncint_pio.c ../ncint/nc_put_vard.c) endif () +# This needs to be in an IF statement. using GDAL_INTEGRATION. But haven't figured that out yet. +set (src ${src} pio_gdal.c) add_library (pioc ${src}) @@ -173,6 +175,14 @@ if (PIO_USE_MPISERIAL) endif () endif () +#===== GDAL ===== +#if (GDAL_Found) + target_include_directories (pioc + PUBLIC ${GDAL_INCLUDE_DIR}) + target_link_libraries (pioc + PUBLIC ${GDAL_LIBRARY}) +#endif () + include(CheckTypeSize) check_type_size("size_t" SIZEOF_SIZE_T) CHECK_TYPE_SIZE("long long" SIZEOF_LONG_LONG) diff --git a/src/clib/pio.h b/src/clib/pio.h index a4b20b7522..8a628b5499 100644 --- a/src/clib/pio.h +++ b/src/clib/pio.h @@ -19,6 +19,8 @@ #include #include +#include + #define NETCDF_VERSION_LE(Maj, Min, Pat) \ (((NC_VERSION_MAJOR == Maj) && (NC_VERSION_MINOR == Min) && (NC_VERSION_PATCH <= Pat)) || \ ((NC_VERSION_MAJOR == Maj) && (NC_VERSION_MINOR < Min)) || (NC_VERSION_MAJOR < Maj)) @@ -606,6 +608,13 @@ typedef struct file_desc_t * feature. One consequence is that PIO_IOTYPE_NETCDF4C files will * not have deflate automatically turned on for each var. */ int ncint_file; + + /** GDAL specific vars - M.Long */ + GDALDatasetH *hDS; + int dateVarID; // Index of field with type OFTDate + int timeVarID; // Index of field with type OFTTime + int datetimeVarID; // Index of field with type OFTDatetime + } file_desc_t; /** @@ -624,7 +633,10 @@ enum PIO_IOTYPE PIO_IOTYPE_NETCDF4C = 3, /** NetCDF4 (HDF5) parallel */ - PIO_IOTYPE_NETCDF4P = 4 + PIO_IOTYPE_NETCDF4P = 4, + + /** GDAL (serial only) */ + PIO_IOTYPE_GDAL = 5 }; /** @@ -1357,6 +1369,14 @@ extern "C" { int nc_put_vard_ulonglong(int ncid, int varid, int decompid, const size_t recnum, const unsigned long long *op); + /* These functions are for the GDAL integration layer. MSL - 9/7/2023 */ + int GDALc_inq_fieldid(int fileid, const char *name, int *varidp); + int GDALc_inq_timeid(int fileid, int *timeid); // Is there a field of type OFTDate, OFTTime, or OFTDateTime? + int GDALc_openfile(int iosysid, int *fileIDp, GDALDatasetH *hDSp, int *iotype, const char *fname, bool mode); + int GDALc_sync(int fileid); + int GDALc_shp_get_int_field(int fileid); + int GDALc_shp_get_double_field(int fileid, int varid, const size_t *startp, const size_t *countp, double *ip); + #if defined(__cplusplus) } #endif diff --git a/src/clib/pio_darray.c b/src/clib/pio_darray.c index e7274da3e0..651b072ba3 100644 --- a/src/clib/pio_darray.c +++ b/src/clib/pio_darray.c @@ -181,7 +181,7 @@ PIOc_write_darray_multi(int ncid, const int *varids, int ioid, int nvars, /* Run these on all tasks if async is not in use, but only on * non-IO tasks if async is in use. */ - if (!ios->async || !ios->ioproc) + if ((!ios->async || !ios->ioproc) && (file->iotype != PIO_IOTYPE_GDAL)) { /* Get the number of dims for this var. */ PLOG((3, "about to call PIOc_inq_varndims varids[0] = %d", varids[0])); @@ -949,6 +949,10 @@ PIOc_read_darray(int ncid, int varid, int ioid, PIO_Offset arraylen, if ((ierr = pio_read_darray_nc(file, iodesc, varid, iobuf))) return pio_err(ios, file, ierr, __FILE__, __LINE__); break; + case PIO_IOTYPE_GDAL: + if ((ierr = pio_read_darray_shp(file, iodesc, varid, iobuf))) + return pio_err(ios, file, ierr, __FILE__, __LINE__); + break; default: return pio_err(NULL, NULL, PIO_EBADIOTYPE, __FILE__, __LINE__); } diff --git a/src/clib/pio_file.c b/src/clib/pio_file.c index e9edb6af4c..0b3dd7a389 100644 --- a/src/clib/pio_file.c +++ b/src/clib/pio_file.c @@ -283,6 +283,10 @@ PIOc_closefile(int ncid) ierr = ncmpi_close(file->fh); break; #endif + case PIO_IOTYPE_GDAL: + ierr = GDALClose((void*)file->hDS); + printf("GDALClose ierr: %d\n",ierr); + break; default: return pio_err(ios, file, PIO_EBADIOTYPE, __FILE__, __LINE__); } diff --git a/src/clib/pio_gdal.c b/src/clib/pio_gdal.c new file mode 100644 index 0000000000..221af2694e --- /dev/null +++ b/src/clib/pio_gdal.c @@ -0,0 +1,791 @@ +#include +#include +#include +#include + +/** + * The PIO library maintains its own set of ncids. This is the next + * ncid number that will be assigned. + */ +extern int pio_next_ncid; + +static int +GDALc_inq_file_metadata(file_desc_t *file, GDALDatasetH hDS, int iotype, int *nvars, + int **rec_var, int **pio_type, int **pio_type_size, + MPI_Datatype **mpi_type, int **mpi_type_size, int **ndims) +{ + int mpierr; + int ret; + + /* Check inputs. */ + pioassert(rec_var && pio_type && pio_type_size && mpi_type && mpi_type_size, + "pointers must be provided", __FILE__, __LINE__); + + if (hDS == NULL) { + return pio_err(file->iosystem, file, -999, __FILE__, __LINE__); + } + /* How many vars in the file? */ + if (iotype == PIO_IOTYPE_GDAL) + { + OGRLayerH hLayer = OGR_DS_GetLayer( hDS, 0 ); + OGR_L_ResetReading(hLayer); + + OGRFeatureDefnH hFD = OGR_L_GetLayerDefn(hLayer); + *nvars = OGR_FD_GetFieldCount(hFD); + if (nvars == 0) // empty file + return pio_err(NULL, file, PIO_ENOMEM, __FILE__, __LINE__); + + /* Allocate storage for info about each var. */ + if (*nvars) + { + if (!(*rec_var = malloc(*nvars * sizeof(int)))) + return PIO_ENOMEM; + if (!(*pio_type = malloc(*nvars * sizeof(int)))) + return PIO_ENOMEM; + if (!(*pio_type_size = malloc(*nvars * sizeof(int)))) + return PIO_ENOMEM; + if (!(*mpi_type = malloc(*nvars * sizeof(MPI_Datatype)))) + return PIO_ENOMEM; + if (!(*mpi_type_size = malloc(*nvars * sizeof(int)))) + return PIO_ENOMEM; + if (!(*ndims = malloc(*nvars * sizeof(int)))) + return PIO_ENOMEM; + } + + /* Learn about each variable in the file. */ + for (int v = 0; v < *nvars; v++) + { + int var_ndims; /* Number of dims for this var. */ + nc_type my_type; + + /* Find type of the var and number of dims in this var. Also + * learn about type. */ + size_t type_size; + + // + var_ndims = 1; // FIXED FOR NOW. For data-read purposes, it's a 1D stream across the number of + // elements. + (*ndims)[v] = var_ndims; + //>> if ((ret = nc_inq_var(ncid, v, NULL, &my_type, &var_ndims, NULL, NULL))) + //>> return pio_err(NULL, file, ret, __FILE__, __LINE__); + OGRFieldType Fld = OGR_Fld_GetType(OGR_FD_GetFieldDefn(hFD,v)); + bool typeOK = true; // assume we're good + switch (Fld) { + case OFTReal: + (*pio_type)[v] = (int)PIO_DOUBLE; + break; + case OFTInteger: + (*pio_type)[v] = (int)PIO_INT; + break; + // This needs to be done. How do we deal with timestamps etc in GDAL vector fields? + //>>case OFTDate: + //>> break; + //>> case OFTTime: + //>> break; + //>> case OFTDate: + //>> break; + //>> case OFTDateTime: + default: + typeOK = false; + break; +// return pio_err(file->iosystem, file, PIO_EBADIOTYPE, __FILE__, __LINE__); + } + //>> if ((ret = nc_inq_type(ncid, (*pio_type)[v], NULL, &type_size))) + //>> return check_netcdf(file, ret, __FILE__, __LINE__); + //>> (*pio_type_size)[v] = type_size; + + if (!typeOK) // Not a usable type + continue; + + /* Get the MPI type corresponding with the PIO type. */ + if ((ret = find_mpi_type((*pio_type)[v], &(*mpi_type)[v], NULL))) + return pio_err(NULL, file, ret, __FILE__, __LINE__); + + /* Get the size of the MPI type. */ + if ((*mpi_type)[v] == MPI_DATATYPE_NULL) + (*mpi_type_size)[v] = 0; + else + if ((mpierr = MPI_Type_size((*mpi_type)[v], &(*mpi_type_size)[v]))) + return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); + + } /* next var */ + } /* If PIO_TYPE_GDAL */ + return PIO_NOERR; +} + +/** + * The PIO-C interface for the GDAL function OGR_L_FindFieldIndex() + * + * This routine is called collectively by all tasks in the communicator + * ios.union_comm. + * + * @param ncid the ncid of the open file, obtained from + * GDALc_openfile() or GDALc_createfile(). + * @param name the field name. + * @param varidp a pointer that will get the variable id + * @return PIO_NOERR for success, error code otherwise. <> + * @ingroup PIO_inq_var_c + * @author Michael Long (adapted from Jim Edwards, Ed Hartnett) + */ +int +GDALc_inq_fieldid(int fileid, const char *name, int *fieldidp) +{ + iosystem_desc_t *ios; /* Pointer to io system information. */ + file_desc_t *file; /* Pointer to file information. */ + int ierr; /* Return code from function calls. */ + int mpierr = MPI_SUCCESS, mpierr2; /* Return code from MPI function codes. */ + + /* Get file info based on fileid. */ + if ((ierr = pio_get_file(fileid, &file))) + return pio_err(NULL, NULL, ierr, __FILE__, __LINE__); + ios = file->iosystem; + + /* Caller must provide name. */ + if (!name || strlen(name) > NC_MAX_NAME) + return pio_err(ios, file, PIO_EINVAL, __FILE__, __LINE__); + + PLOG((1, "GDALc_inq_fieldid fileid = %d name = %s", fileid, name)); + + if (ios->async) + { + if (!ios->ioproc) + { + int msg = PIO_MSG_INQ_VARID; + + if (ios->compmain == MPI_ROOT) + mpierr = MPI_Send(&msg, 1,MPI_INT, ios->ioroot, 1, ios->union_comm); + + if (!mpierr) + mpierr = MPI_Bcast(&fileid, 1, MPI_INT, ios->compmain, ios->intercomm); + int namelen; + namelen = strlen(name); + if (!mpierr) + mpierr = MPI_Bcast(&namelen, 1, MPI_INT, ios->compmain, ios->intercomm); + if (!mpierr) + mpierr = MPI_Bcast((void *)name, namelen + 1, MPI_CHAR, ios->compmain, ios->intercomm); + } + + /* Handle MPI errors. */ + if ((mpierr2 = MPI_Bcast(&mpierr, 1, MPI_INT, ios->comproot, ios->my_comm))) + check_mpi(NULL, file, mpierr2, __FILE__, __LINE__); + if (mpierr) + return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); + } + + /* If this is an IO task, then call the GDAL function. */ + if (ios->ioproc) + { + GDALDatasetH *hDS = file->hDS; + if (file->do_io) { // We assume that its a GDAL file + OGRLayerH hLayer = OGR_DS_GetLayer( hDS, 0 ); + OGR_L_ResetReading(hLayer); + if (hLayer == NULL) { + printf("Layer is NULL"); + return -1; + } + *fieldidp = OGR_L_FindFieldIndex(hLayer,name,1); + + pioassert(*fieldidp > 0, "variable not found", __FILE__, __LINE__); + + } + } + + /* Broadcast and check the return code. */ + if ((mpierr = MPI_Bcast(&ierr, 1, MPI_INT, ios->ioroot, ios->my_comm))) + return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); + if (ierr) + return check_netcdf(file, ierr, __FILE__, __LINE__); + + /* Broadcast results to all tasks. Ignore NULL parameters. */ + if (fieldidp) + if ((mpierr = MPI_Bcast(fieldidp, 1, MPI_INT, ios->ioroot, ios->my_comm))) + check_mpi(NULL, file, mpierr, __FILE__, __LINE__); + + return PIO_NOERR; +} + +int +GDALc_openfile(int iosysid, int *fileIDp, GDALDatasetH *hDSp,int *iotype, const char *filename, bool mode) +//GDALc_openfile(int iosysid, GDALDatasetH *hDSp, int *iotype, const char *filename, bool mode) +{ + iosystem_desc_t *ios; /* Pointer to io system information. */ + file_desc_t *file; /* Pointer to file information. */ + int imode; /* Internal mode val for netcdf4 file open. */ + int nvars = 0; + int *rec_var = NULL; + int *pio_type = NULL; + int *pio_type_size = NULL; + MPI_Datatype *mpi_type = NULL; + int *mpi_type_size = NULL; + int *ndims = NULL; + int mpierr = MPI_SUCCESS, mpierr2; /** Return code from MPI function codes. */ + int ierr = PIO_NOERR; /* Return code from function calls. */ + GDALDatasetH hDS; + +#ifdef USE_MPE + pio_start_mpe_log(OPEN); +#endif /* USE_MPE */ + + /* Get the IO system info from the iosysid. */ + if (!(ios = pio_get_iosystem_from_id(iosysid))) + return pio_err(NULL, NULL, PIO_EBADID, __FILE__, __LINE__); + + /* User must provide valid input for these parameters. */ + if (!hDSp || !iotype || !filename) + return pio_err(ios, NULL, PIO_EINVAL, __FILE__, __LINE__); + if (*iotype != PIO_IOTYPE_GDAL ) + return pio_err(ios, NULL, PIO_EINVAL, __FILE__, __LINE__); + +// PLOG((2, "PIOc_openfile_retry iosysid = %d iotype = %d filename = %s mode = %d retry = %d", +// iosysid, *iotype, filename, mode, retry)); + + /* Allocate space for the file info. */ + if (!(file = calloc(sizeof(*file), 1))) + return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__); + + /* Fill in some file values. */ + file->fh = -1; + file->iotype = *iotype; + file->iosystem = ios; + file->writable = (mode & PIO_WRITE) ? 1 : 0; + + /* Set to true if this task should participate in IO (only true + * for one task with netcdf serial files. */ + if (file->iotype == PIO_IOTYPE_GDAL || + ios->io_rank == 0) + file->do_io = 1; + + /* If async is in use, and this is not an IO task, bcast the parameters. */ + if (ios->async) + { + int msg = PIO_MSG_OPEN_FILE; + size_t len = strlen(filename); + + if (!ios->ioproc) + { + /* Send the message to the message handler. */ + if (ios->compmain == MPI_ROOT) + mpierr = MPI_Send(&msg, 1, MPI_INT, ios->ioroot, 1, ios->union_comm); + + /* Send the parameters of the function call. */ + if (!mpierr) + mpierr = MPI_Bcast(&len, 1, MPI_INT, ios->compmain, ios->intercomm); + if (!mpierr) + mpierr = MPI_Bcast((void *)filename, len + 1, MPI_CHAR, ios->compmain, ios->intercomm); + if (!mpierr) + mpierr = MPI_Bcast(&file->iotype, 1, MPI_INT, ios->compmain, ios->intercomm); + if (!mpierr) + mpierr = MPI_Bcast(&mode, 1, MPI_INT, ios->compmain, ios->intercomm); +//>> if (!mpierr) +//>> mpierr = MPI_Bcast(&use_ext_ncid, 1, MPI_INT, ios->compmain, ios->intercomm); + } + + /* Handle MPI errors. */ + if ((mpierr2 = MPI_Bcast(&mpierr, 1, MPI_INT, ios->comproot, ios->my_comm))) + return check_mpi(NULL, file, mpierr2, __FILE__, __LINE__); + if (mpierr) + return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); + } + + /* If this is an IO task, then call the netCDF function. */ + if (ios->ioproc) + { + switch (file->iotype) + { + case PIO_IOTYPE_GDAL: +// if (ios->io_rank == 0) + { + *hDSp = OGROpen( filename, FALSE, NULL ); + if( hDSp != NULL ) + + ierr = GDALc_inq_file_metadata(file, *hDSp, PIO_IOTYPE_GDAL, + &nvars, &rec_var, &pio_type, + &pio_type_size, &mpi_type, + &mpi_type_size, &ndims); + PLOG((2, "GDALc_openfile:OGROpen for filename = %s mode = %d " + "ierr = %d", filename, mode, ierr)); + } + break; + + default: + return pio_err(ios, file, PIO_EBADIOTYPE, __FILE__, __LINE__); + } + + } + + /* Broadcast and check the return code. */ + if (ios->ioroot == ios->union_rank) + PLOG((2, "Bcasting error code ierr %d ios->ioroot %d ios->my_comm %d", + ierr, ios->ioroot, ios->my_comm)); + if ((mpierr = MPI_Bcast(&ierr, 1, MPI_INT, ios->ioroot, ios->my_comm))) + return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); + PLOG((2, "Bcast openfile_retry error code ierr = %d", ierr)); + + /* If there was an error, free allocated memory and deal with the error. */ + if (ierr) + { + free(file); + return PIO_NOERR;// check_netcdf2(ios, NULL, ierr, __FILE__, __LINE__); + } + + /* Broadcast writability to all tasks. */ + if ((mpierr = MPI_Bcast(&file->writable, 1, MPI_INT, ios->ioroot, ios->my_comm))) + return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); + + /* Broadcast some values to all tasks from io root. */ +//>> if (ios->async) +//>> { +//>> PLOG((3, "open bcasting pio_next_ncid %d ios->ioroot %d", pio_next_ncid, ios->ioroot)); +//>> if ((mpierr = MPI_Bcast(&pio_next_ncid, 1, MPI_INT, ios->ioroot, ios->my_comm))) +//>> return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); +//>> } + + if ((mpierr = MPI_Bcast(&nvars, 1, MPI_INT, ios->ioroot, ios->my_comm))) + return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); + + /* Non io tasks need to allocate to store info about variables. */ + if (nvars && !rec_var) + { + if (!(rec_var = malloc(nvars * sizeof(int)))) + return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__); + if (!(pio_type = malloc(nvars * sizeof(int)))) + return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__); + if (!(pio_type_size = malloc(nvars * sizeof(int)))) + return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__); + if (!(mpi_type = malloc(nvars * sizeof(MPI_Datatype)))) + return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__); + if (!(mpi_type_size = malloc(nvars * sizeof(int)))) + return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__); + if (!(ndims = malloc(nvars * sizeof(int)))) + return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__); + } + if (nvars) + { + if ((mpierr = MPI_Bcast(rec_var, nvars, MPI_INT, ios->ioroot, ios->my_comm))) + return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); + if ((mpierr = MPI_Bcast(pio_type, nvars, MPI_INT, ios->ioroot, ios->my_comm))) + return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); + if ((mpierr = MPI_Bcast(pio_type_size, nvars, MPI_INT, ios->ioroot, ios->my_comm))) + return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); + if ((mpierr = MPI_Bcast(mpi_type, nvars*(int)(sizeof(MPI_Datatype)/sizeof(int)), MPI_INT, ios->ioroot, ios->my_comm))) + return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); + if ((mpierr = MPI_Bcast(mpi_type_size, nvars, MPI_INT, ios->ioroot, ios->my_comm))) + return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); + if ((mpierr = MPI_Bcast(ndims, nvars, MPI_INT, ios->ioroot, ios->my_comm))) + return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); + } + + file->hDS = *hDSp; + + /* Create the ncid/fileid that the user will see. This is necessary + * because otherwise ids will be reused if files are opened + * on multiple iosystems. */ + file->pio_ncid = pio_next_ncid++; + *fileIDp=file->pio_ncid; + + /* Add this file to the list of currently open files. */ + pio_add_to_file_list(file); + + /* Add info about the variables to the file_desc_t struct. */ + for (int v = 0; v < nvars; v++) + if ((ierr = add_to_varlist(v, rec_var[v], pio_type[v], pio_type_size[v], + mpi_type[v], mpi_type_size[v], ndims[v], + &file->varlist))) + return pio_err(ios, NULL, ierr, __FILE__, __LINE__); + file->nvars = nvars; + + /* Free resources. */ + if (nvars) + { + if (rec_var) + free(rec_var); + if (pio_type) + free(pio_type); + if (pio_type_size) + free(pio_type_size); + if (mpi_type) + free(mpi_type); + if (mpi_type_size) + free(mpi_type_size); + if (ndims) + free(ndims); + } + +#ifdef USE_MPE + pio_stop_mpe_log(OPEN, __func__); +#endif /* USE_MPE */ + PLOG((2, "Opened file %s file->pio_ncid = %d file->fh = %d ierr = %d", + filename, file->pio_ncid, file->fh, ierr)); + + return ierr; +} + +int +GDALc_sync(int fileid) { + iosystem_desc_t *ios; /* Pointer to io system information. */ + file_desc_t *file; /* Pointer to file information. */ + int mpierr = MPI_SUCCESS, mpierr2; /* Return code from MPI function codes. */ + int ierr = PIO_NOERR; /* Return code from function calls. */ +} + +int GDALc_inq_timeid(int fileid, int *timeid) { // Is there a field of type OFTDate, OFTTime, or OFTDateTime? + iosystem_desc_t *ios; /* Pointer to io system information. */ + file_desc_t *file; /* Pointer to file information. */ + int ierr = PIO_NOERR; /* Return code from function calls. */ + int mpierr = MPI_SUCCESS, mpierr2; /* Return code from MPI function codes. */ + + /* Get file info based on ncid. */ + if ((ierr = pio_get_file(fileid, &file))) + return pio_err(NULL, NULL, ierr, __FILE__, __LINE__); + ios = file->iosystem; + if (file->hDS == NULL) + return pio_err(NULL, NULL, ierr, __FILE__, __LINE__); + + GDALDatasetH *hDS = file->hDS; + OGRLayerH hLayer = OGR_DS_GetLayer( hDS, 0 ); + if (hLayer == NULL) + return pio_err(NULL, NULL, ierr, __FILE__, __LINE__); + OGR_L_ResetReading(hLayer); + + OGRFeatureDefnH hFD = OGR_L_GetLayerDefn(hLayer); + if (hFD == NULL) + return pio_err(NULL, NULL, ierr, __FILE__, __LINE__); + int nFld = OGR_FD_GetFieldCount(hFD); + OGRFieldDefnH hTMP = OGR_FD_GetFieldDefn(hFD,1); + hTMP = OGR_FD_GetFieldDefn(hFD,0); + + for (int i=0;i<(file->nvars)-1;i++) { + OGRFieldDefnH hFlD = OGR_FD_GetFieldDefn(hFD,i); + OGRFieldType Fld = OGR_Fld_GetType(hFlD); + if (Fld == NULL) + return pio_err(NULL, NULL, ierr, __FILE__, __LINE__); + +// const char* FldTyp = OGR_GetFieldTypeName(Fld); +// PRINTMSG("Field type: " << FldTyp); + } + +// OGR_FD_Destroy(hFD); + + return 0; + } + +/** + * Read an array of data from a file to the (serial) IO library. This + * function is only used with netCDF classic and netCDF-4 serial + * iotypes. + * + * @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 the buffer to be written from this mpi task. May be + * null. for example we have 8 ionodes and a distributed array with + * global size 4, then at least 4 nodes will have a null iobuf. In + * practice the box rearranger trys to have at least blocksize bytes + * on each io task and so if the total number of bytes to write is + * less than blocksize * numiotasks then some iotasks will have a NULL + * iobuf. + * @returns 0 for success, error code otherwise. + * @ingroup PIO_read_darray_c + * @author Jim Edwards, Ed Hartnett + */ +int +pio_read_darray_shp(file_desc_t *file, io_desc_t *iodesc, int vid, + void *iobuf) +{ + iosystem_desc_t *ios; /* Pointer to io system information. */ + var_desc_t *vdesc; /* Information about the variable. */ + int ndims; /* Number of dims in decomposition. */ + int fndims; /* Number of dims for this var in file. */ + MPI_Status status; + int mpierr; /* Return code from MPI functions. */ + int ierr; + + /* Check inputs. */ + pioassert(file && file->iosystem && iodesc && vid >= 0 && vid <= PIO_MAX_VARS, + "invalid input", __FILE__, __LINE__); + + PLOG((2, "pio_read_darray_shp vid = %d", vid)); + ios = file->iosystem; + +#ifdef TIMING + /* Start timer if desired. */ + if ((ierr = pio_start_timer("PIO:read_darray_shp"))) + return pio_err(ios, NULL, ierr, __FILE__, __LINE__); +#endif /* TIMING */ + + /* Get var info for this var. */ + if ((ierr = get_var_desc(vid, &file->varlist, &vdesc))) + return pio_err(NULL, file, ierr, __FILE__, __LINE__); + + /* Get the number of dims in our decomposition. */ + ndims = iodesc->ndims; + + /* Get number of dims for this var. */ + fndims = vdesc->ndims; + + /* If setframe was not called, use a default value of 0. This is + * required for backward compatibility. */ + if (fndims == ndims + 1 && vdesc->record < 0) + vdesc->record = 0; + PLOG((3, "fndims %d ndims %d vdesc->record %d vdesc->ndims %d", fndims, + ndims, vdesc->record, vdesc->ndims)); + + /* Confirm that we are being called with the correct ndims. */ + pioassert((fndims == ndims && vdesc->record < 0) || + (fndims == ndims + 1 && vdesc->record >= 0), + "unexpected record", __FILE__, __LINE__); + + if (ios->ioproc) + { + io_region *region; + size_t start[fndims]; + size_t count[fndims]; + size_t tmp_start[fndims * iodesc->maxregions]; + size_t tmp_count[fndims * iodesc->maxregions]; + size_t tmp_bufsize; + void *bufptr; + + /* buffer is incremented by byte and loffset is in terms of + the iodessc->mpitype so we need to multiply by the size of + the mpitype. */ + region = iodesc->firstregion; + + /* If setframe was not set before this call, assume a value of + * 0. This is required for backward compatibility. */ + if (fndims > ndims) + if (vdesc->record < 0) + vdesc->record = 0; + + /* Put together start/count arrays for all regions. */ + for (int regioncnt = 0; regioncnt < iodesc->maxregions; regioncnt++) + { + if (!region || iodesc->llen == 0) + { + /* Nothing to write for this region. */ + for (int i = 0; i < fndims; i++) + { + tmp_start[i + regioncnt * fndims] = 0; + tmp_count[i + regioncnt * fndims] = 0; + } + bufptr = NULL; + } + else + { + if (vdesc->record >= 0 && fndims > 1) + { + /* This is a record var. Find start for record dims. */ + tmp_start[regioncnt * fndims] = vdesc->record; + + /* Find start/count for all non-record dims. */ + for (int i = 1; i < fndims; i++) + { + tmp_start[i + regioncnt * fndims] = region->start[i - 1]; + tmp_count[i + regioncnt * fndims] = region->count[i - 1]; + } + + /* Set count for record dimension. */ + if (tmp_count[1 + regioncnt * fndims] > 0) + tmp_count[regioncnt * fndims] = 1; + } + else + { + /* Non-time dependent array */ + for (int i = 0; i < fndims; i++) + { + tmp_start[i + regioncnt * fndims] = region->start[i]; + tmp_count[i + regioncnt * fndims] = region->count[i]; + } + } + } + +#if PIO_ENABLE_LOGGING + /* Log arrays for debug purposes. */ + PLOG((3, "region = %d", region)); + for (int i = 0; i < fndims; i++) + PLOG((3, "tmp_start[%d] = %d tmp_count[%d] = %d", i + regioncnt * fndims, tmp_start[i + regioncnt * fndims], + i + regioncnt * fndims, tmp_count[i + regioncnt * fndims])); +#endif /* PIO_ENABLE_LOGGING */ + + /* Move to next region. */ + if (region) + region = region->next; + } /* next regioncnt */ + + /* IO tasks other than 0 send their starts/counts and data to + * IO task 0. */ + if (ios->io_rank > 0) + { + if ((mpierr = MPI_Send(&iodesc->llen, 1, MPI_OFFSET, 0, ios->io_rank, ios->io_comm))) + return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); + PLOG((3, "sent iodesc->llen = %d", iodesc->llen)); + + if (iodesc->llen > 0) + { + if ((mpierr = MPI_Send(&(iodesc->maxregions), 1, MPI_INT, 0, + ios->num_iotasks + ios->io_rank, ios->io_comm))) + return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); + if ((mpierr = MPI_Send(tmp_count, iodesc->maxregions * fndims, MPI_OFFSET, 0, + 2 * ios->num_iotasks + ios->io_rank, ios->io_comm))) + return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); + if ((mpierr = MPI_Send(tmp_start, iodesc->maxregions * fndims, MPI_OFFSET, 0, + 3 * ios->num_iotasks + ios->io_rank, ios->io_comm))) + return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); + PLOG((3, "sent iodesc->maxregions = %d tmp_count and tmp_start arrays", iodesc->maxregions)); + + if ((mpierr = MPI_Recv(iobuf, iodesc->llen, iodesc->mpitype, 0, + 4 * ios->num_iotasks + ios->io_rank, ios->io_comm, &status))) + return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); + PLOG((3, "received %d elements of data", iodesc->llen)); + } + } + else if (ios->io_rank == 0) + { + /* This is IO task 0. Get starts/counts and data from + * other IO tasks. */ + int maxregions = 0; + size_t loffset, regionsize; + size_t this_start[fndims * iodesc->maxregions]; + size_t this_count[fndims * iodesc->maxregions]; + + for (int rtask = 1; rtask <= ios->num_iotasks; rtask++) + { + if (rtask < ios->num_iotasks) + { + if ((mpierr = MPI_Recv(&tmp_bufsize, 1, MPI_OFFSET, rtask, rtask, ios->io_comm, &status))) + return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); + PLOG((3, "received tmp_bufsize = %d", tmp_bufsize)); + + if (tmp_bufsize > 0) + { + if ((mpierr = MPI_Recv(&maxregions, 1, MPI_INT, rtask, ios->num_iotasks + rtask, + ios->io_comm, &status))) + return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); + if ((mpierr = MPI_Recv(this_count, maxregions * fndims, MPI_OFFSET, rtask, + 2 * ios->num_iotasks + rtask, ios->io_comm, &status))) + return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); + if ((mpierr = MPI_Recv(this_start, maxregions * fndims, MPI_OFFSET, rtask, + 3 * ios->num_iotasks + rtask, ios->io_comm, &status))) + return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); + PLOG((3, "received maxregions = %d this_count, this_start arrays ", maxregions)); + } + } + else + { + maxregions = iodesc->maxregions; + tmp_bufsize = iodesc->llen; + } + PLOG((3, "maxregions = %d tmp_bufsize = %d", maxregions, tmp_bufsize)); + + /* Now get each region of data. */ + loffset = 0; + for (int regioncnt = 0; regioncnt < maxregions; regioncnt++) + { + /* Get pointer where data should go. */ + bufptr = (void *)((char *)iobuf + iodesc->mpitype_size * loffset); + regionsize = 1; + + /* ??? */ + if (rtask < ios->num_iotasks) + { + for (int m = 0; m < fndims; m++) + { + start[m] = this_start[m + regioncnt * fndims]; + count[m] = this_count[m + regioncnt * fndims]; + regionsize *= count[m]; + } + } + else + { + for (int m = 0; m < fndims; m++) + { + start[m] = tmp_start[m + regioncnt * fndims]; + count[m] = tmp_count[m + regioncnt * fndims]; + regionsize *= count[m]; + } + } + loffset += regionsize; + + /* Read the data. */ + /* ierr = nc_get_vara(file->fh, vid, start, count, bufptr); */ + switch (iodesc->piotype) + { + case PIO_BYTE: + return pio_err(ios, file, PIO_EBADTYPE, __FILE__, __LINE__); + case PIO_CHAR: + return pio_err(ios, file, PIO_EBADTYPE, __FILE__, __LINE__); + case PIO_SHORT: + return pio_err(ios, file, PIO_EBADTYPE, __FILE__, __LINE__); + case PIO_INT: + ierr = GDALc_shp_get_int_field(file->pio_ncid); + break; + case PIO_FLOAT: + return pio_err(ios, file, PIO_EBADTYPE, __FILE__, __LINE__); + case PIO_DOUBLE: + ierr = GDALc_shp_get_double_field(file->pio_ncid, vid, start, count, (double *)bufptr); + break; + default: + return pio_err(ios, file, PIO_EBADTYPE, __FILE__, __LINE__); + } + + /* Check error code of netCDF call. */ + if (ierr) + return check_netcdf(file, ierr, __FILE__, __LINE__); + } + + /* The decomposition may not use all of the active io + * tasks. rtask here is the io task rank and + * ios->num_iotasks is the number of iotasks actually + * used in this decomposition. */ + if (rtask < ios->num_iotasks && tmp_bufsize > 0){ + if ((mpierr = MPI_Send(iobuf, tmp_bufsize, iodesc->mpitype, rtask, + 4 * ios->num_iotasks + rtask, ios->io_comm))) + return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); + } + } + } + } + +#ifdef TIMING + if ((ierr = pio_stop_timer("PIO:read_darray_nc_serial"))) + return pio_err(ios, NULL, ierr, __FILE__, __LINE__); +#endif /* TIMING */ + + PLOG((2, "pio_read_darray_nc_serial complete ierr %d", ierr)); + return PIO_NOERR; +} + +int +GDALc_shp_get_int_field(int fileid) +{ + return PIO_NOERR; +} +int +GDALc_shp_get_double_field(int fileid, int varid, const size_t *startp, + const size_t *countp, double *ip) +{ + OGRFeatureH hF; + file_desc_t *file; /* Pointer to file information. */ + int ierr; + + /* Get file info based on fileid. */ + if ((ierr = pio_get_file(fileid, &file))) + return pio_err(NULL, NULL, ierr, __FILE__, __LINE__); + if (file->hDS == NULL) + return pio_err(NULL, NULL, ierr, __FILE__, __LINE__); + + OGRLayerH hL = OGR_DS_GetLayer( file->hDS, 0 ); + + // here, we have to assume start and count are only one dimension, and have + // only one assigned value. + for (size_t i = startp[0]; i Date: Fri, 5 Jan 2024 13:34:19 -0500 Subject: [PATCH 2/5] few fixes. Mainly isolating ops to io_rank=0 MSL --- src/clib/pio_file.c | 6 ++++-- src/clib/pio_gdal.c | 7 +++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/clib/pio_file.c b/src/clib/pio_file.c index 0b3dd7a389..328815a553 100644 --- a/src/clib/pio_file.c +++ b/src/clib/pio_file.c @@ -284,8 +284,10 @@ PIOc_closefile(int ncid) break; #endif case PIO_IOTYPE_GDAL: - ierr = GDALClose((void*)file->hDS); - printf("GDALClose ierr: %d\n",ierr); + if (ios->io_rank == 0) { + ierr = GDALClose((void*)file->hDS); + printf("GDALClose ierr: %d\n",ierr); + } break; default: return pio_err(ios, file, PIO_EBADIOTYPE, __FILE__, __LINE__); diff --git a/src/clib/pio_gdal.c b/src/clib/pio_gdal.c index 221af2694e..6e1b61b24f 100644 --- a/src/clib/pio_gdal.c +++ b/src/clib/pio_gdal.c @@ -251,8 +251,7 @@ GDALc_openfile(int iosysid, int *fileIDp, GDALDatasetH *hDSp,int *iotype, const /* Set to true if this task should participate in IO (only true * for one task with netcdf serial files. */ - if (file->iotype == PIO_IOTYPE_GDAL || - ios->io_rank == 0) + if (file->iotype == PIO_IOTYPE_GDAL && ios->io_rank == 0) file->do_io = 1; /* If async is in use, and this is not an IO task, bcast the parameters. */ @@ -293,7 +292,7 @@ GDALc_openfile(int iosysid, int *fileIDp, GDALDatasetH *hDSp,int *iotype, const switch (file->iotype) { case PIO_IOTYPE_GDAL: -// if (ios->io_rank == 0) + if (ios->io_rank == 0) { *hDSp = OGROpen( filename, FALSE, NULL ); if( hDSp != NULL ) @@ -751,7 +750,7 @@ pio_read_darray_shp(file_desc_t *file, io_desc_t *iodesc, int vid, return pio_err(ios, NULL, ierr, __FILE__, __LINE__); #endif /* TIMING */ - PLOG((2, "pio_read_darray_nc_serial complete ierr %d", ierr)); + PLOG((2, "pio_read_darray_shp complete ierr %d", ierr)); return PIO_NOERR; } From 87986f8a56cfcfbd75098e857f1e1bb144cc83ff Mon Sep 17 00:00:00 2001 From: Michael Long Date: Tue, 9 Jan 2024 11:09:12 -0500 Subject: [PATCH 3/5] Added GDAL test. Currently segfaulting in pio_swapm() MSL --- src/clib/pio_gdal.c | 1 + tests/cunit/CMakeLists.txt | 7 + tests/cunit/Makefile.am | 3 +- tests/cunit/data/cb_2018_us_region_20m.cpg | 1 + tests/cunit/data/cb_2018_us_region_20m.dbf | Bin 0 -> 830 bytes tests/cunit/data/cb_2018_us_region_20m.prj | 1 + tests/cunit/data/cb_2018_us_region_20m.shp | Bin 0 -> 112648 bytes .../data/cb_2018_us_region_20m.shp.ea.iso.gfs | 1 + .../data/cb_2018_us_region_20m.shp.ea.iso.xml | 254 +++++++++ .../data/cb_2018_us_region_20m.shp.iso.gfs | 1 + .../data/cb_2018_us_region_20m.shp.iso.xml | 531 ++++++++++++++++++ tests/cunit/data/cb_2018_us_region_20m.shx | Bin 0 -> 132 bytes tests/cunit/test_gdal.c | 307 ++++++++++ 13 files changed, 1106 insertions(+), 1 deletion(-) create mode 100644 tests/cunit/data/cb_2018_us_region_20m.cpg create mode 100644 tests/cunit/data/cb_2018_us_region_20m.dbf create mode 100644 tests/cunit/data/cb_2018_us_region_20m.prj create mode 100644 tests/cunit/data/cb_2018_us_region_20m.shp create mode 100644 tests/cunit/data/cb_2018_us_region_20m.shp.ea.iso.gfs create mode 100755 tests/cunit/data/cb_2018_us_region_20m.shp.ea.iso.xml create mode 100644 tests/cunit/data/cb_2018_us_region_20m.shp.iso.gfs create mode 100755 tests/cunit/data/cb_2018_us_region_20m.shp.iso.xml create mode 100644 tests/cunit/data/cb_2018_us_region_20m.shx create mode 100644 tests/cunit/test_gdal.c diff --git a/src/clib/pio_gdal.c b/src/clib/pio_gdal.c index 6e1b61b24f..d87146aa9d 100644 --- a/src/clib/pio_gdal.c +++ b/src/clib/pio_gdal.c @@ -781,6 +781,7 @@ GDALc_shp_get_double_field(int fileid, int varid, const size_t *startp, hF = OGR_L_GetFeature(hL,i); ip[i] = OGR_F_GetFieldAsDouble(hF,varid); + printf("<<>> ip[%d]=%f\n",i,ip[i]); } return PIO_NOERR; diff --git a/tests/cunit/CMakeLists.txt b/tests/cunit/CMakeLists.txt index dc9239816e..854dccf2c2 100644 --- a/tests/cunit/CMakeLists.txt +++ b/tests/cunit/CMakeLists.txt @@ -120,6 +120,8 @@ if (NOT PIO_USE_MPISERIAL) target_link_libraries (test_simple pioc) add_executable (test_async_perf EXCLUDE_FROM_ALL test_async_perf.c test_common.c) target_link_libraries(test_async_perf pioc) + add_executable (test_gdal EXCLUDE_FROM_ALL test_gdal.c test_common.c) + target_link_libraries (test_gdal pioc) endif () add_executable (test_spmd EXCLUDE_FROM_ALL test_spmd.c test_common.c) target_link_libraries (test_spmd pioc) @@ -154,6 +156,7 @@ add_dependencies (tests test_async_manyproc) add_dependencies (tests test_async_1d) add_dependencies (tests test_simple) add_dependencies (tests test_async_perf) +add_dependencies (tests test_gdal) # Test Timeout in seconds. if (PIO_VALGRIND_CHECK) @@ -341,5 +344,9 @@ else () # EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/test_async_perf # NUMPROCS ${EXACTLY_FOUR_TASKS} # TIMEOUT ${DEFAULT_TEST_TIMEOUT}) + add_mpi_test(test_gdal + EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/test_gdal + NUMPROCS ${EXACTLY_FOUR_TASKS} + TIMEOUT ${DEFAULT_TEST_TIMEOUT}) endif () MESSAGE("CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS}") diff --git a/tests/cunit/Makefile.am b/tests/cunit/Makefile.am index f7afb15a63..74610a86db 100644 --- a/tests/cunit/Makefile.am +++ b/tests/cunit/Makefile.am @@ -20,7 +20,7 @@ test_darray_async test_darray_async_many test_darray_2sync \ test_async_multicomp test_async_multi2 test_async_manyproc \ test_darray_fill test_decomp_frame test_perf2 test_async_perf \ test_darray_vard test_async_1d test_darray_append test_simple \ -test_darray_lossycompress +test_darray_lossycompress test_gdal if RUN_TESTS # Tests will run from a bash script. @@ -69,6 +69,7 @@ test_async_perf_SOURCES = test_async_perf.c test_common.c pio_tests.h test_darray_vard_SOURCES = test_darray_vard.c test_common.c pio_tests.h test_async_1d_SOURCES = test_async_1d.c pio_tests.h test_simple_SOURCES = test_simple.c test_common.c pio_tests.h +test_gdal_SOURCES = test_gdal.c test_common.c pio_tests.h # Distribute the test script. EXTRA_DIST = run_tests.sh.in CMakeLists.txt test_darray_frame.c diff --git a/tests/cunit/data/cb_2018_us_region_20m.cpg b/tests/cunit/data/cb_2018_us_region_20m.cpg new file mode 100644 index 0000000000..3ad133c048 --- /dev/null +++ b/tests/cunit/data/cb_2018_us_region_20m.cpg @@ -0,0 +1 @@ +UTF-8 \ No newline at end of file diff --git a/tests/cunit/data/cb_2018_us_region_20m.dbf b/tests/cunit/data/cb_2018_us_region_20m.dbf new file mode 100644 index 0000000000000000000000000000000000000000..e26408546ce0a1456d392706969715e1cab3150c GIT binary patch literal 830 zcmcJLO-sW-5QZD=Nl@>e<|piY?Z zAL^!#d3H|AZ@PY{aTBZG3spXR7)aN|LwqUsZT~O72Q*}IUTeha^3j}6Z=VfJ7wZ88 z1FQ3_Dw=*$LmJo^WCt|p5N+R&*VCjj07(afa0rf^kTL*zA;)B$A^{IN%=P7~IZwBk xc5>1olHeU$>)D2+!(zNxG%5~c&=EOIy_zJHbVS*bK_||70${Z29R(5%Pd{jzYLfr} literal 0 HcmV?d00001 diff --git a/tests/cunit/data/cb_2018_us_region_20m.prj b/tests/cunit/data/cb_2018_us_region_20m.prj new file mode 100644 index 0000000000..747df588c2 --- /dev/null +++ b/tests/cunit/data/cb_2018_us_region_20m.prj @@ -0,0 +1 @@ +GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137,298.257222101]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]] \ No newline at end of file diff --git a/tests/cunit/data/cb_2018_us_region_20m.shp b/tests/cunit/data/cb_2018_us_region_20m.shp new file mode 100644 index 0000000000000000000000000000000000000000..548ba7148df448d3e021dc35dd2a744f63072e83 GIT binary patch literal 112648 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
AhLKHN-<@)>nJc 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≀57f=2362`h)xVt4$0Q*g%# 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 cnKa&)yp#e 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 diff --git a/tests/cunit/data/cb_2018_us_region_20m.shp.ea.iso.xml b/tests/cunit/data/cb_2018_us_region_20m.shp.ea.iso.xml new file mode 100755 index 0000000000..544a798761 --- /dev/null +++ b/tests/cunit/data/cb_2018_us_region_20m.shp.ea.iso.xml @@ -0,0 +1,254 @@ + + + + Feature Catalog for the 2018 United States 1:20,000,000 Cartographic Boundary File + + + The Region at a scale of 1:20,000,000 + + + cb_2018_region_20m + + + 2019-05 + + + eng + + + utf8 + + + + + + + cb_2018_us_region_20m.shp + + + Current Region (national) + + + false + + + + + + REGIONCE + + + Current Census region code + + + + + + + 1 + + + Northeast + + + + + + + + 2 + + + Midwest + + + + + + + + 3 + + + South + + + + + + + + 4 + + + West + + + + + + + + + + AFFGEOID + + + American FactFinder summary level code + geovariant code + '00US' + GEOID + + + + + + + American FactFinder geographic identifier + + + + + + + + + + GEOID + + + Region code identifier, Census Region code + + + + + + + + Region code code found in REGIONCE + + + + + + + + + NAME + + + Current region name + + + + + + + Census geographic region names + + + + + + + + + + LSAD + + + Current legal/statistical area description code for region + + + + + + + 68 + + + Region (suffix) + + + + + + + + + + ALAND + + + Current land area (square meters) + + + + + + + + + + + + + + Range Domain Minimum: 0 + Range Domain Maximum: 9,999,999,999,999 + + + + + + + + + AWATER + + + Current water area (square meters) + + + + + + + + + + + + + + Range Domain Minimum: 0 + Range Domain Maximum: 9,999,999,999,999 + + + + + + + + \ No newline at end of file diff --git a/tests/cunit/data/cb_2018_us_region_20m.shp.iso.gfs b/tests/cunit/data/cb_2018_us_region_20m.shp.iso.gfs new file mode 100644 index 0000000000..2542326b9e --- /dev/null +++ b/tests/cunit/data/cb_2018_us_region_20m.shp.iso.gfs @@ -0,0 +1 @@ + diff --git a/tests/cunit/data/cb_2018_us_region_20m.shp.iso.xml b/tests/cunit/data/cb_2018_us_region_20m.shp.iso.xml new file mode 100755 index 0000000000..fda6aefe19 --- /dev/null +++ b/tests/cunit/data/cb_2018_us_region_20m.shp.iso.xml @@ -0,0 +1,531 @@ + + + + cb_2018_us_region_20m.shp.iso.xml + + + eng + + + UTF-8 + + + +dataset + + + + + 2019-05 + + + ISO 19115 Geographic Information - Metadata + + + 2009-02-15 + + + https://www2.census.gov/geo/tiger/GENZ2018/shp/cb_2018_us_region_20m.zip + + + + + + + + + complex + + + 4 + + + + + + + + + + + + + INCITS (formerly FIPS) codes + + + + + + + + + + + + + 2018 Cartographic Boundary File, Region for United States, 1:20,000,000 + + + + + + 2019-05 + + + publication + + + + + + + + + + + + The 2018 cartographic boundary shapefiles are simplified representations of selected geographic areas from the U.S. Census Bureau's Master Address File / Topologically Integrated Geographic Encoding and Referencing (MAF/TIGER) Database (MTDB). These boundary files are specifically designed for small-scale thematic mapping. When possible, generalization is performed with the intent to maintain the hierarchical relationships among geographies and to maintain the alignment of geographies within a file set for a given year. Geographic areas may not align with the same areas from another year. Some geographies are available as nation-based files while others are available only as state-based files. + +Regions are four groupings of states (Northeast, South, Midwest, and West) established by the Census Bureau in 1942 for the presentation of census data. + + + These files were specifically created to support small-scale thematic mapping. To improve the appearance of shapes at small scales, areas are represented with fewer vertices than detailed TIGER/Line Shapefiles. Cartographic boundary files take up less disk space than their ungeneralized counterparts. Cartographic boundary files take less time to render on screen than TIGER/Line Shapefiles. You can join this file with table data downloaded from American FactFinder by using the AFFGEOID field in the cartographic boundary file. If detailed boundaries are required, please use the TIGER/Line Shapefiles instead of the generalized cartographic boundary files. + + + + completed + + + + + + + + notPlanned + + + + + + + + Boundaries + + + theme + + + + + ISO 19115 Topic Categories + + + + + + + + + + 2018 + + + SHP + + + Cartographic Boundary + + + Generalized + + + Region + + + theme + + + + + None + + + + + + + + + + United States + + + US + + + place + + + + + ISO 3166 Codes for the representation of names of countries and their subdivisions + + + + + + + + + + otherRestrictions + + + + + + Access Constraints: None + + + Use Constraints:The intended display scale for this file is 1:20,000,000. This file should not be displayed at scales larger than 1:20,000,000. + +These products are free to use in a product or publication, however acknowledgement must be given to the U.S. Census Bureau as the source. The boundary information is for visual display at appropriate small scales only. Cartographic boundary files should not be used for geographic analysis including area or perimeter calculation. Files should not be used for geocoding addresses. Files should not be used for determining precise geographic area relationships. + + + + + + + vector + + + + + + + 20000000 + + + + + + + eng + + + + + + boundaries + + + The cartographic boundary files contain geographic data only and do not include display mapping software or statistical data. For information on how to use cartographic boundary file data with specific software package users shall contact the company that produced the software. + + + + + + + -179.174265 + + + 179.773922 + + + 17.913769 + + + 71.352561 + + + + + + + + publication date + 2019-05 + 2019-05 + + + + + + + + + + + + + true + + + + + Feature Catalog for the 2018 Region 1:20,000,000 Cartographic Boundary File + + + + + + + + + + + https://meta.geo.census.gov/data/existing/decennial/GEO/CPMB/boundary/2018cb/region_20m/2018_region_20m.ea.iso.xml + + + + + + + + + + + SHP + + + + PK-ZIP, version 1.93A or higher + + + + + + + HTML + + + + + + + + + + + The online cartographic boundary files may be downloaded without charge. + + + To obtain more information about ordering Cartographic Boundary Files visit https://www.census.gov/geo/www/tiger. + + + + + + + + + + + https://www2.census.gov/geo/tiger/GENZ2018/shp/cb_2018_us_region_20m.zip + + + Shapefile Zip File + + + + + + + + + + + https://www.census.gov/geo/maps-data/data/tiger-cart-boundary.html + + + Cartographic Boundary Shapefiles + + + Simplified representations of selected geographic areas from the Census Bureau's MAF/TIGER geographic database + + + + + + + + + + + + + dataset + + + + + + + Horizontal Positional Accuracy + + + + + + Data are not accurate. Data are generalized representations of geographic boundaries at 1:20,000,000. + + + + + + meters + + + + + Missing + + + + + + + + + The cartographic boundary files are generalized representations of extracts taken from the MAF/TIGER Database. Generalized boundary files are clipped to a simplified version of the U.S. outline. As a result, some off-shore areas may be excluded from the generalized files. Some small geographic areas, holes, or discontiguous parts of areas may not be included in generalized files if they are not visible at the target scale. + + + + + + + + The cartographic boundary files are generalized representations of extracts taken from the MAF/TIGER Database. Generalized boundary files are clipped to a simplified version of the U.S. outline. As a result, some off-shore areas may be excluded from the generalized files. Some small geographic areas, holes, or discontiguous parts of areas may not be included in generalized files if they are not visible at the target scale. + + + + + + + + The Census Bureau performed automated tests to ensure logical consistency of the source database. Segments making up the outer and inner boundaries of a polygon tie end-to-end to completely enclose the area. All polygons were tested for closure. The Census Bureau uses its internally developed geographic update system to enhance and modify spatial and attribute data in the Census MAF/TIGER database. Standard geographic codes, such as INCITS (formerly FIPS) codes for states, counties, municipalities, county subdivisions, places, American Indian/Alaska Native/Native Hawaiian areas, and congressional districts are used when encoding spatial entities. The Census Bureau performed spatial data tests for logical consistency of the codes during the compilation of the original Census MAF/TIGER database files. Feature attribute information has been examined but has not been fully tested for consistency. + +For the cartographic boundary files, the Point and Vector Object Count for the G-polygon SDTS Point and Vector Object Type reflects the number of records in the file's data table. For multi-polygon features, only one attribute record exists for each multi-polygon rather than one attribute record per individual G-polygon component of the multi-polygon feature. Cartographic Boundary File multi-polygons are an exception to the G-polygon object type classification. Therefore, when multi-polygons exist in a file, the object count will be less than the actual number of G-polygons. + + + + + + + + + + Spatial data were extracted from the MAF/TIGER database and processed through a U.S. Census Bureau batch generalization system. + + + 2019-05-01T00:00:00 + + + + + Geo-spatial Relational Database + + + + + Census MAF/TIGER database + + + MAF/TIGER + + + + + + U.S. Department of Commerce, U.S. Census Bureau, Geography Division, Geographic Customer Services Branch + + + originator + + + + + + Source Contribution: All spatial and feature data + + + + + + + + + + 201706 + 201805 + + + + + + + + + + + + + + + + + + + notPlanned + + + + This was transformed from the Census Metadata Import Format + + + + + \ No newline at end of file diff --git a/tests/cunit/data/cb_2018_us_region_20m.shx b/tests/cunit/data/cb_2018_us_region_20m.shx new file mode 100644 index 0000000000000000000000000000000000000000..9a8dbd4376bec4046a916d0d40b0561c14f9c650 GIT binary patch literal 132 zcmZQzQ0HR64xC;vGcd3M<<3+YPMMsVc0kF{k@x;9BZseF1b-Z^NOKT1V~&|{EzkkG jb`((~1_p^uK>UJ%L8FX;!7+(}!DIphL+LjLhBPh!epeN_ literal 0 HcmV?d00001 diff --git a/tests/cunit/test_gdal.c b/tests/cunit/test_gdal.c new file mode 100644 index 0000000000..9cf1d99d1c --- /dev/null +++ b/tests/cunit/test_gdal.c @@ -0,0 +1,307 @@ +/* + * Tests for PIO distributed arrays. + * + * @author Ed Hartnett + * @date 2/16/17 + */ +#include +#include +#include +#include + +/* The number of tasks this test should run on. */ +#define TARGET_NTASKS 4 + +/* The minimum number of tasks this test should run on. */ +#define MIN_NTASKS 4 + +/* The name of this test. */ +#define TEST_NAME "test_gdal" + +/* Number of processors that will do IO. */ +#define NUM_IO_PROCS 1 + +/* Number of computational components to create. */ +#define COMPONENT_COUNT 1 + +/* The number of dimensions in the example data. In this test, we + * are using three-dimensional data. */ +#define NDIM 1 + +/* But sometimes we need arrays of the non-record dimensions. */ +#define NDIM2 2 + +/* The length of our sample data along each dimension. */ +#define X_DIM_LEN 4 +#define Y_DIM_LEN 4 + +/* The number of timesteps of data to write. */ +#define NUM_TIMESTEPS 2 + +/* The names of variables in the netCDF output files. */ +#define VAR_NAME "Billy-Bob" +#define VAR_NAME2 "Sally-Sue" + +/* Test cases relating to PIOc_write_darray_multi(). */ +#define NUM_TEST_CASES_WRT_MULTI 3 + +/* Test with and without specifying a fill value to + * PIOc_write_darray(). */ +#define NUM_TEST_CASES_FILLVALUE 2 + +/* The dimension names. */ +//char dim_name[NDIM][PIO_MAX_NAME + 1] = {"timestep", "x", "y"}; + +/* Length of the dimensions in the sample data. */ +//int dim_len[NDIM] = {NC_UNLIMITED, X_DIM_LEN, Y_DIM_LEN}; + +/* Create a 1D decomposition. + * + * @param ntasks the number of available tasks + * @param my_rank rank of this task. + * @param iosysid the IO system ID. + * @param dim_len an array of length 3 with the dimension sizes. + * @param ioid a pointer that gets the ID of this decomposition. + * @param pio_type the type that will be used for basetype. + * @returns 0 for success, error code otherwise. + **/ +int create_decomposition_1d(int ntasks, int my_rank, int iosysid, int *ioid, int pio_type) +{ + PIO_Offset elements_per_pe; /* Array elements per processing unit. */ + int dim_len_1d[NDIM] = {X_DIM_LEN}; + int ret; + + /* How many data elements per task? In this example we will end up + * with 2. */ + elements_per_pe = X_DIM_LEN / ntasks; + + PIO_Offset compdof[elements_per_pe]; + + /* Don't forget to add 1! */ + compdof[0] = my_rank + 1; + + /* This means fill value will be used here. */ + compdof[1] = 0; + + /* Create the PIO decomposition for this test. */ + if ((ret = PIOc_InitDecomp(iosysid, pio_type, NDIM, dim_len_1d, elements_per_pe, + compdof, ioid, NULL, NULL, NULL))) + ERR(ret); + + return 0; +} + +/** + * Test the darray functionality. Create a netCDF file with 3 + * dimensions and 1 PIO_INT variable, and use darray to write some + * data. + * + * @param iosysid the IO system ID. + * @param ioid the ID of the decomposition. + * @param num_flavors the number of IOTYPES available in this build. + * @param flavor array of available iotypes. + * @param my_rank rank of this task. + * @param pio_type the type of the data. + * @returns 0 for success, error code otherwise. + */ +int test_gdal(int iosysid, int ioid, int num_flavors, int *flavor, int my_rank, + int pio_type) +{ + char filename[PIO_MAX_NAME + 1]; /* Name for the output files. */ + int dimids[NDIM]; /* The dimension IDs. */ + int ncid; /* The ncid of the netCDF file. */ + int ncid2; /* The ncid of the re-opened netCDF file. */ + int varid; /* The ID of the netCDF varable. */ + int varid2; /* The ID of a netCDF varable of different type. */ + int wrong_varid = TEST_VAL_42; /* A wrong ID. */ + int ret; /* Return code. */ + MPI_Datatype mpi_type; + int type_size; /* size of a variable of type pio_type */ + int other_type; /* another variable of the same size but different type */ + PIO_Offset arraylen = 4; + void *fillvalue, *ofillvalue; + void *test_data; + void *test_data_in; + int fillvalue_int = NC_FILL_INT; + int test_data_int[arraylen]; + int test_data_int_in[arraylen]; + float fillvalue_float = NC_FILL_FLOAT; + float test_data_float[arraylen]; + float test_data_float_in[arraylen]; + double fillvalue_double = NC_FILL_DOUBLE; + double test_data_double[arraylen]; + double test_data_double_in[arraylen]; + int iotype = PIO_IOTYPE_GDAL; + + GDALDatasetH hDSp; + + /* Initialize some data. */ + for (int f = 0; f < arraylen; f++) + { + test_data_int[f] = my_rank * 10 + f; + test_data_float[f] = my_rank * 10 + f + 0.5; + test_data_double[f] = my_rank * 100000 + f + 0.5; + } + + /* Use PIO to create the example file in each of the four + * available ways. */ + for (int fmt = 0; fmt < num_flavors; fmt++) + { + + /* Add a couple of extra tests for the + * PIOc_write_darray_multi() function. */ + for (int test_multi = 0; test_multi < NUM_TEST_CASES_WRT_MULTI; test_multi++) + { + sprintf(filename, "data/cb_2018_us_region_20m.shp"); + + /* Open the file. */ + if ((ret = GDALc_openfile(iosysid, &ncid2, &hDSp, &iotype, filename, PIO_NOWRITE))) + ERR(ret); + + if ((ret = GDALc_inq_fieldid(ncid2, "GEOID", &varid))) + ERR(ret); + + /* Read the data. */ + if ((ret = PIOc_read_darray(ncid2, varid, ioid, arraylen, test_data_in))) + ERR(ret); + + /* Check the results. */ +// TEMPORARILY DISABLED UNTIL A SEGFAULT IS DIAGNOSED +// for (int f = 0; f < arraylen; f++) +// { +// switch (pio_type) +// { +// case PIO_INT: +// if (test_data_int_in[f] != test_data_int[f]) +// return ERR_WRONG; +// break; +// case PIO_FLOAT: +// if (test_data_float_in[f] != test_data_float[f]) +// return ERR_WRONG; +// break; +// case PIO_DOUBLE: +// if (test_data_double_in[f] != test_data_double[f]) +// return ERR_WRONG; +// break; +// default: +// ERR(ERR_WRONG); +// } +// } + + /* Close the netCDF file. */ + if ((ret = PIOc_closefile(ncid2))) + ERR(ret); + } /* next test multi */ + } /* next iotype */ + + return PIO_NOERR; +} + +/** + * Run all the tests. + * + * @param iosysid the IO system ID. + * @param num_flavors number of available iotypes in the build. + * @param flavor pointer to array of the available iotypes. + * @param my_rank rank of this task. + * @param test_comm the communicator the test is running on. + * @returns 0 for success, error code otherwise. + */ +int test_all_gdal(int iosysid, int num_flavors, int *flavor, int my_rank, + MPI_Comm test_comm) +{ +#define NUM_TYPES_TO_TEST 1 + int ioid; + char filename[PIO_MAX_NAME + 1]; + int pio_type[NUM_TYPES_TO_TEST] = {PIO_DOUBLE}; + int dim_len_1d[NDIM] = {X_DIM_LEN};//, Y_DIM_LEN}; + int ret; /* Return code. */ + + for (int t = 0; t < NUM_TYPES_TO_TEST; t++) + { +// /* This will be our file name for writing out decompositions. */ +// sprintf(filename, "%s_decomp_rank_%d_flavor_%d_type_%d.nc", TEST_NAME, my_rank, +// *flavor, pio_type[t]); + + /* Decompose the data over the tasks. */ + if ((ret = create_decomposition_1d(TARGET_NTASKS, my_rank, iosysid, + &ioid, pio_type[t]))) + return ret; + + printf("my_rank %d iosysid %d ioid %d ret %d\n",my_rank, iosysid, ioid, ret); + + /* Run a simple darray test. */ + if ((ret = test_gdal(iosysid, ioid, num_flavors, flavor, my_rank, pio_type[t]))) + return ret; + + /* Free the PIO decomposition. */ + if ((ret = PIOc_freedecomp(iosysid, ioid))) + ERR(ret); + } + + return PIO_NOERR; +} + +/* Run tests for darray functions. */ +int main(int argc, char **argv) +{ +#define NUM_REARRANGERS_TO_TEST 2 + int rearranger[NUM_REARRANGERS_TO_TEST] = {PIO_REARR_BOX, PIO_REARR_SUBSET}; + int my_rank; + int ntasks; + int num_flavors; /* Number of PIO netCDF flavors in this build. */ + int flavor[NUM_FLAVORS]; /* iotypes for the supported netCDF IO flavors. */ + MPI_Comm test_comm; /* A communicator for this test. */ + int ret; /* Return code. */ + + OGRRegisterAll(); + + /* Initialize test. */ + if ((ret = pio_test_init2(argc, argv, &my_rank, &ntasks, MIN_NTASKS, + MIN_NTASKS, -1, &test_comm))) + ERR(ERR_INIT); + + PIOc_set_log_level(4); + + if ((ret = PIOc_set_iosystem_error_handling(PIO_DEFAULT, PIO_RETURN_ERROR, NULL))) + return ret; + + /* Only do something on max_ntasks tasks. */ + if (my_rank < TARGET_NTASKS) + { + int iosysid; /* The ID for the parallel I/O system. */ + int ioproc_stride = 1; /* Stride in the mpi rank between io tasks. */ + int ioproc_start = 0; /* Zero based rank of first processor to be used for I/O. */ + int ret; /* Return code. */ + + /* Figure out iotypes. */ + if ((ret = get_iotypes(&num_flavors, flavor))) + ERR(ret); + + for (int r = 0; r < NUM_REARRANGERS_TO_TEST; r++) + { + /* Initialize the PIO IO system. This specifies how + * many and which processors are involved in I/O. */ + if ((ret = PIOc_Init_Intracomm(test_comm, TARGET_NTASKS, ioproc_stride, + ioproc_start, rearranger[r], &iosysid))) + return ret; + + /* Run tests. */ + if ((ret = test_all_gdal(iosysid, num_flavors, flavor, my_rank, test_comm))) + return ret; + + /* Finalize PIO system. */ + if ((ret = PIOc_free_iosystem(iosysid))) + return ret; + } /* next rearranger */ + } /* endif my_rank < TARGET_NTASKS */ + + /* Finalize the MPI library. */ + if ((ret = pio_test_finalize(&test_comm))) + return ret; + /* if ((ret = pio_test_finalize2(&test_comm, TEST_NAME))) */ + /* return ret; */ + + printf("%d %s SUCCESS!!\n", my_rank, TEST_NAME); + return 0; +} From 1b397a45979f1c0ba605adae5f13aa2350df2ff1 Mon Sep 17 00:00:00 2001 From: Michael Long Date: Tue, 23 Jan 2024 11:51:18 -0500 Subject: [PATCH 4/5] fix for segfault. test_data_in pointer was NULL in test_gdal.c --- tests/cunit/test_gdal.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/cunit/test_gdal.c b/tests/cunit/test_gdal.c index 9cf1d99d1c..f9096ab053 100644 --- a/tests/cunit/test_gdal.c +++ b/tests/cunit/test_gdal.c @@ -154,6 +154,7 @@ int test_gdal(int iosysid, int ioid, int num_flavors, int *flavor, int my_rank, { sprintf(filename, "data/cb_2018_us_region_20m.shp"); + test_data_in = test_data_float_in; /* Open the file. */ if ((ret = GDALc_openfile(iosysid, &ncid2, &hDSp, &iotype, filename, PIO_NOWRITE))) ERR(ret); From bbda042ea978c3a816e6ee2b95b98c95ab259509 Mon Sep 17 00:00:00 2001 From: Michael Long Date: Thu, 7 Mar 2024 17:43:43 -0500 Subject: [PATCH 5/5] Fixed float type issues with GDAL/SHP read. Now can read vars of type ESMF_TYPEKIND_R4. MSL --- src/clib/pio.h | 1 + src/clib/pio_gdal.c | 31 +++++++++++++++++++++++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/clib/pio.h b/src/clib/pio.h index 8a628b5499..e4bd33ed5e 100644 --- a/src/clib/pio.h +++ b/src/clib/pio.h @@ -1375,6 +1375,7 @@ extern "C" { int GDALc_openfile(int iosysid, int *fileIDp, GDALDatasetH *hDSp, int *iotype, const char *fname, bool mode); int GDALc_sync(int fileid); int GDALc_shp_get_int_field(int fileid); + int GDALc_shp_get_float_field(int fileid, int varid, const size_t *startp, const size_t *countp, float *ip); int GDALc_shp_get_double_field(int fileid, int varid, const size_t *startp, const size_t *countp, double *ip); #if defined(__cplusplus) diff --git a/src/clib/pio_gdal.c b/src/clib/pio_gdal.c index 6e1b61b24f..7768e50f27 100644 --- a/src/clib/pio_gdal.c +++ b/src/clib/pio_gdal.c @@ -68,7 +68,8 @@ GDALc_inq_file_metadata(file_desc_t *file, GDALDatasetH hDS, int iotype, int *nv (*ndims)[v] = var_ndims; //>> if ((ret = nc_inq_var(ncid, v, NULL, &my_type, &var_ndims, NULL, NULL))) //>> return pio_err(NULL, file, ret, __FILE__, __LINE__); - OGRFieldType Fld = OGR_Fld_GetType(OGR_FD_GetFieldDefn(hFD,v)); + OGRFieldType Fld = OGR_Fld_GetType(OGR_FD_GetFieldDefn(hFD,v)); + bool typeOK = true; // assume we're good switch (Fld) { case OFTReal: @@ -719,7 +720,8 @@ pio_read_darray_shp(file_desc_t *file, io_desc_t *iodesc, int vid, ierr = GDALc_shp_get_int_field(file->pio_ncid); break; case PIO_FLOAT: - return pio_err(ios, file, PIO_EBADTYPE, __FILE__, __LINE__); + ierr = GDALc_shp_get_float_field(file->pio_ncid, vid, start, count, (float *)bufptr); + break; case PIO_DOUBLE: ierr = GDALc_shp_get_double_field(file->pio_ncid, vid, start, count, (double *)bufptr); break; @@ -785,6 +787,31 @@ GDALc_shp_get_double_field(int fileid, int varid, const size_t *startp, return PIO_NOERR; } +GDALc_shp_get_float_field(int fileid, int varid, const size_t *startp, + const size_t *countp, float *ip) +{ + OGRFeatureH hF; + file_desc_t *file; /* Pointer to file information. */ + int ierr; + + /* Get file info based on fileid. */ + if ((ierr = pio_get_file(fileid, &file))) + return pio_err(NULL, NULL, ierr, __FILE__, __LINE__); + if (file->hDS == NULL) + return pio_err(NULL, NULL, ierr, __FILE__, __LINE__); + + OGRLayerH hL = OGR_DS_GetLayer( file->hDS, 0 ); + + // here, we have to assume start and count are only one dimension, and have + // only one assigned value. + for (size_t i = startp[0]; i