コード例 #1
0
ファイル: test_read64.c プロジェクト: live-clones/pnetcdf
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;
  MPI_Offset attlen, dimlen, varsize;
  MPI_Offset *shape, *start;
  void *valuep;
  int *dimids, *varids, **vardims, *varndims, *varnatts;
  params opts;

  int rank;
  int nprocs;
  int NC_mode;
  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 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_inq_version(ncid1, &NC_mode);

  status = ncmpi_create(comm, opts.outfname, NC_CLOBBER|NC_mode, 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, (char*)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, (short*)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, (int*)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, (float*)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, (double*)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 */
  dimids = (int*) malloc(ndims * sizeof(int));

  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);
  }
  free(dimids);

  vartypes = (nc_type*) malloc(nvars * sizeof(nc_type));
  varids = (int*) malloc(nvars * sizeof(int));
  varndims = (int*) malloc(nvars * sizeof(int));
  varnatts = (int*) malloc(nvars * sizeof(int));
  vardims = (int**) malloc(nvars * sizeof(int*));

  /* Inquire variables */

  for (i = 0; i < nvars; i++) {
    status = ncmpi_inq_varndims(ncid1, i, varndims+i);
    if (status != NC_NOERR) handle_error(status);
    vardims[i] = (int*) malloc(varndims[i] * sizeof(int));

    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, i, j, name);
      if (status != NC_NOERR) handle_error(status);
      status = ncmpi_inq_att (ncid1, 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, i, name, (char*)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, i, name, (short*)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, i, name, (int*)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, i, name, (float*)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, i, name, (double*)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
   * (ONLY DEAL WITH: NC_INT, NC_FLOAT, NC_DOUBLE for now)
   * 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: collective
   */

  for (i = 0; i < nvars; i++) {
    shape = (MPI_Offset*) calloc(varndims[i] * 2, sizeof(MPI_Offset));
    start = shape + varndims[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_all(ncid1, i, start, shape, (short *)valuep);
        if (status != NC_NOERR) handle_error(status);
        status = ncmpi_put_vara_short_all(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_all(ncid1, i, start, shape, (int *)valuep);
        if (status != NC_NOERR) handle_error(status);
        status = ncmpi_put_vara_int_all(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_all(ncid1, i, start, shape, (float *)valuep);
        if (status != NC_NOERR) handle_error(status);
        status = ncmpi_put_vara_float_all(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_all(ncid1, i, start, shape, (double *)valuep);
        if (status != NC_NOERR) handle_error(status);
        status = ncmpi_put_vara_double_all(ncid2, varids[i],
                                     start, shape, (double *)valuep);
        if (status != NC_NOERR) handle_error(status);
        free(valuep);
        break;
      default:
	;
	/* handle unexpected types */
    }
    free(vardims[i]);
    free(shape);
  }

  /**
   * 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);

  free(vartypes);
  free(varids);
  free(varndims);
  free(varnatts);
  free(vardims);

  /*******************  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;
}
コード例 #2
0
ファイル: pres_temp_4D_rd.c プロジェクト: live-clones/pnetcdf
int
main(int argc, char **argv)
{
   int rank, nprocs, ncid, pres_varid, temp_varid;
   int lat_varid, lon_varid;

   /* The start and count arrays will tell the netCDF library where to
      read our data. */
   MPI_Offset start[NDIMS], count[NDIMS];

   /* Program variables to hold the data we will read. We will only
      need enough space to hold one timestep of data; one record. */
   float **pres_in=NULL; /* [NLVL/nprocs][NLAT][NLON] */
   float **temp_in=NULL; /* [NLVL/nprocs][NLAT][NLON] */

   /* These program variables hold the latitudes and longitudes. */
   float lats[NLAT], lons[NLON];

   /* Loop indexes. */
   int lvl, lat, lon, rec, i = 0;

   /* Error handling. */
   int err, nerrs=0;

   char *filename = FILE_NAME;

   MPI_Init(&argc, &argv);
   MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
   MPI_Comm_rank(MPI_COMM_WORLD, &rank);

   if (argc > 2) {
       if (!rank) printf("Usage: %s [filename]\n",argv[0]);
       MPI_Finalize();
       return 1;
   }
   if (argc == 2) filename = argv[1];

   if (rank == 0) {
       char *cmd_str = (char*)malloc(strlen(argv[0]) + 256);
       sprintf(cmd_str, "*** TESTING C   %s for reading file", basename(argv[0]));
       printf("%-66s ------ ", cmd_str);
       free(cmd_str);
   }

   /* Open the file. */
   err = ncmpi_open(MPI_COMM_WORLD, filename, NC_NOWRITE, MPI_INFO_NULL, &ncid);
   CHECK_ERR

   /* Get the varids of the latitude and longitude coordinate
    * variables. */
   err = ncmpi_inq_varid(ncid, LAT_NAME, &lat_varid);
   CHECK_ERR
   err = ncmpi_inq_varid(ncid, LON_NAME, &lon_varid);
   CHECK_ERR

   /* Read the coordinate variable data. */
   memset(lats, 0, sizeof(float)*NLAT);
   memset(lons, 0, sizeof(float)*NLON);
   err = ncmpi_get_var_float_all(ncid, lat_varid, &lats[0]);
   CHECK_ERR
   err = ncmpi_get_var_float_all(ncid, lon_varid, &lons[0]);
   CHECK_ERR

   /* Check the coordinate variable data. */
   for (lat = 0; lat < NLAT; lat++)
      if (lats[lat] != START_LAT + 5.*lat) {
          printf("\nError at line %d in %s: expect %e but got %e\n", __LINE__,__FILE__, START_LAT+5.*lat,lats[lat]);
	  nerrs++;
          goto fn_exit;
      }
   for (lon = 0; lon < NLON; lon++)
      if (lons[lon] != START_LON + 5.*lon) {
          printf("\nError at line %d in %s: expect %e but got %e\n", __LINE__,__FILE__, START_LON+5.*lon,lons[lon]);
	  nerrs++;
          goto fn_exit;
      }

   /* Get the varids of the pressure and temperature netCDF
    * variables. */
   err = ncmpi_inq_varid(ncid, PRES_NAME, &pres_varid);
   CHECK_ERR
   err = ncmpi_inq_varid(ncid, TEMP_NAME, &temp_varid);
   CHECK_ERR

   /* Read the data. Since we know the contents of the file we know
    * that the data arrays in this program are the correct size to
    * hold one timestep. */
   count[0] = 1;
   count[2] = NLAT;
   count[3] = NLON;
   start[2] = 0;
   start[3] = 0;

   /* divide NLVL dimension among processes */
   count[1] = NLVL / nprocs;
   start[1] = count[1] * rank;
   if (rank < NLVL % nprocs) {
       start[1] += rank;
       count[1]++;
   }
   else {
       start[1] += NLVL % nprocs;
   }
   if (count[1] == 0) start[1] = 0;

   /* allocate read buffers */
   pres_in = (float**) malloc(count[1]*2 * sizeof(float*));
   temp_in = pres_in + count[1];
   if (count[1] > 0) {
       pres_in[0] = (float*) malloc(count[1]*2 * NLAT*NLON * sizeof(float));
       temp_in[0] = pres_in[0] + count[1] * NLAT*NLON;
       for (i=1; i<count[1]; i++) {
           pres_in[i] = pres_in[i-1] + NLAT*NLON;
           temp_in[i] = temp_in[i-1] + NLAT*NLON;
       }
   }

   /* Read and check one record at a time. */
   for (rec = 0; rec < NREC; rec++)
   {
      start[0] = rec;
      err = ncmpi_get_vara_float_all(ncid, pres_varid, start, count, &pres_in[0][0]);
      CHECK_ERR
      err = ncmpi_get_vara_float_all(ncid, temp_varid, start, count, &temp_in[0][0]);
      CHECK_ERR

      /* Check the data. */
      i = (int)start[1] * NLAT * NLON;
      for (lvl=0; lvl<count[1]; lvl++)
	 for (lat = 0; lat < NLAT; lat++)
	    for (lon = 0; lon < NLON; lon++) {
	       if (pres_in[lvl][lat*NLON+lon] != SAMPLE_PRESSURE + i) {
                  printf("\nError at line %d in %s: expect %e but got %e\n", __LINE__,__FILE__, SAMPLE_PRESSURE+i,pres_in[lvl][lat*NLON+lon]);
		  nerrs++;
		  goto fn_exit;
               }
	       if (temp_in[lvl][lat*NLON+lon] != SAMPLE_TEMP + i) {
                  printf("\nError at line %d in %s: expect %e but got %e\n", __LINE__,__FILE__, SAMPLE_TEMP+i,temp_in[lvl][lat*NLON+lon]);
		  nerrs++;
		  goto fn_exit;
               }
	       i++;
	    }

   } /* next record */

fn_exit:
    /* Close the file. */
    err = ncmpi_close(ncid);
    CHECK_ERR

    if (pres_in != NULL) {
       if (pres_in[0] != NULL) free(pres_in[0]);
       free(pres_in);
    }

    /* check if there is any malloc residue */
    MPI_Offset malloc_size, sum_size;
    err = ncmpi_inq_malloc_size(&malloc_size);
    if (err == NC_NOERR) {
        MPI_Reduce(&malloc_size, &sum_size, 1, MPI_OFFSET, MPI_SUM, 0, MPI_COMM_WORLD);
        if (rank == 0 && sum_size > 0)
            printf("heap memory allocated by PnetCDF internally has %lld bytes yet to be freed\n",
                   sum_size);
    }

    MPI_Allreduce(MPI_IN_PLACE, &nerrs, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
    if (rank == 0) {
        if (nerrs) printf(FAIL_STR,nerrs);
        else       printf(PASS_STR);
    }

   MPI_Finalize();
   return (nerrs > 0);
}
コード例 #3
0
ファイル: Traj_NcEnsemble.cpp プロジェクト: hainm/cpptraj
// Traj_NcEnsemble::readArray()
int Traj_NcEnsemble::readArray(int set, FrameArray& f_ensemble) {
# ifdef HAS_PNETCDF
  MPI_Offset pstart_[4];
  MPI_Offset pcount_[4];
# define start_ pstart_
# define count_ pcount_
# endif
  start_[0] = set; // Frame
  start_[2] = 0;   // Atoms
  start_[3] = 0;   // XYZ
  count_[0] = 1;        // Frame
  count_[1] = 1;        // Ensemble
  count_[3] = 3;        // XYZ
  //rprintf("DEBUG: Reading frame %i\n", set+1);
  for (int member = ensembleStart_; member != ensembleEnd_; member++) {
#   ifdef MPI
    Frame& frm = f_ensemble[0];
#   else
    Frame& frm = f_ensemble[member];
#   endif
    start_[1] = member;   // Ensemble
    count_[2] = Ncatom(); // Atoms
    // Read Coords
#   ifdef HAS_PNETCDF
    if (checkPNCerr(ncmpi_get_vara_float_all(ncid_, coordVID_, start_, count_, Coord_)))
#   else
    if (NC::CheckErr(nc_get_vara_float(ncid_, coordVID_, start_, count_, Coord_)))
#   endif
    {
      rprinterr("Error: Getting coordinates for frame %i\n", set+1);
      return 1;
    }
    FloatToDouble(frm.xAddress(), Coord_);
    //mprintf("Frm=%8i Rep=%8i ", set+1, member+1); // DEBUG
    //frm.printAtomCoord(0); // DEBUG
    // Read Velocities
    if (velocityVID_ != -1) {
#     ifdef HAS_PNETCDF
      if (checkPNCerr(ncmpi_get_vara_float_all(ncid_, velocityVID_, start_, count_, Coord_)))
#     else
      if (NC::CheckErr(nc_get_vara_float(ncid_, velocityVID_, start_, count_, Coord_)))
#     endif
      {
        rprinterr("Error: Getting velocities for frame %i\n", set+1);
        return 1;
      }
      FloatToDouble(frm.vAddress(), Coord_);
    }
    // Read Box
    if (cellLengthVID_ != -1) {
      count_[2] = 3;
#     ifdef HAS_PNETCDF
      if (checkPNCerr(ncmpi_get_vara_double_all(ncid_, cellLengthVID_, start_, count_, frm.bAddress())))
#     else
      if (NC::CheckErr(nc_get_vara_double(ncid_, cellLengthVID_, start_, count_, frm.bAddress())))
#     endif
      {
        rprinterr("Error: Getting cell lengths for frame %i.\n", set+1);
        return 1;
      }
#     ifdef HAS_PNETCDF
      if (checkPNCerr(ncmpi_get_vara_double_all(ncid_, cellAngleVID_, start_, count_, frm.bAddress()+3)))
#     else
      if (NC::CheckErr(nc_get_vara_double(ncid_, cellAngleVID_, start_, count_, frm.bAddress()+3)))
#     endif
      {
        rprinterr("Error: Getting cell angles for frame %i.\n", set+1);
        return 1;
      }
    }
    // Read Temperature
    if (TempVID_!=-1) {
#     ifdef HAS_PNETCDF
      if (checkPNCerr(ncmpi_get_vara_double_all(ncid_, TempVID_, start_, count_, frm.tAddress())))
#     else
      if (NC::CheckErr(nc_get_vara_double(ncid_, TempVID_, start_, count_, frm.tAddress())))
#     endif
      {
        rprinterr("Error: Getting replica temperature for frame %i.\n", set+1);
        return 1;
      }
      //fprintf(stderr,"DEBUG: Replica Temperature %lf\n",F->T);
    }
    // Read indices
    if (indicesVID_!=-1) {
      count_[2] = remd_dimension_;
#     ifdef HAS_PNETCDF
      if (checkPNCerr(ncmpi_get_vara_int_all(ncid_, indicesVID_, start_, count_, frm.iAddress())))
#     else
      if (NC::CheckErr(nc_get_vara_int(ncid_, indicesVID_, start_, count_, frm.iAddress())))
#     endif
      {
        rprinterr("Error: Getting replica indices for frame %i.\n", set+1);
        return 1;
      }
      // DEBUG
      //char buffer[128];
      //char* ptr = buffer;
      //ptr += sprintf(buffer,"DEBUG:\tReplica indices:");
      //for (int dim=0; dim < remd_dimension_; dim++) ptr += sprintf(ptr, " %i", frm.RemdIndices()[dim]);
      //sprintf(ptr,"\n");
      //rprintf("%s", buffer);
    }
  }
# ifdef HAS_PNETCDF
  // DEBUG
# undef start_
# undef count_
# endif
  return 0;
}
コード例 #4
0
ファイル: io.c プロジェクト: gcasey/cosmotools
/*
  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
}