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

Feature: Smart STK Field Types #1209

Merged
merged 41 commits into from
Sep 27, 2023
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
35f57cd
Add prototype for smartptr
psakievich Sep 12, 2023
7c80c29
Attempt some new things
psakievich Sep 12, 2023
f1391d8
Working concept on device
psakievich Sep 12, 2023
660f458
clean some things up
psakievich Sep 12, 2023
5464e46
Start working on the actual class implementation
psakievich Sep 13, 2023
2f19cc6
Make unit test fixture
psakievich Sep 13, 2023
610da57
Generalize code a little
psakievich Sep 13, 2023
256a3bd
Trying a new design
psakievich Sep 13, 2023
739f50e
Redesign again: templates for space and access type
psakievich Sep 14, 2023
a4767f9
Add more tests
psakievich Sep 14, 2023
dcb0479
Add tests to ensure sync count is correct
psakievich Sep 14, 2023
af017d9
Rename file
psakievich Sep 14, 2023
f5a954d
Add some fixes for host
psakievich Sep 14, 2023
6d9f5fd
Style
psakievich Sep 14, 2023
609ab46
Change scope to access and create creator obj
psakievich Sep 17, 2023
cf82d24
Add host specialization for bucket loops
psakievich Sep 18, 2023
2c6d127
Add host READ access overloads
psakievich Sep 18, 2023
d25fa68
Format
psakievich Sep 18, 2023
bfc6678
Refactor for three different MEMSPACE's
psakievich Sep 18, 2023
a4ad40e
Update some comments
psakievich Sep 18, 2023
e4f309b
Style
psakievich Sep 18, 2023
f579c4c
Passing device tests
psakievich Sep 18, 2023
be477fc
Style
psakievich Sep 18, 2023
6fd30a8
Rename to SmartField and add explicit instantiation
psakievich Sep 19, 2023
005de2d
Code comments and things
psakievich Sep 19, 2023
bf884f8
Tweaks
psakievich Sep 19, 2023
1cc7176
Prep FieldManager for interface
psakievich Sep 19, 2023
8b55e0e
Merge branch 'master' into f/smartptr
psakievich Sep 20, 2023
09b33a0
Add some partial template specializations
psakievich Sep 20, 2023
a7a1c7f
FieldManager interface
psakievich Sep 21, 2023
1a42c96
Test FieldManager iFace
psakievich Sep 21, 2023
bc3de85
Style
psakievich Sep 21, 2023
93ee934
Style
psakievich Sep 21, 2023
fa1b4c1
Start using, and improve interface for legacy case
psakievich Sep 21, 2023
00d9173
More conversions in unit-tests
psakievich Sep 21, 2023
f3080ac
Style
psakievich Sep 21, 2023
b6a6de2
Add additional accessor functions
psakievich Sep 23, 2023
c69329c
Fix unit tests
psakievich Sep 25, 2023
733baba
Split classes
psakievich Sep 27, 2023
9ad8018
Test on device and format
psakievich Sep 27, 2023
d68eba4
Add some convenience type names
psakievich Sep 27, 2023
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
183 changes: 183 additions & 0 deletions include/ngp_utils/SmartFieldRef.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
// Copyright 2017 National Technology & Engineering Solutions of Sandia, LLC
// (NTESS), National Renewable Energy Laboratory, University of Texas Austin,
// Northwest Research Associates. Under the terms of Contract DE-NA0003525
// with NTESS, the U.S. Government retains certain rights in this software.
//
// This software is released under the BSD 3-clause license. See LICENSE file
// for more details.
//

#ifndef SMARTFIELDREF_H
#define SMARTFIELDREF_H
#include <Kokkos_Macros.hpp>
#include <stk_mesh/base/Ngp.hpp>
#include <stk_mesh/base/NgpField.hpp>

