Skip to content

Commit

Permalink
tests finished for multi-slice sub{field,view}
Browse files Browse the repository at this point in the history
  • Loading branch information
mjschmidt271 committed Apr 9, 2024
1 parent b2bc241 commit 52b0241
Show file tree
Hide file tree
Showing 5 changed files with 427 additions and 168 deletions.
44 changes: 22 additions & 22 deletions components/eamxx/src/share/field/field_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,8 @@ auto Field::get_strided_view () const
}

// NOTE: multi-slicing a view is only supported for strided view return type
// TODO: N doesn't actually need to be passed in, since the subview must have
// the same rank as its parent
template<typename DT, int N, HostOrDevice HD>
auto Field::get_multi_sliced_view () const
-> get_strided_view_type<data_nd_t<DT, N>, HD>
Expand All @@ -218,9 +220,6 @@ auto Field::get_multi_sliced_view () const
const auto& fl = m_header->get_identifier().get_layout();

// Checks
// TODO: decide whether a dynamic-rank view is ok
// EKAT_REQUIRE_MSG (DstRankDynamic == 1,
// "Error! Strided view not allowed with compile-time dimensions.\n");
EKAT_REQUIRE_MSG (N == fl.rank(),
"Error! Input Rank must be equal to parent view's rank for multi-sliced subview.\n");
EKAT_REQUIRE_MSG(is_allocated(),
Expand All @@ -230,26 +229,27 @@ auto Field::get_multi_sliced_view () const
EKAT_REQUIRE_MSG(alloc_prop.template is_compatible<DstValueType>(),
"Error! Source field allocation is not compatible with the requested value type.\n");

// Check if this field is a subview of another field
// get parent header and check if this field is a subview of another field
const auto parent = m_header->get_parent().lock();
if (parent != nullptr) {
Field f;
f.m_header = parent;
f.m_data = m_data;

auto v_fullsize = f.get_ND_view<HD, DstValueType, N>();

// Now we can subview v_np1 at the correct slice
const auto& info = m_header->get_alloc_properties().get_subview_info();
const int idim = info.dim_idx;
const int k = info.slice_idx;
const int k_end = info.slice_idx_end;

// this version of ekat::subview overloaded conveniently, so only the single
// version of the call is required here
return DstView(ekat::subview(v_fullsize,
Kokkos::make_pair<int, int>(k, k_end), idim));
}
EKAT_REQUIRE_MSG(parent != nullptr,
"Error! Multi-sliced subview is unavailable for non-subfields.\n");
Field f;
// create new field with the header/data from the parent
f.m_header = parent;
f.m_data = m_data;

auto v_fullsize = f.get_ND_view<HD, DstValueType, N>();

// Now we can subview v_np1 at the correct slice
const auto& info = m_header->get_alloc_properties().get_subview_info();
const int idim = info.dim_idx;
const int k_beg = info.slice_idx;
const int k_end = info.slice_idx_end;

// this version of ekat::subview overloaded conveniently, so only the single
// version of the call is required here
return DstView(ekat::subview(v_fullsize,
Kokkos::make_pair<int, int>(k_beg, k_end), idim));
}

template<HostOrDevice HD>
Expand Down
3 changes: 3 additions & 0 deletions components/eamxx/src/share/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ if (NOT ${SCREAM_BASELINES_ONLY})
# Test fields
CreateUnitTest(field "field_tests.cpp")

# Test fields
CreateUnitTest(subfield "subfield_tests.cpp")

# Test field utils
CreateUnitTest(field_utils "field_utils.cpp"
MPI_RANKS 1 ${SCREAM_TEST_MAX_RANKS})
Expand Down
145 changes: 0 additions & 145 deletions components/eamxx/src/share/tests/field_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,151 +273,6 @@ TEST_CASE("field", "") {
}
}

// Subfields
SECTION ("subfield") {
std::vector<FieldTag> t1 = {COL,CMP,CMP,LEV};
std::vector<int> d1 = {3,10,2,24};

FieldIdentifier fid1("4d",{t1,d1},m/s,"some_grid");

Field f1(fid1);
f1.allocate_view();
randomize(f1,engine,pdf);

const int idim = 1;
const int ivar = 2;

auto f2 = f1.subfield(idim,ivar);

// Wrong rank for the subfield f2
REQUIRE_THROWS(f2.get_view<Real****>());

auto v4d_h = f1.get_view<Real****,Host>();
auto v3d_h = f2.get_view<Real***,Host>();
for (int i=0; i<d1[0]; ++i)
for (int j=0; j<d1[2]; ++j)
for (int k=0; k<d1[3]; ++k) {
REQUIRE (v4d_h(i,ivar,j,k)==v3d_h(i,j,k));
}
}

