/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Copyright by The HDF Group.                                               *
 * All rights reserved.                                                      *
 *                                                                           *
 * This file is part of HDF5.  The full HDF5 copyright notice, including     *
 * terms governing use, modification, and redistribution, is contained in    *
 * the COPYING file, which can be found at the root of the source code       *
 * distribution tree, or in https://www.hdfgroup.org/licenses.               *
 * If you do not have access to either file, you may request a copy from     *
 * help@hdfgroup.org.                                                        *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/*
   This program will test independent and collective reads and writes between
   selections of different rank that non-the-less are deemed as having the
   same shape by H5Sselect_shape_same().
 */

#define H5S_FRIEND /*suppress error about including H5Spkg   */

/* Define this macro to indicate that the testing APIs should be available */
#define H5S_TESTING

#include "H5Spkg.h" /* Dataspaces                           */
#include "testphdf5.h"

#ifndef PATH_MAX
#define PATH_MAX 512
#endif

/* FILENAME and filenames must have the same number of names.
 * Use PARATESTFILE in general and use a separated filename only if the file
 * created in one test is accessed by a different test.
 * filenames[0] is reserved as the file name for PARATESTFILE.
 */
#define NFILENAME    2
#define PARATESTFILE filenames[0]
const char *FILENAME[NFILENAME] = {"ShapeSameTest", NULL};
char       *filenames[NFILENAME];
hid_t       fapl; /* file access property list */

/* On Lustre (and perhaps other parallel file systems?), we have severe
 * slow downs if two or more processes attempt to access the same file system
 * block.  To minimize this problem, we set alignment in the shape same tests
 * to the default Lustre block size -- which greatly reduces contention in
 * the chunked dataset case.
 */

#define SHAPE_SAME_TEST_ALIGNMENT ((hsize_t)(4 * 1024 * 1024))

#define PAR_SS_DR_MAX_RANK 5 /* must update code if this changes */

struct hs_dr_pio_test_vars_t {
    int       mpi_size;
    int       mpi_rank;
    MPI_Comm  mpi_comm;
    MPI_Info  mpi_info;
    int       test_num;
    int       edge_size;
    int       checker_edge_size;
    int       chunk_edge_size;
    int       small_rank;
    int       large_rank;
    hid_t     dset_type;
    uint32_t *small_ds_buf_0;
    uint32_t *small_ds_buf_1;
    uint32_t *small_ds_buf_2;
    uint32_t *small_ds_slice_buf;
    uint32_t *large_ds_buf_0;
    uint32_t *large_ds_buf_1;
    uint32_t *large_ds_buf_2;
    uint32_t *large_ds_slice_buf;
    int       small_ds_offset;
    int       large_ds_offset;
    hid_t     fid; /* HDF5 file ID */
    hid_t     xfer_plist;
    hid_t     full_mem_small_ds_sid;
    hid_t     full_file_small_ds_sid;
    hid_t     mem_small_ds_sid;
    hid_t     file_small_ds_sid_0;
    hid_t     file_small_ds_sid_1;
    hid_t     small_ds_slice_sid;
    hid_t     full_mem_large_ds_sid;
    hid_t     full_file_large_ds_sid;
    hid_t     mem_large_ds_sid;
    hid_t     file_large_ds_sid_0;
    hid_t     file_large_ds_sid_1;
    hid_t     file_large_ds_process_slice_sid;
    hid_t     mem_large_ds_process_slice_sid;
    hid_t     large_ds_slice_sid;
    hid_t     small_dataset; /* Dataset ID */
    hid_t     large_dataset; /* Dataset ID */
    size_t    small_ds_size;
    size_t    small_ds_slice_size;
    size_t    large_ds_size;
    size_t    large_ds_slice_size;
    hsize_t   dims[PAR_SS_DR_MAX_RANK];
    hsize_t   chunk_dims[PAR_SS_DR_MAX_RANK];
    hsize_t   start[PAR_SS_DR_MAX_RANK];
    hsize_t   stride[PAR_SS_DR_MAX_RANK];
    hsize_t   count[PAR_SS_DR_MAX_RANK];
    hsize_t   block[PAR_SS_DR_MAX_RANK];
    hsize_t  *start_ptr;
    hsize_t  *stride_ptr;
    hsize_t  *count_ptr;
    hsize_t  *block_ptr;
    int       skips;
    int       max_skips;
    int64_t   total_tests;
    int64_t   tests_run;
    int64_t   tests_skipped;
};

/*-------------------------------------------------------------------------
 * Function:    hs_dr_pio_test__setup()
 *
 * Purpose:    Do setup for tests of I/O to/from hyperslab selections of
 *         different rank in the parallel case.
 *
 * Return:    void
 *
 *-------------------------------------------------------------------------
 */

#define CONTIG_HS_DR_PIO_TEST__SETUP__DEBUG 0

static void
hs_dr_pio_test__setup(const int test_num, const int edge_size, const int checker_edge_size,
                      const int chunk_edge_size, const int small_rank, const int large_rank,
                      const bool use_collective_io, const hid_t dset_type, const int express_test,
                      struct hs_dr_pio_test_vars_t *tv_ptr)
{
#if CONTIG_HS_DR_PIO_TEST__SETUP__DEBUG
    const char *fcnName = "hs_dr_pio_test__setup()";
#endif /* CONTIG_HS_DR_PIO_TEST__SETUP__DEBUG */
    const char *filename;
    bool        mis_match = false;
    int         i;
    int         mrc;
    int         mpi_rank; /* needed by the VRFY macro */
    uint32_t    expected_value;
    uint32_t   *ptr_0;
    uint32_t   *ptr_1;
    hid_t       acc_tpl; /* File access templates */
    hid_t       small_ds_dcpl_id = H5P_DEFAULT;
    hid_t       large_ds_dcpl_id = H5P_DEFAULT;
    herr_t      ret; /* Generic return value */

    assert(edge_size >= 6);
    assert(edge_size >= chunk_edge_size);
    assert((chunk_edge_size == 0) || (chunk_edge_size >= 3));
    assert(1 < small_rank);
    assert(small_rank < large_rank);
    assert(large_rank <= PAR_SS_DR_MAX_RANK);

    tv_ptr->test_num          = test_num;
    tv_ptr->edge_size         = edge_size;
    tv_ptr->checker_edge_size = checker_edge_size;
    tv_ptr->chunk_edge_size   = chunk_edge_size;
    tv_ptr->small_rank        = small_rank;
    tv_ptr->large_rank        = large_rank;
    tv_ptr->dset_type         = dset_type;

    MPI_Comm_size(MPI_COMM_WORLD, &(tv_ptr->mpi_size));
    MPI_Comm_rank(MPI_COMM_WORLD, &(tv_ptr->mpi_rank));
    /* the VRFY() macro needs the local variable mpi_rank -- set it up now */
    mpi_rank = tv_ptr->mpi_rank;

    assert(tv_ptr->mpi_size >= 1);

    tv_ptr->mpi_comm = MPI_COMM_WORLD;
    tv_ptr->mpi_info = MPI_INFO_NULL;

    for (i = 0; i < tv_ptr->small_rank - 1; i++) {
        tv_ptr->small_ds_size *= (size_t)(tv_ptr->edge_size);
        tv_ptr->small_ds_slice_size *= (size_t)(tv_ptr->edge_size);
    }
    tv_ptr->small_ds_size *= (size_t)(tv_ptr->mpi_size + 1);

    /* used by checker board tests only */
    tv_ptr->small_ds_offset = PAR_SS_DR_MAX_RANK - tv_ptr->small_rank;

    assert(0 < tv_ptr->small_ds_offset);
    assert(tv_ptr->small_ds_offset < PAR_SS_DR_MAX_RANK);

    for (i = 0; i < tv_ptr->large_rank - 1; i++) {

        tv_ptr->large_ds_size *= (size_t)(tv_ptr->edge_size);
        tv_ptr->large_ds_slice_size *= (size_t)(tv_ptr->edge_size);
    }
    tv_ptr->large_ds_size *= (size_t)(tv_ptr->mpi_size + 1);

    /* used by checker board tests only */
    tv_ptr->large_ds_offset = PAR_SS_DR_MAX_RANK - tv_ptr->large_rank;

    assert(0 <= tv_ptr->large_ds_offset);
    assert(tv_ptr->large_ds_offset < PAR_SS_DR_MAX_RANK);

    /* set up the start, stride, count, and block pointers */
    /* used by contiguous tests only */
    tv_ptr->start_ptr  = &(tv_ptr->start[PAR_SS_DR_MAX_RANK - tv_ptr->large_rank]);
    tv_ptr->stride_ptr = &(tv_ptr->stride[PAR_SS_DR_MAX_RANK - tv_ptr->large_rank]);
    tv_ptr->count_ptr  = &(tv_ptr->count[PAR_SS_DR_MAX_RANK - tv_ptr->large_rank]);
    tv_ptr->block_ptr  = &(tv_ptr->block[PAR_SS_DR_MAX_RANK - tv_ptr->large_rank]);

    /* Allocate buffers */
    tv_ptr->small_ds_buf_0 = (uint32_t *)malloc(sizeof(uint32_t) * tv_ptr->small_ds_size);
    VRFY((tv_ptr->small_ds_buf_0 != NULL), "malloc of small_ds_buf_0 succeeded");

    tv_ptr->small_ds_buf_1 = (uint32_t *)malloc(sizeof(uint32_t) * tv_ptr->small_ds_size);
    VRFY((tv_ptr->small_ds_buf_1 != NULL), "malloc of small_ds_buf_1 succeeded");

    tv_ptr->small_ds_buf_2 = (uint32_t *)malloc(sizeof(uint32_t) * tv_ptr->small_ds_size);
    VRFY((tv_ptr->small_ds_buf_2 != NULL), "malloc of small_ds_buf_2 succeeded");

    tv_ptr->small_ds_slice_buf = (uint32_t *)malloc(sizeof(uint32_t) * tv_ptr->small_ds_slice_size);
    VRFY((tv_ptr->small_ds_slice_buf != NULL), "malloc of small_ds_slice_buf succeeded");

    tv_ptr->large_ds_buf_0 = (uint32_t *)malloc(sizeof(uint32_t) * tv_ptr->large_ds_size);
    VRFY((tv_ptr->large_ds_buf_0 != NULL), "malloc of large_ds_buf_0 succeeded");

    tv_ptr->large_ds_buf_1 = (uint32_t *)malloc(sizeof(uint32_t) * tv_ptr->large_ds_size);
    VRFY((tv_ptr->large_ds_buf_1 != NULL), "malloc of large_ds_buf_1 succeeded");

    tv_ptr->large_ds_buf_2 = (uint32_t *)malloc(sizeof(uint32_t) * tv_ptr->large_ds_size);
    VRFY((tv_ptr->large_ds_buf_2 != NULL), "malloc of large_ds_buf_2 succeeded");

    tv_ptr->large_ds_slice_buf = (uint32_t *)malloc(sizeof(uint32_t) * tv_ptr->large_ds_slice_size);
    VRFY((tv_ptr->large_ds_slice_buf != NULL), "malloc of large_ds_slice_buf succeeded");

    /* initialize the buffers */

    ptr_0 = tv_ptr->small_ds_buf_0;
    for (i = 0; i < (int)(tv_ptr->small_ds_size); i++)
        *ptr_0++ = (uint32_t)i;
    memset(tv_ptr->small_ds_buf_1, 0, sizeof(uint32_t) * tv_ptr->small_ds_size);
    memset(tv_ptr->small_ds_buf_2, 0, sizeof(uint32_t) * tv_ptr->small_ds_size);

    memset(tv_ptr->small_ds_slice_buf, 0, sizeof(uint32_t) * tv_ptr->small_ds_slice_size);

    ptr_0 = tv_ptr->large_ds_buf_0;
    for (i = 0; i < (int)(tv_ptr->large_ds_size); i++)
        *ptr_0++ = (uint32_t)i;
    memset(tv_ptr->large_ds_buf_1, 0, sizeof(uint32_t) * tv_ptr->large_ds_size);
    memset(tv_ptr->large_ds_buf_2, 0, sizeof(uint32_t) * tv_ptr->large_ds_size);

    memset(tv_ptr->large_ds_slice_buf, 0, sizeof(uint32_t) * tv_ptr->large_ds_slice_size);

    filename = (const char *)GetTestParameters();
    assert(filename != NULL);
#if CONTIG_HS_DR_PIO_TEST__SETUP__DEBUG
    if (MAINPROCESS) {

        fprintf(stdout, "%d: test num = %d.\n", tv_ptr->mpi_rank, tv_ptr->test_num);
        fprintf(stdout, "%d: mpi_size = %d.\n", tv_ptr->mpi_rank, tv_ptr->mpi_size);
        fprintf(stdout, "%d: small/large rank = %d/%d, use_collective_io = %d.\n", tv_ptr->mpi_rank,
                tv_ptr->small_rank, tv_ptr->large_rank, (int)use_collective_io);
        fprintf(stdout, "%d: edge_size = %d, chunk_edge_size = %d.\n", tv_ptr->mpi_rank, tv_ptr->edge_size,
                tv_ptr->chunk_edge_size);
        fprintf(stdout, "%d: checker_edge_size = %d.\n", tv_ptr->mpi_rank, tv_ptr->checker_edge_size);
        fprintf(stdout, "%d: small_ds_size = %d, large_ds_size = %d.\n", tv_ptr->mpi_rank,
                (int)(tv_ptr->small_ds_size), (int)(tv_ptr->large_ds_size));
        fprintf(stdout, "%d: filename = %s.\n", tv_ptr->mpi_rank, filename);
    }
#endif /* CONTIG_HS_DR_PIO_TEST__SETUP__DEBUG */
    /* ----------------------------------------
     * CREATE AN HDF5 FILE WITH PARALLEL ACCESS
     * ---------------------------------------*/
    /* setup file access template */
    acc_tpl = create_faccess_plist(tv_ptr->mpi_comm, tv_ptr->mpi_info, facc_type);
    VRFY((acc_tpl >= 0), "create_faccess_plist() succeeded");

    /* set the alignment -- need it large so that we aren't always hitting the
     * the same file system block.  Do this only if express_test is greater
     * than zero.
     */
    if (express_test > 0) {

        ret = H5Pset_alignment(acc_tpl, (hsize_t)0, SHAPE_SAME_TEST_ALIGNMENT);
        VRFY((ret != FAIL), "H5Pset_alignment() succeeded");
    }

    /* create the file collectively */
    tv_ptr->fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, acc_tpl);
    VRFY((tv_ptr->fid >= 0), "H5Fcreate succeeded");

    MESG("File opened.");

    /* Release file-access template */
    ret = H5Pclose(acc_tpl);
    VRFY((ret >= 0), "H5Pclose(acc_tpl) succeeded");

    /* setup dims: */
    tv_ptr->dims[0] = (hsize_t)(tv_ptr->mpi_size + 1);
    tv_ptr->dims[1] = tv_ptr->dims[2] = tv_ptr->dims[3] = tv_ptr->dims[4] = (hsize_t)(tv_ptr->edge_size);

    /* Create small ds dataspaces */
    tv_ptr->full_mem_small_ds_sid = H5Screate_simple(tv_ptr->small_rank, tv_ptr->dims, NULL);
    VRFY((tv_ptr->full_mem_small_ds_sid != 0), "H5Screate_simple() full_mem_small_ds_sid succeeded");

    tv_ptr->full_file_small_ds_sid = H5Screate_simple(tv_ptr->small_rank, tv_ptr->dims, NULL);
    VRFY((tv_ptr->full_file_small_ds_sid != 0), "H5Screate_simple() full_file_small_ds_sid succeeded");

    tv_ptr->mem_small_ds_sid = H5Screate_simple(tv_ptr->small_rank, tv_ptr->dims, NULL);
    VRFY((tv_ptr->mem_small_ds_sid != 0), "H5Screate_simple() mem_small_ds_sid succeeded");

    tv_ptr->file_small_ds_sid_0 = H5Screate_simple(tv_ptr->small_rank, tv_ptr->dims, NULL);
    VRFY((tv_ptr->file_small_ds_sid_0 != 0), "H5Screate_simple() file_small_ds_sid_0 succeeded");

    /* used by checker board tests only */
    tv_ptr->file_small_ds_sid_1 = H5Screate_simple(tv_ptr->small_rank, tv_ptr->dims, NULL);
    VRFY((tv_ptr->file_small_ds_sid_1 != 0), "H5Screate_simple() file_small_ds_sid_1 succeeded");

    tv_ptr->small_ds_slice_sid = H5Screate_simple(tv_ptr->small_rank - 1, &(tv_ptr->dims[1]), NULL);
    VRFY((tv_ptr->small_ds_slice_sid != 0), "H5Screate_simple() small_ds_slice_sid succeeded");

    /* Create large ds dataspaces */
    tv_ptr->full_mem_large_ds_sid = H5Screate_simple(tv_ptr->large_rank, tv_ptr->dims, NULL);
    VRFY((tv_ptr->full_mem_large_ds_sid != 0), "H5Screate_simple() full_mem_large_ds_sid succeeded");

    tv_ptr->full_file_large_ds_sid = H5Screate_simple(tv_ptr->large_rank, tv_ptr->dims, NULL);
    VRFY((tv_ptr->full_file_large_ds_sid != FAIL), "H5Screate_simple() full_file_large_ds_sid succeeded");

    tv_ptr->mem_large_ds_sid = H5Screate_simple(tv_ptr->large_rank, tv_ptr->dims, NULL);
    VRFY((tv_ptr->mem_large_ds_sid != FAIL), "H5Screate_simple() mem_large_ds_sid succeeded");

    tv_ptr->file_large_ds_sid_0 = H5Screate_simple(tv_ptr->large_rank, tv_ptr->dims, NULL);
    VRFY((tv_ptr->file_large_ds_sid_0 != FAIL), "H5Screate_simple() file_large_ds_sid_0 succeeded");

    /* used by checker board tests only */
    tv_ptr->file_large_ds_sid_1 = H5Screate_simple(tv_ptr->large_rank, tv_ptr->dims, NULL);
    VRFY((tv_ptr->file_large_ds_sid_1 != FAIL), "H5Screate_simple() file_large_ds_sid_1 succeeded");

    tv_ptr->mem_large_ds_process_slice_sid = H5Screate_simple(tv_ptr->large_rank, tv_ptr->dims, NULL);
    VRFY((tv_ptr->mem_large_ds_process_slice_sid != FAIL),
         "H5Screate_simple() mem_large_ds_process_slice_sid succeeded");

    tv_ptr->file_large_ds_process_slice_sid = H5Screate_simple(tv_ptr->large_rank, tv_ptr->dims, NULL);
    VRFY((tv_ptr->file_large_ds_process_slice_sid != FAIL),
         "H5Screate_simple() file_large_ds_process_slice_sid succeeded");

    tv_ptr->large_ds_slice_sid = H5Screate_simple(tv_ptr->large_rank - 1, &(tv_ptr->dims[1]), NULL);
    VRFY((tv_ptr->large_ds_slice_sid != 0), "H5Screate_simple() large_ds_slice_sid succeeded");

    /* if chunk edge size is greater than zero, set up the small and
     * large data set creation property lists to specify chunked
     * datasets.
     */
    if (tv_ptr->chunk_edge_size > 0) {

        /* Under Lustre (and perhaps other parallel file systems?) we get
         * locking delays when two or more processes attempt to access the
         * same file system block.
         *
         * To minimize this problem, I have changed chunk_dims[0]
         * from (mpi_size + 1) to just when any sort of express test is
         * selected.  Given the structure of the test, and assuming we
         * set the alignment large enough, this avoids the contention
         * issue by seeing to it that each chunk is only accessed by one
         * process.
         *
         * One can argue as to whether this is a good thing to do in our
         * tests, but for now it is necessary if we want the test to complete
         * in a reasonable amount of time.
         *
         *                                         JRM -- 9/16/10
         */

        tv_ptr->chunk_dims[0] = 1;

        tv_ptr->chunk_dims[1] = tv_ptr->chunk_dims[2] = tv_ptr->chunk_dims[3] = tv_ptr->chunk_dims[4] =
            (hsize_t)(tv_ptr->chunk_edge_size);

        small_ds_dcpl_id = H5Pcreate(H5P_DATASET_CREATE);
        VRFY((ret != FAIL), "H5Pcreate() small_ds_dcpl_id succeeded");

        ret = H5Pset_layout(small_ds_dcpl_id, H5D_CHUNKED);
        VRFY((ret != FAIL), "H5Pset_layout() small_ds_dcpl_id succeeded");

        ret = H5Pset_chunk(small_ds_dcpl_id, tv_ptr->small_rank, tv_ptr->chunk_dims);
        VRFY((ret != FAIL), "H5Pset_chunk() small_ds_dcpl_id succeeded");

        large_ds_dcpl_id = H5Pcreate(H5P_DATASET_CREATE);
        VRFY((ret != FAIL), "H5Pcreate() large_ds_dcpl_id succeeded");

        ret = H5Pset_layout(large_ds_dcpl_id, H5D_CHUNKED);
        VRFY((ret != FAIL), "H5Pset_layout() large_ds_dcpl_id succeeded");

        ret = H5Pset_chunk(large_ds_dcpl_id, tv_ptr->large_rank, tv_ptr->chunk_dims);
        VRFY((ret != FAIL), "H5Pset_chunk() large_ds_dcpl_id succeeded");
    }

    /* create the small dataset */
    tv_ptr->small_dataset =
        H5Dcreate2(tv_ptr->fid, "small_dataset", tv_ptr->dset_type, tv_ptr->file_small_ds_sid_0, H5P_DEFAULT,
                   small_ds_dcpl_id, H5P_DEFAULT);
    VRFY((ret != FAIL), "H5Dcreate2() small_dataset succeeded");

    /* create the large dataset */
    tv_ptr->large_dataset =
        H5Dcreate2(tv_ptr->fid, "large_dataset", tv_ptr->dset_type, tv_ptr->file_large_ds_sid_0, H5P_DEFAULT,
                   large_ds_dcpl_id, H5P_DEFAULT);
    VRFY((ret != FAIL), "H5Dcreate2() large_dataset succeeded");

    /* setup xfer property list */
    tv_ptr->xfer_plist = H5Pcreate(H5P_DATASET_XFER);
    VRFY((tv_ptr->xfer_plist >= 0), "H5Pcreate(H5P_DATASET_XFER) succeeded");

    if (use_collective_io) {
        ret = H5Pset_dxpl_mpio(tv_ptr->xfer_plist, H5FD_MPIO_COLLECTIVE);
        VRFY((ret >= 0), "H5Pset_dxpl_mpio succeeded");
    }

    /* setup selection to write initial data to the small and large data sets */
    tv_ptr->start[0]  = (hsize_t)(tv_ptr->mpi_rank);
    tv_ptr->stride[0] = (hsize_t)(2 * (tv_ptr->mpi_size + 1));
    tv_ptr->count[0]  = 1;
    tv_ptr->block[0]  = 1;

    for (i = 1; i < tv_ptr->large_rank; i++) {

        tv_ptr->start[i]  = 0;
        tv_ptr->stride[i] = (hsize_t)(2 * tv_ptr->edge_size);
        tv_ptr->count[i]  = 1;
        tv_ptr->block[i]  = (hsize_t)(tv_ptr->edge_size);
    }

    /* setup selections for writing initial data to the small data set */
    ret = H5Sselect_hyperslab(tv_ptr->mem_small_ds_sid, H5S_SELECT_SET, tv_ptr->start, tv_ptr->stride,
                              tv_ptr->count, tv_ptr->block);
    VRFY((ret >= 0), "H5Sselect_hyperslab(mem_small_ds_sid, set) succeeded");

    ret = H5Sselect_hyperslab(tv_ptr->file_small_ds_sid_0, H5S_SELECT_SET, tv_ptr->start, tv_ptr->stride,
                              tv_ptr->count, tv_ptr->block);
    VRFY((ret >= 0), "H5Sselect_hyperslab(file_small_ds_sid_0, set) succeeded");

    if (MAINPROCESS) { /* add an additional slice to the selections */

        tv_ptr->start[0] = (hsize_t)(tv_ptr->mpi_size);

        ret = H5Sselect_hyperslab(tv_ptr->mem_small_ds_sid, H5S_SELECT_OR, tv_ptr->start, tv_ptr->stride,
                                  tv_ptr->count, tv_ptr->block);
        VRFY((ret >= 0), "H5Sselect_hyperslab(mem_small_ds_sid, or) succeeded");

        ret = H5Sselect_hyperslab(tv_ptr->file_small_ds_sid_0, H5S_SELECT_OR, tv_ptr->start, tv_ptr->stride,
                                  tv_ptr->count, tv_ptr->block);
        VRFY((ret >= 0), "H5Sselect_hyperslab(file_small_ds_sid_0, or) succeeded");
    }

    /* write the initial value of the small data set to file */
    ret = H5Dwrite(tv_ptr->small_dataset, tv_ptr->dset_type, tv_ptr->mem_small_ds_sid,
                   tv_ptr->file_small_ds_sid_0, tv_ptr->xfer_plist, tv_ptr->small_ds_buf_0);

    VRFY((ret >= 0), "H5Dwrite() small_dataset initial write succeeded");

    /* sync with the other processes before checking data */
    mrc = MPI_Barrier(MPI_COMM_WORLD);
    VRFY((mrc == MPI_SUCCESS), "Sync after small dataset writes");

    /* read the small data set back to verify that it contains the
     * expected data.  Note that each process reads in the entire
     * data set and verifies it.
     */
    ret = H5Dread(tv_ptr->small_dataset, H5T_NATIVE_UINT32, tv_ptr->full_mem_small_ds_sid,
                  tv_ptr->full_file_small_ds_sid, tv_ptr->xfer_plist, tv_ptr->small_ds_buf_1);
    VRFY((ret >= 0), "H5Dread() small_dataset initial read succeeded");

    /* verify that the correct data was written to the small data set */
    expected_value = 0;
    mis_match      = false;
    ptr_1          = tv_ptr->small_ds_buf_1;

    i = 0;
    for (i = 0; i < (int)(tv_ptr->small_ds_size); i++) {

        if (*ptr_1 != expected_value) {

            mis_match = true;
        }
        ptr_1++;
        expected_value++;
    }
    VRFY((mis_match == false), "small ds init data good.");

    /* setup selections for writing initial data to the large data set */

    tv_ptr->start[0] = (hsize_t)(tv_ptr->mpi_rank);

    ret = H5Sselect_hyperslab(tv_ptr->mem_large_ds_sid, H5S_SELECT_SET, tv_ptr->start, tv_ptr->stride,
                              tv_ptr->count, tv_ptr->block);
    VRFY((ret >= 0), "H5Sselect_hyperslab(mem_large_ds_sid, set) succeeded");

    ret = H5Sselect_hyperslab(tv_ptr->file_large_ds_sid_0, H5S_SELECT_SET, tv_ptr->start, tv_ptr->stride,
                              tv_ptr->count, tv_ptr->block);
    VRFY((ret >= 0), "H5Sselect_hyperslab(file_large_ds_sid_0, set) succeeded");

    /* In passing, setup the process slice dataspaces as well */

    ret = H5Sselect_hyperslab(tv_ptr->mem_large_ds_process_slice_sid, H5S_SELECT_SET, tv_ptr->start,
                              tv_ptr->stride, tv_ptr->count, tv_ptr->block);
    VRFY((ret >= 0), "H5Sselect_hyperslab(mem_large_ds_process_slice_sid, set) succeeded");

    ret = H5Sselect_hyperslab(tv_ptr->file_large_ds_process_slice_sid, H5S_SELECT_SET, tv_ptr->start,
                              tv_ptr->stride, tv_ptr->count, tv_ptr->block);
    VRFY((ret >= 0), "H5Sselect_hyperslab(file_large_ds_process_slice_sid, set) succeeded");

    if (MAINPROCESS) { /* add an additional slice to the selections */

        tv_ptr->start[0] = (hsize_t)(tv_ptr->mpi_size);

        ret = H5Sselect_hyperslab(tv_ptr->mem_large_ds_sid, H5S_SELECT_OR, tv_ptr->start, tv_ptr->stride,
                                  tv_ptr->count, tv_ptr->block);
        VRFY((ret >= 0), "H5Sselect_hyperslab(mem_large_ds_sid, or) succeeded");

        ret = H5Sselect_hyperslab(tv_ptr->file_large_ds_sid_0, H5S_SELECT_OR, tv_ptr->start, tv_ptr->stride,
                                  tv_ptr->count, tv_ptr->block);
        VRFY((ret >= 0), "H5Sselect_hyperslab(file_large_ds_sid_0, or) succeeded");
    }

    /* write the initial value of the large data set to file */
    ret = H5Dwrite(tv_ptr->large_dataset, tv_ptr->dset_type, tv_ptr->mem_large_ds_sid,
                   tv_ptr->file_large_ds_sid_0, tv_ptr->xfer_plist, tv_ptr->large_ds_buf_0);
    if (ret < 0)
        H5Eprint2(H5E_DEFAULT, stderr);
    VRFY((ret >= 0), "H5Dwrite() large_dataset initial write succeeded");

    /* sync with the other processes before checking data */
    mrc = MPI_Barrier(MPI_COMM_WORLD);
    VRFY((mrc == MPI_SUCCESS), "Sync after large dataset writes");

    /* read the large data set back to verify that it contains the
     * expected data.  Note that each process reads in the entire
     * data set.
     */
    ret = H5Dread(tv_ptr->large_dataset, H5T_NATIVE_UINT32, tv_ptr->full_mem_large_ds_sid,
                  tv_ptr->full_file_large_ds_sid, tv_ptr->xfer_plist, tv_ptr->large_ds_buf_1);
    VRFY((ret >= 0), "H5Dread() large_dataset initial read succeeded");

    /* verify that the correct data was written to the large data set */
    expected_value = 0;
    mis_match      = false;
    ptr_1          = tv_ptr->large_ds_buf_1;

    i = 0;
    for (i = 0; i < (int)(tv_ptr->large_ds_size); i++) {

        if (*ptr_1 != expected_value) {

            mis_match = true;
        }
        ptr_1++;
        expected_value++;
    }
    VRFY((mis_match == false), "large ds init data good.");

    /* sync with the other processes before changing data */
    mrc = MPI_Barrier(MPI_COMM_WORLD);
    VRFY((mrc == MPI_SUCCESS), "Sync initial values check");

    return;

} /* hs_dr_pio_test__setup() */

