int main(int argc, char **argv) { int i, j; int status; int ncid1, ncid2; int ndims, nvars, ngatts, unlimdimid; char name[NC_MAX_NAME]; nc_type type, vartypes[NC_MAX_VARS]; MPI_Offset attlen; MPI_Offset dimlen, shape[NC_MAX_VAR_DIMS], varsize, start[NC_MAX_VAR_DIMS]; void *valuep; int dimids[NC_MAX_DIMS], varids[NC_MAX_VARS]; int vardims[NC_MAX_VARS][NC_MAX_VAR_DIMS/16]; /* divided by 16 due to my memory limitation */ int varndims[NC_MAX_VARS], varnatts[NC_MAX_VARS]; params opts; int rank; int nprocs; MPI_Comm comm = MPI_COMM_WORLD; MPI_Init(&argc, &argv); MPI_Comm_size(MPI_COMM_WORLD, &nprocs); MPI_Comm_rank(MPI_COMM_WORLD, &rank); if (rank == 0) fprintf(stderr, "Testing independent read ... "); parse_read_args(argc, argv, rank, &opts); /********** START OF NETCDF ACCESS **************/ /* Read a netCDF file and write it out to another file */ /** * Open the input dataset - ncid1: * File name: "../data/test_int.nc" * Dataset API: Collective * And create the output dataset - ncid2: * File name: "testread.nc" * Dataset API: Collective */ status = ncmpi_open(comm, opts.infname, 0, MPI_INFO_NULL, &ncid1); if (status != NC_NOERR) handle_error(status); status = ncmpi_create(comm, opts.outfname, NC_CLOBBER, MPI_INFO_NULL, &ncid2); if (status != NC_NOERR) handle_error(status); /** * Inquire the dataset definitions of input dataset AND * Add dataset definitions for output dataset. */ status = ncmpi_inq(ncid1, &ndims, &nvars, &ngatts, &unlimdimid); if (status != NC_NOERR) handle_error(status); /* Inquire global attributes, assume CHAR attributes. */ for (i = 0; i < ngatts; i++) { status = ncmpi_inq_attname(ncid1, NC_GLOBAL, i, name); if (status != NC_NOERR) handle_error(status); status = ncmpi_inq_att (ncid1, NC_GLOBAL, name, &type, &attlen); if (status != NC_NOERR) handle_error(status); switch (type) { case NC_CHAR: valuep = (void *)malloc(attlen * sizeof(char)); status = ncmpi_get_att_text(ncid1, NC_GLOBAL, name, valuep); if (status != NC_NOERR) handle_error(status); status = ncmpi_put_att_text (ncid2, NC_GLOBAL, name, attlen, (char *)valuep); if (status != NC_NOERR) handle_error(status); free(valuep); break; case NC_SHORT: valuep = (void *)malloc(attlen * sizeof(short)); status = ncmpi_get_att_short(ncid1, NC_GLOBAL, name, valuep); if (status != NC_NOERR) handle_error(status); status = ncmpi_put_att_short (ncid2, NC_GLOBAL, name, type, attlen, (short *)valuep); if (status != NC_NOERR) handle_error(status); free(valuep); break; case NC_INT: valuep = (void *)malloc(attlen * sizeof(int)); status = ncmpi_get_att_int(ncid1, NC_GLOBAL, name, valuep); if (status != NC_NOERR) handle_error(status); status = ncmpi_put_att_int (ncid2, NC_GLOBAL, name, type, attlen, (int *)valuep); if (status != NC_NOERR) handle_error(status); free(valuep); break; case NC_FLOAT: valuep = (void *)malloc(attlen * sizeof(float)); status = ncmpi_get_att_float(ncid1, NC_GLOBAL, name, valuep); if (status != NC_NOERR) handle_error(status); status = ncmpi_put_att_float (ncid2, NC_GLOBAL, name, type, attlen, (float *)valuep); if (status != NC_NOERR) handle_error(status); free(valuep); break; case NC_DOUBLE: valuep = (void *)malloc(attlen * sizeof(double)); status = ncmpi_get_att_double(ncid1, NC_GLOBAL, name, valuep); if (status != NC_NOERR) handle_error(status); status = ncmpi_put_att_double (ncid2, NC_GLOBAL, name, type, attlen, (double *)valuep); if (status != NC_NOERR) handle_error(status); free(valuep); break; default: ; /* handle unexpected types */ } } /* Inquire dimension */ for (i = 0; i < ndims; i++) { status = ncmpi_inq_dim(ncid1, i, name, &dimlen); if (status != NC_NOERR) handle_error(status); if (i == unlimdimid) dimlen = NC_UNLIMITED; status = ncmpi_def_dim(ncid2, name, dimlen, dimids+i); if (status != NC_NOERR) handle_error(status); } /* Inquire variables */ for (i = 0; i < nvars; i++) { status = ncmpi_inq_var (ncid1, i, name, vartypes+i, varndims+i, vardims[i], varnatts+i); if (status != NC_NOERR) handle_error(status); status = ncmpi_def_var(ncid2, name, vartypes[i], varndims[i], vardims[i], varids+i); if (status != NC_NOERR) handle_error(status); /* var attributes, assume CHAR attributes */ for (j = 0; j < varnatts[i]; j++) { status = ncmpi_inq_attname(ncid1, varids[i], j, name); if (status != NC_NOERR) handle_error(status); status = ncmpi_inq_att (ncid1, varids[i], name, &type, &attlen); if (status != NC_NOERR) handle_error(status); switch (type) { case NC_CHAR: valuep = (void *)malloc(attlen * sizeof(char)); status = ncmpi_get_att_text(ncid1, varids[i], name, valuep); if (status != NC_NOERR) handle_error(status); status = ncmpi_put_att_text (ncid2, varids[i], name, attlen, (char *)valuep); if (status != NC_NOERR) handle_error(status); free(valuep); break; case NC_SHORT: valuep = (void *)malloc(attlen * sizeof(short)); status = ncmpi_get_att_short(ncid1, varids[i], name, valuep); if (status != NC_NOERR) handle_error(status); status = ncmpi_put_att_short (ncid2, varids[i], name, type, attlen, (short *)valuep); if (status != NC_NOERR) handle_error(status); free(valuep); break; case NC_INT: valuep = (void *)malloc(attlen * sizeof(int)); status = ncmpi_get_att_int(ncid1, varids[i], name, valuep); if (status != NC_NOERR) handle_error(status); status = ncmpi_put_att_int (ncid2, varids[i], name, type, attlen, (int *)valuep); if (status != NC_NOERR) handle_error(status); free(valuep); break; case NC_FLOAT: valuep = (void *)malloc(attlen * sizeof(float)); status = ncmpi_get_att_float(ncid1, varids[i], name, valuep); if (status != NC_NOERR) handle_error(status); status = ncmpi_put_att_float (ncid2, varids[i], name, type, attlen, (float *)valuep); if (status != NC_NOERR) handle_error(status); free(valuep); break; case NC_DOUBLE: valuep = (void *)malloc(attlen * sizeof(double)); status = ncmpi_get_att_double(ncid1, varids[i], name, valuep); if (status != NC_NOERR) handle_error(status); status = ncmpi_put_att_double (ncid2, varids[i], name, type, attlen, (double *)valuep); if (status != NC_NOERR) handle_error(status); free(valuep); break; default: ; /* handle unexpected types */ } } } /** * End Define Mode (switch to data mode) for output dataset * Dataset API: Collective */ status = ncmpi_enddef(ncid2); if (status != NC_NOERR) handle_error(status); /** * Read data of variables from input dataset (assume INT variables) * Write the data out to the corresponding variables in the output dataset * * Data Partition (Assume 4 processors): * square: 2-D, (Block, *), 25*100 from 100*100 * cube: 3-D, (Block, *, *), 25*100*100 from 100*100*100 * xytime: 3-D, (Block, *, *), 25*100*100 from 100*100*100 * time: 1-D, Block-wise, 25 from 100 * * Data Mode API: non-collective */ status = ncmpi_begin_indep_data(ncid1); if (status != NC_NOERR) handle_error(status); status =ncmpi_begin_indep_data(ncid2); if (status != NC_NOERR) handle_error(status); for (i = 0; i < NC_MAX_VAR_DIMS; i++) start[i] = 0; for (i = 0; i < nvars; i++) { varsize = 1; for (j = 0; j < varndims[i]; j++) { status = ncmpi_inq_dim(ncid1, vardims[i][j], name, shape + j); if (status != NC_NOERR) handle_error(status); if (j == 0) { shape[j] /= nprocs; start[j] = shape[j] * rank; } varsize *= shape[j]; } switch (vartypes[i]) { case NC_CHAR: break; case NC_SHORT: valuep = (void *)malloc(varsize * sizeof(short)); status = ncmpi_get_vara_short(ncid1, i, start, shape, (short *)valuep); if (status != NC_NOERR) handle_error(status); status = ncmpi_put_vara_short(ncid2, varids[i], start, shape, (short *)valuep); if (status != NC_NOERR) handle_error(status); free(valuep); break; case NC_INT: valuep = (void *)malloc(varsize * sizeof(int)); status = ncmpi_get_vara_int(ncid1, i, start, shape, (int *)valuep); if (status != NC_NOERR) handle_error(status); status = ncmpi_put_vara_int(ncid2, varids[i], start, shape, (int *)valuep); if (status != NC_NOERR) handle_error(status); free(valuep); break; case NC_FLOAT: valuep = (void *)malloc(varsize * sizeof(float)); status = ncmpi_get_vara_float(ncid1, i, start, shape, (float *)valuep); if (status != NC_NOERR) handle_error(status); status = ncmpi_put_vara_float(ncid2, varids[i], start, shape, (float *)valuep); if (status != NC_NOERR) handle_error(status); free(valuep); break; case NC_DOUBLE: valuep = (void *)malloc(varsize * sizeof(double)); status = ncmpi_get_vara_double(ncid1, i, start, shape, (double *)valuep); if (status != NC_NOERR) handle_error(status); status = ncmpi_put_vara_double(ncid2, varids[i], start, shape, (double *)valuep); if (status != NC_NOERR) handle_error(status); free(valuep); break; default: ; /* handle unexpected types */ } } status = ncmpi_end_indep_data(ncid1); if (status != NC_NOERR) handle_error(status); status = ncmpi_end_indep_data(ncid2); if (status != NC_NOERR) handle_error(status); status = ncmpi_sync(ncid1); if (status != NC_NOERR) handle_error(status); status = ncmpi_sync(ncid2); if (status != NC_NOERR) handle_error(status); /** * Close the datasets * Dataset API: collective */ status = ncmpi_close(ncid1); if (status != NC_NOERR) handle_error(status); status = ncmpi_close(ncid2); if (status != NC_NOERR) handle_error(status); /******************* END OF NETCDF ACCESS ****************/ if (rank == 0) fprintf(stderr, "OK\nInput file %s copied to: %s!\n", opts.infname, opts.outfname); MPI_Finalize(); return 0; }
int main(int argc, char **argv) { int i, j, rank, nprocs, ret; int ncfile, ndims, nvars, ngatts, unlimited; int var_ndims, var_natts;; MPI_Offset *dim_sizes, var_size; MPI_Offset *start, *count; int *requests, *statuses; char varname[NC_MAX_NAME+1]; int dimids[NC_MAX_VAR_DIMS]; nc_type type; int **data; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &nprocs); if (argc != 2) { if (rank == 0) printf("Usage: %s filename\n", argv[0]); MPI_Finalize(); exit(-1); } ret = ncmpi_open(MPI_COMM_WORLD, argv[1], NC_NOWRITE, MPI_INFO_NULL, &ncfile); if (ret != NC_NOERR) handle_error(ret, __LINE__); /* reader knows nothing about dataset, but we can interrogate with query * routines: ncmpi_inq tells us how many of each kind of "thing" * (dimension, variable, attribute) we will find in the file */ /* no commnunication needed after ncmpi_open: all processors have a cached * veiw of the metadata once ncmpi_open returns */ ret = ncmpi_inq(ncfile, &ndims, &nvars, &ngatts, &unlimited); if (ret != NC_NOERR) handle_error(ret, __LINE__); /* we do not really need the name of the dimension or the variable for * reading in this example. we could, in a different example, take the * name of a variable on the command line and read just that one */ dim_sizes = calloc(ndims, sizeof(MPI_Offset)); /* netcdf dimension identifiers are allocated sequentially starting * at zero; same for variable identifiers */ for(i=0; i<ndims; i++) { ret = ncmpi_inq_dimlen(ncfile, i, &(dim_sizes[i]) ); if (ret != NC_NOERR) handle_error(ret, __LINE__); } requests = calloc(nvars, sizeof(int)); statuses = calloc(nvars, sizeof(int)); data = malloc(nvars*sizeof(int*)); for(i=0; i<nvars; i++) { /* much less coordination in this case compared to rank 0 doing all * the i/o: everyone already has the necessary information */ ret = ncmpi_inq_var(ncfile, i, varname, &type, &var_ndims, dimids, &var_natts); if (ret != NC_NOERR) handle_error(ret, __LINE__); start = calloc(var_ndims, sizeof(MPI_Offset)); count = calloc(var_ndims, sizeof(MPI_Offset)); /* we will simply decompose along one dimension. Generally the * application has some algorithim for domain decomposistion. Note * that data decomposistion can have an impact on i/o performance. * Often it's best just to do what is natural for the application, * but something to consider if performance is not what was * expected/desired */ start[0] = (dim_sizes[dimids[0]]/nprocs)*rank; count[0] = (dim_sizes[dimids[0]]/nprocs); var_size = count[0]; for (j=1; j<var_ndims; j++) { start[j] = 0; count[j] = dim_sizes[dimids[j]]; var_size *= count[j]; } switch(type) { case NC_INT: data[i] = calloc(var_size, sizeof(int)); /* as with the writes, this call is independent: we * will do any coordination (if desired) in a * subsequent ncmpi_wait_all() call */ ret = ncmpi_iget_vara(ncfile, i, start, count, data[i], var_size, MPI_INT, &(requests[i])); if (ret != NC_NOERR) handle_error(ret, __LINE__); break; default: /* we can do this for all the known netcdf types but this * example is already getting too long */ fprintf(stderr, "unsupported NetCDF type \n"); } free(start); free(count); } ret = ncmpi_wait_all(ncfile, nvars, requests, statuses); if (ret != NC_NOERR) handle_error(ret, __LINE__); /* now that the ncmpi_wait_all has returned, the caller can do stuff with * the buffers passed in to the non-blocking operations. The buffer resue * rules are similar to MPI non-blocking messages */ for (i=0; i<nvars; i++) { if (data[i] != NULL) free(data[i]); } free(data); free(dim_sizes); free(requests); free(statuses); ret = ncmpi_close(ncfile); if (ret != NC_NOERR) handle_error(ret, __LINE__); MPI_Finalize(); return 0; }
int main(int argc, char **argv) { int i, j=0, rank, nprocs, err; int ncfile, ndims, nvars, ngatts, unlimited, var_ndims, var_natts;; int *dimids=NULL; char filename[256], varname[NC_MAX_NAME+1]; MPI_Offset *dim_sizes=NULL, var_size; nc_type type; int *data=NULL; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &nprocs); if (argc > 2) { if (rank == 0) printf("Usage: %s filename\n", argv[0]); MPI_Finalize(); exit(-1); } if (argc > 1) snprintf(filename, 256, "%s", argv[1]); else strcpy(filename, "testfile.nc"); if (rank == 0) { err = ncmpi_open(MPI_COMM_SELF, filename, NC_NOWRITE, MPI_INFO_NULL, &ncfile); if (err != NC_NOERR) handle_error(err, __LINE__); /* reader knows nothing about dataset, but we can interrogate with * query routines: ncmpi_inq tells us how many of each kind of * "thing" (dimension, variable, attribute) we will find in the * file */ err = ncmpi_inq(ncfile, &ndims, &nvars, &ngatts, &unlimited); if (err != NC_NOERR) handle_error(err, __LINE__); /* we do not really need the name of the dimension or the variable * for reading in this example. we could, in a different example, * take the name of a variable on the command line and read just * that one */ dim_sizes = (MPI_Offset*) calloc(ndims, sizeof(MPI_Offset)); /* netcdf dimension identifiers are allocated sequentially starting * at zero; same for variable identifiers */ for(i=0; i<ndims; i++) { err = ncmpi_inq_dimlen(ncfile, i, &(dim_sizes[i]) ); if (err != NC_NOERR) handle_error(err, __LINE__); } } /* need to inform other MPI processors how many variables we will send */ err = MPI_Bcast(&nvars, 1, MPI_INT, 0, MPI_COMM_WORLD); MPI_ERR(err) for(i=0; i<nvars; i++) { /* rank 0 will find out the size of each variable, read it, and * broadcast it to the rest of the processors */ if (rank == 0) { /* obtain the number of dimensions of variable i, so we can * allocate the dimids array */ err = ncmpi_inq_varndims(ncfile, i, &var_ndims); if (err != NC_NOERR) handle_error(err, __LINE__); dimids = (int*) malloc(var_ndims * sizeof(int)); err = ncmpi_inq_var(ncfile, i, varname, &type, &var_ndims, dimids, &var_natts); if (err != NC_NOERR) handle_error(err, __LINE__); for (j=0, var_size=1; j<var_ndims; j++) { var_size *= dim_sizes[dimids[j]]; } free(dimids); } /* oddity: there's no predefined MPI_Offset type */ err = MPI_Bcast(&var_size, 1, MPI_OFFSET, 0, MPI_COMM_WORLD); MPI_ERR(err) data = (int*) calloc(var_size, sizeof(int)); if (rank == 0) { switch(type) { case NC_INT: /* now we have the variable identifiers and we know how big * they are */ /* this approach is not scalable: i/o happens from a single * processor. This approach can be ok if the amount of * data is quite small, but almost always the underlying * MPI-IO library can do a better job */ err = ncmpi_get_var_int_all(ncfile, j, data); if (err != NC_NOERR) handle_error(err, __LINE__); break; default: /* we can do this for all the known netcdf types but this * example is already getting too long */ fprintf(stderr, "unsupported NetCDF type \n"); } } /*and finally all processors have the data */ err = MPI_Bcast(data, var_size, MPI_INT, 0, MPI_COMM_WORLD); MPI_ERR(err) /* Here, every process can do computation on the local buffer, data, or copy the contents to somewhere else */ free(data); } if (rank == 0) { err = ncmpi_close(ncfile); if (err != NC_NOERR) handle_error(err, __LINE__); free(dim_sizes); } MPI_Finalize(); return 0; }
/* reads input in pnetcdf format nblocks: (output) local number of blocks tot_blocks: (output) total number of blocks vblocks: (output) pointer to array of vblocks in_file: input file name comm: MPI communicator gids: (output) gids of local blocks (allocated by this function) num_neighbors: (output) number of neighbors for each local block (allocated by this function) neighbors: (output) gids of neighbors of each local block (allocated by this function) side effects: allocates vblocks, gids, num_neighbors, neighbors */ void pnetcdf_read(int *nblocks, int *tot_blocks, struct vblock_t ***vblocks, char *in_file, MPI_Comm comm, int *gids, int *num_neighbors, int **neighbors) { #ifdef USEPNETCDF int err; int ncid, varids[23], dimids[8]; MPI_Offset start[2], count[2]; nc_type type; int ndims, natts; int dims[2]; int rank, groupsize; /* MPI usual */ /* open file for reading */ err = ncmpi_open(comm, in_file, NC_NOWRITE, MPI_INFO_NULL, &ncid); ERR; err = ncmpi_inq_varid(ncid, "block_off_num_verts", &varids[5]); ERR; err = ncmpi_inq_varid(ncid, "block_off_num_complete_cells", &varids[6]); ERR; err = ncmpi_inq_varid(ncid, "block_off_tot_num_cell_faces", &varids[7]); ERR; err = ncmpi_inq_varid(ncid, "block_off_tot_num_face_verts", &varids[8]); ERR; err = ncmpi_inq_varid(ncid, "block_off_num_orig_particles", &varids[9]); ERR; /* get number of blocks */ MPI_Offset num_g_blocks; /* 64 bit version of tot_blcoks */ err = ncmpi_inq_dimlen(ncid, dimids[0], &num_g_blocks); ERR; *tot_blocks = num_g_blocks; MPI_Comm_rank(comm, &rank); MPI_Comm_size(comm, &groupsize); int start_block_ofst = rank * (*tot_blocks / groupsize); *nblocks = (rank < groupsize - 1 ? (*tot_blocks / groupsize) : *tot_blocks - (rank * *tot_blocks / groupsize)); /* block offsets */ int64_t *block_ofsts = (int64_t*)malloc(*tot_blocks * sizeof(int64_t)); *vblocks = (struct vblock_t**)malloc(*nblocks * sizeof(struct vblock_t*)); /* read all blocks */ gids = (int *)malloc(*nblocks * sizeof(int)); num_neighbors = (int *)malloc(*nblocks * sizeof(int)); neighbors = (int **)malloc(*nblocks * sizeof(int *)); int b; for (b = 0; b < *nblocks; b++) { struct vblock_t* v = (struct vblock_t*)malloc(sizeof(struct vblock_t)); /* quantities */ start[0] = start_block_ofst + b; count[0] = 1; err = ncmpi_inq_varid(ncid, "num_verts", &varids[0]); ERR; err = ncmpi_get_vara_int_all(ncid, varids[0], start, count, &(v->num_verts)); ERR; err = ncmpi_inq_varid(ncid, "num_complete_cells", &varids[1]); ERR; err = ncmpi_get_vara_int_all(ncid, varids[1], start, count, &(v->num_complete_cells)); ERR; err = ncmpi_inq_varid(ncid, "tot_num_cell_faces", &varids[2]); ERR; err = ncmpi_get_vara_int_all(ncid, varids[2], start, count, &(v->tot_num_cell_faces)); ERR; err = ncmpi_inq_varid(ncid, "tot_num_face_verts", &varids[3]); ERR; err = ncmpi_get_vara_int_all(ncid, varids[3], start, count, &(v->tot_num_face_verts)); ERR; err = ncmpi_inq_varid(ncid, "num_orig_particles", &varids[4]); ERR; err = ncmpi_get_vara_int_all(ncid, varids[4], start, count, &(v->num_orig_particles)); ERR; err = ncmpi_inq_varid(ncid, "neighbors", &varids[21]); ERR; err = ncmpi_inq_var(ncid, varids[21], 0, &type, &ndims, dimids, &natts); /* block bounds */ start[0] = start_block_ofst + b; start[1] = 0; count[0] = 1; count[1] = 3; err = ncmpi_inq_varid(ncid, "mins", &varids[11]); ERR; err = ncmpi_get_vara_float_all(ncid, varids[11], start, count, v->mins); ERR; err = ncmpi_inq_varid(ncid, "maxs", &varids[12]); ERR; err = ncmpi_get_vara_float_all(ncid, varids[12], start, count, v->maxs); ERR; /* save_verts */ start[0] = 0; count[0] = *tot_blocks; err = ncmpi_get_vara_longlong_all(ncid, varids[5], start, count, block_ofsts); ERR; v->save_verts = (float *)malloc(v->num_verts * 3 * sizeof(float)); start[0] = block_ofsts[start_block_ofst + b]; start[1] = 0; count[0] = v->num_verts; count[1] = 3; err = ncmpi_inq_varid(ncid, "save_verts", &varids[13]); ERR; err = ncmpi_get_vara_float_all(ncid, varids[13], start, count, v->save_verts); ERR; /* sites */ start[0] = 0; count[0] = *tot_blocks; err = ncmpi_get_vara_longlong_all(ncid, varids[9], start, count, block_ofsts); ERR; v->sites = (float *)malloc(v->num_orig_particles * 3 * sizeof(float)); start[0] = block_ofsts[start_block_ofst + b]; start[1] = 0; count[0] = v->num_orig_particles; count[1] = 3; err = ncmpi_inq_varid(ncid, "sites", &varids[14]); ERR; err = ncmpi_get_vara_float_all(ncid, varids[14], start, count, v->sites); ERR; /* complete cells */ start[0] = 0; count[0] = *tot_blocks; err = ncmpi_get_vara_longlong_all(ncid, varids[6], start, count, block_ofsts); ERR; v->complete_cells = (int *)malloc(v->num_complete_cells * sizeof(int)); start[0] = block_ofsts[start_block_ofst + b]; count[0] = v->num_complete_cells; err = ncmpi_inq_varid(ncid, "complete_cells", &varids[15]); ERR; err = ncmpi_get_vara_int_all(ncid, varids[15], start, count, v->complete_cells); ERR; /* areas, uses same block offsets as complete cells */ v->areas = (float *)malloc(v->num_complete_cells * sizeof(float)); start[0] = block_ofsts[start_block_ofst + b]; count[0] = v->num_complete_cells; err = ncmpi_inq_varid(ncid, "areas", &varids[16]); ERR; err = ncmpi_get_vara_float_all(ncid, varids[16], start, count, v->areas); ERR; /* volumes, uses same block offsets as complete cells */ v->vols = (float *)malloc(v->num_complete_cells * sizeof(float)); start[0] = block_ofsts[start_block_ofst + b]; count[0] = v->num_complete_cells; err = ncmpi_inq_varid(ncid, "vols", &varids[17]); ERR; err = ncmpi_get_vara_float_all(ncid, varids[17], start, count, v->vols); ERR; /* num_cell_faces, uses same block offsets as complete cells */ v->num_cell_faces = (int *)malloc(v->num_complete_cells * sizeof(int)); start[0] = block_ofsts[start_block_ofst + b]; count[0] = v->num_complete_cells; err = ncmpi_inq_varid(ncid, "num_cell_faces", &varids[18]); ERR; err = ncmpi_get_vara_int_all(ncid, varids[18], start, count, v->num_cell_faces); ERR; /* num_face_verts */ start[0] = 0; count[0] = *tot_blocks; err = ncmpi_get_vara_longlong_all(ncid, varids[7], start, count, block_ofsts); ERR; v->num_face_verts = (int *)malloc(v->tot_num_cell_faces * sizeof(int)); start[0] = block_ofsts[start_block_ofst + b]; count[0] = v->tot_num_cell_faces; err = ncmpi_inq_varid(ncid, "num_face_verts", &varids[19]); ERR; err = ncmpi_get_vara_int_all(ncid, varids[19], start, count, v->num_face_verts); ERR; /* face_verts */ start[0] = 0; count[0] = *tot_blocks; err = ncmpi_get_vara_longlong_all(ncid, varids[8], start, count, block_ofsts); ERR; v->face_verts = (int *)malloc(v->tot_num_face_verts * sizeof(int)); start[0] = block_ofsts[start_block_ofst + b]; count[0] = v->tot_num_face_verts; err = ncmpi_inq_varid(ncid, "face_verts", &varids[20]); ERR; err = ncmpi_get_vara_int_all(ncid, varids[20], start, count, v->face_verts); ERR; /* neighbors */ MPI_Offset n; /* temporary 64-bit version of number of neighbors */ err = ncmpi_inq_varid(ncid, "neighbors", &varids[21]); ERR; err = ncmpi_inq_var(ncid, varids[2], 0, &type, &ndims, dims, &natts); ERR; err = ncmpi_inq_dimlen(ncid, dims[0], &n); ERR; num_neighbors[b] = n; neighbors[b] = (int *)malloc(num_neighbors[b] * sizeof(int)); start[0] = start_block_ofst + b; count[0] = num_neighbors[b]; err = ncmpi_get_vara_int_all(ncid, varids[21], start, count, neighbors[b]); ERR; /* gids */ start[0] = start_block_ofst + b; count[0] = 1; err = ncmpi_inq_varid(ncid, "g_block_ids", &varids[22]); ERR; err = ncmpi_get_vara_int_all(ncid, varids[22], start, count, &gids[b]); ERR; (*vblocks)[b] = v; } /* cleanup */ err = ncmpi_close(ncid); ERR; free(block_ofsts); #endif }
/*----< main() >--------------------------------------------------------------*/ int main(int argc, char **argv) { int i, j, c, err, rank, nprocs, verbose, quiet; int ncid1, ndims1, nvars1, natts1, unlimdimid1, *dimids1; int ncid2, ndims2, nvars2, natts2, unlimdimid2, *dimids2; char *name1, *name2; MPI_Offset *shape=NULL, varsize, *start=NULL; MPI_Offset attlen1, dimlen1, attlen2, dimlen2; nc_type type1, type2; MPI_Comm comm=MPI_COMM_WORLD; int nvars, check_header, check_variable_list, check_entire_file; long long numVarDIFF=0, numHeadDIFF=0, varDIFF, numDIFF; struct vspec var_list; extern char *optarg; extern int optind; MPI_Info info; MPI_Init(&argc, &argv); MPI_Comm_size(comm, &nprocs); MPI_Comm_rank(comm, &rank); progname = argv[0]; verbose = 0; quiet = 0; check_header = 0; check_variable_list = 0; check_entire_file = 0; var_list.names = NULL; var_list.nvars = 0; while ((c = getopt(argc, argv, "bhqv:")) != -1) switch(c) { case 'h': /* compare header only */ check_header = 1; break; case 'v': /* variable names */ /* make list of names of variables specified */ get_var_names(optarg, &var_list); check_variable_list = 1; break; case 'b': verbose = 1; break; case 'q': quiet = 1; break; case '?': usage(rank, argv[0]); break; } /* quiet overwrites verbose */ if (quiet) verbose = 0; if (argc - optind != 2) usage(rank, argv[0]); if (check_header == 0 && check_variable_list == 0) { check_entire_file = 1; check_header = 1; } name1 = (char*) malloc(NC_MAX_NAME); if (!name1) OOM_ERROR name2 = (char*) malloc(NC_MAX_NAME); if (!name2) OOM_ERROR /* Nov. 18, 2014 -- disable subfiling as it does not correctly handle the * cases when nprocs < num_subfiles */ MPI_Info_create (&info); MPI_Info_set (info, "pnetcdf_subfiling", "disable"); /* open files */ err = ncmpi_open(comm, argv[optind], NC_NOWRITE, info, &ncid1); HANDLE_ERROR err = ncmpi_open(comm, argv[optind+1], NC_NOWRITE, info, &ncid2); HANDLE_ERROR MPI_Info_free(&info); /* check header */ if (check_header && rank == 0) { /* only root checks header */ int attnump; err = ncmpi_inq(ncid1, &ndims1, &nvars1, &natts1, &unlimdimid1); HANDLE_ERROR err = ncmpi_inq(ncid2, &ndims2, &nvars2, &natts2, &unlimdimid2); HANDLE_ERROR if (ndims1 != ndims2) { /* check number of dimensions if equal */ if (!quiet) printf("DIFF: number of dimensions (%d) != (%d)\n",ndims1, ndims2); numHeadDIFF++; } else if (verbose) printf("SAME: number of dimensions (%d)\n",ndims1); if (nvars1 != nvars2) { /* check number of variables if equal */ if (!quiet) printf("DIFF: number of variables (%d) != (%d)\n",nvars1, nvars2); numHeadDIFF++; } else if (verbose) printf("SAME: number of variables (%d)\n",nvars1); if (natts1 != natts2) { /* check number of global attributes if equal */ if (!quiet) printf("DIFF: number of global attributes (%d) != (%d)\n",natts1, natts2); numHeadDIFF++; } else if (verbose) printf("SAME: number of global attributes (%d)\n",natts1); /* Compare global attributes, assume CHAR attributes. */ for (i=0; i<natts1; i++) { /* check what's in file1 also in file2 */ err = ncmpi_inq_attname(ncid1, NC_GLOBAL, i, name1); HANDLE_ERROR /* find the attr with the same name from ncid2 */ err = ncmpi_inq_attid(ncid2, NC_GLOBAL, name1, &attnump); if (err == NC_ENOTATT) { if (!quiet) printf("DIFF: global attribute \"%s\" not found in file %s\n", name1,argv[optind+1]); numHeadDIFF++; continue; } err = ncmpi_inq_att(ncid1, NC_GLOBAL, name1, &type1, &attlen1); HANDLE_ERROR err = ncmpi_inq_att(ncid2, NC_GLOBAL, name1, &type2, &attlen2); HANDLE_ERROR if (type1 != type2) { if (!quiet) printf("DIFF: global attribute \"%s\" data type (%s) != (%s)\n", name1,get_type(type1),get_type(type2)); numHeadDIFF++; continue; } else if (verbose) { printf("Global attribute \"%s\":\n",name1); printf("\tSAME: data type (%s)\n",get_type(type1)); } if (attlen1 != attlen2) { if (!quiet) printf("DIFF: global attribute \"%s\" length (%lld) != (%lld)\n", name1,attlen1,attlen2); numHeadDIFF++; continue; } else if (verbose) printf("\tSAME: length (%lld)\n",attlen1); switch (type1) { case NC_CHAR: CHECK_GLOBAL_ATT_DIFF(char, ncmpi_get_att_text, NC_CHAR) case NC_SHORT: CHECK_GLOBAL_ATT_DIFF(short, ncmpi_get_att_short, NC_SHORT) case NC_INT: CHECK_GLOBAL_ATT_DIFF(int, ncmpi_get_att_int, NC_INT) case NC_FLOAT: CHECK_GLOBAL_ATT_DIFF(float, ncmpi_get_att_float, NC_FLOAT) case NC_DOUBLE: CHECK_GLOBAL_ATT_DIFF(double, ncmpi_get_att_double, NC_DOUBLE) case NC_UBYTE: CHECK_GLOBAL_ATT_DIFF(ubyte, ncmpi_get_att_uchar, NC_UBYTE) case NC_USHORT: CHECK_GLOBAL_ATT_DIFF(ushort, ncmpi_get_att_ushort, NC_USHORT) case NC_UINT: CHECK_GLOBAL_ATT_DIFF(uint, ncmpi_get_att_uint, NC_UINT) case NC_INT64: CHECK_GLOBAL_ATT_DIFF(int64, ncmpi_get_att_longlong, NC_INT64) case NC_UINT64: CHECK_GLOBAL_ATT_DIFF(uint64, ncmpi_get_att_ulonglong, NC_UINT64) default: ; /* TODO: handle unexpected types */ } } for (i=0; i<natts2; i++) { /* check attributes in file2 but not in file1 */ err = ncmpi_inq_attname(ncid2, NC_GLOBAL, i, name2); HANDLE_ERROR /* find the attr with the same name from ncid1 */ if (ncmpi_inq_attid(ncid1, NC_GLOBAL, name2, &attnump) == NC_ENOTATT) { numHeadDIFF++; if (!quiet) printf("DIFF: global attribute \"%s\" not found in file %s\n", name1,argv[optind]); } } /* Compare dimension */ if (ndims1 && verbose) printf("Dimension:\n"); for (i=0; i<ndims1; i++) { /* check dimensions in file1 also in file2 */ int dimid; err = ncmpi_inq_dim(ncid1, i, name1, &dimlen1); HANDLE_ERROR /* find the dim with the same name from ncid2 */ err = ncmpi_inq_dimid(ncid2, name1, &dimid); if (err == NC_EBADDIM) { if (!quiet) printf("DIFF: dimension \"%s\" not found in file %s\n", name1,argv[optind+1]); numHeadDIFF++; continue; } err = ncmpi_inq_dimlen(ncid2, dimid, &dimlen2); HANDLE_ERROR if (dimlen1 != dimlen2) { /* cast to quiet warning on 32 bit platforms */ if (!quiet) printf("DIFF: dimension \"%s\" length (%lld) != (%lld)\n", name1,(long long int)dimlen1,(long long int)dimlen2); numHeadDIFF++; } else if (verbose) printf("\tSAME: dimension \"%s\" length (%lld)\n", name1,(long long int)dimlen1); } for (i=0; i<ndims2; i++) { /* check dimensions in file2 but not in file1 */ int dimid; err = ncmpi_inq_dim(ncid2, i, name2, &dimlen2); HANDLE_ERROR /* find the dim with the same name from ncid1 */ if (ncmpi_inq_dimid(ncid2, name1, &dimid) == NC_EBADDIM) { if (!quiet) printf("DIFF: dimension \"%s\" not found in file %s\n", name1,argv[optind]); numHeadDIFF++; } } /* Compare variables' metadata */ for (i=0; i<nvars1; i++) { int varid; err = ncmpi_inq_varndims(ncid1, i, &ndims1); HANDLE_ERROR dimids1 = (int*) malloc((size_t)ndims1 * SIZEOF_INT); if (!dimids1) OOM_ERROR err = ncmpi_inq_var(ncid1, i, name1, &type1, &ndims1, dimids1, &natts1); HANDLE_ERROR /* find the variable with the same name from ncid2 */ err = ncmpi_inq_varid(ncid2, name1, &varid); if (err == NC_ENOTVAR) { if (!quiet) printf("DIFF: variable \"%s\" not found in file %s\n", name1,argv[optind+1]); numHeadDIFF++; numVarDIFF++; continue; } err = ncmpi_inq_varndims(ncid2, varid, &ndims2); HANDLE_ERROR dimids2 = (int*) malloc((size_t)ndims2 * SIZEOF_INT); if (!dimids2) OOM_ERROR err = ncmpi_inq_var(ncid2, varid, name2, &type2, &ndims2, dimids2, &natts2); HANDLE_ERROR if (type1 != type2) { if (!quiet) printf("DIFF: variable \"%s\" data type (%s) != (%s)\n", name1,get_type(type1),get_type(type2)); numHeadDIFF++; } else if (verbose) { printf("Variable \"%s\":\n",name1); printf("\tSAME: data type (%s)\n",get_type(type1)); } if (ndims1 != ndims2) { if (!quiet) printf("DIFF: variable \"%s\" number of dimensions (%d) != (%d)\n", name1,ndims1,ndims2); numHeadDIFF++; } else { if (verbose) printf("\tSAME: number of dimensions (%d)\n",ndims1); for (j=0; j<ndims1; j++) { /* check variable's dimensionality */ char dimname1[NC_MAX_NAME], dimname2[NC_MAX_NAME]; /* get dim name for each dim ID */ err = ncmpi_inq_dim(ncid1, dimids1[j], dimname1, &dimlen1); HANDLE_ERROR err = ncmpi_inq_dim(ncid1, dimids2[j], dimname2, &dimlen2); HANDLE_ERROR if (verbose) printf("\tdimension %d:\n",j); if (strcmp(dimname1, dimname2) != 0) { if (!quiet) printf("DIFF: variable \"%s\" of type \"%s\" dimension %d's name (%s) != (%s)\n", name1,get_type(type1),j,dimname1,dimname2); numHeadDIFF++; } else if (verbose) printf("\t\tSAME: name (%s)\n",dimname1); if (dimlen1 != dimlen2) { if (!quiet) printf("DIFF: variable \"%s\" of type \"%s\" dimension %d's length (%lld) != (%lld)\n", name1,get_type(type1),j,(long long int)dimlen1,(long long int)dimlen2); numHeadDIFF++; } else if (verbose) printf("\t\tSAME: length (%lld)\n",(long long int)dimlen1); } } if (natts1 != natts2) { if (!quiet) printf("DIFF: variable \"%s\" number of attributes (%d) != (%d)\n", name1,natts1,natts2); numHeadDIFF++; } else if (verbose) printf("\tSAME: number of attributes (%d)\n",natts1); /* var attributes, assume CHAR attributes */ for (j=0; j<natts1; j++) { char attrname[NC_MAX_NAME]; err = ncmpi_inq_attname(ncid1, i, j, attrname); HANDLE_ERROR err = ncmpi_inq_att(ncid1, i, attrname, &type1, &attlen1); HANDLE_ERROR /* find the variable attr with the same name from ncid2 */ err = ncmpi_inq_att(ncid2, varid, attrname, &type2, &attlen2); if (err == NC_ENOTATT) { if (!quiet) printf("DIFF: variable \"%s\" attribute \"%s\" not found in file %s\n", name1,attrname,argv[optind+1]); numHeadDIFF++; continue; } if (verbose) printf("\tattribute \"%s\":\n",attrname); if (type1 != type2) { if (!quiet) printf("DIFF: variable \"%s\" attribute \"%s\" data type (%s) != (%s)\n", name1,attrname,get_type(type1),get_type(type2)); numHeadDIFF++; continue; /* skip this attribute */ } else if (verbose) printf("\t\tSAME: data type (%s)\n",get_type(type1)); if (attlen1 != attlen2) { if (!quiet) printf("DIFF: variable \"%s\" attribute \"%s\" length (%lld) != (%lld)\n", name1,attrname,(long long int)attlen1,(long long int)attlen2); numHeadDIFF++; continue; /* skip this attribute */ } else if (verbose) printf("\t\tSAME: length (%lld)\n",(long long int)attlen1); switch (type1) { case NC_CHAR: CHECK_VAR_ATT_DIFF(char, ncmpi_get_att_text, NC_CHAR) case NC_SHORT: CHECK_VAR_ATT_DIFF(short, ncmpi_get_att_short, NC_SHORT) case NC_INT: CHECK_VAR_ATT_DIFF(int, ncmpi_get_att_int, NC_INT) case NC_FLOAT: CHECK_VAR_ATT_DIFF(float, ncmpi_get_att_float, NC_FLOAT) case NC_DOUBLE: CHECK_VAR_ATT_DIFF(double, ncmpi_get_att_double, NC_DOUBLE) case NC_UBYTE: CHECK_VAR_ATT_DIFF(ubyte, ncmpi_get_att_uchar, NC_UBYTE) case NC_USHORT: CHECK_VAR_ATT_DIFF(ushort, ncmpi_get_att_ushort, NC_USHORT) case NC_UINT: CHECK_VAR_ATT_DIFF(uint, ncmpi_get_att_uint, NC_UINT) case NC_INT64: CHECK_VAR_ATT_DIFF(int64, ncmpi_get_att_longlong, NC_INT64) case NC_UINT64: CHECK_VAR_ATT_DIFF(uint64, ncmpi_get_att_ulonglong, NC_UINT64) default: ; /* TODO: handle unexpected types */ } } for (j=0; j<natts2; j++) { char attrname[NC_MAX_NAME]; err = ncmpi_inq_attname(ncid2, varid, j, attrname); HANDLE_ERROR /* find the variable attr with the same name from ncid1 */ err = ncmpi_inq_att(ncid1, i, attrname, &type1, &attlen1); if (err == NC_ENOTATT) { if (!quiet) printf("DIFF: variable \"%s\" attribute \"%s\" not found in file %s\n", name1,attrname,argv[optind]); numHeadDIFF++; } } free(dimids1); free(dimids2); } for (i=0; i<nvars2; i++) { /* check variables in file2 but not in file1 */ int varid; err = ncmpi_inq_varname(ncid2, i, name2); HANDLE_ERROR /* find the variable with the same name from ncid1 */ err = ncmpi_inq_varid(ncid1, name2, &varid); if (err == NC_ENOTVAR) { if (!quiet) printf("DIFF: variable \"%s\" not found in file %s\n", name2,argv[optind]); numHeadDIFF++; numVarDIFF++; } } }