namespace sierra::nalu {

struct READ
{
};
struct WRITE
{
};
struct READ_WRITE
{
};

struct HOST
{
};
struct DEVICE
{
};

template <typename MEMSPACE, typename SCOPE, typename T>
class SmartFieldRef
{
};

template <typename SCOPE, typename T>
class SmartFieldRef<DEVICE, SCOPE, T>
{
public:
SmartFieldRef(stk::mesh::NgpField<T>& ngpField) : fieldRef_(ngpField) {}

SmartFieldRef(const SmartFieldRef& src)
: fieldRef_(src.fieldRef_), is_copy_constructed_(true)
{
if (is_read())
fieldRef_.sync_to_device();
else
fieldRef_.clear_sync_state();
}

// device implementations should only ever execute inside a
// kokkos::paralle_for and hence be captured by a lambda. Therefore we only
// ever need to sync copies that will have been snatched up through lambda
// capture.
~SmartFieldRef()
{
if (is_copy_constructed_ && is_write()) {
fieldRef_.modify_on_device();
}
}

KOKKOS_FUNCTION
unsigned get_ordinal() const { return fieldRef_.get_ordinal(); }

// TODO make it so these accessors are read only for read type i.e. const
// correct and give clear compile or runtime error for programming mistakes
KOKKOS_FUNCTION
T& get(stk::mesh::FastMeshIndex index, int component)
{
return fieldRef_.get(index, component);
}

template <typename MeshIndex>
KOKKOS_FUNCTION T& get(MeshIndex index, int component)
{
return fieldRef_.get(index, component);
}

KOKKOS_FUNCTION
T& operator()(stk::mesh::FastMeshIndex index, int component)
{
return fieldRef_.get(index, component);
}

template <typename MeshIndex>
KOKKOS_FUNCTION T& operator()(MeshIndex index, int component)
{
return fieldRef_.operator()(index, component);
}

private:
bool is_read()
{
return std::is_same<SCOPE, READ>::value ||
std::is_same<SCOPE, READ_WRITE>::value;
}

bool is_write()
{
return std::is_same<SCOPE, WRITE>::value ||
std::is_same<SCOPE, READ_WRITE>::value;
}

stk::mesh::NgpField<T>& fieldRef_;
const bool is_copy_constructed_{false};
};

template <typename SCOPE, typename T>
class SmartFieldRef<HOST, SCOPE, T>
{
public:
SmartFieldRef(stk::mesh::HostField<T>& ngpField) : fieldRef_(ngpField) {}

SmartFieldRef(const SmartFieldRef& src)
: fieldRef_(src.fieldRef_), is_copy_constructed_(true)
{
if (is_read())
fieldRef_.sync_to_host();
else
fieldRef_.clear_sync_state();
}

// TODO is a copy construction appropriate for host instances?
// ideally we will still be using parallel_for's but there are lots of
// places where we don't yet. It would be nice to make this work with
// the old model as well
//
// maybe something like SPACE=OldHost, change the ctor to take a FieldBase ptr
// AND then remove the copy construction check?
~SmartFieldRef()
{
if (is_copy_constructed_ && is_write()) {
fieldRef_.modify_on_host();
}
}

unsigned get_ordinal() const { return fieldRef_.get_ordinal(); }

T& get(stk::mesh::FastMeshIndex index, int component)
{
return fieldRef_.get(index, component);
}

template <typename MeshIndex>
T& get(MeshIndex index, int component)
{
return fieldRef_.get(index, component);
}

T& operator()(stk::mesh::FastMeshIndex index, int component)
{
return fieldRef_.get(index, component);
}

template <typename MeshIndex>
T& operator()(MeshIndex index, int component)
{
return fieldRef_.operator()(index, component);
}

private:
bool is_read()
{
return std::is_same<SCOPE, READ>::value ||
std::is_same<SCOPE, READ_WRITE>::value;
}

bool is_write()
{
return std::is_same<SCOPE, WRITE>::value ||
std::is_same<SCOPE, READ_WRITE>::value;
}

stk::mesh::HostField<T>& fieldRef_;
const bool is_copy_constructed_{false};
};
} // namespace sierra::nalu