/*-------------------------------------------------------------------------
 * Function:    hs_dr_pio_test__takedown()
 *
 * Purpose:    Do takedown after tests of I/O to/from hyperslab selections
 *        of different rank in the parallel case.
 *
 * Return:    void
 *
 *-------------------------------------------------------------------------
 */

#define HS_DR_PIO_TEST__TAKEDOWN__DEBUG 0

static void
hs_dr_pio_test__takedown(struct hs_dr_pio_test_vars_t *tv_ptr)
{
#if HS_DR_PIO_TEST__TAKEDOWN__DEBUG
    const char *fcnName = "hs_dr_pio_test__takedown()";
#endif               /* HS_DR_PIO_TEST__TAKEDOWN__DEBUG */
    int    mpi_rank; /* needed by the VRFY macro */
    herr_t ret;      /* Generic return value */

    /* initialize the local copy of mpi_rank */
    mpi_rank = tv_ptr->mpi_rank;

    /* Close property lists */
    if (tv_ptr->xfer_plist != H5P_DEFAULT) {
        ret = H5Pclose(tv_ptr->xfer_plist);
        VRFY((ret != FAIL), "H5Pclose(xfer_plist) succeeded");
    }

    /* Close dataspaces */
    ret = H5Sclose(tv_ptr->full_mem_small_ds_sid);
    VRFY((ret != FAIL), "H5Sclose(full_mem_small_ds_sid) succeeded");

    ret = H5Sclose(tv_ptr->full_file_small_ds_sid);
    VRFY((ret != FAIL), "H5Sclose(full_file_small_ds_sid) succeeded");

    ret = H5Sclose(tv_ptr->mem_small_ds_sid);
    VRFY((ret != FAIL), "H5Sclose(mem_small_ds_sid) succeeded");

    ret = H5Sclose(tv_ptr->file_small_ds_sid_0);
    VRFY((ret != FAIL), "H5Sclose(file_small_ds_sid_0) succeeded");

    ret = H5Sclose(tv_ptr->file_small_ds_sid_1);
    VRFY((ret != FAIL), "H5Sclose(file_small_ds_sid_1) succeeded");

    ret = H5Sclose(tv_ptr->small_ds_slice_sid);
    VRFY((ret != FAIL), "H5Sclose(small_ds_slice_sid) succeeded");

    ret = H5Sclose(tv_ptr->full_mem_large_ds_sid);
    VRFY((ret != FAIL), "H5Sclose(full_mem_large_ds_sid) succeeded");

    ret = H5Sclose(tv_ptr->full_file_large_ds_sid);
    VRFY((ret != FAIL), "H5Sclose(full_file_large_ds_sid) succeeded");

    ret = H5Sclose(tv_ptr->mem_large_ds_sid);
    VRFY((ret != FAIL), "H5Sclose(mem_large_ds_sid) succeeded");

    ret = H5Sclose(tv_ptr->file_large_ds_sid_0);
    VRFY((ret != FAIL), "H5Sclose(file_large_ds_sid_0) succeeded");

    ret = H5Sclose(tv_ptr->file_large_ds_sid_1);
    VRFY((ret != FAIL), "H5Sclose(file_large_ds_sid_1) succeeded");

    ret = H5Sclose(tv_ptr->mem_large_ds_process_slice_sid);
    VRFY((ret != FAIL), "H5Sclose(mem_large_ds_process_slice_sid) succeeded");

    ret = H5Sclose(tv_ptr->file_large_ds_process_slice_sid);
    VRFY((ret != FAIL), "H5Sclose(file_large_ds_process_slice_sid) succeeded");

    ret = H5Sclose(tv_ptr->large_ds_slice_sid);
    VRFY((ret != FAIL), "H5Sclose(large_ds_slice_sid) succeeded");

    /* Close Datasets */
    ret = H5Dclose(tv_ptr->small_dataset);
    VRFY((ret != FAIL), "H5Dclose(small_dataset) succeeded");

    ret = H5Dclose(tv_ptr->large_dataset);
    VRFY((ret != FAIL), "H5Dclose(large_dataset) succeeded");

    /* close the file collectively */
    MESG("about to close file.");
    ret = H5Fclose(tv_ptr->fid);
    VRFY((ret != FAIL), "file close succeeded");

    /* Free memory buffers */

    if (tv_ptr->small_ds_buf_0 != NULL)
        free(tv_ptr->small_ds_buf_0);
    if (tv_ptr->small_ds_buf_1 != NULL)
        free(tv_ptr->small_ds_buf_1);
    if (tv_ptr->small_ds_buf_2 != NULL)
        free(tv_ptr->small_ds_buf_2);
    if (tv_ptr->small_ds_slice_buf != NULL)
        free(tv_ptr->small_ds_slice_buf);

    if (tv_ptr->large_ds_buf_0 != NULL)
        free(tv_ptr->large_ds_buf_0);
    if (tv_ptr->large_ds_buf_1 != NULL)
        free(tv_ptr->large_ds_buf_1);
    if (tv_ptr->large_ds_buf_2 != NULL)
        free(tv_ptr->large_ds_buf_2);
    if (tv_ptr->large_ds_slice_buf != NULL)
        free(tv_ptr->large_ds_slice_buf);

    return;

} /* hs_dr_pio_test__takedown() */

/*-------------------------------------------------------------------------
 * Function:    contig_hs_dr_pio_test__d2m_l2s()
 *
 * Purpose:    Part one of a series of tests of I/O to/from hyperslab
 *        selections of different rank in the parallel.
 *
 *        Verify that we can read from disk correctly using
 *        selections of different rank that H5Sselect_shape_same()
 *        views as being of the same shape.
 *
 *              In this function, we test this by reading small_rank - 1
 *        slices from the on disk large cube, and verifying that the
 *        data read is correct.  Verify that H5Sselect_shape_same()
 *        returns true on the memory and file selections.
 *
 * Return:    void
 *
 *-------------------------------------------------------------------------
 */

#define CONTIG_HS_DR_PIO_TEST__D2M_L2S__DEBUG 0

static void
contig_hs_dr_pio_test__d2m_l2s(struct hs_dr_pio_test_vars_t *tv_ptr)
{
#if CONTIG_HS_DR_PIO_TEST__D2M_L2S__DEBUG
    const char *fcnName = "contig_hs_dr_pio_test__run_test()";
#endif /* CONTIG_HS_DR_PIO_TEST__D2M_L2S__DEBUG */
    bool      mis_match = false;
    int       i, j, k, l;
    size_t    n;
    int       mpi_rank; /* needed by the VRFY macro */
    uint32_t  expected_value;
    uint32_t *ptr_1;
    htri_t    check; /* Shape comparison return value */
    herr_t    ret;   /* Generic return value */

    /* initialize the local copy of mpi_rank */
    mpi_rank = tv_ptr->mpi_rank;

    /* We have already done a H5Sselect_all() on the dataspace
     * small_ds_slice_sid in the initialization phase, so no need to
     * call H5Sselect_all() again.
     */

    /* set up start, stride, count, and block -- note that we will
     * change start[] so as to read slices of the large cube.
     */
    for (i = 0; i < PAR_SS_DR_MAX_RANK; i++) {

        tv_ptr->start[i]  = 0;
        tv_ptr->stride[i] = (hsize_t)(2 * tv_ptr->edge_size);
        tv_ptr->count[i]  = 1;
        if ((PAR_SS_DR_MAX_RANK - i) > (tv_ptr->small_rank - 1)) {

            tv_ptr->block[i] = 1;
        }
        else {

            tv_ptr->block[i] = (hsize_t)(tv_ptr->edge_size);
        }
    }

    /* zero out the buffer we will be reading into */
    memset(tv_ptr->small_ds_slice_buf, 0, sizeof(uint32_t) * tv_ptr->small_ds_slice_size);

#if CONTIG_HS_DR_PIO_TEST__D2M_L2S__DEBUG
    fprintf(stdout, "%s reading slices from big cube on disk into small cube slice.\n", fcnName);
#endif /* CONTIG_HS_DR_PIO_TEST__D2M_L2S__DEBUG */

    /* in serial versions of this test, we loop through all the dimensions
     * of the large data set.  However, in the parallel version, each
     * process only works with that slice of the large cube indicated
     * by its rank -- hence we set the most slowly changing index to
     * mpi_rank, and don't iterate over it.
     */

    if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 0) {

        i = tv_ptr->mpi_rank;
    }
    else {

        i = 0;
    }

    /* since large_rank is at most PAR_SS_DR_MAX_RANK, no need to
     * loop over it -- either we are setting i to mpi_rank, or
     * we are setting it to zero.  It will not change during the
     * test.
     */

    if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 1) {

        j = tv_ptr->mpi_rank;
    }
    else {

        j = 0;
    }

    do {
        if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 2) {

            k = tv_ptr->mpi_rank;
        }
        else {

            k = 0;
        }

        do {
            /* since small rank >= 2 and large_rank > small_rank, we
             * have large_rank >= 3.  Since PAR_SS_DR_MAX_RANK == 5
             * (baring major re-orgaization), this gives us:
             *
             *     (PAR_SS_DR_MAX_RANK - large_rank) <= 2
             *
             * so no need to repeat the test in the outer loops --
             * just set l = 0.
             */

            l = 0;
            do {
                if ((tv_ptr->skips)++ < tv_ptr->max_skips) { /* skip the test */

                    (tv_ptr->tests_skipped)++;
                }
                else { /* run the test */

                    tv_ptr->skips = 0; /* reset the skips counter */

                    /* we know that small_rank - 1 >= 1 and that
                     * large_rank > small_rank by the assertions at the head
                     * of this function.  Thus no need for another inner loop.
                     */
                    tv_ptr->start[0] = (hsize_t)i;
                    tv_ptr->start[1] = (hsize_t)j;
                    tv_ptr->start[2] = (hsize_t)k;
                    tv_ptr->start[3] = (hsize_t)l;
                    tv_ptr->start[4] = 0;

                    ret = H5Sselect_hyperslab(tv_ptr->file_large_ds_sid_0, H5S_SELECT_SET, tv_ptr->start_ptr,
                                              tv_ptr->stride_ptr, tv_ptr->count_ptr, tv_ptr->block_ptr);
                    VRFY((ret != FAIL), "H5Sselect_hyperslab(file_large_cube_sid) succeeded");

                    /* verify that H5Sselect_shape_same() reports the two
                     * selections as having the same shape.
                     */
                    check = H5Sselect_shape_same(tv_ptr->small_ds_slice_sid, tv_ptr->file_large_ds_sid_0);
                    VRFY((check == true), "H5Sselect_shape_same passed");

                    /* Read selection from disk */
#if CONTIG_HS_DR_PIO_TEST__D2M_L2S__DEBUG
                    fprintf(stdout, "%s:%d: start = %d %d %d %d %d.\n", fcnName, (int)(tv_ptr->mpi_rank),
                            (int)(tv_ptr->start[0]), (int)(tv_ptr->start[1]), (int)(tv_ptr->start[2]),
                            (int)(tv_ptr->start[3]), (int)(tv_ptr->start[4]));
                    fprintf(stdout, "%s slice/file extent dims = %d/%d.\n", fcnName,
                            H5Sget_simple_extent_ndims(tv_ptr->small_ds_slice_sid),
                            H5Sget_simple_extent_ndims(tv_ptr->file_large_ds_sid_0));
#endif /* CONTIG_HS_DR_PIO_TEST__D2M_L2S__DEBUG */
                    ret =
                        H5Dread(tv_ptr->large_dataset, H5T_NATIVE_UINT32, tv_ptr->small_ds_slice_sid,
                                tv_ptr->file_large_ds_sid_0, tv_ptr->xfer_plist, tv_ptr->small_ds_slice_buf);
                    VRFY((ret >= 0), "H5Dread() slice from large ds succeeded.");

                    /* verify that expected data is retrieved */

                    mis_match = false;
                    ptr_1     = tv_ptr->small_ds_slice_buf;
                    expected_value =
                        (uint32_t)((i * tv_ptr->edge_size * tv_ptr->edge_size * tv_ptr->edge_size *
                                    tv_ptr->edge_size) +
                                   (j * tv_ptr->edge_size * tv_ptr->edge_size * tv_ptr->edge_size) +
                                   (k * tv_ptr->edge_size * tv_ptr->edge_size) + (l * tv_ptr->edge_size));

                    for (n = 0; n < tv_ptr->small_ds_slice_size; n++) {

                        if (*ptr_1 != expected_value) {

                            mis_match = true;
                        }

                        *ptr_1 = 0; /* zero data for next use */

                        ptr_1++;
                        expected_value++;
                    }

                    VRFY((mis_match == false), "small slice read from large ds data good.");

                    (tv_ptr->tests_run)++;
                }

                l++;

                (tv_ptr->total_tests)++;

            } while ((tv_ptr->large_rank > 2) && ((tv_ptr->small_rank - 1) <= 1) && (l < tv_ptr->edge_size));
            k++;
        } while ((tv_ptr->large_rank > 3) && ((tv_ptr->small_rank - 1) <= 2) && (k < tv_ptr->edge_size));
        j++;
    } while ((tv_ptr->large_rank > 4) && ((tv_ptr->small_rank - 1) <= 3) && (j < tv_ptr->edge_size));

    return;

} /* contig_hs_dr_pio_test__d2m_l2s() */

/*-------------------------------------------------------------------------
 * Function:    contig_hs_dr_pio_test__d2m_s2l()
 *
 * Purpose:    Part two of a series of tests of I/O to/from hyperslab
 *        selections of different rank in the parallel.
 *
 *        Verify that we can read from disk correctly using
 *        selections of different rank that H5Sselect_shape_same()
 *        views as being of the same shape.
 *
 *        In this function, we test this by reading slices of the
 *        on disk small data set into slices through the in memory
 *        large data set, and verify that the correct data (and
 *        only the correct data) is read.
 *
 * Return:    void
 *
 *-------------------------------------------------------------------------
 */

#define CONTIG_HS_DR_PIO_TEST__D2M_S2L__DEBUG 0

