Exemple #1
0
/**
 * Test the darray functionality. Create a netCDF file with 3
 * dimensions and 3 variable, and use PIOc_write_darray_multi() to
 * write one record of data to all three vars at once.
 *
 * @param iosysid the IO system ID.
 * @param ioid the ID of the decomposition.
 * @param num_flavors the number of IOTYPES available in this build.
 * @param flavor array of available iotypes.
 * @param my_rank rank of this task.
 * @param pio_type the type of the data.
 * @returns 0 for success, error code otherwise.
 */
int test_darray(int iosysid, int ioid, int num_flavors, int *flavor, int my_rank,
                int pio_type)
{
#define NUM_TEST_CASES_WRT_MULTI 2
#define NUM_TEST_CASES_FILLVALUE 2

    char filename[PIO_MAX_NAME + 1]; /* Name for the output files. */
    int dimids[NDIM];      /* The dimension IDs. */
    int ncid;              /* The ncid of the netCDF file. */
    int ncid2;             /* The ncid of the re-opened netCDF file. */
    int varid[NVAR];       /* The IDs of the netCDF varables. */
    int other_varid;       /* The IDs of a var of different type. */
    int wrong_varid[NVAR]; /* These will not work. */
    PIO_Offset arraylen = 4; /* Amount of data from each task. */
    void *fillvalue;       /* Pointer to fill value. */
    void *test_data;       /* Pointer to test data we will write. */
    void *test_data_in;    /* Pointer to buffer we will read into. */
    int ret;               /* Return code. */

    /* Default fill value array for each type. */
    signed char byte_fill[NVAR] = {NC_FILL_BYTE, NC_FILL_BYTE, NC_FILL_BYTE};
    char char_fill[NVAR] = {NC_FILL_CHAR, NC_FILL_CHAR, NC_FILL_CHAR};
    short short_fill[NVAR] = {NC_FILL_SHORT, NC_FILL_SHORT, NC_FILL_SHORT};
    int int_fill[NVAR] = {NC_FILL_INT, NC_FILL_INT, NC_FILL_INT};
    float float_fill[NVAR] = {NC_FILL_FLOAT, NC_FILL_FLOAT, NC_FILL_FLOAT};
    double double_fill[NVAR] = {NC_FILL_DOUBLE, NC_FILL_DOUBLE, NC_FILL_DOUBLE};
#ifdef _NETCDF4
    unsigned char ubyte_fill[NVAR] = {NC_FILL_UBYTE, NC_FILL_UBYTE, NC_FILL_UBYTE};
    unsigned short ushort_fill[NVAR] = {NC_FILL_USHORT, NC_FILL_USHORT, NC_FILL_USHORT};
    unsigned int uint_fill[NVAR] = {NC_FILL_UINT, NC_FILL_UINT, NC_FILL_UINT};
    long long int64_fill[NVAR] = {NC_FILL_INT64, NC_FILL_INT64, NC_FILL_INT64};
    unsigned long long uint64_fill[NVAR] = {NC_FILL_UINT64, NC_FILL_UINT64, NC_FILL_UINT64};
#endif /* _NETCDF4 */

    /* Test data we will write. */
    signed char test_data_byte[arraylen * NVAR];
    char test_data_char[arraylen * NVAR];
    short test_data_short[arraylen * NVAR];
    int test_data_int[arraylen * NVAR];
    float test_data_float[arraylen * NVAR];
    double test_data_double[arraylen * NVAR];
#ifdef _NETCDF4
    unsigned char test_data_ubyte[arraylen * NVAR];
    unsigned short test_data_ushort[arraylen * NVAR];
    unsigned int test_data_uint[arraylen * NVAR];
    long long test_data_int64[arraylen * NVAR];
    unsigned long long test_data_uint64[arraylen * NVAR];
#endif /* _NETCDF4 */

    /* We will read test data into these buffers. */
    signed char test_data_byte_in[arraylen];
    char test_data_char_in[arraylen];
    short test_data_short_in[arraylen];
    int test_data_int_in[arraylen];
    float test_data_float_in[arraylen];
    double test_data_double_in[arraylen];
#ifdef _NETCDF4
    unsigned char test_data_ubyte_in[arraylen];
    unsigned short test_data_ushort_in[arraylen];
    unsigned int test_data_uint_in[arraylen];
    long long test_data_int64_in[arraylen];
    unsigned long long test_data_uint64_in[arraylen];
#endif /* _NETCDF4 */

    /* Initialize a big blob of test data for NVAR vars. */
    for (int f = 0; f < arraylen * NVAR; f++)
    {
        test_data_byte[f] = my_rank * 1 + f;
        test_data_char[f] = my_rank * 2 + f;
        test_data_short[f] = my_rank * 5 + f;
        test_data_int[f] = my_rank * 10 + f;
        test_data_float[f] = my_rank * 10 + f + 0.5;
        test_data_double[f] = my_rank * 100000 + f + 0.5;
#ifdef _NETCDF4
        test_data_ubyte[f] = my_rank * 3 + f;
        test_data_ushort[f] = my_rank * 9 + f;
        test_data_uint[f] = my_rank * 100 + f;
        test_data_int64[f] = my_rank * 10000 + f;
        test_data_uint64[f] = my_rank * 100000 + f;
#endif /* _NETCDF4 */
    }

    /* Use PIO to create the example file in each of the four
     * available ways. */
    for (int fmt = 0; fmt < num_flavors; fmt++)
    {
        /* 1-byte types not working with pnetcdf. */
        if (flavor[fmt] == PIO_IOTYPE_PNETCDF && (pio_type == PIO_BYTE || pio_type == PIO_CHAR))
            continue;

        /* NetCDF-4 types only work with netCDF-4. */
        if (pio_type > PIO_DOUBLE && (flavor[fmt] != PIO_IOTYPE_NETCDF4C &&
                                      flavor[fmt] != PIO_IOTYPE_NETCDF4P))
            continue;

        /* Add a couple of extra tests for the
         * PIOc_write_darray_multi() function. */
        for (int test_multi = 0; test_multi < NUM_TEST_CASES_WRT_MULTI; test_multi++)
        {
            /* Test with/without providing a fill value to PIOc_write_darray(). */
            for (int provide_fill = 0; provide_fill < NUM_TEST_CASES_FILLVALUE; provide_fill++)
            {
                /* Create the filename. */
                sprintf(filename, "data_%s_iotype_%d_pio_type_%d_test_multi_%d_provide_fill_%d.nc", TEST_NAME,
                        flavor[fmt], pio_type, test_multi, provide_fill);

                /* Select the fill value and data. */
                switch (pio_type)
                {
                case PIO_BYTE:
                    fillvalue = provide_fill ? byte_fill : NULL;
                    test_data = test_data_byte;
                    test_data_in = test_data_byte_in;
                    break;
                case PIO_CHAR:
                    fillvalue = provide_fill ? char_fill : NULL;
                    test_data = test_data_char;
                    test_data_in = test_data_char_in;
                    break;
                case PIO_SHORT:
                    fillvalue = provide_fill ? short_fill : NULL;
                    test_data = test_data_short;
                    test_data_in = test_data_short_in;
                    break;
                case PIO_INT:
                    fillvalue = provide_fill ? int_fill : NULL;
                    test_data = test_data_int;
                    test_data_in = test_data_int_in;
                    break;
                case PIO_FLOAT:
                    fillvalue = provide_fill ? float_fill : NULL;
                    test_data = test_data_float;
                    test_data_in = test_data_float_in;
                    break;
                case PIO_DOUBLE:
                    fillvalue = provide_fill ? double_fill : NULL;
                    test_data = test_data_double;
                    test_data_in = test_data_double_in;
                    break;
#ifdef _NETCDF4
                case PIO_UBYTE:
                    fillvalue = provide_fill ? ubyte_fill : NULL;
                    test_data = test_data_ubyte;
                    test_data_in = test_data_ubyte_in;
                    break;
                case PIO_USHORT:
                    fillvalue = provide_fill ? ushort_fill : NULL;
                    test_data = test_data_ushort;
                    test_data_in = test_data_ushort_in;
                    break;
                case PIO_UINT:
                    fillvalue = provide_fill ? uint_fill : NULL;
                    test_data = test_data_uint;
                    test_data_in = test_data_uint_in;
                    break;
                case PIO_INT64:
                    fillvalue = provide_fill ? int64_fill : NULL;
                    test_data = test_data_int64;
                    test_data_in = test_data_int64_in;
                    break;
                case PIO_UINT64:
                    fillvalue = provide_fill ? uint64_fill : NULL;
                    test_data = test_data_uint64;
                    test_data_in = test_data_uint64_in;
                    break;
#endif /* _NETCDF4 */
                default:
                    ERR(ERR_WRONG);
                }

                /* Create the netCDF output file. */
                if ((ret = PIOc_createfile(iosysid, &ncid, &flavor[fmt], filename, PIO_CLOBBER)))
                    ERR(ret);

                /* Define netCDF dimensions and variable. */
                for (int d = 0; d < NDIM; d++)
                    if ((ret = PIOc_def_dim(ncid, dim_name[d], (PIO_Offset)dim_len[d], &dimids[d])))
                        ERR(ret);

                /* Define a variable. */
                for (int v = 0; v < NVAR; v++)
                    if ((ret = PIOc_def_var(ncid, var_name[v], pio_type, NDIM, dimids, &varid[v])))
                        ERR(ret);

                /* Define a variable of a different type, to test error handling. */
                int other_pio_type = pio_type < 5 ? pio_type + 1 : PIO_INT;
                if ((ret = PIOc_def_var(ncid, "OTHER_VAR", other_pio_type, NDIM, dimids, &other_varid)))
                    ERR(ret);

                /* Leave a note. */
                if ((ret = PIOc_put_att_text(ncid, NC_GLOBAL, NOTE_NAME, strlen(NOTE), NOTE)))
                    ERR(ret);
                int num_stooges = TOTAL_NUMBER_OF_STOOGES;
                if ((ret = PIOc_put_att_int(ncid, NC_GLOBAL, TOTAL_NUMBER_OF_STOOGES_NAME, PIO_INT, 1, &num_stooges)))
                    ERR(ret);

                /* End define mode. */
                if ((ret = PIOc_enddef(ncid)))
                    ERR(ret);

                /* Set the value of the record dimension. */
                if ((ret = PIOc_setframe(ncid, varid[0], 0)))
                    ERR(ret);

                int frame[NVAR] = {0, 0, 0};
                int flushtodisk = test_multi;

                /* This will not work, because we mix var types. */
                wrong_varid[0] = varid[0];
                wrong_varid[1] = varid[1];
                wrong_varid[0] = other_varid;
//                if (PIOc_write_darray_multi(ncid, wrong_varid, ioid, NVAR, arraylen, test_data, frame,
//                                            fillvalue, flushtodisk) != PIO_EINVAL)
//                    ERR(ERR_WRONG);

                /* Write the data with the _multi function. */
                if ((ret = PIOc_write_darray_multi(ncid, varid, ioid, NVAR, arraylen, test_data, frame,
                                                   fillvalue, flushtodisk)))
                    ERR(ret);

                /* Close the netCDF file. */
                if ((ret = PIOc_closefile(ncid)))
                    ERR(ret);

                /* Reopen the file. */
                if ((ret = PIOc_openfile(iosysid, &ncid2, &flavor[fmt], filename, PIO_NOWRITE)))
                    ERR(ret);

                /* Now use read_darray on each var in turn and make
                 * sure we get correct data. */
                for (int v = 0; v < NVAR; v++)
                {
                    /* Set the value of the record dimension. */
                    if ((ret = PIOc_setframe(ncid2, varid[v], 0)))
                        ERR(ret);

                    /* Read the data. */
                    if ((ret = PIOc_read_darray(ncid2, varid[v], ioid, arraylen, test_data_in)))
                        ERR(ret);

                    /* Check the results. */
                    for (int f = 0; f < arraylen; f++)
                    {
                        switch (pio_type)
                        {
                        case PIO_BYTE:
                            if (test_data_byte_in[f] != test_data_byte[f + arraylen * v])
                                return ERR_WRONG;
                            break;
                        case PIO_CHAR:
                            if (test_data_char_in[f] != test_data_char[f + arraylen * v])
                                return ERR_WRONG;
                            break;
                        case PIO_SHORT:
                            if (test_data_short_in[f] != test_data_short[f + arraylen * v])
                                return ERR_WRONG;
                            break;
                        case PIO_INT:
                            if (test_data_int_in[f] != test_data_int[f + arraylen * v])
                                return ERR_WRONG;
                            break;
                        case PIO_FLOAT:
                            if (test_data_float_in[f] != test_data_float[f + arraylen * v])
                                return ERR_WRONG;
                            break;
                        case PIO_DOUBLE:
                            if (test_data_double_in[f] != test_data_double[f + arraylen * v])
                                return ERR_WRONG;
                            break;
#ifdef _NETCDF4
                        case PIO_UBYTE:
                            if (test_data_ubyte_in[f] != test_data_ubyte[f + arraylen * v])
                                return ERR_WRONG;
                            break;
                        case PIO_USHORT:
                            if (test_data_ushort_in[f] != test_data_ushort[f + arraylen * v])
                                return ERR_WRONG;
                            break;
                        case PIO_UINT:
                            if (test_data_uint_in[f] != test_data_uint[f + arraylen * v])
                                return ERR_WRONG;
                            break;
                        case PIO_INT64:
                            if (test_data_int64_in[f] != test_data_int64[f + arraylen * v])
                                return ERR_WRONG;
                            break;
                        case PIO_UINT64:
                            if (test_data_uint64_in[f] != test_data_uint64[f + arraylen * v])
                                return ERR_WRONG;
                            break;
#endif /* _NETCDF4 */
                        default:
                            ERR(ERR_WRONG);
                        }
                    }
                }

                /* Close the netCDF file. */
                if ((ret = PIOc_closefile(ncid2)))
                    ERR(ret);
            } /* next fillvalue test case */
        } /* next test multi */
    } /* next iotype */

    return PIO_NOERR;
}
/** Run Tests for NetCDF-4 Functions.
 *
 * @param argc argument count
 * @param argv array of arguments
 */
