diff --git a/CHANGELOG.md b/CHANGELOG.md index 27e19259a..89337cfdc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to ### For users #### Added +* Add tests for HDF5 precision conversion #### Changed diff --git a/plugins/decl_hdf5/tests/compatibility_tests/CMakeLists.txt b/plugins/decl_hdf5/tests/compatibility_tests/CMakeLists.txt index 7b18f57d1..81551ca2f 100644 --- a/plugins/decl_hdf5/tests/compatibility_tests/CMakeLists.txt +++ b/plugins/decl_hdf5/tests/compatibility_tests/CMakeLists.txt @@ -60,3 +60,7 @@ foreach(test_name ${ALL_TEST_NAMES}) endforeach(read_prefix) endforeach(write_prefix) endforeach(test_name) + +add_executable(decl_hdf5_conversion_test decl_hdf5_precision_conversion_test.cxx) +target_link_libraries(decl_hdf5_conversion_test ${HDF5_DEPS} PDI::PDI_C GTest::gmock GTest::gmock_main GTest::gtest GTest::gtest_main) +gtest_discover_tests(decl_hdf5_conversion_test) diff --git a/plugins/decl_hdf5/tests/compatibility_tests/decl_hdf5_precision_conversion_test.cxx b/plugins/decl_hdf5/tests/compatibility_tests/decl_hdf5_precision_conversion_test.cxx new file mode 100644 index 000000000..14100772b --- /dev/null +++ b/plugins/decl_hdf5/tests/compatibility_tests/decl_hdf5_precision_conversion_test.cxx @@ -0,0 +1,147 @@ +/******************************************************************************* + * Copyright (C) 2026 Commissariat a l'energie atomique et aux energies alternatives (CEA) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of CEA nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include +#include + +#include + +#include + +class DeclHdf5: public ::PDI::PdiTest +{}; + +/* Precision conversion with decl_hdf5 + * data in double precision + * file dataset in double, float, and int + */ +TEST_F(DeclHdf5, PrecisionConversion) +{ + InitPdi(PC_parse_string(R"==( +logging: trace +metadata: + N: int +data: + array: {type: array, size: [$N, $N], subtype: double} +plugins: + decl_hdf5: + - file: d2d_test.h5 + datasets: + double_ds: {type: array, size: [$N, $N], subtype: double} + write: + array: + dataset: double_ds + - file: d2f_test.h5 + datasets: + float_ds: {type: array, size: [$N, $N], subtype: float} + write: + array: + dataset: float_ds + - file: d2i_test.h5 + datasets: + int_ds: {type: array, size: [$N, $N], subtype: int} + write: + array: + dataset: int_ds +)==")); + + EXPECT_FALSE(std::filesystem::exists("d2d_test.h5")); + EXPECT_FALSE(std::filesystem::exists("d2f_test.h5")); + EXPECT_FALSE(std::filesystem::exists("d2i_test.h5")); + + static constexpr size_t const N = 100; + PDI_expose("N", &N, PDI_OUT); + + auto const test_array = make_a, N>>(); + PDI_expose("array", test_array.data(), PDI_OUT); + + EXPECT_TRUE(std::filesystem::exists("d2d_test.h5")); + EXPECT_TRUE(std::filesystem::exists("d2f_test.h5")); + EXPECT_TRUE(std::filesystem::exists("d2i_test.h5")); + + // read double precision dataset and compare + hid_t file_id = H5Fopen("d2d_test.h5", H5F_ACC_RDONLY, H5P_DEFAULT); + hid_t dataset_id = H5Dopen2(file_id, "/double_ds", H5P_DEFAULT); + hid_t type_id = H5Dget_type(dataset_id); + + EXPECT_TRUE(H5Tequal(type_id, H5T_IEEE_F64LE)); + std::array, N> read_double_array; + + herr_t status = H5Dread(dataset_id, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, read_double_array.data()); + ASSERT_GE(status, 0); + + EXPECT_EQ(test_array, read_double_array); + + H5Tclose(type_id); + H5Dclose(dataset_id); + H5Fclose(file_id); + + // read simple precision dataset and compare + file_id = H5Fopen("d2f_test.h5", H5F_ACC_RDONLY, H5P_DEFAULT); + dataset_id = H5Dopen2(file_id, "/float_ds", H5P_DEFAULT); + type_id = H5Dget_type(dataset_id); + + EXPECT_TRUE(H5Tequal(type_id, H5T_IEEE_F32LE)); + std::array< std::array, N > read_float_array; + + status = H5Dread(dataset_id, H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL, H5P_DEFAULT, read_float_array.data()); + ASSERT_GE(status, 0); + +#if defined(__clang__) && (__clang_major__ == 15) +// Skipping the numerical comparaison because Clang 15 has known issues with ranges. +#else + EXPECT_THAT(read_float_array, testing::ElementsAreArray(test_array | std::views::transform([](std::array const & aref) { + return testing::Pointwise(testing::FloatEq(), aref); + }))); +#endif + + H5Tclose(type_id); + H5Dclose(dataset_id); + H5Fclose(file_id); + + // read integer dataset and compare + file_id = H5Fopen("d2i_test.h5", H5F_ACC_RDONLY, H5P_DEFAULT); + dataset_id = H5Dopen2(file_id, "/int_ds", H5P_DEFAULT); + type_id = H5Dget_type(dataset_id); + + EXPECT_TRUE(H5Tequal(type_id, H5T_STD_I32LE)); + std::array< std::array, N > read_int_array; + + status = H5Dread(dataset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, read_int_array.data()); + ASSERT_GE(status, 0); + +#if defined(__clang__) && (__clang_major__ == 15) +// Skipping the numerical comparaison because Clang 15 has known issues with ranges. +#else + EXPECT_THAT(read_int_array, testing::ElementsAreArray(test_array | std::views::transform([](std::array const & aref) { + return testing::ElementsAreArray(aref | std::views::transform([](double const & ref) { + return static_cast(ref); + })); + }))); +#endif + + H5Tclose(type_id); + H5Dclose(dataset_id); + H5Fclose(file_id); +}