Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for reading hyperslab using gdal #789

Merged
merged 1 commit into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ namespace lue {


template<typename Index, std::size_t rank>
Shape<Index, rank> default_partition_shape(Shape<Index, rank> const& array_shape)
auto default_partition_shape(Shape<Index, rank> const& array_shape) -> Shape<Index, rank>
{
Count const nr_worker_threads{static_cast<Count>(hpx::get_num_worker_threads())};

Expand Down
113 changes: 113 additions & 0 deletions source/framework/core/include/lue/framework/core/hyperslab.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
#pragma once
#include "lue/framework/core/offset.hpp"
#include <algorithm>
#include <cassert>
#include <stdexcept>


namespace lue {

template<Rank rank>
class Hyperslab
{

private:

using Array = std::array<Index, rank>;

public:

using Offsets = Array;
using Counts = Array;
using Strides = Array;
using Center = Array;
using Shape = Array;


Hyperslab(Center const& center, Shape const& shape):

_counts{shape}

{
Shape half_shape{shape};

std::transform(
half_shape.begin(),
half_shape.end(),
half_shape.begin(),
[](auto const count) { return 0.5 * (count % 2 == 1 ? count - 1 : count); });

// Equality in the sense that shape can be centered and not extend into areas with smaller
// than zero idxs
if (!std::equal(
half_shape.begin(),
half_shape.end(),
center.begin(),
[](auto const count, auto const idx)
{
// Subtracting this many cells from the center cell results in a negative idx...
return idx >= count;
}))
{
throw std::runtime_error("Hyperslab shape extents beyond the limits of the array");
}

std::transform(
center.begin(),
center.end(),
half_shape.begin(),
_offsets.begin(),
[](auto const idx, auto const count)
{
assert(idx >= count);
return idx - count;
});
_strides.fill(1);
}

auto offsets() const -> Offsets const&
{
return _offsets;
}

auto counts() const -> Counts const&
{
return _counts;
}

auto strides() const -> Strides const&
{
return _strides;
}

[[nodiscard]] auto is_strided() const -> bool
{
return std::ranges::any_of(_strides, [](auto const stride) { return stride > 1; });
}

// Returns whether the indices represented by the hyperslab all fall within the bounds of the
// array whose shape is passed in. By definition (see constructor), the minimum indices of the
// hyperslab are fine, so only the maximum indices are checked here.
auto is_contained_by(Shape const& array_shape) const -> bool
{
for (std::size_t idx = 0; idx < rank; ++idx)
{
if (!(_offsets[idx] + _counts[idx] - 1 < array_shape[idx]))
{
return false;
}
}

return true;
}

private:

Offsets _offsets{};

Counts _counts;

Strides _strides{};
};

} // namespace lue
1 change: 1 addition & 0 deletions source/framework/core/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ set(names
configuration_entry
domain_decomposition
hilbert_curve
hyperslab
index_util
linear_curve
math
Expand Down
132 changes: 132 additions & 0 deletions source/framework/core/test/hyperslab_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
#define BOOST_TEST_MODULE lue framework core hyperslab
#include "lue/framework/core/hyperslab.hpp"
#include "lue/stream.hpp"
#include <boost/test/included/unit_test.hpp>


BOOST_AUTO_TEST_CASE(construct_2d_odd_shape)
{
lue::Rank const rank{2};
using Hyperslab = lue::Hyperslab<rank>;

Hyperslab::Center center{20, 30};
Hyperslab::Shape shape{7, 5};
Hyperslab hyperslab{center, shape};

Hyperslab::Offsets const offsets{17, 28};
Hyperslab::Counts const counts{shape};
Hyperslab::Strides const strides{{1, 1}};

BOOST_CHECK_EQUAL(hyperslab.offsets(), offsets);
BOOST_CHECK_EQUAL(hyperslab.counts(), counts);
BOOST_CHECK_EQUAL(hyperslab.strides(), strides);
}


BOOST_AUTO_TEST_CASE(construct_2d_even_shape)
{
lue::Rank const rank{2};
using Hyperslab = lue::Hyperslab<rank>;

Hyperslab::Center center{20, 30};
Hyperslab::Shape shape{6, 4};
Hyperslab hyperslab{center, shape};

Hyperslab::Offsets const offsets{17, 28};
Hyperslab::Counts const counts{shape};
Hyperslab::Strides const strides{{1, 1}};

BOOST_CHECK_EQUAL(hyperslab.offsets(), offsets);
BOOST_CHECK_EQUAL(hyperslab.counts(), counts);
BOOST_CHECK_EQUAL(hyperslab.strides(), strides);
}


BOOST_AUTO_TEST_CASE(valid_hyperslab)
{
lue::Rank const rank{2};
using Hyperslab = lue::Hyperslab<rank>;

{
// Empty hyperslab
Hyperslab::Center const center{30, 20};
Hyperslab::Shape const shape{0, 0};
BOOST_CHECK_NO_THROW(Hyperslab(center, shape));
}

{
// Empty hyperslab
Hyperslab::Center const center{30, 20};
Hyperslab::Shape const shape{60, 0};
BOOST_CHECK_NO_THROW(Hyperslab(center, shape));
}

{
// Empty hyperslab
Hyperslab::Center const center{30, 20};
Hyperslab::Shape const shape{0, 40};
BOOST_CHECK_NO_THROW(Hyperslab(center, shape));
}

{
// Hyperslab corresponds with whole array
Hyperslab::Center const center{30, 20};
Hyperslab::Shape const shape{60, 40};
BOOST_CHECK_NO_THROW(Hyperslab(center, shape));
}
}


BOOST_AUTO_TEST_CASE(invalid_hyperslab)
{
lue::Rank const rank{2};
using Hyperslab = lue::Hyperslab<rank>;

{
Hyperslab::Center const center{30, 20};
Hyperslab::Shape const shape{62, 42};

BOOST_CHECK_EXCEPTION(
Hyperslab(center, shape),
std::runtime_error,
[](auto const& exception)
{ return std::string(exception.what()).find("extents beyond the limits") != std::string::npos; });
}

{
Hyperslab::Center const center{30, 20};
Hyperslab::Shape const shape{62, 40};

BOOST_CHECK_EXCEPTION(
Hyperslab(center, shape),
std::runtime_error,
[](auto const& exception)
{ return std::string(exception.what()).find("extents beyond the limits") != std::string::npos; });
}

{
Hyperslab::Center const center{30, 20};
Hyperslab::Shape const shape{60, 42};

BOOST_CHECK_EXCEPTION(
Hyperslab(center, shape),
std::runtime_error,
[](auto const& exception)
{ return std::string(exception.what()).find("extents beyond the limits") != std::string::npos; });
}
}


BOOST_AUTO_TEST_CASE(is_contained_by)
{
lue::Rank const rank{2};
using Hyperslab = lue::Hyperslab<rank>;

Hyperslab::Center center{20, 30};
Hyperslab::Shape shape{7, 5};
Hyperslab hyperslab{center, shape};

BOOST_CHECK(hyperslab.is_contained_by(Hyperslab::Shape{24, 33}));
BOOST_CHECK(!hyperslab.is_contained_by(Hyperslab::Shape{23, 33}));
BOOST_CHECK(!hyperslab.is_contained_by(Hyperslab::Shape{24, 32}));
}
7 changes: 7 additions & 0 deletions source/framework/io/include/lue/framework/io/gdal.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once
#include "lue/framework/core/hyperslab.hpp"
#include "lue/framework/partitioned_array.hpp"


Expand All @@ -8,6 +9,12 @@ namespace lue {
auto from_gdal(std::string const& name, Shape<Count, 2> const& partition_shape)
-> PartitionedArray<Element, 2>;

template<typename Element>
auto from_gdal(
std::string const& name,
Hyperslab<2> const& hyperslab,
Shape<Count, 2> const& partition_shape) -> PartitionedArray<Element, 2>;

template<typename Element>
auto to_gdal(
PartitionedArray<Element, 2> const& array,
Expand Down
Loading
Loading