From 011c70a2c0148403c624e3d420aeb218e9331760 Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Wed, 29 Nov 2023 19:00:43 +0100 Subject: [PATCH] Move selection related tests. Part of reorganizing the tests requires grouping tests. One such group is anything related to selections, e.g. column, row or point selections, hyperslabs, etc. This commit only moves code from one file to the next without any changes. --- tests/unit/CMakeLists.txt | 2 +- tests/unit/test_high_five_selection.cpp | 536 ++++++++++++++++++++++++ tests/unit/tests_high_five_base.cpp | 505 ---------------------- 3 files changed, 537 insertions(+), 506 deletions(-) create mode 100644 tests/unit/test_high_five_selection.cpp diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index 3644d117c..cb6752cbc 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -7,7 +7,7 @@ if(MSVC) endif() ## Base tests -foreach(test_name tests_high_five_base tests_high_five_multi_dims tests_high_five_easy test_all_types) +foreach(test_name tests_high_five_base tests_high_five_multi_dims tests_high_five_easy test_all_types test_high_five_selection) add_executable(${test_name} "${test_name}.cpp") target_link_libraries(${test_name} HighFive HighFiveWarnings Catch2::Catch2WithMain) catch_discover_tests(${test_name}) diff --git a/tests/unit/test_high_five_selection.cpp b/tests/unit/test_high_five_selection.cpp new file mode 100644 index 000000000..e3b91e4cc --- /dev/null +++ b/tests/unit/test_high_five_selection.cpp @@ -0,0 +1,536 @@ +/* + * Copyright (c), 2017-2023, Blue Brain Project - EPFL + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include "tests_high_five.hpp" + +using namespace HighFive; +using Catch::Matchers::Equals; + +template +void selectionArraySimpleTest() { + typedef typename std::vector Vector; + + std::ostringstream filename; + filename << "h5_rw_select_test_" << typeNameHelper() << "_test.h5"; + + const size_t size_x = 10; + const size_t offset_x = 2, count_x = 5; + + const std::string dataset_name("dset"); + + Vector values(size_x); + + ContentGenerate generator; + std::generate(values.begin(), values.end(), generator); + + // Create a new file using the default property lists. + File file(filename.str(), File::ReadWrite | File::Create | File::Truncate); + + DataSet dataset = file.createDataSet(dataset_name, DataSpace::From(values)); + + dataset.write(values); + + file.flush(); + + // select slice + { + // read it back + Vector result; + std::vector offset{offset_x}; + std::vector size{count_x}; + + Selection slice = dataset.select(offset, size); + + CHECK(slice.getSpace().getDimensions()[0] == size_x); + CHECK(slice.getMemSpace().getDimensions()[0] == count_x); + + slice.read(result); + + CHECK(result.size() == 5); + + for (size_t i = 0; i < count_x; ++i) { + REQUIRE(values[i + offset_x] == result[i]); + } + } + + // select cherry pick + { + // read it back + Vector result; + std::vector ids{1, 3, 4, 7}; + + Selection slice = dataset.select(ElementSet(ids)); + + CHECK(slice.getSpace().getDimensions()[0] == size_x); + CHECK(slice.getMemSpace().getDimensions()[0] == ids.size()); + + slice.read(result); + + CHECK(result.size() == ids.size()); + + for (size_t i = 0; i < ids.size(); ++i) { + const std::size_t id = ids[i]; + REQUIRE(values[id] == result[i]); + } + } +} + +TEST_CASE("selectionArraySimpleString") { + selectionArraySimpleTest(); +} + +TEMPLATE_LIST_TEST_CASE("selectionArraySimple", "[template]", dataset_test_types) { + selectionArraySimpleTest(); +} + +TEST_CASE("selectionByElementMultiDim") { + const std::string file_name("h5_test_selection_multi_dim.h5"); + // Create a 2-dim dataset + File file(file_name, File::ReadWrite | File::Create | File::Truncate); + std::vector dims{3, 3}; + + auto set = file.createDataSet("test", DataSpace(dims), AtomicType()); + int values[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; + set.write(values); + + { + int value; + set.select(ElementSet{{1, 1}}).read(value); + CHECK(value == 5); + } + + { + int value[2]; + set.select(ElementSet{0, 0, 2, 2}).read(value); + CHECK(value[0] == 1); + CHECK(value[1] == 9); + } + + { + int value[2]; + set.select(ElementSet{{0, 1}, {1, 2}}).read(value); + CHECK(value[0] == 2); + CHECK(value[1] == 6); + } + + { + SilenceHDF5 silencer; + CHECK_THROWS_AS(set.select(ElementSet{0, 1, 2}), DataSpaceException); + } +} + +template +void columnSelectionTest() { + std::ostringstream filename; + filename << "h5_rw_select_column_test_" << typeNameHelper() << "_test.h5"; + + const size_t x_size = 10; + const size_t y_size = 7; + + const std::string dataset_name("dset"); + + T values[x_size][y_size]; + + ContentGenerate generator; + generate2D(values, x_size, y_size, generator); + + // Create a new file using the default property lists. + File file(filename.str(), File::ReadWrite | File::Create | File::Truncate); + + // Create the data space for the dataset. + std::vector dims{x_size, y_size}; + + DataSpace dataspace(dims); + // Create a dataset with arbitrary type + DataSet dataset = file.createDataSet(dataset_name, dataspace); + + dataset.write(values); + + file.flush(); + + std::vector columns{1, 3, 5}; + + Selection slice = dataset.select(columns); + T result[x_size][3]; + slice.read(result); + + CHECK(slice.getSpace().getDimensions()[0] == x_size); + CHECK(slice.getMemSpace().getDimensions()[0] == x_size); + + for (size_t i = 0; i < 3; ++i) + for (size_t j = 0; j < x_size; ++j) + REQUIRE(result[j][i] == values[j][columns[i]]); +} + +TEMPLATE_LIST_TEST_CASE("columnSelection", "[template]", numerical_test_types) { + columnSelectionTest(); +} + +std::vector> global_indices_2d(const std::vector& offset, + const std::vector& count) { + std::vector> indices; + indices.reserve(count[0] * count[1]); + + for (size_t i = 0; i < count[0]; ++i) { + for (size_t j = 0; j < count[1]; ++j) { + indices.push_back({offset[0] + i, offset[1] + j}); + } + } + + return indices; +} + +std::vector> local_indices_2d(const std::vector& count) { + return global_indices_2d({0ul, 0ul}, count); +} + +std::vector> local_indices_1d(const std::vector& count) { + std::vector> local_indices; + for (size_t i = 0; i < count[0]; ++i) { + local_indices.push_back({i}); + } + + return local_indices; +} + +struct RegularHyperSlabAnswer { + static RegularHyperSlabAnswer createRegular(const std::vector& offset, + const std::vector& count) { + return RegularHyperSlabAnswer{global_indices_2d(offset, count), + local_indices_1d({count[0] * count[1]})}; + } + + // These are the selected indices in the + // outer (larger) array. + std::vector> global_indices; + + // These are the selected indices in the compacted (inner) + // array. + std::vector> local_indices; +}; + +struct RegularHyperSlabTestData { + std::string desc; + HyperSlab slab; + RegularHyperSlabAnswer answer; +}; + +std::vector make_regular_hyperslab_test_data() { + std::vector test_data; + + // The dataset is 10x8, we define the following regular + // hyperslabs: + // x----------------x + // | | + // | x------x e | 1 + // | | a | | + // x-|------|-------x 3 + // | | x-|-------x 4 + // | | | | b | + // | | c-|-------c 5 + // | | b-|-------b 6 + // | | | | c | + // | d----x-d-------x 7 + // | | d | | + // | a------a | 9 + // | | + // ------------------ + // 1 3 4 8 + + std::map slabs; + + slabs["a"] = RegularHyperSlab(/* offset = */ {1ul, 1ul}, + /* count = */ {8ul, 3ul}); + + slabs["b"] = RegularHyperSlab(/* offset = */ {4ul, 3ul}, + /* count = */ {2ul, 5ul}); + + slabs["c"] = RegularHyperSlab(/* offset = */ {5ul, 3ul}, + /* count = */ {2ul, 5ul}); + + slabs["d"] = RegularHyperSlab(/* offset = */ {7ul, 1ul}, + /* count = */ {2ul, 3ul}); + + slabs["e"] = RegularHyperSlab(/* offset = */ {0ul, 0ul}, + /* count = */ {3ul, 8ul}); + + // Union, regular + auto slab_bc_union = HyperSlab(slabs["b"]) | slabs["c"]; + auto answer_bc_union = RegularHyperSlabAnswer::createRegular({4ul, 3ul}, {3ul, 5ul}); + test_data.push_back({"b | c", slab_bc_union, answer_bc_union}); + + // Intersection, always regular + auto slab_ab_cut = HyperSlab(slabs["a"]) & slabs["b"]; + auto answer_ab_cut = RegularHyperSlabAnswer::createRegular({4ul, 3ul}, {2ul, 1ul}); + test_data.push_back({"a & b", slab_ab_cut, answer_ab_cut}); + + // Intersection, always regular + auto slab_bc_cut = HyperSlab(slabs["b"]) & slabs["c"]; + auto answer_bc_cut = RegularHyperSlabAnswer::createRegular({5ul, 3ul}, {1ul, 5ul}); + test_data.push_back({"b & c", slab_bc_cut, answer_bc_cut}); + + // Xor, regular + auto slab_ad_xor = HyperSlab(slabs["a"]) ^ slabs["d"]; + auto answer_ad_xor = RegularHyperSlabAnswer::createRegular({1ul, 1ul}, {6ul, 3ul}); + test_data.push_back({"a ^ b", slab_ad_xor, answer_ad_xor}); + + // (not b) and c, regular + auto slab_bc_nota = HyperSlab(slabs["b"]).notA(slabs["c"]); + auto answer_bc_nota = RegularHyperSlabAnswer::createRegular({6ul, 3ul}, {1ul, 5ul}); + test_data.push_back({"b notA a", slab_bc_nota, answer_bc_nota}); + + // (not c) and b, regular + auto slab_cb_notb = HyperSlab(slabs["c"]).notB(slabs["b"]); + auto answer_cb_notb = RegularHyperSlabAnswer::createRegular({6ul, 3ul}, {1ul, 5ul}); + test_data.push_back({"c notB b", slab_cb_notb, answer_cb_notb}); + + return test_data; +} + +template +File setupHyperSlabFile(T (&values)[x_size][y_size], + const std::string& filename, + const std::string& dataset_name) { + ContentGenerate generator; + generate2D(values, x_size, y_size, generator); + + // Create a new file using the default property lists. + File file(filename, File::ReadWrite | File::Create | File::Truncate); + + // Create the data space for the dataset. + std::vector dims{x_size, y_size}; + + DataSpace dataspace(dims); + // Create a dataset with arbitrary type + DataSet dataset = file.createDataSet(dataset_name, dataspace); + + dataset.write(values); + file.flush(); + + return file; +} + +template +void regularHyperSlabSelectionTest() { + std::ostringstream filename; + filename << "h5_rw_select_regular_hyperslab_test_" << typeNameHelper() << "_test.h5"; + const std::string dataset_name("dset"); + + const size_t x_size = 10; + const size_t y_size = 8; + + T values[x_size][y_size]; + + auto file = setupHyperSlabFile(values, filename.str(), dataset_name); + auto test_cases = make_regular_hyperslab_test_data(); + + for (const auto& test_case: test_cases) { + SECTION(test_case.desc) { + std::vector result; + + file.getDataSet(dataset_name).select(test_case.slab).read(result); + + auto n_selected = test_case.answer.global_indices.size(); + for (size_t i = 0; i < n_selected; ++i) { + const auto ig = test_case.answer.global_indices[i]; + const auto il = test_case.answer.local_indices[i]; + + REQUIRE(result[il[0]] == values[ig[0]][ig[1]]); + } + } + } +} + +TEMPLATE_LIST_TEST_CASE("hyperSlabSelection", "[template]", numerical_test_types) { + regularHyperSlabSelectionTest(); +} + +struct IrregularHyperSlabAnswer { + // These are the selected indices in the outer (larger) array. + std::vector> global_indices; +}; + +struct IrregularHyperSlabTestData { + std::string desc; + HyperSlab slab; + IrregularHyperSlabAnswer answer; +}; + +std::vector make_irregular_hyperslab_test_data() { + // The dataset is 10x8, with two regular hyperslabs: + // x----------------x + // | | + // | bbbb | + // | bbbb | + // | aaaabb | + // | aaaabb | + // | bbbb | + // | bbbb | + // | | + // | | + // | | + // | | + // ------------------ + + auto slabs = std::map{}; + slabs["a"] = RegularHyperSlab{{2ul, 0ul}, {1ul, 2ul}}; + slabs["b"] = RegularHyperSlab{{1ul, 1ul}, {3ul, 2ul}}; + + std::vector test_data; + + // Union, irregular + auto slab_ab_union = HyperSlab(slabs["a"]) | slabs["b"]; + // clang-format off + auto answer_ab_union = IrregularHyperSlabAnswer{{ + {1ul, 1ul}, {1ul, 2ul}, + {2ul, 0ul}, {2ul, 1ul}, {2ul, 2ul}, + {3ul, 1ul}, {3ul, 2ul} + }}; + // clang-format on + test_data.push_back({"a | b", slab_ab_union, answer_ab_union}); + + // xor, irregular + auto slab_ab_xor = HyperSlab(slabs["a"]) ^ slabs["b"]; + // clang-format off + auto answer_ab_xor = IrregularHyperSlabAnswer{{ + {1ul, 1ul}, {1ul, 2ul}, + {2ul, 0ul}, {2ul, 2ul}, + {3ul, 1ul}, {3ul, 2ul} + }}; + // clang-format on + test_data.push_back({"a xor b", slab_ab_xor, answer_ab_xor}); + + // (not a) and e, irregular + auto slab_ab_nota = HyperSlab(slabs["a"]).notA(slabs["b"]); + // clang-format off + auto answer_ab_nota = IrregularHyperSlabAnswer{{ + {1ul, 1ul}, {1ul, 2ul}, + {2ul, 2ul}, + {3ul, 1ul}, {3ul, 2ul} + }}; + // clang-format on + test_data.push_back({"a nota b", slab_ab_nota, answer_ab_nota}); + + // (not a) and e, irregular + auto slab_ba_notb = HyperSlab(slabs["b"]).notB(slabs["a"]); + // clang-format off + auto answer_ba_notb = IrregularHyperSlabAnswer{{ + {1ul, 1ul}, {1ul, 2ul}, + {2ul, 2ul}, + {3ul, 1ul}, {3ul, 2ul} + }}; + // clang-format on + test_data.push_back({"b notb a", slab_ba_notb, answer_ba_notb}); + + return test_data; +} + +template +void irregularHyperSlabSelectionReadTest() { + std::ostringstream filename; + filename << "h5_write_select_irregular_hyperslab_test_" << typeNameHelper() << "_test.h5"; + + const std::string dataset_name("dset"); + + const size_t x_size = 10; + const size_t y_size = 8; + + T values[x_size][y_size]; + auto file = setupHyperSlabFile(values, filename.str(), dataset_name); + + auto test_cases = make_irregular_hyperslab_test_data(); + + for (const auto& test_case: test_cases) { + SECTION(test_case.desc) { + std::vector result; + + file.getDataSet(dataset_name).select(test_case.slab).read(result); + + auto n_selected = test_case.answer.global_indices.size(); + for (size_t i = 0; i < n_selected; ++i) { + const auto ig = test_case.answer.global_indices[i]; + + REQUIRE(result[i] == values[ig[0]][ig[1]]); + } + } + } +} + +TEMPLATE_LIST_TEST_CASE("irregularHyperSlabSelectionRead", "[template]", numerical_test_types) { + irregularHyperSlabSelectionReadTest(); +} + +template +void irregularHyperSlabSelectionWriteTest() { + std::ostringstream filename; + filename << "h5_write_select_irregular_hyperslab_test_" << typeNameHelper() << "_test.h5"; + + const std::string dataset_name("dset"); + + const size_t x_size = 10; + const size_t y_size = 8; + + T orig_values[x_size][y_size]; + auto file = setupHyperSlabFile(orig_values, filename.str(), dataset_name); + + auto test_cases = make_irregular_hyperslab_test_data(); + + for (const auto& test_case: test_cases) { + SECTION(test_case.desc) { + auto n_selected = test_case.answer.global_indices.size(); + std::vector changed_values(n_selected); + ContentGenerate gen; + std::generate(changed_values.begin(), changed_values.end(), gen); + + file.getDataSet(dataset_name).select(test_case.slab).write(changed_values); + + T overwritten_values[x_size][y_size]; + file.getDataSet(dataset_name).read(overwritten_values); + + T expected_values[x_size][y_size]; + for (size_t i = 0; i < x_size; ++i) { + for (size_t j = 0; j < y_size; ++j) { + expected_values[i][j] = orig_values[i][j]; + } + } + + for (size_t i = 0; i < n_selected; ++i) { + const auto ig = test_case.answer.global_indices[i]; + expected_values[ig[0]][ig[1]] = changed_values[i]; + } + + for (size_t i = 0; i < x_size; ++i) { + for (size_t j = 0; j < y_size; ++j) { + REQUIRE(expected_values[i][j] == overwritten_values[i][j]); + } + } + } + } +} + +TEMPLATE_LIST_TEST_CASE("irregularHyperSlabSelectionWrite", "[template]", std::tuple) { + irregularHyperSlabSelectionWriteTest(); +} diff --git a/tests/unit/tests_high_five_base.cpp b/tests/unit/tests_high_five_base.cpp index 5cd0554e4..1ba790b3a 100644 --- a/tests/unit/tests_high_five_base.cpp +++ b/tests/unit/tests_high_five_base.cpp @@ -1112,511 +1112,6 @@ TEST_CASE("datasetOffset") { CHECK(ds_read.getOffset() > 0); } -template -void selectionArraySimpleTest() { - typedef typename std::vector Vector; - - std::ostringstream filename; - filename << "h5_rw_select_test_" << typeNameHelper() << "_test.h5"; - - const size_t size_x = 10; - const size_t offset_x = 2, count_x = 5; - - const std::string dataset_name("dset"); - - Vector values(size_x); - - ContentGenerate generator; - std::generate(values.begin(), values.end(), generator); - - // Create a new file using the default property lists. - File file(filename.str(), File::ReadWrite | File::Create | File::Truncate); - - DataSet dataset = file.createDataSet(dataset_name, DataSpace::From(values)); - - dataset.write(values); - - file.flush(); - - // select slice - { - // read it back - Vector result; - std::vector offset{offset_x}; - std::vector size{count_x}; - - Selection slice = dataset.select(offset, size); - - CHECK(slice.getSpace().getDimensions()[0] == size_x); - CHECK(slice.getMemSpace().getDimensions()[0] == count_x); - - slice.read(result); - - CHECK(result.size() == 5); - - for (size_t i = 0; i < count_x; ++i) { - REQUIRE(values[i + offset_x] == result[i]); - } - } - - // select cherry pick - { - // read it back - Vector result; - std::vector ids{1, 3, 4, 7}; - - Selection slice = dataset.select(ElementSet(ids)); - - CHECK(slice.getSpace().getDimensions()[0] == size_x); - CHECK(slice.getMemSpace().getDimensions()[0] == ids.size()); - - slice.read(result); - - CHECK(result.size() == ids.size()); - - for (size_t i = 0; i < ids.size(); ++i) { - const std::size_t id = ids[i]; - REQUIRE(values[id] == result[i]); - } - } -} - -TEST_CASE("selectionArraySimpleString") { - selectionArraySimpleTest(); -} - -TEMPLATE_LIST_TEST_CASE("selectionArraySimple", "[template]", dataset_test_types) { - selectionArraySimpleTest(); -} - -TEST_CASE("selectionByElementMultiDim") { - const std::string file_name("h5_test_selection_multi_dim.h5"); - // Create a 2-dim dataset - File file(file_name, File::ReadWrite | File::Create | File::Truncate); - std::vector dims{3, 3}; - - auto set = file.createDataSet("test", DataSpace(dims), AtomicType()); - int values[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; - set.write(values); - - { - int value; - set.select(ElementSet{{1, 1}}).read(value); - CHECK(value == 5); - } - - { - int value[2]; - set.select(ElementSet{0, 0, 2, 2}).read(value); - CHECK(value[0] == 1); - CHECK(value[1] == 9); - } - - { - int value[2]; - set.select(ElementSet{{0, 1}, {1, 2}}).read(value); - CHECK(value[0] == 2); - CHECK(value[1] == 6); - } - - { - SilenceHDF5 silencer; - CHECK_THROWS_AS(set.select(ElementSet{0, 1, 2}), DataSpaceException); - } -} - -template -void columnSelectionTest() { - std::ostringstream filename; - filename << "h5_rw_select_column_test_" << typeNameHelper() << "_test.h5"; - - const size_t x_size = 10; - const size_t y_size = 7; - - const std::string dataset_name("dset"); - - T values[x_size][y_size]; - - ContentGenerate generator; - generate2D(values, x_size, y_size, generator); - - // Create a new file using the default property lists. - File file(filename.str(), File::ReadWrite | File::Create | File::Truncate); - - // Create the data space for the dataset. - std::vector dims{x_size, y_size}; - - DataSpace dataspace(dims); - // Create a dataset with arbitrary type - DataSet dataset = file.createDataSet(dataset_name, dataspace); - - dataset.write(values); - - file.flush(); - - std::vector columns{1, 3, 5}; - - Selection slice = dataset.select(columns); - T result[x_size][3]; - slice.read(result); - - CHECK(slice.getSpace().getDimensions()[0] == x_size); - CHECK(slice.getMemSpace().getDimensions()[0] == x_size); - - for (size_t i = 0; i < 3; ++i) - for (size_t j = 0; j < x_size; ++j) - REQUIRE(result[j][i] == values[j][columns[i]]); -} - -TEMPLATE_LIST_TEST_CASE("columnSelection", "[template]", numerical_test_types) { - columnSelectionTest(); -} - -std::vector> global_indices_2d(const std::vector& offset, - const std::vector& count) { - std::vector> indices; - indices.reserve(count[0] * count[1]); - - for (size_t i = 0; i < count[0]; ++i) { - for (size_t j = 0; j < count[1]; ++j) { - indices.push_back({offset[0] + i, offset[1] + j}); - } - } - - return indices; -} - -std::vector> local_indices_2d(const std::vector& count) { - return global_indices_2d({0ul, 0ul}, count); -} - -std::vector> local_indices_1d(const std::vector& count) { - std::vector> local_indices; - for (size_t i = 0; i < count[0]; ++i) { - local_indices.push_back({i}); - } - - return local_indices; -} - -struct RegularHyperSlabAnswer { - static RegularHyperSlabAnswer createRegular(const std::vector& offset, - const std::vector& count) { - return RegularHyperSlabAnswer{global_indices_2d(offset, count), - local_indices_1d({count[0] * count[1]})}; - } - - // These are the selected indices in the - // outer (larger) array. - std::vector> global_indices; - - // These are the selected indices in the compacted (inner) - // array. - std::vector> local_indices; -}; - -struct RegularHyperSlabTestData { - std::string desc; - HyperSlab slab; - RegularHyperSlabAnswer answer; -}; - -std::vector make_regular_hyperslab_test_data() { - std::vector test_data; - - // The dataset is 10x8, we define the following regular - // hyperslabs: - // x----------------x - // | | - // | x------x e | 1 - // | | a | | - // x-|------|-------x 3 - // | | x-|-------x 4 - // | | | | b | - // | | c-|-------c 5 - // | | b-|-------b 6 - // | | | | c | - // | d----x-d-------x 7 - // | | d | | - // | a------a | 9 - // | | - // ------------------ - // 1 3 4 8 - - std::map slabs; - - slabs["a"] = RegularHyperSlab(/* offset = */ {1ul, 1ul}, - /* count = */ {8ul, 3ul}); - - slabs["b"] = RegularHyperSlab(/* offset = */ {4ul, 3ul}, - /* count = */ {2ul, 5ul}); - - slabs["c"] = RegularHyperSlab(/* offset = */ {5ul, 3ul}, - /* count = */ {2ul, 5ul}); - - slabs["d"] = RegularHyperSlab(/* offset = */ {7ul, 1ul}, - /* count = */ {2ul, 3ul}); - - slabs["e"] = RegularHyperSlab(/* offset = */ {0ul, 0ul}, - /* count = */ {3ul, 8ul}); - - // Union, regular - auto slab_bc_union = HyperSlab(slabs["b"]) | slabs["c"]; - auto answer_bc_union = RegularHyperSlabAnswer::createRegular({4ul, 3ul}, {3ul, 5ul}); - test_data.push_back({"b | c", slab_bc_union, answer_bc_union}); - - // Intersection, always regular - auto slab_ab_cut = HyperSlab(slabs["a"]) & slabs["b"]; - auto answer_ab_cut = RegularHyperSlabAnswer::createRegular({4ul, 3ul}, {2ul, 1ul}); - test_data.push_back({"a & b", slab_ab_cut, answer_ab_cut}); - - // Intersection, always regular - auto slab_bc_cut = HyperSlab(slabs["b"]) & slabs["c"]; - auto answer_bc_cut = RegularHyperSlabAnswer::createRegular({5ul, 3ul}, {1ul, 5ul}); - test_data.push_back({"b & c", slab_bc_cut, answer_bc_cut}); - - // Xor, regular - auto slab_ad_xor = HyperSlab(slabs["a"]) ^ slabs["d"]; - auto answer_ad_xor = RegularHyperSlabAnswer::createRegular({1ul, 1ul}, {6ul, 3ul}); - test_data.push_back({"a ^ b", slab_ad_xor, answer_ad_xor}); - - // (not b) and c, regular - auto slab_bc_nota = HyperSlab(slabs["b"]).notA(slabs["c"]); - auto answer_bc_nota = RegularHyperSlabAnswer::createRegular({6ul, 3ul}, {1ul, 5ul}); - test_data.push_back({"b notA a", slab_bc_nota, answer_bc_nota}); - - // (not c) and b, regular - auto slab_cb_notb = HyperSlab(slabs["c"]).notB(slabs["b"]); - auto answer_cb_notb = RegularHyperSlabAnswer::createRegular({6ul, 3ul}, {1ul, 5ul}); - test_data.push_back({"c notB b", slab_cb_notb, answer_cb_notb}); - - return test_data; -} - -template -File setupHyperSlabFile(T (&values)[x_size][y_size], - const std::string& filename, - const std::string& dataset_name) { - ContentGenerate generator; - generate2D(values, x_size, y_size, generator); - - // Create a new file using the default property lists. - File file(filename, File::ReadWrite | File::Create | File::Truncate); - - // Create the data space for the dataset. - std::vector dims{x_size, y_size}; - - DataSpace dataspace(dims); - // Create a dataset with arbitrary type - DataSet dataset = file.createDataSet(dataset_name, dataspace); - - dataset.write(values); - file.flush(); - - return file; -} - -template -void regularHyperSlabSelectionTest() { - std::ostringstream filename; - filename << "h5_rw_select_regular_hyperslab_test_" << typeNameHelper() << "_test.h5"; - const std::string dataset_name("dset"); - - const size_t x_size = 10; - const size_t y_size = 8; - - T values[x_size][y_size]; - - auto file = setupHyperSlabFile(values, filename.str(), dataset_name); - auto test_cases = make_regular_hyperslab_test_data(); - - for (const auto& test_case: test_cases) { - SECTION(test_case.desc) { - std::vector result; - - file.getDataSet(dataset_name).select(test_case.slab).read(result); - - auto n_selected = test_case.answer.global_indices.size(); - for (size_t i = 0; i < n_selected; ++i) { - const auto ig = test_case.answer.global_indices[i]; - const auto il = test_case.answer.local_indices[i]; - - REQUIRE(result[il[0]] == values[ig[0]][ig[1]]); - } - } - } -} - -TEMPLATE_LIST_TEST_CASE("hyperSlabSelection", "[template]", numerical_test_types) { - regularHyperSlabSelectionTest(); -} - -struct IrregularHyperSlabAnswer { - // These are the selected indices in the outer (larger) array. - std::vector> global_indices; -}; - -struct IrregularHyperSlabTestData { - std::string desc; - HyperSlab slab; - IrregularHyperSlabAnswer answer; -}; - -std::vector make_irregular_hyperslab_test_data() { - // The dataset is 10x8, with two regular hyperslabs: - // x----------------x - // | | - // | bbbb | - // | bbbb | - // | aaaabb | - // | aaaabb | - // | bbbb | - // | bbbb | - // | | - // | | - // | | - // | | - // ------------------ - - auto slabs = std::map{}; - slabs["a"] = RegularHyperSlab{{2ul, 0ul}, {1ul, 2ul}}; - slabs["b"] = RegularHyperSlab{{1ul, 1ul}, {3ul, 2ul}}; - - std::vector test_data; - - // Union, irregular - auto slab_ab_union = HyperSlab(slabs["a"]) | slabs["b"]; - // clang-format off - auto answer_ab_union = IrregularHyperSlabAnswer{{ - {1ul, 1ul}, {1ul, 2ul}, - {2ul, 0ul}, {2ul, 1ul}, {2ul, 2ul}, - {3ul, 1ul}, {3ul, 2ul} - }}; - // clang-format on - test_data.push_back({"a | b", slab_ab_union, answer_ab_union}); - - // xor, irregular - auto slab_ab_xor = HyperSlab(slabs["a"]) ^ slabs["b"]; - // clang-format off - auto answer_ab_xor = IrregularHyperSlabAnswer{{ - {1ul, 1ul}, {1ul, 2ul}, - {2ul, 0ul}, {2ul, 2ul}, - {3ul, 1ul}, {3ul, 2ul} - }}; - // clang-format on - test_data.push_back({"a xor b", slab_ab_xor, answer_ab_xor}); - - // (not a) and e, irregular - auto slab_ab_nota = HyperSlab(slabs["a"]).notA(slabs["b"]); - // clang-format off - auto answer_ab_nota = IrregularHyperSlabAnswer{{ - {1ul, 1ul}, {1ul, 2ul}, - {2ul, 2ul}, - {3ul, 1ul}, {3ul, 2ul} - }}; - // clang-format on - test_data.push_back({"a nota b", slab_ab_nota, answer_ab_nota}); - - // (not a) and e, irregular - auto slab_ba_notb = HyperSlab(slabs["b"]).notB(slabs["a"]); - // clang-format off - auto answer_ba_notb = IrregularHyperSlabAnswer{{ - {1ul, 1ul}, {1ul, 2ul}, - {2ul, 2ul}, - {3ul, 1ul}, {3ul, 2ul} - }}; - // clang-format on - test_data.push_back({"b notb a", slab_ba_notb, answer_ba_notb}); - - return test_data; -} - -template -void irregularHyperSlabSelectionReadTest() { - std::ostringstream filename; - filename << "h5_write_select_irregular_hyperslab_test_" << typeNameHelper() << "_test.h5"; - - const std::string dataset_name("dset"); - - const size_t x_size = 10; - const size_t y_size = 8; - - T values[x_size][y_size]; - auto file = setupHyperSlabFile(values, filename.str(), dataset_name); - - auto test_cases = make_irregular_hyperslab_test_data(); - - for (const auto& test_case: test_cases) { - SECTION(test_case.desc) { - std::vector result; - - file.getDataSet(dataset_name).select(test_case.slab).read(result); - - auto n_selected = test_case.answer.global_indices.size(); - for (size_t i = 0; i < n_selected; ++i) { - const auto ig = test_case.answer.global_indices[i]; - - REQUIRE(result[i] == values[ig[0]][ig[1]]); - } - } - } -} - -TEMPLATE_LIST_TEST_CASE("irregularHyperSlabSelectionRead", "[template]", numerical_test_types) { - irregularHyperSlabSelectionReadTest(); -} - -template -void irregularHyperSlabSelectionWriteTest() { - std::ostringstream filename; - filename << "h5_write_select_irregular_hyperslab_test_" << typeNameHelper() << "_test.h5"; - - const std::string dataset_name("dset"); - - const size_t x_size = 10; - const size_t y_size = 8; - - T orig_values[x_size][y_size]; - auto file = setupHyperSlabFile(orig_values, filename.str(), dataset_name); - - auto test_cases = make_irregular_hyperslab_test_data(); - - for (const auto& test_case: test_cases) { - SECTION(test_case.desc) { - auto n_selected = test_case.answer.global_indices.size(); - std::vector changed_values(n_selected); - ContentGenerate gen; - std::generate(changed_values.begin(), changed_values.end(), gen); - - file.getDataSet(dataset_name).select(test_case.slab).write(changed_values); - - T overwritten_values[x_size][y_size]; - file.getDataSet(dataset_name).read(overwritten_values); - - T expected_values[x_size][y_size]; - for (size_t i = 0; i < x_size; ++i) { - for (size_t j = 0; j < y_size; ++j) { - expected_values[i][j] = orig_values[i][j]; - } - } - - for (size_t i = 0; i < n_selected; ++i) { - const auto ig = test_case.answer.global_indices[i]; - expected_values[ig[0]][ig[1]] = changed_values[i]; - } - - for (size_t i = 0; i < x_size; ++i) { - for (size_t j = 0; j < y_size; ++j) { - REQUIRE(expected_values[i][j] == overwritten_values[i][j]); - } - } - } - } -} - -TEMPLATE_LIST_TEST_CASE("irregularHyperSlabSelectionWrite", "[template]", std::tuple) { - irregularHyperSlabSelectionWriteTest(); -} template void attribute_scalar_rw() {