#endif
1 change: 1 addition & 0 deletions unit_tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ target_sources(${utest_ex_name} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/UnitTestPecletFunction.C
${CMAKE_CURRENT_SOURCE_DIR}/UnitTestRadarPattern.C
${CMAKE_CURRENT_SOURCE_DIR}/UnitTestRealm.C
${CMAKE_CURRENT_SOURCE_DIR}/UnitTestSmartFieldRef.C
${CMAKE_CURRENT_SOURCE_DIR}/UnitTestScanningLidarPattern.C
${CMAKE_CURRENT_SOURCE_DIR}/UnitTestScratchViews.C
${CMAKE_CURRENT_SOURCE_DIR}/UnitTestShmemAlignment.C
Expand Down
91 changes: 91 additions & 0 deletions unit_tests/UnitTestSmartFieldRef.C
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// Copyright 2017 National Technology & Engineering Solutions of Sandia, LLC
// (NTESS), National Renewable Energy Laboratory, University of Texas Austin,
// Northwest Research Associates. Under the terms of Contract DE-NA0003525
// with NTESS, the U.S. Government retains certain rights in this software.
//
// This software is released under the BSD 3-clause license. See LICENSE file
// for more details.
//

#include <Kokkos_Macros.hpp>
#include <gtest/gtest.h>
#include "UnitTestUtils.h"
#include <stk_mesh/base/GetNgpField.hpp>
#include "ngp_utils/SmartFieldRef.h"

class TestSmartFieldRef : public Hex8Mesh
{
protected:
void SetUp()
{
fill_mesh_and_initialize_test_fields();

auto* field = fieldManager->get_field_ptr<ScalarFieldType>("scalarQ");

ngpField_ = &stk::mesh::get_updated_ngp_field<double>(*field);

initSyncsHost_ = ngpField_->num_syncs_to_host();
initSyncsDevice_ = ngpField_->num_syncs_to_device();
}

stk::mesh::NgpField<double>* ngpField_;
int initSyncsHost_{0};
int initSyncsDevice_{0};
};

template <typename T>
void
lambda_impl(T& ptr)
{
Kokkos::parallel_for(
1, KOKKOS_LAMBDA(int) { ptr.get_ordinal(); });
}

namespace sierra::nalu {
TEST_F(TestSmartFieldRef, device_read_write_mod_sync_with_lambda)
{
ngpField_->modify_on_host();

ASSERT_TRUE(ngpField_->need_sync_to_device());

// TODO can we get rid of the double template param some how?
auto sPtr = SmartFieldRef<DEVICE, READ_WRITE, double>(*ngpField_);
lambda_impl(sPtr);

EXPECT_FALSE(ngpField_->need_sync_to_device());
EXPECT_TRUE(ngpField_->need_sync_to_host());
EXPECT_EQ(initSyncsDevice_ + 1, ngpField_->num_syncs_to_device());
EXPECT_EQ(initSyncsHost_ + 0, ngpField_->num_syncs_to_host());
}

TEST_F(TestSmartFieldRef, device_write_clear_mod_with_lambda)
{
ngpField_->modify_on_host();

ASSERT_TRUE(ngpField_->need_sync_to_device());

auto sPtr = SmartFieldRef<DEVICE, WRITE, double>(*ngpField_);
lambda_impl(sPtr);

EXPECT_FALSE(ngpField_->need_sync_to_device());
EXPECT_TRUE(ngpField_->need_sync_to_host());
EXPECT_EQ(initSyncsDevice_ + 0, ngpField_->num_syncs_to_device());
EXPECT_EQ(initSyncsHost_ + 0, ngpField_->num_syncs_to_host());
}

TEST_F(TestSmartFieldRef, device_read_mod_no_sync_with_lambda)
{
ngpField_->modify_on_host();

ASSERT_TRUE(ngpField_->need_sync_to_device());

auto sPtr = SmartFieldRef<DEVICE, READ, double>(*ngpField_);
lambda_impl(sPtr);

EXPECT_FALSE(ngpField_->need_sync_to_device());
EXPECT_FALSE(ngpField_->need_sync_to_host());
EXPECT_EQ(initSyncsDevice_ + 1, ngpField_->num_syncs_to_device());
EXPECT_EQ(initSyncsHost_ + 0, ngpField_->num_syncs_to_host());
}

} // namespace sierra::nalu
Loading