// Subfields (multi-sliced)
SECTION ("subfield--multi-slice") {
std::vector<FieldTag> t1 = {COL,CMP,CMP,LEV};
std::vector<int> d1 = {5,10,2,24};

FieldIdentifier fid1("4d",{t1,d1},m/s,"some_grid");

Field f1(fid1);
f1.allocate_view();
randomize(f1,engine,pdf);

const int idim[4] = {0, 1, 2, 3};
const int sl_beg[4] = {2, 3, 0, 9};
const int sl_end[4] = {4, 6, 1, 15};

auto v4d_h = f1.get_view<Real****, Host>();

int i1, i2, j1, j2, k1, k2, l1, l2;

for (int ens = 0; ens < 4; ens++) {
auto sf = f1.subfield(idim[ens], sl_beg[ens], sl_end[ens]);
auto sv_h = sf.get_multi_sliced_view<Real, 4, Host>();
i1 = (ens == 0) ? sl_beg[0] : 0;
i2 = (ens == 0) ? sl_end[0] : d1[0];
j1 = (ens == 1) ? sl_beg[1] : 0;
j2 = (ens == 1) ? sl_end[1] : d1[1];
k1 = (ens == 2) ? sl_beg[2] : 0;
k2 = (ens == 2) ? sl_end[2] : d1[2];
l1 = (ens == 3) ? sl_beg[3] : 0;
l2 = (ens == 3) ? sl_end[3] : d1[3];
for (int i = i1; i < i2; i++) {
for (int j = j1; j < j2; j++) {
for (int k = k1; k < k2; k++) {
for (int l = l1; l < l2; l++) {
REQUIRE(v4d_h(i, j, k, l) == sv_h(i - i1, j - j1, k - k1, l - l1));
}
}
}
}
}
}

// Dynamic Subfields
SECTION ("dynamic_subfield") {
const int vec_dim = 10;
std::vector<FieldTag> t1 = {COL,CMP,CMP,LEV};
std::vector<int> d1 = {3,vec_dim,2,24};

FieldIdentifier fid1("4d",{t1,d1},m/s,"some_grid");

Field f1(fid1);
f1.allocate_view();
randomize(f1,engine,pdf);

const int idim = 1;
const int ivar = 0;

auto f2 = f1.subfield(idim,ivar,/* dynamic = */ true);

// Cannot reset subview idx of non-subfield fields
REQUIRE_THROWS(f1.get_header().get_alloc_properties().reset_subview_idx(0));

// subview idx out of bounds
auto& f2_ap = f2.get_header().get_alloc_properties();
REQUIRE_THROWS(f2_ap.reset_subview_idx(-1));
REQUIRE_THROWS(f2_ap.reset_subview_idx(vec_dim));

// Fill f1 with random numbers, and verify corresponding subviews get same values
randomize(f1,engine,pdf);

for (int ivar_dyn=0; ivar_dyn<vec_dim; ++ivar_dyn) {
// Reset slice idx
f2_ap.reset_subview_idx(ivar_dyn);
REQUIRE(f2_ap.get_subview_info().slice_idx==ivar_dyn);

auto v4d_h = f1.get_view<Real****,Host>();
auto v3d_h = f2.get_view<Real***,Host>();
for (int i=0; i<d1[0]; ++i)
for (int j=0; j<d1[2]; ++j)
for (int k=0; k<d1[3]; ++k) {
REQUIRE (v4d_h(i,ivar_dyn,j,k)==v3d_h(i,j,k));
}
}
}

SECTION ("vector_component") {
std::vector<FieldTag> tags_2 = {COL,CMP,LEV};
std::vector<int> dims_2 = {3,2,24};

FieldIdentifier fid_2("vec_3d",{tags_2,dims_2},m/s,"some_grid");

Field f_vec(fid_2);
f_vec.allocate_view();

auto f0 = f_vec.get_component(0);
auto f1 = f_vec.get_component(1);

// No 3rd component
REQUIRE_THROWS(f_vec.get_component(2));

// f0 is scalar, no vector dimension
REQUIRE_THROWS(f0.get_component(0));

f0.deep_copy(1.0);
f1.deep_copy(2.0);

f_vec.sync_to_host();

auto v = f_vec.get_view<Real***,Host>();
for (int col=0; col<3; ++col) {
for (int lev=0; lev<24; ++lev) {
REQUIRE (v(col,0,lev)==1.0);
REQUIRE (v(col,1,lev)==2.0);
}
}
}

SECTION ("host_view") {
Field f(fid);

Expand Down
Loading

0 comments on commit 52b0241

Please sign in to comment.