static void
contig_hs_dr_pio_test__d2m_s2l(struct hs_dr_pio_test_vars_t *tv_ptr)
{
#if CONTIG_HS_DR_PIO_TEST__D2M_S2L__DEBUG
    const char *fcnName = "contig_hs_dr_pio_test__d2m_s2l()";
#endif /* CONTIG_HS_DR_PIO_TEST__D2M_S2L__DEBUG */
    bool      mis_match = false;
    int       i, j, k, l;
    size_t    n;
    int       mpi_rank; /* needed by the VRFY macro */
    size_t    start_index;
    size_t    stop_index;
    uint32_t  expected_value;
    uint32_t *ptr_1;
    htri_t    check; /* Shape comparison return value */
    herr_t    ret;   /* Generic return value */

    /* initialize the local copy of mpi_rank */
    mpi_rank = tv_ptr->mpi_rank;

    /* Read slices of the on disk small data set into slices
     * through the in memory large data set, and verify that the correct
     * data (and only the correct data) is read.
     */

    tv_ptr->start[0]  = (hsize_t)(tv_ptr->mpi_rank);
    tv_ptr->stride[0] = (hsize_t)(2 * (tv_ptr->mpi_size + 1));
    tv_ptr->count[0]  = 1;
    tv_ptr->block[0]  = 1;

    for (i = 1; i < tv_ptr->large_rank; i++) {

        tv_ptr->start[i]  = 0;
        tv_ptr->stride[i] = (hsize_t)(2 * tv_ptr->edge_size);
        tv_ptr->count[i]  = 1;
        tv_ptr->block[i]  = (hsize_t)(tv_ptr->edge_size);
    }

    ret = H5Sselect_hyperslab(tv_ptr->file_small_ds_sid_0, H5S_SELECT_SET, tv_ptr->start, tv_ptr->stride,
                              tv_ptr->count, tv_ptr->block);
    VRFY((ret >= 0), "H5Sselect_hyperslab(file_small_ds_sid_0, set) succeeded");

#if CONTIG_HS_DR_PIO_TEST__D2M_S2L__DEBUG
    fprintf(stdout, "%s reading slices of on disk small data set into slices of big data set.\n", fcnName);
#endif /* CONTIG_HS_DR_PIO_TEST__D2M_S2L__DEBUG */

    /* zero out the in memory large ds */
    memset(tv_ptr->large_ds_buf_1, 0, sizeof(uint32_t) * tv_ptr->large_ds_size);

    /* set up start, stride, count, and block -- note that we will
     * change start[] so as to read slices of the large cube.
     */
    for (i = 0; i < PAR_SS_DR_MAX_RANK; i++) {

        tv_ptr->start[i]  = 0;
        tv_ptr->stride[i] = (hsize_t)(2 * tv_ptr->edge_size);
        tv_ptr->count[i]  = 1;
        if ((PAR_SS_DR_MAX_RANK - i) > (tv_ptr->small_rank - 1)) {

            tv_ptr->block[i] = 1;
        }
        else {

            tv_ptr->block[i] = (hsize_t)(tv_ptr->edge_size);
        }
    }

    /* in serial versions of this test, we loop through all the dimensions
     * of the large data set that don't appear in the small data set.
     *
     * However, in the parallel version, each process only works with that
     * slice of the large (and small) data set indicated by its rank -- hence
     * we set the most slowly changing index to mpi_rank, and don't iterate
     * over it.
     */

    if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 0) {

        i = tv_ptr->mpi_rank;
    }
    else {

        i = 0;
    }

    /* since large_rank is at most PAR_SS_DR_MAX_RANK, no need to
     * loop over it -- either we are setting i to mpi_rank, or
     * we are setting it to zero.  It will not change during the
     * test.
     */

    if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 1) {

        j = tv_ptr->mpi_rank;
    }
    else {

        j = 0;
    }

    do {
        if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 2) {

            k = tv_ptr->mpi_rank;
        }
        else {

            k = 0;
        }

        do {
            /* since small rank >= 2 and large_rank > small_rank, we
             * have large_rank >= 3.  Since PAR_SS_DR_MAX_RANK == 5
             * (baring major re-orgaization), this gives us:
             *
             *     (PAR_SS_DR_MAX_RANK - large_rank) <= 2
             *
             * so no need to repeat the test in the outer loops --
             * just set l = 0.
             */

            l = 0;
            do {
                if ((tv_ptr->skips)++ < tv_ptr->max_skips) { /* skip the test */

                    (tv_ptr->tests_skipped)++;
                }
                else { /* run the test */

                    tv_ptr->skips = 0; /* reset the skips counter */

                    /* we know that small_rank >= 1 and that large_rank > small_rank
                     * by the assertions at the head of this function.  Thus no
                     * need for another inner loop.
                     */
                    tv_ptr->start[0] = (hsize_t)i;
                    tv_ptr->start[1] = (hsize_t)j;
                    tv_ptr->start[2] = (hsize_t)k;
                    tv_ptr->start[3] = (hsize_t)l;
                    tv_ptr->start[4] = 0;

                    ret = H5Sselect_hyperslab(tv_ptr->mem_large_ds_sid, H5S_SELECT_SET, tv_ptr->start_ptr,
                                              tv_ptr->stride_ptr, tv_ptr->count_ptr, tv_ptr->block_ptr);
                    VRFY((ret != FAIL), "H5Sselect_hyperslab(mem_large_ds_sid) succeeded");

                    /* verify that H5Sselect_shape_same() reports the two
                     * selections as having the same shape.
                     */
                    check = H5Sselect_shape_same(tv_ptr->file_small_ds_sid_0, tv_ptr->mem_large_ds_sid);
                    VRFY((check == true), "H5Sselect_shape_same passed");

                    /* Read selection from disk */
#if CONTIG_HS_DR_PIO_TEST__D2M_S2L__DEBUG
                    fprintf(stdout, "%s:%d: start = %d %d %d %d %d.\n", fcnName, (int)(tv_ptr->mpi_rank),
                            (int)(tv_ptr->start[0]), (int)(tv_ptr->start[1]), (int)(tv_ptr->start[2]),
                            (int)(tv_ptr->start[3]), (int)(tv_ptr->start[4]));
                    fprintf(stdout, "%s:%d: mem/file extent dims = %d/%d.\n", fcnName, tv_ptr->mpi_rank,
                            H5Sget_simple_extent_ndims(tv_ptr->mem_large_ds_sid),
                            H5Sget_simple_extent_ndims(tv_ptr->file_small_ds_sid_0));
#endif /* CONTIG_HS_DR_PIO_TEST__D2M_S2L__DEBUG */
                    ret = H5Dread(tv_ptr->small_dataset, H5T_NATIVE_UINT32, tv_ptr->mem_large_ds_sid,
                                  tv_ptr->file_small_ds_sid_0, tv_ptr->xfer_plist, tv_ptr->large_ds_buf_1);
                    VRFY((ret >= 0), "H5Dread() slice from small ds succeeded.");

                    /* verify that the expected data and only the
                     * expected data was read.
                     */
                    ptr_1          = tv_ptr->large_ds_buf_1;
                    expected_value = (uint32_t)((size_t)(tv_ptr->mpi_rank) * tv_ptr->small_ds_slice_size);
                    start_index =
                        (size_t)((i * tv_ptr->edge_size * tv_ptr->edge_size * tv_ptr->edge_size *
                                  tv_ptr->edge_size) +
                                 (j * tv_ptr->edge_size * tv_ptr->edge_size * tv_ptr->edge_size) +
                                 (k * tv_ptr->edge_size * tv_ptr->edge_size) + (l * tv_ptr->edge_size));
                    stop_index = start_index + tv_ptr->small_ds_slice_size - 1;

                    assert(start_index < stop_index);
                    assert(stop_index <= tv_ptr->large_ds_size);

                    for (n = 0; n < tv_ptr->large_ds_size; n++) {

                        if ((n >= start_index) && (n <= stop_index)) {

                            if (*ptr_1 != expected_value) {

                                mis_match = true;
                            }
                            expected_value++;
                        }
                        else {

                            if (*ptr_1 != 0) {

                                mis_match = true;
                            }
                        }
                        /* zero out the value for the next pass */
                        *ptr_1 = 0;

                        ptr_1++;
                    }

                    VRFY((mis_match == false), "small slice read from large ds data good.");

                    (tv_ptr->tests_run)++;
                }

                l++;

                (tv_ptr->total_tests)++;

            } while ((tv_ptr->large_rank > 2) && ((tv_ptr->small_rank - 1) <= 1) && (l < tv_ptr->edge_size));
            k++;
        } while ((tv_ptr->large_rank > 3) && ((tv_ptr->small_rank - 1) <= 2) && (k < tv_ptr->edge_size));
        j++;
    } while ((tv_ptr->large_rank > 4) && ((tv_ptr->small_rank - 1) <= 3) && (j < tv_ptr->edge_size));

    return;

} /* contig_hs_dr_pio_test__d2m_s2l() */

/*-------------------------------------------------------------------------
 * Function:    contig_hs_dr_pio_test__m2d_l2s()
 *
 * Purpose:    Part three of a series of tests of I/O to/from hyperslab
 *        selections of different rank in the parallel.
 *
 *        Verify that we can write from memory to file using
 *        selections of different rank that H5Sselect_shape_same()
 *        views as being of the same shape.
 *
 *        Do this by writing small_rank - 1 dimensional slices from
 *        the in memory large data set to the on disk small cube
 *        dataset.  After each write, read the slice of the small
 *        dataset back from disk, and verify that it contains
 *        the expected data. Verify that H5Sselect_shape_same()
 *        returns true on the memory and file selections.
 *
 * Return:    void
 *
 *-------------------------------------------------------------------------
 */

#define CONTIG_HS_DR_PIO_TEST__M2D_L2S__DEBUG 0

static void
contig_hs_dr_pio_test__m2d_l2s(struct hs_dr_pio_test_vars_t *tv_ptr)
{
#if CONTIG_HS_DR_PIO_TEST__M2D_L2S__DEBUG
    const char *fcnName = "contig_hs_dr_pio_test__m2d_l2s()";
#endif /* CONTIG_HS_DR_PIO_TEST__M2D_L2S__DEBUG */
    bool      mis_match = false;
    int       i, j, k, l;
    size_t    n;
    int       mpi_rank; /* needed by the VRFY macro */
    size_t    start_index;
    size_t    stop_index;
    uint32_t  expected_value;
    uint32_t *ptr_1;
    htri_t    check; /* Shape comparison return value */
    herr_t    ret;   /* Generic return value */

    /* initialize the local copy of mpi_rank */
    mpi_rank = tv_ptr->mpi_rank;

    /* now we go in the opposite direction, verifying that we can write
     * from memory to file using selections of different rank that
     * H5Sselect_shape_same() views as being of the same shape.
     *
     * Start by writing small_rank - 1 dimensional slices from the in memory large
     * data set to the on disk small cube dataset.  After each write, read the
     * slice of the small dataset back from disk, and verify that it contains
     * the expected data. Verify that H5Sselect_shape_same() returns true on
     * the memory and file selections.
     */

    tv_ptr->start[0]  = (hsize_t)(tv_ptr->mpi_rank);
    tv_ptr->stride[0] = (hsize_t)(2 * (tv_ptr->mpi_size + 1));
    tv_ptr->count[0]  = 1;
    tv_ptr->block[0]  = 1;

    for (i = 1; i < tv_ptr->large_rank; i++) {

        tv_ptr->start[i]  = 0;
        tv_ptr->stride[i] = (hsize_t)(2 * tv_ptr->edge_size);
        tv_ptr->count[i]  = 1;
        tv_ptr->block[i]  = (hsize_t)(tv_ptr->edge_size);
    }

    ret = H5Sselect_hyperslab(tv_ptr->file_small_ds_sid_0, H5S_SELECT_SET, tv_ptr->start, tv_ptr->stride,
                              tv_ptr->count, tv_ptr->block);
    VRFY((ret >= 0), "H5Sselect_hyperslab(file_small_ds_sid_0, set) succeeded");

    ret = H5Sselect_hyperslab(tv_ptr->mem_small_ds_sid, H5S_SELECT_SET, tv_ptr->start, tv_ptr->stride,
                              tv_ptr->count, tv_ptr->block);
    VRFY((ret >= 0), "H5Sselect_hyperslab(mem_small_ds_sid, set) succeeded");

    /* set up start, stride, count, and block -- note that we will
     * change start[] so as to read slices of the large cube.
     */
    for (i = 0; i < PAR_SS_DR_MAX_RANK; i++) {

        tv_ptr->start[i]  = 0;
        tv_ptr->stride[i] = (hsize_t)(2 * tv_ptr->edge_size);
        tv_ptr->count[i]  = 1;
        if ((PAR_SS_DR_MAX_RANK - i) > (tv_ptr->small_rank - 1)) {

            tv_ptr->block[i] = 1;
        }
        else {

            tv_ptr->block[i] = (hsize_t)(tv_ptr->edge_size);
        }
    }

    /* zero out the in memory small ds */
    memset(tv_ptr->small_ds_buf_1, 0, sizeof(uint32_t) * tv_ptr->small_ds_size);

#if CONTIG_HS_DR_PIO_TEST__M2D_L2S__DEBUG
    fprintf(stdout, "%s writing slices from big ds to slices of small ds on disk.\n", fcnName);
#endif /* CONTIG_HS_DR_PIO_TEST__M2D_L2S__DEBUG */

    /* in serial versions of this test, we loop through all the dimensions
     * of the large data set that don't appear in the small data set.
     *
     * However, in the parallel version, each process only works with that
     * slice of the large (and small) data set indicated by its rank -- hence
     * we set the most slowly changing index to mpi_rank, and don't iterate
     * over it.
     */

    if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 0) {

        i = tv_ptr->mpi_rank;
    }
    else {

        i = 0;
    }

    /* since large_rank is at most PAR_SS_DR_MAX_RANK, no need to
     * loop over it -- either we are setting i to mpi_rank, or
     * we are setting it to zero.  It will not change during the
     * test.
     */

    if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 1) {

        j = tv_ptr->mpi_rank;
    }
    else {

        j = 0;
    }

    j = 0;
    do {
        if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 2) {

            k = tv_ptr->mpi_rank;
        }
        else {

            k = 0;
        }

        do {
            /* since small rank >= 2 and large_rank > small_rank, we
             * have large_rank >= 3.  Since PAR_SS_DR_MAX_RANK == 5
             * (baring major re-orgaization), this gives us:
             *
             *     (PAR_SS_DR_MAX_RANK - large_rank) <= 2
             *
             * so no need to repeat the test in the outer loops --
             * just set l = 0.
             */

            l = 0;
            do {
                if ((tv_ptr->skips)++ < tv_ptr->max_skips) { /* skip the test */

                    (tv_ptr->tests_skipped)++;
                }
                else { /* run the test */

                    tv_ptr->skips = 0; /* reset the skips counter */

                    /* we know that small_rank >= 1 and that large_rank > small_rank
                     * by the assertions at the head of this function.  Thus no
                     * need for another inner loop.
                     */

                    /* zero out this rank's slice of the on disk small data set */
                    ret = H5Dwrite(tv_ptr->small_dataset, H5T_NATIVE_UINT32, tv_ptr->mem_small_ds_sid,
                                   tv_ptr->file_small_ds_sid_0, tv_ptr->xfer_plist, tv_ptr->small_ds_buf_2);
                    VRFY((ret >= 0), "H5Dwrite() zero slice to small ds succeeded.");

                    /* select the portion of the in memory large cube from which we
                     * are going to write data.
                     */
                    tv_ptr->start[0] = (hsize_t)i;
                    tv_ptr->start[1] = (hsize_t)j;
                    tv_ptr->start[2] = (hsize_t)k;
                    tv_ptr->start[3] = (hsize_t)l;
                    tv_ptr->start[4] = 0;

                    ret = H5Sselect_hyperslab(tv_ptr->mem_large_ds_sid, H5S_SELECT_SET, tv_ptr->start_ptr,
                                              tv_ptr->stride_ptr, tv_ptr->count_ptr, tv_ptr->block_ptr);
                    VRFY((ret >= 0), "H5Sselect_hyperslab() mem_large_ds_sid succeeded.");

                    /* verify that H5Sselect_shape_same() reports the in
                     * memory slice through the cube selection and the
                     * on disk full square selections as having the same shape.
                     */
                    check = H5Sselect_shape_same(tv_ptr->file_small_ds_sid_0, tv_ptr->mem_large_ds_sid);
                    VRFY((check == true), "H5Sselect_shape_same passed.");

                    /* write the slice from the in memory large data set to the
                     * slice of the on disk small dataset. */
#if CONTIG_HS_DR_PIO_TEST__M2D_L2S__DEBUG
                    fprintf(stdout, "%s:%d: start = %d %d %d %d %d.\n", fcnName, (int)(tv_ptr->mpi_rank),
                            (int)(tv_ptr->start[0]), (int)(tv_ptr->start[1]), (int)(tv_ptr->start[2]),
                            (int)(tv_ptr->start[3]), (int)(tv_ptr->start[4]));
                    fprintf(stdout, "%s:%d: mem/file extent dims = %d/%d.\n", fcnName, tv_ptr->mpi_rank,
                            H5Sget_simple_extent_ndims(tv_ptr->mem_large_ds_sid),
                            H5Sget_simple_extent_ndims(tv_ptr->file_small_ds_sid_0));
#endif /* CONTIG_HS_DR_PIO_TEST__M2D_L2S__DEBUG */
                    ret = H5Dwrite(tv_ptr->small_dataset, H5T_NATIVE_UINT32, tv_ptr->mem_large_ds_sid,
                                   tv_ptr->file_small_ds_sid_0, tv_ptr->xfer_plist, tv_ptr->large_ds_buf_0);
                    VRFY((ret >= 0), "H5Dwrite() slice to large ds succeeded.");

                    /* read the on disk square into memory */
                    ret = H5Dread(tv_ptr->small_dataset, H5T_NATIVE_UINT32, tv_ptr->mem_small_ds_sid,
                                  tv_ptr->file_small_ds_sid_0, tv_ptr->xfer_plist, tv_ptr->small_ds_buf_1);
                    VRFY((ret >= 0), "H5Dread() slice from small ds succeeded.");

                    /* verify that expected data is retrieved */

                    mis_match = false;
                    ptr_1     = tv_ptr->small_ds_buf_1;

                    expected_value =
                        (uint32_t)((i * tv_ptr->edge_size * tv_ptr->edge_size * tv_ptr->edge_size *
                                    tv_ptr->edge_size) +
                                   (j * tv_ptr->edge_size * tv_ptr->edge_size * tv_ptr->edge_size) +
                                   (k * tv_ptr->edge_size * tv_ptr->edge_size) + (l * tv_ptr->edge_size));

                    start_index = (size_t)(tv_ptr->mpi_rank) * tv_ptr->small_ds_slice_size;
                    stop_index  = start_index + tv_ptr->small_ds_slice_size - 1;

                    assert(start_index < stop_index);
                    assert(stop_index <= tv_ptr->small_ds_size);

                    for (n = 0; n < tv_ptr->small_ds_size; n++) {

                        if ((n >= start_index) && (n <= stop_index)) {

                            if (*ptr_1 != expected_value) {

                                mis_match = true;
                            }
                            expected_value++;
                        }
                        else {

                            if (*ptr_1 != 0) {

                                mis_match = true;
                            }
                        }
                        /* zero out the value for the next pass */
                        *ptr_1 = 0;

                        ptr_1++;
                    }

                    VRFY((mis_match == false), "small slice write from large ds data good.");

                    (tv_ptr->tests_run)++;
                }

                l++;

                (tv_ptr->total_tests)++;

            } while ((tv_ptr->large_rank > 2) && ((tv_ptr->small_rank - 1) <= 1) && (l < tv_ptr->edge_size));
            k++;
        } while ((tv_ptr->large_rank > 3) && ((tv_ptr->small_rank - 1) <= 2) && (k < tv_ptr->edge_size));
        j++;
    } while ((tv_ptr->large_rank > 4) && ((tv_ptr->small_rank - 1) <= 3) && (j < tv_ptr->edge_size));

    return;

} /* contig_hs_dr_pio_test__m2d_l2s() */

/*-------------------------------------------------------------------------
 * Function:    contig_hs_dr_pio_test__m2d_s2l()
 *
 * Purpose:    Part four of a series of tests of I/O to/from hyperslab
 *        selections of different rank in the parallel.
 *
 *        Verify that we can write from memory to file using
 *        selections of different rank that H5Sselect_shape_same()
 *        views as being of the same shape.
 *
 *        Do this by writing the contents of the process's slice of
 *        the in memory small data set to slices of the on disk
 *        large data set.  After each write, read the process's
 *        slice of the large data set back into memory, and verify
 *        that it contains the expected data.
 *
 *        Verify that H5Sselect_shape_same() returns true on the
 *        memory and file selections.
 *
 * Return:    void
 *
 *-------------------------------------------------------------------------
 */

#define CONTIG_HS_DR_PIO_TEST__M2D_S2L__DEBUG 0

