1 /* This is part of the netCDF package.
2    Copyright 2005 University Corporation for Atmospheric Research/Unidata
3    See COPYRIGHT file for conditions of use.
4 
5    Test fix of bug involving creation of a file with PnetCDF APIs,
6    then opening and modifying the file with netcdf.
7 
8    Author: Wei-keng Liao.
9 */
10 
11 #include <nc_tests.h>
12 #include "err_macros.h"
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <mpi.h>
17 #include <netcdf.h>
18 #include <netcdf_par.h>
19 #include <assert.h>
20 
21 #define NVARS 6
22 #define NX    5
23 #define FILENAME "tst_pnetcdf.nc"
24 
25 #define CHK_ERR(e) { \
26     if (e != NC_NOERR) { \
27         printf("Error at %s:%d : %s\n", __FILE__,__LINE__, nc_strerror(e)); \
28         goto fn_exit; \
29     } \
30 }
31 
32 #define EXP_ERR(e, exp) { \
33     if (e != exp) { \
34         printf("Error at %s:%d : expect "#exp" but got %d\n", __FILE__,__LINE__, e); \
35     } \
36 }
37 
38 
main(int argc,char * argv[])39 int main(int argc, char* argv[])
40 {
41     int i, j, rank, nprocs, ncid, cmode, varid[NVARS], dimid[2], *buf;
42     int st, nerrs=0;
43     char str[32];
44     size_t start[2], count[2];
45     MPI_Comm comm=MPI_COMM_SELF;
46     MPI_Info info=MPI_INFO_NULL;
47 
48     printf("\n*** Testing bug fix with changing PnetCDF variable offsets...");
49 
50     MPI_Init(&argc,&argv);
51     MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
52     MPI_Comm_rank(MPI_COMM_WORLD, &rank);
53 
54     if (nprocs > 1 && rank == 0)
55         printf("This test program is intended to run on ONE process\n");
56     if (rank > 0) goto fn_exit;
57 
58     /* first, use PnetCDF to create a file with default header/variable alignment */
59 #ifdef DISABLE_PNETCDF_ALIGNMENT
60     MPI_Info_create(&info);
61     MPI_Info_set(info, "nc_header_align_size", "1");
62     MPI_Info_set(info, "nc_var_align_size",    "1");
63 #endif
64 
65     cmode = NC_CLOBBER;
66     st = nc_create_par(FILENAME, cmode, comm, info, &ncid);
67 #ifdef USE_PNETCDF
68     CHK_ERR(st)
69 #else
70     EXP_ERR(st, NC_ENOTBUILT)
71     goto fn_exit;
72 #endif
73 
74     /* define dimension */
75     st = nc_def_dim(ncid, "Y", NC_UNLIMITED, &dimid[0]); CHK_ERR(st)
76     st = nc_def_dim(ncid, "X", NX,           &dimid[1]); CHK_ERR(st)
77 
78     /* Odd numbers are fixed variables, even numbers are record variables */
79     for (i=0; i<NVARS; i++) {
80         if (i%2) {
81             sprintf(str,"fixed_var_%d",i);
82             st = nc_def_var(ncid, str, NC_INT, 1, dimid+1, &varid[i]); CHK_ERR(st)
83         }
84         else {
85             sprintf(str,"record_var_%d",i);
86             st = nc_def_var(ncid, str, NC_INT, 2, dimid, &varid[i]); CHK_ERR(st)
87         }
88     }
89     st = nc_enddef(ncid); CHK_ERR(st)
90 
91     /* Note NC_INDEPENDENT is the default */
92     st = nc_var_par_access(ncid, NC_GLOBAL, NC_INDEPENDENT); CHK_ERR(st)
93 
94     /* write all variables */
95     buf = (int*) malloc(NX * sizeof(int));
96     for (i=0; i<NVARS; i++) {
97         for (j=0; j<NX; j++) buf[j] = i*10 + j;
98         if (i%2) {
99             start[0] = 0; count[0] = NX;
100             st = nc_put_vara_int(ncid, varid[i], start, count, buf); CHK_ERR(st)
101         }
102         else {
103             start[0] = 0; start[1] = 0;
104             count[0] = 1; count[1] = NX;
105             st = nc_put_vara_int(ncid, varid[i], start, count, buf); CHK_ERR(st)
106         }
107     }
108     st = nc_close(ncid); CHK_ERR(st)
109     if (info != MPI_INFO_NULL) MPI_Info_free(&info);
110 
111     /* re-open the file with netCDF (parallel) and enter define mode */
112     st = nc_open_par(FILENAME, NC_WRITE, comm, info, &ncid); CHK_ERR(st)
113 
114     st = nc_redef(ncid); CHK_ERR(st)
115 
116     /* add attributes to make header grow */
117     for (i=0; i<NVARS; i++) {
118         sprintf(str, "annotation_for_var_%d",i);
119         st = nc_put_att_text(ncid, varid[i], "text_attr", strlen(str), str); CHK_ERR(st)
120     }
121     st = nc_enddef(ncid); CHK_ERR(st)
122 
123     /* read variables and check their contents */
124     for (i=0; i<NVARS; i++) {
125         for (j=0; j<NX; j++) buf[j] = -1;
126         if (i%2) {
127             start[0] = 0; count[0] = NX;
128             st = nc_get_var_int(ncid, varid[i], buf); CHK_ERR(st)
129             for (j=0; j<NX; j++)
130                 if (buf[j] != i*10 + j)
131                     printf("unexpected read value var i=%d buf[j=%d]=%d should be %d\n",i,j,buf[j],i*10+j);
132         }
133         else {
134             start[0] = 0; start[1] = 0;
135             count[0] = 1; count[1] = NX;
136             st = nc_get_vara_int(ncid, varid[i], start, count, buf); CHK_ERR(st)
137             for (j=0; j<NX; j++)
138                 if (buf[j] != i*10+j)
139                     printf("unexpected read value var i=%d buf[j=%d]=%d should be %d\n",i,j,buf[j],i*10+j);
140         }
141     }
142     st = nc_close(ncid); CHK_ERR(st)
143 
144 fn_exit:
145     MPI_Finalize();
146     err = nerrs;
147     SUMMARIZE_ERR;
148     FINAL_RESULTS;
149     return (nerrs > 0);
150 }
151 
152 /*
153     Compile:
154         mpicc -g -o nc_pnc nc_pnc.c -lnetcdf -lcurl -lhdf5_hl -lhdf5 -lpnetcdf -lz -lm
155 
156     Run:
157         nc_pnc
158 
159     Standard Output:
160         At the time of this test is written, I used the following libraries.
161             HDF5    version 1.8.10
162             netCDF  version 4.2.1.1 and
163             PnetCDF version 1.3.1
164 
165         If macro DISABLE_PNETCDF_ALIGNMENT is defined (i.e. disable PnetCDF
166         alignment) then there is no standard output.
167 
168         If macro DISABLE_PNETCDF_ALIGNMENT is NOT defined (i.e. default PnetCDF
169         alignment) then this test reports unexpected read values below.
170 
171          unexpected read value var i=1 buf[j=0]=0 should be 10
172          unexpected read value var i=1 buf[j=1]=0 should be 11
173          unexpected read value var i=1 buf[j=2]=0 should be 12
174          unexpected read value var i=1 buf[j=3]=0 should be 13
175          unexpected read value var i=1 buf[j=4]=0 should be 14
176          unexpected read value var i=3 buf[j=0]=0 should be 30
177          unexpected read value var i=3 buf[j=1]=0 should be 31
178          unexpected read value var i=3 buf[j=2]=0 should be 32
179          unexpected read value var i=3 buf[j=3]=0 should be 33
180          unexpected read value var i=3 buf[j=4]=0 should be 34
181          unexpected read value var i=5 buf[j=0]=0 should be 50
182          unexpected read value var i=5 buf[j=1]=0 should be 51
183          unexpected read value var i=5 buf[j=2]=0 should be 52
184          unexpected read value var i=5 buf[j=3]=0 should be 53
185          unexpected read value var i=5 buf[j=4]=0 should be 54
186 */
187