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(<ime), 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