static void
contig_hs_dr_pio_test__m2d_s2l(struct hs_dr_pio_test_vars_t *tv_ptr)
{
#if CONTIG_HS_DR_PIO_TEST__M2D_S2L__DEBUG
    const char *fcnName = "contig_hs_dr_pio_test__m2d_s2l()";
#endif /* CONTIG_HS_DR_PIO_TEST__M2D_S2L__DEBUG */
    bool      mis_match = false;
    int       i, j, k, l;
    size_t    n;
    int       mpi_rank; /* needed by the VRFY macro */
    size_t    start_index;
    size_t    stop_index;
    uint32_t  expected_value;
    uint32_t *ptr_1;
    htri_t    check; /* Shape comparison return value */
    herr_t    ret;   /* Generic return value */

    /* initialize the local copy of mpi_rank */
    mpi_rank = tv_ptr->mpi_rank;

    /* Now write the contents of the process's slice of the in memory
     * small data set to slices of the on disk large data set.  After
     * each write, read the process's slice of the large data set back
     * into memory, and verify that it contains the expected data.
     * Verify that H5Sselect_shape_same() returns true on the memory
     * and file selections.
     */

    /* select the slice of the in memory small data set associated with
     * the process's mpi rank.
     */
    tv_ptr->start[0]  = (hsize_t)(tv_ptr->mpi_rank);
    tv_ptr->stride[0] = (hsize_t)(2 * (tv_ptr->mpi_size + 1));
    tv_ptr->count[0]  = 1;
    tv_ptr->block[0]  = 1;

    for (i = 1; i < tv_ptr->large_rank; i++) {

        tv_ptr->start[i]  = 0;
        tv_ptr->stride[i] = (hsize_t)(2 * tv_ptr->edge_size);
        tv_ptr->count[i]  = 1;
        tv_ptr->block[i]  = (hsize_t)(tv_ptr->edge_size);
    }

    ret = H5Sselect_hyperslab(tv_ptr->mem_small_ds_sid, H5S_SELECT_SET, tv_ptr->start, tv_ptr->stride,
                              tv_ptr->count, tv_ptr->block);
    VRFY((ret >= 0), "H5Sselect_hyperslab(mem_small_ds_sid, set) succeeded");

    /* set up start, stride, count, and block -- note that we will
     * change start[] so as to write slices of the small data set to
     * slices of the large data set.
     */
    for (i = 0; i < PAR_SS_DR_MAX_RANK; i++) {

        tv_ptr->start[i]  = 0;
        tv_ptr->stride[i] = (hsize_t)(2 * tv_ptr->edge_size);
        tv_ptr->count[i]  = 1;
        if ((PAR_SS_DR_MAX_RANK - i) > (tv_ptr->small_rank - 1)) {

            tv_ptr->block[i] = 1;
        }
        else {

            tv_ptr->block[i] = (hsize_t)(tv_ptr->edge_size);
        }
    }

    /* zero out the in memory large ds */
    memset(tv_ptr->large_ds_buf_1, 0, sizeof(uint32_t) * tv_ptr->large_ds_size);

#if CONTIG_HS_DR_PIO_TEST__M2D_S2L__DEBUG
    fprintf(stdout, "%s writing process slices of small ds to slices of large ds on disk.\n", fcnName);
#endif /* CONTIG_HS_DR_PIO_TEST__M2D_S2L__DEBUG */

    if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 0) {

        i = tv_ptr->mpi_rank;
    }
    else {

        i = 0;
    }

    /* since large_rank is at most PAR_SS_DR_MAX_RANK, no need to
     * loop over it -- either we are setting i to mpi_rank, or
     * we are setting it to zero.  It will not change during the
     * test.
     */

    if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 1) {

        j = tv_ptr->mpi_rank;
    }
    else {

        j = 0;
    }

    do {
        if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 2) {

            k = tv_ptr->mpi_rank;
        }
        else {

            k = 0;
        }

        do {
            /* since small rank >= 2 and large_rank > small_rank, we
             * have large_rank >= 3.  Since PAR_SS_DR_MAX_RANK == 5
             * (baring major re-orgaization), this gives us:
             *
             *     (PAR_SS_DR_MAX_RANK - large_rank) <= 2
             *
             * so no need to repeat the test in the outer loops --
             * just set l = 0.
             */

            l = 0;
            do {
                if ((tv_ptr->skips)++ < tv_ptr->max_skips) { /* skip the test */

                    (tv_ptr->tests_skipped)++;

#if CONTIG_HS_DR_PIO_TEST__M2D_S2L__DEBUG
                    tv_ptr->start[0] = (hsize_t)i;
                    tv_ptr->start[1] = (hsize_t)j;
                    tv_ptr->start[2] = (hsize_t)k;
                    tv_ptr->start[3] = (hsize_t)l;
                    tv_ptr->start[4] = 0;

                    fprintf(stdout, "%s:%d: skipping test with start = %d %d %d %d %d.\n", fcnName,
                            (int)(tv_ptr->mpi_rank), (int)(tv_ptr->start[0]), (int)(tv_ptr->start[1]),
                            (int)(tv_ptr->start[2]), (int)(tv_ptr->start[3]), (int)(tv_ptr->start[4]));
                    fprintf(stdout, "%s:%d: mem/file extent dims = %d/%d.\n", fcnName, tv_ptr->mpi_rank,
                            H5Sget_simple_extent_ndims(tv_ptr->mem_small_ds_sid),
                            H5Sget_simple_extent_ndims(tv_ptr->file_large_ds_sid_0));
#endif /* CONTIG_HS_DR_PIO_TEST__M2D_S2L__DEBUG */
                }
                else { /* run the test */

                    tv_ptr->skips = 0; /* reset the skips counter */

                    /* we know that small_rank >= 1 and that large_rank > small_rank
                     * by the assertions at the head of this function.  Thus no
                     * need for another inner loop.
                     */

                    /* Zero out this processes slice of the on disk large data set.
                     * Note that this will leave one slice with its original data
                     * as there is one more slice than processes.
                     */
                    ret = H5Dwrite(tv_ptr->large_dataset, H5T_NATIVE_UINT32, tv_ptr->large_ds_slice_sid,
                                   tv_ptr->file_large_ds_process_slice_sid, tv_ptr->xfer_plist,
                                   tv_ptr->large_ds_buf_2);
                    VRFY((ret != FAIL), "H5Dwrite() to zero large ds succeeded");

                    /* select the portion of the in memory large cube to which we
                     * are going to write data.
                     */
                    tv_ptr->start[0] = (hsize_t)i;
                    tv_ptr->start[1] = (hsize_t)j;
                    tv_ptr->start[2] = (hsize_t)k;
                    tv_ptr->start[3] = (hsize_t)l;
                    tv_ptr->start[4] = 0;

                    ret = H5Sselect_hyperslab(tv_ptr->file_large_ds_sid_0, H5S_SELECT_SET, tv_ptr->start_ptr,
                                              tv_ptr->stride_ptr, tv_ptr->count_ptr, tv_ptr->block_ptr);
                    VRFY((ret != FAIL), "H5Sselect_hyperslab() target large ds slice succeeded");

                    /* verify that H5Sselect_shape_same() reports the in
                     * memory small data set slice selection and the
                     * on disk slice through the large data set selection
                     * as having the same shape.
                     */
                    check = H5Sselect_shape_same(tv_ptr->mem_small_ds_sid, tv_ptr->file_large_ds_sid_0);
                    VRFY((check == true), "H5Sselect_shape_same passed");

                    /* write the small data set slice from memory to the
                     * target slice of the disk data set
                     */
#if CONTIG_HS_DR_PIO_TEST__M2D_S2L__DEBUG
                    fprintf(stdout, "%s:%d: start = %d %d %d %d %d.\n", fcnName, (int)(tv_ptr->mpi_rank),
                            (int)(tv_ptr->start[0]), (int)(tv_ptr->start[1]), (int)(tv_ptr->start[2]),
                            (int)(tv_ptr->start[3]), (int)(tv_ptr->start[4]));
                    fprintf(stdout, "%s:%d: mem/file extent dims = %d/%d.\n", fcnName, tv_ptr->mpi_rank,
                            H5Sget_simple_extent_ndims(tv_ptr->mem_small_ds_sid),
                            H5Sget_simple_extent_ndims(tv_ptr->file_large_ds_sid_0));
#endif /* CONTIG_HS_DR_PIO_TEST__M2D_S2L__DEBUG */
                    ret = H5Dwrite(tv_ptr->large_dataset, H5T_NATIVE_UINT32, tv_ptr->mem_small_ds_sid,
                                   tv_ptr->file_large_ds_sid_0, tv_ptr->xfer_plist, tv_ptr->small_ds_buf_0);
                    VRFY((ret != FAIL), "H5Dwrite of small ds slice to large ds succeeded");

                    /* read this processes slice on the on disk large
                     * data set into memory.
                     */

                    ret = H5Dread(
                        tv_ptr->large_dataset, H5T_NATIVE_UINT32, tv_ptr->mem_large_ds_process_slice_sid,
                        tv_ptr->file_large_ds_process_slice_sid, tv_ptr->xfer_plist, tv_ptr->large_ds_buf_1);
                    VRFY((ret != FAIL), "H5Dread() of process slice of large ds succeeded");

                    /* verify that the expected data and only the
                     * expected data was read.
                     */
                    ptr_1          = tv_ptr->large_ds_buf_1;
                    expected_value = (uint32_t)((size_t)(tv_ptr->mpi_rank) * tv_ptr->small_ds_slice_size);

                    start_index =
                        (size_t)((i * tv_ptr->edge_size * tv_ptr->edge_size * tv_ptr->edge_size *
                                  tv_ptr->edge_size) +
                                 (j * tv_ptr->edge_size * tv_ptr->edge_size * tv_ptr->edge_size) +
                                 (k * tv_ptr->edge_size * tv_ptr->edge_size) + (l * tv_ptr->edge_size));
                    stop_index = start_index + tv_ptr->small_ds_slice_size - 1;

                    assert(start_index < stop_index);
                    assert(stop_index < tv_ptr->large_ds_size);

                    for (n = 0; n < tv_ptr->large_ds_size; n++) {

                        if ((n >= start_index) && (n <= stop_index)) {

                            if (*ptr_1 != expected_value) {

                                mis_match = true;
                            }

                            expected_value++;
                        }
                        else {

                            if (*ptr_1 != 0) {

                                mis_match = true;
                            }
                        }
                        /* zero out buffer for next test */
                        *ptr_1 = 0;
                        ptr_1++;
                    }

                    VRFY((mis_match == false), "small ds slice write to large ds slice data good.");

                    (tv_ptr->tests_run)++;
                }

                l++;

                (tv_ptr->total_tests)++;

            } while ((tv_ptr->large_rank > 2) && ((tv_ptr->small_rank - 1) <= 1) && (l < tv_ptr->edge_size));
            k++;
        } while ((tv_ptr->large_rank > 3) && ((tv_ptr->small_rank - 1) <= 2) && (k < tv_ptr->edge_size));
        j++;
    } while ((tv_ptr->large_rank > 4) && ((tv_ptr->small_rank - 1) <= 3) && (j < tv_ptr->edge_size));

    return;

} /* contig_hs_dr_pio_test__m2d_s2l() */

/*-------------------------------------------------------------------------
 * Function:    contig_hs_dr_pio_test__run_test()
 *
 * Purpose:    Test I/O to/from hyperslab selections of different rank in
 *        the parallel.
 *
 * Return:    void
 *
 *-------------------------------------------------------------------------
 */

#define CONTIG_HS_DR_PIO_TEST__RUN_TEST__DEBUG 0

static void
contig_hs_dr_pio_test__run_test(const int test_num, const int edge_size, const int chunk_edge_size,
                                const int small_rank, const int large_rank, const bool use_collective_io,
                                const hid_t dset_type, int express_test, int *skips_ptr, int max_skips,
                                int64_t *total_tests_ptr, int64_t *tests_run_ptr, int64_t *tests_skipped_ptr,
                                int mpi_rank)
{
#if CONTIG_HS_DR_PIO_TEST__RUN_TEST__DEBUG
    const char *fcnName = "contig_hs_dr_pio_test__run_test()";
#endif /* CONTIG_HS_DR_PIO_TEST__RUN_TEST__DEBUG */
    struct hs_dr_pio_test_vars_t test_vars = {
        /* int           mpi_size                        = */ -1,
        /* int         mpi_rank                        = */ -1,
        /* MPI_Comm    mpi_comm                        = */ MPI_COMM_NULL,
        /* MPI_Inf     mpi_info                        = */ MPI_INFO_NULL,
        /* int         test_num                        = */ -1,
        /* int         edge_size                       = */ -1,
        /* int         checker_edge_size               = */ -1,
        /* int         chunk_edge_size                 = */ -1,
        /* int         small_rank                      = */ -1,
        /* int         large_rank                      = */ -1,
        /* hid_t       dset_type                       = */ H5I_INVALID_HID,
        /* uint32_t  * small_ds_buf_0                  = */ NULL,
        /* uint32_t  * small_ds_buf_1                  = */ NULL,
        /* uint32_t  * small_ds_buf_2                  = */ NULL,
        /* uint32_t  * small_ds_slice_buf              = */ NULL,
        /* uint32_t  * large_ds_buf_0                  = */ NULL,
        /* uint32_t  * large_ds_buf_1                  = */ NULL,
        /* uint32_t  * large_ds_buf_2                  = */ NULL,
        /* uint32_t  * large_ds_slice_buf              = */ NULL,
        /* int         small_ds_offset                 = */ -1,
        /* int         large_ds_offset                 = */ -1,
        /* hid_t       fid                             = */ H5I_INVALID_HID, /* HDF5 file ID */
        /* hid_t       xfer_plist                      = */ H5P_DEFAULT,
        /* hid_t       full_mem_small_ds_sid           = */ H5I_INVALID_HID,
        /* hid_t       full_file_small_ds_sid          = */ H5I_INVALID_HID,
        /* hid_t       mem_small_ds_sid                = */ H5I_INVALID_HID,
        /* hid_t       file_small_ds_sid_0             = */ H5I_INVALID_HID,
        /* hid_t       file_small_ds_sid_1             = */ H5I_INVALID_HID,
        /* hid_t       small_ds_slice_sid              = */ H5I_INVALID_HID,
        /* hid_t       full_mem_large_ds_sid           = */ H5I_INVALID_HID,
        /* hid_t       full_file_large_ds_sid          = */ H5I_INVALID_HID,
        /* hid_t       mem_large_ds_sid                = */ H5I_INVALID_HID,
        /* hid_t       file_large_ds_sid_0             = */ H5I_INVALID_HID,
        /* hid_t       file_large_ds_sid_1             = */ H5I_INVALID_HID,
        /* hid_t       file_large_ds_process_slice_sid = */ H5I_INVALID_HID,
        /* hid_t       mem_large_ds_process_slice_sid  = */ H5I_INVALID_HID,
        /* hid_t       large_ds_slice_sid              = */ H5I_INVALID_HID,
        /* hid_t       small_dataset                   = */ H5I_INVALID_HID, /* Dataset ID */
        /* hid_t       large_dataset                   = */ H5I_INVALID_HID, /* Dataset ID */
        /* size_t      small_ds_size                   = */ 1,
        /* size_t      small_ds_slice_size             = */ 1,
        /* size_t      large_ds_size                   = */ 1,
        /* size_t      large_ds_slice_size             = */ 1,
        /* hsize_t     dims[PAR_SS_DR_MAX_RANK]        = */ {0, 0, 0, 0, 0},
        /* hsize_t     chunk_dims[PAR_SS_DR_MAX_RANK]  = */ {0, 0, 0, 0, 0},
        /* hsize_t     start[PAR_SS_DR_MAX_RANK]       = */ {0, 0, 0, 0, 0},
        /* hsize_t     stride[PAR_SS_DR_MAX_RANK]      = */ {0, 0, 0, 0, 0},
        /* hsize_t     count[PAR_SS_DR_MAX_RANK]       = */ {0, 0, 0, 0, 0},
        /* hsize_t     block[PAR_SS_DR_MAX_RANK]       = */ {0, 0, 0, 0, 0},
        /* hsize_t   * start_ptr                       = */ NULL,
        /* hsize_t   * stride_ptr                      = */ NULL,
        /* hsize_t   * count_ptr                       = */ NULL,
        /* hsize_t   * block_ptr                       = */ NULL,
        /* int            skips                           = */ 0,
        /* int            max_skips                       = */ 0,
        /* int64_t     total_tests                     = */ 0,
        /* int64_t     tests_run                       = */ 0,
        /* int64_t     tests_skipped                   = */ 0};
    struct hs_dr_pio_test_vars_t *tv_ptr = &test_vars;

    if (MAINPROCESS)
        printf("\r - running test #%lld: small rank = %d, large rank = %d", (long long)(test_num + 1),
               small_rank, large_rank);

    hs_dr_pio_test__setup(test_num, edge_size, -1, chunk_edge_size, small_rank, large_rank, use_collective_io,
                          dset_type, express_test, tv_ptr);

    /* initialize skips & max_skips */
    tv_ptr->skips     = *skips_ptr;
    tv_ptr->max_skips = max_skips;

#if CONTIG_HS_DR_PIO_TEST__RUN_TEST__DEBUG
    if (MAINPROCESS) {
        fprintf(stdout, "test %d: small rank = %d, large rank = %d.\n", test_num, small_rank, large_rank);
        fprintf(stdout, "test %d: Initialization complete.\n", test_num);
    }
#endif /* CONTIG_HS_DR_PIO_TEST__RUN_TEST__DEBUG */

    /* first, verify that we can read from disk correctly using selections
     * of different rank that H5Sselect_shape_same() views as being of the
     * same shape.
     *
     * Start by reading small_rank - 1 dimensional slice from the on disk
     * large cube, and verifying that the data read is correct.  Verify that
     * H5Sselect_shape_same() returns true on the memory and file selections.
     */

#if CONTIG_HS_DR_PIO_TEST__RUN_TEST__DEBUG
    if (MAINPROCESS) {
        fprintf(stdout, "test %d: running contig_hs_dr_pio_test__d2m_l2s.\n", test_num);
    }
#endif /* CONTIG_HS_DR_PIO_TEST__RUN_TEST__DEBUG */
    contig_hs_dr_pio_test__d2m_l2s(tv_ptr);

    /* Second, read slices of the on disk small data set into slices
     * through the in memory large data set, and verify that the correct
     * data (and only the correct data) is read.
     */

#if CONTIG_HS_DR_PIO_TEST__RUN_TEST__DEBUG
    if (MAINPROCESS) {
        fprintf(stdout, "test %d: running contig_hs_dr_pio_test__d2m_s2l.\n", test_num);
    }
#endif /* CONTIG_HS_DR_PIO_TEST__RUN_TEST__DEBUG */
    contig_hs_dr_pio_test__d2m_s2l(tv_ptr);

    /* now we go in the opposite direction, verifying that we can write
     * from memory to file using selections of different rank that
     * H5Sselect_shape_same() views as being of the same shape.
     *
     * Start by writing small_rank - 1 D slices from the in memory large data
     * set to the on disk small cube dataset.  After each write, read the
     * slice of the small dataset back from disk, and verify that it contains
     * the expected data. Verify that H5Sselect_shape_same() returns true on
     * the memory and file selections.
     */

#if CONTIG_HS_DR_PIO_TEST__RUN_TEST__DEBUG
    if (MAINPROCESS) {
        fprintf(stdout, "test %d: running contig_hs_dr_pio_test__m2d_l2s.\n", test_num);
    }
#endif /* CONTIG_HS_DR_PIO_TEST__RUN_TEST__DEBUG */
    contig_hs_dr_pio_test__m2d_l2s(tv_ptr);

    /* Now write the contents of the process's slice of the in memory
     * small data set to slices of the on disk large data set.  After
     * each write, read the process's slice of the large data set back
     * into memory, and verify that it contains the expected data.
     * Verify that H5Sselect_shape_same() returns true on the memory
     * and file selections.
     */

#if CONTIG_HS_DR_PIO_TEST__RUN_TEST__DEBUG
    if (MAINPROCESS) {
        fprintf(stdout, "test %d: running contig_hs_dr_pio_test__m2d_s2l.\n", test_num);
    }
#endif /* CONTIG_HS_DR_PIO_TEST__RUN_TEST__DEBUG */
    contig_hs_dr_pio_test__m2d_s2l(tv_ptr);

#if CONTIG_HS_DR_PIO_TEST__RUN_TEST__DEBUG
    if (MAINPROCESS) {
        fprintf(stdout, "test %d: Subtests complete -- tests run/skipped/total = %lld/%lld/%lld.\n", test_num,
                (long long)(tv_ptr->tests_run), (long long)(tv_ptr->tests_skipped),
                (long long)(tv_ptr->total_tests));
    }
#endif /* CONTIG_HS_DR_PIO_TEST__RUN_TEST__DEBUG */

    hs_dr_pio_test__takedown(tv_ptr);

#if CONTIG_HS_DR_PIO_TEST__RUN_TEST__DEBUG
    if (MAINPROCESS) {
        fprintf(stdout, "test %d: Takedown complete.\n", test_num);
    }
#endif /* CONTIG_HS_DR_PIO_TEST__RUN_TEST__DEBUG */

    *skips_ptr = tv_ptr->skips;
    *total_tests_ptr += tv_ptr->total_tests;
    *tests_run_ptr += tv_ptr->tests_run;
    *tests_skipped_ptr += tv_ptr->tests_skipped;

    return;

} /* contig_hs_dr_pio_test__run_test() */

/*-------------------------------------------------------------------------
 * Function:    contig_hs_dr_pio_test(ShapeSameTestMethods sstest_type)
 *
 * Purpose:    Test I/O to/from hyperslab selections of different rank in
 *        the parallel case.
 *
 * Return:    void
 *
 *-------------------------------------------------------------------------
 */

#define CONTIG_HS_DR_PIO_TEST__DEBUG 0

static void
contig_hs_dr_pio_test(ShapeSameTestMethods sstest_type)
{
    int express_test;
    int local_express_test;
    int mpi_rank = -1;
    int mpi_size;
    int test_num = 0;
    int edge_size;
    int chunk_edge_size = 0;
    int small_rank;
    int large_rank;
    int mpi_result;
    int skips     = 0;
    int max_skips = 0;
    /* The following table list the number of sub-tests skipped between
     * each test that is actually executed as a function of the express
     * test level.  Note that any value in excess of 4880 will cause all
     * sub tests to be skipped.
     */
    int     max_skips_tbl[4] = {0, 4, 64, 1024};
    hid_t   dset_type        = H5T_NATIVE_UINT;
    int64_t total_tests      = 0;
    int64_t tests_run        = 0;
    int64_t tests_skipped    = 0;

    HDcompile_assert(sizeof(uint32_t) == sizeof(unsigned));

    MPI_Comm_size(MPI_COMM_WORLD, &mpi_size);
    MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);

    edge_size = (mpi_size > 6 ? mpi_size : 6);

    local_express_test = GetTestExpress();

    mpi_result = MPI_Allreduce((void *)&local_express_test, (void *)&express_test, 1, MPI_INT, MPI_MAX,
                               MPI_COMM_WORLD);

    VRFY((mpi_result == MPI_SUCCESS), "MPI_Allreduce(0) succeeded");

    if (local_express_test < 0) {
        max_skips = max_skips_tbl[0];
    }
    else if (local_express_test > 3) {
        max_skips = max_skips_tbl[3];
    }
    else {
        max_skips = max_skips_tbl[local_express_test];
    }

    for (large_rank = 3; large_rank <= PAR_SS_DR_MAX_RANK; large_rank++) {

        for (small_rank = 2; small_rank < large_rank; small_rank++) {

            switch (sstest_type) {
                case IND_CONTIG:
                    /* contiguous data set, independent I/O */
                    chunk_edge_size = 0;

                    contig_hs_dr_pio_test__run_test(
                        test_num, edge_size, chunk_edge_size, small_rank, large_rank, false, dset_type,
                        express_test, &skips, max_skips, &total_tests, &tests_run, &tests_skipped, mpi_rank);
                    test_num++;
                    break;
                    /* end of case IND_CONTIG */

                case COL_CONTIG:
                    /* contiguous data set, collective I/O */
                    chunk_edge_size = 0;

                    contig_hs_dr_pio_test__run_test(
                        test_num, edge_size, chunk_edge_size, small_rank, large_rank, true, dset_type,
                        express_test, &skips, max_skips, &total_tests, &tests_run, &tests_skipped, mpi_rank);
                    test_num++;
                    break;
                    /* end of case COL_CONTIG */

                case IND_CHUNKED:
                    /* chunked data set, independent I/O */
                    chunk_edge_size = 5;

                    contig_hs_dr_pio_test__run_test(
                        test_num, edge_size, chunk_edge_size, small_rank, large_rank, false, dset_type,
                        express_test, &skips, max_skips, &total_tests, &tests_run, &tests_skipped, mpi_rank);
                    test_num++;
                    break;
                    /* end of case IND_CHUNKED */

                case COL_CHUNKED:
                    /* chunked data set, collective I/O */
                    chunk_edge_size = 5;

                    contig_hs_dr_pio_test__run_test(
                        test_num, edge_size, chunk_edge_size, small_rank, large_rank, true, dset_type,
                        express_test, &skips, max_skips, &total_tests, &tests_run, &tests_skipped, mpi_rank);
                    test_num++;
                    break;
                    /* end of case COL_CHUNKED */

                default:
                    VRFY((false), "unknown test type");
                    break;

            } /* end of switch(sstest_type) */
#if CONTIG_HS_DR_PIO_TEST__DEBUG
            if ((MAINPROCESS) && (tests_skipped > 0)) {
                fprintf(stdout, "    run/skipped/total = %lld/%lld/%lld.\n", tests_run, tests_skipped,
                        total_tests);
            }
#endif /* CONTIG_HS_DR_PIO_TEST__DEBUG */
        }
    }

    if (MAINPROCESS) {
        if (tests_skipped > 0) {
            fprintf(stdout, "    %" PRId64 " of %" PRId64 " subtests skipped to expedite testing.\n",
                    tests_skipped, total_tests);
        }
        else
            printf("\n");
    }

    return;

} /* contig_hs_dr_pio_test() */

/****************************************************************
**
**  ckrbrd_hs_dr_pio_test__slct_ckrbrd():
**    Given a dataspace of tgt_rank, and dimensions:
**
**        (mpi_size + 1), edge_size, ... , edge_size
**
**    edge_size, and a checker_edge_size, select a checker
**    board selection of a sel_rank (sel_rank < tgt_rank)
**    dimensional slice through the dataspace parallel to the
**      sel_rank fastest changing indices, with origin (in the
**    higher indices) as indicated by the start array.
**
**    Note that this function, like all its relatives, is
**    hard coded to presume a maximum dataspace rank of 5.
**    While this maximum is declared as a constant, increasing
**    it will require extensive coding in addition to changing
**      the value of the constant.
**
**                    JRM -- 10/8/09
**
****************************************************************/

#define CKRBRD_HS_DR_PIO_TEST__SELECT_CHECKER_BOARD__DEBUG 0

