1 /*********************************************************************
2  *
3  *  Copyright (C) 2012, Northwestern University and Argonne National Laboratory
4  *  See COPYRIGHT notice in top-level directory.
5  *
6  *********************************************************************/
7 /* $Id: pnetcdf-read-flexible.c 2369 2016-03-22 21:56:02Z wkliao $ */
8 
9 /* simple demonstration of pnetcdf
10  * knowing nothing about the file, read in the variables.
11  *
12  * This example demonstrates the flexible interface */
13 
14 #include <stdlib.h>
15 #include <mpi.h>
16 #include <pnetcdf.h>
17 #include <stdio.h>
18 
handle_error(int status,int lineno)19 static void handle_error(int status, int lineno)
20 {
21     fprintf(stderr, "Error at line %d: %s\n", lineno, ncmpi_strerror(status));
22     MPI_Abort(MPI_COMM_WORLD, 1);
23 }
24 
main(int argc,char ** argv)25 int main(int argc, char **argv) {
26 
27     int i, j, rank, nprocs, ret;
28     int ncfile, ndims, nvars, ngatts, unlimited;
29     int var_ndims, var_natts;;
30     MPI_Offset *dim_sizes, var_size;
31     MPI_Offset *start, *count;
32     char varname[NC_MAX_NAME+1];
33     int dimids[NC_MAX_VAR_DIMS];
34     nc_type type;
35     int *data=NULL;
36 
37     MPI_Init(&argc, &argv);
38 
39     MPI_Comm_rank(MPI_COMM_WORLD, &rank);
40     MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
41 
42     if (argc != 2) {
43         if (rank == 0) printf("Usage: %s filename\n", argv[0]);
44         MPI_Finalize();
45         exit(-1);
46     }
47 
48     ret = ncmpi_open(MPI_COMM_WORLD, argv[1], NC_NOWRITE, MPI_INFO_NULL,
49                      &ncfile);
50     if (ret != NC_NOERR) handle_error(ret, __LINE__);
51 
52     /* reader knows nothing about dataset, but we can interrogate with query
53      * routines: ncmpi_inq tells us how many of each kind of "thing"
54      * (dimension, variable, attribute) we will find in the file  */
55 
56     /* no communication needed after ncmpi_open: all processors have a cached
57      * view of the metadata once ncmpi_open returns */
58 
59     ret = ncmpi_inq(ncfile, &ndims, &nvars, &ngatts, &unlimited);
60     if (ret != NC_NOERR) handle_error(ret, __LINE__);
61 
62     /* we do not really need the name of the dimension or the variable for
63      * reading in this example.  we could, in a different example, take the
64      * name of a variable on the command line and read just that one */
65 
66     dim_sizes = (MPI_Offset*) calloc(ndims, sizeof(MPI_Offset));
67     /* netcdf dimension identifiers are allocated sequentially starting
68      * at zero; same for variable identifiers */
69     for(i=0; i<ndims; i++)  {
70         ret = ncmpi_inq_dimlen(ncfile, i, &(dim_sizes[i]) );
71         if (ret != NC_NOERR) handle_error(ret, __LINE__);
72     }
73 
74     for(i=0; i<nvars; i++) {
75         /* much less coordination in this case compared to rank 0 doing all
76          * the i/o: everyone already has the necessary information */
77         ret = ncmpi_inq_var(ncfile, i, varname, &type, &var_ndims, dimids,
78                 &var_natts);
79         if (ret != NC_NOERR) handle_error(ret, __LINE__);
80 
81         start = (MPI_Offset*) calloc(var_ndims, sizeof(MPI_Offset));
82         count = (MPI_Offset*) calloc(var_ndims, sizeof(MPI_Offset));
83 
84         /* we will simply decompose along one dimension.  Generally the
85          * application has some algorithm for domain decomposition.  Note
86          * that data decomposition can have an impact on i/o performance.
87          * Often it's best just to do what is natural for the application,
88          * but something to consider if performance is not what was
89          * expected/desired */
90 
91         start[0] = (dim_sizes[dimids[0]]/nprocs)*rank;
92         count[0] = (dim_sizes[dimids[0]]/nprocs);
93         var_size = count[0];
94 
95         for (j=1; j<var_ndims; j++) {
96             start[j] = 0;
97             count[j] = dim_sizes[dimids[j]];
98             var_size *= count[j];
99         }
100 
101         switch(type) {
102             case NC_INT:
103                 data = (int*) calloc(var_size, sizeof(int));
104                 ret = ncmpi_get_vara_all(ncfile, i, start, count, data,
105                         var_size, MPI_INT);
106                 if (ret != NC_NOERR) handle_error(ret, __LINE__);
107                 break;
108             default:
109                 /* we can do this for all the known netcdf types but this
110                  * example is already getting too long  */
111                 fprintf(stderr, "unsupported NetCDF type \n");
112         }
113 
114         free(start);
115         free(count);
116         if (data != NULL) free(data);
117     }
118 
119     ret = ncmpi_close(ncfile);
120     if (ret != NC_NOERR) handle_error(ret, __LINE__);
121     free(dim_sizes);
122 
123     MPI_Finalize();
124     return 0;
125 }
126 
127 /*
128  *vim: ts=8 sts=4 sw=4 noexpandtab */
129