1 /*********************************************************************
2  *
3  *  Copyright (C) 2014, Northwestern University and Argonne National Laboratory
4  *  See COPYRIGHT notice in top-level directory.
5  *
6  *********************************************************************/
7 /* $Id: global_attributes.c 2717 2016-12-18 01:20:47Z wkliao $ */
8 
9 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
10  * This example creates a new file and add 2 global attributes, one is of text
11  * type and the other 10 short integers. The file is closed and re-opened to
12  * read back the attributes.
13  *
14  *    To compile:
15  *        mpicc -O2 global_attributes.c -o global_attributes -lpnetcdf
16  *
17  * Example commands for MPI run and outputs from running ncmpidump on the
18  * netCDF file produced by this example program:
19  *
20  *    % mpiexec -n 4 ./global_attributes /pvfs2/wkliao/testfile.nc
21  *
22  *    % ncmpidump /pvfs2/wkliao/testfile.nc
23  *    netcdf testfile {
24  *    // file format: CDF-1
25  *
26  *    // global attributes:
27  *                    :history = "Sun May  4 13:11:47 2014\n",
28  *        "" ;
29  *                    :digits = 0s, 1s, 2s, 3s, 4s, 5s, 6s, 7s, 8s, 9s ;
30  *    }
31  *
32  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
33 
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h> /* strcpy(), strncpy(), strlen() */
37 #include <unistd.h> /* getopt() */
38 #include <time.h>   /* time() localtime(), asctime() */
39 #include <mpi.h>
40 #include <pnetcdf.h>
41 
42 #ifndef MPI_OFFSET
43 #define MPI_OFFSET MPI_LONG_LONG_INT
44 #endif
45 
46 #define ERR { \
47     if(err!=NC_NOERR) { \
48         printf("Error at line=%d: %s\n", __LINE__, ncmpi_strerror(err)); \
49         nerrs++; \
50         goto fn_exit; \
51     } \
52 }
53 
54 static void
usage(char * argv0)55 usage(char *argv0)
56 {
57     char *help =
58     "Usage: %s [-h] | [-q] [file_name]\n"
59     "       [-h] Print help\n"
60     "       [-q] Quiet mode (reports when fail)\n"
61     "       [filename] output netCDF file name\n";
62     fprintf(stderr, help, argv0);
63 }
64 
main(int argc,char ** argv)65 int main(int argc, char** argv)
66 {
67     extern int optind;
68     char filename[256];
69     char str_att[128], att_name[NC_MAX_NAME];
70     int i, rank, err, nerrs=0, verbose=1, ncid, cmode, omode, ngatts;
71     short short_att[10], digit[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
72     time_t ltime;
73 
74     MPI_Init(&argc, &argv);
75     MPI_Comm_rank(MPI_COMM_WORLD, &rank);
76 
77     /* get command-line arguments */
78     while ((i = getopt(argc, argv, "hq")) != EOF)
79         switch(i) {
80             case 'q': verbose = 0;
81                       break;
82             case 'h':
83             default:  if (rank==0) usage(argv[0]);
84                       MPI_Finalize();
85                       return 0;
86         }
87     argc -= optind;
88     argv += optind;
89     if (argc == 1) snprintf(filename, 256, "%s", argv[0]);
90     else           strcpy(filename, "testfile.nc");
91 
92     /* create a new file for writing ----------------------------------------*/
93     cmode = NC_CLOBBER;
94     err = ncmpi_create(MPI_COMM_WORLD, filename, cmode, MPI_INFO_NULL, &ncid);
95     ERR
96 
97     /* add a global attribute named "history": a time stamp at rank 0 */
98     ltime = time(NULL); /* get the current calendar time */
99     asctime_r(localtime(&ltime), str_att);
100 
101     /* make sure the time string are consistent among all processes */
102     MPI_Bcast(str_att, strlen(str_att), MPI_CHAR, 0, MPI_COMM_WORLD);
103 
104     err = ncmpi_put_att_text(ncid, NC_GLOBAL, "history", strlen(str_att),
105                              &str_att[0]);
106     ERR
107     if (rank == 0 && verbose)
108         printf("writing global attribute \"history\" of text %s\n",
109                str_att);
110 
111     /* add another global attribute named "digits": an array of short type */
112     err = ncmpi_put_att_short(ncid, NC_GLOBAL, "digits", NC_SHORT, 10,
113                              &digit[0]);
114     ERR
115     if (rank == 0 && verbose)
116         printf("writing global attribute \"digits\" of 10 short integers\n");
117 
118     /* close file */
119     err = ncmpi_close(ncid);
120     ERR
121 
122     /* open the newly created file for read only -----------------------------*/
123     omode = NC_NOWRITE;
124     err = ncmpi_open(MPI_COMM_WORLD, filename, omode, MPI_INFO_NULL, &ncid);
125     ERR
126 
127     /* find the number of global attributes */
128     err = ncmpi_inq_natts(ncid, &ngatts);
129     ERR
130 
131     err = 0;
132     if (ngatts != 2) {
133         printf("Error: expected number of global attributes is 2, but got %d\n",
134                ngatts);
135         err = -1;
136     }
137     MPI_Allreduce(MPI_IN_PLACE, &err, 1, MPI_INT, MPI_MIN, MPI_COMM_WORLD);
138     if (err < 0) { nerrs++; goto fn_exit; }
139 
140     /* find the name of first global attribute */
141     err = ncmpi_inq_attname(ncid, NC_GLOBAL, 0, att_name);
142     ERR
143 
144     err = 0;
145     if (strncmp(att_name, "history", strlen("history"))) {
146         printf("Error: expected attribute name \"history\", but got %s\n",
147                att_name);
148         err = -1;
149     }
150     MPI_Allreduce(MPI_IN_PLACE, &err, 1, MPI_INT, MPI_MIN, MPI_COMM_WORLD);
151     if (err < 0) { nerrs++; goto fn_exit; }
152 
153     /* read attribute value */
154     err = ncmpi_get_att_text(ncid, NC_GLOBAL, att_name, &str_att[0]);
155     ERR
156 
157     /* find the name of second global attribute */
158     err = ncmpi_inq_attname(ncid, NC_GLOBAL, 1, att_name);
159     ERR
160 
161     err = 0;
162     if (strncmp(att_name, "digits", strlen("digits"))) {
163         printf("Error: expected attribute name \"digits\", but got %s\n",
164                att_name);
165         err = -1;
166     }
167     MPI_Allreduce(MPI_IN_PLACE, &err, 1, MPI_INT, MPI_MIN, MPI_COMM_WORLD);
168     if (err < 0) { nerrs++; goto fn_exit; }
169 
170     /* read attribute value */
171     err = ncmpi_get_att_short(ncid, NC_GLOBAL, att_name, &short_att[0]);
172     ERR
173 
174     /* close file */
175     err = ncmpi_close(ncid);
176     ERR
177 
178     /* check if there is any PnetCDF internal malloc residue */
179     MPI_Offset malloc_size, sum_size;
180     err = ncmpi_inq_malloc_size(&malloc_size);
181     if (err == NC_NOERR) {
182         MPI_Reduce(&malloc_size, &sum_size, 1, MPI_OFFSET, MPI_SUM, 0, MPI_COMM_WORLD);
183         if (rank == 0 && sum_size > 0)
184             printf("heap memory allocated by PnetCDF internally has %lld bytes yet to be freed\n",
185                    sum_size);
186     }
187 
188 fn_exit:
189     MPI_Finalize();
190     return nerrs;
191 }
192 
193