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