static void
ckrbrd_hs_dr_pio_test__slct_ckrbrd(const int mpi_rank, const hid_t tgt_sid, const int tgt_rank,
                                   const int edge_size, const int checker_edge_size, const int sel_rank,
                                   hsize_t sel_start[])
{
#if CKRBRD_HS_DR_PIO_TEST__SELECT_CHECKER_BOARD__DEBUG
    const char *fcnName = "ckrbrd_hs_dr_pio_test__slct_ckrbrd():";
#endif
    bool      first_selection = true;
    int       i, j, k, l, m;
    int       n_cube_offset;
    int       sel_offset;
    const int test_max_rank = PAR_SS_DR_MAX_RANK; /* must update code if */
                                                  /* this changes        */
    hsize_t base_count;
    hsize_t offset_count;
    hsize_t start[PAR_SS_DR_MAX_RANK];
    hsize_t stride[PAR_SS_DR_MAX_RANK];
    hsize_t count[PAR_SS_DR_MAX_RANK];
    hsize_t block[PAR_SS_DR_MAX_RANK];
    herr_t  ret; /* Generic return value */

    assert(edge_size >= 6);
    assert(0 < checker_edge_size);
    assert(checker_edge_size <= edge_size);
    assert(0 < sel_rank);
    assert(sel_rank <= tgt_rank);
    assert(tgt_rank <= test_max_rank);
    assert(test_max_rank <= PAR_SS_DR_MAX_RANK);

    sel_offset = test_max_rank - sel_rank;
    assert(sel_offset >= 0);

    n_cube_offset = test_max_rank - tgt_rank;
    assert(n_cube_offset >= 0);
    assert(n_cube_offset <= sel_offset);

#if CKRBRD_HS_DR_PIO_TEST__SELECT_CHECKER_BOARD__DEBUG
    fprintf(stdout, "%s:%d: edge_size/checker_edge_size = %d/%d\n", fcnName, mpi_rank, edge_size,
            checker_edge_size);
    fprintf(stdout, "%s:%d: sel_rank/sel_offset = %d/%d.\n", fcnName, mpi_rank, sel_rank, sel_offset);
    fprintf(stdout, "%s:%d: tgt_rank/n_cube_offset = %d/%d.\n", fcnName, mpi_rank, tgt_rank, n_cube_offset);
#endif /* CKRBRD_HS_DR_PIO_TEST__SELECT_CHECKER_BOARD__DEBUG */

    /* First, compute the base count (which assumes start == 0
     * for the associated offset) and offset_count (which
     * assumes start == checker_edge_size for the associated
     * offset).
     *
     * Note that the following computation depends on the C99
     * requirement that integer division discard any fraction
     * (truncation towards zero) to function correctly. As we
     * now require C99, this shouldn't be a problem, but noting
     * it may save us some pain if we are ever obliged to support
     * pre-C99 compilers again.
     */

    base_count = (hsize_t)(edge_size / (checker_edge_size * 2));

    if ((edge_size % (checker_edge_size * 2)) > 0) {

        base_count++;
    }

    offset_count = (hsize_t)((edge_size - checker_edge_size) / (checker_edge_size * 2));

    if (((edge_size - checker_edge_size) % (checker_edge_size * 2)) > 0) {

        offset_count++;
    }

    /* Now set up the stride and block arrays, and portions of the start
     * and count arrays that will not be altered during the selection of
     * the checker board.
     */
    i = 0;
    while (i < n_cube_offset) {

        /* these values should never be used */
        start[i]  = 0;
        stride[i] = 0;
        count[i]  = 0;
        block[i]  = 0;

        i++;
    }

    while (i < sel_offset) {

        start[i]  = sel_start[i];
        stride[i] = (hsize_t)(2 * edge_size);
        count[i]  = 1;
        block[i]  = 1;

        i++;
    }

    while (i < test_max_rank) {

        stride[i] = (hsize_t)(2 * checker_edge_size);
        block[i]  = (hsize_t)checker_edge_size;

        i++;
    }

    i = 0;
    do {
        if (0 >= sel_offset) {

            if (i == 0) {

                start[0] = 0;
                count[0] = base_count;
            }
            else {

                start[0] = (hsize_t)checker_edge_size;
                count[0] = offset_count;
            }
        }

        j = 0;
        do {
            if (1 >= sel_offset) {

                if (j == 0) {

                    start[1] = 0;
                    count[1] = base_count;
                }
                else {

                    start[1] = (hsize_t)checker_edge_size;
                    count[1] = offset_count;
                }
            }

            k = 0;
            do {
                if (2 >= sel_offset) {

                    if (k == 0) {

                        start[2] = 0;
                        count[2] = base_count;
                    }
                    else {

                        start[2] = (hsize_t)checker_edge_size;
                        count[2] = offset_count;
                    }
                }

                l = 0;
                do {
                    if (3 >= sel_offset) {

                        if (l == 0) {

                            start[3] = 0;
                            count[3] = base_count;
                        }
                        else {

                            start[3] = (hsize_t)checker_edge_size;
                            count[3] = offset_count;
                        }
                    }

                    m = 0;
                    do {
                        if (4 >= sel_offset) {

                            if (m == 0) {

                                start[4] = 0;
                                count[4] = base_count;
                            }
                            else {

                                start[4] = (hsize_t)checker_edge_size;
                                count[4] = offset_count;
                            }
                        }

                        if (((i + j + k + l + m) % 2) == 0) {

#if CKRBRD_HS_DR_PIO_TEST__SELECT_CHECKER_BOARD__DEBUG
                            fprintf(stdout, "%s%d: *** first_selection = %d ***\n", fcnName, mpi_rank,
                                    (int)first_selection);
                            fprintf(stdout, "%s:%d: i/j/k/l/m = %d/%d/%d/%d/%d\n", fcnName, mpi_rank, i, j, k,
                                    l, m);
                            fprintf(stdout, "%s:%d: start = %d %d %d %d %d.\n", fcnName, mpi_rank,
                                    (int)start[0], (int)start[1], (int)start[2], (int)start[3],
                                    (int)start[4]);
                            fprintf(stdout, "%s:%d: stride = %d %d %d %d %d.\n", fcnName, mpi_rank,
                                    (int)stride[0], (int)stride[1], (int)stride[2], (int)stride[3],
                                    (int)stride[4]);
                            fprintf(stdout, "%s:%d: count = %d %d %d %d %d.\n", fcnName, mpi_rank,
                                    (int)count[0], (int)count[1], (int)count[2], (int)count[3],
                                    (int)count[4]);
                            fprintf(stdout, "%s:%d: block = %d %d %d %d %d.\n", fcnName, mpi_rank,
                                    (int)block[0], (int)block[1], (int)block[2], (int)block[3],
                                    (int)block[4]);
                            fprintf(stdout, "%s:%d: n-cube extent dims = %d.\n", fcnName, mpi_rank,
                                    H5Sget_simple_extent_ndims(tgt_sid));
                            fprintf(stdout, "%s:%d: selection rank = %d.\n", fcnName, mpi_rank, sel_rank);
#endif

                            if (first_selection) {

                                first_selection = false;

                                ret = H5Sselect_hyperslab(tgt_sid, H5S_SELECT_SET, &(start[n_cube_offset]),
                                                          &(stride[n_cube_offset]), &(count[n_cube_offset]),
                                                          &(block[n_cube_offset]));

                                VRFY((ret != FAIL), "H5Sselect_hyperslab(SET) succeeded");
                            }
                            else {

                                ret = H5Sselect_hyperslab(tgt_sid, H5S_SELECT_OR, &(start[n_cube_offset]),
                                                          &(stride[n_cube_offset]), &(count[n_cube_offset]),
                                                          &(block[n_cube_offset]));

                                VRFY((ret != FAIL), "H5Sselect_hyperslab(OR) succeeded");
                            }
                        }

                        m++;

                    } while ((m <= 1) && (4 >= sel_offset));

                    l++;

                } while ((l <= 1) && (3 >= sel_offset));

                k++;

            } while ((k <= 1) && (2 >= sel_offset));

            j++;

        } while ((j <= 1) && (1 >= sel_offset));

        i++;

    } while ((i <= 1) && (0 >= sel_offset));

#if CKRBRD_HS_DR_PIO_TEST__SELECT_CHECKER_BOARD__DEBUG
    fprintf(stdout, "%s%d: H5Sget_select_npoints(tgt_sid) = %d.\n", fcnName, mpi_rank,
            (int)H5Sget_select_npoints(tgt_sid));
#endif /* CKRBRD_HS_DR_PIO_TEST__SELECT_CHECKER_BOARD__DEBUG */

    /* Clip the selection back to the dataspace proper. */

    for (i = 0; i < test_max_rank; i++) {

        start[i]  = 0;
        stride[i] = (hsize_t)edge_size;
        count[i]  = 1;
        block[i]  = (hsize_t)edge_size;
    }

    ret = H5Sselect_hyperslab(tgt_sid, H5S_SELECT_AND, start, stride, count, block);

    VRFY((ret != FAIL), "H5Sselect_hyperslab(AND) succeeded");

#if CKRBRD_HS_DR_PIO_TEST__SELECT_CHECKER_BOARD__DEBUG
    fprintf(stdout, "%s%d: H5Sget_select_npoints(tgt_sid) = %d.\n", fcnName, mpi_rank,
            (int)H5Sget_select_npoints(tgt_sid));
    fprintf(stdout, "%s%d: done.\n", fcnName, mpi_rank);
#endif /* CKRBRD_HS_DR_PIO_TEST__SELECT_CHECKER_BOARD__DEBUG */

    return;

} /* ckrbrd_hs_dr_pio_test__slct_ckrbrd() */

/****************************************************************
**
**  ckrbrd_hs_dr_pio_test__verify_data():
**
**    Examine the supplied buffer to see if it contains the
**    expected data.  Return true if it does, and false
**      otherwise.
**
**    The supplied buffer is presumed to this process's slice
**    of the target data set.  Each such slice will be an
**    n-cube of rank (rank -1) and the supplied edge_size with
**    origin (mpi_rank, 0, ... , 0) in the target data set.
**
**    Further, the buffer is presumed to be the result of reading
**    or writing a checker board selection of an m (1 <= m <
**      rank) dimensional slice through this processes slice
**    of the target data set.  Also, this slice must be parallel
**    to the fastest changing indices.
**
**    It is further presumed that the buffer was zeroed before
**    the read/write, and that the full target data set (i.e.
**    the buffer/data set for all processes) was initialized
**      with the natural numbers listed in order from the origin
**    along the fastest changing axis.
**
**      Thus for a 20x10x10 dataset, the value stored in location
**    (x, y, z) (assuming that z is the fastest changing index
**    and x the slowest) is assumed to be:
**
**        (10 * 10 * x) + (10 * y) + z
**
**    Further, supposing that this is process 10, this process's
**    slice of the dataset would be a 10 x 10 2-cube with origin
**    (10, 0, 0) in the data set, and would be initialize (prior
**    to the checkerboard selection) as follows:
**
**        1000, 1001, 1002, ... 1008, 1009
**        1010, 1011, 1012, ... 1018, 1019
**          .     .     .         .     .
**          .     .     .         .     .
**          .     .     .         .     .
**        1090, 1091, 1092, ... 1098, 1099
**
**    In the case of a read from the processors slice of another
**    data set of different rank, the values expected will have
**    to be adjusted accordingly.  This is done via the
**    first_expected_val parameter.
**
**    Finally, the function presumes that the first element
**    of the buffer resides either at the origin of either
**    a selected or an unselected checker.  (Translation:
**    if partial checkers appear in the buffer, they will
**    intersect the edges of the n-cube opposite the origin.)
**
****************************************************************/

#define CKRBRD_HS_DR_PIO_TEST__VERIFY_DATA__DEBUG 0

static bool
ckrbrd_hs_dr_pio_test__verify_data(uint32_t *buf_ptr, const int rank, const int edge_size,
                                   const int checker_edge_size, uint32_t first_expected_val,
                                   bool buf_starts_in_checker)
{
#if CKRBRD_HS_DR_PIO_TEST__VERIFY_DATA__DEBUG
    const char *fcnName = "ckrbrd_hs_dr_pio_test__verify_data():";
#endif
    bool      good_data = true;
    bool      in_checker;
    bool      start_in_checker[5];
    uint32_t  expected_value;
    uint32_t *val_ptr;
    int       i, j, k, l, m;     /* to track position in n-cube */
    int       v, w, x, y, z;     /* to track position in checker */
    const int test_max_rank = 5; /* code changes needed if this is increased */

    assert(buf_ptr != NULL);
    assert(0 < rank);
    assert(rank <= test_max_rank);
    assert(edge_size >= 6);
    assert(0 < checker_edge_size);
    assert(checker_edge_size <= edge_size);
    assert(test_max_rank <= PAR_SS_DR_MAX_RANK);

#if CKRBRD_HS_DR_PIO_TEST__VERIFY_DATA__DEBUG

    int mpi_rank;

    MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
    fprintf(stdout, "%s mpi_rank = %d.\n", fcnName, mpi_rank);
    fprintf(stdout, "%s rank = %d.\n", fcnName, rank);
    fprintf(stdout, "%s edge_size = %d.\n", fcnName, edge_size);
    fprintf(stdout, "%s checker_edge_size = %d.\n", fcnName, checker_edge_size);
    fprintf(stdout, "%s first_expected_val = %d.\n", fcnName, (int)first_expected_val);
    fprintf(stdout, "%s starts_in_checker = %d.\n", fcnName, (int)buf_starts_in_checker);
}
#endif

val_ptr        = buf_ptr;
expected_value = first_expected_val;

i                   = 0;
v                   = 0;
start_in_checker[0] = buf_starts_in_checker;
do {
    if (v >= checker_edge_size) {

        start_in_checker[0] = !start_in_checker[0];
        v                   = 0;
    }

    j                   = 0;
    w                   = 0;
    start_in_checker[1] = start_in_checker[0];
    do {
        if (w >= checker_edge_size) {

            start_in_checker[1] = !start_in_checker[1];
            w                   = 0;
        }

        k                   = 0;
        x                   = 0;
        start_in_checker[2] = start_in_checker[1];
        do {
            if (x >= checker_edge_size) {

                start_in_checker[2] = !start_in_checker[2];
                x                   = 0;
            }

            l                   = 0;
            y                   = 0;
            start_in_checker[3] = start_in_checker[2];
            do {
                if (y >= checker_edge_size) {

                    start_in_checker[3] = !start_in_checker[3];
                    y                   = 0;
                }

                m = 0;
                z = 0;
#if CKRBRD_HS_DR_PIO_TEST__VERIFY_DATA__DEBUG
                fprintf(stdout, "%d, %d, %d, %d, %d:", i, j, k, l, m);
#endif
                in_checker = start_in_checker[3];
                do {
#if CKRBRD_HS_DR_PIO_TEST__VERIFY_DATA__DEBUG
                    fprintf(stdout, " %d", (int)(*val_ptr));
#endif
                    if (z >= checker_edge_size) {

                        in_checker = !in_checker;
                        z          = 0;
                    }

                    if (in_checker) {

                        if (*val_ptr != expected_value) {

                            good_data = false;
                        }

                        /* zero out buffer for reuse */
                        *val_ptr = 0;
                    }
                    else if (*val_ptr != 0) {

                        good_data = false;

                        /* zero out buffer for reuse */
                        *val_ptr = 0;
                    }

                    val_ptr++;
                    expected_value++;
                    m++;
                    z++;

                } while ((rank >= (test_max_rank - 4)) && (m < edge_size));
#if CKRBRD_HS_DR_PIO_TEST__VERIFY_DATA__DEBUG
                fprintf(stdout, "\n");
#endif
                l++;
                y++;
            } while ((rank >= (test_max_rank - 3)) && (l < edge_size));
            k++;
            x++;
        } while ((rank >= (test_max_rank - 2)) && (k < edge_size));
        j++;
        w++;
    } while ((rank >= (test_max_rank - 1)) && (j < edge_size));
    i++;
    v++;
} while ((rank >= test_max_rank) && (i < edge_size));

return (good_data);

} /* ckrbrd_hs_dr_pio_test__verify_data() */

/*-------------------------------------------------------------------------
 * Function:    ckrbrd_hs_dr_pio_test__d2m_l2s()
 *
 * Purpose:    Part one of a series of tests of I/O to/from hyperslab
 *        selections of different rank in the parallel.
 *
 *        Verify that we can read from disk correctly using checker
 *        board selections of different rank that
 *        H5Sselect_shape_same() views as being of the same shape.
 *
 *        In this function, we test this by reading small_rank - 1
 *        checker board slices from the on disk large cube, and
 *        verifying that the data read is correct.  Verify that
 *        H5Sselect_shape_same() returns true on the memory and
 *        file selections.
 *
 * Return:    void
 *
 *-------------------------------------------------------------------------
 */

#define CHECKER_BOARD_HS_DR_PIO_TEST__D2M_L2S__DEBUG 0

static void
ckrbrd_hs_dr_pio_test__d2m_l2s(struct hs_dr_pio_test_vars_t *tv_ptr)
{
#if CHECKER_BOARD_HS_DR_PIO_TEST__D2M_L2S__DEBUG
    const char *fcnName = "ckrbrd_hs_dr_pio_test__d2m_l2s()";
    uint32_t   *ptr_0;
#endif /* CHECKER_BOARD_HS_DR_PIO_TEST__D2M_L2S__DEBUG */
    bool     data_ok = false;
    int      i, j, k, l;
    uint32_t expected_value;
    int      mpi_rank; /* needed by VRFY */
    hsize_t  sel_start[PAR_SS_DR_MAX_RANK];
    htri_t   check; /* Shape comparison return value */
    herr_t   ret;   /* Generic return value */

    /* initialize the local copy of mpi_rank */
    mpi_rank = tv_ptr->mpi_rank;

    /* first, verify that we can read from disk correctly using selections
     * of different rank that H5Sselect_shape_same() views as being of the
     * same shape.
     *
     * Start by reading a (small_rank - 1)-D checker board slice from this
     * processes slice of the on disk large data set, and verifying that the
     * data read is correct.  Verify that H5Sselect_shape_same() returns
     * true on the memory and file selections.
     *
     * The first step is to set up the needed checker board selection in the
     * in memory small small cube
     */

    sel_start[0] = sel_start[1] = sel_start[2] = sel_start[3] = sel_start[4] = 0;
    sel_start[tv_ptr->small_ds_offset]                                       = (hsize_t)(tv_ptr->mpi_rank);

    ckrbrd_hs_dr_pio_test__slct_ckrbrd(tv_ptr->mpi_rank, tv_ptr->small_ds_slice_sid, tv_ptr->small_rank - 1,
                                       tv_ptr->edge_size, tv_ptr->checker_edge_size, tv_ptr->small_rank - 1,
                                       sel_start);

    /* zero out the buffer we will be reading into */
    memset(tv_ptr->small_ds_slice_buf, 0, sizeof(uint32_t) * tv_ptr->small_ds_slice_size);

#if CHECKER_BOARD_HS_DR_PIO_TEST__D2M_L2S__DEBUG
    fprintf(stdout, "%s:%d: initial small_ds_slice_buf = ", fcnName, tv_ptr->mpi_rank);
    ptr_0 = tv_ptr->small_ds_slice_buf;
    for (i = 0; i < (int)(tv_ptr->small_ds_slice_size); i++) {
        fprintf(stdout, "%d ", (int)(*ptr_0));
        ptr_0++;
    }
    fprintf(stdout, "\n");
#endif /* CHECKER_BOARD_HS_DR_PIO_TEST__D2M_L2S__DEBUG */

    /* set up start, stride, count, and block -- note that we will
     * change start[] so as to read slices of the large cube.
     */
    for (i = 0; i < PAR_SS_DR_MAX_RANK; i++) {

        tv_ptr->start[i]  = 0;
        tv_ptr->stride[i] = (hsize_t)(2 * tv_ptr->edge_size);
        tv_ptr->count[i]  = 1;
        if ((PAR_SS_DR_MAX_RANK - i) > (tv_ptr->small_rank - 1)) {

            tv_ptr->block[i] = 1;
        }
        else {

            tv_ptr->block[i] = (hsize_t)(tv_ptr->edge_size);
        }
    }

#if CHECKER_BOARD_HS_DR_PIO_TEST__D2M_L2S__DEBUG
    fprintf(stdout, "%s:%d: reading slice from big ds on disk into small ds slice.\n", fcnName,
            tv_ptr->mpi_rank);
#endif /* CHECKER_BOARD_HS_DR_PIO_TEST__D2M_L2S__DEBUG */
    /* in serial versions of this test, we loop through all the dimensions
     * of the large data set.  However, in the parallel version, each
     * process only works with that slice of the large cube indicated
     * by its rank -- hence we set the most slowly changing index to
     * mpi_rank, and don't iterate over it.
     */

    if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 0) {

        i = tv_ptr->mpi_rank;
    }
    else {

        i = 0;
    }

    /* since large_rank is at most PAR_SS_DR_MAX_RANK, no need to
     * loop over it -- either we are setting i to mpi_rank, or
     * we are setting it to zero.  It will not change during the
     * test.
     */

    if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 1) {

        j = tv_ptr->mpi_rank;
    }
    else {

        j = 0;
    }

    do {
        if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 2) {

            k = tv_ptr->mpi_rank;
        }
        else {

            k = 0;
        }

        do {
            /* since small rank >= 2 and large_rank > small_rank, we
             * have large_rank >= 3.  Since PAR_SS_DR_MAX_RANK == 5
             * (baring major re-orgaization), this gives us:
             *
             *     (PAR_SS_DR_MAX_RANK - large_rank) <= 2
             *
             * so no need to repeat the test in the outer loops --
             * just set l = 0.
             */

            l = 0;
            do {
                if ((tv_ptr->skips)++ < tv_ptr->max_skips) { /* skip the test */

                    (tv_ptr->tests_skipped)++;
                }
                else { /* run the test */

                    tv_ptr->skips = 0; /* reset the skips counter */

                    /* we know that small_rank - 1 >= 1 and that
                     * large_rank > small_rank by the assertions at the head
                     * of this function.  Thus no need for another inner loop.
                     */
                    tv_ptr->start[0] = (hsize_t)i;
                    tv_ptr->start[1] = (hsize_t)j;
                    tv_ptr->start[2] = (hsize_t)k;
                    tv_ptr->start[3] = (hsize_t)l;
                    tv_ptr->start[4] = 0;

                    assert((tv_ptr->start[0] == 0) || (0 < tv_ptr->small_ds_offset + 1));
                    assert((tv_ptr->start[1] == 0) || (1 < tv_ptr->small_ds_offset + 1));
                    assert((tv_ptr->start[2] == 0) || (2 < tv_ptr->small_ds_offset + 1));
                    assert((tv_ptr->start[3] == 0) || (3 < tv_ptr->small_ds_offset + 1));
                    assert((tv_ptr->start[4] == 0) || (4 < tv_ptr->small_ds_offset + 1));

                    ckrbrd_hs_dr_pio_test__slct_ckrbrd(
                        tv_ptr->mpi_rank, tv_ptr->file_large_ds_sid_0, tv_ptr->large_rank, tv_ptr->edge_size,
                        tv_ptr->checker_edge_size, tv_ptr->small_rank - 1, tv_ptr->start);

                    /* verify that H5Sselect_shape_same() reports the two
                     * selections as having the same shape.
                     */
                    check = H5Sselect_shape_same(tv_ptr->small_ds_slice_sid, tv_ptr->file_large_ds_sid_0);
                    VRFY((check == true), "H5Sselect_shape_same passed");

                    /* Read selection from disk */
#if CHECKER_BOARD_HS_DR_PIO_TEST__D2M_L2S__DEBUG
                    fprintf(stdout, "%s:%d: start = %d %d %d %d %d.\n", fcnName, tv_ptr->mpi_rank,
                            tv_ptr->start[0], tv_ptr->start[1], tv_ptr->start[2], tv_ptr->start[3],
                            tv_ptr->start[4]);
                    fprintf(stdout, "%s slice/file extent dims = %d/%d.\n", fcnName,
                            H5Sget_simple_extent_ndims(tv_ptr->small_ds_slice_sid),
                            H5Sget_simple_extent_ndims(tv_ptr->file_large_ds_sid_0));
#endif /* CHECKER_BOARD_HS_DR_PIO_TEST__D2M_L2S__DEBUG */

                    ret =
                        H5Dread(tv_ptr->large_dataset, H5T_NATIVE_UINT32, tv_ptr->small_ds_slice_sid,
                                tv_ptr->file_large_ds_sid_0, tv_ptr->xfer_plist, tv_ptr->small_ds_slice_buf);
                    VRFY((ret >= 0), "H5Dread() slice from large ds succeeded.");

#if CHECKER_BOARD_HS_DR_PIO_TEST__D2M_L2S__DEBUG
                    fprintf(stdout, "%s:%d: H5Dread() returns.\n", fcnName, tv_ptr->mpi_rank);
#endif /* CHECKER_BOARD_HS_DR_PIO_TEST__D2M_L2S__DEBUG */

                    /* verify that expected data is retrieved */

                    expected_value =
                        (uint32_t)((i * tv_ptr->edge_size * tv_ptr->edge_size * tv_ptr->edge_size *
                                    tv_ptr->edge_size) +
                                   (j * tv_ptr->edge_size * tv_ptr->edge_size * tv_ptr->edge_size) +
                                   (k * tv_ptr->edge_size * tv_ptr->edge_size) + (l * tv_ptr->edge_size));

                    data_ok = ckrbrd_hs_dr_pio_test__verify_data(
                        tv_ptr->small_ds_slice_buf, tv_ptr->small_rank - 1, tv_ptr->edge_size,
                        tv_ptr->checker_edge_size, expected_value, (bool)true);

                    VRFY((data_ok == true), "small slice read from large ds data good.");

                    (tv_ptr->tests_run)++;
                }

                l++;

                (tv_ptr->total_tests)++;

            } while ((tv_ptr->large_rank > 2) && ((tv_ptr->small_rank - 1) <= 1) && (l < tv_ptr->edge_size));
            k++;
        } while ((tv_ptr->large_rank > 3) && ((tv_ptr->small_rank - 1) <= 2) && (k < tv_ptr->edge_size));
        j++;
    } while ((tv_ptr->large_rank > 4) && ((tv_ptr->small_rank - 1) <= 3) && (j < tv_ptr->edge_size));

    return;

} /* ckrbrd_hs_dr_pio_test__d2m_l2s() */

