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