1 /* Copyright 2018, UCAR/Unidata See COPYRIGHT file for copying and
2 * redistribution conditions.
3 *
4 * This program tests netcdf-4 parallel I/O.
5 *
6 * Ed Hartnett
7 */
8
9 #include <nc_tests.h>
10 #include "err_macros.h"
11 #include <mpi.h>
12
13 #define FILE "tst_parallel5.nc"
14 #define VAR_NAME "TheIrishRover"
15 #define DIM_NAME "number_of_masts"
16 #define MASTS 27
17 #define NDIMS1 1
18 #define DIMSIZE 4
19 #define NUM_PROC 4
20 #define NUM_SLABS 10
21 #define NUM_ACCESS_TESTS 2
22
23 int
main(int argc,char ** argv)24 main(int argc, char **argv)
25 {
26 int mpi_size, mpi_rank;
27 MPI_Comm comm = MPI_COMM_WORLD;
28 MPI_Info info = MPI_INFO_NULL;
29 int ncid, v1id, dimid;
30 size_t start[NDIMS1] = {0}, count[NDIMS1] = {0};
31 int data = MASTS;
32 int data_in = TEST_VAL_42;
33 int acc;
34
35 /* Initialize MPI. */
36 MPI_Init(&argc, &argv);
37 MPI_Comm_size(MPI_COMM_WORLD, &mpi_size);
38 MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
39
40 /* Require exactly 4 tasks. */
41 if (mpi_size != NUM_PROC) ERR;
42
43 if (!mpi_rank)
44 printf("\n*** Testing parallel I/O.\n");
45
46 if (!mpi_rank)
47 printf("*** testing whether we can write 0 elements from some tasks...");
48 {
49 for (acc = 0; acc < NUM_ACCESS_TESTS; acc++)
50 {
51 /* Create a parallel netcdf-4 file. */
52 /*nc_set_log_level(3);*/
53 if (nc_create_par(FILE, NC_NETCDF4, comm, info, &ncid)) ERR;
54
55 /* Create a dimension. */
56 if (nc_def_dim(ncid, DIM_NAME, DIMSIZE, &dimid)) ERR;
57
58 /* Create one var. */
59 if (nc_def_var(ncid, VAR_NAME, NC_INT, NDIMS1, &dimid, &v1id)) ERR;
60
61 /* Write metadata to file. */
62 if (nc_enddef(ncid)) ERR;
63
64 /* Set up slab for this process. */
65 if (!mpi_rank)
66 count[0] = 1;
67
68 if (nc_var_par_access(ncid, v1id, acc ? NC_COLLECTIVE : NC_INDEPENDENT)) ERR;
69
70 /* Write phoney data. */
71 if (nc_put_vara_int(ncid, v1id, start, count, &data)) ERR;
72
73 if (nc_sync(ncid)) ERR;
74
75 /* Read phoney data. */
76 if (nc_get_vara_int(ncid, v1id, start, count, &data_in)) ERR;
77
78 /* Task 0 has MASTS, the others have data_in remaining, as
79 * initialized, at TEST_VAL_42. */
80 if (data_in != (mpi_rank ? TEST_VAL_42 : MASTS)) ERR;
81
82 /* Close the netcdf file. */
83 if (nc_close(ncid)) ERR;
84 }
85 }
86 if (!mpi_rank)
87 SUMMARIZE_ERR;
88
89 if (!mpi_rank)
90 printf("*** testing enum type and parallel I/O...");
91 {
92 for (acc = 0; acc < NUM_ACCESS_TESTS; acc++)
93 {
94 #define ENUM_NAME "cargo"
95 #define ENUM_VAR_NAME "in_the_hold_of_the_Irish_Rover"
96 #define NUM_ENUM_FIELDS 8
97 int typeid;
98 int f;
99 char field_name[NUM_ENUM_FIELDS][NC_MAX_NAME + 1] = {"bags of the best Sligo rags", "barrels of bones",
100 "bails of old nanny goats' tails", "barrels of stones",
101 "dogs", "hogs", "barrels of porter",
102 "sides of old blind horses hides"};
103 unsigned long long field_value[NUM_ENUM_FIELDS] = {1000000, 2000000, 3000000, 4000000,
104 5000000, 6000000, 7000000, 8000000};
105 unsigned long long data = 1000000, data_in = TEST_VAL_42;
106
107 /* Create a parallel netcdf-4 file. */
108 /*nc_set_log_level(3);*/
109 if (nc_create_par(FILE, NC_NETCDF4, comm, info, &ncid)) ERR;
110
111 /* Create a dimension. */
112 if (nc_def_dim(ncid, DIM_NAME, DIMSIZE, &dimid)) ERR;
113
114 /* Create an enum type. */
115 if (nc_def_enum(ncid, NC_UINT64, ENUM_NAME, &typeid)) ERR;
116 for (f = 0; f < NUM_ENUM_FIELDS; f++)
117 if (nc_insert_enum(ncid, typeid, field_name[f], &field_value[f])) ERR;
118
119 /* Create one var. */
120 if (nc_def_var(ncid, ENUM_VAR_NAME, typeid, NDIMS1, &dimid, &v1id)) ERR;
121
122 /* Write metadata to file. */
123 if (nc_enddef(ncid)) ERR;
124
125 /* Set up slab for this process. */
126 if (!mpi_rank)
127 count[0] = 1;
128
129 if (nc_var_par_access(ncid, v1id, acc ? NC_COLLECTIVE : NC_INDEPENDENT)) ERR;
130
131 /* Write phoney data. */
132 if (nc_put_vara(ncid, v1id, start, count, &data)) ERR;
133
134 if (nc_sync(ncid)) ERR;
135
136 /* Read phoney data. */
137 if (nc_get_vara(ncid, v1id, start, count, &data_in)) ERR;
138
139 /* Task 0 has 1000000, the others have data_in remaining, as
140 * initialized, at TEST_VAL_42. */
141 if (data_in != (mpi_rank ? TEST_VAL_42 : 1000000)) ERR;
142
143 /* Close the netcdf file. */
144 if (nc_close(ncid)) ERR;
145 }
146 }
147 if (!mpi_rank)
148 SUMMARIZE_ERR;
149 if (!mpi_rank)
150 printf("*** testing compound type and parallel I/O...");
151 {
152 for (acc = 0; acc < NUM_ACCESS_TESTS; acc++)
153 {
154 #define COMPOUND_NAME "crew_info"
155 #define COMPOUND_VAR_NAME "whale_of_a_crew"
156 #define NUM_CREW 5
157 #define CREW_DIM_NAME "number_of_crew"
158 int typeid;
159 struct crew
160 {
161 char name[NC_MAX_NAME + 1];
162 char description[NC_MAX_NAME + 1];
163 char origin[NC_MAX_NAME + 1];
164 int age;
165 };
166 struct crew data = {"Mick McCann", "the skipper of the Irish Rover",
167 "from the banks of the Bann", 42};
168 struct crew data_in = {"", "", "", -42};
169 int dim_size = NC_MAX_NAME + 1;
170
171 /* Create a parallel netcdf-4 file. */
172 /*nc_set_log_level(3);*/
173 if (nc_create_par(FILE, NC_NETCDF4, comm, info, &ncid)) ERR;
174
175 /* Create a dimension. */
176 if (nc_def_dim(ncid, CREW_DIM_NAME, NUM_CREW, &dimid)) ERR;
177
178 /* Create a compound type. */
179 if (nc_def_compound(ncid, sizeof(struct crew), COMPOUND_NAME, &typeid)) ERR;
180 if (nc_insert_array_compound(ncid, typeid, "name", NC_COMPOUND_OFFSET(struct crew, name), NC_CHAR, 1, &dim_size)) ERR;
181 if (nc_insert_array_compound(ncid, typeid, "description", NC_COMPOUND_OFFSET(struct crew, description), NC_CHAR, 1, &dim_size)) ERR;
182 if (nc_insert_array_compound(ncid, typeid, "origin", NC_COMPOUND_OFFSET(struct crew, origin), NC_CHAR, 1, &dim_size)) ERR;
183 if (nc_insert_compound(ncid, typeid, "age", NC_COMPOUND_OFFSET(struct crew, age), NC_INT)) ERR;
184
185 /* Create one var. */
186 if (nc_def_var(ncid, COMPOUND_VAR_NAME, typeid, NDIMS1, &dimid, &v1id)) ERR;
187
188 /* Write metadata to file. */
189 if (nc_enddef(ncid)) ERR;
190
191 /* Set up slab for this process. */
192 if (!mpi_rank)
193 count[0] = 1;
194
195 if (nc_var_par_access(ncid, v1id, acc ? NC_COLLECTIVE : NC_INDEPENDENT)) ERR;
196
197 /* Write phoney data. */
198 if (nc_put_vara(ncid, v1id, start, count, &data)) ERR;
199
200 if (nc_sync(ncid)) ERR;
201
202 /* Read phoney data. */
203 if (nc_get_vara(ncid, v1id, start, count, &data_in)) ERR;
204
205 /* Task 0 has data, the others have nothing. */
206 if (!mpi_rank)
207 {
208 if (strcmp(data_in.name, data.name) || strcmp(data_in.description, data.description) ||
209 strcmp(data_in.origin, data.origin) || data_in.age != data.age) ERR;
210 }
211 else
212 {
213 if (strcmp(data_in.name, "") || strcmp(data_in.description, "") ||
214 strcmp(data_in.origin, "") || data_in.age != -42) ERR;
215 }
216
217 /* Close the netcdf file. */
218 if (nc_close(ncid)) ERR;
219 }
220 }
221 if (!mpi_rank)
222 SUMMARIZE_ERR;
223 if (!mpi_rank)
224 printf("*** testing string type and parallel I/O...");
225 {
226 for (acc = 0; acc < NUM_ACCESS_TESTS; acc++)
227 {
228 #define STORY_VAR_NAME "fate_of_the_Irish_Rover"
229 #define STORY_DIM_NAME "number_of_lines"
230 #define STORY_LEN 8
231 char *story[STORY_LEN] = {"We had sailed seven years when the measles broke out",
232 "And the ship lost it's way in the fog",
233 "And that whale of the crew was reduced down to two",
234 "Just myself and the captain's old dog",
235 "Then the ship struck a rock, oh Lord what a shock",
236 "The bulkhead was turned right over",
237 "Turned nine times around, and the poor dog was drowned",
238 "I'm the last of the Irish Rover"};
239 char *story_in[STORY_LEN];
240 int s;
241
242 /* Create a netcdf-4 file. Turns out that HDF5 does not
243 * support VLEN writes with parallel I/O. Strings are
244 * VLENS. So here I write a file with task 0 and then read it
245 * with all tasks. */
246 if (!mpi_rank)
247 {
248 if (nc_create(FILE, NC_NETCDF4, &ncid)) ERR;
249
250 /* Create a dimension. */
251 if (nc_def_dim(ncid, STORY_DIM_NAME, STORY_LEN, &dimid)) ERR;
252
253 /* Create one var. */
254 if (nc_def_var(ncid, STORY_VAR_NAME, NC_STRING, NDIMS1, &dimid, &v1id)) ERR;
255
256 /* Write metadata to file. */
257 if (nc_enddef(ncid)) ERR;
258
259 /* Set up slab for this process. */
260 count[0] = STORY_LEN;
261
262 /* Write phoney data. */
263 if (nc_put_vara(ncid, v1id, start, count, story)) ERR;
264
265 /* Close the netcdf file. */
266 if (nc_close(ncid)) ERR;
267 }
268
269 /* Now try parallel read. */
270 if (nc_open_par(FILE, 0, comm, info, &ncid)) ERR;
271
272 /* Task 0 reads all 8 lines, other tasks read 0. */
273 if (nc_get_vara(ncid, v1id, start, count, story_in)) ERR;
274
275 if (!mpi_rank)
276 {
277 for (s = 0; s < STORY_LEN; s++)
278 if (strcmp(story_in[s], story[s])) ERR;
279 if (nc_free_string(STORY_LEN, (char **)story_in)) ERR;
280 }
281
282 /* Close the netcdf file. */
283 if (nc_close(ncid)) ERR;
284 }
285 }
286 if (!mpi_rank)
287 SUMMARIZE_ERR;
288
289 if (!mpi_rank)
290 printf("*** testing NC_BYTE type and parallel I/O...");
291 {
292 /* This test is related to
293 * https://github.com/Unidata/netcdf-c/issues/1462. */
294 int ncid, varid;
295 signed char test_data_in, test_data = 42;
296
297 /* Crate a file with a scalar NC_BYTE value. */
298 if (nc_create_par(FILE, NC_NETCDF4, MPI_COMM_WORLD, MPI_INFO_NULL,
299 &ncid)) ERR;
300 if (nc_def_var(ncid, "fred", NC_BYTE, 0, NULL, &varid)) ERR;
301 if (nc_enddef(ncid)) ERR;
302 if (nc_put_var_schar(ncid, varid, &test_data)) ERR;
303 if (nc_close(ncid)) ERR;
304
305 /* Reopen the file and check. */
306 if (nc_open_par(FILE, 0, comm, info, &ncid)) ERR;
307 if (nc_get_var_schar(ncid, varid, &test_data_in)) ERR;
308 if (test_data_in != test_data) ERR;
309 if (nc_close(ncid)) ERR;
310 }
311 if (!mpi_rank)
312 SUMMARIZE_ERR;
313 #ifdef USE_SZIP
314 #ifdef HDF5_SUPPORTS_PAR_FILTERS
315 #define SZIP_DIM_LEN 256
316 #define SZIP_DIM_NAME "Barrels"
317 #define SZIP_VAR_NAME "Best_Sligo_Rags"
318 #define SZIP_PIXELS_PER_BLOCK 32
319 if (!mpi_rank)
320 printf("*** testing szip compression with parallel I/O...");
321 {
322 int ncid, dimid, varid;
323 float *data;
324 float *data_in;
325 int elements_per_pe = SZIP_DIM_LEN/mpi_size;
326 size_t start[NDIMS1], count[NDIMS1];
327 int i;
328
329 /* Create test data. */
330 if (!(data = malloc(elements_per_pe * sizeof(float)))) ERR;
331 for (i = 0; i < elements_per_pe; i++)
332 data[i] = mpi_rank + i * 0.1;
333
334 /* Crate a file with a scalar NC_BYTE value. */
335 if (nc_create_par(FILE, NC_NETCDF4, MPI_COMM_WORLD, MPI_INFO_NULL,
336 &ncid)) ERR;
337 if (nc_def_dim(ncid, SZIP_DIM_NAME, SZIP_DIM_LEN, &dimid)) ERR;
338 if (nc_def_var(ncid, SZIP_VAR_NAME, NC_FLOAT, NDIMS1, &dimid, &varid)) ERR;
339 if (nc_def_var_szip(ncid, varid, H5_SZIP_NN_OPTION_MASK,
340 SZIP_PIXELS_PER_BLOCK)) ERR;
341 if (nc_enddef(ncid)) ERR;
342 start[0] = mpi_rank * elements_per_pe;
343 count[0] = elements_per_pe;
344 if (nc_put_vara_float(ncid, varid, start, count, data)) ERR;
345 if (nc_close(ncid)) ERR;
346
347 /* Reopen the file and check. */
348 if (nc_open_par(FILE, 0, comm, info, &ncid)) ERR;
349 if (!(data_in = malloc(elements_per_pe * sizeof(float)))) ERR;
350 if (nc_get_vara_float(ncid, varid, start, count, data_in)) ERR;
351 if (nc_close(ncid)) ERR;
352 for (i = 0; i < elements_per_pe; i++)
353 if (data_in[i] != data[i]) ERR;
354
355 /* Release resources. */
356 free(data_in);
357 free(data);
358 }
359 if (!mpi_rank)
360 SUMMARIZE_ERR;
361 #endif /* HDF5_SUPPORTS_PAR_FILTERS */
362 #endif /* USE_SZIP */
363
364 /* Shut down MPI. */
365 MPI_Finalize();
366
367 if (!mpi_rank)
368 FINAL_RESULTS;
369
370 return 0;
371 }
372