1 /*
2  * Distributed under the OSI-approved Apache License, Version 2.0.  See
3  * accompanying file Copyright.txt for details.
4  */
5 #include <cstdint>
6 #include <cstring>
7 
8 #include <iostream>
9 #include <stdexcept>
10 
11 #include <adios2.h>
12 
13 #include <hdf5.h>
14 
15 #include <gtest/gtest.h>
16 
17 #include "../SmallTestData.h"
18 
19 class HDF5WriteReadTest : public ::testing::Test
20 {
21 public:
22     HDF5WriteReadTest() = default;
23 
24     SmallTestData m_TestData;
25 };
26 
27 class HDF5NativeReader
28 {
29 
30 public:
31     HDF5NativeReader(const std::string fileName);
32     ~HDF5NativeReader();
33 
34     bool Advance();
35 
36     void GetVarInfo(const std::string varName, std::vector<hsize_t> &dims,
37                     hid_t &h5Type);
38     // If offset, count and memspaceSize are provided, then variable would be
39     // read by selection
40     void ReadString(const std::string varName, std::string &result);
41     void ReadVar(const std::string varName, void *dataArray,
42                  hsize_t *offset = nullptr, hsize_t *count = nullptr,
43                  const size_t memsspaceSize = 0);
44 
45     int m_CurrentTimeStep;
46     unsigned int m_TotalTimeSteps;
47 
48 private:
49     hid_t m_FilePropertyListId;
50     hid_t m_FileId;
51     hid_t m_GroupId;
52 };
53 
54 class HDF5NativeWriter
55 {
56 public:
57 #ifdef TEST_HDF5_MPI
58     HDF5NativeWriter(const std::string &fileName, MPI_Comm comm);
59 #else
60     HDF5NativeWriter(const std::string &fileName);
61 #endif
62     ~HDF5NativeWriter();
63 
64     void Advance();
65 
66     void CreateAndStoreScalar(std::string const &variableName, hid_t h5Type,
67                               const void *values);
68     void CreateAndStoreVar(std::string const &variableName, int dimSize,
69                            hid_t h5Type, const hsize_t *global_dims,
70                            const hsize_t *offsets, const hsize_t *counts,
71                            const void *values);
72 
73     /*
74       void WriteVar(const std::string varName, void *dataArray,
75                     hsize_t *offset = nullptr, hsize_t *count = nullptr,
76                     const size_t memsspaceSize = 0);
77     */
78     int m_CurrentTimeStep;
79     unsigned int m_TotalTimeSteps;
80 
81 private:
82     void CheckWriteGroup();
83 
84     hid_t m_FilePropertyListId;
85     hid_t m_FileId;
86     hid_t m_GroupId;
87 };
88 #ifdef TEST_HDF5_MPI
HDF5NativeWriter(const std::string & fileName,MPI_Comm comm)89 HDF5NativeWriter::HDF5NativeWriter(const std::string &fileName, MPI_Comm comm)
90 #else
91 HDF5NativeWriter::HDF5NativeWriter(const std::string &fileName)
92 #endif
93 : m_CurrentTimeStep(0), m_TotalTimeSteps(0)
94 {
95     m_FilePropertyListId = H5Pcreate(H5P_FILE_ACCESS);
96 
97 #ifdef TEST_HDF5_MPI
98     H5Pset_fapl_mpio(m_FilePropertyListId, comm, MPI_INFO_NULL);
99 #endif
100 
101     // std::string ts0 = "/AdiosStep0";
102     // stepName = "/Step" + std::to_string(ts);
103     std::string ts0 = "/Step0";
104 
105     /*
106      * Create a new file collectively and release property list identifier.
107      */
108     m_FileId = H5Fcreate(fileName.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT,
109                          m_FilePropertyListId);
110     if (m_FileId < 0)
111     {
112         throw std::runtime_error("Unable to create file: " + fileName);
113     }
114 
115     m_GroupId = H5Gcreate2(m_FileId, ts0.c_str(), H5P_DEFAULT, H5P_DEFAULT,
116                            H5P_DEFAULT);
117 
118     if (m_GroupId < 0)
119     {
120         throw std::runtime_error("ERROR: Unable to create HDF5 group " + ts0);
121     }
122 }
123 
~HDF5NativeWriter()124 HDF5NativeWriter::~HDF5NativeWriter()
125 {
126     if (m_FileId < 0)
127     {
128         return;
129     }
130 
131     // write NumStep attr
132     hid_t s = H5Screate(H5S_SCALAR);
133 
134     hid_t attr = H5Acreate(m_FileId, "NumSteps", H5T_NATIVE_UINT, s,
135                            H5P_DEFAULT, H5P_DEFAULT);
136     unsigned int totalAdiosSteps = m_CurrentTimeStep + 1;
137 
138     if (m_GroupId < 0)
139     {
140         totalAdiosSteps = m_CurrentTimeStep;
141     }
142 
143     H5Awrite(attr, H5T_NATIVE_UINT, &totalAdiosSteps);
144 
145     H5Sclose(s);
146     H5Aclose(attr);
147 
148     // now close necessary ids
149     if (m_GroupId >= 0)
150     {
151         H5Gclose(m_GroupId);
152     }
153 
154     H5Fclose(m_FileId);
155     H5Pclose(m_FilePropertyListId);
156 }
157 
CheckWriteGroup()158 void HDF5NativeWriter::CheckWriteGroup()
159 {
160     if (m_GroupId >= 0)
161     {
162         return;
163     }
164 
165     std::string stepName = "/Step" + std::to_string(m_CurrentTimeStep);
166 
167     m_GroupId = H5Gcreate2(m_FileId, stepName.c_str(), H5P_DEFAULT, H5P_DEFAULT,
168                            H5P_DEFAULT);
169 
170     if (m_GroupId < 0)
171     {
172         throw std::runtime_error("ERROR: Unable to create HDF5 group " +
173                                  stepName);
174     }
175 }
176 
CreateAndStoreScalar(std::string const & variableName,hid_t h5Type,const void * values)177 void HDF5NativeWriter::CreateAndStoreScalar(std::string const &variableName,
178                                             hid_t h5Type, const void *values)
179 {
180     CheckWriteGroup();
181 
182     // write scalar
183     hid_t filespaceID = H5Screate(H5S_SCALAR);
184     hid_t plistID = H5Pcreate(H5P_DATASET_XFER);
185 #ifdef TEST_HDF5_MPI
186     H5Pset_dxpl_mpio(plistID, H5FD_MPIO_COLLECTIVE);
187 #endif
188 
189     hid_t dsetID;
190 
191     if (h5Type != H5T_STRING)
192     {
193         dsetID = H5Dcreate(m_GroupId, variableName.c_str(), h5Type, filespaceID,
194                            H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
195         herr_t status =
196             H5Dwrite(dsetID, h5Type, H5S_ALL, H5S_ALL, plistID, values);
197     }
198     else
199     {
200         /* Create a datatype to refer to. */
201         hid_t type = H5Tcopy(H5T_C_S1);
202         char *strval = (char *)values;
203         hid_t ret = H5Tset_size(type, strlen(strval));
204 
205         ret = H5Tset_strpad(type, H5T_STR_NULLTERM);
206 
207         /* Test creating a "normal" sized string attribute */
208         dsetID = H5Dcreate(m_GroupId, variableName.c_str(), type, filespaceID,
209                            H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
210 
211         ret = H5Dwrite(dsetID, type, H5S_ALL, H5S_ALL, plistID, values);
212 
213 #ifdef DOUBLECHECK
214         size_t typesize = H5Tget_size(type);
215         char *val = (char *)(calloc(typesize, sizeof(char)));
216 
217         hid_t ret2 = H5Dread(dsetID, type, H5S_ALL, H5S_ALL, H5P_DEFAULT, val);
218         std::cerr << "        ....  typesize=" << typesize << "  val=" << val
219                   << std::endl;
220         free val;
221 #endif
222     }
223 
224     H5Sclose(filespaceID);
225     H5Dclose(dsetID);
226 }
227 
CreateAndStoreVar(std::string const & variableName,int dimSize,hid_t h5Type,const hsize_t * global_dims,const hsize_t * offsets,const hsize_t * counts,const void * values)228 void HDF5NativeWriter::CreateAndStoreVar(std::string const &variableName,
229                                          int dimSize, hid_t h5Type,
230                                          const hsize_t *global_dims,
231                                          const hsize_t *offsets,
232                                          const hsize_t *counts,
233                                          const void *values)
234 {
235     if (h5Type == H5T_STRING)
236     {
237         throw std::runtime_error("Sync with ADIOS2. It does not store string "
238                                  "var with dimensions yet!");
239     }
240 
241     CheckWriteGroup();
242     hid_t fileSpace = H5Screate_simple(dimSize, global_dims, NULL);
243 
244     hid_t dsetID = H5Dcreate(m_GroupId, variableName.c_str(), h5Type, fileSpace,
245                              H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
246     hid_t memSpace = H5Screate_simple(dimSize, counts, NULL);
247 
248     // Select hyperslab
249     fileSpace = H5Dget_space(dsetID);
250     H5Sselect_hyperslab(fileSpace, H5S_SELECT_SET, offsets, NULL, counts, NULL);
251 
252     //  Create property list for collective dataset write.
253 
254     hid_t plistID = H5Pcreate(H5P_DATASET_XFER);
255 #ifdef TEST_HDF5_MPI
256     H5Pset_dxpl_mpio(plistID, H5FD_MPIO_COLLECTIVE);
257 #endif
258     herr_t status =
259         H5Dwrite(dsetID, h5Type, memSpace, fileSpace, plistID, values);
260 
261     if (status < 0)
262     {
263         throw std::runtime_error(
264             "ERROR: HDF5 file Write failed, in call to Write\n");
265     }
266 
267     H5Dclose(dsetID);
268     H5Sclose(fileSpace);
269     H5Sclose(memSpace);
270     H5Pclose(plistID);
271 }
272 
Advance()273 void HDF5NativeWriter::Advance()
274 {
275     if (m_GroupId >= 0)
276     {
277         H5Gclose(m_GroupId);
278         m_GroupId = -1;
279     }
280     ++m_CurrentTimeStep;
281 }
282 
283 //
284 //
285 //
HDF5NativeReader(const std::string fileName)286 HDF5NativeReader::HDF5NativeReader(const std::string fileName)
287 : m_CurrentTimeStep(0), m_TotalTimeSteps(0)
288 {
289     m_FilePropertyListId = H5Pcreate(H5P_FILE_ACCESS);
290 
291 #ifdef TEST_HDF5_MPI
292     // read a file collectively
293     H5Pset_fapl_mpio(m_FilePropertyListId, MPI_COMM_WORLD, MPI_INFO_NULL);
294 #endif
295 
296     m_FileId = H5Fopen(fileName.c_str(), H5F_ACC_RDONLY, m_FilePropertyListId);
297     if (m_FileId < 0)
298     {
299         throw std::runtime_error("Unable to open " + fileName + " for reading");
300     }
301 
302     std::string ts0 = "/Step0";
303     m_GroupId = H5Gopen(m_FileId, ts0.c_str(), H5P_DEFAULT);
304     if (m_GroupId < 0)
305     {
306         throw std::runtime_error("Unable to open group " + ts0 +
307                                  " for reading");
308     }
309 
310     hid_t attrId = H5Aopen(m_FileId, "NumSteps", H5P_DEFAULT);
311     if (attrId < 0)
312     {
313         throw std::runtime_error("Unable to open attribute NumSteps");
314     }
315     H5Aread(attrId, H5T_NATIVE_UINT, &m_TotalTimeSteps);
316     H5Aclose(attrId);
317 }
318 
~HDF5NativeReader()319 HDF5NativeReader::~HDF5NativeReader()
320 {
321     if (m_GroupId >= 0)
322     {
323         H5Gclose(m_GroupId);
324     }
325 
326     H5Fclose(m_FileId);
327     H5Pclose(m_FilePropertyListId);
328 }
329 
GetVarInfo(const std::string varName,std::vector<hsize_t> & dims,hid_t & h5Type)330 void HDF5NativeReader::GetVarInfo(const std::string varName,
331                                   std::vector<hsize_t> &dims, hid_t &h5Type)
332 {
333     hid_t dataSetId = H5Dopen(m_GroupId, varName.c_str(), H5P_DEFAULT);
334     if (dataSetId < 0)
335     {
336         throw std::runtime_error("Unable to open dataset " + varName +
337                                  " when getVarInfo");
338     }
339 
340     hid_t fileSpaceId = H5Dget_space(dataSetId);
341     if (fileSpaceId < 0)
342     {
343         throw std::runtime_error("Unable to get filespace for dataset " +
344                                  varName);
345     }
346 
347     const int ndims = H5Sget_simple_extent_ndims(fileSpaceId);
348     if (ndims < 0)
349     {
350         throw std::runtime_error(
351             "Unable to get number of dimensions for dataset " + varName);
352     }
353 
354     dims.resize(ndims);
355     if (H5Sget_simple_extent_dims(fileSpaceId, dims.data(), NULL) != ndims)
356     {
357         throw std::runtime_error("Unable to get dimensions for dataset " +
358                                  varName);
359     }
360 
361     h5Type = H5Dget_type(dataSetId);
362 
363     H5Sclose(fileSpaceId);
364     H5Dclose(dataSetId);
365 }
366 
Advance()367 bool HDF5NativeReader::Advance()
368 {
369     if (m_GroupId >= 0)
370     {
371         H5Gclose(m_GroupId);
372         m_GroupId = -1;
373     }
374 
375     if (m_CurrentTimeStep + 1 >= m_TotalTimeSteps)
376     {
377         return false;
378     }
379 
380     const std::string tsName = "Step" + std::to_string(m_CurrentTimeStep + 1);
381     m_GroupId = H5Gopen(m_FileId, tsName.c_str(), H5P_DEFAULT);
382     if (m_GroupId < 0)
383     {
384         throw std::runtime_error("Unable to open group " + tsName +
385                                  " for reading");
386     }
387     ++m_CurrentTimeStep;
388 
389     return true;
390 }
391 
ReadString(const std::string varName,std::string & result)392 void HDF5NativeReader::ReadString(const std::string varName,
393                                   std::string &result)
394 {
395     if (m_GroupId < 0)
396     {
397         throw std::runtime_error("Can't read variable " + varName +
398                                  " since a group is not currently open");
399     }
400 
401     hid_t dataSetId = H5Dopen(m_GroupId, varName.c_str(), H5P_DEFAULT);
402     if (dataSetId < 0)
403     {
404         throw std::runtime_error("Unable to open dataset " + varName +
405                                  "when ReadVar");
406     }
407 
408     hid_t h5Type = H5Dget_type(dataSetId);
409     size_t typesize = H5Tget_size(h5Type);
410 
411     char *val = (char *)(calloc(typesize, sizeof(char)));
412     hid_t ret2 = H5Dread(dataSetId, h5Type, H5S_ALL, H5S_ALL, H5P_DEFAULT, val);
413 
414     result.assign(val, typesize);
415     free(val);
416 
417     H5Dclose(dataSetId);
418 }
419 
ReadVar(const std::string varName,void * dataArray,hsize_t * offset,hsize_t * count,const size_t memspaceSize)420 void HDF5NativeReader::ReadVar(const std::string varName, void *dataArray,
421                                hsize_t *offset, hsize_t *count,
422                                const size_t memspaceSize)
423 {
424     if (m_GroupId < 0)
425     {
426         throw std::runtime_error("Can't read variable " + varName +
427                                  " since a group is not currently open");
428     }
429 
430     hid_t dataSetId = H5Dopen(m_GroupId, varName.c_str(), H5P_DEFAULT);
431     if (dataSetId < 0)
432     {
433         throw std::runtime_error("Unable to open dataset " + varName +
434                                  "when ReadVar");
435     }
436     hid_t fileSpace = H5Dget_space(dataSetId);
437     if (fileSpace < 0)
438     {
439         throw std::runtime_error("Unable to get filespace for dataset " +
440                                  varName);
441     }
442 
443     hid_t h5type = H5Dget_type(dataSetId);
444 
445     // Extend reader to support read by hyperslab selection
446     // Reference link: https://support.hdfgroup.org/HDF5/Tutor/select.html
447     // Check if hyperspace is provided
448     if (offset && count)
449     {
450         // Get the dataspace
451         hid_t dataspace = H5Dget_space(dataSetId);
452         // Define hyperslab in the dataset
453         hid_t status = H5Sselect_hyperslab(dataspace, H5S_SELECT_SET, offset,
454                                            NULL, count, NULL);
455         if (status < 0)
456         {
457             throw std::runtime_error(
458                 "Unable to create a selection for dataset" + varName);
459         }
460 
461         hsize_t dimsm[1];
462         dimsm[0] = memspaceSize;
463         hid_t memspace = H5Screate_simple(1, dimsm, NULL);
464 
465         hid_t ret = H5Dread(dataSetId, h5type, memspace, dataspace, H5P_DEFAULT,
466                             dataArray);
467     }
468     else
469     {
470         hid_t ret = H5Dread(dataSetId, h5type, H5S_ALL, H5S_ALL, H5P_DEFAULT,
471                             dataArray);
472     }
473 
474     H5Sclose(fileSpace);
475     H5Dclose(dataSetId);
476 }
477 
478 //******************************************************************************
479 // 1D 1x8 test data
480 //******************************************************************************
481 
482 // ADIOS2 write, native HDF5 read
TEST_F(HDF5WriteReadTest,ADIOS2HDF5WriteHDF5Read1D8)483 TEST_F(HDF5WriteReadTest, ADIOS2HDF5WriteHDF5Read1D8)
484 {
485     // Each process would write a 1x8 array and all processes would
486     // form a mpiSize * Nx 1D array
487     const std::string fname = "ADIOS2HDF5WriteHDF5Read1D8.h5";
488 
489     int mpiRank = 0, mpiSize = 1;
490     // Number of rows
491     const std::size_t Nx = 8;
492 
493     // Number of steps
494     const std::size_t NSteps = 3;
495 
496 #ifdef TEST_HDF5_MPI
497     MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
498     MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
499 #endif
500 
501     // Write test data using ADIOS2
502 
503 #ifdef TEST_HDF5_MPI
504     adios2::ADIOS adios(MPI_COMM_WORLD);
505 #else
506     adios2::ADIOS adios;
507 #endif
508     adios2::IO io = adios.DeclareIO("TestIO");
509 
510     // Declare 1D variables (NumOfProcesses * Nx)
511     // The local process' part (start, count) can be defined now or later
512     // before Write().
513     {
514         adios2::Dims shape{static_cast<unsigned int>(Nx * mpiSize)};
515         adios2::Dims start{static_cast<unsigned int>(Nx * mpiRank)};
516         adios2::Dims count{static_cast<unsigned int>(Nx)};
517 
518         io.DefineVariable<std::string>("iString");
519         io.DefineVariable<int8_t>("i8", shape, start, count);
520         io.DefineVariable<int16_t>("i16", shape, start, count);
521         io.DefineVariable<int32_t>("i32", shape, start, count);
522         io.DefineVariable<int64_t>("i64", shape, start, count);
523         io.DefineVariable<uint8_t>("u8", shape, start, count);
524         io.DefineVariable<uint16_t>("u16", shape, start, count);
525         io.DefineVariable<uint32_t>("u32", shape, start, count);
526         io.DefineVariable<uint64_t>("u64", shape, start, count);
527         io.DefineVariable<float>("r32", shape, start, count);
528         io.DefineVariable<double>("r64", shape, start, count);
529     }
530 
531     // Create the HDF5 Engine
532     io.SetEngine("HDF5");
533 
534     // HDf5 engine calls the HDF5 common object that calls the hDF5 library.
535     // The IO functionality, SetParameters and AddTransports will be added
536     // in the future. For now `io.AddTransport("file", {
537     // "library", "MPI"}});` is omitted.
538     // })
539     // io.AddTransport("File");
540 
541     adios2::Engine engine = io.Open(fname, adios2::Mode::Write);
542 
543     for (size_t step = 0; step < NSteps; ++step)
544     {
545         // Generate test data for each process uniquely
546         SmallTestData currentTestData =
547             generateNewSmallTestData(m_TestData, step, mpiRank, mpiSize);
548 
549         // Retrieve the variables that previously went out of scope
550         auto var_iString = io.InquireVariable<std::string>("iString");
551         auto var_i8 = io.InquireVariable<int8_t>("i8");
552         auto var_i16 = io.InquireVariable<int16_t>("i16");
553         auto var_i32 = io.InquireVariable<int32_t>("i32");
554         auto var_i64 = io.InquireVariable<int64_t>("i64");
555         auto var_u8 = io.InquireVariable<uint8_t>("u8");
556         auto var_u16 = io.InquireVariable<uint16_t>("u16");
557         auto var_u32 = io.InquireVariable<uint32_t>("u32");
558         auto var_u64 = io.InquireVariable<uint64_t>("u64");
559         auto var_r32 = io.InquireVariable<float>("r32");
560         auto var_r64 = io.InquireVariable<double>("r64");
561 
562         // Make a 1D selection to describe the local dimensions of the
563         // variable we write and its offsets in the global spaces
564         adios2::Box<adios2::Dims> sel({mpiRank * Nx}, {Nx});
565         var_i8.SetSelection(sel);
566         var_i16.SetSelection(sel);
567         var_i32.SetSelection(sel);
568         var_i64.SetSelection(sel);
569         var_u8.SetSelection(sel);
570         var_u16.SetSelection(sel);
571         var_u32.SetSelection(sel);
572         var_u64.SetSelection(sel);
573         var_r32.SetSelection(sel);
574         var_r64.SetSelection(sel);
575 
576         // Write each one
577         // fill in the variable with values from starting index to
578         // starting index + count
579         engine.BeginStep();
580         engine.Put(var_iString, currentTestData.S1);
581         engine.Put(var_i8, currentTestData.I8.data());
582         engine.Put(var_i16, currentTestData.I16.data());
583         engine.Put(var_i32, currentTestData.I32.data());
584         engine.Put(var_i64, currentTestData.I64.data());
585         engine.Put(var_u8, currentTestData.U8.data());
586         engine.Put(var_u16, currentTestData.U16.data());
587         engine.Put(var_u32, currentTestData.U32.data());
588         engine.Put(var_u64, currentTestData.U64.data());
589         engine.Put(var_r32, currentTestData.R32.data());
590         engine.Put(var_r64, currentTestData.R64.data());
591         // Advance to the next time step
592         engine.EndStep();
593     }
594 
595     // Close the file
596     engine.Close();
597 
598     bool doRead = true;
599     if (doRead)
600     {
601         const size_t arraySize = Nx;
602         std::string IString;
603         std::array<int8_t, arraySize> I8;
604         std::array<int16_t, arraySize> I16;
605         std::array<int32_t, arraySize> I32;
606         std::array<int64_t, arraySize> I64;
607         std::array<uint8_t, arraySize> U8;
608         std::array<uint16_t, arraySize> U16;
609         std::array<uint32_t, arraySize> U32;
610         std::array<uint64_t, arraySize> U64;
611         std::array<float, arraySize> R32;
612         std::array<double, arraySize> R64;
613 
614         HDF5NativeReader hdf5Reader(fname);
615         // 1D
616         hsize_t count[1], offset[1];
617         offset[0] = mpiRank * Nx;
618         count[0] = Nx;
619         size_t globalArraySize = Nx * mpiSize;
620 
621         // For each variable, we would verify its global size and type.
622         // Then we would retrieve the data back which is written by the
623         // current process and validate the value
624         for (size_t t = 0; t < NSteps; ++t)
625         {
626             SmallTestData currentTestData =
627                 generateNewSmallTestData(m_TestData, t, mpiRank, mpiSize);
628 
629             std::vector<hsize_t> gDims;
630             hid_t h5Type;
631 
632             // auto var_iString = io.InquireVariable<std::string>("iString");
633             hdf5Reader.GetVarInfo("iString", gDims, h5Type);
634             // ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_IN), 1);
635             ASSERT_EQ(gDims.size(), 0);
636             hdf5Reader.ReadString("iString", IString);
637 
638             hdf5Reader.GetVarInfo("i8", gDims, h5Type);
639             ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_INT8), 1);
640             ASSERT_EQ(gDims.size(), 1);
641             ASSERT_EQ(gDims[0], globalArraySize);
642             hdf5Reader.ReadVar("i8", I8.data(), offset, count, arraySize);
643 
644             hdf5Reader.GetVarInfo("i16", gDims, h5Type);
645             ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_SHORT), 1);
646             ASSERT_EQ(gDims.size(), 1);
647             ASSERT_EQ(gDims[0], globalArraySize);
648             hdf5Reader.ReadVar("i16", I16.data(), offset, count, arraySize);
649 
650             hdf5Reader.GetVarInfo("i32", gDims, h5Type);
651             ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_INT), 1);
652             ASSERT_EQ(gDims.size(), 1);
653             ASSERT_EQ(gDims[0], globalArraySize);
654             hdf5Reader.ReadVar("i32", I32.data(), offset, count, arraySize);
655 
656             hdf5Reader.GetVarInfo("i64", gDims, h5Type);
657             ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_LONG), 1);
658             ASSERT_EQ(gDims.size(), 1);
659             ASSERT_EQ(gDims[0], globalArraySize);
660             hdf5Reader.ReadVar("i64", I64.data(), offset, count, arraySize);
661 
662             hdf5Reader.GetVarInfo("u8", gDims, h5Type);
663             ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_UCHAR), 1);
664             ASSERT_EQ(gDims.size(), 1);
665             ASSERT_EQ(gDims[0], globalArraySize);
666             hdf5Reader.ReadVar("u8", U8.data(), offset, count, arraySize);
667 
668             hdf5Reader.GetVarInfo("u16", gDims, h5Type);
669             ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_USHORT), 1);
670             ASSERT_EQ(gDims.size(), 1);
671             ASSERT_EQ(gDims[0], globalArraySize);
672             hdf5Reader.ReadVar("u16", U16.data(), offset, count, arraySize);
673 
674             hdf5Reader.GetVarInfo("u32", gDims, h5Type);
675             ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_UINT), 1);
676             ASSERT_EQ(gDims.size(), 1);
677             ASSERT_EQ(gDims[0], globalArraySize);
678             hdf5Reader.ReadVar("u32", U32.data(), offset, count, arraySize);
679 
680             hdf5Reader.GetVarInfo("u64", gDims, h5Type);
681             ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_ULONG), 1);
682             ASSERT_EQ(gDims.size(), 1);
683             ASSERT_EQ(gDims[0], globalArraySize);
684             hdf5Reader.ReadVar("u64", U64.data(), offset, count, arraySize);
685 
686             hdf5Reader.GetVarInfo("r32", gDims, h5Type);
687             ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_FLOAT), 1);
688             ASSERT_EQ(gDims.size(), 1);
689             ASSERT_EQ(gDims[0], globalArraySize);
690             hdf5Reader.ReadVar("r32", R32.data(), offset, count, arraySize);
691 
692             hdf5Reader.GetVarInfo("r64", gDims, h5Type);
693             ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_DOUBLE), 1);
694             ASSERT_EQ(gDims.size(), 1);
695             ASSERT_EQ(gDims[0], globalArraySize);
696             hdf5Reader.ReadVar("r64", R64.data(), offset, count, arraySize);
697 
698             EXPECT_EQ(IString, currentTestData.S1);
699 
700             // Check if it's correct
701             for (size_t i = 0; i < Nx; ++i)
702             {
703                 std::stringstream ss;
704                 ss << "t=" << t << " i=" << i << " rank=" << mpiRank;
705                 std::string msg = ss.str();
706 
707                 EXPECT_EQ(I8[i], currentTestData.I8[i]) << msg;
708                 EXPECT_EQ(I16[i], currentTestData.I16[i]) << msg;
709                 EXPECT_EQ(I32[i], currentTestData.I32[i]) << msg;
710                 EXPECT_EQ(I64[i], currentTestData.I64[i]) << msg;
711                 EXPECT_EQ(U8[i], currentTestData.U8[i]) << msg;
712                 EXPECT_EQ(U16[i], currentTestData.U16[i]) << msg;
713                 EXPECT_EQ(U32[i], currentTestData.U32[i]) << msg;
714                 EXPECT_EQ(U64[i], currentTestData.U64[i]) << msg;
715                 EXPECT_EQ(R32[i], currentTestData.R32[i]) << msg;
716                 EXPECT_EQ(R64[i], currentTestData.R64[i]) << msg;
717             }
718             hdf5Reader.Advance();
719         }
720     }
721 }
722 
723 // ADIOS2 write, ADIOS2 read
TEST_F(HDF5WriteReadTest,ADIOS2HDF5WriteADIOS2HDF5Read1D8)724 TEST_F(HDF5WriteReadTest, ADIOS2HDF5WriteADIOS2HDF5Read1D8)
725 {
726     // Each process would write a 1x8 array and all processes would
727     // form a mpiSize * Nx 1D array
728     const std::string fname = "ADIOS2HDF5WriteADIOS2HDF5Read1D8.h5";
729 
730     int mpiRank = 0, mpiSize = 1;
731     // Number of rows
732     const std::size_t Nx = 8;
733 
734     // Number of steps
735     const std::size_t NSteps = 3;
736 
737 #ifdef TEST_HDF5_MPI
738     MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
739     MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
740 #endif
741 
742     // Write test data using ADIOS2
743 
744 #ifdef TEST_HDF5_MPI
745     adios2::ADIOS adios(MPI_COMM_WORLD);
746 #else
747     adios2::ADIOS adios;
748 #endif
749     adios2::IO io = adios.DeclareIO("TestIO");
750 
751     // Declare 1D variables (NumOfProcesses * Nx)
752     // The local process' part (start, count) can be defined now or later
753     // before Write().
754     {
755         adios2::Dims shape{static_cast<unsigned int>(Nx * mpiSize)};
756         adios2::Dims start{static_cast<unsigned int>(Nx * mpiRank)};
757         adios2::Dims count{static_cast<unsigned int>(Nx)};
758 
759         io.DefineVariable<std::string>("iString");
760         io.DefineVariable<int8_t>("i8", shape, start, count);
761         io.DefineVariable<int16_t>("i16", shape, start, count);
762         io.DefineVariable<int32_t>("i32", shape, start, count);
763         io.DefineVariable<int64_t>("i64", shape, start, count);
764         io.DefineVariable<uint8_t>("u8", shape, start, count);
765         io.DefineVariable<uint16_t>("u16", shape, start, count);
766         io.DefineVariable<uint32_t>("u32", shape, start, count);
767         io.DefineVariable<uint64_t>("u64", shape, start, count);
768         io.DefineVariable<float>("r32", shape, start, count);
769         io.DefineVariable<double>("r64", shape, start, count);
770     }
771 
772     // Create the HDF5 Engine
773     io.SetEngine("HDF5");
774 
775     // HDf5 engine calls the HDF5 common object that calls the hDF5 library.
776     // The IO functionality, SetParameters and AddTransports will be added
777     // in the future. For now `io.AddTransport("file", {
778     // "library", "MPI"}});` is omitted.
779     // })
780     // io.AddTransport("File");
781 
782     adios2::Engine engine = io.Open(fname, adios2::Mode::Write);
783 
784     for (size_t step = 0; step < NSteps; ++step)
785     {
786         // Generate test data for each process uniquely
787         SmallTestData currentTestData =
788             generateNewSmallTestData(m_TestData, step, mpiRank, mpiSize);
789 
790         // Retrieve the variables that previously went out of scope
791         auto var_iString = io.InquireVariable<std::string>("iString");
792         auto var_i8 = io.InquireVariable<int8_t>("i8");
793         auto var_i16 = io.InquireVariable<int16_t>("i16");
794         auto var_i32 = io.InquireVariable<int32_t>("i32");
795         auto var_i64 = io.InquireVariable<int64_t>("i64");
796         auto var_u8 = io.InquireVariable<uint8_t>("u8");
797         auto var_u16 = io.InquireVariable<uint16_t>("u16");
798         auto var_u32 = io.InquireVariable<uint32_t>("u32");
799         auto var_u64 = io.InquireVariable<uint64_t>("u64");
800         auto var_r32 = io.InquireVariable<float>("r32");
801         auto var_r64 = io.InquireVariable<double>("r64");
802 
803         // Make a 1D selection to describe the local dimensions of the
804         // variable we write and its offsets in the global spaces
805 
806         adios2::Box<adios2::Dims> sel({mpiRank * Nx}, {Nx});
807 
808         EXPECT_THROW(var_iString.SetSelection(sel), std::invalid_argument);
809 
810         var_i8.SetSelection(sel);
811         var_i16.SetSelection(sel);
812         var_i32.SetSelection(sel);
813         var_i64.SetSelection(sel);
814         var_u8.SetSelection(sel);
815         var_u16.SetSelection(sel);
816         var_u32.SetSelection(sel);
817         var_u64.SetSelection(sel);
818         var_r32.SetSelection(sel);
819         var_r64.SetSelection(sel);
820 
821         // Write each one
822         // fill in the variable with values from starting index to
823         // starting index + count
824         engine.BeginStep();
825         engine.Put(var_iString, currentTestData.S1);
826         engine.Put(var_i8, currentTestData.I8.data());
827         engine.Put(var_i16, currentTestData.I16.data());
828         engine.Put(var_i32, currentTestData.I32.data());
829         engine.Put(var_i64, currentTestData.I64.data());
830         engine.Put(var_u8, currentTestData.U8.data());
831         engine.Put(var_u16, currentTestData.U16.data());
832         engine.Put(var_u32, currentTestData.U32.data());
833         engine.Put(var_u64, currentTestData.U64.data());
834         engine.Put(var_r32, currentTestData.R32.data());
835         engine.Put(var_r64, currentTestData.R64.data());
836         // Advance to the next time step
837         engine.EndStep();
838     }
839 
840     // Close the file
841     engine.Close();
842 
843     {
844         adios2::IO io = adios.DeclareIO("HDF5ReadIO");
845         io.SetEngine("HDF5");
846 
847         adios2::Engine hdf5Reader = io.Open(fname, adios2::Mode::Read);
848 
849         auto var_iString = io.InquireVariable<std::string>("iString");
850         EXPECT_TRUE(var_iString);
851         ASSERT_EQ(var_iString.Shape().size(), 0);
852         ASSERT_EQ(var_iString.Steps(), NSteps);
853 
854         auto var_i8 = io.InquireVariable<int8_t>("i8");
855         EXPECT_TRUE(var_i8);
856         ASSERT_EQ(var_i8.ShapeID(), adios2::ShapeID::GlobalArray);
857         ASSERT_EQ(var_i8.Steps(), NSteps);
858         ASSERT_EQ(var_i8.Shape()[0], mpiSize * Nx);
859 
860         auto var_i16 = io.InquireVariable<int16_t>("i16");
861         EXPECT_TRUE(var_i16);
862         ASSERT_EQ(var_i16.ShapeID(), adios2::ShapeID::GlobalArray);
863         ASSERT_EQ(var_i16.Steps(), NSteps);
864         ASSERT_EQ(var_i16.Shape()[0], mpiSize * Nx);
865 
866         auto var_i32 = io.InquireVariable<int32_t>("i32");
867         EXPECT_TRUE(var_i32);
868         ASSERT_EQ(var_i32.ShapeID(), adios2::ShapeID::GlobalArray);
869         ASSERT_EQ(var_i32.Steps(), NSteps);
870         ASSERT_EQ(var_i32.Shape()[0], mpiSize * Nx);
871 
872         auto var_i64 = io.InquireVariable<int64_t>("i64");
873         EXPECT_TRUE(var_i64);
874         ASSERT_EQ(var_i64.ShapeID(), adios2::ShapeID::GlobalArray);
875         ASSERT_EQ(var_i64.Steps(), NSteps);
876         ASSERT_EQ(var_i64.Shape()[0], mpiSize * Nx);
877 
878         auto var_u8 = io.InquireVariable<uint8_t>("u8");
879         EXPECT_TRUE(var_u8);
880         ASSERT_EQ(var_u8.ShapeID(), adios2::ShapeID::GlobalArray);
881         ASSERT_EQ(var_u8.Steps(), NSteps);
882         ASSERT_EQ(var_u8.Shape()[0], mpiSize * Nx);
883 
884         auto var_u16 = io.InquireVariable<uint16_t>("u16");
885         EXPECT_TRUE(var_u16);
886         ASSERT_EQ(var_u16.ShapeID(), adios2::ShapeID::GlobalArray);
887         ASSERT_EQ(var_u16.Steps(), NSteps);
888         ASSERT_EQ(var_u16.Shape()[0], mpiSize * Nx);
889 
890         auto var_u32 = io.InquireVariable<uint32_t>("u32");
891         EXPECT_TRUE(var_u32);
892         ASSERT_EQ(var_u32.ShapeID(), adios2::ShapeID::GlobalArray);
893         ASSERT_EQ(var_u32.Steps(), NSteps);
894         ASSERT_EQ(var_u32.Shape()[0], mpiSize * Nx);
895 
896         auto var_u64 = io.InquireVariable<uint64_t>("u64");
897         EXPECT_TRUE(var_u64);
898         ASSERT_EQ(var_u64.ShapeID(), adios2::ShapeID::GlobalArray);
899         ASSERT_EQ(var_u64.Steps(), NSteps);
900         ASSERT_EQ(var_u64.Shape()[0], mpiSize * Nx);
901 
902         auto var_r32 = io.InquireVariable<float>("r32");
903         EXPECT_TRUE(var_r32);
904         ASSERT_EQ(var_r32.ShapeID(), adios2::ShapeID::GlobalArray);
905         ASSERT_EQ(var_r32.Steps(), NSteps);
906         ASSERT_EQ(var_r32.Shape()[0], mpiSize * Nx);
907 
908         auto var_r64 = io.InquireVariable<double>("r64");
909         EXPECT_TRUE(var_r64);
910         ASSERT_EQ(var_r64.ShapeID(), adios2::ShapeID::GlobalArray);
911         ASSERT_EQ(var_r64.Steps(), NSteps);
912         ASSERT_EQ(var_r64.Shape()[0], mpiSize * Nx);
913 
914         // TODO: other types
915 
916         SmallTestData testData;
917 
918         std::string IString;
919         std::array<int8_t, Nx> I8;
920         std::array<int16_t, Nx> I16;
921         std::array<int32_t, Nx> I32;
922         std::array<int64_t, Nx> I64;
923         std::array<uint8_t, Nx> U8;
924         std::array<uint16_t, Nx> U16;
925         std::array<uint32_t, Nx> U32;
926         std::array<uint64_t, Nx> U64;
927         std::array<float, Nx> R32;
928         std::array<double, Nx> R64;
929 
930         const adios2::Dims start{mpiRank * Nx};
931         const adios2::Dims count{Nx};
932 
933         const adios2::Box<adios2::Dims> sel(start, count);
934 
935         var_i8.SetSelection(sel);
936         var_i16.SetSelection(sel);
937         var_i32.SetSelection(sel);
938         var_i64.SetSelection(sel);
939 
940         var_u8.SetSelection(sel);
941         var_u16.SetSelection(sel);
942         var_u32.SetSelection(sel);
943         var_u64.SetSelection(sel);
944 
945         var_r32.SetSelection(sel);
946         var_r64.SetSelection(sel);
947 
948         for (size_t t = 0; t < NSteps; ++t)
949         {
950             var_i8.SetStepSelection({t, 1});
951             var_i16.SetStepSelection({t, 1});
952             var_i32.SetStepSelection({t, 1});
953             var_i64.SetStepSelection({t, 1});
954 
955             var_u8.SetStepSelection({t, 1});
956             var_u16.SetStepSelection({t, 1});
957             var_u32.SetStepSelection({t, 1});
958             var_u64.SetStepSelection({t, 1});
959 
960             var_r32.SetStepSelection({t, 1});
961             var_r64.SetStepSelection({t, 1});
962 
963             // Generate test data for each rank uniquely
964             SmallTestData currentTestData = generateNewSmallTestData(
965                 m_TestData, static_cast<int>(t), mpiRank, mpiSize);
966 
967             hdf5Reader.Get(var_iString, IString);
968 
969             hdf5Reader.Get(var_i8, I8.data());
970             hdf5Reader.Get(var_i16, I16.data());
971             hdf5Reader.Get(var_i32, I32.data());
972             hdf5Reader.Get(var_i64, I64.data());
973 
974             hdf5Reader.Get(var_u8, U8.data());
975             hdf5Reader.Get(var_u16, U16.data());
976             hdf5Reader.Get(var_u32, U32.data());
977             hdf5Reader.Get(var_u64, U64.data());
978 
979             hdf5Reader.Get(var_r32, R32.data());
980             hdf5Reader.Get(var_r64, R64.data());
981             hdf5Reader.PerformGets();
982 
983             EXPECT_EQ(IString, currentTestData.S1);
984 
985             for (size_t i = 0; i < Nx; ++i)
986             {
987                 std::stringstream ss;
988                 ss << "t=" << t << " i=" << i << " rank=" << mpiRank;
989                 std::string msg = ss.str();
990 
991                 EXPECT_EQ(I8[i], currentTestData.I8[i]) << msg;
992                 EXPECT_EQ(I16[i], currentTestData.I16[i]) << msg;
993                 EXPECT_EQ(I32[i], currentTestData.I32[i]) << msg;
994                 EXPECT_EQ(I64[i], currentTestData.I64[i]) << msg;
995                 EXPECT_EQ(U8[i], currentTestData.U8[i]) << msg;
996                 EXPECT_EQ(U16[i], currentTestData.U16[i]) << msg;
997                 EXPECT_EQ(U32[i], currentTestData.U32[i]) << msg;
998                 EXPECT_EQ(U64[i], currentTestData.U64[i]) << msg;
999                 EXPECT_EQ(R32[i], currentTestData.R32[i]) << msg;
1000                 EXPECT_EQ(R64[i], currentTestData.R64[i]) << msg;
1001             }
1002         }
1003         hdf5Reader.Close();
1004     }
1005 }
1006 
1007 // Native HDF5 write, ADIOS2 read
TEST_F(HDF5WriteReadTest,HDF5WriteADIOS2HDF5Read1D8)1008 TEST_F(HDF5WriteReadTest, HDF5WriteADIOS2HDF5Read1D8)
1009 {
1010     std::string fname = "HDF5WriteADIOS2HDF5Read1D8.h5";
1011 
1012     int mpiRank = 0, mpiSize = 1;
1013     // Number of rows
1014     const std::size_t Nx = 8;
1015 
1016     // Number of steps
1017     const std::size_t NSteps = 3;
1018 
1019     {
1020 #ifdef TEST_HDF5_MPI
1021         MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
1022         MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
1023 
1024         HDF5NativeWriter h5writer(fname, MPI_COMM_WORLD);
1025 #else
1026         HDF5NativeWriter h5writer(fname);
1027 #endif
1028 
1029         int dimSize = 1;
1030         hsize_t global_dims[1] = {Nx * mpiSize};
1031         hsize_t count[1] = {Nx};
1032         hsize_t offset[1] = {Nx * mpiRank};
1033 
1034         for (size_t step = 0; step < NSteps; ++step)
1035         {
1036             // Generate test data for each process uniquely
1037             SmallTestData currentTestData =
1038                 generateNewSmallTestData(m_TestData, step, mpiRank, mpiSize);
1039 
1040             h5writer.CreateAndStoreScalar("iString", H5T_STRING,
1041                                           currentTestData.S1.data());
1042             h5writer.CreateAndStoreVar("i8", dimSize, H5T_NATIVE_INT8,
1043                                        global_dims, offset, count,
1044                                        currentTestData.I8.data());
1045             h5writer.CreateAndStoreVar("i16", dimSize, H5T_NATIVE_SHORT,
1046                                        global_dims, offset, count,
1047                                        currentTestData.I16.data());
1048             h5writer.CreateAndStoreVar("i32", dimSize, H5T_NATIVE_INT,
1049                                        global_dims, offset, count,
1050                                        currentTestData.I32.data());
1051             h5writer.CreateAndStoreVar("i64", dimSize, H5T_NATIVE_LONG,
1052                                        global_dims, offset, count,
1053                                        currentTestData.I64.data());
1054             h5writer.CreateAndStoreVar("u8", dimSize, H5T_NATIVE_UCHAR,
1055                                        global_dims, offset, count,
1056                                        currentTestData.U8.data());
1057             h5writer.CreateAndStoreVar("u16", dimSize, H5T_NATIVE_USHORT,
1058                                        global_dims, offset, count,
1059                                        currentTestData.U16.data());
1060             h5writer.CreateAndStoreVar("u32", dimSize, H5T_NATIVE_UINT,
1061                                        global_dims, offset, count,
1062                                        currentTestData.U32.data());
1063             h5writer.CreateAndStoreVar("u64", dimSize, H5T_NATIVE_ULONG,
1064                                        global_dims, offset, count,
1065                                        currentTestData.U64.data());
1066             h5writer.CreateAndStoreVar("r32", dimSize, H5T_NATIVE_FLOAT,
1067                                        global_dims, offset, count,
1068                                        currentTestData.R32.data());
1069             h5writer.CreateAndStoreVar("r64", dimSize, H5T_NATIVE_DOUBLE,
1070                                        global_dims, offset, count,
1071                                        currentTestData.R64.data());
1072             h5writer.Advance();
1073         }
1074     }
1075 
1076     { // ADIOS2 read back
1077 
1078         // Write test data using ADIOS2
1079 
1080 #ifdef TEST_HDF5_MPI
1081         adios2::ADIOS adios(MPI_COMM_WORLD);
1082 #else
1083         adios2::ADIOS adios;
1084 #endif
1085         adios2::IO io = adios.DeclareIO("HDF5ReadIO");
1086         io.SetEngine("HDF5");
1087 
1088         adios2::Engine hdf5Reader = io.Open(fname, adios2::Mode::Read);
1089 
1090         auto var_iString = io.InquireVariable<std::string>("iString");
1091         EXPECT_TRUE(var_iString);
1092         ASSERT_EQ(var_iString.Shape().size(), 0);
1093         ASSERT_EQ(var_iString.Steps(), NSteps);
1094 
1095         auto var_i8 = io.InquireVariable<int8_t>("i8");
1096         EXPECT_TRUE(var_i8);
1097         ASSERT_EQ(var_i8.ShapeID(), adios2::ShapeID::GlobalArray);
1098         ASSERT_EQ(var_i8.Steps(), NSteps);
1099         ASSERT_EQ(var_i8.Shape()[0], mpiSize * Nx);
1100 
1101         auto var_i16 = io.InquireVariable<int16_t>("i16");
1102         EXPECT_TRUE(var_i16);
1103         ASSERT_EQ(var_i16.ShapeID(), adios2::ShapeID::GlobalArray);
1104         ASSERT_EQ(var_i16.Steps(), NSteps);
1105         ASSERT_EQ(var_i16.Shape()[0], mpiSize * Nx);
1106 
1107         auto var_i32 = io.InquireVariable<int32_t>("i32");
1108         EXPECT_TRUE(var_i32);
1109         ASSERT_EQ(var_i32.ShapeID(), adios2::ShapeID::GlobalArray);
1110         ASSERT_EQ(var_i32.Steps(), NSteps);
1111         ASSERT_EQ(var_i32.Shape()[0], mpiSize * Nx);
1112 
1113         auto var_i64 = io.InquireVariable<int64_t>("i64");
1114         EXPECT_TRUE(var_i64);
1115         ASSERT_EQ(var_i64.ShapeID(), adios2::ShapeID::GlobalArray);
1116         ASSERT_EQ(var_i64.Steps(), NSteps);
1117         ASSERT_EQ(var_i64.Shape()[0], mpiSize * Nx);
1118 
1119         auto var_u8 = io.InquireVariable<uint8_t>("u8");
1120         EXPECT_TRUE(var_u8);
1121         ASSERT_EQ(var_u8.ShapeID(), adios2::ShapeID::GlobalArray);
1122         ASSERT_EQ(var_u8.Steps(), NSteps);
1123         ASSERT_EQ(var_u8.Shape()[0], mpiSize * Nx);
1124 
1125         auto var_u16 = io.InquireVariable<uint16_t>("u16");
1126         EXPECT_TRUE(var_u16);
1127         ASSERT_EQ(var_u16.ShapeID(), adios2::ShapeID::GlobalArray);
1128         ASSERT_EQ(var_u16.Steps(), NSteps);
1129         ASSERT_EQ(var_u16.Shape()[0], mpiSize * Nx);
1130 
1131         auto var_u32 = io.InquireVariable<uint32_t>("u32");
1132         EXPECT_TRUE(var_u32);
1133         ASSERT_EQ(var_u32.ShapeID(), adios2::ShapeID::GlobalArray);
1134         ASSERT_EQ(var_u32.Steps(), NSteps);
1135         ASSERT_EQ(var_u32.Shape()[0], mpiSize * Nx);
1136 
1137         auto var_u64 = io.InquireVariable<uint64_t>("u64");
1138         EXPECT_TRUE(var_u64);
1139         ASSERT_EQ(var_u64.ShapeID(), adios2::ShapeID::GlobalArray);
1140         ASSERT_EQ(var_u64.Steps(), NSteps);
1141         ASSERT_EQ(var_u64.Shape()[0], mpiSize * Nx);
1142 
1143         auto var_r32 = io.InquireVariable<float>("r32");
1144         EXPECT_TRUE(var_r32);
1145         ASSERT_EQ(var_r32.ShapeID(), adios2::ShapeID::GlobalArray);
1146         ASSERT_EQ(var_r32.Steps(), NSteps);
1147         ASSERT_EQ(var_r32.Shape()[0], mpiSize * Nx);
1148 
1149         auto var_r64 = io.InquireVariable<double>("r64");
1150         EXPECT_TRUE(var_r64);
1151         ASSERT_EQ(var_r64.ShapeID(), adios2::ShapeID::GlobalArray);
1152         ASSERT_EQ(var_r64.Steps(), NSteps);
1153         ASSERT_EQ(var_r64.Shape()[0], mpiSize * Nx);
1154 
1155         // TODO: other types
1156 
1157         SmallTestData testData;
1158 
1159         std::string IString;
1160         std::array<int8_t, Nx> I8;
1161         std::array<int16_t, Nx> I16;
1162         std::array<int32_t, Nx> I32;
1163         std::array<int64_t, Nx> I64;
1164         std::array<uint8_t, Nx> U8;
1165         std::array<uint16_t, Nx> U16;
1166         std::array<uint32_t, Nx> U32;
1167         std::array<uint64_t, Nx> U64;
1168         std::array<float, Nx> R32;
1169         std::array<double, Nx> R64;
1170 
1171         const adios2::Dims start{mpiRank * Nx};
1172         const adios2::Dims count{Nx};
1173 
1174         const adios2::Box<adios2::Dims> sel(start, count);
1175 
1176         var_i8.SetSelection(sel);
1177         var_i16.SetSelection(sel);
1178         var_i32.SetSelection(sel);
1179         var_i64.SetSelection(sel);
1180 
1181         var_u8.SetSelection(sel);
1182         var_u16.SetSelection(sel);
1183         var_u32.SetSelection(sel);
1184         var_u64.SetSelection(sel);
1185 
1186         var_r32.SetSelection(sel);
1187         var_r64.SetSelection(sel);
1188 
1189         for (size_t t = 0; t < NSteps; ++t)
1190         {
1191             var_i8.SetStepSelection({t, 1});
1192             var_i16.SetStepSelection({t, 1});
1193             var_i32.SetStepSelection({t, 1});
1194             var_i64.SetStepSelection({t, 1});
1195 
1196             var_u8.SetStepSelection({t, 1});
1197             var_u16.SetStepSelection({t, 1});
1198             var_u32.SetStepSelection({t, 1});
1199             var_u64.SetStepSelection({t, 1});
1200 
1201             var_r32.SetStepSelection({t, 1});
1202             var_r64.SetStepSelection({t, 1});
1203 
1204             // Generate test data for each rank uniquely
1205             SmallTestData currentTestData = generateNewSmallTestData(
1206                 m_TestData, static_cast<int>(t), mpiRank, mpiSize);
1207 
1208             hdf5Reader.Get(var_iString, IString);
1209 
1210             hdf5Reader.Get(var_i8, I8.data());
1211             hdf5Reader.Get(var_i16, I16.data());
1212             hdf5Reader.Get(var_i32, I32.data());
1213             hdf5Reader.Get(var_i64, I64.data());
1214 
1215             hdf5Reader.Get(var_u8, U8.data());
1216             hdf5Reader.Get(var_u16, U16.data());
1217             hdf5Reader.Get(var_u32, U32.data());
1218             hdf5Reader.Get(var_u64, U64.data());
1219 
1220             hdf5Reader.Get(var_r32, R32.data());
1221             hdf5Reader.Get(var_r64, R64.data());
1222 
1223             hdf5Reader.PerformGets();
1224 
1225             EXPECT_EQ(IString, currentTestData.S1);
1226 
1227             for (size_t i = 0; i < Nx; ++i)
1228             {
1229                 std::stringstream ss;
1230                 ss << "t=" << t << " i=" << i << " rank=" << mpiRank;
1231                 std::string msg = ss.str();
1232 
1233                 EXPECT_EQ(I8[i], currentTestData.I8[i]) << msg;
1234                 EXPECT_EQ(I16[i], currentTestData.I16[i]) << msg;
1235                 EXPECT_EQ(I32[i], currentTestData.I32[i]) << msg;
1236                 EXPECT_EQ(I64[i], currentTestData.I64[i]) << msg;
1237                 EXPECT_EQ(U8[i], currentTestData.U8[i]) << msg;
1238                 EXPECT_EQ(U16[i], currentTestData.U16[i]) << msg;
1239                 EXPECT_EQ(U32[i], currentTestData.U32[i]) << msg;
1240                 EXPECT_EQ(U64[i], currentTestData.U64[i]) << msg;
1241                 EXPECT_EQ(R32[i], currentTestData.R32[i]) << msg;
1242                 EXPECT_EQ(R64[i], currentTestData.R64[i]) << msg;
1243             }
1244         }
1245         hdf5Reader.Close();
1246     }
1247 }
1248 
1249 //******************************************************************************
1250 // 2D 2x4 test data
1251 //******************************************************************************
1252 
1253 // ADIOS2 write, native HDF5 read
TEST_F(HDF5WriteReadTest,ADIOS2HDF5WriteHDF5Read2D2x4)1254 TEST_F(HDF5WriteReadTest, ADIOS2HDF5WriteHDF5Read2D2x4)
1255 {
1256     // Each process would write a 2x4 array and all processes would
1257     // form a 2D 2 * (numberOfProcess*Nx) matrix where Nx is 4 here
1258     std::string fname = "ADIOS2HDF5WriteHDF5Read2D2x4Test.h5";
1259 
1260     int mpiRank = 0, mpiSize = 1;
1261     // Number of rows
1262     const std::size_t Nx = 4;
1263 
1264     // Number of rows
1265     const std::size_t Ny = 2;
1266 
1267     // Number of steps
1268     const std::size_t NSteps = 3;
1269 
1270 #ifdef TEST_HDF5_MPI
1271     MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
1272     MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
1273 #endif
1274 
1275     // Write test data using ADIOS2
1276     {
1277 #ifdef TEST_HDF5_MPI
1278         adios2::ADIOS adios(MPI_COMM_WORLD);
1279 #else
1280         adios2::ADIOS adios;
1281 #endif
1282         adios2::IO io = adios.DeclareIO("TestIO");
1283 
1284         // Declare 2D variables (Ny * (NumOfProcesses * Nx))
1285         // The local process' part (start, count) can be defined now or later
1286         // before Write().
1287         {
1288             adios2::Dims shape{static_cast<unsigned int>(Ny),
1289                                static_cast<unsigned int>(Nx * mpiSize)};
1290             adios2::Dims start{static_cast<unsigned int>(0),
1291                                static_cast<unsigned int>(mpiRank * Nx)};
1292             adios2::Dims count{static_cast<unsigned int>(Ny),
1293                                static_cast<unsigned int>(Nx)};
1294             auto var_iString = io.DefineVariable<std::string>("iString");
1295             auto var_i8 = io.DefineVariable<int8_t>("i8", shape, start, count);
1296             auto var_i16 =
1297                 io.DefineVariable<int16_t>("i16", shape, start, count);
1298             auto var_i32 =
1299                 io.DefineVariable<int32_t>("i32", shape, start, count);
1300             auto var_i64 =
1301                 io.DefineVariable<int64_t>("i64", shape, start, count);
1302             auto var_u8 = io.DefineVariable<uint8_t>("u8", shape, start, count);
1303             auto var_u16 =
1304                 io.DefineVariable<uint16_t>("u16", shape, start, count);
1305             auto var_u32 =
1306                 io.DefineVariable<uint32_t>("u32", shape, start, count);
1307             auto var_u64 =
1308                 io.DefineVariable<uint64_t>("u64", shape, start, count);
1309             auto var_r32 = io.DefineVariable<float>("r32", shape, start, count);
1310             auto var_r64 =
1311                 io.DefineVariable<double>("r64", shape, start, count);
1312         }
1313 
1314         // Create the HDF5 Engine
1315         io.SetEngine("HDF5");
1316 
1317         // HDf5 engine calls the HDF5 common object that calls the hDF5 library.
1318         // The IO functionality, SetParameters and AddTransports will be added
1319         // in the future. For now `io.AddTransport("file", {
1320         // "library", "MPI"}});` is omitted.
1321         // })
1322         io.AddTransport("file");
1323 
1324         adios2::Engine engine = io.Open(fname, adios2::Mode::Write);
1325 
1326         for (size_t step = 0; step < NSteps; ++step)
1327         {
1328             // Generate test data for each process uniquely
1329             SmallTestData currentTestData =
1330                 generateNewSmallTestData(m_TestData, step, mpiRank, mpiSize);
1331 
1332             // Retrieve the variables that previously went out of scope
1333             auto var_iString = io.InquireVariable<std::string>("iString");
1334             auto var_i8 = io.InquireVariable<int8_t>("i8");
1335             auto var_i16 = io.InquireVariable<int16_t>("i16");
1336             auto var_i32 = io.InquireVariable<int32_t>("i32");
1337             auto var_i64 = io.InquireVariable<int64_t>("i64");
1338             auto var_u8 = io.InquireVariable<uint8_t>("u8");
1339             auto var_u16 = io.InquireVariable<uint16_t>("u16");
1340             auto var_u32 = io.InquireVariable<uint32_t>("u32");
1341             auto var_u64 = io.InquireVariable<uint64_t>("u64");
1342             auto var_r32 = io.InquireVariable<float>("r32");
1343             auto var_r64 = io.InquireVariable<double>("r64");
1344 
1345             // Make a 2D selection to describe the local dimensions of the
1346             // variable we write and its offsets in the global spaces
1347             adios2::Box<adios2::Dims> sel(
1348                 {0, static_cast<unsigned int>(mpiRank * Nx)}, {Ny, Nx});
1349             var_i8.SetSelection(sel);
1350             var_i16.SetSelection(sel);
1351             var_i32.SetSelection(sel);
1352             var_i64.SetSelection(sel);
1353             var_u8.SetSelection(sel);
1354             var_u16.SetSelection(sel);
1355             var_u32.SetSelection(sel);
1356             var_u64.SetSelection(sel);
1357             var_r32.SetSelection(sel);
1358             var_r64.SetSelection(sel);
1359 
1360             // Write each one
1361             // fill in the variable with values from starting index to
1362             // starting index + count
1363             engine.Put(var_iString, currentTestData.S1);
1364             engine.Put(var_i8, currentTestData.I8.data());
1365             engine.Put(var_i16, currentTestData.I16.data());
1366             engine.Put(var_i32, currentTestData.I32.data());
1367             engine.Put(var_i64, currentTestData.I64.data());
1368             engine.Put(var_u8, currentTestData.U8.data());
1369             engine.Put(var_u16, currentTestData.U16.data());
1370             engine.Put(var_u32, currentTestData.U32.data());
1371             engine.Put(var_u64, currentTestData.U64.data());
1372             engine.Put(var_r32, currentTestData.R32.data());
1373             engine.Put(var_r64, currentTestData.R64.data());
1374 
1375             // Advance to the next time step
1376             engine.EndStep();
1377         }
1378 
1379         // Close the file
1380         engine.Close();
1381     }
1382 
1383     {
1384         HDF5NativeReader hdf5Reader(fname);
1385 
1386         std::string IString;
1387         const size_t arraySize = Nx * Ny;
1388         std::array<int8_t, arraySize> I8;
1389         std::array<int16_t, arraySize> I16;
1390         std::array<int32_t, arraySize> I32;
1391         std::array<int64_t, arraySize> I64;
1392         std::array<uint8_t, arraySize> U8;
1393         std::array<uint16_t, arraySize> U16;
1394         std::array<uint32_t, arraySize> U32;
1395         std::array<uint64_t, arraySize> U64;
1396         std::array<float, arraySize> R32;
1397         std::array<double, arraySize> R64;
1398         // 2D
1399         hsize_t count[2], offset[2];
1400 
1401         offset[0] = 0;
1402         offset[1] = mpiRank * Nx;
1403         count[0] = Ny;
1404         count[1] = Nx;
1405 
1406         size_t globalArraySize = Nx * mpiSize;
1407 
1408         // For each variable, we would verify its global size and type.
1409         // Then we would retrieve the data back which is written by the
1410         // current process and validate the value
1411         for (size_t t = 0; t < NSteps; ++t)
1412         {
1413             SmallTestData currentTestData =
1414                 generateNewSmallTestData(m_TestData, t, mpiRank, mpiSize);
1415 
1416             std::vector<hsize_t> gDims;
1417             hid_t h5Type;
1418 
1419             hdf5Reader.GetVarInfo("iString", gDims, h5Type);
1420             // ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_IN), 1);
1421             ASSERT_EQ(gDims.size(), 0);
1422             hdf5Reader.ReadString("iString", IString);
1423 
1424             hdf5Reader.GetVarInfo("i8", gDims, h5Type);
1425             ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_INT8), 1);
1426             ASSERT_EQ(gDims.size(), 2);
1427             ASSERT_EQ(gDims[0], 2);
1428             ASSERT_EQ(gDims[1], globalArraySize);
1429             hdf5Reader.ReadVar("i8", I8.data(), offset, count, arraySize);
1430 
1431             hdf5Reader.GetVarInfo("i16", gDims, h5Type);
1432             ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_SHORT), 1);
1433             ASSERT_EQ(gDims.size(), 2);
1434             ASSERT_EQ(gDims[0], 2);
1435             ASSERT_EQ(gDims[1], globalArraySize);
1436             hdf5Reader.ReadVar("i16", I16.data(), offset, count, arraySize);
1437 
1438             hdf5Reader.GetVarInfo("i32", gDims, h5Type);
1439             ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_INT), 1);
1440             ASSERT_EQ(gDims.size(), 2);
1441             ASSERT_EQ(gDims[0], 2);
1442             ASSERT_EQ(gDims[1], globalArraySize);
1443             hdf5Reader.ReadVar("i32", I32.data(), offset, count, arraySize);
1444 
1445             hdf5Reader.GetVarInfo("i64", gDims, h5Type);
1446             ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_LONG), 1);
1447             ASSERT_EQ(gDims.size(), 2);
1448             ASSERT_EQ(gDims[0], 2);
1449             ASSERT_EQ(gDims[1], globalArraySize);
1450             hdf5Reader.ReadVar("i64", I64.data(), offset, count, arraySize);
1451 
1452             hdf5Reader.GetVarInfo("u8", gDims, h5Type);
1453             ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_UCHAR), 1);
1454             ASSERT_EQ(gDims.size(), 2);
1455             ASSERT_EQ(gDims[0], 2);
1456             ASSERT_EQ(gDims[1], globalArraySize);
1457             hdf5Reader.ReadVar("u8", U8.data(), offset, count, arraySize);
1458 
1459             hdf5Reader.GetVarInfo("u16", gDims, h5Type);
1460             ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_USHORT), 1);
1461             ASSERT_EQ(gDims.size(), 2);
1462             ASSERT_EQ(gDims[0], 2);
1463             ASSERT_EQ(gDims[1], globalArraySize);
1464             hdf5Reader.ReadVar("u16", U16.data(), offset, count, arraySize);
1465 
1466             hdf5Reader.GetVarInfo("u32", gDims, h5Type);
1467             ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_UINT), 1);
1468             ASSERT_EQ(gDims.size(), 2);
1469             ASSERT_EQ(gDims[0], 2);
1470             ASSERT_EQ(gDims[1], globalArraySize);
1471             hdf5Reader.ReadVar("u32", U32.data(), offset, count, arraySize);
1472 
1473             hdf5Reader.GetVarInfo("u64", gDims, h5Type);
1474             ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_ULONG), 1);
1475             ASSERT_EQ(gDims.size(), 2);
1476             ASSERT_EQ(gDims[0], 2);
1477             ASSERT_EQ(gDims[1], globalArraySize);
1478             hdf5Reader.ReadVar("u64", U64.data(), offset, count, arraySize);
1479 
1480             hdf5Reader.GetVarInfo("r32", gDims, h5Type);
1481             ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_FLOAT), 1);
1482             ASSERT_EQ(gDims.size(), 2);
1483             ASSERT_EQ(gDims[0], 2);
1484             ASSERT_EQ(gDims[1], globalArraySize);
1485             hdf5Reader.ReadVar("r32", R32.data(), offset, count, arraySize);
1486 
1487             hdf5Reader.GetVarInfo("r64", gDims, h5Type);
1488             ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_DOUBLE), 1);
1489             ASSERT_EQ(gDims.size(), 2);
1490             ASSERT_EQ(gDims[0], 2);
1491             ASSERT_EQ(gDims[1], globalArraySize);
1492             hdf5Reader.ReadVar("r64", R64.data(), offset, count, arraySize);
1493 
1494             EXPECT_EQ(IString, currentTestData.S1);
1495 
1496             // Check if it's correct
1497             for (size_t i = 0; i < Nx; ++i)
1498             {
1499                 std::stringstream ss;
1500                 ss << "t=" << t << " i=" << i << " rank=" << mpiRank;
1501                 std::string msg = ss.str();
1502 
1503                 EXPECT_EQ(I8[i], currentTestData.I8[i]) << msg;
1504                 EXPECT_EQ(I16[i], currentTestData.I16[i]) << msg;
1505                 EXPECT_EQ(I32[i], currentTestData.I32[i]) << msg;
1506                 EXPECT_EQ(I64[i], currentTestData.I64[i]) << msg;
1507                 EXPECT_EQ(U8[i], currentTestData.U8[i]) << msg;
1508                 EXPECT_EQ(U16[i], currentTestData.U16[i]) << msg;
1509                 EXPECT_EQ(U32[i], currentTestData.U32[i]) << msg;
1510                 EXPECT_EQ(U64[i], currentTestData.U64[i]) << msg;
1511                 EXPECT_EQ(R32[i], currentTestData.R32[i]) << msg;
1512                 EXPECT_EQ(R64[i], currentTestData.R64[i]) << msg;
1513             }
1514             hdf5Reader.Advance();
1515         }
1516     }
1517 }
1518 
1519 // ADIOS2 write, ADIOS2 read
TEST_F(HDF5WriteReadTest,ADIOS2HDF5WriteADIOS2HDF5Read2D2x4)1520 TEST_F(HDF5WriteReadTest, ADIOS2HDF5WriteADIOS2HDF5Read2D2x4)
1521 {
1522     std::string fname = "ADIOS2HDF5WriteADIOS2HDF5Read2D2x4Test.h5";
1523     int mpiRank = 0, mpiSize = 1;
1524     // Number of rows
1525     const std::size_t Nx = 4;
1526 
1527     // Number of rows
1528     const std::size_t Ny = 2;
1529 
1530     // Number of steps
1531     const std::size_t NSteps = 3;
1532 
1533 #ifdef TEST_HDF5_MPI
1534     MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
1535     MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
1536 #endif
1537 
1538 #ifdef TEST_HDF5_MPI
1539     adios2::ADIOS adios(MPI_COMM_WORLD);
1540 #else
1541     adios2::ADIOS adios;
1542 #endif
1543     // Write test data using ADIOS2
1544     {
1545         adios2::IO io = adios.DeclareIO("TestIO");
1546 
1547         // Declare 2D variables (Ny * (NumOfProcesses * Nx))
1548         // The local process' part (start, count) can be defined now or later
1549         // before Write().
1550         {
1551             adios2::Dims shape{static_cast<unsigned int>(Ny),
1552                                static_cast<unsigned int>(Nx * mpiSize)};
1553             adios2::Dims start{static_cast<unsigned int>(0),
1554                                static_cast<unsigned int>(mpiRank * Nx)};
1555             adios2::Dims count{static_cast<unsigned int>(Ny),
1556                                static_cast<unsigned int>(Nx)};
1557 
1558             auto var_iString = io.DefineVariable<std::string>("iString");
1559 
1560             auto var_i8 = io.DefineVariable<int8_t>("i8", shape, start, count);
1561             auto var_i16 =
1562                 io.DefineVariable<int16_t>("i16", shape, start, count);
1563             auto var_i32 =
1564                 io.DefineVariable<int32_t>("i32", shape, start, count);
1565             auto var_i64 =
1566                 io.DefineVariable<int64_t>("i64", shape, start, count);
1567             auto var_u8 = io.DefineVariable<uint8_t>("u8", shape, start, count);
1568             auto var_u16 =
1569                 io.DefineVariable<uint16_t>("u16", shape, start, count);
1570             auto var_u32 =
1571                 io.DefineVariable<uint32_t>("u32", shape, start, count);
1572             auto var_u64 =
1573                 io.DefineVariable<uint64_t>("u64", shape, start, count);
1574             auto var_r32 = io.DefineVariable<float>("r32", shape, start, count);
1575             auto var_r64 =
1576                 io.DefineVariable<double>("r64", shape, start, count);
1577         }
1578 
1579         // Create the HDF5 Engine
1580         io.SetEngine("HDF5");
1581 
1582         // HDf5 engine calls the HDF5 common object that calls the hDF5 library.
1583         // The IO functionality, SetParameters and AddTransports will be added
1584         // in the future. For now `io.AddTransport("file", {
1585         // "library", "MPI"}});` is omitted.
1586         // })
1587         io.AddTransport("file");
1588 
1589         adios2::Engine engine = io.Open(fname, adios2::Mode::Write);
1590 
1591         for (size_t step = 0; step < NSteps; ++step)
1592         {
1593             // Generate test data for each process uniquely
1594             SmallTestData currentTestData =
1595                 generateNewSmallTestData(m_TestData, step, mpiRank, mpiSize);
1596 
1597             // Retrieve the variables that previously went out of scope
1598             auto var_iString = io.InquireVariable<std::string>("iString");
1599             auto var_i8 = io.InquireVariable<int8_t>("i8");
1600             auto var_i16 = io.InquireVariable<int16_t>("i16");
1601             auto var_i32 = io.InquireVariable<int32_t>("i32");
1602             auto var_i64 = io.InquireVariable<int64_t>("i64");
1603             auto var_u8 = io.InquireVariable<uint8_t>("u8");
1604             auto var_u16 = io.InquireVariable<uint16_t>("u16");
1605             auto var_u32 = io.InquireVariable<uint32_t>("u32");
1606             auto var_u64 = io.InquireVariable<uint64_t>("u64");
1607             auto var_r32 = io.InquireVariable<float>("r32");
1608             auto var_r64 = io.InquireVariable<double>("r64");
1609 
1610             // Make a 2D selection to describe the local dimensions of the
1611             // variable we write and its offsets in the global spaces
1612             adios2::Box<adios2::Dims> sel(
1613                 {0, static_cast<unsigned int>(mpiRank * Nx)}, {Ny, Nx});
1614             var_i8.SetSelection(sel);
1615             var_i16.SetSelection(sel);
1616             var_i32.SetSelection(sel);
1617             var_i64.SetSelection(sel);
1618             var_u8.SetSelection(sel);
1619             var_u16.SetSelection(sel);
1620             var_u32.SetSelection(sel);
1621             var_u64.SetSelection(sel);
1622             var_r32.SetSelection(sel);
1623             var_r64.SetSelection(sel);
1624 
1625             // Write each one
1626             // fill in the variable with values from starting index to
1627             // starting index + count
1628             engine.Put(var_iString, currentTestData.S1);
1629             engine.Put(var_i8, currentTestData.I8.data());
1630             engine.Put(var_i16, currentTestData.I16.data());
1631             engine.Put(var_i32, currentTestData.I32.data());
1632             engine.Put(var_i64, currentTestData.I64.data());
1633             engine.Put(var_u8, currentTestData.U8.data());
1634             engine.Put(var_u16, currentTestData.U16.data());
1635             engine.Put(var_u32, currentTestData.U32.data());
1636             engine.Put(var_u64, currentTestData.U64.data());
1637             engine.Put(var_r32, currentTestData.R32.data());
1638             engine.Put(var_r64, currentTestData.R64.data());
1639 
1640             // Advance to the next time step
1641             engine.EndStep();
1642         }
1643 
1644         // Close the file
1645         engine.Close();
1646     }
1647 
1648     { // reading back
1649         adios2::IO io = adios.DeclareIO("HDF5ReadIO");
1650         io.SetEngine("HDF5");
1651 
1652         adios2::Engine hdf5Reader = io.Open(fname, adios2::Mode::Read);
1653 
1654         auto var_iString = io.InquireVariable<std::string>("iString");
1655         EXPECT_TRUE(var_iString);
1656         ASSERT_EQ(var_iString.Shape().size(), 0);
1657         ASSERT_EQ(var_iString.Steps(), NSteps);
1658 
1659         auto var_i8 = io.InquireVariable<int8_t>("i8");
1660         EXPECT_TRUE(var_i8);
1661         ASSERT_EQ(var_i8.ShapeID(), adios2::ShapeID::GlobalArray);
1662         ASSERT_EQ(var_i8.Steps(), NSteps);
1663         ASSERT_EQ(var_i8.Shape()[0], Ny);
1664         ASSERT_EQ(var_i8.Shape()[1], static_cast<size_t>(mpiSize * Nx));
1665 
1666         auto var_i16 = io.InquireVariable<int16_t>("i16");
1667         EXPECT_TRUE(var_i16);
1668         ASSERT_EQ(var_i16.ShapeID(), adios2::ShapeID::GlobalArray);
1669         ASSERT_EQ(var_i16.Steps(), NSteps);
1670         ASSERT_EQ(var_i16.Shape()[0], Ny);
1671         ASSERT_EQ(var_i16.Shape()[1], static_cast<size_t>(mpiSize * Nx));
1672 
1673         auto var_i32 = io.InquireVariable<int32_t>("i32");
1674         EXPECT_TRUE(var_i32);
1675         ASSERT_EQ(var_i32.ShapeID(), adios2::ShapeID::GlobalArray);
1676         ASSERT_EQ(var_i32.Steps(), NSteps);
1677         ASSERT_EQ(var_i32.Shape()[0], Ny);
1678         ASSERT_EQ(var_i32.Shape()[1], static_cast<size_t>(mpiSize * Nx));
1679 
1680         auto var_i64 = io.InquireVariable<int64_t>("i64");
1681         EXPECT_TRUE(var_i64);
1682         ASSERT_EQ(var_i64.ShapeID(), adios2::ShapeID::GlobalArray);
1683         ASSERT_EQ(var_i64.Steps(), NSteps);
1684         ASSERT_EQ(var_i64.Shape()[0], Ny);
1685         ASSERT_EQ(var_i64.Shape()[1], static_cast<size_t>(mpiSize * Nx));
1686 
1687         auto var_u8 = io.InquireVariable<uint8_t>("u8");
1688         EXPECT_TRUE(var_u8);
1689         ASSERT_EQ(var_u8.ShapeID(), adios2::ShapeID::GlobalArray);
1690         ASSERT_EQ(var_u8.Steps(), NSteps);
1691         ASSERT_EQ(var_u8.Shape()[0], Ny);
1692         ASSERT_EQ(var_u8.Shape()[1], static_cast<size_t>(mpiSize * Nx));
1693 
1694         auto var_u16 = io.InquireVariable<uint16_t>("u16");
1695         EXPECT_TRUE(var_u16);
1696         ASSERT_EQ(var_u16.ShapeID(), adios2::ShapeID::GlobalArray);
1697         ASSERT_EQ(var_u16.Steps(), NSteps);
1698         ASSERT_EQ(var_u16.Shape()[0], Ny);
1699         ASSERT_EQ(var_u16.Shape()[1], static_cast<size_t>(mpiSize * Nx));
1700 
1701         auto var_u32 = io.InquireVariable<uint32_t>("u32");
1702         EXPECT_TRUE(var_u32);
1703         ASSERT_EQ(var_u32.ShapeID(), adios2::ShapeID::GlobalArray);
1704         ASSERT_EQ(var_u32.Steps(), NSteps);
1705         ASSERT_EQ(var_u32.Shape()[0], Ny);
1706         ASSERT_EQ(var_u32.Shape()[1], static_cast<size_t>(mpiSize * Nx));
1707 
1708         auto var_u64 = io.InquireVariable<uint64_t>("u64");
1709         EXPECT_TRUE(var_u64);
1710         ASSERT_EQ(var_u64.ShapeID(), adios2::ShapeID::GlobalArray);
1711         ASSERT_EQ(var_u64.Steps(), NSteps);
1712         ASSERT_EQ(var_u64.Shape()[0], Ny);
1713         ASSERT_EQ(var_u64.Shape()[1], static_cast<size_t>(mpiSize * Nx));
1714 
1715         auto var_r32 = io.InquireVariable<float>("r32");
1716         EXPECT_TRUE(var_r32);
1717         ASSERT_EQ(var_r32.ShapeID(), adios2::ShapeID::GlobalArray);
1718         ASSERT_EQ(var_r32.Steps(), NSteps);
1719         ASSERT_EQ(var_r32.Shape()[0], Ny);
1720         ASSERT_EQ(var_r32.Shape()[1], static_cast<size_t>(mpiSize * Nx));
1721 
1722         auto var_r64 = io.InquireVariable<double>("r64");
1723         EXPECT_TRUE(var_r64);
1724         ASSERT_EQ(var_r64.ShapeID(), adios2::ShapeID::GlobalArray);
1725         ASSERT_EQ(var_r64.Steps(), NSteps);
1726         ASSERT_EQ(var_r64.Shape()[0], Ny);
1727         ASSERT_EQ(var_r64.Shape()[1], static_cast<size_t>(mpiSize * Nx));
1728 
1729         std::string IString;
1730         std::array<int8_t, Nx * Ny> I8;
1731         std::array<int16_t, Nx * Ny> I16;
1732         std::array<int32_t, Nx * Ny> I32;
1733         std::array<int64_t, Nx * Ny> I64;
1734         std::array<uint8_t, Nx * Ny> U8;
1735         std::array<uint16_t, Nx * Ny> U16;
1736         std::array<uint32_t, Nx * Ny> U32;
1737         std::array<uint64_t, Nx * Ny> U64;
1738         std::array<float, Nx * Ny> R32;
1739         std::array<double, Nx * Ny> R64;
1740 
1741         const adios2::Dims start{0, static_cast<size_t>(mpiRank * Nx)};
1742         const adios2::Dims count{Ny, Nx};
1743 
1744         const adios2::Box<adios2::Dims> sel(start, count);
1745 
1746         var_i8.SetSelection(sel);
1747         var_i16.SetSelection(sel);
1748         var_i32.SetSelection(sel);
1749         var_i64.SetSelection(sel);
1750 
1751         var_u8.SetSelection(sel);
1752         var_u16.SetSelection(sel);
1753         var_u32.SetSelection(sel);
1754         var_u64.SetSelection(sel);
1755 
1756         var_r32.SetSelection(sel);
1757         var_r64.SetSelection(sel);
1758 
1759         for (size_t t = 0; t < NSteps; ++t)
1760         {
1761             var_i8.SetStepSelection({t, 1});
1762             var_i16.SetStepSelection({t, 1});
1763             var_i32.SetStepSelection({t, 1});
1764             var_i64.SetStepSelection({t, 1});
1765 
1766             var_u8.SetStepSelection({t, 1});
1767             var_u16.SetStepSelection({t, 1});
1768             var_u32.SetStepSelection({t, 1});
1769             var_u64.SetStepSelection({t, 1});
1770 
1771             var_r32.SetStepSelection({t, 1});
1772             var_r64.SetStepSelection({t, 1});
1773 
1774             hdf5Reader.Get(var_iString, IString);
1775 
1776             hdf5Reader.Get(var_i8, I8.data());
1777             hdf5Reader.Get(var_i16, I16.data());
1778             hdf5Reader.Get(var_i32, I32.data());
1779             hdf5Reader.Get(var_i64, I64.data());
1780 
1781             hdf5Reader.Get(var_u8, U8.data());
1782             hdf5Reader.Get(var_u16, U16.data());
1783             hdf5Reader.Get(var_u32, U32.data());
1784             hdf5Reader.Get(var_u64, U64.data());
1785 
1786             hdf5Reader.Get(var_r32, R32.data());
1787             hdf5Reader.Get(var_r64, R64.data());
1788 
1789             hdf5Reader.PerformGets();
1790 
1791             // Generate test data for each rank uniquely
1792             SmallTestData currentTestData = generateNewSmallTestData(
1793                 m_TestData, static_cast<int>(t), mpiRank, mpiSize);
1794 
1795             EXPECT_EQ(IString, currentTestData.S1);
1796 
1797             for (size_t i = 0; i < Nx * Ny; ++i)
1798             {
1799                 std::stringstream ss;
1800                 ss << "t=" << t << " i=" << i << " rank=" << mpiRank;
1801                 std::string msg = ss.str();
1802 
1803                 EXPECT_EQ(I8[i], currentTestData.I8[i]) << msg;
1804                 EXPECT_EQ(I16[i], currentTestData.I16[i]) << msg;
1805                 EXPECT_EQ(I32[i], currentTestData.I32[i]) << msg;
1806                 EXPECT_EQ(I64[i], currentTestData.I64[i]) << msg;
1807                 EXPECT_EQ(U8[i], currentTestData.U8[i]) << msg;
1808                 EXPECT_EQ(U16[i], currentTestData.U16[i]) << msg;
1809                 EXPECT_EQ(U32[i], currentTestData.U32[i]) << msg;
1810                 EXPECT_EQ(U64[i], currentTestData.U64[i]) << msg;
1811                 EXPECT_EQ(R32[i], currentTestData.R32[i]) << msg;
1812                 EXPECT_EQ(R64[i], currentTestData.R64[i]) << msg;
1813             }
1814         }
1815         hdf5Reader.Close();
1816     }
1817 }
1818 
1819 // Native HDF5 write, ADIOS2 read
TEST_F(HDF5WriteReadTest,HDF5WriteADIOS2HDF5Read2D2x4)1820 TEST_F(HDF5WriteReadTest, HDF5WriteADIOS2HDF5Read2D2x4)
1821 {
1822     std::string fname = "HDF5WriteADIOS2HDF5Read2D2x4Test.h5";
1823 
1824     int mpiRank = 0, mpiSize = 1;
1825     // Number of rows
1826     const std::size_t Nx = 4;
1827     const std::size_t Ny = 2;
1828     // Number of steps
1829     const std::size_t NSteps = 3;
1830 
1831     {
1832 #ifdef TEST_HDF5_MPI
1833         MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
1834         MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
1835 
1836         HDF5NativeWriter h5writer(fname, MPI_COMM_WORLD);
1837 #else
1838         HDF5NativeWriter h5writer(fname);
1839 #endif
1840 
1841         int dimSize = 2;
1842         hsize_t global_dims[2] = {Ny, Nx * mpiSize};
1843         hsize_t count[2] = {Ny, Nx};
1844         hsize_t offset[2] = {0, Nx * mpiRank};
1845 
1846         for (size_t step = 0; step < NSteps; ++step)
1847         {
1848             // Generate test data for each process uniquely
1849             SmallTestData currentTestData =
1850                 generateNewSmallTestData(m_TestData, step, mpiRank, mpiSize);
1851 
1852             h5writer.CreateAndStoreScalar("iString", H5T_STRING,
1853                                           currentTestData.S1.data());
1854             h5writer.CreateAndStoreVar("i8", dimSize, H5T_NATIVE_INT8,
1855                                        global_dims, offset, count,
1856                                        currentTestData.I8.data());
1857             h5writer.CreateAndStoreVar("i16", dimSize, H5T_NATIVE_SHORT,
1858                                        global_dims, offset, count,
1859                                        currentTestData.I16.data());
1860             h5writer.CreateAndStoreVar("i32", dimSize, H5T_NATIVE_INT,
1861                                        global_dims, offset, count,
1862                                        currentTestData.I32.data());
1863             h5writer.CreateAndStoreVar("i64", dimSize, H5T_NATIVE_LONG,
1864                                        global_dims, offset, count,
1865                                        currentTestData.I64.data());
1866             h5writer.CreateAndStoreVar("u8", dimSize, H5T_NATIVE_UCHAR,
1867                                        global_dims, offset, count,
1868                                        currentTestData.U8.data());
1869             h5writer.CreateAndStoreVar("u16", dimSize, H5T_NATIVE_USHORT,
1870                                        global_dims, offset, count,
1871                                        currentTestData.U16.data());
1872             h5writer.CreateAndStoreVar("u32", dimSize, H5T_NATIVE_UINT,
1873                                        global_dims, offset, count,
1874                                        currentTestData.U32.data());
1875             h5writer.CreateAndStoreVar("u64", dimSize, H5T_NATIVE_ULONG,
1876                                        global_dims, offset, count,
1877                                        currentTestData.U64.data());
1878             h5writer.CreateAndStoreVar("r32", dimSize, H5T_NATIVE_FLOAT,
1879                                        global_dims, offset, count,
1880                                        currentTestData.R32.data());
1881             h5writer.CreateAndStoreVar("r64", dimSize, H5T_NATIVE_DOUBLE,
1882                                        global_dims, offset, count,
1883                                        currentTestData.R64.data());
1884             h5writer.Advance();
1885         }
1886     }
1887 
1888     { // read back
1889 #ifdef TEST_HDF5_MPI
1890         MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
1891         MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
1892 #endif
1893 
1894 #ifdef TEST_HDF5_MPI
1895         adios2::ADIOS adios(MPI_COMM_WORLD);
1896 #else
1897         adios2::ADIOS adios;
1898 #endif
1899         adios2::IO io = adios.DeclareIO("HDF5ReadIO");
1900         io.SetEngine("HDF5");
1901 
1902         adios2::Engine hdf5Reader = io.Open(fname, adios2::Mode::Read);
1903 
1904         auto var_iString = io.InquireVariable<std::string>("iString");
1905         EXPECT_TRUE(var_iString);
1906         ASSERT_EQ(var_iString.Shape().size(), 0);
1907         ASSERT_EQ(var_iString.Steps(), NSteps);
1908 
1909         auto var_i8 = io.InquireVariable<int8_t>("i8");
1910         EXPECT_TRUE(var_i8);
1911         ASSERT_EQ(var_i8.ShapeID(), adios2::ShapeID::GlobalArray);
1912         ASSERT_EQ(var_i8.Steps(), NSteps);
1913         ASSERT_EQ(var_i8.Shape()[0], Ny);
1914         ASSERT_EQ(var_i8.Shape()[1], static_cast<size_t>(mpiSize * Nx));
1915 
1916         auto var_i16 = io.InquireVariable<int16_t>("i16");
1917         EXPECT_TRUE(var_i16);
1918         ASSERT_EQ(var_i16.ShapeID(), adios2::ShapeID::GlobalArray);
1919         ASSERT_EQ(var_i16.Steps(), NSteps);
1920         ASSERT_EQ(var_i16.Shape()[0], Ny);
1921         ASSERT_EQ(var_i16.Shape()[1], static_cast<size_t>(mpiSize * Nx));
1922 
1923         auto var_i32 = io.InquireVariable<int32_t>("i32");
1924         EXPECT_TRUE(var_i32);
1925         ASSERT_EQ(var_i32.ShapeID(), adios2::ShapeID::GlobalArray);
1926         ASSERT_EQ(var_i32.Steps(), NSteps);
1927         ASSERT_EQ(var_i32.Shape()[0], Ny);
1928         ASSERT_EQ(var_i32.Shape()[1], static_cast<size_t>(mpiSize * Nx));
1929 
1930         auto var_i64 = io.InquireVariable<int64_t>("i64");
1931         EXPECT_TRUE(var_i64);
1932         ASSERT_EQ(var_i64.ShapeID(), adios2::ShapeID::GlobalArray);
1933         ASSERT_EQ(var_i64.Steps(), NSteps);
1934         ASSERT_EQ(var_i64.Shape()[0], Ny);
1935         ASSERT_EQ(var_i64.Shape()[1], static_cast<size_t>(mpiSize * Nx));
1936 
1937         auto var_u8 = io.InquireVariable<uint8_t>("u8");
1938         EXPECT_TRUE(var_u8);
1939         ASSERT_EQ(var_u8.ShapeID(), adios2::ShapeID::GlobalArray);
1940         ASSERT_EQ(var_u8.Steps(), NSteps);
1941         ASSERT_EQ(var_u8.Shape()[0], Ny);
1942         ASSERT_EQ(var_u8.Shape()[1], static_cast<size_t>(mpiSize * Nx));
1943 
1944         auto var_u16 = io.InquireVariable<uint16_t>("u16");
1945         EXPECT_TRUE(var_u16);
1946         ASSERT_EQ(var_u16.ShapeID(), adios2::ShapeID::GlobalArray);
1947         ASSERT_EQ(var_u16.Steps(), NSteps);
1948         ASSERT_EQ(var_u16.Shape()[0], Ny);
1949         ASSERT_EQ(var_u16.Shape()[1], static_cast<size_t>(mpiSize * Nx));
1950 
1951         auto var_u32 = io.InquireVariable<uint32_t>("u32");
1952         EXPECT_TRUE(var_u32);
1953         ASSERT_EQ(var_u32.ShapeID(), adios2::ShapeID::GlobalArray);
1954         ASSERT_EQ(var_u32.Steps(), NSteps);
1955         ASSERT_EQ(var_u32.Shape()[0], Ny);
1956         ASSERT_EQ(var_u32.Shape()[1], static_cast<size_t>(mpiSize * Nx));
1957 
1958         auto var_u64 = io.InquireVariable<uint64_t>("u64");
1959         EXPECT_TRUE(var_u64);
1960         ASSERT_EQ(var_u64.ShapeID(), adios2::ShapeID::GlobalArray);
1961         ASSERT_EQ(var_u64.Steps(), NSteps);
1962         ASSERT_EQ(var_u64.Shape()[0], Ny);
1963         ASSERT_EQ(var_u64.Shape()[1], static_cast<size_t>(mpiSize * Nx));
1964 
1965         auto var_r32 = io.InquireVariable<float>("r32");
1966         EXPECT_TRUE(var_r32);
1967         ASSERT_EQ(var_r32.ShapeID(), adios2::ShapeID::GlobalArray);
1968         ASSERT_EQ(var_r32.Steps(), NSteps);
1969         ASSERT_EQ(var_r32.Shape()[0], Ny);
1970         ASSERT_EQ(var_r32.Shape()[1], static_cast<size_t>(mpiSize * Nx));
1971 
1972         auto var_r64 = io.InquireVariable<double>("r64");
1973         EXPECT_TRUE(var_r64);
1974         ASSERT_EQ(var_r64.ShapeID(), adios2::ShapeID::GlobalArray);
1975         ASSERT_EQ(var_r64.Steps(), NSteps);
1976         ASSERT_EQ(var_r64.Shape()[0], Ny);
1977         ASSERT_EQ(var_r64.Shape()[1], static_cast<size_t>(mpiSize * Nx));
1978 
1979         std::string IString;
1980         std::array<int8_t, Nx * Ny> I8;
1981         std::array<int16_t, Nx * Ny> I16;
1982         std::array<int32_t, Nx * Ny> I32;
1983         std::array<int64_t, Nx * Ny> I64;
1984         std::array<uint8_t, Nx * Ny> U8;
1985         std::array<uint16_t, Nx * Ny> U16;
1986         std::array<uint32_t, Nx * Ny> U32;
1987         std::array<uint64_t, Nx * Ny> U64;
1988         std::array<float, Nx * Ny> R32;
1989         std::array<double, Nx * Ny> R64;
1990 
1991         const adios2::Dims start{0, static_cast<size_t>(mpiRank * Nx)};
1992         const adios2::Dims count{Ny, Nx};
1993 
1994         const adios2::Box<adios2::Dims> sel(start, count);
1995 
1996         var_i8.SetSelection(sel);
1997         var_i16.SetSelection(sel);
1998         var_i32.SetSelection(sel);
1999         var_i64.SetSelection(sel);
2000 
2001         var_u8.SetSelection(sel);
2002         var_u16.SetSelection(sel);
2003         var_u32.SetSelection(sel);
2004         var_u64.SetSelection(sel);
2005 
2006         var_r32.SetSelection(sel);
2007         var_r64.SetSelection(sel);
2008 
2009         for (size_t t = 0; t < NSteps; ++t)
2010         {
2011             var_i8.SetStepSelection({t, 1});
2012             var_i16.SetStepSelection({t, 1});
2013             var_i32.SetStepSelection({t, 1});
2014             var_i64.SetStepSelection({t, 1});
2015 
2016             var_u8.SetStepSelection({t, 1});
2017             var_u16.SetStepSelection({t, 1});
2018             var_u32.SetStepSelection({t, 1});
2019             var_u64.SetStepSelection({t, 1});
2020 
2021             var_r32.SetStepSelection({t, 1});
2022             var_r64.SetStepSelection({t, 1});
2023 
2024             hdf5Reader.Get(var_iString, IString);
2025 
2026             hdf5Reader.Get(var_i8, I8.data());
2027             hdf5Reader.Get(var_i16, I16.data());
2028             hdf5Reader.Get(var_i32, I32.data());
2029             hdf5Reader.Get(var_i64, I64.data());
2030 
2031             hdf5Reader.Get(var_u8, U8.data());
2032             hdf5Reader.Get(var_u16, U16.data());
2033             hdf5Reader.Get(var_u32, U32.data());
2034             hdf5Reader.Get(var_u64, U64.data());
2035 
2036             hdf5Reader.Get(var_r32, R32.data());
2037             hdf5Reader.Get(var_r64, R64.data());
2038 
2039             hdf5Reader.PerformGets();
2040 
2041             // Generate test data for each rank uniquely
2042             SmallTestData currentTestData = generateNewSmallTestData(
2043                 m_TestData, static_cast<int>(t), mpiRank, mpiSize);
2044 
2045             EXPECT_EQ(IString, currentTestData.S1);
2046 
2047             for (size_t i = 0; i < Nx * Ny; ++i)
2048             {
2049                 std::stringstream ss;
2050                 ss << "t=" << t << " i=" << i << " rank=" << mpiRank;
2051                 std::string msg = ss.str();
2052 
2053                 EXPECT_EQ(I8[i], currentTestData.I8[i]) << msg;
2054                 EXPECT_EQ(I16[i], currentTestData.I16[i]) << msg;
2055                 EXPECT_EQ(I32[i], currentTestData.I32[i]) << msg;
2056                 EXPECT_EQ(I64[i], currentTestData.I64[i]) << msg;
2057                 EXPECT_EQ(U8[i], currentTestData.U8[i]) << msg;
2058                 EXPECT_EQ(U16[i], currentTestData.U16[i]) << msg;
2059                 EXPECT_EQ(U32[i], currentTestData.U32[i]) << msg;
2060                 EXPECT_EQ(U64[i], currentTestData.U64[i]) << msg;
2061                 EXPECT_EQ(R32[i], currentTestData.R32[i]) << msg;
2062                 EXPECT_EQ(R64[i], currentTestData.R64[i]) << msg;
2063             }
2064         }
2065         hdf5Reader.Close();
2066     }
2067 }
2068 
2069 //******************************************************************************
2070 // 2D 4x2 test data
2071 //******************************************************************************
2072 
2073 // ADIOS2 write, native HDF5 read
TEST_F(HDF5WriteReadTest,ADIOS2HDF5WriteHDF5Read2D4x2)2074 TEST_F(HDF5WriteReadTest, ADIOS2HDF5WriteHDF5Read2D4x2)
2075 {
2076 
2077     // Each process would write a 4x2 array and all processes would
2078     // form a 2D 4 * (NumberOfProcess * Nx) matrix where Nx is 2 here
2079     std::string fname = "ADIOS2HDF5WriteHDF5Read2D4x2Test.h5";
2080 
2081     int mpiRank = 0, mpiSize = 1;
2082     // Number of rows
2083     const std::size_t Nx = 2;
2084     // Number of cols
2085     const std::size_t Ny = 4;
2086 
2087     // Number of steps
2088     const std::size_t NSteps = 3;
2089 
2090 #ifdef TEST_HDF5_MPI
2091     MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
2092     MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
2093 #endif
2094 
2095     // Write test data using ADIOS2
2096     {
2097 #ifdef TEST_HDF5_MPI
2098         adios2::ADIOS adios(MPI_COMM_WORLD);
2099 #else
2100         adios2::ADIOS adios;
2101 #endif
2102         adios2::IO io = adios.DeclareIO("TestIO");
2103 
2104         // Declare 2D variables (4 * (NumberOfProcess * Nx))
2105         // The local process' part (start, count) can be defined now or later
2106         // before Write().
2107         {
2108             adios2::Dims shape{static_cast<unsigned int>(Ny),
2109                                static_cast<unsigned int>(mpiSize * Nx)};
2110             adios2::Dims start{static_cast<unsigned int>(0),
2111                                static_cast<unsigned int>(mpiRank * Nx)};
2112             adios2::Dims count{static_cast<unsigned int>(Ny),
2113                                static_cast<unsigned int>(Nx)};
2114 
2115             auto var_iString = io.DefineVariable<std::string>("iString");
2116             auto var_i8 = io.DefineVariable<int8_t>("i8", shape, start, count);
2117             auto var_i16 =
2118                 io.DefineVariable<int16_t>("i16", shape, start, count);
2119             auto var_i32 =
2120                 io.DefineVariable<int32_t>("i32", shape, start, count);
2121             auto var_i64 =
2122                 io.DefineVariable<int64_t>("i64", shape, start, count);
2123             auto var_u8 = io.DefineVariable<uint8_t>("u8", shape, start, count);
2124             auto var_u16 =
2125                 io.DefineVariable<uint16_t>("u16", shape, start, count);
2126             auto var_u32 =
2127                 io.DefineVariable<uint32_t>("u32", shape, start, count);
2128             auto var_u64 =
2129                 io.DefineVariable<uint64_t>("u64", shape, start, count);
2130             auto var_r32 = io.DefineVariable<float>("r32", shape, start, count);
2131             auto var_r64 =
2132                 io.DefineVariable<double>("r64", shape, start, count);
2133         }
2134 
2135         // Create the HDF5 Engine
2136         io.SetEngine("HDF5");
2137 
2138         // HDf5 engine calls the HDF5 common object that calls the hDF5 library.
2139         // The IO functionality, SetParameters and AddTransports will be added
2140         // in the future. For now `io.AddTransport("file", {
2141         // "library", "MPI"}});` is omitted.
2142         // })
2143         io.AddTransport("file");
2144 
2145         adios2::Engine engine = io.Open(fname, adios2::Mode::Write);
2146 
2147         for (size_t step = 0; step < NSteps; ++step)
2148         {
2149             // Generate test data for each process uniquely
2150             SmallTestData currentTestData =
2151                 generateNewSmallTestData(m_TestData, step, mpiRank, mpiSize);
2152 
2153             // Retrieve the variables that previously went out of scope
2154             auto var_iString = io.InquireVariable<std::string>("iString");
2155             auto var_i8 = io.InquireVariable<int8_t>("i8");
2156             auto var_i16 = io.InquireVariable<int16_t>("i16");
2157             auto var_i32 = io.InquireVariable<int32_t>("i32");
2158             auto var_i64 = io.InquireVariable<int64_t>("i64");
2159             auto var_u8 = io.InquireVariable<uint8_t>("u8");
2160             auto var_u16 = io.InquireVariable<uint16_t>("u16");
2161             auto var_u32 = io.InquireVariable<uint32_t>("u32");
2162             auto var_u64 = io.InquireVariable<uint64_t>("u64");
2163             auto var_r32 = io.InquireVariable<float>("r32");
2164             auto var_r64 = io.InquireVariable<double>("r64");
2165 
2166             // Make a 2D selection to describe the local dimensions of the
2167             // variable we write and its offsets in the global spaces
2168             adios2::Box<adios2::Dims> sel(
2169                 {0, static_cast<unsigned int>(mpiRank * Nx)}, {Ny, Nx});
2170             var_i8.SetSelection(sel);
2171             var_i16.SetSelection(sel);
2172             var_i32.SetSelection(sel);
2173             var_i64.SetSelection(sel);
2174             var_u8.SetSelection(sel);
2175             var_u16.SetSelection(sel);
2176             var_u32.SetSelection(sel);
2177             var_u64.SetSelection(sel);
2178             var_r32.SetSelection(sel);
2179             var_r64.SetSelection(sel);
2180 
2181             // Write each one
2182             // fill in the variable with values from starting index to
2183             // starting index + count
2184             engine.BeginStep();
2185             engine.Put(var_iString, currentTestData.S1);
2186             engine.Put(var_i8, currentTestData.I8.data());
2187             engine.Put(var_i16, currentTestData.I16.data());
2188             engine.Put(var_i32, currentTestData.I32.data());
2189             engine.Put(var_i64, currentTestData.I64.data());
2190             engine.Put(var_u8, currentTestData.U8.data());
2191             engine.Put(var_u16, currentTestData.U16.data());
2192             engine.Put(var_u32, currentTestData.U32.data());
2193             engine.Put(var_u64, currentTestData.U64.data());
2194             engine.Put(var_r32, currentTestData.R32.data());
2195             engine.Put(var_r64, currentTestData.R64.data());
2196             engine.EndStep();
2197         }
2198 
2199         engine.Close();
2200     }
2201 
2202     {
2203 
2204         HDF5NativeReader hdf5Reader(fname);
2205 
2206         std::string IString;
2207         const size_t arraySize = Nx * Ny;
2208         std::array<int8_t, arraySize> I8;
2209         std::array<int16_t, arraySize> I16;
2210         std::array<int32_t, arraySize> I32;
2211         std::array<int64_t, arraySize> I64;
2212         std::array<uint8_t, arraySize> U8;
2213         std::array<uint16_t, arraySize> U16;
2214         std::array<uint32_t, arraySize> U32;
2215         std::array<uint64_t, arraySize> U64;
2216         std::array<float, arraySize> R32;
2217         std::array<double, arraySize> R64;
2218         // 2D
2219         hsize_t count[2], offset[2];
2220         offset[0] = 0;
2221         offset[1] = mpiRank * Nx;
2222         count[0] = Ny;
2223         count[1] = Nx;
2224         size_t globalArraySize = Nx * mpiSize;
2225 
2226         // For each variable, we would verify its global size and type.
2227         // Then we would retrieve the data back which is written by the
2228         // current process and validate the value
2229         for (size_t t = 0; t < NSteps; ++t)
2230         {
2231             SmallTestData currentTestData =
2232                 generateNewSmallTestData(m_TestData, t, mpiRank, mpiSize);
2233 
2234             std::vector<hsize_t> gDims;
2235             hid_t h5Type;
2236 
2237             hdf5Reader.GetVarInfo("iString", gDims, h5Type);
2238             // ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_IN), 1);
2239             ASSERT_EQ(gDims.size(), 0);
2240             hdf5Reader.ReadString("iString", IString);
2241 
2242             hdf5Reader.GetVarInfo("i8", gDims, h5Type);
2243             ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_INT8), 1);
2244             ASSERT_EQ(gDims.size(), 2);
2245             ASSERT_EQ(gDims[0], 4);
2246             ASSERT_EQ(gDims[1], globalArraySize);
2247             hdf5Reader.ReadVar("i8", I8.data(), offset, count, arraySize);
2248 
2249             hdf5Reader.GetVarInfo("i16", gDims, h5Type);
2250             ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_SHORT), 1);
2251             ASSERT_EQ(gDims.size(), 2);
2252             ASSERT_EQ(gDims[0], 4);
2253             ASSERT_EQ(gDims[1], globalArraySize);
2254             hdf5Reader.ReadVar("i16", I16.data(), offset, count, arraySize);
2255 
2256             hdf5Reader.GetVarInfo("i32", gDims, h5Type);
2257             ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_INT), 1);
2258             ASSERT_EQ(gDims.size(), 2);
2259             ASSERT_EQ(gDims[0], 4);
2260             ASSERT_EQ(gDims[1], globalArraySize);
2261             hdf5Reader.ReadVar("i32", I32.data(), offset, count, arraySize);
2262 
2263             hdf5Reader.GetVarInfo("i64", gDims, h5Type);
2264             ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_LONG), 1);
2265             ASSERT_EQ(gDims.size(), 2);
2266             ASSERT_EQ(gDims[0], 4);
2267             ASSERT_EQ(gDims[1], globalArraySize);
2268             hdf5Reader.ReadVar("i64", I64.data(), offset, count, arraySize);
2269 
2270             hdf5Reader.GetVarInfo("u8", gDims, h5Type);
2271             ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_UCHAR), 1);
2272             ASSERT_EQ(gDims.size(), 2);
2273             ASSERT_EQ(gDims[0], 4);
2274             ASSERT_EQ(gDims[1], globalArraySize);
2275             hdf5Reader.ReadVar("u8", U8.data(), offset, count, arraySize);
2276 
2277             hdf5Reader.GetVarInfo("u16", gDims, h5Type);
2278             ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_USHORT), 1);
2279             ASSERT_EQ(gDims.size(), 2);
2280             ASSERT_EQ(gDims[0], 4);
2281             ASSERT_EQ(gDims[1], globalArraySize);
2282             hdf5Reader.ReadVar("u16", U16.data(), offset, count, arraySize);
2283 
2284             hdf5Reader.GetVarInfo("u32", gDims, h5Type);
2285             ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_UINT), 1);
2286             ASSERT_EQ(gDims.size(), 2);
2287             ASSERT_EQ(gDims[0], 4);
2288             ASSERT_EQ(gDims[1], globalArraySize);
2289             hdf5Reader.ReadVar("u32", U32.data(), offset, count, arraySize);
2290 
2291             hdf5Reader.GetVarInfo("u64", gDims, h5Type);
2292             ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_ULONG), 1);
2293             ASSERT_EQ(gDims.size(), 2);
2294             ASSERT_EQ(gDims[0], 4);
2295             ASSERT_EQ(gDims[1], globalArraySize);
2296             hdf5Reader.ReadVar("u64", U64.data(), offset, count, arraySize);
2297 
2298             hdf5Reader.GetVarInfo("r32", gDims, h5Type);
2299             ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_FLOAT), 1);
2300             ASSERT_EQ(gDims.size(), 2);
2301             ASSERT_EQ(gDims[0], 4);
2302             ASSERT_EQ(gDims[1], globalArraySize);
2303             hdf5Reader.ReadVar("r32", R32.data(), offset, count, arraySize);
2304 
2305             hdf5Reader.GetVarInfo("r64", gDims, h5Type);
2306             ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_DOUBLE), 1);
2307             ASSERT_EQ(gDims.size(), 2);
2308             ASSERT_EQ(gDims[0], 4);
2309             ASSERT_EQ(gDims[1], globalArraySize);
2310             hdf5Reader.ReadVar("r64", R64.data(), offset, count, arraySize);
2311 
2312             EXPECT_EQ(IString, currentTestData.S1);
2313             // Check if it's correct
2314             for (size_t i = 0; i < Nx; ++i)
2315             {
2316                 std::stringstream ss;
2317                 ss << "t=" << t << " i=" << i << " rank=" << mpiRank;
2318                 std::string msg = ss.str();
2319 
2320                 EXPECT_EQ(I8[i], currentTestData.I8[i]) << msg;
2321                 EXPECT_EQ(I16[i], currentTestData.I16[i]) << msg;
2322                 EXPECT_EQ(I32[i], currentTestData.I32[i]) << msg;
2323                 EXPECT_EQ(I64[i], currentTestData.I64[i]) << msg;
2324                 EXPECT_EQ(U8[i], currentTestData.U8[i]) << msg;
2325                 EXPECT_EQ(U16[i], currentTestData.U16[i]) << msg;
2326                 EXPECT_EQ(U32[i], currentTestData.U32[i]) << msg;
2327                 EXPECT_EQ(U64[i], currentTestData.U64[i]) << msg;
2328                 EXPECT_EQ(R32[i], currentTestData.R32[i]) << msg;
2329                 EXPECT_EQ(R64[i], currentTestData.R64[i]) << msg;
2330             }
2331             hdf5Reader.Advance();
2332         }
2333     }
2334 }
2335 
2336 // ADIOS2 write, ADIOS2 read
TEST_F(HDF5WriteReadTest,ADIOS2HDF5WriteADIOS2HDF5Read2D4x2)2337 TEST_F(HDF5WriteReadTest, ADIOS2HDF5WriteADIOS2HDF5Read2D4x2)
2338 {
2339     std::string fname = "ADIOS2HDF5WriteADIOS2HDF5Read2D4x2Test.h5";
2340 
2341     int mpiRank = 0, mpiSize = 1;
2342     // Number of rows
2343     const std::size_t Nx = 2;
2344     // Number of cols
2345     const std::size_t Ny = 4;
2346 
2347     // Number of steps
2348     const std::size_t NSteps = 3;
2349 
2350 #ifdef TEST_HDF5_MPI
2351     MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
2352     MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
2353 #endif
2354 
2355 #ifdef TEST_HDF5_MPI
2356     adios2::ADIOS adios(MPI_COMM_WORLD);
2357 #else
2358     adios2::ADIOS adios;
2359 #endif
2360 
2361     // Write test data using ADIOS2
2362     {
2363         adios2::IO io = adios.DeclareIO("TestIO");
2364 
2365         // Declare 2D variables (4 * (NumberOfProcess * Nx))
2366         // The local process' part (start, count) can be defined now or later
2367         // before Write().
2368         {
2369             adios2::Dims shape{static_cast<unsigned int>(Ny),
2370                                static_cast<unsigned int>(mpiSize * Nx)};
2371             adios2::Dims start{static_cast<unsigned int>(0),
2372                                static_cast<unsigned int>(mpiRank * Nx)};
2373             adios2::Dims count{static_cast<unsigned int>(Ny),
2374                                static_cast<unsigned int>(Nx)};
2375             auto var_iString = io.DefineVariable<std::string>("iString");
2376             auto var_i8 = io.DefineVariable<int8_t>("i8", shape, start, count);
2377             auto var_i16 =
2378                 io.DefineVariable<int16_t>("i16", shape, start, count);
2379             auto var_i32 =
2380                 io.DefineVariable<int32_t>("i32", shape, start, count);
2381             auto var_i64 =
2382                 io.DefineVariable<int64_t>("i64", shape, start, count);
2383             auto var_u8 = io.DefineVariable<uint8_t>("u8", shape, start, count);
2384             auto var_u16 =
2385                 io.DefineVariable<uint16_t>("u16", shape, start, count);
2386             auto var_u32 =
2387                 io.DefineVariable<uint32_t>("u32", shape, start, count);
2388             auto var_u64 =
2389                 io.DefineVariable<uint64_t>("u64", shape, start, count);
2390             auto var_r32 = io.DefineVariable<float>("r32", shape, start, count);
2391             auto var_r64 =
2392                 io.DefineVariable<double>("r64", shape, start, count);
2393         }
2394 
2395         // Create the HDF5 Engine
2396         io.SetEngine("HDF5");
2397 
2398         // HDf5 engine calls the HDF5 common object that calls the hDF5 library.
2399         // The IO functionality, SetParameters and AddTransports will be added
2400         // in the future. For now `io.AddTransport("file", {
2401         // "library", "MPI"}});` is omitted.
2402         // })
2403         io.AddTransport("file");
2404 
2405         adios2::Engine engine = io.Open(fname, adios2::Mode::Write);
2406 
2407         for (size_t step = 0; step < NSteps; ++step)
2408         {
2409             // Generate test data for each process uniquely
2410             SmallTestData currentTestData =
2411                 generateNewSmallTestData(m_TestData, step, mpiRank, mpiSize);
2412 
2413             // Retrieve the variables that previously went out of scope
2414             auto var_iString = io.InquireVariable<std::string>("iString");
2415             auto var_i8 = io.InquireVariable<int8_t>("i8");
2416             auto var_i16 = io.InquireVariable<int16_t>("i16");
2417             auto var_i32 = io.InquireVariable<int32_t>("i32");
2418             auto var_i64 = io.InquireVariable<int64_t>("i64");
2419             auto var_u8 = io.InquireVariable<uint8_t>("u8");
2420             auto var_u16 = io.InquireVariable<uint16_t>("u16");
2421             auto var_u32 = io.InquireVariable<uint32_t>("u32");
2422             auto var_u64 = io.InquireVariable<uint64_t>("u64");
2423             auto var_r32 = io.InquireVariable<float>("r32");
2424             auto var_r64 = io.InquireVariable<double>("r64");
2425 
2426             // Make a 2D selection to describe the local dimensions of the
2427             // variable we write and its offsets in the global spaces
2428             adios2::Box<adios2::Dims> sel(
2429                 {0, static_cast<unsigned int>(mpiRank * Nx)}, {Ny, Nx});
2430             var_i8.SetSelection(sel);
2431             var_i16.SetSelection(sel);
2432             var_i32.SetSelection(sel);
2433             var_i64.SetSelection(sel);
2434             var_u8.SetSelection(sel);
2435             var_u16.SetSelection(sel);
2436             var_u32.SetSelection(sel);
2437             var_u64.SetSelection(sel);
2438             var_r32.SetSelection(sel);
2439             var_r64.SetSelection(sel);
2440 
2441             // Write each one
2442             // fill in the variable with values from starting index to
2443             // starting index + count
2444             engine.BeginStep();
2445             engine.Put(var_iString, currentTestData.S1);
2446             engine.Put(var_i8, currentTestData.I8.data());
2447             engine.Put(var_i16, currentTestData.I16.data());
2448             engine.Put(var_i32, currentTestData.I32.data());
2449             engine.Put(var_i64, currentTestData.I64.data());
2450             engine.Put(var_u8, currentTestData.U8.data());
2451             engine.Put(var_u16, currentTestData.U16.data());
2452             engine.Put(var_u32, currentTestData.U32.data());
2453             engine.Put(var_u64, currentTestData.U64.data());
2454             engine.Put(var_r32, currentTestData.R32.data());
2455             engine.Put(var_r64, currentTestData.R64.data());
2456             engine.EndStep();
2457         }
2458 
2459         engine.Close();
2460     }
2461 
2462     { // reading back
2463         adios2::IO io = adios.DeclareIO("HDF5ReadIO");
2464         io.SetEngine("HDF5");
2465 
2466         adios2::Engine hdf5Reader = io.Open(fname, adios2::Mode::Read);
2467 
2468         auto var_iString = io.InquireVariable<std::string>("iString");
2469         EXPECT_TRUE(var_iString);
2470         ASSERT_EQ(var_iString.Shape().size(), 0);
2471         ASSERT_EQ(var_iString.Steps(), NSteps);
2472 
2473         auto var_i8 = io.InquireVariable<int8_t>("i8");
2474         EXPECT_TRUE(var_i8);
2475         ASSERT_EQ(var_i8.ShapeID(), adios2::ShapeID::GlobalArray);
2476         ASSERT_EQ(var_i8.Steps(), NSteps);
2477         ASSERT_EQ(var_i8.Shape()[0], Ny);
2478         ASSERT_EQ(var_i8.Shape()[1], static_cast<size_t>(mpiSize * Nx));
2479 
2480         auto var_i16 = io.InquireVariable<int16_t>("i16");
2481         EXPECT_TRUE(var_i16);
2482         ASSERT_EQ(var_i16.ShapeID(), adios2::ShapeID::GlobalArray);
2483         ASSERT_EQ(var_i16.Steps(), NSteps);
2484         ASSERT_EQ(var_i16.Shape()[0], Ny);
2485         ASSERT_EQ(var_i16.Shape()[1], static_cast<size_t>(mpiSize * Nx));
2486 
2487         auto var_i32 = io.InquireVariable<int32_t>("i32");
2488         EXPECT_TRUE(var_i32);
2489         ASSERT_EQ(var_i32.ShapeID(), adios2::ShapeID::GlobalArray);
2490         ASSERT_EQ(var_i32.Steps(), NSteps);
2491         ASSERT_EQ(var_i32.Shape()[0], Ny);
2492         ASSERT_EQ(var_i32.Shape()[1], static_cast<size_t>(mpiSize * Nx));
2493 
2494         auto var_i64 = io.InquireVariable<int64_t>("i64");
2495         EXPECT_TRUE(var_i64);
2496         ASSERT_EQ(var_i64.ShapeID(), adios2::ShapeID::GlobalArray);
2497         ASSERT_EQ(var_i64.Steps(), NSteps);
2498         ASSERT_EQ(var_i64.Shape()[0], Ny);
2499         ASSERT_EQ(var_i64.Shape()[1], static_cast<size_t>(mpiSize * Nx));
2500 
2501         auto var_u8 = io.InquireVariable<uint8_t>("u8");
2502         EXPECT_TRUE(var_u8);
2503         ASSERT_EQ(var_u8.ShapeID(), adios2::ShapeID::GlobalArray);
2504         ASSERT_EQ(var_u8.Steps(), NSteps);
2505         ASSERT_EQ(var_u8.Shape()[0], Ny);
2506         ASSERT_EQ(var_u8.Shape()[1], static_cast<size_t>(mpiSize * Nx));
2507 
2508         auto var_u16 = io.InquireVariable<uint16_t>("u16");
2509         EXPECT_TRUE(var_u16);
2510         ASSERT_EQ(var_u16.ShapeID(), adios2::ShapeID::GlobalArray);
2511         ASSERT_EQ(var_u16.Steps(), NSteps);
2512         ASSERT_EQ(var_u16.Shape()[0], Ny);
2513         ASSERT_EQ(var_u16.Shape()[1], static_cast<size_t>(mpiSize * Nx));
2514 
2515         auto var_u32 = io.InquireVariable<uint32_t>("u32");
2516         EXPECT_TRUE(var_u32);
2517         ASSERT_EQ(var_u32.ShapeID(), adios2::ShapeID::GlobalArray);
2518         ASSERT_EQ(var_u32.Steps(), NSteps);
2519         ASSERT_EQ(var_u32.Shape()[0], Ny);
2520         ASSERT_EQ(var_u32.Shape()[1], static_cast<size_t>(mpiSize * Nx));
2521 
2522         auto var_u64 = io.InquireVariable<uint64_t>("u64");
2523         EXPECT_TRUE(var_u64);
2524         ASSERT_EQ(var_u64.ShapeID(), adios2::ShapeID::GlobalArray);
2525         ASSERT_EQ(var_u64.Steps(), NSteps);
2526         ASSERT_EQ(var_u64.Shape()[0], Ny);
2527         ASSERT_EQ(var_u64.Shape()[1], static_cast<size_t>(mpiSize * Nx));
2528 
2529         auto var_r32 = io.InquireVariable<float>("r32");
2530         EXPECT_TRUE(var_r32);
2531         ASSERT_EQ(var_r32.ShapeID(), adios2::ShapeID::GlobalArray);
2532         ASSERT_EQ(var_r32.Steps(), NSteps);
2533         ASSERT_EQ(var_r32.Shape()[0], Ny);
2534         ASSERT_EQ(var_r32.Shape()[1], static_cast<size_t>(mpiSize * Nx));
2535 
2536         auto var_r64 = io.InquireVariable<double>("r64");
2537         EXPECT_TRUE(var_r64);
2538         ASSERT_EQ(var_r64.ShapeID(), adios2::ShapeID::GlobalArray);
2539         ASSERT_EQ(var_r64.Steps(), NSteps);
2540         ASSERT_EQ(var_r64.Shape()[0], Ny);
2541         ASSERT_EQ(var_r64.Shape()[1], static_cast<size_t>(mpiSize * Nx));
2542 
2543         std::string IString;
2544         std::array<int8_t, Nx * Ny> I8;
2545         std::array<int16_t, Nx * Ny> I16;
2546         std::array<int32_t, Nx * Ny> I32;
2547         std::array<int64_t, Nx * Ny> I64;
2548         std::array<uint8_t, Nx * Ny> U8;
2549         std::array<uint16_t, Nx * Ny> U16;
2550         std::array<uint32_t, Nx * Ny> U32;
2551         std::array<uint64_t, Nx * Ny> U64;
2552         std::array<float, Nx * Ny> R32;
2553         std::array<double, Nx * Ny> R64;
2554 
2555         const adios2::Dims start{0, static_cast<size_t>(mpiRank * Nx)};
2556         const adios2::Dims count{Ny, Nx};
2557 
2558         const adios2::Box<adios2::Dims> sel(start, count);
2559 
2560         var_i8.SetSelection(sel);
2561         var_i16.SetSelection(sel);
2562         var_i32.SetSelection(sel);
2563         var_i64.SetSelection(sel);
2564 
2565         var_u8.SetSelection(sel);
2566         var_u16.SetSelection(sel);
2567         var_u32.SetSelection(sel);
2568         var_u64.SetSelection(sel);
2569 
2570         var_r32.SetSelection(sel);
2571         var_r64.SetSelection(sel);
2572 
2573         for (size_t t = 0; t < NSteps; ++t)
2574         {
2575             var_i8.SetStepSelection({t, 1});
2576             var_i16.SetStepSelection({t, 1});
2577             var_i32.SetStepSelection({t, 1});
2578             var_i64.SetStepSelection({t, 1});
2579 
2580             var_u8.SetStepSelection({t, 1});
2581             var_u16.SetStepSelection({t, 1});
2582             var_u32.SetStepSelection({t, 1});
2583             var_u64.SetStepSelection({t, 1});
2584 
2585             var_r32.SetStepSelection({t, 1});
2586             var_r64.SetStepSelection({t, 1});
2587 
2588             hdf5Reader.Get(var_iString, IString);
2589 
2590             hdf5Reader.Get(var_i8, I8.data());
2591             hdf5Reader.Get(var_i16, I16.data());
2592             hdf5Reader.Get(var_i32, I32.data());
2593             hdf5Reader.Get(var_i64, I64.data());
2594 
2595             hdf5Reader.Get(var_u8, U8.data());
2596             hdf5Reader.Get(var_u16, U16.data());
2597             hdf5Reader.Get(var_u32, U32.data());
2598             hdf5Reader.Get(var_u64, U64.data());
2599 
2600             hdf5Reader.Get(var_r32, R32.data());
2601             hdf5Reader.Get(var_r64, R64.data());
2602             hdf5Reader.PerformGets();
2603 
2604             // Generate test data for each rank uniquely
2605             SmallTestData currentTestData = generateNewSmallTestData(
2606                 m_TestData, static_cast<int>(t), mpiRank, mpiSize);
2607 
2608             EXPECT_EQ(IString, currentTestData.S1);
2609 
2610             for (size_t i = 0; i < Nx * Ny; ++i)
2611             {
2612                 std::stringstream ss;
2613                 ss << "t=" << t << " i=" << i << " rank=" << mpiRank;
2614                 std::string msg = ss.str();
2615 
2616                 EXPECT_EQ(I8[i], currentTestData.I8[i]) << msg;
2617                 EXPECT_EQ(I16[i], currentTestData.I16[i]) << msg;
2618                 EXPECT_EQ(I32[i], currentTestData.I32[i]) << msg;
2619                 EXPECT_EQ(I64[i], currentTestData.I64[i]) << msg;
2620                 EXPECT_EQ(U8[i], currentTestData.U8[i]) << msg;
2621                 EXPECT_EQ(U16[i], currentTestData.U16[i]) << msg;
2622                 EXPECT_EQ(U32[i], currentTestData.U32[i]) << msg;
2623                 EXPECT_EQ(U64[i], currentTestData.U64[i]) << msg;
2624                 EXPECT_EQ(R32[i], currentTestData.R32[i]) << msg;
2625                 EXPECT_EQ(R64[i], currentTestData.R64[i]) << msg;
2626             }
2627         }
2628         hdf5Reader.Close();
2629     }
2630 }
2631 
2632 // Native HDF5 write, ADIOS2 read
TEST_F(HDF5WriteReadTest,HDF5WriteADIOS2HDF5Read2D4x2)2633 TEST_F(HDF5WriteReadTest, HDF5WriteADIOS2HDF5Read2D4x2)
2634 {
2635     std::string fname = "HDF5WriteADIOS2HDF5Read2D4x2Test.h5";
2636 
2637     int mpiRank = 0, mpiSize = 1;
2638     // Number of rows
2639     const std::size_t Nx = 2;
2640     const std::size_t Ny = 4;
2641     // Number of steps
2642     const std::size_t NSteps = 3;
2643 
2644     {
2645 #ifdef TEST_HDF5_MPI
2646         MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
2647         MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
2648 
2649         HDF5NativeWriter h5writer(fname, MPI_COMM_WORLD);
2650 #else
2651         HDF5NativeWriter h5writer(fname);
2652 #endif
2653 
2654         int dimSize = 2;
2655         hsize_t global_dims[2] = {Ny, Nx * mpiSize};
2656         hsize_t count[2] = {Ny, Nx};
2657         hsize_t offset[2] = {0, Nx * mpiRank};
2658 
2659         for (size_t step = 0; step < NSteps; ++step)
2660         {
2661             // Generate test data for each process uniquely
2662             SmallTestData currentTestData =
2663                 generateNewSmallTestData(m_TestData, step, mpiRank, mpiSize);
2664 
2665             h5writer.CreateAndStoreScalar("iString", H5T_STRING,
2666                                           currentTestData.S1.data());
2667             h5writer.CreateAndStoreVar("i8", dimSize, H5T_NATIVE_INT8,
2668                                        global_dims, offset, count,
2669                                        currentTestData.I8.data());
2670             h5writer.CreateAndStoreVar("i16", dimSize, H5T_NATIVE_SHORT,
2671                                        global_dims, offset, count,
2672                                        currentTestData.I16.data());
2673             h5writer.CreateAndStoreVar("i32", dimSize, H5T_NATIVE_INT,
2674                                        global_dims, offset, count,
2675                                        currentTestData.I32.data());
2676             h5writer.CreateAndStoreVar("i64", dimSize, H5T_NATIVE_LONG,
2677                                        global_dims, offset, count,
2678                                        currentTestData.I64.data());
2679             h5writer.CreateAndStoreVar("u8", dimSize, H5T_NATIVE_UCHAR,
2680                                        global_dims, offset, count,
2681                                        currentTestData.U8.data());
2682             h5writer.CreateAndStoreVar("u16", dimSize, H5T_NATIVE_USHORT,
2683                                        global_dims, offset, count,
2684                                        currentTestData.U16.data());
2685             h5writer.CreateAndStoreVar("u32", dimSize, H5T_NATIVE_UINT,
2686                                        global_dims, offset, count,
2687                                        currentTestData.U32.data());
2688             h5writer.CreateAndStoreVar("u64", dimSize, H5T_NATIVE_ULONG,
2689                                        global_dims, offset, count,
2690                                        currentTestData.U64.data());
2691             h5writer.CreateAndStoreVar("r32", dimSize, H5T_NATIVE_FLOAT,
2692                                        global_dims, offset, count,
2693                                        currentTestData.R32.data());
2694             h5writer.CreateAndStoreVar("r64", dimSize, H5T_NATIVE_DOUBLE,
2695                                        global_dims, offset, count,
2696                                        currentTestData.R64.data());
2697             h5writer.Advance();
2698         }
2699     }
2700 
2701     { // read back
2702 #ifdef TEST_HDF5_MPI
2703         MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
2704         MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
2705 #endif
2706 
2707 #ifdef TEST_HDF5_MPI
2708         adios2::ADIOS adios(MPI_COMM_WORLD);
2709 #else
2710         adios2::ADIOS adios;
2711 #endif
2712 
2713         adios2::IO io = adios.DeclareIO("HDF5ReadIO");
2714         io.SetEngine("HDF5");
2715 
2716         adios2::Engine hdf5Reader = io.Open(fname, adios2::Mode::Read);
2717 
2718         auto var_iString = io.InquireVariable<std::string>("iString");
2719         EXPECT_TRUE(var_iString);
2720         ASSERT_EQ(var_iString.Shape().size(), 0);
2721         ASSERT_EQ(var_iString.Steps(), NSteps);
2722 
2723         auto var_i8 = io.InquireVariable<int8_t>("i8");
2724         EXPECT_TRUE(var_i8);
2725         ASSERT_EQ(var_i8.ShapeID(), adios2::ShapeID::GlobalArray);
2726         ASSERT_EQ(var_i8.Steps(), NSteps);
2727         ASSERT_EQ(var_i8.Shape()[0], Ny);
2728         ASSERT_EQ(var_i8.Shape()[1], static_cast<size_t>(mpiSize * Nx));
2729 
2730         auto var_i16 = io.InquireVariable<int16_t>("i16");
2731         EXPECT_TRUE(var_i16);
2732         ASSERT_EQ(var_i16.ShapeID(), adios2::ShapeID::GlobalArray);
2733         ASSERT_EQ(var_i16.Steps(), NSteps);
2734         ASSERT_EQ(var_i16.Shape()[0], Ny);
2735         ASSERT_EQ(var_i16.Shape()[1], static_cast<size_t>(mpiSize * Nx));
2736 
2737         auto var_i32 = io.InquireVariable<int32_t>("i32");
2738         EXPECT_TRUE(var_i32);
2739         ASSERT_EQ(var_i32.ShapeID(), adios2::ShapeID::GlobalArray);
2740         ASSERT_EQ(var_i32.Steps(), NSteps);
2741         ASSERT_EQ(var_i32.Shape()[0], Ny);
2742         ASSERT_EQ(var_i32.Shape()[1], static_cast<size_t>(mpiSize * Nx));
2743 
2744         auto var_i64 = io.InquireVariable<int64_t>("i64");
2745         EXPECT_TRUE(var_i64);
2746         ASSERT_EQ(var_i64.ShapeID(), adios2::ShapeID::GlobalArray);
2747         ASSERT_EQ(var_i64.Steps(), NSteps);
2748         ASSERT_EQ(var_i64.Shape()[0], Ny);
2749         ASSERT_EQ(var_i64.Shape()[1], static_cast<size_t>(mpiSize * Nx));
2750 
2751         auto var_u8 = io.InquireVariable<uint8_t>("u8");
2752         EXPECT_TRUE(var_u8);
2753         ASSERT_EQ(var_u8.ShapeID(), adios2::ShapeID::GlobalArray);
2754         ASSERT_EQ(var_u8.Steps(), NSteps);
2755         ASSERT_EQ(var_u8.Shape()[0], Ny);
2756         ASSERT_EQ(var_u8.Shape()[1], static_cast<size_t>(mpiSize * Nx));
2757 
2758         auto var_u16 = io.InquireVariable<uint16_t>("u16");
2759         EXPECT_TRUE(var_u16);
2760         ASSERT_EQ(var_u16.ShapeID(), adios2::ShapeID::GlobalArray);
2761         ASSERT_EQ(var_u16.Steps(), NSteps);
2762         ASSERT_EQ(var_u16.Shape()[0], Ny);
2763         ASSERT_EQ(var_u16.Shape()[1], static_cast<size_t>(mpiSize * Nx));
2764 
2765         auto var_u32 = io.InquireVariable<uint32_t>("u32");
2766         EXPECT_TRUE(var_u32);
2767         ASSERT_EQ(var_u32.ShapeID(), adios2::ShapeID::GlobalArray);
2768         ASSERT_EQ(var_u32.Steps(), NSteps);
2769         ASSERT_EQ(var_u32.Shape()[0], Ny);
2770         ASSERT_EQ(var_u32.Shape()[1], static_cast<size_t>(mpiSize * Nx));
2771 
2772         auto var_u64 = io.InquireVariable<uint64_t>("u64");
2773         EXPECT_TRUE(var_u64);
2774         ASSERT_EQ(var_u64.ShapeID(), adios2::ShapeID::GlobalArray);
2775         ASSERT_EQ(var_u64.Steps(), NSteps);
2776         ASSERT_EQ(var_u64.Shape()[0], Ny);
2777         ASSERT_EQ(var_u64.Shape()[1], static_cast<size_t>(mpiSize * Nx));
2778 
2779         auto var_r32 = io.InquireVariable<float>("r32");
2780         EXPECT_TRUE(var_r32);
2781         ASSERT_EQ(var_r32.ShapeID(), adios2::ShapeID::GlobalArray);
2782         ASSERT_EQ(var_r32.Steps(), NSteps);
2783         ASSERT_EQ(var_r32.Shape()[0], Ny);
2784         ASSERT_EQ(var_r32.Shape()[1], static_cast<size_t>(mpiSize * Nx));
2785 
2786         auto var_r64 = io.InquireVariable<double>("r64");
2787         EXPECT_TRUE(var_r64);
2788         ASSERT_EQ(var_r64.ShapeID(), adios2::ShapeID::GlobalArray);
2789         ASSERT_EQ(var_r64.Steps(), NSteps);
2790         ASSERT_EQ(var_r64.Shape()[0], Ny);
2791         ASSERT_EQ(var_r64.Shape()[1], static_cast<size_t>(mpiSize * Nx));
2792 
2793         std::string IString;
2794         std::array<int8_t, Nx * Ny> I8;
2795         std::array<int16_t, Nx * Ny> I16;
2796         std::array<int32_t, Nx * Ny> I32;
2797         std::array<int64_t, Nx * Ny> I64;
2798         std::array<uint8_t, Nx * Ny> U8;
2799         std::array<uint16_t, Nx * Ny> U16;
2800         std::array<uint32_t, Nx * Ny> U32;
2801         std::array<uint64_t, Nx * Ny> U64;
2802         std::array<float, Nx * Ny> R32;
2803         std::array<double, Nx * Ny> R64;
2804 
2805         const adios2::Dims start{0, static_cast<size_t>(mpiRank * Nx)};
2806         const adios2::Dims count{Ny, Nx};
2807 
2808         const adios2::Box<adios2::Dims> sel(start, count);
2809 
2810         var_i8.SetSelection(sel);
2811         var_i16.SetSelection(sel);
2812         var_i32.SetSelection(sel);
2813         var_i64.SetSelection(sel);
2814 
2815         var_u8.SetSelection(sel);
2816         var_u16.SetSelection(sel);
2817         var_u32.SetSelection(sel);
2818         var_u64.SetSelection(sel);
2819 
2820         var_r32.SetSelection(sel);
2821         var_r64.SetSelection(sel);
2822 
2823         for (size_t t = 0; t < NSteps; ++t)
2824         {
2825             var_i8.SetStepSelection({t, 1});
2826             var_i16.SetStepSelection({t, 1});
2827             var_i32.SetStepSelection({t, 1});
2828             var_i64.SetStepSelection({t, 1});
2829 
2830             var_u8.SetStepSelection({t, 1});
2831             var_u16.SetStepSelection({t, 1});
2832             var_u32.SetStepSelection({t, 1});
2833             var_u64.SetStepSelection({t, 1});
2834 
2835             var_r32.SetStepSelection({t, 1});
2836             var_r64.SetStepSelection({t, 1});
2837 
2838             hdf5Reader.Get(var_iString, IString);
2839 
2840             hdf5Reader.Get(var_i8, I8.data());
2841             hdf5Reader.Get(var_i16, I16.data());
2842             hdf5Reader.Get(var_i32, I32.data());
2843             hdf5Reader.Get(var_i64, I64.data());
2844 
2845             hdf5Reader.Get(var_u8, U8.data());
2846             hdf5Reader.Get(var_u16, U16.data());
2847             hdf5Reader.Get(var_u32, U32.data());
2848             hdf5Reader.Get(var_u64, U64.data());
2849 
2850             hdf5Reader.Get(var_r32, R32.data());
2851             hdf5Reader.Get(var_r64, R64.data());
2852             hdf5Reader.PerformGets();
2853 
2854             // Generate test data for each rank uniquely
2855             SmallTestData currentTestData = generateNewSmallTestData(
2856                 m_TestData, static_cast<int>(t), mpiRank, mpiSize);
2857 
2858             EXPECT_EQ(IString, currentTestData.S1);
2859 
2860             for (size_t i = 0; i < Nx * Ny; ++i)
2861             {
2862                 std::stringstream ss;
2863                 ss << "t=" << t << " i=" << i << " rank=" << mpiRank;
2864                 std::string msg = ss.str();
2865 
2866                 EXPECT_EQ(I8[i], currentTestData.I8[i]) << msg;
2867                 EXPECT_EQ(I16[i], currentTestData.I16[i]) << msg;
2868                 EXPECT_EQ(I32[i], currentTestData.I32[i]) << msg;
2869                 EXPECT_EQ(I64[i], currentTestData.I64[i]) << msg;
2870                 EXPECT_EQ(U8[i], currentTestData.U8[i]) << msg;
2871                 EXPECT_EQ(U16[i], currentTestData.U16[i]) << msg;
2872                 EXPECT_EQ(U32[i], currentTestData.U32[i]) << msg;
2873                 EXPECT_EQ(U64[i], currentTestData.U64[i]) << msg;
2874                 EXPECT_EQ(R32[i], currentTestData.R32[i]) << msg;
2875                 EXPECT_EQ(R64[i], currentTestData.R64[i]) << msg;
2876             }
2877         }
2878         hdf5Reader.Close();
2879     }
2880 }
2881 
TEST_F(HDF5WriteReadTest,ATTRTESTADIOS2vsHDF5)2882 TEST_F(HDF5WriteReadTest, /*DISABLE_*/ ATTRTESTADIOS2vsHDF5)
2883 {
2884     // Each process would write a 1x8 array and all processes would
2885     // form a mpiSize * Nx 1D array
2886     const std::string h5name = "ATTRTESTADIOS2vsHDF5.h5";
2887     const std::string bpname = "ATTRTESTADIOS2vsHDF5.bp";
2888 
2889     int mpiRank = 0, mpiSize = 1;
2890     // Number of rows
2891     const std::size_t Nx = 8;
2892 
2893     // Number of steps
2894     const std::size_t NSteps = 3;
2895 
2896 #ifdef TEST_HDF5_MPI
2897     MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
2898     MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
2899 #endif
2900 
2901     // Write test data using ADIOS2
2902 
2903 #ifdef TEST_HDF5_MPI
2904     adios2::ADIOS adios(MPI_COMM_WORLD);
2905 #else
2906     adios2::ADIOS adios;
2907 #endif
2908     adios2::IO io = adios.DeclareIO("TestIO");
2909 
2910     std::string var1Name = "var1";
2911     // std::string var1Name = "/var1";
2912     std::string var2Name = "var2";
2913     std::string var3Name = "grp/var3";
2914     std::string var4Name = "var4";
2915 
2916     std::string ioAttrName = "file_notes";
2917     std::string ioAttrValue = "this is a comment";
2918 
2919     std::string v1AttrAName = "var1/meshWidth";
2920     int32_t v1AttrAValue = 111;
2921     std::string v1AttrBName = "var1/meshLength";
2922     int32_t v1AttrBValue = 222;
2923 
2924     std::string v2AttrName = "var2/meshName";
2925     std::string v2AttrValue = "unstructured";
2926 
2927     std::string v3AttrName = var3Name + "/targetDensity";
2928     double v3AttrValue = 55;
2929 
2930     std::string v4AttrName = "var4/unitName";
2931     std::string v4AttrValue = "kg";
2932 
2933     std::string fantacyPathName = "no/such/path";
2934     std::string longerV1AttrName1 = "var1/mesh/level";
2935     std::string longerV1AttrName2 = "mesh/also/level";
2936 
2937     int numAttr = 0;
2938     // Declare 1D variables (NumOfProcesses * Nx)
2939     // The local process' part (start, count) can be defined now or later
2940     // before Write().
2941     {
2942         adios2::Dims shape{static_cast<unsigned int>(Nx * mpiSize)};
2943         adios2::Dims start{static_cast<unsigned int>(Nx * mpiRank)};
2944         adios2::Dims count{static_cast<unsigned int>(Nx)};
2945 
2946         io.DefineVariable<int32_t>(var1Name, shape, start, count);
2947         io.DefineVariable<float>(var2Name, shape, start, count);
2948         io.DefineVariable<double>(var3Name, shape, start, count);
2949 
2950         io.DefineAttribute<std::string>(ioAttrName, ioAttrValue);
2951         numAttr++;
2952 
2953         io.DefineAttribute<int32_t>(v1AttrAName, v1AttrAValue);
2954         numAttr++;
2955         io.DefineAttribute<int32_t>(v1AttrBName, v1AttrBValue);
2956         numAttr++;
2957 
2958         // this expects that  var and attr can have different names
2959         io.DefineAttribute<double>(var1Name, v3AttrValue);
2960         numAttr++;
2961 
2962         // this allows attr can be path like (no need to exist)
2963         io.DefineAttribute<int32_t>(fantacyPathName, v1AttrAValue);
2964         numAttr++;
2965 
2966         // this allows variable can attach attr with long name
2967         io.DefineAttribute<int32_t>(longerV1AttrName1, v1AttrBValue);
2968         numAttr++;
2969         io.DefineAttribute<int32_t>(longerV1AttrName2, v1AttrBValue, var1Name);
2970         numAttr++;
2971 
2972         io.DefineAttribute<std::string>(v2AttrName, v2AttrValue);
2973         numAttr++;
2974         io.DefineAttribute<double>(v3AttrName, v3AttrValue);
2975         numAttr++;
2976     }
2977 
2978     // Create the HDF5 Engine
2979     io.SetEngine("HDF5");
2980 
2981     // HDf5 engine calls the HDF5 common object that calls the hDF5 library.
2982     // The IO functionality, SetParameters and AddTransports will be added
2983     // in the future. For now `io.AddTransport("file", {
2984     // "library", "MPI"}});` is omitted.
2985     // })
2986     // io.AddTransport("File");
2987 
2988     adios2::Engine engine = io.Open(h5name, adios2::Mode::Write);
2989 
2990     for (size_t step = 0; step < NSteps; ++step)
2991     {
2992         // Generate test data for each process uniquely
2993         SmallTestData currentTestData =
2994             generateNewSmallTestData(m_TestData, step, mpiRank, mpiSize);
2995 
2996         // Retrieve the variables that previously went out of scope
2997         auto var1 = io.InquireVariable<int32_t>(var1Name);
2998         auto var2 = io.InquireVariable<float>(var2Name);
2999         auto var3 = io.InquireVariable<double>(var3Name);
3000 
3001         // Make a 1D selection to describe the local dimensions of the
3002         // variable we write and its offsets in the global spaces
3003 
3004         adios2::Box<adios2::Dims> sel({mpiRank * Nx}, {Nx});
3005 
3006         var1.SetSelection(sel);
3007         var2.SetSelection(sel);
3008         var3.SetSelection(sel);
3009 
3010         // Write each one
3011         // fill in the variable with values from starting index to
3012         // starting index + count
3013         engine.BeginStep();
3014         engine.Put(var1, currentTestData.I32.data());
3015         engine.Put(var2, currentTestData.R32.data());
3016         engine.Put(var3, currentTestData.R64.data());
3017         if (step == 1)
3018         {
3019             adios2::Dims shape{static_cast<unsigned int>(Nx * mpiSize)};
3020             adios2::Dims start{static_cast<unsigned int>(Nx * mpiRank)};
3021             adios2::Dims count{static_cast<unsigned int>(Nx)};
3022 
3023             io.DefineVariable<int32_t>(var4Name, shape, start, count);
3024             auto var4 = io.InquireVariable<int32_t>(var4Name);
3025             engine.Put(var4, currentTestData.I32.data());
3026 
3027             io.DefineAttribute<std::string>(v4AttrName, v4AttrValue);
3028             numAttr++;
3029         }
3030 
3031         // Advance to the next time step
3032         engine.EndStep();
3033 
3034         if (step == 1)
3035         {
3036             io.RemoveVariable(var4Name);
3037             io.RemoveAttribute(v4AttrName);
3038         }
3039     }
3040 
3041     // Close the file
3042     engine.Close();
3043 
3044     {
3045         adios2::IO io = adios.DeclareIO("HDF5ReadIO");
3046         io.SetEngine("HDF5");
3047 
3048         adios2::Engine hdf5Reader = io.Open(h5name, adios2::Mode::Read);
3049 
3050         auto var1 = io.InquireVariable<int32_t>(var1Name);
3051         EXPECT_TRUE(var1);
3052         ASSERT_EQ(var1.ShapeID(), adios2::ShapeID::GlobalArray);
3053         ASSERT_EQ(var1.Steps(), NSteps);
3054         ASSERT_EQ(var1.Shape()[0], mpiSize * Nx);
3055 
3056         auto var2 = io.InquireVariable<float>(var2Name);
3057         EXPECT_TRUE(var2);
3058         ASSERT_EQ(var2.ShapeID(), adios2::ShapeID::GlobalArray);
3059         ASSERT_EQ(var2.Steps(), NSteps);
3060         ASSERT_EQ(var2.Shape()[0], mpiSize * Nx);
3061 
3062         auto var3 = io.InquireVariable<double>(var3Name);
3063         EXPECT_TRUE(var3);
3064         ASSERT_EQ(var3.ShapeID(), adios2::ShapeID::GlobalArray);
3065         ASSERT_EQ(var3.Steps(), NSteps);
3066         ASSERT_EQ(var3.Shape()[0], mpiSize * Nx);
3067 
3068         SmallTestData testData;
3069 
3070         std::array<int32_t, Nx> I32;
3071         std::array<float, Nx> R32;
3072         std::array<double, Nx> R64;
3073 
3074         const adios2::Dims start{mpiRank * Nx};
3075         const adios2::Dims count{Nx};
3076 
3077         const adios2::Box<adios2::Dims> sel(start, count);
3078 
3079         var1.SetSelection(sel);
3080         var2.SetSelection(sel);
3081         var3.SetSelection(sel);
3082 
3083         for (size_t t = 0; t < NSteps; ++t)
3084         {
3085             var1.SetStepSelection({t, 1});
3086             var2.SetStepSelection({t, 1});
3087             var3.SetStepSelection({t, 1});
3088 
3089             // Generate test data for each rank uniquely
3090             SmallTestData currentTestData = generateNewSmallTestData(
3091                 m_TestData, static_cast<int>(t), mpiRank, mpiSize);
3092 
3093             hdf5Reader.BeginStep();
3094 
3095             hdf5Reader.Get(var1, I32.data());
3096             hdf5Reader.Get(var2, R32.data());
3097             hdf5Reader.Get(var3, R64.data());
3098 
3099             hdf5Reader.EndStep();
3100 
3101             // EXPECT_EQ(IString, currentTestData.S1);
3102 
3103             for (size_t i = 0; i < Nx; ++i)
3104             {
3105                 std::stringstream ss;
3106                 ss << "t=" << t << " i=" << i << " rank=" << mpiRank;
3107                 std::string msg = ss.str();
3108 
3109                 EXPECT_EQ(I32[i], currentTestData.I32[i]) << msg;
3110                 EXPECT_EQ(R32[i], currentTestData.R32[i]) << msg;
3111                 EXPECT_EQ(R64[i], currentTestData.R64[i]) << msg;
3112             }
3113         }
3114 
3115         const std::map<std::string, adios2::Params> &attributesInfo =
3116             io.AvailableAttributes();
3117 
3118         EXPECT_EQ(numAttr, attributesInfo.size());
3119 
3120         EXPECT_EQ(4, io.AvailableAttributes(var1Name).size());
3121         EXPECT_EQ(1, io.AvailableAttributes(var2Name).size());
3122         EXPECT_EQ(1, io.AvailableAttributes(var3Name).size());
3123 
3124         std::cout << " test below of attrs of var4Name is false b/c "
3125                      "io.m_EngineStep=2 but var4 is only in step 1, this it "
3126                      "thinks so such var"
3127                   << std::endl;
3128         std::cout << " need to fix semantics of io.AvailableAttributes()"
3129                   << std::endl;
3130         // EXPECT_EQ(1, io.AvailableAttributes(var4Name).size());
3131 
3132         std::cout << " other tests will follow after William make changes: "
3133                      "e.g. GetNumAttr(var) etc +  Write a bp file and read "
3134                      "back in hdf5 and verify"
3135                   << std::endl;
3136         /*
3137         hdf5Reader.GetNumAttributes(var1); // expects 2
3138         hdf5Reader.GetNumAttributes(var2); // expects 1
3139         hdf5Reader.GetNumAttributes(var3); // expects 0
3140 
3141         hdf5Reader.GetNumAttributes(); // expects 4
3142         */
3143         hdf5Reader.Close();
3144     }
3145 }
3146 
3147 //******************************************************************************
3148 // main
3149 //******************************************************************************
3150 
main(int argc,char ** argv)3151 int main(int argc, char **argv)
3152 {
3153 #ifdef TEST_HDF5_MPI
3154     MPI_Init(nullptr, nullptr);
3155 #endif
3156 
3157     int result;
3158     ::testing::InitGoogleTest(&argc, argv);
3159     result = RUN_ALL_TESTS();
3160 
3161 #ifdef TEST_HDF5_MPI
3162     MPI_Finalize();
3163 #endif
3164 
3165     return result;
3166 }
3167