int
main(int argc, char **argv)
{
    int verbose = 1;
    
    /** Zero-based rank of processor. */
    int my_rank;

    /** Number of processors involved in current execution. */
    int ntasks;

    /** Specifies the flavor of netCDF output format. */
    int iotype;

    /** Different output flavors. */
    int format[NUM_NETCDF_FLAVORS] = {PIO_IOTYPE_PNETCDF, 
				      PIO_IOTYPE_NETCDF,
				      PIO_IOTYPE_NETCDF4C,
				      PIO_IOTYPE_NETCDF4P};

    /** Names for the output files. */
    char filename[NUM_NETCDF_FLAVORS][NC_MAX_NAME + 1] = {"test_names_pnetcdf.nc",
							  "test_names_classic.nc",
							  "test_names_serial4.nc",
							  "test_names_parallel4.nc"};
	
    /** Number of processors that will do IO. In this test we
     * will do IO from all processors. */
    int niotasks;

    /** Stride in the mpi rank between io tasks. Always 1 in this
     * test. */
    int ioproc_stride = 1;

    /** Number of the aggregator? Always 0 in this test. */
    int numAggregator = 0;

    /** Zero based rank of first processor to be used for I/O. */
    int ioproc_start = 0;

    /** The dimension IDs. */
    int dimids[NDIM];

    /** Array index per processing unit. */
    PIO_Offset elements_per_pe;

    /** The ID for the parallel I/O system. */
    int iosysid;

    /** The ncid of the netCDF file. */
    int ncid = 0;

    /** The ID of the netCDF varable. */
    int varid;

    /** Storage of netCDF-4 files (contiguous vs. chunked). */
    int storage;

    /** Chunksizes set in the file. */
    size_t my_chunksize[NDIM];
    
    /** The shuffle filter setting in the netCDF-4 test file. */
    int shuffle;
    
    /** Non-zero if deflate set for the variable in the netCDF-4 test file. */
    int deflate;

    /** The deflate level set for the variable in the netCDF-4 test file. */
    int deflate_level;

    /** Non-zero if fletcher32 filter is used for variable. */
    int fletcher32;

    /** Endianness of variable. */
    int endianness;

    /* Size of the file chunk cache. */
    size_t chunk_cache_size;

    /* Number of elements in file cache. */
    size_t nelems;

    /* File cache preemption. */
    float preemption;

    /* Size of the var chunk cache. */
    size_t var_cache_size;

    /* Number of elements in var cache. */
    size_t var_cache_nelems;

    /* Var cache preemption. */    
    float var_cache_preemption;
    
    /** The I/O description ID. */
    int ioid;

    /** A buffer for sample data. */
    float *buffer;

    /** A buffer for reading data back from the file. */
    int *read_buffer;

    /** The decomposition mapping. */
    PIO_Offset *compdof;

    /** Return code. */
    int ret;

    /** Index for loops. */
    int fmt, d, d1, i;
    
#ifdef TIMING    
    /* Initialize the GPTL timing library. */
    if ((ret = GPTLinitialize ()))
	return ret;
#endif    
    
    /* Initialize MPI. */
    if ((ret = MPI_Init(&argc, &argv)))
	MPIERR(ret);

    /* Learn my rank and the total number of processors. */
    if ((ret = MPI_Comm_rank(MPI_COMM_WORLD, &my_rank)))
	MPIERR(ret);
    if ((ret = MPI_Comm_size(MPI_COMM_WORLD, &ntasks)))
	MPIERR(ret);

    /* Check that a valid number of processors was specified. */
    if (!(ntasks == 1 || ntasks == 2 || ntasks == 4 ||
	  ntasks == 8 || ntasks == 16))
	fprintf(stderr, "Number of processors must be 1, 2, 4, 8, or 16!\n");
    if (verbose)
	printf("%d: ParallelIO Library example1 running on %d processors.\n",
	       my_rank, ntasks);

    /* keep things simple - 1 iotask per MPI process */    
    niotasks = ntasks; 

    /* Initialize the PIO IO system. This specifies how
     * many and which processors are involved in I/O. */
    if ((ret = PIOc_Init_Intracomm(MPI_COMM_WORLD, niotasks, ioproc_stride,
				   ioproc_start, PIO_REARR_SUBSET, &iosysid)))
	ERR(ret);

    /* Describe the decomposition. This is a 1-based array, so add 1! */
    elements_per_pe = X_DIM_LEN * Y_DIM_LEN / ntasks;
    if (!(compdof = malloc(elements_per_pe * sizeof(PIO_Offset))))
	return PIO_ENOMEM;
    for (i = 0; i < elements_per_pe; i++) {
	compdof[i] = my_rank * elements_per_pe + i + 1;
    }
	
    /* Create the PIO decomposition for this test. */
    if (verbose)
	printf("rank: %d Creating decomposition...\n", my_rank);
    if ((ret = PIOc_InitDecomp(iosysid, PIO_FLOAT, 2, &dim_len[1], (PIO_Offset)elements_per_pe,
			       compdof, &ioid, NULL, NULL, NULL)))
	ERR(ret);
    free(compdof);

    /* How many flavors will we be running for? */
    int num_flavors = 0;
    int fmtidx = 0;
#ifdef _PNETCDF
    num_flavors++;
    format[fmtidx++] = PIO_IOTYPE_PNETCDF;
#endif
#ifdef _NETCDF
    num_flavors++;
    format[fmtidx++] = PIO_IOTYPE_NETCDF;
#endif
#ifdef _NETCDF4
    num_flavors += 2;
    format[fmtidx++] = PIO_IOTYPE_NETCDF4C;
    format[fmtidx] = PIO_IOTYPE_NETCDF4P;
#endif
    
    /* Use PIO to create the example file in each of the four
     * available ways. */
    for (fmt = 0; fmt < num_flavors; fmt++) 
    {
	/* Create the netCDF output file. */
	if (verbose)
	    printf("rank: %d Creating sample file %s with format %d...\n",
		   my_rank, filename[fmt], format[fmt]);
	if ((ret = PIOc_createfile(iosysid, &ncid, &(format[fmt]), filename[fmt],
				   PIO_CLOBBER)))
	    ERR(ret);
	
	/* Define netCDF dimensions and variable. */
	if (verbose)
	    printf("rank: %d Defining netCDF metadata...\n", my_rank);
	for (d = 0; d < NDIM; d++) {
	    if (verbose)
		printf("rank: %d Defining netCDF dimension %s, length %d\n", my_rank,
		       dim_name[d], dim_len[d]);
	    if ((ret = PIOc_def_dim(ncid, dim_name[d], (PIO_Offset)dim_len[d], &dimids[d])))
		ERR(ret);
	}

	/* Check the dimension names. */
	if ((ret = check_dim_names(my_rank, ncid, verbose)))
	    ERR(ret);

	/* Define a global attribute. */
	int att_val = 42;
	if ((ret = PIOc_put_att_int(ncid, NC_GLOBAL, ATT_NAME, NC_INT, 1, &att_val)))
	    ERR(ret);

	/* Check the attribute name. */
	if ((ret = check_att_name(my_rank, ncid, verbose)))
	    ERR(ret);

	/* Define a variable. */
	if ((ret = PIOc_def_var(ncid, VAR_NAME, PIO_FLOAT, NDIM, dimids, &varid)))
	    ERR(ret);

	/* Check the variable name. */
	if ((ret = check_var_name(my_rank, ncid, verbose)))
	    ERR(ret);

	if ((ret = PIOc_enddef(ncid)))
	    ERR(ret);

	/* Close the netCDF file. */
	if (verbose)
	    printf("rank: %d Closing the sample data file...\n", my_rank);
	if ((ret = PIOc_closefile(ncid)))
	    ERR(ret);

	/* Put a barrier here to make verbose output look better. */
	if ((ret = MPI_Barrier(MPI_COMM_WORLD)))
	    MPIERR(ret);

    }
	
    /* Free the PIO decomposition. */
    if (verbose)
	printf("rank: %d Freeing PIO decomposition...\n", my_rank);
    if ((ret = PIOc_freedecomp(iosysid, ioid)))
	ERR(ret);
	
    /* Finalize the IO system. */
    if (verbose)
	printf("rank: %d Freeing PIO resources...\n", my_rank);
    if ((ret = PIOc_finalize(iosysid)))
	ERR(ret);

    /* Finalize the MPI library. */
    MPI_Finalize();

#ifdef TIMING    
    /* Finalize the GPTL timing library. */
    if ((ret = GPTLfinalize ()))
	return ret;
#endif    
    

    return 0;
}
Exemple #3
0
/* Run Tests for Init_Intercomm. */
int main(int argc, char **argv)
{
    /* Zero-based rank of processor. */
    int my_rank;

    /* Number of processors involved in current execution. */
    int ntasks;

    int num_flavors; /* Number of PIO netCDF flavors in this build. */
    int flavor[NUM_FLAVORS]; /* iotypes for the supported netCDF IO flavors. */

    /* Names for the output files. */
    char filename[NUM_FLAVORS][NC_MAX_NAME + 1];

    /* The ID for the parallel I/O system. */
    int iosysid[COMPONENT_COUNT];

    /* Return code. */
    int ret;

    MPI_Comm test_comm;

    char too_long_name[PIO_MAX_NAME * 5 + 1];

    /* Create a name that is too long. */
    memset(too_long_name, 74, PIO_MAX_NAME * 5);
    too_long_name[PIO_MAX_NAME * 5] = 0;

    /* Set up test. */
    if ((ret = pio_test_init2(argc, argv, &my_rank, &ntasks, TARGET_NTASKS, TARGET_NTASKS,
                              -1, &test_comm)))
        ERR(ERR_INIT);

    /* Figure out iotypes. */
    if ((ret = get_iotypes(&num_flavors, flavor)))
        ERR(ret);

    if (my_rank < TARGET_NTASKS)
    {

        /* How many processors will be used for our IO and 2 computation components. */
        int num_procs[COMPONENT_COUNT] = {2};

        /* Is the current process a computation task? */
        int comp_task = my_rank < 2 ? 0 : 1;

        /* Index of computation task in iosysid array. Varies by rank and
         * does not apply to IO component processes. */
        int my_comp_idx = comp_task ? 0 : -1;

        /* Initialize the IO system. */
        if ((ret = PIOc_init_async(test_comm, NUM_IO_PROCS, NULL, COMPONENT_COUNT,
                                   num_procs, NULL, NULL, NULL, PIO_REARR_BOX, iosysid)))
            ERR(ERR_AWFUL);

        /* All the netCDF calls are only executed on the computation
         * tasks. The IO tasks have not returned from PIOc_Init_Intercomm,
         * and when the do, they should go straight to finalize. */
        if (comp_task)
        {
            for (int fmt = 0; fmt < num_flavors; fmt++)
            {
                int ncid, varid, dimid;
                PIO_Offset start[NDIM], count[NDIM] = {0};
                int data[DIM_LEN];

                /* Create the filename for this flavor. */
                sprintf(filename[fmt], "test_intercomm2_%d.nc", flavor[fmt]);

                /* Create a netCDF file with one dimension and one variable. */
                if ((ret = PIOc_createfile(iosysid[my_comp_idx], &ncid, &flavor[fmt], filename[fmt],
                                           NC_CLOBBER)))
                    ERR(ret);

                /* End define mode, then re-enter it. */
                if ((ret = PIOc_enddef(ncid)))
                    ERR(ret);
                if ((ret = PIOc_redef(ncid)))
                    ERR(ret);

                /* Test the inq_format function. */
                int myformat;
                if (PIOc_inq_format(ncid + TEST_VAL_42, &myformat) != PIO_EBADID)
                    ERR(ERR_WRONG);
                if ((ret = PIOc_inq_format(ncid, &myformat)))
                    ERR(ret);
                if ((flavor[fmt] == PIO_IOTYPE_PNETCDF || flavor[fmt] == PIO_IOTYPE_NETCDF) &&
                    myformat != 1)
                    ERR(ERR_AWFUL);
                else if ((flavor[fmt] == PIO_IOTYPE_NETCDF4C || flavor[fmt] == PIO_IOTYPE_NETCDF4P) &&
                         myformat != 3)
                    ERR(ERR_AWFUL);

                /* Test the inq_type function for atomic types. */
                char type_name[NC_MAX_NAME + 1];
                PIO_Offset type_size;
                nc_type xtype[NUM_TYPES] = {NC_CHAR, NC_BYTE, NC_SHORT, NC_INT, NC_FLOAT, NC_DOUBLE,
                                            NC_UBYTE, NC_USHORT, NC_UINT, NC_INT64, NC_UINT64};
                int type_len[NUM_TYPES] = {1, 1, 2, 4, 4, 8, 1, 2, 4, 8, 8};
                int max_type = flavor[fmt] == PIO_IOTYPE_NETCDF ? NC_DOUBLE : NC_UINT64;

                /* This should not work. */
                if (PIOc_inq_type(ncid + TEST_VAL_42, xtype[0], type_name, &type_size) != PIO_EBADID)
                    ERR(ERR_WRONG);

                /* These should work. */
                for (int i = 0; i < max_type; i++)
                {
                    if ((ret = PIOc_inq_type(ncid, xtype[i], type_name, &type_size)))
                        ERR(ret);
                    if (type_size != type_len[i])
                        ERR(ERR_AWFUL);
                }

                /* Define a dimension. */
                char dimname2[NC_MAX_NAME + 1];
                if ((ret = PIOc_def_dim(ncid, FIRST_DIM_NAME, DIM_LEN, &dimid)))
                    ERR(ret);
                if ((ret = PIOc_inq_dimname(ncid, 0, dimname2)))
                    ERR(ret);
                if (strcmp(dimname2, FIRST_DIM_NAME))
                    ERR(ERR_WRONG);
                if ((ret = PIOc_rename_dim(ncid, 0, DIM_NAME)))
                    ERR(ret);

                /* These should not work. */
                if (PIOc_rename_dim(ncid + TEST_VAL_42, 0, DIM_NAME) != PIO_EBADID)
                    ERR(ERR_WRONG);
                if (PIOc_rename_dim(ncid, 0, NULL) != PIO_EINVAL)
                    ERR(ERR_WRONG);
                if (PIOc_rename_dim(ncid, 0, too_long_name) != PIO_EINVAL)
                    ERR(ERR_WRONG);

                /* Define a 1-D variable. */
                char varname2[NC_MAX_NAME + 1];
                if ((ret = PIOc_def_var(ncid, FIRST_VAR_NAME, NC_INT, NDIM, &dimid, &varid)))
                    ERR(ret);
                if ((ret = PIOc_inq_varname(ncid, 0, varname2)))
                    ERR(ret);
                if (strcmp(varname2, FIRST_VAR_NAME))
                    ERR(ERR_WRONG);
                if ((ret = PIOc_rename_var(ncid, 0, VAR_NAME)))
                    ERR(ret);

                /* These should not work. */
                if (PIOc_rename_var(ncid + TEST_VAL_42, 0, VAR_NAME) != PIO_EBADID)
                    ERR(ERR_WRONG);
                if (PIOc_rename_var(ncid, 0, NULL) != PIO_EINVAL)
                    ERR(ERR_WRONG);
                if (PIOc_rename_var(ncid, 0, too_long_name) != PIO_EINVAL)
                    ERR(ERR_WRONG);

                /* Add a global attribute. */
                int att_data = ATT_VALUE;
                short short_att_data = ATT_VALUE;
                float float_att_data = ATT_VALUE;
                double double_att_data = ATT_VALUE;
                char attname2[NC_MAX_NAME + 1];

                /* Write an att and rename it. */
                if ((ret = PIOc_put_att_int(ncid, NC_GLOBAL, FIRST_ATT_NAME, NC_INT, 1, &att_data)))
                    ERR(ret);
                if ((ret = PIOc_inq_attname(ncid, NC_GLOBAL, 0, attname2)))
                    ERR(ret);
                if (strcmp(attname2, FIRST_ATT_NAME))
                    ERR(ERR_WRONG);
                if ((ret = PIOc_rename_att(ncid, NC_GLOBAL, FIRST_ATT_NAME, ATT_NAME)))
                    ERR(ret);

                /* These should not work. */
                if (PIOc_inq_attname(ncid + TEST_VAL_42, NC_GLOBAL, 0, attname2) != PIO_EBADID)
                    ERR(ERR_WRONG);
                if (PIOc_rename_att(ncid + TEST_VAL_42, NC_GLOBAL, FIRST_ATT_NAME, ATT_NAME) != PIO_EBADID)
                    ERR(ERR_WRONG);
                if (PIOc_rename_att(ncid, NC_GLOBAL, FIRST_ATT_NAME, NULL) != PIO_EINVAL)
                    ERR(ERR_WRONG);
                if (PIOc_rename_att(ncid, NC_GLOBAL, FIRST_ATT_NAME, too_long_name) != PIO_EINVAL)
                    ERR(ERR_WRONG);
                if (PIOc_del_att(ncid + TEST_VAL_42, NC_GLOBAL, FIRST_ATT_NAME) != PIO_EBADID)
                    ERR(ERR_WRONG);
                if (PIOc_del_att(ncid, NC_GLOBAL, NULL) != PIO_EINVAL)
                    ERR(ERR_WRONG);
                if (PIOc_del_att(ncid, NC_GLOBAL, too_long_name) != PIO_EINVAL)
                    ERR(ERR_WRONG);

                /* Write an att and delete it. */
                if ((ret = PIOc_put_att_int(ncid, NC_GLOBAL, FIRST_ATT_NAME, NC_INT, 1, &att_data)))
                    ERR(ret);
                if ((ret = PIOc_del_att(ncid, NC_GLOBAL, FIRST_ATT_NAME)))
                    ERR(ret);
                /* if ((ret = PIOc_inq_att(ncid, NC_GLOBAL, FIRST_ATT_NAME, NULL, NULL)) != PIO_ENOTATT) */
                /* { */
                /*      printf("ret = %d\n", ret); */
                /*      ERR(ERR_AWFUL); */
                /* } */

                /* Write some atts of different types. */
                if ((ret = PIOc_put_att_short(ncid, NC_GLOBAL, SHORT_ATT_NAME, NC_SHORT, 1, &short_att_data)))
                    ERR(ret);
                if ((ret = PIOc_put_att_float(ncid, NC_GLOBAL, FLOAT_ATT_NAME, NC_FLOAT, 1, &float_att_data)))
                    ERR(ret);
                if ((ret = PIOc_put_att_double(ncid, NC_GLOBAL, DOUBLE_ATT_NAME, NC_DOUBLE, 1, &double_att_data)))
                    ERR(ret);

                /* Check some att types. */
                nc_type myatttype;
                if ((ret = PIOc_inq_atttype(ncid, NC_GLOBAL, SHORT_ATT_NAME, &myatttype)))
                    ERR(ret);
                if (myatttype != NC_SHORT)
                    ERR(ERR_WRONG);
                if ((ret = PIOc_inq_atttype(ncid, NC_GLOBAL, FLOAT_ATT_NAME, &myatttype)))
                    ERR(ret);
                if (myatttype != NC_FLOAT)
                    ERR(ERR_WRONG);
                if ((ret = PIOc_inq_atttype(ncid, NC_GLOBAL, DOUBLE_ATT_NAME, &myatttype)))
                    ERR(ret);
                if (myatttype != NC_DOUBLE)
                    ERR(ERR_WRONG);

                /* End define mode. */
                if ((ret = PIOc_enddef(ncid)))
                    ERR(ret);

                /* Write some data. For the PIOc_put/get functions, all
                 * data must be on compmaster before the function is
                 * called. Only compmaster's arguments are passed to the
                 * async msg handler. All other computation tasks are
                 * ignored. */
                for (int i = 0; i < DIM_LEN; i++)
                    data[i] = i;
                start[0] = 0;
                count[0] = DIM_LEN;
                if ((ret = PIOc_put_vars_tc(ncid, varid, start, count, NULL, NC_INT, data)))
                    ERR(ret);

                /* Close the file. */
                if ((ret = PIOc_closefile(ncid)))
                    ERR(ret);

                /* Check the file for correctness. */
                if ((ret = check_file(iosysid[my_comp_idx], flavor[fmt], filename[fmt], my_rank)))
                    ERR(ret);

                /* Now delete the file. */
                /* if ((ret = PIOc_deletefile(iosysid, filename[fmt]))) */
                /*      ERR(ret); */
                /* if ((ret = PIOc_openfile(iosysid, &ncid, &flavor[fmt], filename[fmt], */
                /*                           NC_NOWRITE)) != PIO_ENFILE) */
                /*      ERR(ERR_AWFUL); */

            } /* next netcdf flavor */

            /* Finalize the IO system. Only call this from the computation tasks. */
            if ((ret = PIOc_finalize(iosysid[my_comp_idx])))
                ERR(ret);
        }
    } /* my_rank < TARGET_NTASKS */

    /* Finalize test. */
    if ((ret = pio_test_finalize(&test_comm)))
        return ERR_AWFUL;

    printf("%d %s SUCCESS!!\n", my_rank, TEST_NAME);

    return 0;
}