Skip to content

Commit b2bc241

Browse files
committed
multi-sliced subfield/subviews working
1 parent e86f408 commit b2bc241

File tree

6 files changed

+56
-98
lines changed

6 files changed

+56
-98
lines changed

components/eamxx/src/share/field/field.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,8 @@ Field Field::subfield(const std::string& sf_name,
128128
EKAT_REQUIRE_MSG(
129129
is_allocated(),
130130
"Error! Input field must be allocated in order to subview it.\n");
131-
EKAT_REQUIRE_MSG(idim == 0 || idim == 1,
132-
"Error! Subview dimension index must be either 0 or 1.\n");
131+
// EKAT_REQUIRE_MSG(idim == 0 || idim == 1,
132+
// "Error! Subview dimension index must be either 0 or 1.\n");
133133

134134
auto sf_layout =
135135
lt.clone_with_different_extent(idim, index_end - index_beg + 1);

components/eamxx/src/share/field/field.hpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -136,9 +136,11 @@ class Field {
136136
get_strided_view_type<DT,HD>
137137
get_strided_view () const;
138138

139-
template<typename DT, HostOrDevice HD = Device>
140-
Kokkos::View<Real****, Kokkos::LayoutStride>
141-
get_strided_view (bool special) const;
139+
// this is the same as above but for a multi-sliced view
140+
// which is to say, also a strided view
141+
template<typename DT, int N, HostOrDevice HD = Device>
142+
auto get_multi_sliced_view () const
143+
-> get_strided_view_type<data_nd_t<DT, N>, HD>;
142144

143145
// These two getters are convenience function for commonly accessed metadata.
144146
// The same info can be extracted from the metadata stored in the FieldHeader
@@ -245,10 +247,9 @@ class Field {
245247
Field subfield (const std::string& sf_name, const int idim,
246248
const int index, const bool dynamic = false) const;
247249
Field subfield (const int idim, const int k, const bool dynamic = false) const;
248-
// get subfield to extract multiple slices in a continuous range of indices
250+
// subfield fxn to extract multiple slices in a continuous range of indices
249251
// e.g., (in matlab syntax) subf = f.subfield(:, 1:3, :)
250252
// but NOT subf = f.subfield(:, [1, 3, 4], :)
251-
// NOTE: use std::pair(index_beg, index_end) or a kokkos::pair()?
252253
Field subfield (const std::string& sf_name, const ekat::units::Units& sf_units,
253254
const int idim, const int index_beg, const int index_end,
254255
const bool dynamic = false) const;

components/eamxx/src/share/field/field_alloc_prop.cpp

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -77,22 +77,20 @@ subview (const int idim, const int k, const bool dynamic) const {
7777
return props;
7878
}
7979

80-
FieldAllocProp FieldAllocProp::subview(const int idim, const int k_beg,
80+
FieldAllocProp FieldAllocProp::subview(const int idim,
81+
const int k_beg,
8182
const int k_end,
8283
const bool dynamic) const {
8384
EKAT_REQUIRE_MSG(
8485
is_committed(),
8586
"Error! Subview requires alloc properties to be committed.\n");
86-
EKAT_REQUIRE_MSG(
87-
idim == 0 || idim == 1,
88-
"Error! Subviewing is only allowed along first or second dimension.\n");
89-
EKAT_REQUIRE_MSG(idim < m_layout.rank(),
87+
EKAT_REQUIRE_MSG(idim <= m_layout.rank(),
9088
"Error! Dimension index out of bounds.\n");
91-
EKAT_REQUIRE_MSG(k_beg <= k_end,
89+
EKAT_REQUIRE_MSG(k_beg < k_end,
9290
"Error! Slice indices are invalid (non-increasing).\n");
9391
EKAT_REQUIRE_MSG(
9492
k_beg >= 0 && k_end < m_layout.dim(idim),
95-
"Error! Index range along the dimension is out of bounds.\n");
93+
"Error! Slice index range along the idim dimension is out of bounds.\n");
9694

9795
// Set new layout basic stuff
9896
FieldAllocProp props(m_scalar_type_size);

components/eamxx/src/share/field/field_alloc_prop.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ class FieldAllocProp {
106106

107107
FieldAllocProp& operator= (const FieldAllocProp&);
108108

109-
// Return allocation props of an unmanaged subivew of this field
109+
// Return allocation props of an unmanaged subview of this field
110110
// at entry k along dimension idim. If dynamic = true, then it will be
111111
// possible to change the entry index (k) at runtime.
112112
FieldAllocProp subview (const int idim, const int k, const bool dynamic) const;

components/eamxx/src/share/field/field_impl.hpp

Lines changed: 19 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,6 @@ auto Field::get_view () const
9999
// Make sure input field is allocated
100100
EKAT_REQUIRE_MSG(is_allocated(),
101101
"Error! Cannot extract a field's view before allocation happens.\n");
102-
// FIXME: add check
103-
// EKAT_REQUIRE_MSG(true /*is_multiSlice_subview()*/,
104-
// "Error! Multi-sliced subfield is incompatible--must employ "
105-
// "get_strided_view().\n")
106102

107103
EKAT_REQUIRE_MSG (not m_is_read_only || std::is_const<DstValueType>::value,
108104
"Error! Cannot get a view to non-const data if the field is read-only.\n");
@@ -207,26 +203,26 @@ auto Field::get_strided_view () const
207203
return DstView(get_ND_view<HD,DstValueType,1>());
208204
}
209205

210-
template<typename DT, HostOrDevice HD>
211-
Kokkos::View<Real****, Kokkos::LayoutStride> Field::get_strided_view (bool special) const
206+
// NOTE: multi-slicing a view is only supported for strided view return type
207+
template<typename DT, int N, HostOrDevice HD>
208+
auto Field::get_multi_sliced_view () const
209+
-> get_strided_view_type<data_nd_t<DT, N>, HD>
212210
{
213211
// The destination view type on correct mem space
214-
using DstView = get_strided_view_type<DT,HD>;
212+
using DstView = get_strided_view_type<data_nd_t<DT, N>, HD>;
215213
// The dst value types
216214
using DstValueType = typename DstView::traits::value_type;
217-
// We only allow to reshape to a view of the correct rank
218-
constexpr int DstRank = DstView::rank;
219-
constexpr int DstRankDynamic = DstView::rank_dynamic;
220215

221216
// Get src details
222217
const auto& alloc_prop = m_header->get_alloc_properties();
223218
const auto& fl = m_header->get_identifier().get_layout();
224219

225220
// Checks
226-
// EKAT_REQUIRE_MSG (DstRank==1 && fl.rank()==1,
227-
// "Error! Strided view only available for rank-1 fields.\n");
228-
// EKAT_REQUIRE_MSG (DstRankDynamic==1,
221+
// TODO: decide whether a dynamic-rank view is ok
222+
// EKAT_REQUIRE_MSG (DstRankDynamic == 1,
229223
// "Error! Strided view not allowed with compile-time dimensions.\n");
224+
EKAT_REQUIRE_MSG (N == fl.rank(),
225+
"Error! Input Rank must be equal to parent view's rank for multi-sliced subview.\n");
230226
EKAT_REQUIRE_MSG(is_allocated(),
231227
"Error! Cannot extract a field's view before allocation happens.\n");
232228
EKAT_REQUIRE_MSG (not m_is_read_only || std::is_const<DstValueType>::value,
@@ -236,51 +232,23 @@ Kokkos::View<Real****, Kokkos::LayoutStride> Field::get_strided_view (bool speci
236232

237233
// Check if this field is a subview of another field
238234
const auto parent = m_header->get_parent().lock();
239-
if (parent!=nullptr) {
240-
// Parent field has correct layout to reinterpret the view into N+1-dim view
241-
// So create the parent field on the fly, use it to get the N+1-dim view, then subview it.
242-
// NOTE: we can set protected members, since f is the same type of this class.
235+
if (parent != nullptr) {
243236
Field f;
244237
f.m_header = parent;
245238
f.m_data = m_data;
246239

247-
// // Take 2 dimensional view with normal LayoutRight
248-
// auto v_np1 = f.get_ND_view<HD,DstValueType,2>();
249-
// const auto vfs_rank = f.get_header().get_identifier().get_layout().rank();
250-
auto v_fullsize = f.get_ND_view<HD, DstValueType, 4>();
240+
auto v_fullsize = f.get_ND_view<HD, DstValueType, N>();
251241

252242
// Now we can subview v_np1 at the correct slice
253243
const auto& info = m_header->get_alloc_properties().get_subview_info();
254-
const int idim = info.dim_idx;
255-
const int k = info.slice_idx;
256-
const int k_end = info.slice_idx_end;
257-
258-
// // So far we can only subview at first or second dimension.
259-
// EKAT_REQUIRE_MSG (idim==0 || idim==1,
260-
// "Error! Subview dimension index is out of bounds.\n");
261-
262-
// Use correct subview utility
263-
if (idim==0) {
264-
// FIXME: what's a better way to do this? can't use v_fullsize after the
265-
// logic block b/c of scoping, and it's also not easy to know what type of
266-
// exotic
267-
// we know it's a subview, so if it has the same rank as its parent, then
268-
// we know that it's a multi-slice subview
269-
if (fl.rank() == f.get_header().get_identifier().get_layout().rank()) {
270-
auto svs = ekat::subview(v_fullsize, Kokkos::make_pair<int, int>(k, k_end), idim);
271-
// for (size_t i = 0; i < 4; i++)
272-
// {
273-
// std::cout << "i = " << i << "\n";
274-
// std::cout << "svs.stride(i) = " << svs.stride(i) << "\n";
275-
// std::cout << "svs.extent(i) = " << svs.extent(i) << "\n";
276-
// }
277-
return svs;
278-
} else {
279-
// return DstView(ekat::subview(v_np1,k));
280-
}
281-
} else {
282-
// return DstView(ekat::subview_1(v_np1,k));
283-
}
244+
const int idim = info.dim_idx;
245+
const int k = info.slice_idx;
246+
const int k_end = info.slice_idx_end;
247+
248+
// this version of ekat::subview overloaded conveniently, so only the single
249+
// version of the call is required here
250+
return DstView(ekat::subview(v_fullsize,
251+
Kokkos::make_pair<int, int>(k, k_end), idim));
284252
}
285253
}
286254

@@ -838,7 +806,6 @@ auto Field::get_ND_view () const ->
838806
return ret_type (ptr,kl);
839807
}
840808

841-
// TODO: will need to set this up for multi-sliced subfield
842809
template<HostOrDevice HD,typename T,int N>
843810
auto Field::get_ND_view () const ->
844811
if_t<N==MaxRank,get_view_type<data_nd_t<T,N>,HD>>
@@ -848,7 +815,6 @@ auto Field::get_ND_view () const ->
848815
"Error! Input Rank must either be 1 (flat array) or the actual field rank.\n");
849816

850817
// Given that N==MaxRank, this field cannot be a subview of another field
851-
// NOTE: this will not be true for multi-slice
852818
EKAT_REQUIRE_MSG (m_header->get_parent().expired(),
853819
"Error! A view of rank " + std::to_string(MaxRank) + " should not be the subview of another field.\n");
854820

components/eamxx/src/share/tests/field_tests.cpp

Lines changed: 23 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -312,38 +312,31 @@ TEST_CASE("field", "") {
312312
f1.allocate_view();
313313
randomize(f1,engine,pdf);
314314

315-
const int idim = 0;
316-
const int ivar = 2;
317-
const int sl_beg = 2;
318-
const int sl_end = 4;
319-
320-
auto f3 = f1.subfield(idim, sl_beg, sl_end);
321-
322-
// const auto fl3 = f3.get_header().get_identifier().get_layout();
323-
// const auto alprop3 = f3.get_header().get_alloc_properties();
324-
// std::cout << "fl3.rank() = " << fl3.rank() << "\n";
325-
// auto f3dim = fl3.dims();
326-
// for (size_t i = 0; i < 4; i++)
327-
// {
328-
// std::cout << "f3dim(i) = " << f3dim[i] << "\n";
329-
// }
330-
// auto f3ext = fl3.extents();
331-
// for (size_t i = 0; i < 4; i++)
332-
// {
333-
// std::cout << "f3ext(i) = " << f3ext(i) << "\n";
334-
// }
335-
// std::cout << "alprop3.is_subfield() = " << alprop3.is_subfield() << "\n";
336-
337-
auto v3_h = f3.get_strided_view<Real****, Host>(true);
315+
const int idim[4] = {0, 1, 2, 3};
316+
const int sl_beg[4] = {2, 3, 0, 9};
317+
const int sl_end[4] = {4, 6, 1, 15};
318+
338319
auto v4d_h = f1.get_view<Real****, Host>();
339320

340-
for (size_t i = sl_beg; i < sl_end; i++) {
341-
for (size_t j = 0; j < d1[1]; j++) {
342-
for (size_t k = 0; k < d1[2]; k++) {
343-
for (size_t l = 0; l < d1[3]; l++) {
344-
// std::cout << "v4d_h(i, j, k, l) = " << v4d_h(i, j, k, l) << "\n";
345-
// std::cout << "v3_h(i - sl_beg, j, k, l) = " << v3_h(i - sl_beg, j, k, l) << "\n";
346-
REQUIRE(v4d_h(i, j, k, l) == v3_h(i - sl_beg, j, k, l));
321+
int i1, i2, j1, j2, k1, k2, l1, l2;
322+
323+
for (int ens = 0; ens < 4; ens++) {
324+
auto sf = f1.subfield(idim[ens], sl_beg[ens], sl_end[ens]);
325+
auto sv_h = sf.get_multi_sliced_view<Real, 4, Host>();
326+
i1 = (ens == 0) ? sl_beg[0] : 0;
327+
i2 = (ens == 0) ? sl_end[0] : d1[0];
328+
j1 = (ens == 1) ? sl_beg[1] : 0;
329+
j2 = (ens == 1) ? sl_end[1] : d1[1];
330+
k1 = (ens == 2) ? sl_beg[2] : 0;
331+
k2 = (ens == 2) ? sl_end[2] : d1[2];
332+
l1 = (ens == 3) ? sl_beg[3] : 0;
333+
l2 = (ens == 3) ? sl_end[3] : d1[3];
334+
for (int i = i1; i < i2; i++) {
335+
for (int j = j1; j < j2; j++) {
336+
for (int k = k1; k < k2; k++) {
337+
for (int l = l1; l < l2; l++) {
338+
REQUIRE(v4d_h(i, j, k, l) == sv_h(i - i1, j - j1, k - k1, l - l1));
339+
}
347340
}
348341
}
349342
}

0 commit comments

Comments
 (0)