/*-------------------------------------------------------------------------
 * Function:    ckrbrd_hs_dr_pio_test__d2m_s2l()
 *
 * Purpose:    Part two of a series of tests of I/O to/from hyperslab
 *        selections of different rank in the parallel.
 *
 *        Verify that we can read from disk correctly using
 *        selections of different rank that H5Sselect_shape_same()
 *        views as being of the same shape.
 *
 *        In this function, we test this by reading checker board
 *        slices of the on disk small data set into slices through
 *        the in memory large data set, and verify that the correct
 *        data (and only the correct data) is read.
 *
 * Return:    void
 *
 *-------------------------------------------------------------------------
 */

#define CHECKER_BOARD_HS_DR_PIO_TEST__D2M_S2L__DEBUG 0

static void
ckrbrd_hs_dr_pio_test__d2m_s2l(struct hs_dr_pio_test_vars_t *tv_ptr)
{
#if CHECKER_BOARD_HS_DR_PIO_TEST__D2M_S2L__DEBUG
    const char *fcnName = "ckrbrd_hs_dr_pio_test__d2m_s2l()";
#endif /* CHECKER_BOARD_HS_DR_PIO_TEST__D2M_S2L__DEBUG */
    bool      data_ok = false;
    int       i, j, k, l;
    size_t    u;
    size_t    start_index;
    size_t    stop_index;
    uint32_t  expected_value;
    uint32_t *ptr_1;
    int       mpi_rank; /* needed by VRFY */
    hsize_t   sel_start[PAR_SS_DR_MAX_RANK];
    htri_t    check; /* Shape comparison return value */
    herr_t    ret;   /* Generic return value */

    /* initialize the local copy of mpi_rank */
    mpi_rank = tv_ptr->mpi_rank;

    /* similarly, read slices of the on disk small data set into slices
     * through the in memory large data set, and verify that the correct
     * data (and only the correct data) is read.
     */

    sel_start[0] = sel_start[1] = sel_start[2] = sel_start[3] = sel_start[4] = 0;
    sel_start[tv_ptr->small_ds_offset]                                       = (hsize_t)(tv_ptr->mpi_rank);

    ckrbrd_hs_dr_pio_test__slct_ckrbrd(tv_ptr->mpi_rank, tv_ptr->file_small_ds_sid_0, tv_ptr->small_rank,
                                       tv_ptr->edge_size, tv_ptr->checker_edge_size, tv_ptr->small_rank - 1,
                                       sel_start);

#if CHECKER_BOARD_HS_DR_PIO_TEST__D2M_S2L__DEBUG
    fprintf(stdout, "%s reading slices of on disk small data set into slices of big data set.\n", fcnName);
#endif /* CHECKER_BOARD_HS_DR_PIO_TEST__D2M_S2L__DEBUG */

    /* zero out the buffer we will be reading into */
    memset(tv_ptr->large_ds_buf_1, 0, sizeof(uint32_t) * tv_ptr->large_ds_size);

    /* set up start, stride, count, and block -- note that we will
     * change start[] so as to read the slice of the small data set
     * into different slices of the process slice of the large data
     * set.
     */
    for (i = 0; i < PAR_SS_DR_MAX_RANK; i++) {

        tv_ptr->start[i]  = 0;
        tv_ptr->stride[i] = (hsize_t)(2 * tv_ptr->edge_size);
        tv_ptr->count[i]  = 1;
        if ((PAR_SS_DR_MAX_RANK - i) > (tv_ptr->small_rank - 1)) {

            tv_ptr->block[i] = 1;
        }
        else {

            tv_ptr->block[i] = (hsize_t)(tv_ptr->edge_size);
        }
    }

    /* in serial versions of this test, we loop through all the dimensions
     * of the large data set that don't appear in the small data set.
     *
     * However, in the parallel version, each process only works with that
     * slice of the large (and small) data set indicated by its rank -- hence
     * we set the most slowly changing index to mpi_rank, and don't iterate
     * over it.
     */

    if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 0) {

        i = tv_ptr->mpi_rank;
    }
    else {

        i = 0;
    }

    /* since large_rank is at most PAR_SS_DR_MAX_RANK, no need to
     * loop over it -- either we are setting i to mpi_rank, or
     * we are setting it to zero.  It will not change during the
     * test.
     */

    if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 1) {

        j = tv_ptr->mpi_rank;
    }
    else {

        j = 0;
    }

    do {
        if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 2) {

            k = tv_ptr->mpi_rank;
        }
        else {

            k = 0;
        }

        do {
            /* since small rank >= 2 and large_rank > small_rank, we
             * have large_rank >= 3.  Since PAR_SS_DR_MAX_RANK == 5
             * (baring major re-orgaization), this gives us:
             *
             *     (PAR_SS_DR_MAX_RANK - large_rank) <= 2
             *
             * so no need to repeat the test in the outer loops --
             * just set l = 0.
             */

            l = 0;
            do {
                if ((tv_ptr->skips)++ < tv_ptr->max_skips) { /* skip the test */

                    (tv_ptr->tests_skipped)++;
                }
                else { /* run the test */

                    tv_ptr->skips = 0; /* reset the skips counter */

                    /* we know that small_rank >= 1 and that large_rank > small_rank
                     * by the assertions at the head of this function.  Thus no
                     * need for another inner loop.
                     */
                    tv_ptr->start[0] = (hsize_t)i;
                    tv_ptr->start[1] = (hsize_t)j;
                    tv_ptr->start[2] = (hsize_t)k;
                    tv_ptr->start[3] = (hsize_t)l;
                    tv_ptr->start[4] = 0;

                    assert((tv_ptr->start[0] == 0) || (0 < tv_ptr->small_ds_offset + 1));
                    assert((tv_ptr->start[1] == 0) || (1 < tv_ptr->small_ds_offset + 1));
                    assert((tv_ptr->start[2] == 0) || (2 < tv_ptr->small_ds_offset + 1));
                    assert((tv_ptr->start[3] == 0) || (3 < tv_ptr->small_ds_offset + 1));
                    assert((tv_ptr->start[4] == 0) || (4 < tv_ptr->small_ds_offset + 1));

                    ckrbrd_hs_dr_pio_test__slct_ckrbrd(
                        tv_ptr->mpi_rank, tv_ptr->mem_large_ds_sid, tv_ptr->large_rank, tv_ptr->edge_size,
                        tv_ptr->checker_edge_size, tv_ptr->small_rank - 1, tv_ptr->start);

                    /* verify that H5Sselect_shape_same() reports the two
                     * selections as having the same shape.
                     */
                    check = H5Sselect_shape_same(tv_ptr->file_small_ds_sid_0, tv_ptr->mem_large_ds_sid);
                    VRFY((check == true), "H5Sselect_shape_same passed");

                    /* Read selection from disk */
#if CHECKER_BOARD_HS_DR_PIO_TEST__D2M_S2L__DEBUG
                    fprintf(stdout, "%s:%d: start = %d %d %d %d %d.\n", fcnName, tv_ptr->mpi_rank,
                            tv_ptr->start[0], tv_ptr->start[1], tv_ptr->start[2], tv_ptr->start[3],
                            tv_ptr->start[4]);
                    fprintf(stdout, "%s:%d: mem/file extent dims = %d/%d.\n", fcnName, tv_ptr->mpi_rank,
                            H5Sget_simple_extent_ndims(tv_ptr->large_ds_slice_sid),
                            H5Sget_simple_extent_ndims(tv_ptr->file_small_ds_sid_0));
#endif /* CHECKER_BOARD_HS_DR_PIO_TEST__D2M_S2L__DEBUG */
                    ret = H5Dread(tv_ptr->small_dataset, H5T_NATIVE_UINT32, tv_ptr->mem_large_ds_sid,
                                  tv_ptr->file_small_ds_sid_0, tv_ptr->xfer_plist, tv_ptr->large_ds_buf_1);
                    VRFY((ret >= 0), "H5Dread() slice from small ds succeeded.");

                    /* verify that the expected data and only the
                     * expected data was read.
                     */
                    data_ok        = true;
                    ptr_1          = tv_ptr->large_ds_buf_1;
                    expected_value = (uint32_t)((size_t)(tv_ptr->mpi_rank) * tv_ptr->small_ds_slice_size);
                    start_index =
                        (size_t)((i * tv_ptr->edge_size * tv_ptr->edge_size * tv_ptr->edge_size *
                                  tv_ptr->edge_size) +
                                 (j * tv_ptr->edge_size * tv_ptr->edge_size * tv_ptr->edge_size) +
                                 (k * tv_ptr->edge_size * tv_ptr->edge_size) + (l * tv_ptr->edge_size));
                    stop_index = start_index + tv_ptr->small_ds_slice_size - 1;

#if CHECKER_BOARD_HS_DR_PIO_TEST__D2M_S2L__DEBUG
                    {
                        int m, n;

                        fprintf(stdout, "%s:%d: expected_value = %d.\n", fcnName, tv_ptr->mpi_rank,
                                expected_value);
                        fprintf(stdout, "%s:%d: start/stop index = %d/%d.\n", fcnName, tv_ptr->mpi_rank,
                                start_index, stop_index);
                        n = 0;
                        for (m = 0; (unsigned)m < tv_ptr->large_ds_size; m++) {
                            fprintf(stdout, "%d ", (int)(*ptr_1));
                            ptr_1++;
                            n++;
                            if (n >= tv_ptr->edge_size) {
                                fprintf(stdout, "\n");
                                n = 0;
                            }
                        }
                        fprintf(stdout, "\n");
                        ptr_1 = tv_ptr->large_ds_buf_1;
                    }
#endif /* CHECKER_BOARD_HS_DR_PIO_TEST__D2M_S2L__DEBUG */

                    assert(start_index < stop_index);
                    assert(stop_index <= tv_ptr->large_ds_size);

                    for (u = 0; u < start_index; u++) {

                        if (*ptr_1 != 0) {

                            data_ok = false;
                        }

                        /* zero out the value for the next pass */
                        *ptr_1 = 0;

                        ptr_1++;
                    }

                    VRFY((data_ok == true), "slice read from small to large ds data good(1).");

                    data_ok = ckrbrd_hs_dr_pio_test__verify_data(ptr_1, tv_ptr->small_rank - 1,
                                                                 tv_ptr->edge_size, tv_ptr->checker_edge_size,
                                                                 expected_value, (bool)true);

                    VRFY((data_ok == true), "slice read from small to large ds data good(2).");

                    ptr_1 = tv_ptr->large_ds_buf_1 + stop_index + 1;

                    for (u = stop_index + 1; u < tv_ptr->large_ds_size; u++) {

                        if (*ptr_1 != 0) {

                            data_ok = false;
                        }

                        /* zero out the value for the next pass */
                        *ptr_1 = 0;

                        ptr_1++;
                    }

                    VRFY((data_ok == true), "slice read from small to large ds data good(3).");

                    (tv_ptr->tests_run)++;
                }

                l++;

                (tv_ptr->total_tests)++;

            } while ((tv_ptr->large_rank > 2) && ((tv_ptr->small_rank - 1) <= 1) && (l < tv_ptr->edge_size));
            k++;
        } while ((tv_ptr->large_rank > 3) && ((tv_ptr->small_rank - 1) <= 2) && (k < tv_ptr->edge_size));
        j++;
    } while ((tv_ptr->large_rank > 4) && ((tv_ptr->small_rank - 1) <= 3) && (j < tv_ptr->edge_size));

    return;

} /* ckrbrd_hs_dr_pio_test__d2m_s2l() */

/*-------------------------------------------------------------------------
 * Function:    ckrbrd_hs_dr_pio_test__m2d_l2s()
 *
 * Purpose:    Part three of a series of tests of I/O to/from checker
 *        board hyperslab selections of different rank in the
 *        parallel.
 *
 *        Verify that we can write from memory to file using checker
 *        board selections of different rank that
 *        H5Sselect_shape_same() views as being of the same shape.
 *
 *        Do this by writing small_rank - 1 dimensional checker
 *        board slices from the in memory large data set to the on
 *        disk small cube dataset.  After each write, read the
 *        slice of the small dataset back from disk, and verify
 *        that it contains the expected data. Verify that
 *        H5Sselect_shape_same() returns true on the memory and
 *        file selections.
 *
 * Return:    void
 *
 *-------------------------------------------------------------------------
 */

#define CHECKER_BOARD_HS_DR_PIO_TEST__M2D_L2S__DEBUG 0

static void
ckrbrd_hs_dr_pio_test__m2d_l2s(struct hs_dr_pio_test_vars_t *tv_ptr)
{
#if CHECKER_BOARD_HS_DR_PIO_TEST__M2D_L2S__DEBUG
    const char *fcnName = "ckrbrd_hs_dr_pio_test__m2d_l2s()";
#endif /* CHECKER_BOARD_HS_DR_PIO_TEST__M2D_L2S__DEBUG */
    bool      data_ok = false;
    int       i, j, k, l;
    size_t    u;
    size_t    start_index;
    size_t    stop_index;
    uint32_t  expected_value;
    uint32_t *ptr_1;
    int       mpi_rank; /* needed by VRFY */
    hsize_t   sel_start[PAR_SS_DR_MAX_RANK];
    htri_t    check; /* Shape comparison return value */
    herr_t    ret;   /* Generic return value */

    /* initialize the local copy of mpi_rank */
    mpi_rank = tv_ptr->mpi_rank;

    /* now we go in the opposite direction, verifying that we can write
     * from memory to file using selections of different rank that
     * H5Sselect_shape_same() views as being of the same shape.
     *
     * Start by writing small_rank - 1 D slices from the in memory large data
     * set to the on disk small dataset.  After each write, read the slice of
     * the small dataset back from disk, and verify that it contains the
     * expected data. Verify that H5Sselect_shape_same() returns true on
     * the memory and file selections.
     */

    tv_ptr->start[0]  = (hsize_t)(tv_ptr->mpi_rank);
    tv_ptr->stride[0] = (hsize_t)(2 * (tv_ptr->mpi_size + 1));
    tv_ptr->count[0]  = 1;
    tv_ptr->block[0]  = 1;

    for (i = 1; i < tv_ptr->large_rank; i++) {

        tv_ptr->start[i]  = 0;
        tv_ptr->stride[i] = (hsize_t)(2 * tv_ptr->edge_size);
        tv_ptr->count[i]  = 1;
        tv_ptr->block[i]  = (hsize_t)(tv_ptr->edge_size);
    }

    ret = H5Sselect_hyperslab(tv_ptr->file_small_ds_sid_0, H5S_SELECT_SET, tv_ptr->start, tv_ptr->stride,
                              tv_ptr->count, tv_ptr->block);
    VRFY((ret >= 0), "H5Sselect_hyperslab(file_small_ds_sid_0, set) succeeded");

    ret = H5Sselect_hyperslab(tv_ptr->mem_small_ds_sid, H5S_SELECT_SET, tv_ptr->start, tv_ptr->stride,
                              tv_ptr->count, tv_ptr->block);
    VRFY((ret >= 0), "H5Sselect_hyperslab(mem_small_ds_sid, set) succeeded");

    sel_start[0] = sel_start[1] = sel_start[2] = sel_start[3] = sel_start[4] = 0;
    sel_start[tv_ptr->small_ds_offset]                                       = (hsize_t)(tv_ptr->mpi_rank);

    ckrbrd_hs_dr_pio_test__slct_ckrbrd(tv_ptr->mpi_rank, tv_ptr->file_small_ds_sid_1, tv_ptr->small_rank,
                                       tv_ptr->edge_size, tv_ptr->checker_edge_size, tv_ptr->small_rank - 1,
                                       sel_start);

    /* set up start, stride, count, and block -- note that we will
     * change start[] so as to read slices of the large cube.
     */
    for (i = 0; i < PAR_SS_DR_MAX_RANK; i++) {

        tv_ptr->start[i]  = 0;
        tv_ptr->stride[i] = (hsize_t)(2 * tv_ptr->edge_size);
        tv_ptr->count[i]  = 1;
        if ((PAR_SS_DR_MAX_RANK - i) > (tv_ptr->small_rank - 1)) {

            tv_ptr->block[i] = 1;
        }
        else {

            tv_ptr->block[i] = (hsize_t)(tv_ptr->edge_size);
        }
    }

    /* zero out the in memory small ds */
    memset(tv_ptr->small_ds_buf_1, 0, sizeof(uint32_t) * tv_ptr->small_ds_size);

#if CHECKER_BOARD_HS_DR_PIO_TEST__M2D_L2S__DEBUG
    fprintf(stdout,
            "%s writing checker boards selections of slices from big ds to slices of small ds on disk.\n",
            fcnName);
#endif /* CHECKER_BOARD_HS_DR_PIO_TEST__M2D_L2S__DEBUG */

    /* in serial versions of this test, we loop through all the dimensions
     * of the large data set that don't appear in the small data set.
     *
     * However, in the parallel version, each process only works with that
     * slice of the large (and small) data set indicated by its rank -- hence
     * we set the most slowly changing index to mpi_rank, and don't iterate
     * over it.
     */

    if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 0) {

        i = tv_ptr->mpi_rank;
    }
    else {

        i = 0;
    }

    /* since large_rank is at most PAR_SS_DR_MAX_RANK, no need to
     * loop over it -- either we are setting i to mpi_rank, or
     * we are setting it to zero.  It will not change during the
     * test.
     */

    if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 1) {

        j = tv_ptr->mpi_rank;
    }
    else {

        j = 0;
    }

    j = 0;
    do {
        if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 2) {

            k = tv_ptr->mpi_rank;
        }
        else {

            k = 0;
        }

        do {
            /* since small rank >= 2 and large_rank > small_rank, we
             * have large_rank >= 3.  Since PAR_SS_DR_MAX_RANK == 5
             * (baring major re-orgaization), this gives us:
             *
             *     (PAR_SS_DR_MAX_RANK - large_rank) <= 2
             *
             * so no need to repeat the test in the outer loops --
             * just set l = 0.
             */

            l = 0;
            do {
                if ((tv_ptr->skips)++ < tv_ptr->max_skips) { /* skip the test */

                    (tv_ptr->tests_skipped)++;
                }
                else { /* run the test */

                    tv_ptr->skips = 0; /* reset the skips counter */

                    /* we know that small_rank >= 1 and that large_rank > small_rank
                     * by the assertions at the head of this function.  Thus no
                     * need for another inner loop.
                     */

                    /* zero out this rank's slice of the on disk small data set */
                    ret = H5Dwrite(tv_ptr->small_dataset, H5T_NATIVE_UINT32, tv_ptr->mem_small_ds_sid,
                                   tv_ptr->file_small_ds_sid_0, tv_ptr->xfer_plist, tv_ptr->small_ds_buf_2);
                    VRFY((ret >= 0), "H5Dwrite() zero slice to small ds succeeded.");

                    /* select the portion of the in memory large cube from which we
                     * are going to write data.
                     */
                    tv_ptr->start[0] = (hsize_t)i;
                    tv_ptr->start[1] = (hsize_t)j;
                    tv_ptr->start[2] = (hsize_t)k;
                    tv_ptr->start[3] = (hsize_t)l;
                    tv_ptr->start[4] = 0;

                    assert((tv_ptr->start[0] == 0) || (0 < tv_ptr->small_ds_offset + 1));
                    assert((tv_ptr->start[1] == 0) || (1 < tv_ptr->small_ds_offset + 1));
                    assert((tv_ptr->start[2] == 0) || (2 < tv_ptr->small_ds_offset + 1));
                    assert((tv_ptr->start[3] == 0) || (3 < tv_ptr->small_ds_offset + 1));
                    assert((tv_ptr->start[4] == 0) || (4 < tv_ptr->small_ds_offset + 1));

                    ckrbrd_hs_dr_pio_test__slct_ckrbrd(
                        tv_ptr->mpi_rank, tv_ptr->mem_large_ds_sid, tv_ptr->large_rank, tv_ptr->edge_size,
                        tv_ptr->checker_edge_size, tv_ptr->small_rank - 1, tv_ptr->start);

                    /* verify that H5Sselect_shape_same() reports the in
                     * memory checkerboard selection of the slice through the
                     * large dataset and the checkerboard selection of the process
                     * slice of the small data set as having the same shape.
                     */
                    check = H5Sselect_shape_same(tv_ptr->file_small_ds_sid_1, tv_ptr->mem_large_ds_sid);
                    VRFY((check == true), "H5Sselect_shape_same passed.");

                    /* write the checker board selection of the slice from the in
                     * memory large data set to the slice of the on disk small
                     * dataset.
                     */
#if CHECKER_BOARD_HS_DR_PIO_TEST__M2D_L2S__DEBUG
                    fprintf(stdout, "%s:%d: start = %d %d %d %d %d.\n", fcnName, tv_ptr->mpi_rank,
                            tv_ptr->start[0], tv_ptr->start[1], tv_ptr->start[2], tv_ptr->start[3],
                            tv_ptr->start[4]);
                    fprintf(stdout, "%s:%d: mem/file extent dims = %d/%d.\n", fcnName, tv_ptr->mpi_rank,
                            H5Sget_simple_extent_ndims(tv_ptr->mem_large_ds_sid),
                            H5Sget_simple_extent_ndims(tv_ptr->file_small_ds_sid_1));
#endif /* CHECKER_BOARD_HS_DR_PIO_TEST__M2D_L2S__DEBUG */
                    ret = H5Dwrite(tv_ptr->small_dataset, H5T_NATIVE_UINT32, tv_ptr->mem_large_ds_sid,
                                   tv_ptr->file_small_ds_sid_1, tv_ptr->xfer_plist, tv_ptr->large_ds_buf_0);
                    VRFY((ret >= 0), "H5Dwrite() slice to large ds succeeded.");

                    /* read the on disk process slice of the small dataset into memory */
                    ret = H5Dread(tv_ptr->small_dataset, H5T_NATIVE_UINT32, tv_ptr->mem_small_ds_sid,
                                  tv_ptr->file_small_ds_sid_0, tv_ptr->xfer_plist, tv_ptr->small_ds_buf_1);
                    VRFY((ret >= 0), "H5Dread() slice from small ds succeeded.");

                    /* verify that expected data is retrieved */

                    expected_value =
                        (uint32_t)((i * tv_ptr->edge_size * tv_ptr->edge_size * tv_ptr->edge_size *
                                    tv_ptr->edge_size) +
                                   (j * tv_ptr->edge_size * tv_ptr->edge_size * tv_ptr->edge_size) +
                                   (k * tv_ptr->edge_size * tv_ptr->edge_size) + (l * tv_ptr->edge_size));

                    start_index = (size_t)(tv_ptr->mpi_rank) * tv_ptr->small_ds_slice_size;
                    stop_index  = start_index + tv_ptr->small_ds_slice_size - 1;

                    assert(start_index < stop_index);
                    assert(stop_index <= tv_ptr->small_ds_size);

                    data_ok = true;

                    ptr_1 = tv_ptr->small_ds_buf_1;
                    for (u = 0; u < start_index; u++, ptr_1++) {

                        if (*ptr_1 != 0) {

                            data_ok = false;
                            *ptr_1  = 0;
                        }
                    }

                    data_ok &= ckrbrd_hs_dr_pio_test__verify_data(
                        tv_ptr->small_ds_buf_1 + start_index, tv_ptr->small_rank - 1, tv_ptr->edge_size,
                        tv_ptr->checker_edge_size, expected_value, (bool)true);

                    ptr_1 = tv_ptr->small_ds_buf_1;
                    for (u = stop_index; u < tv_ptr->small_ds_size; u++, ptr_1++) {

                        if (*ptr_1 != 0) {

                            data_ok = false;
                            *ptr_1  = 0;
                        }
                    }

                    VRFY((data_ok == true), "large slice write slice to small slice data good.");

                    (tv_ptr->tests_run)++;
                }

                l++;

                (tv_ptr->total_tests)++;

            } while ((tv_ptr->large_rank > 2) && ((tv_ptr->small_rank - 1) <= 1) && (l < tv_ptr->edge_size));
            k++;
        } while ((tv_ptr->large_rank > 3) && ((tv_ptr->small_rank - 1) <= 2) && (k < tv_ptr->edge_size));
        j++;
    } while ((tv_ptr->large_rank > 4) && ((tv_ptr->small_rank - 1) <= 3) && (j < tv_ptr->edge_size));

    return;

} /* ckrbrd_hs_dr_pio_test__m2d_l2s() */

