From cc5cff9e943b55e83c632de1a3b6a05e2ed3972f Mon Sep 17 00:00:00 2001 From: Dimitri Vlachos Date: Wed, 29 Jan 2025 13:09:02 +0000 Subject: [PATCH] Update h5write to handle pre-existing datasets and add test cases --- include/dx2/h5/h5write.h | 47 ++++++++++++------ tests/test_write_h5_array.cxx | 93 +++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+), 14 deletions(-) diff --git a/include/dx2/h5/h5write.h b/include/dx2/h5/h5write.h index d41850c..2b1615e 100644 --- a/include/dx2/h5/h5write.h +++ b/include/dx2/h5/h5write.h @@ -201,20 +201,41 @@ void write_data_to_h5_file(const std::string &filename, // Flatten the data into a 1D vector auto flat_data = flatten(data); - // Create dataspace for the dataset - hid_t dataspace = H5Screate_simple(shape.size(), shape.data(), NULL); - if (dataspace < 0) { - throw std::runtime_error( - "Error: Unable to create dataspace for dataset: " + dataset_name); - } - - // Create the dataset - hid_t dataset = H5Dcreate(group, dataset_name.c_str(), H5T_NATIVE_DOUBLE, - dataspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + // Check if dataset exists + hid_t dataset = H5Dopen(group, dataset_name.c_str(), H5P_DEFAULT); if (dataset < 0) { + // Dataset does not exist, create it + hid_t dataspace = H5Screate_simple(shape.size(), shape.data(), NULL); + if (dataspace < 0) { + throw std::runtime_error( + "Error: Unable to create dataspace for dataset: " + dataset_name); + } + + dataset = H5Dcreate(group, dataset_name.c_str(), H5T_NATIVE_DOUBLE, + dataspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + if (dataset < 0) { + H5Sclose(dataspace); + throw std::runtime_error("Error: Unable to create dataset: " + + dataset_name); + } + H5Sclose(dataspace); - throw std::runtime_error("Error: Unable to create dataset: " + - dataset_name); + } else { + // Dataset exists, check if the shape matches + hid_t existing_space = H5Dget_space(dataset); + int ndims = H5Sget_simple_extent_ndims(existing_space); + std::vector existing_dims(ndims); + H5Sget_simple_extent_dims(existing_space, existing_dims.data(), NULL); + H5Sclose(existing_space); + + if (existing_dims != shape) { + H5Dclose(dataset); + throw std::runtime_error( + "Error: Dataset shape mismatch. Cannot overwrite dataset: " + + dataset_name); + } + + // Dataset exists and has the correct shape, proceed to overwrite } // Write the data to the dataset @@ -222,14 +243,12 @@ void write_data_to_h5_file(const std::string &filename, H5P_DEFAULT, flat_data.data()); if (status < 0) { H5Dclose(dataset); - H5Sclose(dataspace); throw std::runtime_error("Error: Unable to write data to dataset: " + dataset_name); } // Cleanup resources H5Dclose(dataset); - H5Sclose(dataspace); H5Gclose(group); } catch (...) { H5Fclose(file); diff --git a/tests/test_write_h5_array.cxx b/tests/test_write_h5_array.cxx index 7e323ea..f85ecd1 100644 --- a/tests/test_write_h5_array.cxx +++ b/tests/test_write_h5_array.cxx @@ -253,4 +253,97 @@ TEST(WriteDataTests, WriteEmptyDataset) { // Clean up test file std::filesystem::remove(filename); } + +// Test writing to a file that already exists +TEST(WriteDataTests, WriteToExistingFile) { + std::string filename = "test_existing_file.h5"; + std::string dataset_path = "/existing_group/existing_dataset"; + + // Create the file first + hid_t file = + H5Fcreate(filename.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + ASSERT_GE(file, 0) << "Failed to create HDF5 file."; + H5Fclose(file); + + // Now attempt to write data into it + std::vector data = {1.0, 2.0, 3.0, 4.0}; + write_data_to_h5_file(filename, dataset_path, data); + + // Read back the data to verify it was written correctly + auto read_data = read_array_from_h5_file(filename, dataset_path); + EXPECT_EQ(data, read_data); + + // Clean up test file + std::filesystem::remove(filename); +} + +// Test writing to a group that already exists +TEST(WriteDataTests, WriteToExistingGroup) { + std::string filename = "test_existing_group.h5"; + std::string dataset_path = "/group_1/dataset_1"; + + // Create file and group manually + hid_t file = + H5Fcreate(filename.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + ASSERT_GE(file, 0) << "Failed to create HDF5 file."; + + hid_t group = + H5Gcreate(file, "/group_1", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + ASSERT_GE(group, 0) << "Failed to create group."; + + H5Gclose(group); + H5Fclose(file); + + // Now attempt to write data into the existing group + std::vector data = {10.0, 20.0, 30.0, 40.0}; + write_data_to_h5_file(filename, dataset_path, data); + + // Read back the data to verify it was written correctly + auto read_data = read_array_from_h5_file(filename, dataset_path); + EXPECT_EQ(data, read_data); + + // Clean up test file + std::filesystem::remove(filename); +} + +// Test writing to a dataset that already exists +TEST(WriteDataTests, WriteToExistingDataset) { + std::string filename = "test_existing_dataset.h5"; + std::string dataset_path = "/group_2/dataset_existing"; + + // Create file and dataset manually + hid_t file = + H5Fcreate(filename.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + ASSERT_GE(file, 0) << "Failed to create HDF5 file."; + + hid_t group = + H5Gcreate(file, "/group_2", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + ASSERT_GE(group, 0) << "Failed to create group."; + + hsize_t dims[1] = {4}; // 1D dataset with 4 elements + hid_t dataspace = H5Screate_simple(1, dims, NULL); + hid_t dataset = H5Dcreate(group, "dataset_existing", H5T_NATIVE_DOUBLE, + dataspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + ASSERT_GE(dataset, 0) << "Failed to create dataset."; + + std::vector initial_data = {1.1, 2.2, 3.3, 4.4}; + H5Dwrite(dataset, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, + initial_data.data()); + + H5Dclose(dataset); + H5Sclose(dataspace); + H5Gclose(group); + H5Fclose(file); + + // Now attempt to overwrite the dataset + std::vector new_data = {5.5, 6.6, 7.7, 8.8}; + write_data_to_h5_file(filename, dataset_path, new_data); + + // Read back the data to verify it was overwritten correctly + auto read_data = read_array_from_h5_file(filename, dataset_path); + EXPECT_EQ(new_data, read_data); + + // Clean up test file + std::filesystem::remove(filename); +} #pragma endregion write_h5 tests \ No newline at end of file