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

Refactor _readSelection. #315

Merged
merged 1 commit into from
Nov 29, 2023
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
65 changes: 20 additions & 45 deletions src/population.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

#include <fmt/format.h>

#include "read_bulk.hpp"
#include "read_canonical_selection.hpp"
#include <highfive/H5File.hpp>

namespace bbp {
Expand Down Expand Up @@ -58,45 +60,22 @@ std::set<std::string> _listExplicitEnumerations(const HighFive::Group h5Group,
}

template <typename T>
std::vector<T> _readChunk(const HighFive::DataSet& dset, const Selection::Range& range) {
std::vector<T> result;
assert(range.first < range.second);
auto chunkSize = static_cast<size_t>(range.second - range.first);
dset.select({static_cast<size_t>(range.first)}, {chunkSize}).read(result);
return result;
}


template <typename T, typename std::enable_if<!std::is_pod<T>::value>::type* = nullptr>
std::vector<T> _readSelection(const HighFive::DataSet& dset, const Selection& selection) {
if (selection.ranges().empty() || dset.getElementCount() == 0) {
if (dset.getElementCount() == 0) {
return {};
}

if (selection.ranges().size() == 1) {
return _readChunk<T>(dset, selection.ranges().front());
if (bulk_read::detail::isCanonical(selection)) {
return detail::readCanonicalSelection<T>(dset, selection);
}

std::vector<T> result;

// for POD types we can pre-allocate result vector... see below template specialization
for (const auto& range : selection.ranges()) {
for (auto& x : _readChunk<T>(dset, range)) {
result.emplace_back(std::move(x));
}
}

return result;
}


template <typename T, typename std::enable_if<std::is_pod<T>::value>::type* = nullptr>
std::vector<T> _readSelection(const HighFive::DataSet& dset, const Selection& selection) {
if (selection.ranges().empty() || dset.getElementCount() == 0) {
return {};
} else if (selection.ranges().size() == 1) {
return _readChunk<T>(dset, selection.ranges().front());
}
// The fully general case:
//
// 1. Create a canonical selection and read into `linear_result`.
// 2. Copy values from the canonical `linear_results` to their final
// destination.
auto canonicalRanges = bulk_read::sortAndMerge(selection, 0);
auto linear_result = detail::readCanonicalSelection<T>(dset, canonicalRanges);

const auto ids = selection.flatten();

Expand All @@ -106,19 +85,15 @@ std::vector<T> _readSelection(const HighFive::DataSet& dset, const Selection& se
return ids[i0] < ids[i1];
});

std::vector<std::size_t> ids_sorted;
ids_sorted.reserve(ids.size());
std::transform(ids_index.begin(),
ids_index.end(),
std::back_inserter(ids_sorted),
[&ids](size_t i) { return static_cast<size_t>(ids[i]); });

std::vector<T> linear_result;
dset.select(HighFive::ElementSet{ids_sorted}).read(linear_result);
std::vector<T> result(ids.size());
size_t linear_index = 0;
result[ids_index[0]] = linear_result[0];
for (size_t i = 1; i < ids.size(); ++i) {
if (ids[ids_index[i - 1]] != ids[ids_index[i]]) {
linear_index += 1;
}

std::vector<T> result(ids_sorted.size());
for (size_t i = 0; i < ids_sorted.size(); ++i) {
result[ids_index[i]] = linear_result[i];
result[ids_index[i]] = linear_result[linear_index];
}

return result;
Expand Down
35 changes: 35 additions & 0 deletions src/read_canonical_selection.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#pragma once

#include <vector>

#include <highfive/H5File.hpp>

namespace bbp {
namespace sonata {
namespace detail {


template <class Range>
HighFive::HyperSlab make_hyperslab(const std::vector<Range>& ranges) {
HighFive::HyperSlab slab;
for (const auto& range : ranges) {
size_t i_begin = std::get<0>(range);
size_t i_end = std::get<1>(range);
slab |= HighFive::RegularHyperSlab({i_begin}, {i_end - i_begin});
}

return slab;
}

template <class T>
std::vector<T> readCanonicalSelection(const HighFive::DataSet& dset, const Selection& selection) {
if (selection.empty()) {
return {};
}

return dset.select(make_hyperslab(selection.ranges())).template read<std::vector<T>>();
}

} // namespace detail
} // namespace sonata
} // namespace bbp
Loading