/*-------------------------------------------------------------------------
 * Function:    ckrbrd_hs_dr_pio_test__m2d_s2l()
 *
 * Purpose:    Part four of a series of tests of I/O to/from checker
 *        board hyperslab selections of different rank in the parallel.
 *
 *        Verify that we can write from memory to file using
 *        selections of different rank that H5Sselect_shape_same()
 *        views as being of the same shape.
 *
 *        Do this by writing checker board selections of the contents
 *        of the process's slice of the in memory small data set to
 *        slices of the on disk large data set.  After each write,
 *        read the process's slice of the large data set back into
 *        memory, and verify that it contains the expected data.
 *
 *        Verify that H5Sselect_shape_same() returns true on the
 *        memory and file selections.
 *
 * Return:    void
 *
 *-------------------------------------------------------------------------
 */

#define CHECKER_BOARD_HS_DR_PIO_TEST__M2D_S2L__DEBUG 0

static void
ckrbrd_hs_dr_pio_test__m2d_s2l(struct hs_dr_pio_test_vars_t *tv_ptr)
{
#if CHECKER_BOARD_HS_DR_PIO_TEST__M2D_S2L__DEBUG
    const char *fcnName = "ckrbrd_hs_dr_pio_test__m2d_s2l()";
#endif /* CONTIG_HS_DR_PIO_TEST__M2D_S2L__DEBUG */
    bool      data_ok = false;
    int       i, j, k, l;
    size_t    u;
    size_t    start_index;
    size_t    stop_index;
    uint32_t  expected_value;
    uint32_t *ptr_1;
    int       mpi_rank; /* needed by VRFY */
    hsize_t   sel_start[PAR_SS_DR_MAX_RANK];
    htri_t    check; /* Shape comparison return value */
    herr_t    ret;   /* Generic return value */

    /* initialize the local copy of mpi_rank */
    mpi_rank = tv_ptr->mpi_rank;

    /* Now write the contents of the process's slice of the in memory
     * small data set to slices of the on disk large data set.  After
     * each write, read the process's slice of the large data set back
     * into memory, and verify that it contains the expected data.
     * Verify that H5Sselect_shape_same() returns true on the memory
     * and file selections.
     */

    tv_ptr->start[0]  = (hsize_t)(tv_ptr->mpi_rank);
    tv_ptr->stride[0] = (hsize_t)(2 * (tv_ptr->mpi_size + 1));
    tv_ptr->count[0]  = 1;
    tv_ptr->block[0]  = 1;

    for (i = 1; i < tv_ptr->large_rank; i++) {

        tv_ptr->start[i]  = 0;
        tv_ptr->stride[i] = (hsize_t)(2 * tv_ptr->edge_size);
        tv_ptr->count[i]  = 1;
        tv_ptr->block[i]  = (hsize_t)(tv_ptr->edge_size);
    }

    ret = H5Sselect_hyperslab(tv_ptr->file_large_ds_sid_0, H5S_SELECT_SET, tv_ptr->start, tv_ptr->stride,
                              tv_ptr->count, tv_ptr->block);
    VRFY((ret >= 0), "H5Sselect_hyperslab(file_large_ds_sid_0, set) succeeded");

    ret = H5Sselect_hyperslab(tv_ptr->mem_large_ds_sid, H5S_SELECT_SET, tv_ptr->start, tv_ptr->stride,
                              tv_ptr->count, tv_ptr->block);
    VRFY((ret >= 0), "H5Sselect_hyperslab(tv_ptr->mem_large_ds_sid, set) succeeded");

    /* setup a checkerboard selection of the slice of the in memory small
     * data set associated with the process's mpi rank.
     */

    sel_start[0] = sel_start[1] = sel_start[2] = sel_start[3] = sel_start[4] = 0;
    sel_start[tv_ptr->small_ds_offset]                                       = (hsize_t)(tv_ptr->mpi_rank);

    ckrbrd_hs_dr_pio_test__slct_ckrbrd(tv_ptr->mpi_rank, tv_ptr->mem_small_ds_sid, tv_ptr->small_rank,
                                       tv_ptr->edge_size, tv_ptr->checker_edge_size, tv_ptr->small_rank - 1,
                                       sel_start);

    /* set up start, stride, count, and block -- note that we will
     * change start[] so as to write checkerboard selections of slices
     * of the small data set to slices of the large data set.
     */
    for (i = 0; i < PAR_SS_DR_MAX_RANK; i++) {

        tv_ptr->start[i]  = 0;
        tv_ptr->stride[i] = (hsize_t)(2 * tv_ptr->edge_size);
        tv_ptr->count[i]  = 1;
        if ((PAR_SS_DR_MAX_RANK - i) > (tv_ptr->small_rank - 1)) {

            tv_ptr->block[i] = 1;
        }
        else {

            tv_ptr->block[i] = (hsize_t)(tv_ptr->edge_size);
        }
    }

    /* zero out the in memory large ds */
    memset(tv_ptr->large_ds_buf_1, 0, sizeof(uint32_t) * tv_ptr->large_ds_size);

#if CHECKER_BOARD_HS_DR_PIO_TEST__M2D_S2L__DEBUG
    fprintf(stdout,
            "%s writing process checkerboard selections of slices of small ds to process slices of large "
            "ds on disk.\n",
            fcnName);
#endif /* CHECKER_BOARD_HS_DR_PIO_TEST__M2D_S2L__DEBUG */

    if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 0) {

        i = tv_ptr->mpi_rank;
    }
    else {

        i = 0;
    }

    /* since large_rank is at most PAR_SS_DR_MAX_RANK, no need to
     * loop over it -- either we are setting i to mpi_rank, or
     * we are setting it to zero.  It will not change during the
     * test.
     */

    if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 1) {

        j = tv_ptr->mpi_rank;
    }
    else {

        j = 0;
    }

    do {
        if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 2) {

            k = tv_ptr->mpi_rank;
        }
        else {

            k = 0;
        }

        do {
            /* since small rank >= 2 and large_rank > small_rank, we
             * have large_rank >= 3.  Since PAR_SS_DR_MAX_RANK == 5
             * (baring major re-orgaization), this gives us:
             *
             *     (PAR_SS_DR_MAX_RANK - large_rank) <= 2
             *
             * so no need to repeat the test in the outer loops --
             * just set l = 0.
             */

            l = 0;
            do {
                if ((tv_ptr->skips)++ < tv_ptr->max_skips) { /* skip the test */

                    (tv_ptr->tests_skipped)++;
                }
                else { /* run the test */

                    tv_ptr->skips = 0; /* reset the skips counter */

                    /* we know that small_rank >= 1 and that large_rank > small_rank
                     * by the assertions at the head of this function.  Thus no
                     * need for another inner loop.
                     */

                    /* Zero out this processes slice of the on disk large data set.
                     * Note that this will leave one slice with its original data
                     * as there is one more slice than processes.
                     */
                    ret = H5Dwrite(tv_ptr->large_dataset, H5T_NATIVE_UINT32, tv_ptr->mem_large_ds_sid,
                                   tv_ptr->file_large_ds_sid_0, tv_ptr->xfer_plist, tv_ptr->large_ds_buf_2);
                    VRFY((ret != FAIL), "H5Dwrite() to zero large ds succeeded");

                    /* select the portion of the in memory large cube to which we
                     * are going to write data.
                     */
                    tv_ptr->start[0] = (hsize_t)i;
                    tv_ptr->start[1] = (hsize_t)j;
                    tv_ptr->start[2] = (hsize_t)k;
                    tv_ptr->start[3] = (hsize_t)l;
                    tv_ptr->start[4] = 0;

                    assert((tv_ptr->start[0] == 0) || (0 < tv_ptr->small_ds_offset + 1));
                    assert((tv_ptr->start[1] == 0) || (1 < tv_ptr->small_ds_offset + 1));
                    assert((tv_ptr->start[2] == 0) || (2 < tv_ptr->small_ds_offset + 1));
                    assert((tv_ptr->start[3] == 0) || (3 < tv_ptr->small_ds_offset + 1));
                    assert((tv_ptr->start[4] == 0) || (4 < tv_ptr->small_ds_offset + 1));

                    ckrbrd_hs_dr_pio_test__slct_ckrbrd(
                        tv_ptr->mpi_rank, tv_ptr->file_large_ds_sid_1, tv_ptr->large_rank, tv_ptr->edge_size,
                        tv_ptr->checker_edge_size, tv_ptr->small_rank - 1, tv_ptr->start);

                    /* verify that H5Sselect_shape_same() reports the in
                     * memory small data set slice selection and the
                     * on disk slice through the large data set selection
                     * as having the same shape.
                     */
                    check = H5Sselect_shape_same(tv_ptr->mem_small_ds_sid, tv_ptr->file_large_ds_sid_1);
                    VRFY((check == true), "H5Sselect_shape_same passed");

                    /* write the small data set slice from memory to the
                     * target slice of the disk data set
                     */
#if CHECKER_BOARD_HS_DR_PIO_TEST__M2D_S2L__DEBUG
                    fprintf(stdout, "%s:%d: start = %d %d %d %d %d.\n", fcnName, tv_ptr->mpi_rank,
                            tv_ptr->start[0], tv_ptr->start[1], tv_ptr->start[2], tv_ptr->start[3],
                            tv_ptr->start[4]);
                    fprintf(stdout, "%s:%d: mem/file extent dims = %d/%d.\n", fcnName, tv_ptr->mpi_rank,
                            H5Sget_simple_extent_ndims(tv_ptr->mem_small_ds_sid),
                            H5Sget_simple_extent_ndims(tv_ptr->file_large_ds_sid_1));
#endif /* CHECKER_BOARD_HS_DR_PIO_TEST__M2D_S2L__DEBUG */
                    ret = H5Dwrite(tv_ptr->large_dataset, H5T_NATIVE_UINT32, tv_ptr->mem_small_ds_sid,
                                   tv_ptr->file_large_ds_sid_1, tv_ptr->xfer_plist, tv_ptr->small_ds_buf_0);
                    VRFY((ret != FAIL), "H5Dwrite of small ds slice to large ds succeeded");

                    /* read this processes slice on the on disk large
                     * data set into memory.
                     */

                    ret = H5Dread(tv_ptr->large_dataset, H5T_NATIVE_UINT32, tv_ptr->mem_large_ds_sid,
                                  tv_ptr->file_large_ds_sid_0, tv_ptr->xfer_plist, tv_ptr->large_ds_buf_1);
                    VRFY((ret != FAIL), "H5Dread() of process slice of large ds succeeded");

                    /* verify that the expected data and only the
                     * expected data was read.
                     */
                    expected_value = (uint32_t)((size_t)(tv_ptr->mpi_rank) * tv_ptr->small_ds_slice_size);

                    start_index =
                        (size_t)((i * tv_ptr->edge_size * tv_ptr->edge_size * tv_ptr->edge_size *
                                  tv_ptr->edge_size) +
                                 (j * tv_ptr->edge_size * tv_ptr->edge_size * tv_ptr->edge_size) +
                                 (k * tv_ptr->edge_size * tv_ptr->edge_size) + (l * tv_ptr->edge_size));
                    stop_index = start_index + tv_ptr->small_ds_slice_size - 1;

                    assert(start_index < stop_index);
                    assert(stop_index < tv_ptr->large_ds_size);

                    data_ok = true;

                    ptr_1 = tv_ptr->large_ds_buf_1;
                    for (u = 0; u < start_index; u++, ptr_1++) {

                        if (*ptr_1 != 0) {

                            data_ok = false;
                            *ptr_1  = 0;
                        }
                    }

                    data_ok &= ckrbrd_hs_dr_pio_test__verify_data(
                        tv_ptr->large_ds_buf_1 + start_index, tv_ptr->small_rank - 1, tv_ptr->edge_size,
                        tv_ptr->checker_edge_size, expected_value, (bool)true);

                    ptr_1 = tv_ptr->large_ds_buf_1;
                    for (u = stop_index; u < tv_ptr->small_ds_size; u++, ptr_1++) {

                        if (*ptr_1 != 0) {

                            data_ok = false;
                            *ptr_1  = 0;
                        }
                    }

                    VRFY((data_ok == true), "small ds cb slice write to large ds slice data good.");

                    (tv_ptr->tests_run)++;
                }

                l++;

                (tv_ptr->total_tests)++;

            } while ((tv_ptr->large_rank > 2) && ((tv_ptr->small_rank - 1) <= 1) && (l < tv_ptr->edge_size));
            k++;
        } while ((tv_ptr->large_rank > 3) && ((tv_ptr->small_rank - 1) <= 2) && (k < tv_ptr->edge_size));
        j++;
    } while ((tv_ptr->large_rank > 4) && ((tv_ptr->small_rank - 1) <= 3) && (j < tv_ptr->edge_size));

    return;

} /* ckrbrd_hs_dr_pio_test__m2d_s2l() */

/*-------------------------------------------------------------------------
 * Function:    ckrbrd_hs_dr_pio_test__run_test()
 *
 * Purpose:    Test I/O to/from checkerboard selections of hyperslabs of
 *        different rank in the parallel.
 *
 * Return:    void
 *
 *-------------------------------------------------------------------------
 */

#define CKRBRD_HS_DR_PIO_TEST__RUN_TEST__DEBUG 0

static void
ckrbrd_hs_dr_pio_test__run_test(const int test_num, const int edge_size, const int checker_edge_size,
                                const int chunk_edge_size, const int small_rank, const int large_rank,
                                const bool use_collective_io, const hid_t dset_type, const int express_test,
                                int *skips_ptr, int max_skips, int64_t *total_tests_ptr,
                                int64_t *tests_run_ptr, int64_t *tests_skipped_ptr, int mpi_rank)

{
#if CKRBRD_HS_DR_PIO_TEST__RUN_TEST__DEBUG
    const char *fcnName = "ckrbrd_hs_dr_pio_test__run_test()";
#endif /* CKRBRD_HS_DR_PIO_TEST__RUN_TEST__DEBUG */
    struct hs_dr_pio_test_vars_t test_vars = {
        /* int           mpi_size                        = */ -1,
        /* int         mpi_rank                        = */ -1,
        /* MPI_Comm    mpi_comm                        = */ MPI_COMM_NULL,
        /* MPI_Inf     mpi_info                        = */ MPI_INFO_NULL,
        /* int         test_num                        = */ -1,
        /* int         edge_size                       = */ -1,
        /* int         checker_edge_size               = */ -1,
        /* int         chunk_edge_size                 = */ -1,
        /* int         small_rank                      = */ -1,
        /* int         large_rank                      = */ -1,
        /* hid_t       dset_type                       = */ H5I_INVALID_HID,
        /* uint32_t  * small_ds_buf_0                  = */ NULL,
        /* uint32_t  * small_ds_buf_1                  = */ NULL,
        /* uint32_t  * small_ds_buf_2                  = */ NULL,
        /* uint32_t  * small_ds_slice_buf              = */ NULL,
        /* uint32_t  * large_ds_buf_0                  = */ NULL,
        /* uint32_t  * large_ds_buf_1                  = */ NULL,
        /* uint32_t  * large_ds_buf_2                  = */ NULL,
        /* uint32_t  * large_ds_slice_buf              = */ NULL,
        /* int         small_ds_offset                 = */ -1,
        /* int         large_ds_offset                 = */ -1,
        /* hid_t       fid                             = */ H5I_INVALID_HID, /* HDF5 file ID */
        /* hid_t       xfer_plist                      = */ H5P_DEFAULT,
        /* hid_t       full_mem_small_ds_sid           = */ H5I_INVALID_HID,
        /* hid_t       full_file_small_ds_sid          = */ H5I_INVALID_HID,
        /* hid_t       mem_small_ds_sid                = */ H5I_INVALID_HID,
        /* hid_t       file_small_ds_sid_0             = */ H5I_INVALID_HID,
        /* hid_t       file_small_ds_sid_1             = */ H5I_INVALID_HID,
        /* hid_t       small_ds_slice_sid              = */ H5I_INVALID_HID,
        /* hid_t       full_mem_large_ds_sid           = */ H5I_INVALID_HID,
        /* hid_t       full_file_large_ds_sid          = */ H5I_INVALID_HID,
        /* hid_t       mem_large_ds_sid                = */ H5I_INVALID_HID,
        /* hid_t       file_large_ds_sid_0             = */ H5I_INVALID_HID,
        /* hid_t       file_large_ds_sid_1             = */ H5I_INVALID_HID,
        /* hid_t       file_large_ds_process_slice_sid = */ H5I_INVALID_HID,
        /* hid_t       mem_large_ds_process_slice_sid  = */ H5I_INVALID_HID,
        /* hid_t       large_ds_slice_sid              = */ H5I_INVALID_HID,
        /* hid_t       small_dataset                   = */ H5I_INVALID_HID, /* Dataset ID */
        /* hid_t       large_dataset                   = */ H5I_INVALID_HID, /* Dataset ID */
        /* size_t      small_ds_size                   = */ 1,
        /* size_t      small_ds_slice_size             = */ 1,
        /* size_t      large_ds_size                   = */ 1,
        /* size_t      large_ds_slice_size             = */ 1,
        /* hsize_t     dims[PAR_SS_DR_MAX_RANK]        = */ {0, 0, 0, 0, 0},
        /* hsize_t     chunk_dims[PAR_SS_DR_MAX_RANK]  = */ {0, 0, 0, 0, 0},
        /* hsize_t     start[PAR_SS_DR_MAX_RANK]       = */ {0, 0, 0, 0, 0},
        /* hsize_t     stride[PAR_SS_DR_MAX_RANK]      = */ {0, 0, 0, 0, 0},
        /* hsize_t     count[PAR_SS_DR_MAX_RANK]       = */ {0, 0, 0, 0, 0},
        /* hsize_t     block[PAR_SS_DR_MAX_RANK]       = */ {0, 0, 0, 0, 0},
        /* hsize_t   * start_ptr                       = */ NULL,
        /* hsize_t   * stride_ptr                      = */ NULL,
        /* hsize_t   * count_ptr                       = */ NULL,
        /* hsize_t   * block_ptr                       = */ NULL,
        /* int            skips                           = */ 0,
        /* int            max_skips                       = */ 0,
        /* int64_t     total_tests                     = */ 0,
        /* int64_t     tests_run                       = */ 0,
        /* int64_t     tests_skipped                   = */ 0};
    struct hs_dr_pio_test_vars_t *tv_ptr = &test_vars;

    if (MAINPROCESS)
        printf("\r - running test #%lld: small rank = %d, large rank = %d", (long long)(test_num + 1),
               small_rank, large_rank);

    hs_dr_pio_test__setup(test_num, edge_size, checker_edge_size, chunk_edge_size, small_rank, large_rank,
                          use_collective_io, dset_type, express_test, tv_ptr);

    /* initialize skips & max_skips */
    tv_ptr->skips     = *skips_ptr;
    tv_ptr->max_skips = max_skips;

#if CKRBRD_HS_DR_PIO_TEST__RUN_TEST__DEBUG
    if (MAINPROCESS) {
        fprintf(stdout, "test %d: small rank = %d, large rank = %d.\n", test_num, small_rank, large_rank);
        fprintf(stdout, "test %d: Initialization complete.\n", test_num);
    }
#endif /* CKRBRD_HS_DR_PIO_TEST__RUN_TEST__DEBUG */

    /* first, verify that we can read from disk correctly using selections
     * of different rank that H5Sselect_shape_same() views as being of the
     * same shape.
     *
     * Start by reading a (small_rank - 1)-D slice from this processes slice
     * of the on disk large data set, and verifying that the data read is
     * correct.  Verify that H5Sselect_shape_same() returns true on the
     * memory and file selections.
     *
     * The first step is to set up the needed checker board selection in the
     * in memory small small cube
     */

    ckrbrd_hs_dr_pio_test__d2m_l2s(tv_ptr);

    /* similarly, read slices of the on disk small data set into slices
     * through the in memory large data set, and verify that the correct
     * data (and only the correct data) is read.
     */

    ckrbrd_hs_dr_pio_test__d2m_s2l(tv_ptr);

    /* now we go in the opposite direction, verifying that we can write
     * from memory to file using selections of different rank that
     * H5Sselect_shape_same() views as being of the same shape.
     *
     * Start by writing small_rank - 1 D slices from the in memory large data
     * set to the on disk small dataset.  After each write, read the slice of
     * the small dataset back from disk, and verify that it contains the
     * expected data. Verify that H5Sselect_shape_same() returns true on
     * the memory and file selections.
     */

    ckrbrd_hs_dr_pio_test__m2d_l2s(tv_ptr);

    /* Now write the contents of the process's slice of the in memory
     * small data set to slices of the on disk large data set.  After
     * each write, read the process's slice of the large data set back
     * into memory, and verify that it contains the expected data.
     * Verify that H5Sselect_shape_same() returns true on the memory
     * and file selections.
     */

    ckrbrd_hs_dr_pio_test__m2d_s2l(tv_ptr);

#if CKRBRD_HS_DR_PIO_TEST__RUN_TEST__DEBUG
    if (MAINPROCESS) {
        fprintf(stdout, "test %d: Subtests complete -- tests run/skipped/total = %lld/%lld/%lld.\n", test_num,
                (long long)(tv_ptr->tests_run), (long long)(tv_ptr->tests_skipped),
                (long long)(tv_ptr->total_tests));
    }
#endif /* CKRBRD_HS_DR_PIO_TEST__RUN_TEST__DEBUG */

    hs_dr_pio_test__takedown(tv_ptr);

#if CKRBRD_HS_DR_PIO_TEST__RUN_TEST__DEBUG
    if (MAINPROCESS) {
        fprintf(stdout, "test %d: Takedown complete.\n", test_num);
    }
#endif /* CKRBRD_HS_DR_PIO_TEST__RUN_TEST__DEBUG */

    *skips_ptr = tv_ptr->skips;
    *total_tests_ptr += tv_ptr->total_tests;
    *tests_run_ptr += tv_ptr->tests_run;
    *tests_skipped_ptr += tv_ptr->tests_skipped;

    return;

} /* ckrbrd_hs_dr_pio_test__run_test() */

/*-------------------------------------------------------------------------
 * Function:    ckrbrd_hs_dr_pio_test()
 *
 * Purpose:    Test I/O to/from hyperslab selections of different rank in
 *        the parallel case.
 *
 * Return:    void
 *
 *-------------------------------------------------------------------------
 */

static void
ckrbrd_hs_dr_pio_test(ShapeSameTestMethods sstest_type)
{
    int   express_test;
    int   local_express_test;
    int   mpi_size = -1;
    int   mpi_rank = -1;
    int   test_num = 0;
    int   edge_size;
    int   checker_edge_size = 3;
    int   chunk_edge_size   = 0;
    int   small_rank        = 3;
    int   large_rank        = 4;
    int   mpi_result;
    hid_t dset_type = H5T_NATIVE_UINT;
    int   skips     = 0;
    int   max_skips = 0;
    /* The following table list the number of sub-tests skipped between
     * each test that is actually executed as a function of the express
     * test level.  Note that any value in excess of 4880 will cause all
     * sub tests to be skipped.
     */
    int     max_skips_tbl[4] = {0, 4, 64, 1024};
    int64_t total_tests      = 0;
    int64_t tests_run        = 0;
    int64_t tests_skipped    = 0;

    MPI_Comm_size(MPI_COMM_WORLD, &mpi_size);
    MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);

    edge_size = (mpi_size > 6 ? mpi_size : 6);

    local_express_test = GetTestExpress();

    HDcompile_assert(sizeof(uint32_t) == sizeof(unsigned));

    mpi_result = MPI_Allreduce((void *)&local_express_test, (void *)&express_test, 1, MPI_INT, MPI_MAX,
                               MPI_COMM_WORLD);

    VRFY((mpi_result == MPI_SUCCESS), "MPI_Allreduce(0) succeeded");

    if (local_express_test < 0) {
        max_skips = max_skips_tbl[0];
    }
    else if (local_express_test > 3) {
        max_skips = max_skips_tbl[3];
    }
    else {
        max_skips = max_skips_tbl[local_express_test];
    }

#if 0
    {
        int DebugWait = 1;

        while (DebugWait) ;
    }
#endif

    for (large_rank = 3; large_rank <= PAR_SS_DR_MAX_RANK; large_rank++) {

        for (small_rank = 2; small_rank < large_rank; small_rank++) {
            switch (sstest_type) {
                case IND_CONTIG:
                    /* contiguous data set, independent I/O */
                    chunk_edge_size = 0;
                    ckrbrd_hs_dr_pio_test__run_test(test_num, edge_size, checker_edge_size, chunk_edge_size,
                                                    small_rank, large_rank, false, dset_type, express_test,
                                                    &skips, max_skips, &total_tests, &tests_run,
                                                    &tests_skipped, mpi_rank);
                    test_num++;
                    break;
                    /* end of case IND_CONTIG */

                case COL_CONTIG:
                    /* contiguous data set, collective I/O */
                    chunk_edge_size = 0;
                    ckrbrd_hs_dr_pio_test__run_test(test_num, edge_size, checker_edge_size, chunk_edge_size,
                                                    small_rank, large_rank, true, dset_type, express_test,
                                                    &skips, max_skips, &total_tests, &tests_run,
                                                    &tests_skipped, mpi_rank);
                    test_num++;
                    break;
                    /* end of case COL_CONTIG */

                case IND_CHUNKED:
                    /* chunked data set, independent I/O */
                    chunk_edge_size = 5;
                    ckrbrd_hs_dr_pio_test__run_test(test_num, edge_size, checker_edge_size, chunk_edge_size,
                                                    small_rank, large_rank, false, dset_type, express_test,
                                                    &skips, max_skips, &total_tests, &tests_run,
                                                    &tests_skipped, mpi_rank);
                    test_num++;
                    break;
                    /* end of case IND_CHUNKED */

                case COL_CHUNKED:
                    /* chunked data set, collective I/O */
                    chunk_edge_size = 5;
                    ckrbrd_hs_dr_pio_test__run_test(test_num, edge_size, checker_edge_size, chunk_edge_size,
                                                    small_rank, large_rank, true, dset_type, express_test,
                                                    &skips, max_skips, &total_tests, &tests_run,
                                                    &tests_skipped, mpi_rank);
                    test_num++;
                    break;
                    /* end of case COL_CHUNKED */

                default:
                    VRFY((false), "unknown test type");
                    break;

            } /* end of switch(sstest_type) */
#if CONTIG_HS_DR_PIO_TEST__DEBUG
            if ((MAINPROCESS) && (tests_skipped > 0)) {
                fprintf(stdout, "     run/skipped/total = %" PRId64 "/%" PRId64 "/%" PRId64 ".\n", tests_run,
                        tests_skipped, total_tests);
            }
#endif /* CONTIG_HS_DR_PIO_TEST__DEBUG */
        }
    }

    if (MAINPROCESS) {
        if (tests_skipped > 0) {
            fprintf(stdout, "     %" PRId64 " of %" PRId64 " subtests skipped to expedite testing.\n",
                    tests_skipped, total_tests);
        }
        else
            printf("\n");
    }

    return;

} /* ckrbrd_hs_dr_pio_test() */

/* Main Body. Here for now, may have to move them to a separated file later. */

/*
 * Main driver of the Parallel HDF5 tests
 */

/* global variables */
int dim0;
int dim1;
int chunkdim0;
int chunkdim1;
int nerrors   = 0;               /* errors count */
int ndatasets = 300;             /* number of datasets to create*/
int ngroups   = 512;             /* number of groups to create in root
                                  * group. */
int facc_type       = FACC_MPIO; /*Test file access type */
int dxfer_coll_type = DXFER_COLLECTIVE_IO;

H5E_auto2_t old_func;        /* previous error handler */
void       *old_client_data; /* previous error handler arg.*/

/* other option flags */

#ifdef USE_PAUSE
/* pause the process for a moment to allow debugger to attach if desired. */
/* Will pause more if greenlight file is not present but will eventually */
/* continue. */
#include <sys/types.h>
#include <sys/stat.h>

void
pause_proc(void)
{

    int       pid;
    h5_stat_t statbuf;
    char      greenlight[] = "go";
    int       maxloop      = 10;
    int       loops        = 0;
    int       time_int     = 10;

    /* mpi variables */
    int  mpi_size, mpi_rank;
    int  mpi_namelen;
    char mpi_name[MPI_MAX_PROCESSOR_NAME];

    pid = getpid();
    MPI_Comm_size(MPI_COMM_WORLD, &mpi_size);
    MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
    MPI_Get_processor_name(mpi_name, &mpi_namelen);

    if (MAINPROCESS) {
        memset(&statbuf, 0, sizeof(h5_stat_t));
        while ((HDstat(greenlight, &statbuf) == -1) && loops < maxloop) {
            if (!loops++) {
                printf("Proc %d (%*s, %d): to debug, attach %d\n", mpi_rank, mpi_namelen, mpi_name, pid, pid);
            }
            printf("waiting(%ds) for file %s ...\n", time_int, greenlight);
            fflush(stdout);
            HDsleep(time_int);

            memset(&statbuf, 0, sizeof(h5_stat_t));
        }
    }
    MPI_Barrier(MPI_COMM_WORLD);
}

/* Use the Profile feature of MPI to call the pause_proc() */
int
MPI_Init(int *argc, char ***argv)
{
    int ret_code;
    ret_code = PMPI_Init(argc, argv);
    pause_proc();
    return (ret_code);
}
#endif /* USE_PAUSE */

/*
 * Show command usage
 */
static void
usage(void)
{
    printf("    [-r] [-w] [-m<n_datasets>] [-n<n_groups>] "
           "[-o] [-f <prefix>] [-d <dim0> <dim1>]\n");
    printf("\t-m<n_datasets>"
           "\tset number of datasets for the multiple dataset test\n");
    printf("\t-n<n_groups>"
           "\tset number of groups for the multiple group test\n");
    printf("\t-f <prefix>\tfilename prefix\n");
    printf("\t-2\t\tuse Split-file together with MPIO\n");
    printf("\t-d <factor0> <factor1>\tdataset dimensions factors. Defaults (%d,%d)\n", ROW_FACTOR,
           COL_FACTOR);
    printf("\t-c <dim0> <dim1>\tdataset chunk dimensions. Defaults (dim0/10,dim1/10)\n");
    printf("\n");
}

/*
 * parse the command line options
 */
static int
parse_options(int argc, char **argv)
{
    int mpi_size, mpi_rank; /* mpi variables */

    MPI_Comm_size(MPI_COMM_WORLD, &mpi_size);
    MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);

    /* setup default chunk-size. Make sure sizes are > 0 */

    chunkdim0 = (dim0 + 9) / 10;
    chunkdim1 = (dim1 + 9) / 10;

    while (--argc) {
        if (**(++argv) != '-') {
            break;
        }
        else {
            switch (*(*argv + 1)) {
                case 'm':
                    ndatasets = atoi((*argv + 1) + 1);
                    if (ndatasets < 0) {
                        nerrors++;
                        return (1);
                    }
                    break;
                case 'n':
                    ngroups = atoi((*argv + 1) + 1);
                    if (ngroups < 0) {
                        nerrors++;
                        return (1);
                    }
                    break;
                case 'f':
                    if (--argc < 1) {
                        nerrors++;
                        return (1);
                    }
                    if (**(++argv) == '-') {
                        nerrors++;
                        return (1);
                    }
                    paraprefix = *argv;
                    break;
                case 'i': /* Collective MPI-IO access with independent IO  */
                    dxfer_coll_type = DXFER_INDEPENDENT_IO;
                    break;
                case '2': /* Use the split-file driver with MPIO access */
                    /* Can use $HDF5_METAPREFIX to define the */
                    /* meta-file-prefix. */
                    facc_type = FACC_MPIO | FACC_SPLIT;
                    break;
                case 'd': /* dimensizes */
                    if (--argc < 2) {
                        nerrors++;
                        return (1);
                    }
                    dim0 = atoi(*(++argv)) * mpi_size;
                    argc--;
                    dim1 = atoi(*(++argv)) * mpi_size;
                    /* set default chunkdim sizes too */
                    chunkdim0 = (dim0 + 9) / 10;
                    chunkdim1 = (dim1 + 9) / 10;
                    break;
                case 'c': /* chunk dimensions */
                    if (--argc < 2) {
                        nerrors++;
                        return (1);
                    }
                    chunkdim0 = atoi(*(++argv));
                    argc--;
                    chunkdim1 = atoi(*(++argv));
                    break;
                case 'h': /* print help message--return with nerrors set */
                    return (1);
                default:
                    if (MAINPROCESS)
                        printf("Illegal option(%s)\n", *argv);
                    nerrors++;
                    return (1);
            }
        }
    } /*while*/

    /* check validity of dimension and chunk sizes */
    if (dim0 <= 0 || dim1 <= 0) {
        if (MAINPROCESS)
            printf("Illegal dim sizes (%d, %d)\n", dim0, dim1);
        nerrors++;
        return (1);
    }
    if (chunkdim0 <= 0 || chunkdim1 <= 0) {
        if (MAINPROCESS)
            printf("Illegal chunkdim sizes (%d, %d)\n", chunkdim0, chunkdim1);
        nerrors++;
        return (1);
    }

    /* Make sure datasets can be divided into equal portions by the processes */
    if ((dim0 % mpi_size) || (dim1 % mpi_size)) {
        if (MAINPROCESS)
            printf("dim0(%d) and dim1(%d) must be multiples of processes(%d)\n", dim0, dim1, mpi_size);
        nerrors++;
        return (1);
    }

    /* compose the test filenames */
    {
        int i, n;

        n = sizeof(FILENAME) / sizeof(FILENAME[0]) - 1; /* exclude the NULL */

        for (i = 0; i < n; i++)
            if (h5_fixname(FILENAME[i], fapl, filenames[i], PATH_MAX) == NULL) {
                printf("h5_fixname failed\n");
                nerrors++;
                return (1);
            }
        if (MAINPROCESS) {
            printf("Test filenames are:\n");
            for (i = 0; i < n; i++)
                printf("    %s\n", filenames[i]);
        }
    }

    return (0);
}

/*
 * Create the appropriate File access property list
 */
hid_t
create_faccess_plist(MPI_Comm comm, MPI_Info info, int l_facc_type)
{
    hid_t  ret_pl = H5I_INVALID_HID;
    herr_t ret;      /* generic return value */
    int    mpi_rank; /* mpi variables */

    /* need the rank for error checking macros */
    MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);

    ret_pl = H5Pcreate(H5P_FILE_ACCESS);
    VRFY((ret_pl >= 0), "H5P_FILE_ACCESS");

    if (l_facc_type == FACC_DEFAULT)
        return (ret_pl);

    if (l_facc_type == FACC_MPIO) {
        /* set Parallel access with communicator */
        ret = H5Pset_fapl_mpio(ret_pl, comm, info);
        VRFY((ret >= 0), "");
        ret = H5Pset_all_coll_metadata_ops(ret_pl, true);
        VRFY((ret >= 0), "");
        ret = H5Pset_coll_metadata_write(ret_pl, true);
        VRFY((ret >= 0), "");
        return (ret_pl);
    }

    if (l_facc_type == (FACC_MPIO | FACC_SPLIT)) {
        hid_t mpio_pl;

        mpio_pl = H5Pcreate(H5P_FILE_ACCESS);
        VRFY((mpio_pl >= 0), "");
        /* set Parallel access with communicator */
        ret = H5Pset_fapl_mpio(mpio_pl, comm, info);
        VRFY((ret >= 0), "");

        /* setup file access template */
        ret_pl = H5Pcreate(H5P_FILE_ACCESS);
        VRFY((ret_pl >= 0), "");
        /* set Parallel access with communicator */
        ret = H5Pset_fapl_split(ret_pl, ".meta", mpio_pl, ".raw", mpio_pl);
        VRFY((ret >= 0), "H5Pset_fapl_split succeeded");
        H5Pclose(mpio_pl);
        return (ret_pl);
    }

    /* unknown file access types */
    return (ret_pl);
}

/* Shape Same test using contiguous hyperslab using independent IO on contiguous datasets */
static void
sscontig1(void)
{
    contig_hs_dr_pio_test(IND_CONTIG);
}

/* Shape Same test using contiguous hyperslab using collective IO on contiguous datasets */
static void
sscontig2(void)
{
    contig_hs_dr_pio_test(COL_CONTIG);
}

/* Shape Same test using contiguous hyperslab using independent IO on chunked datasets */
static void
sscontig3(void)
{
    contig_hs_dr_pio_test(IND_CHUNKED);
}

/* Shape Same test using contiguous hyperslab using collective IO on chunked datasets */
static void
sscontig4(void)
{
    contig_hs_dr_pio_test(COL_CHUNKED);
}

/* Shape Same test using checker hyperslab using independent IO on contiguous datasets */
static void
sschecker1(void)
{
    ckrbrd_hs_dr_pio_test(IND_CONTIG);
}

/* Shape Same test using checker hyperslab using collective IO on contiguous datasets */
static void
sschecker2(void)
{
    ckrbrd_hs_dr_pio_test(COL_CONTIG);
}

/* Shape Same test using checker hyperslab using independent IO on chunked datasets */
static void
sschecker3(void)
{
    ckrbrd_hs_dr_pio_test(IND_CHUNKED);
}

/* Shape Same test using checker hyperslab using collective IO on chunked datasets */
static void
sschecker4(void)
{
    ckrbrd_hs_dr_pio_test(COL_CHUNKED);
}

int
main(int argc, char **argv)
{
    int mpi_size, mpi_rank; /* mpi variables */
    int mpi_code;
#ifdef H5_HAVE_TEST_API
    int required = MPI_THREAD_MULTIPLE;
    int provided;
#endif

#ifndef H5_HAVE_WIN32_API
    /* Un-buffer the stdout and stderr */
    setbuf(stderr, NULL);
    setbuf(stdout, NULL);
#endif

#ifdef H5_HAVE_TEST_API
    /* Attempt to initialize with MPI_THREAD_MULTIPLE if possible */
    if (MPI_SUCCESS != (mpi_code = MPI_Init_thread(&argc, &argv, required, &provided))) {
        printf("MPI_Init_thread failed with error code %d\n", mpi_code);
        return -1;
    }
#else
    if (MPI_SUCCESS != (mpi_code = MPI_Init(&argc, &argv))) {
        printf("MPI_Init failed with error code %d\n", mpi_code);
        return -1;
    }
#endif

    if (MPI_SUCCESS != (mpi_code = MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank))) {
        printf("MPI_Comm_rank failed with error code %d\n", mpi_code);
        MPI_Finalize();
        return -1;
    }

#ifdef H5_HAVE_TEST_API
    /* Warn about missing MPI_THREAD_MULTIPLE support */
    if ((provided < required) && MAINPROCESS)
        printf("** MPI doesn't support MPI_Init_thread with MPI_THREAD_MULTIPLE **\n");
#endif

    if (MPI_SUCCESS != (mpi_code = MPI_Comm_size(MPI_COMM_WORLD, &mpi_size))) {
        if (MAINPROCESS)
            printf("MPI_Comm_size failed with error code %d\n", mpi_code);
        MPI_Finalize();
        return -1;
    }

    mpi_rank_framework_g = mpi_rank;

    dim0 = ROW_FACTOR * mpi_size;
    dim1 = COL_FACTOR * mpi_size;

    if (MAINPROCESS) {
        printf("===================================\n");
        printf("Shape Same Tests Start\n");
        printf("    express_test = %d.\n", GetTestExpress());
        printf("===================================\n");
    }

    /* Attempt to turn off atexit post processing so that in case errors
     * happen during the test and the process is aborted, it will not get
     * hung in the atexit post processing in which it may try to make MPI
     * calls.  By then, MPI calls may not work.
     */
    if (H5dont_atexit() < 0) {
        if (MAINPROCESS)
            printf("%d: Failed to turn off atexit processing. Continue.\n", mpi_rank);
    };
    H5open();
    h5_show_hostname();

    fapl = H5Pcreate(H5P_FILE_ACCESS);

    /* Get the capability flag of the VOL connector being used */
    if (H5Pget_vol_cap_flags(fapl, &vol_cap_flags_g) < 0) {
        if (MAINPROCESS)
            printf("Failed to get the capability flag of the VOL connector being used\n");

        MPI_Finalize();
        return -1;
    }

    /* Make sure the connector supports the API functions being tested.  This test only
     * uses a few API functions, such as H5Fcreate/close/delete, H5Dcreate/write/read/close,
     */
    if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) {
        if (MAINPROCESS)
            printf("API functions for basic file and dataset aren't supported with this connector\n");

        MPI_Finalize();
        return 0;
    }

    memset(filenames, 0, sizeof(filenames));
    for (int i = 0; i < NFILENAME; i++) {
        if (NULL == (filenames[i] = malloc(PATH_MAX))) {
            printf("couldn't allocate filename array\n");
            MPI_Abort(MPI_COMM_WORLD, -1);
        }
    }

    /* Initialize testing framework */
    TestInit(argv[0], usage, parse_options);

    /* Shape Same tests using contiguous hyperslab */
    AddTest("sscontig1", sscontig1, NULL, "Cntg hslab, ind IO, cntg dsets", PARATESTFILE);
    AddTest("sscontig2", sscontig2, NULL, "Cntg hslab, col IO, cntg dsets", PARATESTFILE);
    AddTest("sscontig3", sscontig3, NULL, "Cntg hslab, ind IO, chnk dsets", PARATESTFILE);
    AddTest("sscontig4", sscontig4, NULL, "Cntg hslab, col IO, chnk dsets", PARATESTFILE);

    /* Shape Same tests using checker board hyperslab */
    AddTest("sschecker1", sschecker1, NULL, "Check hslab, ind IO, cntg dsets", PARATESTFILE);
    AddTest("sschecker2", sschecker2, NULL, "Check hslab, col IO, cntg dsets", PARATESTFILE);
    AddTest("sschecker3", sschecker3, NULL, "Check hslab, ind IO, chnk dsets", PARATESTFILE);
    AddTest("sschecker4", sschecker4, NULL, "Check hslab, col IO, chnk dsets", PARATESTFILE);

    /* Display testing information */
    TestInfo(argv[0]);

    /* setup file access property list */
    H5Pset_fapl_mpio(fapl, MPI_COMM_WORLD, MPI_INFO_NULL);

    /* Parse command line arguments */
    TestParseCmdLine(argc, argv);

    if (dxfer_coll_type == DXFER_INDEPENDENT_IO && MAINPROCESS) {
        printf("===================================\n"
               "   Using Independent I/O with file set view to replace collective I/O \n"
               "===================================\n");
    }

    /* Perform requested testing */
    PerformTests();

    /* make sure all processes are finished before final report, cleanup
     * and exit.
     */
    MPI_Barrier(MPI_COMM_WORLD);

    /* Display test summary, if requested */
    if (MAINPROCESS && GetTestSummary())
        TestSummary();

    /* Clean up test files */
    h5_delete_all_test_files(FILENAME, fapl);
    H5Pclose(fapl);

    nerrors += GetTestNumErrs();

    /* Gather errors from all processes */
    {
        int temp;
        MPI_Allreduce(&nerrors, &temp, 1, MPI_INT, MPI_MAX, MPI_COMM_WORLD);
        nerrors = temp;
    }

    if (MAINPROCESS) { /* only process 0 reports */
        printf("===================================\n");
        if (nerrors)
            printf("***Shape Same tests detected %d errors***\n", nerrors);
        else
            printf("Shape Same tests finished with no errors\n");
        printf("===================================\n");
    }

    for (int i = 0; i < NFILENAME; i++) {
        free(filenames[i]);
        filenames[i] = NULL;
    }

    /* close HDF5 library */
    H5close();

    /* Release test infrastructure */
    TestShutdown();

    MPI_Finalize();

    /* cannot just return (nerrors) because exit code is limited to 1byte */
    return (nerrors != 0);
}
