From 35f57cda0e084b73cf66d663523456f5bb7d8a6b Mon Sep 17 00:00:00 2001 From: psakiev Date: Tue, 12 Sep 2023 05:18:20 -0600 Subject: [PATCH 01/40] Add prototype for smartptr --- unit_tests/CMakeLists.txt | 1 + unit_tests/UnitTestSmartFieldPtr.C | 44 ++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 unit_tests/UnitTestSmartFieldPtr.C diff --git a/unit_tests/CMakeLists.txt b/unit_tests/CMakeLists.txt index e529aa132..7bc8fd265 100644 --- a/unit_tests/CMakeLists.txt +++ b/unit_tests/CMakeLists.txt @@ -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}/UnitTestSmartFieldPtr.C ${CMAKE_CURRENT_SOURCE_DIR}/UnitTestScanningLidarPattern.C ${CMAKE_CURRENT_SOURCE_DIR}/UnitTestScratchViews.C ${CMAKE_CURRENT_SOURCE_DIR}/UnitTestShmemAlignment.C diff --git a/unit_tests/UnitTestSmartFieldPtr.C b/unit_tests/UnitTestSmartFieldPtr.C new file mode 100644 index 000000000..347c1c51b --- /dev/null +++ b/unit_tests/UnitTestSmartFieldPtr.C @@ -0,0 +1,44 @@ +// 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 +#include "UnitTestUtils.h" +#include + +template +class SmartFieldPtr{ +public: + SmartFieldPtr(stk::mesh::NgpField& fieldRef):fieldPtr_(&fieldRef){} + SmartFieldPtr(const SmartFieldPtr& src): is_a_copy_(true), fieldPtr_(src.fieldPtr_){ + fieldPtr_->sync_to_device(); + } + ~SmartFieldPtr(){ + if(is_a_copy_){ + fieldPtr_->modify_on_device(); + } + } +protected: + bool is_a_copy_{false}; + stk::mesh::NgpField* fieldPtr_; +}; + +TEST_F(Hex8Mesh, SmartFieldPtr){ + fill_mesh_and_initialize_test_fields(); + auto* field = fieldManager->get_field_ptr("scalarQ"); + stk::mesh::NgpField& ngpField = + stk::mesh::get_updated_ngp_field(*field); + ngpField.modify_on_host(); + ASSERT_TRUE(ngpField.need_sync_to_device()); + auto sPtr = SmartFieldPtr(ngpField); + Kokkos::parallel_for(1, KOKKOS_LAMBDA(int){ + (void)sPtr;}); + EXPECT_FALSE(ngpField.need_sync_to_device()); + EXPECT_TRUE(ngpField.need_sync_to_host()); + +} From 7c80c29b5ec194287dfc0a1c1d4855c7d888009c Mon Sep 17 00:00:00 2001 From: psakiev Date: Tue, 12 Sep 2023 12:02:15 -0600 Subject: [PATCH 02/40] Attempt some new things --- unit_tests/UnitTestSmartFieldPtr.C | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/unit_tests/UnitTestSmartFieldPtr.C b/unit_tests/UnitTestSmartFieldPtr.C index 347c1c51b..d035b85fe 100644 --- a/unit_tests/UnitTestSmartFieldPtr.C +++ b/unit_tests/UnitTestSmartFieldPtr.C @@ -7,6 +7,7 @@ // for more details. // +#include #include #include "UnitTestUtils.h" #include @@ -14,20 +15,35 @@ template class SmartFieldPtr{ public: + KOKKOS_FUNCTION + SmartFieldPtr():fieldPtr_(NULL){} SmartFieldPtr(stk::mesh::NgpField& fieldRef):fieldPtr_(&fieldRef){} SmartFieldPtr(const SmartFieldPtr& src): is_a_copy_(true), fieldPtr_(src.fieldPtr_){ +#if defined(KOKKOS_IF_ON_HOST) fieldPtr_->sync_to_device(); +#endif } + KOKKOS_FUNCTION ~SmartFieldPtr(){ +#if defined( KOKKOS_IF_ON_HOST) if(is_a_copy_){ fieldPtr_->modify_on_device(); } +#endif } protected: bool is_a_copy_{false}; stk::mesh::NgpField* fieldPtr_; }; + +template +void lambda_impl(SmartFieldPtr& ptr){ + Kokkos::parallel_for(1, + KOKKOS_LAMBDA(int){ + (void)ptr; + }); +} TEST_F(Hex8Mesh, SmartFieldPtr){ fill_mesh_and_initialize_test_fields(); auto* field = fieldManager->get_field_ptr("scalarQ"); @@ -36,8 +52,7 @@ TEST_F(Hex8Mesh, SmartFieldPtr){ ngpField.modify_on_host(); ASSERT_TRUE(ngpField.need_sync_to_device()); auto sPtr = SmartFieldPtr(ngpField); - Kokkos::parallel_for(1, KOKKOS_LAMBDA(int){ - (void)sPtr;}); + lambda_impl(sPtr); EXPECT_FALSE(ngpField.need_sync_to_device()); EXPECT_TRUE(ngpField.need_sync_to_host()); From f1391d8b1c55fd74b5ace6cc5c6986ea82f240ca Mon Sep 17 00:00:00 2001 From: Philip Sakievich Date: Tue, 12 Sep 2023 15:12:01 -0600 Subject: [PATCH 03/40] Working concept on device --- unit_tests/UnitTestSmartFieldPtr.C | 37 +++++++++++++++--------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/unit_tests/UnitTestSmartFieldPtr.C b/unit_tests/UnitTestSmartFieldPtr.C index d035b85fe..823362877 100644 --- a/unit_tests/UnitTestSmartFieldPtr.C +++ b/unit_tests/UnitTestSmartFieldPtr.C @@ -15,25 +15,19 @@ template class SmartFieldPtr{ public: - KOKKOS_FUNCTION - SmartFieldPtr():fieldPtr_(NULL){} - SmartFieldPtr(stk::mesh::NgpField& fieldRef):fieldPtr_(&fieldRef){} - SmartFieldPtr(const SmartFieldPtr& src): is_a_copy_(true), fieldPtr_(src.fieldPtr_){ -#if defined(KOKKOS_IF_ON_HOST) - fieldPtr_->sync_to_device(); -#endif + SmartFieldPtr(stk::mesh::DeviceField& fieldRef):fieldPtr_(fieldRef){} + + SmartFieldPtr(const SmartFieldPtr& src): fieldPtr_(src.fieldPtr_){ + fieldPtr_.sync_to_device(); } + KOKKOS_FUNCTION + unsigned get_ordinal(){return fieldPtr_.get_ordinal();} + ~SmartFieldPtr(){ -#if defined( KOKKOS_IF_ON_HOST) - if(is_a_copy_){ - fieldPtr_->modify_on_device(); - } -#endif + fieldPtr_.modify_on_device(); } -protected: - bool is_a_copy_{false}; - stk::mesh::NgpField* fieldPtr_; + stk::mesh::DeviceField& fieldPtr_; }; @@ -41,18 +35,25 @@ template void lambda_impl(SmartFieldPtr& ptr){ Kokkos::parallel_for(1, KOKKOS_LAMBDA(int){ - (void)ptr; + ptr.fieldPtr_.get_ordinal(); }); } + TEST_F(Hex8Mesh, SmartFieldPtr){ fill_mesh_and_initialize_test_fields(); + auto* field = fieldManager->get_field_ptr("scalarQ"); - stk::mesh::NgpField& ngpField = - stk::mesh::get_updated_ngp_field(*field); + + stk::mesh::NgpField& ngpField = + stk::mesh::get_updated_ngp_field(*field); + ngpField.modify_on_host(); + ASSERT_TRUE(ngpField.need_sync_to_device()); + auto sPtr = SmartFieldPtr(ngpField); lambda_impl(sPtr); + EXPECT_FALSE(ngpField.need_sync_to_device()); EXPECT_TRUE(ngpField.need_sync_to_host()); From 660f458e673a543382ef502e1bf18168036238e0 Mon Sep 17 00:00:00 2001 From: Philip Sakievich Date: Tue, 12 Sep 2023 15:55:52 -0600 Subject: [PATCH 04/40] clean some things up --- unit_tests/UnitTestSmartFieldPtr.C | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/unit_tests/UnitTestSmartFieldPtr.C b/unit_tests/UnitTestSmartFieldPtr.C index 823362877..5290b9857 100644 --- a/unit_tests/UnitTestSmartFieldPtr.C +++ b/unit_tests/UnitTestSmartFieldPtr.C @@ -22,7 +22,9 @@ public: } KOKKOS_FUNCTION - unsigned get_ordinal(){return fieldPtr_.get_ordinal();} + unsigned get_ordinal() const{ + return fieldPtr_.get_ordinal(); + } ~SmartFieldPtr(){ fieldPtr_.modify_on_device(); @@ -35,7 +37,7 @@ template void lambda_impl(SmartFieldPtr& ptr){ Kokkos::parallel_for(1, KOKKOS_LAMBDA(int){ - ptr.fieldPtr_.get_ordinal(); + ptr.get_ordinal(); }); } From 5464e4688e49091645fe1f6fbf7bfdca2f4c51b8 Mon Sep 17 00:00:00 2001 From: psakiev Date: Wed, 13 Sep 2023 12:21:08 -0600 Subject: [PATCH 05/40] Start working on the actual class implementation --- include/ngp_utils/SmartFieldRef.h | 62 ++++++++++++++++++++++++++++++ unit_tests/UnitTestSmartFieldPtr.C | 29 ++++++++++++-- 2 files changed, 88 insertions(+), 3 deletions(-) create mode 100644 include/ngp_utils/SmartFieldRef.h diff --git a/include/ngp_utils/SmartFieldRef.h b/include/ngp_utils/SmartFieldRef.h new file mode 100644 index 000000000..343763ed2 --- /dev/null +++ b/include/ngp_utils/SmartFieldRef.h @@ -0,0 +1,62 @@ +// 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 +#include + +namespace sierra::nalu::nalu_ngp{ +struct READ{}; + +enum class Scope{ + READ, + WRITE, + READWRITE +}; + + +template +class DeviceSmartFieldRef{ +public: + DeviceSmartFieldRef(stk::mesh::NgpField& ngpField, Scope scope):fieldRef_(ngpField),scope_(scope){} + + DeviceSmartFieldRef(const DeviceSmartFieldRef& src):fieldRef_(src.fieldRef_), scope_(src.scope_), is_copy_constructed_(true) + { + if(scope_ == Scope::WRITE) + fieldRef_.clear_sync_state(); + else + fieldRef_.sync_to_device(); + } + + ~DeviceSmartFieldRef(){ + if(is_copy_constructed_ && !scope_is(Scope::READ)){ + fieldRef_.modify_on_device(); + } + } + + KOKKOS_FUNCTION + unsigned get_ordinal() const{ + return fieldRef_.get_ordinal(); + } + +private: + bool scope_is(Scope test){ + return scope_ == test; + } + + stk::mesh::NgpField& fieldRef_; + const Scope scope_; + const bool is_copy_constructed_{false}; +}; + + +} + +#endif diff --git a/unit_tests/UnitTestSmartFieldPtr.C b/unit_tests/UnitTestSmartFieldPtr.C index 5290b9857..169d1f268 100644 --- a/unit_tests/UnitTestSmartFieldPtr.C +++ b/unit_tests/UnitTestSmartFieldPtr.C @@ -11,11 +11,12 @@ #include #include "UnitTestUtils.h" #include +#include "ngp_utils/SmartFieldRef.h" template class SmartFieldPtr{ public: - SmartFieldPtr(stk::mesh::DeviceField& fieldRef):fieldPtr_(fieldRef){} + SmartFieldPtr(stk::mesh::NgpField& fieldRef):fieldPtr_(fieldRef){} SmartFieldPtr(const SmartFieldPtr& src): fieldPtr_(src.fieldPtr_){ fieldPtr_.sync_to_device(); @@ -29,18 +30,19 @@ public: ~SmartFieldPtr(){ fieldPtr_.modify_on_device(); } - stk::mesh::DeviceField& fieldPtr_; + stk::mesh::NgpField& fieldPtr_; }; template -void lambda_impl(SmartFieldPtr& ptr){ +void lambda_impl(T& ptr){ Kokkos::parallel_for(1, KOKKOS_LAMBDA(int){ ptr.get_ordinal(); }); } +namespace sierra::nalu{ TEST_F(Hex8Mesh, SmartFieldPtr){ fill_mesh_and_initialize_test_fields(); @@ -60,3 +62,24 @@ TEST_F(Hex8Mesh, SmartFieldPtr){ EXPECT_TRUE(ngpField.need_sync_to_host()); } + +TEST_F(Hex8Mesh, SmartFieldRef){ + fill_mesh_and_initialize_test_fields(); + + auto* field = fieldManager->get_field_ptr("scalarQ"); + + stk::mesh::NgpField& ngpField = + stk::mesh::get_updated_ngp_field(*field); + + ngpField.modify_on_host(); + + ASSERT_TRUE(ngpField.need_sync_to_device()); + + auto sPtr = nalu_ngp::DeviceSmartFieldRef(ngpField, nalu_ngp::Scope::READWRITE); + lambda_impl(sPtr); + + EXPECT_FALSE(ngpField.need_sync_to_device()); + EXPECT_TRUE(ngpField.need_sync_to_host()); + +} +} From 2f19cc613d931cd2bd1d8037e72649115cc2a42b Mon Sep 17 00:00:00 2001 From: psakiev Date: Wed, 13 Sep 2023 12:36:18 -0600 Subject: [PATCH 06/40] Make unit test fixture --- unit_tests/UnitTestSmartFieldPtr.C | 53 +++++++++++++++--------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/unit_tests/UnitTestSmartFieldPtr.C b/unit_tests/UnitTestSmartFieldPtr.C index 169d1f268..63777e0a6 100644 --- a/unit_tests/UnitTestSmartFieldPtr.C +++ b/unit_tests/UnitTestSmartFieldPtr.C @@ -13,6 +13,20 @@ #include #include "ngp_utils/SmartFieldRef.h" +class TestSmartFieldRef : public Hex8Mesh{ +protected: + void SetUp(){ + fill_mesh_and_initialize_test_fields(); + + auto* field = fieldManager->get_field_ptr("scalarQ"); + + ngpField_ = + &stk::mesh::get_updated_ngp_field(*field); + + } + stk::mesh::NgpField* ngpField_; +}; + template class SmartFieldPtr{ public: @@ -43,43 +57,28 @@ void lambda_impl(T& ptr){ } namespace sierra::nalu{ -TEST_F(Hex8Mesh, SmartFieldPtr){ - fill_mesh_and_initialize_test_fields(); +TEST_F(TestSmartFieldRef, SmartFieldPtr){ - auto* field = fieldManager->get_field_ptr("scalarQ"); + ngpField_->modify_on_host(); - stk::mesh::NgpField& ngpField = - stk::mesh::get_updated_ngp_field(*field); + ASSERT_TRUE(ngpField_->need_sync_to_device()); - ngpField.modify_on_host(); - - ASSERT_TRUE(ngpField.need_sync_to_device()); - - auto sPtr = SmartFieldPtr(ngpField); + auto sPtr = SmartFieldPtr(*ngpField_); lambda_impl(sPtr); - EXPECT_FALSE(ngpField.need_sync_to_device()); - EXPECT_TRUE(ngpField.need_sync_to_host()); - + EXPECT_FALSE(ngpField_->need_sync_to_device()); + EXPECT_TRUE(ngpField_->need_sync_to_host()); } -TEST_F(Hex8Mesh, SmartFieldRef){ - fill_mesh_and_initialize_test_fields(); +TEST_F(TestSmartFieldRef, SmartFieldRef){ + ngpField_->modify_on_host(); - auto* field = fieldManager->get_field_ptr("scalarQ"); + ASSERT_TRUE(ngpField_->need_sync_to_device()); - stk::mesh::NgpField& ngpField = - stk::mesh::get_updated_ngp_field(*field); - - ngpField.modify_on_host(); - - ASSERT_TRUE(ngpField.need_sync_to_device()); - - auto sPtr = nalu_ngp::DeviceSmartFieldRef(ngpField, nalu_ngp::Scope::READWRITE); + auto sPtr = nalu_ngp::DeviceSmartFieldRef(*ngpField_, nalu_ngp::Scope::READWRITE); lambda_impl(sPtr); - EXPECT_FALSE(ngpField.need_sync_to_device()); - EXPECT_TRUE(ngpField.need_sync_to_host()); - + EXPECT_FALSE(ngpField_->need_sync_to_device()); + EXPECT_TRUE(ngpField_->need_sync_to_host()); } } From 610da575ffa3e517bb4c2f6edb8449763bc41a54 Mon Sep 17 00:00:00 2001 From: psakiev Date: Wed, 13 Sep 2023 13:21:38 -0600 Subject: [PATCH 07/40] Generalize code a little --- include/ngp_utils/SmartFieldRef.h | 22 +++++++++++++++++----- unit_tests/UnitTestSmartFieldPtr.C | 2 +- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/include/ngp_utils/SmartFieldRef.h b/include/ngp_utils/SmartFieldRef.h index 343763ed2..01484168e 100644 --- a/include/ngp_utils/SmartFieldRef.h +++ b/include/ngp_utils/SmartFieldRef.h @@ -21,13 +21,23 @@ enum class Scope{ READWRITE }; +template +using DeviceField = stk::mesh::NgpField; template -class DeviceSmartFieldRef{ +using HostField = stk::mesh::HostField; + +template typename FieldType> +class SmartFieldRef{ public: - DeviceSmartFieldRef(stk::mesh::NgpField& ngpField, Scope scope):fieldRef_(ngpField),scope_(scope){} + SmartFieldRef(FieldType& ngpField, Scope scope): + fieldRef_(ngpField), + scope_(scope){} - DeviceSmartFieldRef(const DeviceSmartFieldRef& src):fieldRef_(src.fieldRef_), scope_(src.scope_), is_copy_constructed_(true) + SmartFieldRef(const SmartFieldRef& src): + fieldRef_(src.fieldRef_), + scope_(src.scope_), + is_copy_constructed_(true) { if(scope_ == Scope::WRITE) fieldRef_.clear_sync_state(); @@ -35,7 +45,7 @@ class DeviceSmartFieldRef{ fieldRef_.sync_to_device(); } - ~DeviceSmartFieldRef(){ + ~SmartFieldRef(){ if(is_copy_constructed_ && !scope_is(Scope::READ)){ fieldRef_.modify_on_device(); } @@ -51,11 +61,13 @@ class DeviceSmartFieldRef{ return scope_ == test; } - stk::mesh::NgpField& fieldRef_; + FieldType& fieldRef_; const Scope scope_; const bool is_copy_constructed_{false}; }; +template +using DeviceSmartFieldRef = SmartFieldRef; } diff --git a/unit_tests/UnitTestSmartFieldPtr.C b/unit_tests/UnitTestSmartFieldPtr.C index 63777e0a6..d39bbd55a 100644 --- a/unit_tests/UnitTestSmartFieldPtr.C +++ b/unit_tests/UnitTestSmartFieldPtr.C @@ -75,7 +75,7 @@ TEST_F(TestSmartFieldRef, SmartFieldRef){ ASSERT_TRUE(ngpField_->need_sync_to_device()); - auto sPtr = nalu_ngp::DeviceSmartFieldRef(*ngpField_, nalu_ngp::Scope::READWRITE); + auto sPtr = nalu_ngp::DeviceSmartFieldRef(*ngpField_, nalu_ngp::Scope::READWRITE); lambda_impl(sPtr); EXPECT_FALSE(ngpField_->need_sync_to_device()); From 256a3bdc45a61cbf71d26df637c665a0330d23bd Mon Sep 17 00:00:00 2001 From: psakiev Date: Wed, 13 Sep 2023 16:42:15 -0600 Subject: [PATCH 08/40] Trying a new design --- include/ngp_utils/SmartFieldRef.h | 78 ++++++++++++++++++------------ unit_tests/UnitTestSmartFieldPtr.C | 3 +- 2 files changed, 48 insertions(+), 33 deletions(-) diff --git a/include/ngp_utils/SmartFieldRef.h b/include/ngp_utils/SmartFieldRef.h index 01484168e..e5e456161 100644 --- a/include/ngp_utils/SmartFieldRef.h +++ b/include/ngp_utils/SmartFieldRef.h @@ -9,44 +9,38 @@ #ifndef SMARTFIELDREF_H #define SMARTFIELDREF_H +#include #include #include -namespace sierra::nalu::nalu_ngp{ -struct READ{}; - -enum class Scope{ - READ, - WRITE, - READWRITE -}; +namespace sierra::nalu::SmartFieldRef{ -template -using DeviceField = stk::mesh::NgpField; - -template -using HostField = stk::mesh::HostField; +struct READ{}; +struct WRITE{}; +struct READ_WRITE{}; -template typename FieldType> -class SmartFieldRef{ +template +class DeviceRef{ public: - SmartFieldRef(FieldType& ngpField, Scope scope): - fieldRef_(ngpField), - scope_(scope){} + DeviceRef(stk::mesh::NgpField& ngpField): + fieldRef_(ngpField){} - SmartFieldRef(const SmartFieldRef& src): + DeviceRef(const DeviceRef& src): fieldRef_(src.fieldRef_), - scope_(src.scope_), is_copy_constructed_(true) { - if(scope_ == Scope::WRITE) - fieldRef_.clear_sync_state(); - else + if(is_read()) fieldRef_.sync_to_device(); + else + fieldRef_.clear_sync_state(); } - ~SmartFieldRef(){ - if(is_copy_constructed_ && !scope_is(Scope::READ)){ + // 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. + ~DeviceRef(){ + if(is_copy_constructed_ && is_write()){ fieldRef_.modify_on_device(); } } @@ -56,19 +50,39 @@ class SmartFieldRef{ return fieldRef_.get_ordinal(); } + KOKKOS_FUNCTION + T& get(stk::mesh::FastMeshIndex index, int component){ + return fieldRef_.get(index, component); + } + + template 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 KOKKOS_FUNCTION + T& operator()(MeshIndex index, int component){ + return fieldRef_.operator()(index, component); + } + private: - bool scope_is(Scope test){ - return scope_ == test; + bool is_read(){ + return std::is_same::value || std::is_same::value; } - FieldType& fieldRef_; - const Scope scope_; + bool is_write(){ + return std::is_same::value || std::is_same::value; + } + + stk::mesh::NgpField& fieldRef_; const bool is_copy_constructed_{false}; }; -template -using DeviceSmartFieldRef = SmartFieldRef; - } #endif diff --git a/unit_tests/UnitTestSmartFieldPtr.C b/unit_tests/UnitTestSmartFieldPtr.C index d39bbd55a..e1e016c8c 100644 --- a/unit_tests/UnitTestSmartFieldPtr.C +++ b/unit_tests/UnitTestSmartFieldPtr.C @@ -57,6 +57,7 @@ void lambda_impl(T& ptr){ } namespace sierra::nalu{ +namespace sfr = SmartFieldRef; TEST_F(TestSmartFieldRef, SmartFieldPtr){ ngpField_->modify_on_host(); @@ -75,7 +76,7 @@ TEST_F(TestSmartFieldRef, SmartFieldRef){ ASSERT_TRUE(ngpField_->need_sync_to_device()); - auto sPtr = nalu_ngp::DeviceSmartFieldRef(*ngpField_, nalu_ngp::Scope::READWRITE); + auto sPtr = sfr::DeviceRef(*ngpField_); lambda_impl(sPtr); EXPECT_FALSE(ngpField_->need_sync_to_device()); From 739f50effe886f2a23f9f2143e75108b68e408eb Mon Sep 17 00:00:00 2001 From: psakiev Date: Wed, 13 Sep 2023 21:30:46 -0600 Subject: [PATCH 09/40] Redesign again: templates for space and access type --- include/ngp_utils/SmartFieldRef.h | 81 +++++++++++++++++++++++++++--- unit_tests/UnitTestSmartFieldPtr.C | 4 +- 2 files changed, 77 insertions(+), 8 deletions(-) diff --git a/include/ngp_utils/SmartFieldRef.h b/include/ngp_utils/SmartFieldRef.h index e5e456161..df6c4ba31 100644 --- a/include/ngp_utils/SmartFieldRef.h +++ b/include/ngp_utils/SmartFieldRef.h @@ -13,19 +13,25 @@ #include #include -namespace sierra::nalu::SmartFieldRef{ +namespace sierra::nalu{ struct READ{}; struct WRITE{}; struct READ_WRITE{}; -template -class DeviceRef{ +struct HOST{}; +struct DEVICE{}; + +template +class SmartFieldRef{}; + +template +class SmartFieldRef{ public: - DeviceRef(stk::mesh::NgpField& ngpField): + SmartFieldRef(stk::mesh::NgpField& ngpField): fieldRef_(ngpField){} - DeviceRef(const DeviceRef& src): + SmartFieldRef(const SmartFieldRef& src): fieldRef_(src.fieldRef_), is_copy_constructed_(true) { @@ -39,7 +45,7 @@ class DeviceRef{ // and hence be captured by a lambda. // Therefore we only ever need to sync copies that will have been snatched up // through lambda capture. - ~DeviceRef(){ + ~SmartFieldRef(){ if(is_copy_constructed_ && is_write()){ fieldRef_.modify_on_device(); } @@ -50,6 +56,8 @@ class DeviceRef{ 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); @@ -83,6 +91,67 @@ class DeviceRef{ const bool is_copy_constructed_{false}; }; + +template +class SmartFieldRef{ +public: + SmartFieldRef(stk::mesh::HostField& 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(); + } + } + + unsigned get_ordinal() const{ + return fieldRef_.get_ordinal(); + } + + T& get(stk::mesh::FastMeshIndex index, int component){ + return fieldRef_.get(index, component); + } + + template + 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 + T& operator()(MeshIndex index, int component){ + return fieldRef_.operator()(index, component); + } + +private: + bool is_read(){ + return std::is_same::value || std::is_same::value; + } + + bool is_write(){ + return std::is_same::value || std::is_same::value; + } + + stk::mesh::HostField& fieldRef_; + const bool is_copy_constructed_{false}; +}; } #endif diff --git a/unit_tests/UnitTestSmartFieldPtr.C b/unit_tests/UnitTestSmartFieldPtr.C index e1e016c8c..bd0a863de 100644 --- a/unit_tests/UnitTestSmartFieldPtr.C +++ b/unit_tests/UnitTestSmartFieldPtr.C @@ -57,7 +57,6 @@ void lambda_impl(T& ptr){ } namespace sierra::nalu{ -namespace sfr = SmartFieldRef; TEST_F(TestSmartFieldRef, SmartFieldPtr){ ngpField_->modify_on_host(); @@ -76,7 +75,8 @@ TEST_F(TestSmartFieldRef, SmartFieldRef){ ASSERT_TRUE(ngpField_->need_sync_to_device()); - auto sPtr = sfr::DeviceRef(*ngpField_); + //TODO can we get rid of the double template param some how? + auto sPtr = SmartFieldRef(*ngpField_); lambda_impl(sPtr); EXPECT_FALSE(ngpField_->need_sync_to_device()); From a4767f94d5c3aa828904ad52165060b9cd7a8857 Mon Sep 17 00:00:00 2001 From: psakiev Date: Wed, 13 Sep 2023 21:34:55 -0600 Subject: [PATCH 10/40] Add more tests --- unit_tests/UnitTestSmartFieldPtr.C | 45 ++++++++++++------------------ 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/unit_tests/UnitTestSmartFieldPtr.C b/unit_tests/UnitTestSmartFieldPtr.C index bd0a863de..0fe3f34c0 100644 --- a/unit_tests/UnitTestSmartFieldPtr.C +++ b/unit_tests/UnitTestSmartFieldPtr.C @@ -27,27 +27,6 @@ protected: stk::mesh::NgpField* ngpField_; }; -template -class SmartFieldPtr{ -public: - SmartFieldPtr(stk::mesh::NgpField& fieldRef):fieldPtr_(fieldRef){} - - SmartFieldPtr(const SmartFieldPtr& src): fieldPtr_(src.fieldPtr_){ - fieldPtr_.sync_to_device(); - } - - KOKKOS_FUNCTION - unsigned get_ordinal() const{ - return fieldPtr_.get_ordinal(); - } - - ~SmartFieldPtr(){ - fieldPtr_.modify_on_device(); - } - stk::mesh::NgpField& fieldPtr_; -}; - - template void lambda_impl(T& ptr){ Kokkos::parallel_for(1, @@ -57,29 +36,41 @@ void lambda_impl(T& ptr){ } namespace sierra::nalu{ -TEST_F(TestSmartFieldRef, SmartFieldPtr){ - +TEST_F(TestSmartFieldRef, device_read_write_mod_sync_with_lambda){ ngpField_->modify_on_host(); ASSERT_TRUE(ngpField_->need_sync_to_device()); - auto sPtr = SmartFieldPtr(*ngpField_); + //TODO can we get rid of the double template param some how? + auto sPtr = SmartFieldRef(*ngpField_); lambda_impl(sPtr); EXPECT_FALSE(ngpField_->need_sync_to_device()); EXPECT_TRUE(ngpField_->need_sync_to_host()); } -TEST_F(TestSmartFieldRef, SmartFieldRef){ +TEST_F(TestSmartFieldRef, device_write_clear_mod_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(*ngpField_); + auto sPtr = SmartFieldRef(*ngpField_); lambda_impl(sPtr); EXPECT_FALSE(ngpField_->need_sync_to_device()); EXPECT_TRUE(ngpField_->need_sync_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(*ngpField_); + lambda_impl(sPtr); + + EXPECT_FALSE(ngpField_->need_sync_to_device()); + EXPECT_FALSE(ngpField_->need_sync_to_host()); +} + } From dcb04792f916750c2fea2097d4f5584aa6026809 Mon Sep 17 00:00:00 2001 From: psakiev Date: Wed, 13 Sep 2023 21:45:51 -0600 Subject: [PATCH 11/40] Add tests to ensure sync count is correct --- unit_tests/UnitTestSmartFieldPtr.C | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/unit_tests/UnitTestSmartFieldPtr.C b/unit_tests/UnitTestSmartFieldPtr.C index 0fe3f34c0..2d0939382 100644 --- a/unit_tests/UnitTestSmartFieldPtr.C +++ b/unit_tests/UnitTestSmartFieldPtr.C @@ -23,8 +23,13 @@ protected: ngpField_ = &stk::mesh::get_updated_ngp_field(*field); + initSyncsHost_ = ngpField_->num_syncs_to_host(); + initSyncsDevice_ = ngpField_->num_syncs_to_device(); } + stk::mesh::NgpField* ngpField_; + int initSyncsHost_{0}; + int initSyncsDevice_{0}; }; template @@ -47,6 +52,8 @@ TEST_F(TestSmartFieldRef, device_read_write_mod_sync_with_lambda){ 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){ @@ -59,6 +66,8 @@ TEST_F(TestSmartFieldRef, device_write_clear_mod_with_lambda){ 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){ @@ -71,6 +80,8 @@ TEST_F(TestSmartFieldRef, device_read_mod_no_sync_with_lambda){ 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()); } } From af017d93efa804a77b7732c6cec31a90ca6c9396 Mon Sep 17 00:00:00 2001 From: psakiev Date: Wed, 13 Sep 2023 21:47:42 -0600 Subject: [PATCH 12/40] Rename file --- unit_tests/CMakeLists.txt | 2 +- unit_tests/{UnitTestSmartFieldPtr.C => UnitTestSmartFieldRef.C} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename unit_tests/{UnitTestSmartFieldPtr.C => UnitTestSmartFieldRef.C} (100%) diff --git a/unit_tests/CMakeLists.txt b/unit_tests/CMakeLists.txt index 7bc8fd265..25b9948f4 100644 --- a/unit_tests/CMakeLists.txt +++ b/unit_tests/CMakeLists.txt @@ -27,7 +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}/UnitTestSmartFieldPtr.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 diff --git a/unit_tests/UnitTestSmartFieldPtr.C b/unit_tests/UnitTestSmartFieldRef.C similarity index 100% rename from unit_tests/UnitTestSmartFieldPtr.C rename to unit_tests/UnitTestSmartFieldRef.C From f5a954dd89dd25bcbf57a8d2148ceeca546eb8f8 Mon Sep 17 00:00:00 2001 From: psakiev Date: Wed, 13 Sep 2023 21:52:56 -0600 Subject: [PATCH 13/40] Add some fixes for host --- include/ngp_utils/SmartFieldRef.h | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/include/ngp_utils/SmartFieldRef.h b/include/ngp_utils/SmartFieldRef.h index df6c4ba31..f6d3b2309 100644 --- a/include/ngp_utils/SmartFieldRef.h +++ b/include/ngp_utils/SmartFieldRef.h @@ -103,18 +103,21 @@ class SmartFieldRef{ is_copy_constructed_(true) { if(is_read()) - fieldRef_.sync_to_device(); + fieldRef_.sync_to_host(); 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. + // 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_device(); + fieldRef_.modify_on_host(); } } From 6d9f5fd883d0a6f3c1cf20a4684ed06ebc4f1a61 Mon Sep 17 00:00:00 2001 From: Philip Sakievich Date: Wed, 13 Sep 2023 22:18:17 -0600 Subject: [PATCH 14/40] Style --- include/ngp_utils/SmartFieldRef.h | 141 +++++++++++++++++------------ unit_tests/UnitTestSmartFieldRef.C | 56 ++++++------ 2 files changed, 112 insertions(+), 85 deletions(-) diff --git a/include/ngp_utils/SmartFieldRef.h b/include/ngp_utils/SmartFieldRef.h index f6d3b2309..1712b49f2 100644 --- a/include/ngp_utils/SmartFieldRef.h +++ b/include/ngp_utils/SmartFieldRef.h @@ -13,96 +13,112 @@ #include #include -namespace sierra::nalu{ +namespace sierra::nalu { -struct READ{}; -struct WRITE{}; -struct READ_WRITE{}; +struct READ +{ +}; +struct WRITE +{ +}; +struct READ_WRITE +{ +}; -struct HOST{}; -struct DEVICE{}; +struct HOST +{ +}; +struct DEVICE +{ +}; template -class SmartFieldRef{}; +class SmartFieldRef +{ +}; template -class SmartFieldRef{ +class SmartFieldRef +{ public: - SmartFieldRef(stk::mesh::NgpField& ngpField): - fieldRef_(ngpField){} + SmartFieldRef(stk::mesh::NgpField& ngpField) : fieldRef_(ngpField) {} - SmartFieldRef(const SmartFieldRef& src): - fieldRef_(src.fieldRef_), - is_copy_constructed_(true) + SmartFieldRef(const SmartFieldRef& src) + : fieldRef_(src.fieldRef_), is_copy_constructed_(true) { - if(is_read()) + 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()){ + // 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(); - } + 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 + // 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){ + T& get(stk::mesh::FastMeshIndex index, int component) + { return fieldRef_.get(index, component); } - template KOKKOS_FUNCTION - T& get(MeshIndex index, int component){ + template + KOKKOS_FUNCTION T& get(MeshIndex index, int component) + { return fieldRef_.get(index, component); } KOKKOS_FUNCTION - T& operator()(stk::mesh::FastMeshIndex index, int component){ + T& operator()(stk::mesh::FastMeshIndex index, int component) + { return fieldRef_.get(index, component); } - template KOKKOS_FUNCTION - T& operator()(MeshIndex index, int component){ + template + KOKKOS_FUNCTION T& operator()(MeshIndex index, int component) + { return fieldRef_.operator()(index, component); } private: - bool is_read(){ - return std::is_same::value || std::is_same::value; + bool is_read() + { + return std::is_same::value || + std::is_same::value; } - bool is_write(){ - return std::is_same::value || std::is_same::value; + bool is_write() + { + return std::is_same::value || + std::is_same::value; } stk::mesh::NgpField& fieldRef_; const bool is_copy_constructed_{false}; }; - template -class SmartFieldRef{ +class SmartFieldRef +{ public: - SmartFieldRef(stk::mesh::HostField& ngpField): - fieldRef_(ngpField){} + SmartFieldRef(stk::mesh::HostField& ngpField) : fieldRef_(ngpField) {} - SmartFieldRef(const SmartFieldRef& src): - fieldRef_(src.fieldRef_), - is_copy_constructed_(true) + SmartFieldRef(const SmartFieldRef& src) + : fieldRef_(src.fieldRef_), is_copy_constructed_(true) { - if(is_read()) + if (is_read()) fieldRef_.sync_to_host(); else fieldRef_.clear_sync_state(); @@ -115,46 +131,53 @@ class SmartFieldRef{ // // 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()){ + ~SmartFieldRef() + { + if (is_copy_constructed_ && is_write()) { fieldRef_.modify_on_host(); } } - unsigned get_ordinal() const{ - return fieldRef_.get_ordinal(); - } + unsigned get_ordinal() const { return fieldRef_.get_ordinal(); } - T& get(stk::mesh::FastMeshIndex index, int component){ + T& get(stk::mesh::FastMeshIndex index, int component) + { return fieldRef_.get(index, component); } - template - T& get(MeshIndex index, int component){ + template + T& get(MeshIndex index, int component) + { return fieldRef_.get(index, component); } - T& operator()(stk::mesh::FastMeshIndex index, int component){ + T& operator()(stk::mesh::FastMeshIndex index, int component) + { return fieldRef_.get(index, component); } - template - T& operator()(MeshIndex index, int component){ + template + T& operator()(MeshIndex index, int component) + { return fieldRef_.operator()(index, component); } private: - bool is_read(){ - return std::is_same::value || std::is_same::value; + bool is_read() + { + return std::is_same::value || + std::is_same::value; } - bool is_write(){ - return std::is_same::value || std::is_same::value; + bool is_write() + { + return std::is_same::value || + std::is_same::value; } stk::mesh::HostField& fieldRef_; const bool is_copy_constructed_{false}; }; -} +} // namespace sierra::nalu #endif diff --git a/unit_tests/UnitTestSmartFieldRef.C b/unit_tests/UnitTestSmartFieldRef.C index 2d0939382..462e96573 100644 --- a/unit_tests/UnitTestSmartFieldRef.C +++ b/unit_tests/UnitTestSmartFieldRef.C @@ -13,18 +13,19 @@ #include #include "ngp_utils/SmartFieldRef.h" -class TestSmartFieldRef : public Hex8Mesh{ +class TestSmartFieldRef : public Hex8Mesh +{ protected: - void SetUp(){ - fill_mesh_and_initialize_test_fields(); + void SetUp() + { + fill_mesh_and_initialize_test_fields(); - auto* field = fieldManager->get_field_ptr("scalarQ"); + auto* field = fieldManager->get_field_ptr("scalarQ"); - ngpField_ = - &stk::mesh::get_updated_ngp_field(*field); + ngpField_ = &stk::mesh::get_updated_ngp_field(*field); - initSyncsHost_ = ngpField_->num_syncs_to_host(); - initSyncsDevice_ = ngpField_->num_syncs_to_device(); + initSyncsHost_ = ngpField_->num_syncs_to_host(); + initSyncsDevice_ = ngpField_->num_syncs_to_device(); } stk::mesh::NgpField* ngpField_; @@ -32,31 +33,33 @@ protected: int initSyncsDevice_{0}; }; -template -void lambda_impl(T& ptr){ - Kokkos::parallel_for(1, - KOKKOS_LAMBDA(int){ - ptr.get_ordinal(); - }); +template +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){ +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? + // TODO can we get rid of the double template param some how? auto sPtr = SmartFieldRef(*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()); + 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){ +TEST_F(TestSmartFieldRef, device_write_clear_mod_with_lambda) +{ ngpField_->modify_on_host(); ASSERT_TRUE(ngpField_->need_sync_to_device()); @@ -66,11 +69,12 @@ TEST_F(TestSmartFieldRef, device_write_clear_mod_with_lambda){ 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()); + 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){ +TEST_F(TestSmartFieldRef, device_read_mod_no_sync_with_lambda) +{ ngpField_->modify_on_host(); ASSERT_TRUE(ngpField_->need_sync_to_device()); @@ -80,8 +84,8 @@ TEST_F(TestSmartFieldRef, device_read_mod_no_sync_with_lambda){ 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()); + EXPECT_EQ(initSyncsDevice_ + 1, ngpField_->num_syncs_to_device()); + EXPECT_EQ(initSyncsHost_ + 0, ngpField_->num_syncs_to_host()); } -} +} // namespace sierra::nalu From 609ab468e1e4970d6c01af0388330b6256b9e731 Mon Sep 17 00:00:00 2001 From: psakiev Date: Sun, 17 Sep 2023 06:09:46 -0600 Subject: [PATCH 15/40] Change scope to access and create creator obj --- include/ngp_utils/SmartFieldRef.h | 120 +++++++---------------------- unit_tests/UnitTestSmartFieldRef.C | 6 +- 2 files changed, 30 insertions(+), 96 deletions(-) diff --git a/include/ngp_utils/SmartFieldRef.h b/include/ngp_utils/SmartFieldRef.h index 1712b49f2..ab5b939d8 100644 --- a/include/ngp_utils/SmartFieldRef.h +++ b/include/ngp_utils/SmartFieldRef.h @@ -14,31 +14,22 @@ #include namespace sierra::nalu { +//clang-format off +struct READ{}; +struct WRITE{}; +struct READ_WRITE{}; -struct READ -{ -}; -struct WRITE -{ -}; -struct READ_WRITE -{ -}; +struct HOST{}; +struct DEVICE{}; +//clang-format on -struct HOST -{ -}; -struct DEVICE -{ -}; - -template +template class SmartFieldRef { }; -template -class SmartFieldRef +template +class SmartFieldRef { public: SmartFieldRef(stk::mesh::NgpField& ngpField) : fieldRef_(ngpField) {} @@ -63,31 +54,31 @@ class SmartFieldRef } } - KOKKOS_FUNCTION + KOKKOS_INLINE_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 + KOKKOS_INLINE_FUNCTION T& get(stk::mesh::FastMeshIndex index, int component) { return fieldRef_.get(index, component); } template - KOKKOS_FUNCTION T& get(MeshIndex index, int component) + KOKKOS_INLINE_FUNCTION T& get(MeshIndex index, int component) { return fieldRef_.get(index, component); } - KOKKOS_FUNCTION + KOKKOS_INLINE_FUNCTION T& operator()(stk::mesh::FastMeshIndex index, int component) { return fieldRef_.get(index, component); } template - KOKKOS_FUNCTION T& operator()(MeshIndex index, int component) + KOKKOS_INLINE_FUNCTION T& operator()(MeshIndex index, int component) { return fieldRef_.operator()(index, component); } @@ -95,88 +86,31 @@ class SmartFieldRef private: bool is_read() { - return std::is_same::value || - std::is_same::value; + return std::is_same::value || + std::is_same::value; } bool is_write() { - return std::is_same::value || - std::is_same::value; + return std::is_same::value || + std::is_same::value; } stk::mesh::NgpField& fieldRef_; const bool is_copy_constructed_{false}; }; -template -class SmartFieldRef -{ -public: - SmartFieldRef(stk::mesh::HostField& 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 - T& get(MeshIndex index, int component) - { - return fieldRef_.get(index, component); - } +template +struct MakeFieldRef{}; - T& operator()(stk::mesh::FastMeshIndex index, int component) - { - return fieldRef_.get(index, component); - } - - template - T& operator()(MeshIndex index, int component) - { - return fieldRef_.operator()(index, component); - } - -private: - bool is_read() - { - return std::is_same::value || - std::is_same::value; - } - - bool is_write() - { - return std::is_same::value || - std::is_same::value; +template +struct MakeFieldRef +{ + template + SmartFieldRef operator()(stk::mesh::NgpField& field){ + return SmartFieldRef(field); } - - stk::mesh::HostField& fieldRef_; - const bool is_copy_constructed_{false}; }; } // namespace sierra::nalu diff --git a/unit_tests/UnitTestSmartFieldRef.C b/unit_tests/UnitTestSmartFieldRef.C index 462e96573..87eb97d33 100644 --- a/unit_tests/UnitTestSmartFieldRef.C +++ b/unit_tests/UnitTestSmartFieldRef.C @@ -49,7 +49,7 @@ TEST_F(TestSmartFieldRef, device_read_write_mod_sync_with_lambda) ASSERT_TRUE(ngpField_->need_sync_to_device()); // TODO can we get rid of the double template param some how? - auto sPtr = SmartFieldRef(*ngpField_); + auto sPtr = MakeFieldRef()(*ngpField_); lambda_impl(sPtr); EXPECT_FALSE(ngpField_->need_sync_to_device()); @@ -64,7 +64,7 @@ TEST_F(TestSmartFieldRef, device_write_clear_mod_with_lambda) ASSERT_TRUE(ngpField_->need_sync_to_device()); - auto sPtr = SmartFieldRef(*ngpField_); + auto sPtr = MakeFieldRef()(*ngpField_); lambda_impl(sPtr); EXPECT_FALSE(ngpField_->need_sync_to_device()); @@ -79,7 +79,7 @@ TEST_F(TestSmartFieldRef, device_read_mod_no_sync_with_lambda) ASSERT_TRUE(ngpField_->need_sync_to_device()); - auto sPtr = SmartFieldRef(*ngpField_); + auto sPtr = MakeFieldRef()(*ngpField_); lambda_impl(sPtr); EXPECT_FALSE(ngpField_->need_sync_to_device()); From cf82d244afe0029a6a445ce7a8db92c7c3d4f447 Mon Sep 17 00:00:00 2001 From: psakiev Date: Mon, 18 Sep 2023 05:58:23 -0600 Subject: [PATCH 16/40] Add host specialization for bucket loops --- include/ngp_utils/SmartFieldRef.h | 87 ++++++++++++++++++++++++++++-- unit_tests/UnitTestSmartFieldRef.C | 70 ++++++++++++++++++++++-- 2 files changed, 147 insertions(+), 10 deletions(-) diff --git a/include/ngp_utils/SmartFieldRef.h b/include/ngp_utils/SmartFieldRef.h index ab5b939d8..69ae4224b 100644 --- a/include/ngp_utils/SmartFieldRef.h +++ b/include/ngp_utils/SmartFieldRef.h @@ -13,7 +13,7 @@ #include #include -namespace sierra::nalu { +namespace tags{ //clang-format off struct READ{}; struct WRITE{}; @@ -22,6 +22,11 @@ struct READ_WRITE{}; struct HOST{}; struct DEVICE{}; //clang-format on +} + +namespace sierra::nalu { + +using namespace tags; template class SmartFieldRef @@ -60,25 +65,25 @@ class SmartFieldRef // 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_INLINE_FUNCTION - T& get(stk::mesh::FastMeshIndex index, int component) + T& get(stk::mesh::FastMeshIndex& index, int component) const { return fieldRef_.get(index, component); } template - KOKKOS_INLINE_FUNCTION T& get(MeshIndex index, int component) + KOKKOS_INLINE_FUNCTION T& get(MeshIndex index, int component) const { return fieldRef_.get(index, component); } KOKKOS_INLINE_FUNCTION - T& operator()(stk::mesh::FastMeshIndex index, int component) + T& operator()(const stk::mesh::FastMeshIndex& index, int component) const { return fieldRef_.get(index, component); } template - KOKKOS_INLINE_FUNCTION T& operator()(MeshIndex index, int component) + KOKKOS_INLINE_FUNCTION T& operator()(const MeshIndex index, int component) const { return fieldRef_.operator()(index, component); } @@ -100,10 +105,82 @@ class SmartFieldRef const bool is_copy_constructed_{false}; }; +// HOST specialization using legacy bucket loops +// TODO would we ever/can we use stk::mesh::HostField's inside a device enabled +// build? +// If so I think we should change this to LEGACY instead of HOST +template +class SmartFieldRef +{ +public: + SmartFieldRef(stk::mesh::Field& field) : fieldRef_(field) + { + if (is_read()) + fieldRef_.sync_to_host(); + else + fieldRef_.clear_sync_state(); + } + + SmartFieldRef(const SmartFieldRef& src) + : fieldRef_(src.fieldRef_), is_copy_constructed_(true) + { + if (is_read()) + fieldRef_.sync_to_host(); + else + fieldRef_.clear_sync_state(); + } + + // try removing the copy constructor requirement for host fields + ~SmartFieldRef() + { + if (is_write()) { + fieldRef_.modify_on_host(); + } + } + + // 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 + inline + T& get(const stk::mesh::Entity& entity) const + { + return *stk::mesh::field_data(fieldRef_, entity); + } + + inline + T& operator()(const stk::mesh::Entity& entity) const + { + return *stk::mesh::field_data(fieldRef_, entity); + } + +private: + bool is_read() + { + return std::is_same::value || + std::is_same::value; + } + + bool is_write() + { + return std::is_same::value || + std::is_same::value; + } + + stk::mesh::Field& fieldRef_; + const bool is_copy_constructed_{false}; +}; template struct MakeFieldRef{}; +template +struct MakeFieldRef +{ + template + SmartFieldRef operator()(stk::mesh::Field& field){ + return SmartFieldRef(field); + } +}; + template struct MakeFieldRef { diff --git a/unit_tests/UnitTestSmartFieldRef.C b/unit_tests/UnitTestSmartFieldRef.C index 87eb97d33..be4820699 100644 --- a/unit_tests/UnitTestSmartFieldRef.C +++ b/unit_tests/UnitTestSmartFieldRef.C @@ -15,6 +15,7 @@ class TestSmartFieldRef : public Hex8Mesh { +public: protected: void SetUp() { @@ -32,16 +33,39 @@ protected: int initSyncsHost_{0}; int initSyncsDevice_{0}; }; - +//***************************************************************************** +// Free functions for execution on device +//***************************************************************************** template void -lambda_impl(T& ptr) +lambda_ordinal(T& ptr) { Kokkos::parallel_for( 1, KOKKOS_LAMBDA(int) { ptr.get_ordinal(); }); } +template +void lambda_loop_assign(stk::mesh::BulkData& bulk, stk::mesh::PartVector partVec, T& ptr, double val = 300.0) +{ + stk::mesh::NgpMesh& ngpMesh = stk::mesh::get_updated_ngp_mesh(bulk); + stk::mesh::Selector sel = stk::mesh::selectUnion(partVec); + stk::mesh::for_each_entity_run( + ngpMesh, + stk::topology::NODE_RANK, + sel, + KOKKOS_LAMBDA(const stk::mesh::FastMeshIndex& entity){ + ptr(entity, 0) = val; + } + ); + +} + +//***************************************************************************** +// Tests +//***************************************************************************** namespace sierra::nalu { +using namespace tags; + TEST_F(TestSmartFieldRef, device_read_write_mod_sync_with_lambda) { ngpField_->modify_on_host(); @@ -50,7 +74,7 @@ TEST_F(TestSmartFieldRef, device_read_write_mod_sync_with_lambda) // TODO can we get rid of the double template param some how? auto sPtr = MakeFieldRef()(*ngpField_); - lambda_impl(sPtr); + lambda_ordinal(sPtr); EXPECT_FALSE(ngpField_->need_sync_to_device()); EXPECT_TRUE(ngpField_->need_sync_to_host()); @@ -65,7 +89,7 @@ TEST_F(TestSmartFieldRef, device_write_clear_mod_with_lambda) ASSERT_TRUE(ngpField_->need_sync_to_device()); auto sPtr = MakeFieldRef()(*ngpField_); - lambda_impl(sPtr); + lambda_ordinal(sPtr); EXPECT_FALSE(ngpField_->need_sync_to_device()); EXPECT_TRUE(ngpField_->need_sync_to_host()); @@ -80,7 +104,7 @@ TEST_F(TestSmartFieldRef, device_read_mod_no_sync_with_lambda) ASSERT_TRUE(ngpField_->need_sync_to_device()); auto sPtr = MakeFieldRef()(*ngpField_); - lambda_impl(sPtr); + lambda_ordinal(sPtr); EXPECT_FALSE(ngpField_->need_sync_to_device()); EXPECT_FALSE(ngpField_->need_sync_to_host()); @@ -88,4 +112,40 @@ TEST_F(TestSmartFieldRef, device_read_mod_no_sync_with_lambda) EXPECT_EQ(initSyncsHost_ + 0, ngpField_->num_syncs_to_host()); } +TEST_F(TestSmartFieldRef, update_field_on_device_check_on_host) +{ + ngpField_->modify_on_host(); + + ASSERT_TRUE(ngpField_->need_sync_to_device()); + + auto sPtr = MakeFieldRef()(*ngpField_); + + double assignmentValue = 300.0; + lambda_loop_assign(*bulk, partVec, sPtr, assignmentValue); + + // Check field values on host using standard bucket loop + // Do it inside brackets so fieldRef will destruct + { + double sum = 0.0; + int counter = 0; + auto* field = fieldManager->get_field_ptr("scalarQ"); + auto fieldRef = sierra::nalu::MakeFieldRef()(*field); + stk::mesh::Selector sel = stk::mesh::selectUnion(partVec); + const auto& buckets = bulk->get_buckets(stk::topology::NODE_RANK, sel); + for (auto b : buckets){ + for( size_t in = 0; in< b->size(); in++){ + auto node = (*b)[in]; + sum += fieldRef(node); + counter++; + } + } + EXPECT_NEAR(assignmentValue*counter, sum, 1e-12); + } + + 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_ + 1, ngpField_->num_syncs_to_host()); +} + } // namespace sierra::nalu From 2c6d12735b0c96bcd5186c31e18b25b8723ae954 Mon Sep 17 00:00:00 2001 From: psakiev Date: Mon, 18 Sep 2023 10:52:57 -0600 Subject: [PATCH 17/40] Add host READ access overloads --- include/ngp_utils/SmartFieldRef.h | 44 ++++++++++++++++-------------- unit_tests/UnitTestSmartFieldRef.C | 2 +- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/include/ngp_utils/SmartFieldRef.h b/include/ngp_utils/SmartFieldRef.h index 69ae4224b..a5fac8e50 100644 --- a/include/ngp_utils/SmartFieldRef.h +++ b/include/ngp_utils/SmartFieldRef.h @@ -138,16 +138,30 @@ class SmartFieldRef } } - // 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 - inline - T& get(const stk::mesh::Entity& entity) const + template + const typename std::enable_if_t::value, T>& + get(const stk::mesh::Entity& entity) const + { + return *stk::mesh::field_data(fieldRef_, entity); + } + + template + const typename std::enable_if_t::value, T>& + operator()(const stk::mesh::Entity& entity) const + { + return *stk::mesh::field_data(fieldRef_, entity); + } + + template + typename std::enable_if_t::value, T>& + get(const stk::mesh::Entity& entity) const { return *stk::mesh::field_data(fieldRef_, entity); } - inline - T& operator()(const stk::mesh::Entity& entity) const + template + typename std::enable_if_t::value, T>& + operator()(const stk::mesh::Entity& entity) const { return *stk::mesh::field_data(fieldRef_, entity); } @@ -170,25 +184,13 @@ class SmartFieldRef }; template -struct MakeFieldRef{}; - -template -struct MakeFieldRef -{ +struct MakeFieldRef{ template - SmartFieldRef operator()(stk::mesh::Field& field){ - return SmartFieldRef(field); + SmartFieldRef operator()(T& field){ + return SmartFieldRef(field); } }; -template -struct MakeFieldRef -{ - template - SmartFieldRef operator()(stk::mesh::NgpField& field){ - return SmartFieldRef(field); - } -}; } // namespace sierra::nalu #endif diff --git a/unit_tests/UnitTestSmartFieldRef.C b/unit_tests/UnitTestSmartFieldRef.C index be4820699..e137de3ba 100644 --- a/unit_tests/UnitTestSmartFieldRef.C +++ b/unit_tests/UnitTestSmartFieldRef.C @@ -135,7 +135,7 @@ TEST_F(TestSmartFieldRef, update_field_on_device_check_on_host) for (auto b : buckets){ for( size_t in = 0; in< b->size(); in++){ auto node = (*b)[in]; - sum += fieldRef(node); + sum += fieldRef.get(node); counter++; } } From d25fa685941a1931afe1803f092d2eef93d63677 Mon Sep 17 00:00:00 2001 From: psakiev Date: Mon, 18 Sep 2023 11:10:43 -0600 Subject: [PATCH 18/40] Format --- include/ngp_utils/SmartFieldRef.h | 53 +++++++++++++++++++----------- unit_tests/UnitTestSmartFieldRef.C | 34 ++++++++++--------- 2 files changed, 51 insertions(+), 36 deletions(-) diff --git a/include/ngp_utils/SmartFieldRef.h b/include/ngp_utils/SmartFieldRef.h index a5fac8e50..8baedc067 100644 --- a/include/ngp_utils/SmartFieldRef.h +++ b/include/ngp_utils/SmartFieldRef.h @@ -13,16 +13,26 @@ #include #include -namespace tags{ +namespace tags { //clang-format off -struct READ{}; -struct WRITE{}; -struct READ_WRITE{}; +struct READ +{ +}; +struct WRITE +{ +}; +struct READ_WRITE +{ +}; -struct HOST{}; -struct DEVICE{}; +struct HOST +{ +}; +struct DEVICE +{ +}; //clang-format on -} +} // namespace tags namespace sierra::nalu { @@ -83,7 +93,8 @@ class SmartFieldRef } template - KOKKOS_INLINE_FUNCTION T& operator()(const MeshIndex index, int component) const + KOKKOS_INLINE_FUNCTION T& + operator()(const MeshIndex index, int component) const { return fieldRef_.operator()(index, component); } @@ -138,30 +149,30 @@ class SmartFieldRef } } - template + template const typename std::enable_if_t::value, T>& - get(const stk::mesh::Entity& entity) const + get(const stk::mesh::Entity& entity) const { return *stk::mesh::field_data(fieldRef_, entity); } - template + template const typename std::enable_if_t::value, T>& - operator()(const stk::mesh::Entity& entity) const + operator()(const stk::mesh::Entity& entity) const { return *stk::mesh::field_data(fieldRef_, entity); } - template + template typename std::enable_if_t::value, T>& - get(const stk::mesh::Entity& entity) const + get(const stk::mesh::Entity& entity) const { return *stk::mesh::field_data(fieldRef_, entity); } - template + template typename std::enable_if_t::value, T>& - operator()(const stk::mesh::Entity& entity) const + operator()(const stk::mesh::Entity& entity) const { return *stk::mesh::field_data(fieldRef_, entity); } @@ -183,10 +194,12 @@ class SmartFieldRef const bool is_copy_constructed_{false}; }; -template -struct MakeFieldRef{ - template - SmartFieldRef operator()(T& field){ +template +struct MakeFieldRef +{ + template + SmartFieldRef operator()(T& field) + { return SmartFieldRef(field); } }; diff --git a/unit_tests/UnitTestSmartFieldRef.C b/unit_tests/UnitTestSmartFieldRef.C index e137de3ba..82003bd22 100644 --- a/unit_tests/UnitTestSmartFieldRef.C +++ b/unit_tests/UnitTestSmartFieldRef.C @@ -45,19 +45,20 @@ lambda_ordinal(T& ptr) } template -void lambda_loop_assign(stk::mesh::BulkData& bulk, stk::mesh::PartVector partVec, T& ptr, double val = 300.0) +void +lambda_loop_assign( + stk::mesh::BulkData& bulk, + stk::mesh::PartVector partVec, + T& ptr, + double val = 300.0) { stk::mesh::NgpMesh& ngpMesh = stk::mesh::get_updated_ngp_mesh(bulk); stk::mesh::Selector sel = stk::mesh::selectUnion(partVec); stk::mesh::for_each_entity_run( - ngpMesh, - stk::topology::NODE_RANK, - sel, - KOKKOS_LAMBDA(const stk::mesh::FastMeshIndex& entity){ + ngpMesh, stk::topology::NODE_RANK, sel, + KOKKOS_LAMBDA(const stk::mesh::FastMeshIndex& entity) { ptr(entity, 0) = val; - } - ); - + }); } //***************************************************************************** @@ -129,17 +130,18 @@ TEST_F(TestSmartFieldRef, update_field_on_device_check_on_host) double sum = 0.0; int counter = 0; auto* field = fieldManager->get_field_ptr("scalarQ"); - auto fieldRef = sierra::nalu::MakeFieldRef()(*field); + auto fieldRef = + sierra::nalu::MakeFieldRef()(*field); stk::mesh::Selector sel = stk::mesh::selectUnion(partVec); const auto& buckets = bulk->get_buckets(stk::topology::NODE_RANK, sel); - for (auto b : buckets){ - for( size_t in = 0; in< b->size(); in++){ - auto node = (*b)[in]; - sum += fieldRef.get(node); - counter++; - } + for (auto b : buckets) { + for (size_t in = 0; in < b->size(); in++) { + auto node = (*b)[in]; + sum += fieldRef.get(node); + counter++; + } } - EXPECT_NEAR(assignmentValue*counter, sum, 1e-12); + EXPECT_NEAR(assignmentValue * counter, sum, 1e-12); } EXPECT_FALSE(ngpField_->need_sync_to_device()); From bfc6678eff1b53ab5b8b183350cc64dff1a88c39 Mon Sep 17 00:00:00 2001 From: psakiev Date: Mon, 18 Sep 2023 15:21:38 -0600 Subject: [PATCH 19/40] Refactor for three different MEMSPACE's --- include/ngp_utils/SmartFieldRef.h | 320 +++++++++++++++++++---------- unit_tests/UnitTestSmartFieldRef.C | 3 +- 2 files changed, 218 insertions(+), 105 deletions(-) diff --git a/include/ngp_utils/SmartFieldRef.h b/include/ngp_utils/SmartFieldRef.h index 8baedc067..fb75e8c0e 100644 --- a/include/ngp_utils/SmartFieldRef.h +++ b/include/ngp_utils/SmartFieldRef.h @@ -14,193 +14,307 @@ #include namespace tags { -//clang-format off -struct READ -{ -}; -struct WRITE -{ -}; -struct READ_WRITE -{ -}; +// clang-format off -struct HOST -{ -}; -struct DEVICE -{ -}; -//clang-format on +//ACCESS TYPES +struct READ{}; +struct WRITE{}; +struct READ_WRITE{}; + +// MEMSPACE +struct HOST{}; +struct DEVICE{}; +struct LEGACY{}; + +// clang-format on } // namespace tags namespace sierra::nalu { using namespace tags; -template +template class SmartFieldRef +{}; + +template +class SmartFieldRef::value>> { +public: + using T = typename FieldType::value_type; + + SmartFieldRef(FieldType& fieldRef) : fieldRef_(fieldRef) {} + SmartFieldRef(const SmartFieldRef& src) + : fieldRef_(src.fieldRef_) + { + if (is_read_){ + fieldRef_.sync_to_host(); + } + else{ + fieldRef_.clear_sync_state(); + } + } + // --- Default Accessors + template + typename std::enable_if_t::value, T>& + get(const stk::mesh::Entity& entity) const + { + return *stk::mesh::field_data(fieldRef_, entity); + } + + template + typename std::enable_if_t::value, T>& + operator()(const stk::mesh::Entity& entity) const + { + return *stk::mesh::field_data(fieldRef_, entity); + } + + // --- Const Accessors + template + const typename std::enable_if_t::value, T>& + get(const stk::mesh::Entity& entity) const + { + return *stk::mesh::field_data(fieldRef_, entity); + } + + template + const typename std::enable_if_t::value, T>& + operator()(const stk::mesh::Entity& entity) const + { + return *stk::mesh::field_data(fieldRef_, entity); + } + + + ~SmartFieldRef() + { + if (is_write_) { + fieldRef_.modify_on_host(); + } + } +private: + static constexpr bool is_read_ + { + std::is_same::value || + std::is_same::value + }; + + static constexpr bool is_write_ + { + std::is_same::value || + std::is_same::value + }; + + FieldType& fieldRef_; }; -template -class SmartFieldRef +template +class SmartFieldRef::value>> { public: - SmartFieldRef(stk::mesh::NgpField& ngpField) : fieldRef_(ngpField) {} + using T = typename FieldType::value_type; + + SmartFieldRef(FieldType fieldRef) : fieldRef_(fieldRef) {} SmartFieldRef(const SmartFieldRef& src) : fieldRef_(src.fieldRef_), is_copy_constructed_(true) { - if (is_read()) - fieldRef_.sync_to_device(); - else + if (is_read_){ + if(is_device_space){ + fieldRef_.sync_to_device(); + } + else{ + fieldRef_.sync_to_host(); + } + } + 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(); + if (is_write_) { + if(is_copy_constructed_){ + // 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. + fieldRef_.modify_on_device(); + } + else{ + // try not requiring copy mechanism for host + fieldRef_.modify_on_host(); + } } } - KOKKOS_INLINE_FUNCTION - unsigned get_ordinal() const { return fieldRef_.get_ordinal(); } + //************************************************************ + // Host functions (Remove KOKKOS_FUNCTION decorators) + //************************************************************ + template + std::enable_if_t::value, 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_INLINE_FUNCTION - T& get(stk::mesh::FastMeshIndex& index, int component) const + // --- Default Accessors + template + std::enable_if_t::value && !std::is_same::value, T>& + get(stk::mesh::FastMeshIndex& index, int component) const { return fieldRef_.get(index, component); } - template - KOKKOS_INLINE_FUNCTION T& get(MeshIndex index, int component) const + template + std::enable_if_t::value && !std::is_same::value, T>& + get(MeshIndex index, int component) const { return fieldRef_.get(index, component); } - KOKKOS_INLINE_FUNCTION - T& operator()(const stk::mesh::FastMeshIndex& index, int component) const + template + std::enable_if_t::value && !std::is_same::value, T>& + operator()(const stk::mesh::FastMeshIndex& index, int component) const { return fieldRef_.get(index, component); } - template - KOKKOS_INLINE_FUNCTION T& + template + std::enable_if_t::value && !std::is_same::value, T>& operator()(const MeshIndex index, int component) const { return fieldRef_.operator()(index, component); } -private: - bool is_read() + // --- Const Accessors + template + const std::enable_if_t::value && std::is_same::value, T>& + get(stk::mesh::FastMeshIndex& index, int component) const { - return std::is_same::value || - std::is_same::value; + return fieldRef_.get(index, component); } - bool is_write() + template + const std::enable_if_t::value && std::is_same::value, T>& + get(MeshIndex index, int component) const { - return std::is_same::value || - std::is_same::value; + return fieldRef_.get(index, component); } - stk::mesh::NgpField& fieldRef_; - const bool is_copy_constructed_{false}; -}; + template + const std::enable_if_t::value && std::is_same::value, T>& + operator()(const stk::mesh::FastMeshIndex& index, int component) const + { + return fieldRef_.get(index, component); + } -// HOST specialization using legacy bucket loops -// TODO would we ever/can we use stk::mesh::HostField's inside a device enabled -// build? -// If so I think we should change this to LEGACY instead of HOST -template -class SmartFieldRef -{ -public: - SmartFieldRef(stk::mesh::Field& field) : fieldRef_(field) + template + const std::enable_if_t::value && std::is_same::value, T>& + operator()(const MeshIndex index, int component) const { - if (is_read()) - fieldRef_.sync_to_host(); - else - fieldRef_.clear_sync_state(); + return fieldRef_.operator()(index, component); } + //************************************************************ + // Device functions + //************************************************************ + KOKKOS_FUNCTION + template + std::enable_if_t::value, unsigned> + get_ordinal() const { return fieldRef_.get_ordinal(); } - SmartFieldRef(const SmartFieldRef& src) - : fieldRef_(src.fieldRef_), is_copy_constructed_(true) + // --- Default Accessors + KOKKOS_FUNCTION + template + std::enable_if_t::value && !std::is_same::value, T>& + get(stk::mesh::FastMeshIndex& index, int component) const { - if (is_read()) - fieldRef_.sync_to_host(); - else - fieldRef_.clear_sync_state(); + return fieldRef_.get(index, component); } - // try removing the copy constructor requirement for host fields - ~SmartFieldRef() + KOKKOS_FUNCTION + template + std::enable_if_t::value && !std::is_same::value, T>& + get(MeshIndex index, int component) const { - if (is_write()) { - fieldRef_.modify_on_host(); - } + return fieldRef_.get(index, component); } - template - const typename std::enable_if_t::value, T>& - get(const stk::mesh::Entity& entity) const + KOKKOS_FUNCTION + template + std::enable_if_t::value && !std::is_same::value, T>& + operator()(const stk::mesh::FastMeshIndex& index, int component) const { - return *stk::mesh::field_data(fieldRef_, entity); + return fieldRef_.get(index, component); } - template - const typename std::enable_if_t::value, T>& - operator()(const stk::mesh::Entity& entity) const + KOKKOS_FUNCTION + template + std::enable_if_t::value && !std::is_same::value, T>& + operator()(const MeshIndex index, int component) const { - return *stk::mesh::field_data(fieldRef_, entity); + return fieldRef_.operator()(index, component); } - template - typename std::enable_if_t::value, T>& - get(const stk::mesh::Entity& entity) const + // --- Const Accessors + KOKKOS_FUNCTION + template + const std::enable_if_t::value && std::is_same::value, T>& + get(stk::mesh::FastMeshIndex& index, int component) const { - return *stk::mesh::field_data(fieldRef_, entity); + return fieldRef_.get(index, component); } - template - typename std::enable_if_t::value, T>& - operator()(const stk::mesh::Entity& entity) const + KOKKOS_FUNCTION + template + const std::enable_if_t::value && std::is_same::value, T>& + get(MeshIndex index, int component) const { - return *stk::mesh::field_data(fieldRef_, entity); + return fieldRef_.get(index, component); } -private: - bool is_read() + KOKKOS_FUNCTION + template + const std::enable_if_t::value && std::is_same::value, T>& + operator()(const stk::mesh::FastMeshIndex& index, int component) const { - return std::is_same::value || - std::is_same::value; + return fieldRef_.get(index, component); } - bool is_write() + KOKKOS_FUNCTION + template + const std::enable_if_t::value && std::is_same::value, T>& + operator()(const MeshIndex index, int component) const { - return std::is_same::value || - std::is_same::value; + return fieldRef_.operator()(index, component); } - stk::mesh::Field& fieldRef_; +private: + static constexpr bool is_device_space + { + std::is_same::value + }; + + static constexpr bool is_read_ + { + std::is_same::value || + std::is_same::value + }; + + static constexpr bool is_write_ + { + std::is_same::value || + std::is_same::value + }; + + FieldType fieldRef_; const bool is_copy_constructed_{false}; }; template struct MakeFieldRef { - template - SmartFieldRef operator()(T& field) + template + SmartFieldRef operator()(FieldType& field) { - return SmartFieldRef(field); + return SmartFieldRef(field); } }; diff --git a/unit_tests/UnitTestSmartFieldRef.C b/unit_tests/UnitTestSmartFieldRef.C index 82003bd22..f6ac9bdf6 100644 --- a/unit_tests/UnitTestSmartFieldRef.C +++ b/unit_tests/UnitTestSmartFieldRef.C @@ -73,7 +73,6 @@ TEST_F(TestSmartFieldRef, device_read_write_mod_sync_with_lambda) ASSERT_TRUE(ngpField_->need_sync_to_device()); - // TODO can we get rid of the double template param some how? auto sPtr = MakeFieldRef()(*ngpField_); lambda_ordinal(sPtr); @@ -131,7 +130,7 @@ TEST_F(TestSmartFieldRef, update_field_on_device_check_on_host) int counter = 0; auto* field = fieldManager->get_field_ptr("scalarQ"); auto fieldRef = - sierra::nalu::MakeFieldRef()(*field); + sierra::nalu::MakeFieldRef()(*field); stk::mesh::Selector sel = stk::mesh::selectUnion(partVec); const auto& buckets = bulk->get_buckets(stk::topology::NODE_RANK, sel); for (auto b : buckets) { From a4ad40ebcb3fdfb90a1aac33cf786d067aaf69c2 Mon Sep 17 00:00:00 2001 From: psakiev Date: Mon, 18 Sep 2023 15:25:18 -0600 Subject: [PATCH 20/40] Update some comments --- include/ngp_utils/SmartFieldRef.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/ngp_utils/SmartFieldRef.h b/include/ngp_utils/SmartFieldRef.h index fb75e8c0e..74326cc94 100644 --- a/include/ngp_utils/SmartFieldRef.h +++ b/include/ngp_utils/SmartFieldRef.h @@ -88,6 +88,10 @@ class SmartFieldRef Date: Mon, 18 Sep 2023 15:27:24 -0600 Subject: [PATCH 21/40] Style --- include/ngp_utils/SmartFieldRef.h | 203 +++++++++++++++++------------- 1 file changed, 119 insertions(+), 84 deletions(-) diff --git a/include/ngp_utils/SmartFieldRef.h b/include/ngp_utils/SmartFieldRef.h index 74326cc94..bd0b0f6c9 100644 --- a/include/ngp_utils/SmartFieldRef.h +++ b/include/ngp_utils/SmartFieldRef.h @@ -33,24 +33,32 @@ namespace sierra::nalu { using namespace tags; -template +template < + typename FieldType, + typename MEMSPACE, + typename ACCESS, + typename Enable = void> class SmartFieldRef -{}; +{ +}; template -class SmartFieldRef::value>> +class SmartFieldRef< + FieldType, + LEGACY, + ACCESS, + typename std::enable_if_t< + std::is_base_of::value>> { public: using T = typename FieldType::value_type; SmartFieldRef(FieldType& fieldRef) : fieldRef_(fieldRef) {} - SmartFieldRef(const SmartFieldRef& src) - : fieldRef_(src.fieldRef_) + SmartFieldRef(const SmartFieldRef& src) : fieldRef_(src.fieldRef_) { - if (is_read_){ + if (is_read_) { fieldRef_.sync_to_host(); - } - else{ + } else { fieldRef_.clear_sync_state(); } } @@ -84,7 +92,6 @@ class SmartFieldRef::value || - std::is_same::value - }; + static constexpr bool is_read_{ + std::is_same::value || + std::is_same::value}; - static constexpr bool is_write_ - { - std::is_same::value || - std::is_same::value - }; + static constexpr bool is_write_{ + std::is_same::value || + std::is_same::value}; FieldType& fieldRef_; }; template -class SmartFieldRef::value>> +class SmartFieldRef< + FieldType, + MEMSPACE, + ACCESS, + typename std::enable_if_t< + std::is_base_of::value>> { public: using T = typename FieldType::value_type; @@ -122,15 +131,13 @@ class SmartFieldRef - std::enable_if_t::value, unsigned> - get_ordinal() const { return fieldRef_.get_ordinal(); } + template + std::enable_if_t::value, unsigned> get_ordinal() const + { + return fieldRef_.get_ordinal(); + } // --- Default Accessors - template - std::enable_if_t::value && !std::is_same::value, T>& + template + std::enable_if_t< + std::is_same::value && !std::is_same::value, + T>& get(stk::mesh::FastMeshIndex& index, int component) const { return fieldRef_.get(index, component); } - template - std::enable_if_t::value && !std::is_same::value, T>& + template + std::enable_if_t< + std::is_same::value && !std::is_same::value, + T>& get(MeshIndex index, int component) const { return fieldRef_.get(index, component); } - template - std::enable_if_t::value && !std::is_same::value, T>& + template + std::enable_if_t< + std::is_same::value && !std::is_same::value, + T>& operator()(const stk::mesh::FastMeshIndex& index, int component) const { return fieldRef_.get(index, component); } - template - std::enable_if_t::value && !std::is_same::value, T>& + template + std::enable_if_t< + std::is_same::value && !std::is_same::value, + T>& operator()(const MeshIndex index, int component) const { return fieldRef_.operator()(index, component); } // --- Const Accessors - template - const std::enable_if_t::value && std::is_same::value, T>& + template + const std::enable_if_t< + std::is_same::value && std::is_same::value, + T>& get(stk::mesh::FastMeshIndex& index, int component) const { return fieldRef_.get(index, component); } - template - const std::enable_if_t::value && std::is_same::value, T>& + template + const std::enable_if_t< + std::is_same::value && std::is_same::value, + T>& get(MeshIndex index, int component) const { return fieldRef_.get(index, component); } - template - const std::enable_if_t::value && std::is_same::value, T>& + template + const std::enable_if_t< + std::is_same::value && std::is_same::value, + T>& operator()(const stk::mesh::FastMeshIndex& index, int component) const { return fieldRef_.get(index, component); } - template - const std::enable_if_t::value && std::is_same::value, T>& + template + const std::enable_if_t< + std::is_same::value && std::is_same::value, + T>& operator()(const MeshIndex index, int component) const { return fieldRef_.operator()(index, component); @@ -220,38 +244,48 @@ class SmartFieldRef - std::enable_if_t::value, unsigned> - get_ordinal() const { return fieldRef_.get_ordinal(); } + template + std::enable_if_t::value, unsigned> get_ordinal() const + { + return fieldRef_.get_ordinal(); + } // --- Default Accessors KOKKOS_FUNCTION - template - std::enable_if_t::value && !std::is_same::value, T>& + template + std::enable_if_t< + std::is_same::value && !std::is_same::value, + T>& get(stk::mesh::FastMeshIndex& index, int component) const { return fieldRef_.get(index, component); } KOKKOS_FUNCTION - template - std::enable_if_t::value && !std::is_same::value, T>& + template + std::enable_if_t< + std::is_same::value && !std::is_same::value, + T>& get(MeshIndex index, int component) const { return fieldRef_.get(index, component); } KOKKOS_FUNCTION - template - std::enable_if_t::value && !std::is_same::value, T>& + template + std::enable_if_t< + std::is_same::value && !std::is_same::value, + T>& operator()(const stk::mesh::FastMeshIndex& index, int component) const { return fieldRef_.get(index, component); } KOKKOS_FUNCTION - template - std::enable_if_t::value && !std::is_same::value, T>& + template + std::enable_if_t< + std::is_same::value && !std::is_same::value, + T>& operator()(const MeshIndex index, int component) const { return fieldRef_.operator()(index, component); @@ -259,54 +293,55 @@ class SmartFieldRef - const std::enable_if_t::value && std::is_same::value, T>& + template + const std::enable_if_t< + std::is_same::value && std::is_same::value, + T>& get(stk::mesh::FastMeshIndex& index, int component) const { return fieldRef_.get(index, component); } KOKKOS_FUNCTION - template - const std::enable_if_t::value && std::is_same::value, T>& + template + const std::enable_if_t< + std::is_same::value && std::is_same::value, + T>& get(MeshIndex index, int component) const { return fieldRef_.get(index, component); } KOKKOS_FUNCTION - template - const std::enable_if_t::value && std::is_same::value, T>& + template + const std::enable_if_t< + std::is_same::value && std::is_same::value, + T>& operator()(const stk::mesh::FastMeshIndex& index, int component) const { return fieldRef_.get(index, component); } KOKKOS_FUNCTION - template - const std::enable_if_t::value && std::is_same::value, T>& + template + const std::enable_if_t< + std::is_same::value && std::is_same::value, + T>& operator()(const MeshIndex index, int component) const { return fieldRef_.operator()(index, component); } private: - static constexpr bool is_device_space - { - std::is_same::value - }; + static constexpr bool is_device_space{std::is_same::value}; - static constexpr bool is_read_ - { - std::is_same::value || - std::is_same::value - }; + static constexpr bool is_read_{ + std::is_same::value || + std::is_same::value}; - static constexpr bool is_write_ - { - std::is_same::value || - std::is_same::value - }; + static constexpr bool is_write_{ + std::is_same::value || + std::is_same::value}; FieldType fieldRef_; const bool is_copy_constructed_{false}; From f579c4c618cb4512e4c23d07de02d0f616445707 Mon Sep 17 00:00:00 2001 From: Philip Sakievich Date: Mon, 18 Sep 2023 17:29:53 -0600 Subject: [PATCH 22/40] Passing device tests --- include/ngp_utils/SmartFieldRef.h | 117 +++++++++++++++--------------- 1 file changed, 58 insertions(+), 59 deletions(-) diff --git a/include/ngp_utils/SmartFieldRef.h b/include/ngp_utils/SmartFieldRef.h index bd0b0f6c9..9ba01dd00 100644 --- a/include/ngp_utils/SmartFieldRef.h +++ b/include/ngp_utils/SmartFieldRef.h @@ -50,17 +50,34 @@ class SmartFieldRef< typename std::enable_if_t< std::is_base_of::value>> { + +private: + static constexpr bool is_read_{ + std::is_same::value || + std::is_same::value}; + + static constexpr bool is_write_{ + std::is_same::value || + std::is_same::value}; + + FieldType& fieldRef_; + public: using T = typename FieldType::value_type; - SmartFieldRef(FieldType& fieldRef) : fieldRef_(fieldRef) {} + SmartFieldRef(FieldType& fieldRef) : fieldRef_(fieldRef) { + if (is_read_) + fieldRef_.sync_to_host(); + else + fieldRef_.clear_sync_state(); + } + SmartFieldRef(const SmartFieldRef& src) : fieldRef_(src.fieldRef_) { - if (is_read_) { + if (is_read_) fieldRef_.sync_to_host(); - } else { + else fieldRef_.clear_sync_state(); - } } // --- Default Accessors template @@ -102,8 +119,19 @@ class SmartFieldRef< fieldRef_.modify_on_host(); } } +}; +template +class SmartFieldRef< + FieldType, + MEMSPACE, + ACCESS, + typename std::enable_if_t< + std::is_base_of::value>> +{ private: + static constexpr bool is_device_space_{std::is_same::value}; + static constexpr bool is_read_{ std::is_same::value || std::is_same::value}; @@ -112,17 +140,9 @@ class SmartFieldRef< std::is_same::value || std::is_same::value}; - FieldType& fieldRef_; -}; + FieldType fieldRef_; + const bool is_copy_constructed_{false}; -template -class SmartFieldRef< - FieldType, - MEMSPACE, - ACCESS, - typename std::enable_if_t< - std::is_base_of::value>> -{ public: using T = typename FieldType::value_type; @@ -132,7 +152,7 @@ class SmartFieldRef< : fieldRef_(src.fieldRef_), is_copy_constructed_(true) { if (is_read_) { - if (is_device_space) { + if (is_device_space_) { fieldRef_.sync_to_device(); } else { fieldRef_.sync_to_host(); @@ -150,10 +170,10 @@ class SmartFieldRef< // 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. - fieldRef_.modify_on_device(); - } else { - // try not requiring copy mechanism for host - fieldRef_.modify_on_host(); + if (is_device_space_) + fieldRef_.modify_on_device(); + else + fieldRef_.modify_on_host(); } } } @@ -192,7 +212,7 @@ class SmartFieldRef< T>& operator()(const stk::mesh::FastMeshIndex& index, int component) const { - return fieldRef_.get(index, component); + return fieldRef_(index, component); } template @@ -201,7 +221,7 @@ class SmartFieldRef< T>& operator()(const MeshIndex index, int component) const { - return fieldRef_.operator()(index, component); + return fieldRef_(index, component); } // --- Const Accessors @@ -229,7 +249,7 @@ class SmartFieldRef< T>& operator()(const stk::mesh::FastMeshIndex& index, int component) const { - return fieldRef_.get(index, component); + return fieldRef_(index, component); } template @@ -238,22 +258,22 @@ class SmartFieldRef< T>& operator()(const MeshIndex index, int component) const { - return fieldRef_.operator()(index, component); + return fieldRef_(index, component); } + //************************************************************ // Device functions //************************************************************ - KOKKOS_FUNCTION template - std::enable_if_t::value, unsigned> get_ordinal() const + KOKKOS_FUNCTION std::enable_if_t::value, unsigned> + get_ordinal() const { return fieldRef_.get_ordinal(); } // --- Default Accessors - KOKKOS_FUNCTION template - std::enable_if_t< + KOKKOS_FUNCTION std::enable_if_t< std::is_same::value && !std::is_same::value, T>& get(stk::mesh::FastMeshIndex& index, int component) const @@ -261,9 +281,8 @@ class SmartFieldRef< return fieldRef_.get(index, component); } - KOKKOS_FUNCTION template - std::enable_if_t< + KOKKOS_FUNCTION std::enable_if_t< std::is_same::value && !std::is_same::value, T>& get(MeshIndex index, int component) const @@ -271,30 +290,27 @@ class SmartFieldRef< return fieldRef_.get(index, component); } - KOKKOS_FUNCTION template - std::enable_if_t< + KOKKOS_FUNCTION std::enable_if_t< std::is_same::value && !std::is_same::value, T>& operator()(const stk::mesh::FastMeshIndex& index, int component) const { - return fieldRef_.get(index, component); + return fieldRef_(index, component); } - KOKKOS_FUNCTION template - std::enable_if_t< + KOKKOS_FUNCTION std::enable_if_t< std::is_same::value && !std::is_same::value, T>& operator()(const MeshIndex index, int component) const { - return fieldRef_.operator()(index, component); + return fieldRef_(index, component); } // --- Const Accessors - KOKKOS_FUNCTION template - const std::enable_if_t< + KOKKOS_FUNCTION const std::enable_if_t< std::is_same::value && std::is_same::value, T>& get(stk::mesh::FastMeshIndex& index, int component) const @@ -302,9 +318,8 @@ class SmartFieldRef< return fieldRef_.get(index, component); } - KOKKOS_FUNCTION template - const std::enable_if_t< + KOKKOS_FUNCTION const std::enable_if_t< std::is_same::value && std::is_same::value, T>& get(MeshIndex index, int component) const @@ -312,39 +327,23 @@ class SmartFieldRef< return fieldRef_.get(index, component); } - KOKKOS_FUNCTION template - const std::enable_if_t< + KOKKOS_FUNCTION const std::enable_if_t< std::is_same::value && std::is_same::value, T>& operator()(const stk::mesh::FastMeshIndex& index, int component) const { - return fieldRef_.get(index, component); + return fieldRef_(index, component); } - KOKKOS_FUNCTION template - const std::enable_if_t< + KOKKOS_FUNCTION const std::enable_if_t< std::is_same::value && std::is_same::value, T>& operator()(const MeshIndex index, int component) const { - return fieldRef_.operator()(index, component); + return fieldRef_(index, component); } - -private: - static constexpr bool is_device_space{std::is_same::value}; - - static constexpr bool is_read_{ - std::is_same::value || - std::is_same::value}; - - static constexpr bool is_write_{ - std::is_same::value || - std::is_same::value}; - - FieldType fieldRef_; - const bool is_copy_constructed_{false}; }; template From be477fc3710ff251cf4e14f612b3a467d669e2af Mon Sep 17 00:00:00 2001 From: Philip Sakievich Date: Mon, 18 Sep 2023 17:33:29 -0600 Subject: [PATCH 23/40] Style --- include/ngp_utils/SmartFieldRef.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/ngp_utils/SmartFieldRef.h b/include/ngp_utils/SmartFieldRef.h index 9ba01dd00..2075b73d5 100644 --- a/include/ngp_utils/SmartFieldRef.h +++ b/include/ngp_utils/SmartFieldRef.h @@ -65,7 +65,8 @@ class SmartFieldRef< public: using T = typename FieldType::value_type; - SmartFieldRef(FieldType& fieldRef) : fieldRef_(fieldRef) { + SmartFieldRef(FieldType& fieldRef) : fieldRef_(fieldRef) + { if (is_read_) fieldRef_.sync_to_host(); else @@ -79,6 +80,7 @@ class SmartFieldRef< else fieldRef_.clear_sync_state(); } + // --- Default Accessors template typename std::enable_if_t::value, T>& From 6fd30a84d208dec46a28dcc6fc5a080dd2a6255e Mon Sep 17 00:00:00 2001 From: Philip Sakievich Date: Mon, 18 Sep 2023 20:42:09 -0600 Subject: [PATCH 24/40] Rename to SmartField and add explicit instantiation --- .../SmartFieldRef.h => SmartField.h} | 98 +++++++++---------- src/CMakeLists.txt | 1 + src/SmartField.C | 26 +++++ unit_tests/CMakeLists.txt | 2 +- ...stSmartFieldRef.C => UnitTestSmartField.C} | 22 ++--- 5 files changed, 88 insertions(+), 61 deletions(-) rename include/{ngp_utils/SmartFieldRef.h => SmartField.h} (80%) create mode 100644 src/SmartField.C rename unit_tests/{UnitTestSmartFieldRef.C => UnitTestSmartField.C} (86%) diff --git a/include/ngp_utils/SmartFieldRef.h b/include/SmartField.h similarity index 80% rename from include/ngp_utils/SmartFieldRef.h rename to include/SmartField.h index 2075b73d5..d422afd6f 100644 --- a/include/ngp_utils/SmartFieldRef.h +++ b/include/SmartField.h @@ -7,8 +7,8 @@ // for more details. // -#ifndef SMARTFIELDREF_H -#define SMARTFIELDREF_H +#ifndef SMARTFIELD_H +#define SMARTFIELD_H #include #include #include @@ -38,12 +38,12 @@ template < typename MEMSPACE, typename ACCESS, typename Enable = void> -class SmartFieldRef +class SmartField { }; template -class SmartFieldRef< +class SmartField< FieldType, LEGACY, ACCESS, @@ -60,25 +60,25 @@ class SmartFieldRef< std::is_same::value || std::is_same::value}; - FieldType& fieldRef_; + FieldType& stkField_; public: using T = typename FieldType::value_type; - SmartFieldRef(FieldType& fieldRef) : fieldRef_(fieldRef) + SmartField(FieldType& fieldRef) : stkField_(fieldRef) { if (is_read_) - fieldRef_.sync_to_host(); + stkField_.sync_to_host(); else - fieldRef_.clear_sync_state(); + stkField_.clear_sync_state(); } - SmartFieldRef(const SmartFieldRef& src) : fieldRef_(src.fieldRef_) + SmartField(const SmartField& src) : stkField_(src.stkField_) { if (is_read_) - fieldRef_.sync_to_host(); + stkField_.sync_to_host(); else - fieldRef_.clear_sync_state(); + stkField_.clear_sync_state(); } // --- Default Accessors @@ -86,14 +86,14 @@ class SmartFieldRef< typename std::enable_if_t::value, T>& get(const stk::mesh::Entity& entity) const { - return *stk::mesh::field_data(fieldRef_, entity); + return *stk::mesh::field_data(stkField_, entity); } template typename std::enable_if_t::value, T>& operator()(const stk::mesh::Entity& entity) const { - return *stk::mesh::field_data(fieldRef_, entity); + return *stk::mesh::field_data(stkField_, entity); } // --- Const Accessors @@ -101,30 +101,30 @@ class SmartFieldRef< const typename std::enable_if_t::value, T>& get(const stk::mesh::Entity& entity) const { - return *stk::mesh::field_data(fieldRef_, entity); + return *stk::mesh::field_data(stkField_, entity); } template const typename std::enable_if_t::value, T>& operator()(const stk::mesh::Entity& entity) const { - return *stk::mesh::field_data(fieldRef_, entity); + return *stk::mesh::field_data(stkField_, entity); } - ~SmartFieldRef() + ~SmartField() { if (is_write_) { // LEGACY implementation needs to be used in a limited scope. // Redundant usage is fine since sync's and mod's will be no-ops // but long lived cases like alg class members will negate the // purpose of this abstraction - fieldRef_.modify_on_host(); + stkField_.modify_on_host(); } } }; template -class SmartFieldRef< +class SmartField< FieldType, MEMSPACE, ACCESS, @@ -142,29 +142,29 @@ class SmartFieldRef< std::is_same::value || std::is_same::value}; - FieldType fieldRef_; + FieldType stkField_; const bool is_copy_constructed_{false}; public: using T = typename FieldType::value_type; - SmartFieldRef(FieldType fieldRef) : fieldRef_(fieldRef) {} + SmartField(FieldType fieldRef) : stkField_(fieldRef) {} - SmartFieldRef(const SmartFieldRef& src) - : fieldRef_(src.fieldRef_), is_copy_constructed_(true) + SmartField(const SmartField& src) + : stkField_(src.stkField_), is_copy_constructed_(true) { if (is_read_) { if (is_device_space_) { - fieldRef_.sync_to_device(); + stkField_.sync_to_device(); } else { - fieldRef_.sync_to_host(); + stkField_.sync_to_host(); } } else { - fieldRef_.clear_sync_state(); + stkField_.clear_sync_state(); } } - ~SmartFieldRef() + ~SmartField() { if (is_write_) { if (is_copy_constructed_) { @@ -173,9 +173,9 @@ class SmartFieldRef< // only ever need to sync copies that will have been snatched up through // lambda capture. if (is_device_space_) - fieldRef_.modify_on_device(); + stkField_.modify_on_device(); else - fieldRef_.modify_on_host(); + stkField_.modify_on_host(); } } } @@ -186,7 +186,7 @@ class SmartFieldRef< template std::enable_if_t::value, unsigned> get_ordinal() const { - return fieldRef_.get_ordinal(); + return stkField_.get_ordinal(); } // --- Default Accessors @@ -196,7 +196,7 @@ class SmartFieldRef< T>& get(stk::mesh::FastMeshIndex& index, int component) const { - return fieldRef_.get(index, component); + return stkField_.get(index, component); } template @@ -205,7 +205,7 @@ class SmartFieldRef< T>& get(MeshIndex index, int component) const { - return fieldRef_.get(index, component); + return stkField_.get(index, component); } template @@ -214,7 +214,7 @@ class SmartFieldRef< T>& operator()(const stk::mesh::FastMeshIndex& index, int component) const { - return fieldRef_(index, component); + return stkField_(index, component); } template @@ -223,7 +223,7 @@ class SmartFieldRef< T>& operator()(const MeshIndex index, int component) const { - return fieldRef_(index, component); + return stkField_(index, component); } // --- Const Accessors @@ -233,7 +233,7 @@ class SmartFieldRef< T>& get(stk::mesh::FastMeshIndex& index, int component) const { - return fieldRef_.get(index, component); + return stkField_.get(index, component); } template @@ -242,7 +242,7 @@ class SmartFieldRef< T>& get(MeshIndex index, int component) const { - return fieldRef_.get(index, component); + return stkField_.get(index, component); } template @@ -251,7 +251,7 @@ class SmartFieldRef< T>& operator()(const stk::mesh::FastMeshIndex& index, int component) const { - return fieldRef_(index, component); + return stkField_(index, component); } template @@ -260,7 +260,7 @@ class SmartFieldRef< T>& operator()(const MeshIndex index, int component) const { - return fieldRef_(index, component); + return stkField_(index, component); } //************************************************************ @@ -270,7 +270,7 @@ class SmartFieldRef< KOKKOS_FUNCTION std::enable_if_t::value, unsigned> get_ordinal() const { - return fieldRef_.get_ordinal(); + return stkField_.get_ordinal(); } // --- Default Accessors @@ -280,7 +280,7 @@ class SmartFieldRef< T>& get(stk::mesh::FastMeshIndex& index, int component) const { - return fieldRef_.get(index, component); + return stkField_.get(index, component); } template @@ -289,7 +289,7 @@ class SmartFieldRef< T>& get(MeshIndex index, int component) const { - return fieldRef_.get(index, component); + return stkField_.get(index, component); } template @@ -298,7 +298,7 @@ class SmartFieldRef< T>& operator()(const stk::mesh::FastMeshIndex& index, int component) const { - return fieldRef_(index, component); + return stkField_(index, component); } template @@ -307,7 +307,7 @@ class SmartFieldRef< T>& operator()(const MeshIndex index, int component) const { - return fieldRef_(index, component); + return stkField_(index, component); } // --- Const Accessors @@ -317,7 +317,7 @@ class SmartFieldRef< T>& get(stk::mesh::FastMeshIndex& index, int component) const { - return fieldRef_.get(index, component); + return stkField_.get(index, component); } template @@ -326,7 +326,7 @@ class SmartFieldRef< T>& get(MeshIndex index, int component) const { - return fieldRef_.get(index, component); + return stkField_.get(index, component); } template @@ -335,7 +335,7 @@ class SmartFieldRef< T>& operator()(const stk::mesh::FastMeshIndex& index, int component) const { - return fieldRef_(index, component); + return stkField_(index, component); } template @@ -344,17 +344,17 @@ class SmartFieldRef< T>& operator()(const MeshIndex index, int component) const { - return fieldRef_(index, component); + return stkField_(index, component); } }; template -struct MakeFieldRef +struct MakeSmartField { template - SmartFieldRef operator()(FieldType& field) + SmartField operator()(FieldType& field) { - return SmartFieldRef(field); + return SmartField(field); } }; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 737aca74e..1f1b0563d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -79,6 +79,7 @@ target_sources( ${CMAKE_CURRENT_SOURCE_DIR}/ShearStressTransportEquationSystem.C ${CMAKE_CURRENT_SOURCE_DIR}/SideWriter.C ${CMAKE_CURRENT_SOURCE_DIR}/Simulation.C + ${CMAKE_CURRENT_SOURCE_DIR}/SmartField.C ${CMAKE_CURRENT_SOURCE_DIR}/SolutionNormPostProcessing.C ${CMAKE_CURRENT_SOURCE_DIR}/SolutionOptions.C ${CMAKE_CURRENT_SOURCE_DIR}/SolverAlgorithm.C diff --git a/src/SmartField.C b/src/SmartField.C new file mode 100644 index 000000000..3d8b6afd0 --- /dev/null +++ b/src/SmartField.C @@ -0,0 +1,26 @@ +// 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 + +namespace sierra::nalu{ +using namespace tags; + +#define TYPE_INSTANTIATOR_NGP(T) \ + template class SmartField, DEVICE, READ>; \ + template class SmartField, DEVICE, WRITE>; \ + template class SmartField, DEVICE, READ_WRITE>; \ + template class SmartField, HOST, READ>; \ + template class SmartField, HOST, WRITE>; \ + template class SmartField, HOST, READ_WRITE> + +TYPE_INSTANTIATOR_NGP(double); +TYPE_INSTANTIATOR_NGP(int); +TYPE_INSTANTIATOR_NGP(unsigned); +} diff --git a/unit_tests/CMakeLists.txt b/unit_tests/CMakeLists.txt index 25b9948f4..1c19d298a 100644 --- a/unit_tests/CMakeLists.txt +++ b/unit_tests/CMakeLists.txt @@ -27,7 +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}/UnitTestSmartField.C ${CMAKE_CURRENT_SOURCE_DIR}/UnitTestScanningLidarPattern.C ${CMAKE_CURRENT_SOURCE_DIR}/UnitTestScratchViews.C ${CMAKE_CURRENT_SOURCE_DIR}/UnitTestShmemAlignment.C diff --git a/unit_tests/UnitTestSmartFieldRef.C b/unit_tests/UnitTestSmartField.C similarity index 86% rename from unit_tests/UnitTestSmartFieldRef.C rename to unit_tests/UnitTestSmartField.C index f6ac9bdf6..508fd2d31 100644 --- a/unit_tests/UnitTestSmartFieldRef.C +++ b/unit_tests/UnitTestSmartField.C @@ -11,9 +11,9 @@ #include #include "UnitTestUtils.h" #include -#include "ngp_utils/SmartFieldRef.h" +#include "SmartField.h" -class TestSmartFieldRef : public Hex8Mesh +class TestSmartField : public Hex8Mesh { public: protected: @@ -67,13 +67,13 @@ lambda_loop_assign( namespace sierra::nalu { using namespace tags; -TEST_F(TestSmartFieldRef, device_read_write_mod_sync_with_lambda) +TEST_F(TestSmartField, device_read_write_mod_sync_with_lambda) { ngpField_->modify_on_host(); ASSERT_TRUE(ngpField_->need_sync_to_device()); - auto sPtr = MakeFieldRef()(*ngpField_); + auto sPtr = MakeSmartField()(*ngpField_); lambda_ordinal(sPtr); EXPECT_FALSE(ngpField_->need_sync_to_device()); @@ -82,13 +82,13 @@ TEST_F(TestSmartFieldRef, device_read_write_mod_sync_with_lambda) EXPECT_EQ(initSyncsHost_ + 0, ngpField_->num_syncs_to_host()); } -TEST_F(TestSmartFieldRef, device_write_clear_mod_with_lambda) +TEST_F(TestSmartField, device_write_clear_mod_with_lambda) { ngpField_->modify_on_host(); ASSERT_TRUE(ngpField_->need_sync_to_device()); - auto sPtr = MakeFieldRef()(*ngpField_); + auto sPtr = MakeSmartField()(*ngpField_); lambda_ordinal(sPtr); EXPECT_FALSE(ngpField_->need_sync_to_device()); @@ -97,13 +97,13 @@ TEST_F(TestSmartFieldRef, device_write_clear_mod_with_lambda) EXPECT_EQ(initSyncsHost_ + 0, ngpField_->num_syncs_to_host()); } -TEST_F(TestSmartFieldRef, device_read_mod_no_sync_with_lambda) +TEST_F(TestSmartField, device_read_mod_no_sync_with_lambda) { ngpField_->modify_on_host(); ASSERT_TRUE(ngpField_->need_sync_to_device()); - auto sPtr = MakeFieldRef()(*ngpField_); + auto sPtr = MakeSmartField()(*ngpField_); lambda_ordinal(sPtr); EXPECT_FALSE(ngpField_->need_sync_to_device()); @@ -112,13 +112,13 @@ TEST_F(TestSmartFieldRef, device_read_mod_no_sync_with_lambda) EXPECT_EQ(initSyncsHost_ + 0, ngpField_->num_syncs_to_host()); } -TEST_F(TestSmartFieldRef, update_field_on_device_check_on_host) +TEST_F(TestSmartField, update_field_on_device_check_on_host) { ngpField_->modify_on_host(); ASSERT_TRUE(ngpField_->need_sync_to_device()); - auto sPtr = MakeFieldRef()(*ngpField_); + auto sPtr = MakeSmartField()(*ngpField_); double assignmentValue = 300.0; lambda_loop_assign(*bulk, partVec, sPtr, assignmentValue); @@ -130,7 +130,7 @@ TEST_F(TestSmartFieldRef, update_field_on_device_check_on_host) int counter = 0; auto* field = fieldManager->get_field_ptr("scalarQ"); auto fieldRef = - sierra::nalu::MakeFieldRef()(*field); + sierra::nalu::MakeSmartField()(*field); stk::mesh::Selector sel = stk::mesh::selectUnion(partVec); const auto& buckets = bulk->get_buckets(stk::topology::NODE_RANK, sel); for (auto b : buckets) { From 005de2dacdce3256a15a5c2b7ad6efa761d73c3e Mon Sep 17 00:00:00 2001 From: Philip Sakievich Date: Mon, 18 Sep 2023 21:05:04 -0600 Subject: [PATCH 25/40] Code comments and things --- include/SmartField.h | 39 +++++++++++++++++++++++++++++++++++---- src/SmartField.C | 43 +++++++++++++++++++++++++++++++------------ 2 files changed, 66 insertions(+), 16 deletions(-) diff --git a/include/SmartField.h b/include/SmartField.h index d422afd6f..866c5fee2 100644 --- a/include/SmartField.h +++ b/include/SmartField.h @@ -18,7 +18,7 @@ namespace tags { //ACCESS TYPES struct READ{}; -struct WRITE{}; +struct WRITE_ALL{}; struct READ_WRITE{}; // MEMSPACE @@ -32,7 +32,27 @@ struct LEGACY{}; namespace sierra::nalu { using namespace tags; - +/* SmartField is a type that is designed to automatically handle field syncs + * and modifies + * It adheres to the pattern of sync before you use, and modify after + * + * There are 3 Template params: + * - FieldType: Data type for the underlying stk field + * + * - MEMSPACE: where the field is valid + * - DEVICE: is self explanatory + * - HOST: is using the same modern stk syntax based on + * kokkos::parallel_for but for host data + * - LEGACY: for the stk::mesh::field_data type access (bucket loops) + * + * - ACCESS: how the data can/should be used + * - READ: read only/const data accessors (only syncs data) + * - READ_WRITE: read and write data to field (syncs then marks modified) + * - WRITE_ALL: should only be used when overwritting all the field_data + * (clears sync state) + * + * NOTE: this implementation makes heavy use of SFINAE + */ template < typename FieldType, typename MEMSPACE, @@ -42,6 +62,11 @@ class SmartField { }; +// LEGACY implementation, HOST only, data type has to be a reference b/c the +// stk::mesh::field ctor is not public +// +// This Type should be used as close to a bucket loop as possible, and not +// stored as a class member since sync/modify are marked in the ctor/dtor template class SmartField< FieldType, @@ -57,7 +82,7 @@ class SmartField< std::is_same::value}; static constexpr bool is_write_{ - std::is_same::value || + std::is_same::value || std::is_same::value}; FieldType& stkField_; @@ -123,6 +148,12 @@ class SmartField< } }; +// DEVICE and HOST implementations +// +// These should always be used as part of lambda/functor captures +// using copy by value. +// +// SFINAE is used to remove KOKKOS_FUNCTION type decorators for HOST MEMSPACE template class SmartField< FieldType, @@ -139,7 +170,7 @@ class SmartField< std::is_same::value}; static constexpr bool is_write_{ - std::is_same::value || + std::is_same::value || std::is_same::value}; FieldType stkField_; diff --git a/src/SmartField.C b/src/SmartField.C index 3d8b6afd0..246644cda 100644 --- a/src/SmartField.C +++ b/src/SmartField.C @@ -7,20 +7,39 @@ // for more details. // -#include +#include +#include -namespace sierra::nalu{ +namespace sierra::nalu { using namespace tags; -#define TYPE_INSTANTIATOR_NGP(T) \ - template class SmartField, DEVICE, READ>; \ - template class SmartField, DEVICE, WRITE>; \ - template class SmartField, DEVICE, READ_WRITE>; \ - template class SmartField, HOST, READ>; \ - template class SmartField, HOST, WRITE>; \ +#define EXPLICIT_TYPE_INSTANTIATOR_NGP(T) \ + template class SmartField, DEVICE, READ>; \ + template class SmartField, DEVICE, WRITE_ALL>; \ + template class SmartField, DEVICE, READ_WRITE>; \ + template class SmartField, HOST, READ>; \ + template class SmartField, HOST, WRITE_ALL>; \ template class SmartField, HOST, READ_WRITE> -TYPE_INSTANTIATOR_NGP(double); -TYPE_INSTANTIATOR_NGP(int); -TYPE_INSTANTIATOR_NGP(unsigned); -} +#define EXPLICIT_TYPE_INSTANTIATOR_LEGACY(T) \ + template class SmartField, HOST, READ>; \ + template class SmartField, HOST, WRITE_ALL>; \ + template class SmartField, HOST, READ_WRITE> + +EXPLICIT_TYPE_INSTANTIATOR_NGP(double); +EXPLICIT_TYPE_INSTANTIATOR_NGP(int); +EXPLICIT_TYPE_INSTANTIATOR_NGP(stk::mesh::EntityId); +EXPLICIT_TYPE_INSTANTIATOR_NGP(HypreIntType); + +EXPLICIT_TYPE_INSTANTIATOR_LEGACY(ScalarFieldType); +EXPLICIT_TYPE_INSTANTIATOR_LEGACY(VectorFieldType); +EXPLICIT_TYPE_INSTANTIATOR_LEGACY(TensorFieldType); +EXPLICIT_TYPE_INSTANTIATOR_LEGACY(GenericFieldType); +EXPLICIT_TYPE_INSTANTIATOR_LEGACY(GenericIntFieldType); +EXPLICIT_TYPE_INSTANTIATOR_LEGACY(TpetIDFieldType); +EXPLICIT_TYPE_INSTANTIATOR_LEGACY(LocalIdFieldType); +EXPLICIT_TYPE_INSTANTIATOR_LEGACY(GlobalIdFieldType); +EXPLICIT_TYPE_INSTANTIATOR_LEGACY(HypreIDFieldType); +EXPLICIT_TYPE_INSTANTIATOR_LEGACY(ScalarIntFieldType); + +} // namespace sierra::nalu From bf884f8d161b89b72106582eca46bf0b045ba09b Mon Sep 17 00:00:00 2001 From: Philip Sakievich Date: Mon, 18 Sep 2023 21:28:25 -0600 Subject: [PATCH 26/40] Tweaks --- include/SmartField.h | 39 ++++++++++++++++++++++----------- src/SmartField.C | 12 +++++++--- unit_tests/UnitTestSmartField.C | 2 +- 3 files changed, 36 insertions(+), 17 deletions(-) diff --git a/include/SmartField.h b/include/SmartField.h index 866c5fee2..13423d912 100644 --- a/include/SmartField.h +++ b/include/SmartField.h @@ -62,10 +62,10 @@ class SmartField { }; -// LEGACY implementation, HOST only, data type has to be a reference b/c the +// LEGACY implementation, HOST only, data type has to be a reference b/c the // stk::mesh::field ctor is not public // -// This Type should be used as close to a bucket loop as possible, and not +// This Type should be used as close to a bucket loop as possible, and not // stored as a class member since sync/modify are marked in the ctor/dtor template class SmartField< @@ -108,6 +108,7 @@ class SmartField< // --- Default Accessors template + inline typename std::enable_if_t::value, T>& get(const stk::mesh::Entity& entity) const { @@ -115,6 +116,7 @@ class SmartField< } template + inline typename std::enable_if_t::value, T>& operator()(const stk::mesh::Entity& entity) const { @@ -123,6 +125,7 @@ class SmartField< // --- Const Accessors template + inline const typename std::enable_if_t::value, T>& get(const stk::mesh::Entity& entity) const { @@ -130,6 +133,7 @@ class SmartField< } template + inline const typename std::enable_if_t::value, T>& operator()(const stk::mesh::Entity& entity) const { @@ -153,7 +157,7 @@ class SmartField< // These should always be used as part of lambda/functor captures // using copy by value. // -// SFINAE is used to remove KOKKOS_FUNCTION type decorators for HOST MEMSPACE +// SFINAE is used to remove KOKKOS_INLINE_FUNCTION type decorators for HOST MEMSPACE template class SmartField< FieldType, @@ -212,9 +216,10 @@ class SmartField< } //************************************************************ - // Host functions (Remove KOKKOS_FUNCTION decorators) + // Host functions (Remove KOKKOS_INLINE_FUNCTION decorators) //************************************************************ template + inline std::enable_if_t::value, unsigned> get_ordinal() const { return stkField_.get_ordinal(); @@ -222,6 +227,7 @@ class SmartField< // --- Default Accessors template + inline std::enable_if_t< std::is_same::value && !std::is_same::value, T>& @@ -231,6 +237,7 @@ class SmartField< } template + inline std::enable_if_t< std::is_same::value && !std::is_same::value, T>& @@ -240,6 +247,7 @@ class SmartField< } template + inline std::enable_if_t< std::is_same::value && !std::is_same::value, T>& @@ -249,6 +257,7 @@ class SmartField< } template + inline std::enable_if_t< std::is_same::value && !std::is_same::value, T>& @@ -259,6 +268,7 @@ class SmartField< // --- Const Accessors template + inline const std::enable_if_t< std::is_same::value && std::is_same::value, T>& @@ -268,6 +278,7 @@ class SmartField< } template + inline const std::enable_if_t< std::is_same::value && std::is_same::value, T>& @@ -277,6 +288,7 @@ class SmartField< } template + inline const std::enable_if_t< std::is_same::value && std::is_same::value, T>& @@ -286,6 +298,7 @@ class SmartField< } template + inline const std::enable_if_t< std::is_same::value && std::is_same::value, T>& @@ -298,7 +311,7 @@ class SmartField< // Device functions //************************************************************ template - KOKKOS_FUNCTION std::enable_if_t::value, unsigned> + KOKKOS_INLINE_FUNCTION std::enable_if_t::value, unsigned> get_ordinal() const { return stkField_.get_ordinal(); @@ -306,7 +319,7 @@ class SmartField< // --- Default Accessors template - KOKKOS_FUNCTION std::enable_if_t< + KOKKOS_INLINE_FUNCTION std::enable_if_t< std::is_same::value && !std::is_same::value, T>& get(stk::mesh::FastMeshIndex& index, int component) const @@ -315,7 +328,7 @@ class SmartField< } template - KOKKOS_FUNCTION std::enable_if_t< + KOKKOS_INLINE_FUNCTION std::enable_if_t< std::is_same::value && !std::is_same::value, T>& get(MeshIndex index, int component) const @@ -324,7 +337,7 @@ class SmartField< } template - KOKKOS_FUNCTION std::enable_if_t< + KOKKOS_INLINE_FUNCTION std::enable_if_t< std::is_same::value && !std::is_same::value, T>& operator()(const stk::mesh::FastMeshIndex& index, int component) const @@ -333,7 +346,7 @@ class SmartField< } template - KOKKOS_FUNCTION std::enable_if_t< + KOKKOS_INLINE_FUNCTION std::enable_if_t< std::is_same::value && !std::is_same::value, T>& operator()(const MeshIndex index, int component) const @@ -343,7 +356,7 @@ class SmartField< // --- Const Accessors template - KOKKOS_FUNCTION const std::enable_if_t< + KOKKOS_INLINE_FUNCTION const std::enable_if_t< std::is_same::value && std::is_same::value, T>& get(stk::mesh::FastMeshIndex& index, int component) const @@ -352,7 +365,7 @@ class SmartField< } template - KOKKOS_FUNCTION const std::enable_if_t< + KOKKOS_INLINE_FUNCTION const std::enable_if_t< std::is_same::value && std::is_same::value, T>& get(MeshIndex index, int component) const @@ -361,7 +374,7 @@ class SmartField< } template - KOKKOS_FUNCTION const std::enable_if_t< + KOKKOS_INLINE_FUNCTION const std::enable_if_t< std::is_same::value && std::is_same::value, T>& operator()(const stk::mesh::FastMeshIndex& index, int component) const @@ -370,7 +383,7 @@ class SmartField< } template - KOKKOS_FUNCTION const std::enable_if_t< + KOKKOS_INLINE_FUNCTION const std::enable_if_t< std::is_same::value && std::is_same::value, T>& operator()(const MeshIndex index, int component) const diff --git a/src/SmartField.C b/src/SmartField.C index 246644cda..4fc1948a9 100644 --- a/src/SmartField.C +++ b/src/SmartField.C @@ -26,10 +26,17 @@ using namespace tags; template class SmartField, HOST, WRITE_ALL>; \ template class SmartField, HOST, READ_WRITE> -EXPLICIT_TYPE_INSTANTIATOR_NGP(double); EXPLICIT_TYPE_INSTANTIATOR_NGP(int); +EXPLICIT_TYPE_INSTANTIATOR_NGP(double); EXPLICIT_TYPE_INSTANTIATOR_NGP(stk::mesh::EntityId); -EXPLICIT_TYPE_INSTANTIATOR_NGP(HypreIntType); + +// Hypre Integer types +// What to do about HYPRE int vs long vs long long here? +/* #ifdef NALU_USES_HYPRE */ +/* typedef HYPRE_Int HypreIntType; */ +/* EXPLICIT_TYPE_INSTANTIATOR_NGP(HypreIntType); */ +/* EXPLICIT_TYPE_INSTANTIATOR_LEGACY(HypreIDFieldType); */ +/* #endif */ EXPLICIT_TYPE_INSTANTIATOR_LEGACY(ScalarFieldType); EXPLICIT_TYPE_INSTANTIATOR_LEGACY(VectorFieldType); @@ -39,7 +46,6 @@ EXPLICIT_TYPE_INSTANTIATOR_LEGACY(GenericIntFieldType); EXPLICIT_TYPE_INSTANTIATOR_LEGACY(TpetIDFieldType); EXPLICIT_TYPE_INSTANTIATOR_LEGACY(LocalIdFieldType); EXPLICIT_TYPE_INSTANTIATOR_LEGACY(GlobalIdFieldType); -EXPLICIT_TYPE_INSTANTIATOR_LEGACY(HypreIDFieldType); EXPLICIT_TYPE_INSTANTIATOR_LEGACY(ScalarIntFieldType); } // namespace sierra::nalu diff --git a/unit_tests/UnitTestSmartField.C b/unit_tests/UnitTestSmartField.C index 508fd2d31..09cf68af0 100644 --- a/unit_tests/UnitTestSmartField.C +++ b/unit_tests/UnitTestSmartField.C @@ -88,7 +88,7 @@ TEST_F(TestSmartField, device_write_clear_mod_with_lambda) ASSERT_TRUE(ngpField_->need_sync_to_device()); - auto sPtr = MakeSmartField()(*ngpField_); + auto sPtr = MakeSmartField()(*ngpField_); lambda_ordinal(sPtr); EXPECT_FALSE(ngpField_->need_sync_to_device()); From 1cc717630e06adb14b294f3fd66c176ffb6a27bc Mon Sep 17 00:00:00 2001 From: Philip Sakievich Date: Tue, 19 Sep 2023 12:31:27 -0600 Subject: [PATCH 27/40] Prep FieldManager for interface --- include/ElemDataRequestsGPU.h | 4 ++-- include/FieldManager.h | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/include/ElemDataRequestsGPU.h b/include/ElemDataRequestsGPU.h index b79bc26e7..2215de6e7 100644 --- a/include/ElemDataRequestsGPU.h +++ b/include/ElemDataRequestsGPU.h @@ -258,7 +258,7 @@ auto& ElemDataRequestsGPU::get_coord_ptr(const T& fieldMgr, const U& iter) const { if constexpr (std::is_same_v) - return fieldMgr.get_ngp_field_ptr(iter.second->name()); + return fieldMgr.template get_ngp_field_ptr(iter.second->name()); else return fieldMgr.template get_field( iter.second->mesh_meta_data_ordinal()); @@ -297,7 +297,7 @@ ElemDataRequestsGPU::get_field_ptr( const T& fieldMgr, const FieldInfo& finfo) const { if constexpr (std::is_same_v) - return fieldMgr.get_ngp_field_ptr(finfo.field->name()); + return fieldMgr.template get_ngp_field_ptr(finfo.field->name()); else return fieldMgr.template get_field( finfo.field->mesh_meta_data_ordinal()); diff --git a/include/FieldManager.h b/include/FieldManager.h index d84572185..8170aa5b3 100644 --- a/include/FieldManager.h +++ b/include/FieldManager.h @@ -132,7 +132,8 @@ class FieldManager /// Given the named field that has already been registered on the CPU /// return the GPU version of the same field. - stk::mesh::NgpField& get_ngp_field_ptr(std::string name) const + template + stk::mesh::NgpField& get_ngp_field_ptr(std::string name) const { FieldDefTypes fieldDef = FieldRegistry::query(numDimensions_, numStates_, name); @@ -143,8 +144,8 @@ class FieldManager ->field_of_state(stk::mesh::FieldState::StateNone); }, fieldDef); - stk::mesh::NgpField& tmp = - stk::mesh::get_updated_ngp_field(stkField); + stk::mesh::NgpField& tmp = + stk::mesh::get_updated_ngp_field(stkField); return tmp; } }; From 09b33a06b6e9df93eee05b5818903b4941e752e3 Mon Sep 17 00:00:00 2001 From: psakiev Date: Wed, 20 Sep 2023 16:39:01 -0600 Subject: [PATCH 28/40] Add some partial template specializations --- include/FieldManager.h | 8 ++------ include/SmartField.h | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/include/FieldManager.h b/include/FieldManager.h index 8170aa5b3..71aca0f62 100644 --- a/include/FieldManager.h +++ b/include/FieldManager.h @@ -16,14 +16,11 @@ #include #include -namespace stk { -namespace mesh { +namespace stk::mesh { class MetaData; -} } // namespace stk -namespace sierra { -namespace nalu { +namespace sierra::nalu{ class FieldManager { @@ -149,7 +146,6 @@ class FieldManager return tmp; } }; -} // namespace nalu } // namespace sierra #endif /* FIELDMANAGER_H_ */ diff --git a/include/SmartField.h b/include/SmartField.h index 13423d912..4332f4ca5 100644 --- a/include/SmartField.h +++ b/include/SmartField.h @@ -402,6 +402,26 @@ struct MakeSmartField } }; +template +struct MakeSmartField +{ + template + SmartField, LEGACY, ACCESS> operator()(stk::mesh::Field& field) + { + return SmartField, LEGACY, ACCESS>(field); + } +}; + +template +struct MakeSmartField +{ + template + SmartField, DEVICE, ACCESS> operator()(stk::mesh::NgpField& field) + { + return SmartField, DEVICE, ACCESS>(field); + } +}; + } // namespace sierra::nalu #endif From a7a1c7f1b864a86526209dd7a8f8d480f054e0b3 Mon Sep 17 00:00:00 2001 From: psakiev Date: Thu, 21 Sep 2023 07:11:21 -0600 Subject: [PATCH 29/40] FieldManager interface --- include/FieldManager.h | 18 ++++++++++++++++-- include/SmartField.h | 19 +++++++++++++------ unit_tests/UnitTestFieldManager.C | 13 +++++++++++++ unit_tests/UnitTestSmartField.C | 2 +- 4 files changed, 43 insertions(+), 9 deletions(-) diff --git a/include/FieldManager.h b/include/FieldManager.h index 71aca0f62..30e135401 100644 --- a/include/FieldManager.h +++ b/include/FieldManager.h @@ -11,6 +11,7 @@ #define FIELDMANAGER_H_ #include "FieldRegistry.h" +#include "SmartField.h" #include #include "stk_mesh/base/GetNgpField.hpp" #include @@ -130,7 +131,7 @@ class FieldManager /// Given the named field that has already been registered on the CPU /// return the GPU version of the same field. template - stk::mesh::NgpField& get_ngp_field_ptr(std::string name) const + stk::mesh::NgpField& get_ngp_field_ptr(std::string name, stk::mesh::FieldState state = stk::mesh::FieldState::StateNone) const { FieldDefTypes fieldDef = FieldRegistry::query(numDimensions_, numStates_, name); @@ -138,13 +139,26 @@ class FieldManager [&](auto def) -> stk::mesh::FieldBase& { return meta_ .get_field(def.rank, name) - ->field_of_state(stk::mesh::FieldState::StateNone); + ->field_of_state(state); }, fieldDef); stk::mesh::NgpField& tmp = stk::mesh::get_updated_ngp_field(stkField); return tmp; } + + template + SmartField, tags::DEVICE, ACCESS> + get_device_smart_field(std::string name, stk::mesh::FieldState state = stk::mesh::FieldState::StateNone) const{ + return MakeSmartField().template operator()(get_ngp_field_ptr(name, state)); + } + + template + SmartField + get_legacy_smart_field(std::string name, stk::mesh::FieldState state = stk::mesh::FieldState::StateNone) const{ + return MakeSmartField().template operator()(get_field_ptr(name, state)); + } + }; } // namespace sierra diff --git a/include/SmartField.h b/include/SmartField.h index 4332f4ca5..5db3b4643 100644 --- a/include/SmartField.h +++ b/include/SmartField.h @@ -392,23 +392,30 @@ class SmartField< } }; + template struct MakeSmartField { - template - SmartField operator()(FieldType& field) +}; + +template +struct MakeSmartField +{ + // use pointer since that is the common access type for stk::mesh::Field + template + SmartField operator()(T* field) { - return SmartField(field); + return SmartField(*field); } }; template -struct MakeSmartField +struct MakeSmartField { template - SmartField, LEGACY, ACCESS> operator()(stk::mesh::Field& field) + SmartField, HOST, ACCESS> operator()(stk::mesh::HostField& field) { - return SmartField, LEGACY, ACCESS>(field); + return SmartField, HOST, ACCESS>(field); } }; diff --git a/unit_tests/UnitTestFieldManager.C b/unit_tests/UnitTestFieldManager.C index 0fec15e48..350b9974f 100644 --- a/unit_tests/UnitTestFieldManager.C +++ b/unit_tests/UnitTestFieldManager.C @@ -124,6 +124,19 @@ TEST_F(FieldManagerTest, numStatesCanBeChangedAtRegistration) ASSERT_TRUE(field != nullptr); EXPECT_EQ(numStates, field->number_of_states()); } + + +TEST_F(FieldManagerTest, minimalSmartFieldCreation) +{ + const std::string name = "velocity"; + const int numStates = 3; + const stk::mesh::PartVector universal(1, &meta().universal_part()); + FieldManager fm(meta(), numStates); + fm.register_field(name, universal, numStates); + + auto managerNgpField = fm.get_device_smart_field(name); + auto managerLegacyField = fm.get_legacy_smart_field(name); +} } // namespace } // namespace nalu } // namespace sierra diff --git a/unit_tests/UnitTestSmartField.C b/unit_tests/UnitTestSmartField.C index 09cf68af0..41ebbd3aa 100644 --- a/unit_tests/UnitTestSmartField.C +++ b/unit_tests/UnitTestSmartField.C @@ -130,7 +130,7 @@ TEST_F(TestSmartField, update_field_on_device_check_on_host) int counter = 0; auto* field = fieldManager->get_field_ptr("scalarQ"); auto fieldRef = - sierra::nalu::MakeSmartField()(*field); + sierra::nalu::MakeSmartField()(field); stk::mesh::Selector sel = stk::mesh::selectUnion(partVec); const auto& buckets = bulk->get_buckets(stk::topology::NODE_RANK, sel); for (auto b : buckets) { From 1a42c9641db9ca5bde64e4d205e131cec21bf165 Mon Sep 17 00:00:00 2001 From: psakiev Date: Thu, 21 Sep 2023 11:00:34 -0600 Subject: [PATCH 30/40] Test FieldManager iFace --- unit_tests/UnitTestFieldManager.C | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/unit_tests/UnitTestFieldManager.C b/unit_tests/UnitTestFieldManager.C index 350b9974f..9a53dad54 100644 --- a/unit_tests/UnitTestFieldManager.C +++ b/unit_tests/UnitTestFieldManager.C @@ -9,6 +9,7 @@ #include "gtest/gtest.h" #include "stk_mesh/base/MeshBuilder.hpp" +#include "UnitTestUtils.h" #include "FieldManager.h" #include #include @@ -126,16 +127,22 @@ TEST_F(FieldManagerTest, numStatesCanBeChangedAtRegistration) } -TEST_F(FieldManagerTest, minimalSmartFieldCreation) +class TestFieldManagerWithElems : public Hex8Mesh { - const std::string name = "velocity"; - const int numStates = 3; - const stk::mesh::PartVector universal(1, &meta().universal_part()); - FieldManager fm(meta(), numStates); - fm.register_field(name, universal, numStates); +public: +protected: + void SetUp() + { + fill_mesh_and_initialize_test_fields(); + } +}; + +TEST_F(TestFieldManagerWithElems, minimalSmartFieldCreation) +{ + const std::string name = "elemCentroid"; - auto managerNgpField = fm.get_device_smart_field(name); - auto managerLegacyField = fm.get_legacy_smart_field(name); + auto managerNgpField = fieldManager->get_device_smart_field(name); + auto managerLegacyField = fieldManager->get_legacy_smart_field(name); } } // namespace } // namespace nalu From bc3de85fc897f97c75f995e9573f9ef65ac8e02c Mon Sep 17 00:00:00 2001 From: Philip Sakievich Date: Thu, 21 Sep 2023 11:19:01 -0600 Subject: [PATCH 31/40] Style --- unit_tests/UnitTestFieldManager.C | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/unit_tests/UnitTestFieldManager.C b/unit_tests/UnitTestFieldManager.C index 9a53dad54..3f5ccc8bc 100644 --- a/unit_tests/UnitTestFieldManager.C +++ b/unit_tests/UnitTestFieldManager.C @@ -126,23 +126,21 @@ TEST_F(FieldManagerTest, numStatesCanBeChangedAtRegistration) EXPECT_EQ(numStates, field->number_of_states()); } - class TestFieldManagerWithElems : public Hex8Mesh { public: protected: - void SetUp() - { - fill_mesh_and_initialize_test_fields(); - } + void SetUp() { fill_mesh_and_initialize_test_fields(); } }; TEST_F(TestFieldManagerWithElems, minimalSmartFieldCreation) { const std::string name = "elemCentroid"; - auto managerNgpField = fieldManager->get_device_smart_field(name); - auto managerLegacyField = fieldManager->get_legacy_smart_field(name); + auto managerNgpField = + fieldManager->get_device_smart_field(name); + auto managerLegacyField = + fieldManager->get_legacy_smart_field(name); } } // namespace } // namespace nalu From 93ee9342740c11716201105524e4942428cf883d Mon Sep 17 00:00:00 2001 From: psakiev Date: Thu, 21 Sep 2023 12:04:55 -0600 Subject: [PATCH 32/40] Style --- include/FieldManager.h | 41 ++++++++++++++++++------------- include/SmartField.h | 55 ++++++++++++++++++------------------------ 2 files changed, 47 insertions(+), 49 deletions(-) diff --git a/include/FieldManager.h b/include/FieldManager.h index 30e135401..d8727524e 100644 --- a/include/FieldManager.h +++ b/include/FieldManager.h @@ -19,9 +19,9 @@ namespace stk::mesh { class MetaData; -} // namespace stk +} // namespace stk::mesh -namespace sierra::nalu{ +namespace sierra::nalu { class FieldManager { @@ -130,8 +130,10 @@ class FieldManager /// Given the named field that has already been registered on the CPU /// return the GPU version of the same field. - template - stk::mesh::NgpField& get_ngp_field_ptr(std::string name, stk::mesh::FieldState state = stk::mesh::FieldState::StateNone) const + template + stk::mesh::NgpField& get_ngp_field_ptr( + std::string name, + stk::mesh::FieldState state = stk::mesh::FieldState::StateNone) const { FieldDefTypes fieldDef = FieldRegistry::query(numDimensions_, numStates_, name); @@ -142,24 +144,29 @@ class FieldManager ->field_of_state(state); }, fieldDef); - stk::mesh::NgpField& tmp = - stk::mesh::get_updated_ngp_field(stkField); + stk::mesh::NgpField& tmp = stk::mesh::get_updated_ngp_field(stkField); return tmp; } - template + template SmartField, tags::DEVICE, ACCESS> - get_device_smart_field(std::string name, stk::mesh::FieldState state = stk::mesh::FieldState::StateNone) const{ - return MakeSmartField().template operator()(get_ngp_field_ptr(name, state)); - } - - template - SmartField - get_legacy_smart_field(std::string name, stk::mesh::FieldState state = stk::mesh::FieldState::StateNone) const{ - return MakeSmartField().template operator()(get_field_ptr(name, state)); - } + get_device_smart_field( + std::string name, + stk::mesh::FieldState state = stk::mesh::FieldState::StateNone) const + { + return MakeSmartField().template operator()( + get_ngp_field_ptr(name, state)); + } + template + SmartField get_legacy_smart_field( + std::string name, + stk::mesh::FieldState state = stk::mesh::FieldState::StateNone) const + { + return MakeSmartField().template operator()( + get_field_ptr(name, state)); + } }; -} // namespace sierra +} // namespace sierra::nalu #endif /* FIELDMANAGER_H_ */ diff --git a/include/SmartField.h b/include/SmartField.h index 5db3b4643..e26cc8b75 100644 --- a/include/SmartField.h +++ b/include/SmartField.h @@ -108,16 +108,14 @@ class SmartField< // --- Default Accessors template - inline - typename std::enable_if_t::value, T>& + inline typename std::enable_if_t::value, T>& get(const stk::mesh::Entity& entity) const { return *stk::mesh::field_data(stkField_, entity); } template - inline - typename std::enable_if_t::value, T>& + inline typename std::enable_if_t::value, T>& operator()(const stk::mesh::Entity& entity) const { return *stk::mesh::field_data(stkField_, entity); @@ -125,16 +123,14 @@ class SmartField< // --- Const Accessors template - inline - const typename std::enable_if_t::value, T>& + inline const typename std::enable_if_t::value, T>& get(const stk::mesh::Entity& entity) const { return *stk::mesh::field_data(stkField_, entity); } template - inline - const typename std::enable_if_t::value, T>& + inline const typename std::enable_if_t::value, T>& operator()(const stk::mesh::Entity& entity) const { return *stk::mesh::field_data(stkField_, entity); @@ -157,7 +153,8 @@ class SmartField< // These should always be used as part of lambda/functor captures // using copy by value. // -// SFINAE is used to remove KOKKOS_INLINE_FUNCTION type decorators for HOST MEMSPACE +// SFINAE is used to remove KOKKOS_INLINE_FUNCTION type decorators for HOST +// MEMSPACE template class SmartField< FieldType, @@ -219,16 +216,15 @@ class SmartField< // Host functions (Remove KOKKOS_INLINE_FUNCTION decorators) //************************************************************ template - inline - std::enable_if_t::value, unsigned> get_ordinal() const + inline std::enable_if_t::value, unsigned> + get_ordinal() const { return stkField_.get_ordinal(); } // --- Default Accessors template - inline - std::enable_if_t< + inline std::enable_if_t< std::is_same::value && !std::is_same::value, T>& get(stk::mesh::FastMeshIndex& index, int component) const @@ -237,8 +233,7 @@ class SmartField< } template - inline - std::enable_if_t< + inline std::enable_if_t< std::is_same::value && !std::is_same::value, T>& get(MeshIndex index, int component) const @@ -247,8 +242,7 @@ class SmartField< } template - inline - std::enable_if_t< + inline std::enable_if_t< std::is_same::value && !std::is_same::value, T>& operator()(const stk::mesh::FastMeshIndex& index, int component) const @@ -257,8 +251,7 @@ class SmartField< } template - inline - std::enable_if_t< + inline std::enable_if_t< std::is_same::value && !std::is_same::value, T>& operator()(const MeshIndex index, int component) const @@ -268,8 +261,7 @@ class SmartField< // --- Const Accessors template - inline - const std::enable_if_t< + inline const std::enable_if_t< std::is_same::value && std::is_same::value, T>& get(stk::mesh::FastMeshIndex& index, int component) const @@ -278,8 +270,7 @@ class SmartField< } template - inline - const std::enable_if_t< + inline const std::enable_if_t< std::is_same::value && std::is_same::value, T>& get(MeshIndex index, int component) const @@ -288,8 +279,7 @@ class SmartField< } template - inline - const std::enable_if_t< + inline const std::enable_if_t< std::is_same::value && std::is_same::value, T>& operator()(const stk::mesh::FastMeshIndex& index, int component) const @@ -298,8 +288,7 @@ class SmartField< } template - inline - const std::enable_if_t< + inline const std::enable_if_t< std::is_same::value && std::is_same::value, T>& operator()(const MeshIndex index, int component) const @@ -311,8 +300,9 @@ class SmartField< // Device functions //************************************************************ template - KOKKOS_INLINE_FUNCTION std::enable_if_t::value, unsigned> - get_ordinal() const + KOKKOS_INLINE_FUNCTION + std::enable_if_t::value, unsigned> + get_ordinal() const { return stkField_.get_ordinal(); } @@ -392,7 +382,6 @@ class SmartField< } }; - template struct MakeSmartField { @@ -413,7 +402,8 @@ template struct MakeSmartField { template - SmartField, HOST, ACCESS> operator()(stk::mesh::HostField& field) + SmartField, HOST, ACCESS> + operator()(stk::mesh::HostField& field) { return SmartField, HOST, ACCESS>(field); } @@ -423,7 +413,8 @@ template struct MakeSmartField { template - SmartField, DEVICE, ACCESS> operator()(stk::mesh::NgpField& field) + SmartField, DEVICE, ACCESS> + operator()(stk::mesh::NgpField& field) { return SmartField, DEVICE, ACCESS>(field); } From fa1b4c1e8adf404327267977ac20f814a6390747 Mon Sep 17 00:00:00 2001 From: psakiev Date: Thu, 21 Sep 2023 16:40:29 -0600 Subject: [PATCH 33/40] Start using, and improve interface for legacy case --- include/SmartField.h | 19 ++++++------- unit_tests/UnitTestFieldManager.C | 4 +-- unit_tests/UnitTestSmartField.C | 2 +- unit_tests/UnitTestUtils.h | 46 +++++++++++++++++++------------ 4 files changed, 41 insertions(+), 30 deletions(-) diff --git a/include/SmartField.h b/include/SmartField.h index e26cc8b75..885991da2 100644 --- a/include/SmartField.h +++ b/include/SmartField.h @@ -108,32 +108,32 @@ class SmartField< // --- Default Accessors template - inline typename std::enable_if_t::value, T>& + inline typename std::enable_if_t::value, T>* get(const stk::mesh::Entity& entity) const { - return *stk::mesh::field_data(stkField_, entity); + return stk::mesh::field_data(stkField_, entity); } template - inline typename std::enable_if_t::value, T>& + inline typename std::enable_if_t::value, T>* operator()(const stk::mesh::Entity& entity) const { - return *stk::mesh::field_data(stkField_, entity); + return stk::mesh::field_data(stkField_, entity); } // --- Const Accessors template - inline const typename std::enable_if_t::value, T>& + inline const typename std::enable_if_t::value, T>* get(const stk::mesh::Entity& entity) const { - return *stk::mesh::field_data(stkField_, entity); + return stk::mesh::field_data(stkField_, entity); } template - inline const typename std::enable_if_t::value, T>& + inline const typename std::enable_if_t::value, T>* operator()(const stk::mesh::Entity& entity) const { - return *stk::mesh::field_data(stkField_, entity); + return stk::mesh::field_data(stkField_, entity); } ~SmartField() @@ -402,7 +402,7 @@ template struct MakeSmartField { template - SmartField, HOST, ACCESS> + SmartField, HOST, ACCESS> operator()(stk::mesh::HostField& field) { return SmartField, HOST, ACCESS>(field); @@ -419,7 +419,6 @@ struct MakeSmartField return SmartField, DEVICE, ACCESS>(field); } }; - } // namespace sierra::nalu #endif diff --git a/unit_tests/UnitTestFieldManager.C b/unit_tests/UnitTestFieldManager.C index 3f5ccc8bc..94d7022a7 100644 --- a/unit_tests/UnitTestFieldManager.C +++ b/unit_tests/UnitTestFieldManager.C @@ -137,9 +137,9 @@ TEST_F(TestFieldManagerWithElems, minimalSmartFieldCreation) { const std::string name = "elemCentroid"; - auto managerNgpField = + SmartField, tags::DEVICE, tags::READ_WRITE> managerNgpField = fieldManager->get_device_smart_field(name); - auto managerLegacyField = + SmartField managerLegacyField = fieldManager->get_legacy_smart_field(name); } } // namespace diff --git a/unit_tests/UnitTestSmartField.C b/unit_tests/UnitTestSmartField.C index 41ebbd3aa..ac2e40ae0 100644 --- a/unit_tests/UnitTestSmartField.C +++ b/unit_tests/UnitTestSmartField.C @@ -136,7 +136,7 @@ TEST_F(TestSmartField, update_field_on_device_check_on_host) for (auto b : buckets) { for (size_t in = 0; in < b->size(); in++) { auto node = (*b)[in]; - sum += fieldRef.get(node); + sum += *fieldRef.get(node); counter++; } } diff --git a/unit_tests/UnitTestUtils.h b/unit_tests/UnitTestUtils.h index a601bebb6..827ef8fcd 100644 --- a/unit_tests/UnitTestUtils.h +++ b/unit_tests/UnitTestUtils.h @@ -21,8 +21,9 @@ #include #include -#include "master_element/MasterElementRepo.h" -#include "FieldManager.h" +#include +#include +#include #include @@ -432,15 +433,14 @@ class CylinderMesh : public ::testing::Test const double xfac = (outerRad - innerRad) / xMax; const double yfac = 2 * M_PI / yMax; + auto nodeCoord = sierra::nalu::MakeSmartField()(coordField); for (const stk::mesh::Bucket* bptr : bkts) { for (stk::mesh::Entity node : *bptr) { - double* nodeCoord = - reinterpret_cast(stk::mesh::field_data(*coordField, node)); - const double radius = innerRad + nodeCoord[0] * xfac; - const double theta = nodeCoord[1] * yfac; - nodeCoord[0] = radius * std::cos(theta); - nodeCoord[1] = radius * std::sin(theta); + const double radius = innerRad + nodeCoord(node)[0] * xfac; + const double theta = nodeCoord(node)[1] * yfac; + nodeCoord(node)[0] = radius * std::cos(theta); + nodeCoord(node)[1] = radius * std::sin(theta); } } } @@ -494,28 +494,42 @@ class ABLWallFunctionHex8ElementWithBCFields : public Hex8ElementWithBCFields upSpec_ = up; ypSpec_ = yp; + + // create an object for creating SmartField's + sierra::nalu::MakeSmartField smartener; + // Assign some values to the nodal fields + // all these fields will sync_to_host here and call modified_on_host when + // they go out of scope + auto smrtDensity = smartener(density); + auto smrtVelocity = smartener(velocity); + auto smrtBcVelocity = smartener(bcVelocity); + auto smrtBcHeatFlux = smartener(bcHeatFlux); + auto smrtSpecificHeat = smartener(specificHeat); for (const auto* ib : bulk->get_buckets(stk::topology::NODE_RANK, meta->universal_part())) { const auto& b = *ib; const size_t length = b.size(); for (size_t k = 0; k < length; ++k) { stk::mesh::Entity node = b[k]; - *stk::mesh::field_data(*density, node) = rhoSpec_; - double* vel = stk::mesh::field_data(*velocity, node); + *smrtDensity(node) = rhoSpec_; + double* vel = smrtVelocity(node); vel[0] = upSpec_; vel[1] = 0.0; vel[2] = 0.0; - double* bcVel = stk::mesh::field_data(*bcVelocity, node); + double* bcVel = smrtBcVelocity(node); bcVel[0] = 0.0; bcVel[1] = 0.0; bcVel[3] = 0.0; - *stk::mesh::field_data(*bcHeatFlux, node) = 0.0; - *stk::mesh::field_data(*specificHeat, node) = 1000.0; + *smrtBcHeatFlux(node) = 0.0; + *smrtSpecificHeat(node) = 1000.0; } } // Assign some values to the boundary integration point fields + auto utauIp = smartener(wallFrictionVelocityBip); + auto ypIp = smartener(wallNormalDistanceBip); + const sierra::nalu::MasterElement* meFC = sierra::nalu::MasterElementRepo::get_surface_master_element_on_host( stk::topology::QUAD_4); @@ -528,11 +542,9 @@ class ABLWallFunctionHex8ElementWithBCFields : public Hex8ElementWithBCFields const size_t length = b.size(); for (size_t k = 0; k < length; ++k) { stk::mesh::Entity face = b[k]; - double* utauIp = stk::mesh::field_data(*wallFrictionVelocityBip, face); - double* ypIp = stk::mesh::field_data(*wallNormalDistanceBip, face); for (int ip = 0; ip < numScsBip; ++ip) { - utauIp[ip] = utauSpec_; - ypIp[ip] = ypSpec_; + utauIp(face)[ip] = utauSpec_; + ypIp(face)[ip] = ypSpec_; } } } From 00d91730b4001ff897a1f21407ba9bfd142c9c59 Mon Sep 17 00:00:00 2001 From: psakiev Date: Thu, 21 Sep 2023 17:08:48 -0600 Subject: [PATCH 34/40] More conversions in unit-tests --- .../mesh_motion/UnitTestCompositeFrames.C | 45 +++++++++---------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/unit_tests/mesh_motion/UnitTestCompositeFrames.C b/unit_tests/mesh_motion/UnitTestCompositeFrames.C index 414c27006..35bf88ace 100644 --- a/unit_tests/mesh_motion/UnitTestCompositeFrames.C +++ b/unit_tests/mesh_motion/UnitTestCompositeFrames.C @@ -7,6 +7,7 @@ #include "mesh_motion/MotionScalingKernel.h" #include "mesh_motion/MotionTranslationKernel.h" #include "Realm.h" +#include "SmartField.h" #include "SolutionOptions.h" #include "TimeIntegrator.h" @@ -168,6 +169,7 @@ TEST(meshMotion, NGP_initialize) unit_test_utils::fill_hex8_mesh(meshSpec, realm.bulk_data()); realm.init_current_coordinates(); + // copy coordinates to copy coordinates VectorFieldType* modelCoords = realm.meta_data().get_field( stk::topology::NODE_RANK, "coordinates"); @@ -180,18 +182,21 @@ TEST(meshMotion, NGP_initialize) const auto& bkts = realm.bulk_data().get_buckets(stk::topology::NODE_RANK, sel); + { // limit scope for SmartFields so sync/modify is called right after use + // we should time this call. it might be fine to just stick in the outer bucket loop + auto mxyz = sierra::nalu::MakeSmartField()(modelCoords); + auto cxyz = sierra::nalu::MakeSmartField()(modelCoordsCopy); for (auto b : bkts) { for (size_t in = 0; in < b->size(); in++) { auto node = (*b)[in]; // mesh node and NOT YAML node - double* mxyz = stk::mesh::field_data(*modelCoords, node); - double* cxyz = stk::mesh::field_data(*modelCoordsCopy, node); for (int d = 0; d < nDim; ++d) { - cxyz[d] = mxyz[d]; + cxyz(node)[d] = mxyz(node)[d]; } } // end for loop - in index } // end for loop - bkts + } // create mesh transformation algorithm class std::unique_ptr meshTransformationAlg; @@ -209,40 +214,34 @@ TEST(meshMotion, NGP_initialize) meshMotionAlg->initialize(currTime); // get fields to be tested - auto* currCoords = - realm.fieldManager_->get_field_ptr("current_coordinates"); - auto* meshVelocity = - realm.fieldManager_->get_field_ptr("mesh_velocity"); - - // sync coordinates to host - currCoords->sync_to_host(); - meshVelocity->sync_to_host(); + { // Scope limiting braces again... + auto oxyz = realm.fieldManager_->get_legacy_smart_field("coordinates_copy"); + auto xyz = realm.fieldManager_->get_legacy_smart_field("current_coordinates"); + auto vel = realm.fieldManager_->get_legacy_smart_field("mesh_velocity"); for (auto b : bkts) { for (size_t in = 0; in < b->size(); in++) { auto node = (*b)[in]; // mesh node and NOT YAML node - double* oxyz = stk::mesh::field_data(*modelCoordsCopy, node); - double* xyz = stk::mesh::field_data(*currCoords, node); - double* vel = stk::mesh::field_data(*meshVelocity, node); sierra::nalu::mm::TransMatType transMat = - eval_transformation(realm, currTime, oxyz); + eval_transformation(realm, currTime, oxyz(node)); - std::vector gold_norm_xyz = eval_coords(transMat, oxyz); + std::vector gold_norm_xyz = eval_coords(transMat, oxyz(node)); std::vector gold_norm_vel = - eval_vel(currTime, transMat, oxyz, &gold_norm_xyz[0]); + eval_vel(currTime, transMat, oxyz(node), &gold_norm_xyz[0]); - EXPECT_NEAR(xyz[0], gold_norm_xyz[0], testTol); - EXPECT_NEAR(xyz[1], gold_norm_xyz[1], testTol); - EXPECT_NEAR(xyz[2], gold_norm_xyz[2], testTol); + EXPECT_NEAR(xyz(node)[0], gold_norm_xyz[0], testTol); + EXPECT_NEAR(xyz(node)[1], gold_norm_xyz[1], testTol); + EXPECT_NEAR(xyz(node)[2], gold_norm_xyz[2], testTol); - EXPECT_NEAR(vel[0], gold_norm_vel[0], testTol); - EXPECT_NEAR(vel[1], gold_norm_vel[1], testTol); - EXPECT_NEAR(vel[2], gold_norm_vel[2], testTol); + EXPECT_NEAR(vel(node)[0], gold_norm_vel[0], testTol); + EXPECT_NEAR(vel(node)[1], gold_norm_vel[1], testTol); + EXPECT_NEAR(vel(node)[2], gold_norm_vel[2], testTol); } // end for loop - in index } // end for loop - bkts } +} TEST(meshMotion, NGP_execute) { From f3080ac984523fbf04dc7cd851a74bc78ce1a2d1 Mon Sep 17 00:00:00 2001 From: psakiev Date: Thu, 21 Sep 2023 17:14:31 -0600 Subject: [PATCH 35/40] Style --- unit_tests/UnitTestFieldManager.C | 5 +- unit_tests/UnitTestUtils.h | 5 +- .../mesh_motion/UnitTestCompositeFrames.C | 88 ++++++++++--------- 3 files changed, 54 insertions(+), 44 deletions(-) diff --git a/unit_tests/UnitTestFieldManager.C b/unit_tests/UnitTestFieldManager.C index 94d7022a7..1baaa9843 100644 --- a/unit_tests/UnitTestFieldManager.C +++ b/unit_tests/UnitTestFieldManager.C @@ -137,8 +137,9 @@ TEST_F(TestFieldManagerWithElems, minimalSmartFieldCreation) { const std::string name = "elemCentroid"; - SmartField, tags::DEVICE, tags::READ_WRITE> managerNgpField = - fieldManager->get_device_smart_field(name); + SmartField, tags::DEVICE, tags::READ_WRITE> + managerNgpField = + fieldManager->get_device_smart_field(name); SmartField managerLegacyField = fieldManager->get_legacy_smart_field(name); } diff --git a/unit_tests/UnitTestUtils.h b/unit_tests/UnitTestUtils.h index 827ef8fcd..a9b6d927f 100644 --- a/unit_tests/UnitTestUtils.h +++ b/unit_tests/UnitTestUtils.h @@ -433,7 +433,9 @@ class CylinderMesh : public ::testing::Test const double xfac = (outerRad - innerRad) / xMax; const double yfac = 2 * M_PI / yMax; - auto nodeCoord = sierra::nalu::MakeSmartField()(coordField); + auto nodeCoord = + sierra::nalu::MakeSmartField()( + coordField); for (const stk::mesh::Bucket* bptr : bkts) { for (stk::mesh::Entity node : *bptr) { @@ -494,7 +496,6 @@ class ABLWallFunctionHex8ElementWithBCFields : public Hex8ElementWithBCFields upSpec_ = up; ypSpec_ = yp; - // create an object for creating SmartField's sierra::nalu::MakeSmartField smartener; diff --git a/unit_tests/mesh_motion/UnitTestCompositeFrames.C b/unit_tests/mesh_motion/UnitTestCompositeFrames.C index 35bf88ace..e2950e4ad 100644 --- a/unit_tests/mesh_motion/UnitTestCompositeFrames.C +++ b/unit_tests/mesh_motion/UnitTestCompositeFrames.C @@ -169,7 +169,6 @@ TEST(meshMotion, NGP_initialize) unit_test_utils::fill_hex8_mesh(meshSpec, realm.bulk_data()); realm.init_current_coordinates(); - // copy coordinates to copy coordinates VectorFieldType* modelCoords = realm.meta_data().get_field( stk::topology::NODE_RANK, "coordinates"); @@ -183,19 +182,22 @@ TEST(meshMotion, NGP_initialize) realm.bulk_data().get_buckets(stk::topology::NODE_RANK, sel); { // limit scope for SmartFields so sync/modify is called right after use - // we should time this call. it might be fine to just stick in the outer bucket loop - auto mxyz = sierra::nalu::MakeSmartField()(modelCoords); - auto cxyz = sierra::nalu::MakeSmartField()(modelCoordsCopy); - for (auto b : bkts) { - for (size_t in = 0; in < b->size(); in++) { - - auto node = (*b)[in]; // mesh node and NOT YAML node - - for (int d = 0; d < nDim; ++d) { - cxyz(node)[d] = mxyz(node)[d]; - } - } // end for loop - in index - } // end for loop - bkts + // we should time this call. it might be fine to just stick in the outer + // bucket loop + auto mxyz = + sierra::nalu::MakeSmartField()(modelCoords); + auto cxyz = sierra::nalu::MakeSmartField()( + modelCoordsCopy); + for (auto b : bkts) { + for (size_t in = 0; in < b->size(); in++) { + + auto node = (*b)[in]; // mesh node and NOT YAML node + + for (int d = 0; d < nDim; ++d) { + cxyz(node)[d] = mxyz(node)[d]; + } + } // end for loop - in index + } // end for loop - bkts } // create mesh transformation algorithm class @@ -215,32 +217,38 @@ TEST(meshMotion, NGP_initialize) // get fields to be tested { // Scope limiting braces again... - auto oxyz = realm.fieldManager_->get_legacy_smart_field("coordinates_copy"); - auto xyz = realm.fieldManager_->get_legacy_smart_field("current_coordinates"); - auto vel = realm.fieldManager_->get_legacy_smart_field("mesh_velocity"); - - for (auto b : bkts) { - for (size_t in = 0; in < b->size(); in++) { - - auto node = (*b)[in]; // mesh node and NOT YAML node - - sierra::nalu::mm::TransMatType transMat = - eval_transformation(realm, currTime, oxyz(node)); - - std::vector gold_norm_xyz = eval_coords(transMat, oxyz(node)); - std::vector gold_norm_vel = - eval_vel(currTime, transMat, oxyz(node), &gold_norm_xyz[0]); - - EXPECT_NEAR(xyz(node)[0], gold_norm_xyz[0], testTol); - EXPECT_NEAR(xyz(node)[1], gold_norm_xyz[1], testTol); - EXPECT_NEAR(xyz(node)[2], gold_norm_xyz[2], testTol); - - EXPECT_NEAR(vel(node)[0], gold_norm_vel[0], testTol); - EXPECT_NEAR(vel(node)[1], gold_norm_vel[1], testTol); - EXPECT_NEAR(vel(node)[2], gold_norm_vel[2], testTol); - } // end for loop - in index - } // end for loop - bkts -} + auto oxyz = + realm.fieldManager_->get_legacy_smart_field( + "coordinates_copy"); + auto xyz = + realm.fieldManager_->get_legacy_smart_field( + "current_coordinates"); + auto vel = + realm.fieldManager_->get_legacy_smart_field( + "mesh_velocity"); + + for (auto b : bkts) { + for (size_t in = 0; in < b->size(); in++) { + + auto node = (*b)[in]; // mesh node and NOT YAML node + + sierra::nalu::mm::TransMatType transMat = + eval_transformation(realm, currTime, oxyz(node)); + + std::vector gold_norm_xyz = eval_coords(transMat, oxyz(node)); + std::vector gold_norm_vel = + eval_vel(currTime, transMat, oxyz(node), &gold_norm_xyz[0]); + + EXPECT_NEAR(xyz(node)[0], gold_norm_xyz[0], testTol); + EXPECT_NEAR(xyz(node)[1], gold_norm_xyz[1], testTol); + EXPECT_NEAR(xyz(node)[2], gold_norm_xyz[2], testTol); + + EXPECT_NEAR(vel(node)[0], gold_norm_vel[0], testTol); + EXPECT_NEAR(vel(node)[1], gold_norm_vel[1], testTol); + EXPECT_NEAR(vel(node)[2], gold_norm_vel[2], testTol); + } // end for loop - in index + } // end for loop - bkts + } } TEST(meshMotion, NGP_execute) From b6a6de2e6d8071d01fe0f7aeeb842f14e6c5d785 Mon Sep 17 00:00:00 2001 From: psakiev Date: Sat, 23 Sep 2023 13:13:44 -0600 Subject: [PATCH 36/40] Add additional accessor functions --- include/SmartField.h | 36 +++++++++++++++++++++++++++++++++++ unit_tests/UnitTestNgpMesh1.C | 30 ++++++++++++++--------------- 2 files changed, 51 insertions(+), 15 deletions(-) diff --git a/include/SmartField.h b/include/SmartField.h index 885991da2..eef3ba82c 100644 --- a/include/SmartField.h +++ b/include/SmartField.h @@ -223,6 +223,15 @@ class SmartField< } // --- Default Accessors + template + inline std::enable_if_t< + std::is_same::value && !std::is_same::value, + T>& + get(const Mesh& ngpMesh, stk::mesh::Entity entity, int component) const + { + return stkField_.get(ngpMesh, entity, component); + } + template inline std::enable_if_t< std::is_same::value && !std::is_same::value, @@ -260,6 +269,15 @@ class SmartField< } // --- Const Accessors + template + inline const std::enable_if_t< + std::is_same::value && std::is_same::value, + T>& + get(const Mesh& ngpMesh, stk::mesh::Entity entity, int component) const + { + return stkField_.get(ngpMesh, entity, component); + } + template inline const std::enable_if_t< std::is_same::value && std::is_same::value, @@ -308,6 +326,15 @@ class SmartField< } // --- Default Accessors + template + KOKKOS_INLINE_FUNCTION std::enable_if_t< + std::is_same::value && !std::is_same::value, + T>& + get(const Mesh& ngpMesh, stk::mesh::Entity entity, int component) const + { + return stkField_.get(ngpMesh, entity, component); + } + template KOKKOS_INLINE_FUNCTION std::enable_if_t< std::is_same::value && !std::is_same::value, @@ -345,6 +372,15 @@ class SmartField< } // --- Const Accessors + template + KOKKOS_INLINE_FUNCTION const std::enable_if_t< + std::is_same::value && std::is_same::value, + T>& + get(const Mesh& ngpMesh, stk::mesh::Entity entity, int component) const + { + return stkField_.get(ngpMesh, entity, component); + } + template KOKKOS_INLINE_FUNCTION const std::enable_if_t< std::is_same::value && std::is_same::value, diff --git a/unit_tests/UnitTestNgpMesh1.C b/unit_tests/UnitTestNgpMesh1.C index 61e80cee3..39a762cbb 100644 --- a/unit_tests/UnitTestNgpMesh1.C +++ b/unit_tests/UnitTestNgpMesh1.C @@ -13,6 +13,7 @@ #include "KokkosInterface.h" #include "SimdInterface.h" #include "ElemDataRequests.h" +#include "FieldManager.h" #include "stk_mesh/base/Ngp.hpp" #include "stk_mesh/base/Types.hpp" @@ -94,6 +95,7 @@ TEST(NgpMesh, NGPMesh) void test_ngp_mesh_field_values( + sierra::nalu::FieldManager& fieldManager, const stk::mesh::BulkData& bulk, VectorFieldType* velocity, GenericFieldType* massFlowRate) @@ -104,11 +106,11 @@ test_ngp_mesh_field_values( const stk::mesh::BucketVector& elemBuckets = bulk.get_buckets(stk::topology::ELEM_RANK, all_local); + auto ngpVelocity = fieldManager.get_device_smart_field + ("velocity"); + auto ngpMassFlowRate = fieldManager.get_device_smart_field + ("mass_flow_rate"); stk::mesh::NgpMesh ngpMesh(bulk); - stk::mesh::NgpField& ngpVelocity = - stk::mesh::get_updated_ngp_field(*velocity); - stk::mesh::NgpField& ngpMassFlowRate = - stk::mesh::get_updated_ngp_field(*massFlowRate); const int bytes_per_team = 0; const int bytes_per_thread = 0; @@ -153,24 +155,22 @@ test_ngp_mesh_field_values( }); }); - ngpVelocity.modify_on_device(); - ngpMassFlowRate.modify_on_device(); - ngpVelocity.sync_to_host(); - ngpMassFlowRate.sync_to_host(); + auto flowRateData = fieldManager.get_legacy_smart_field + ("mass_flow_rate"); + auto velocityData = fieldManager.get_legacy_smart_field + ("velocity"); const double tol = 1.0e-16; for (const stk::mesh::Bucket* b : elemBuckets) { for (stk::mesh::Entity elem : *b) { - const double* flowRateData = stk::mesh::field_data(*massFlowRate, elem); - EXPECT_NEAR(flowRate, *flowRateData, tol); + EXPECT_NEAR(flowRate, *flowRateData(elem), tol); const stk::mesh::Entity* nodes = bulk.begin_nodes(elem); const unsigned numNodes = bulk.num_nodes(elem); for (unsigned n = 0; n < numNodes; ++n) { - const double* velocityData = stk::mesh::field_data(*velocity, nodes[n]); - EXPECT_NEAR(xVel, velocityData[0], tol); - EXPECT_NEAR(yVel, velocityData[1], tol); - EXPECT_NEAR(zVel, velocityData[2], tol); + EXPECT_NEAR(xVel, velocityData(nodes[n])[0], tol); + EXPECT_NEAR(yVel, velocityData(nodes[n])[1], tol); + EXPECT_NEAR(zVel, velocityData(nodes[n])[2], tol); } } } @@ -180,7 +180,7 @@ TEST_F(Hex8MeshWithNSOFields, NGPMeshField) { fill_mesh_and_initialize_test_fields("generated:2x2x2"); - test_ngp_mesh_field_values(*bulk, velocity, massFlowRate); + test_ngp_mesh_field_values(*fieldManager, *bulk, velocity, massFlowRate); } struct TestKernelWithNgpField From c69329c846f89274378921c12f6b8a022ad3dd6b Mon Sep 17 00:00:00 2001 From: Philip Sakievich Date: Mon, 25 Sep 2023 16:28:37 -0600 Subject: [PATCH 37/40] Fix unit tests --- src/FieldRegistry.C | 5 +++-- unit_tests/UnitTestNgpMesh1.C | 22 +++++++++++++--------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/FieldRegistry.C b/src/FieldRegistry.C index bb2829af6..c6db47e8a 100644 --- a/src/FieldRegistry.C +++ b/src/FieldRegistry.C @@ -44,6 +44,7 @@ Registry() static const std::map registry = { {"average_dudx" , SingleStateNodalTensor}, {"coordinates", SingleStateNodalVector}, + {"coordinates_copy", SingleStateNodalVector}, // Used in testing {"current_coordinates", SingleStateNodalVector}, {"density", SingleStateNodalScalar}, {"dhdx", SingleStateNodalVector}, @@ -57,7 +58,7 @@ Registry() {"dwdx", SingleStateNodalVector}, {"edge_area_vector", SingleStateEdgeVector}, {"effective_viscosity" , SingleStateNodalScalar}, - {"elemCentroid", SingleStateElemVector}, + {"elemCentroid", SingleStateElemVector}, {"element_volume", SingleStateElemScalar}, {"elemScalarField", SingleStateElemScalar}, // Used in testing {"elemTensorField", SingleStateElemGeneric}, // Used in testing @@ -66,7 +67,7 @@ Registry() {"Gju", SingleStateNodeGeneric}, {"hypre_global_id", HypreId}, {"iblank", NodalScalarInt}, - {"idField", SingleStateNodalScalar}, + {"idField", SingleStateNodalScalar}, {"mass_flow_rate_scs", SingleStateElemGeneric}, {"mesh_displacement", MultiStateNodalVector}, {"mesh_velocity", SingleStateNodalVector}, diff --git a/unit_tests/UnitTestNgpMesh1.C b/unit_tests/UnitTestNgpMesh1.C index 39a762cbb..a01fb27b2 100644 --- a/unit_tests/UnitTestNgpMesh1.C +++ b/unit_tests/UnitTestNgpMesh1.C @@ -106,10 +106,11 @@ test_ngp_mesh_field_values( const stk::mesh::BucketVector& elemBuckets = bulk.get_buckets(stk::topology::ELEM_RANK, all_local); - auto ngpVelocity = fieldManager.get_device_smart_field - ("velocity"); - auto ngpMassFlowRate = fieldManager.get_device_smart_field - ("mass_flow_rate"); + auto ngpVelocity = + fieldManager.get_device_smart_field("velocity"); + auto ngpMassFlowRate = + fieldManager.get_device_smart_field( + "mass_flow_rate_scs"); stk::mesh::NgpMesh ngpMesh(bulk); const int bytes_per_team = 0; @@ -155,11 +156,14 @@ test_ngp_mesh_field_values( }); }); - - auto flowRateData = fieldManager.get_legacy_smart_field - ("mass_flow_rate"); - auto velocityData = fieldManager.get_legacy_smart_field - ("velocity"); + auto flowRateData = + fieldManager + .get_legacy_smart_field( + "mass_flow_rate_scs"); + auto velocityData = + fieldManager + .get_legacy_smart_field( + "velocity"); const double tol = 1.0e-16; for (const stk::mesh::Bucket* b : elemBuckets) { for (stk::mesh::Entity elem : *b) { From 733babacf289171bf286e889e2922736a1679650 Mon Sep 17 00:00:00 2001 From: psakiev Date: Tue, 26 Sep 2023 20:46:20 -0600 Subject: [PATCH 38/40] Split classes --- include/SmartField.h | 223 +++++++++++++++++++++++++------------------ src/SmartField.C | 6 +- 2 files changed, 133 insertions(+), 96 deletions(-) diff --git a/include/SmartField.h b/include/SmartField.h index eef3ba82c..54eac76cd 100644 --- a/include/SmartField.h +++ b/include/SmartField.h @@ -148,24 +148,18 @@ class SmartField< } }; -// DEVICE and HOST implementations +// DEVICE // // These should always be used as part of lambda/functor captures // using copy by value. // -// SFINAE is used to remove KOKKOS_INLINE_FUNCTION type decorators for HOST -// MEMSPACE -template +template class SmartField< FieldType, - MEMSPACE, - ACCESS, - typename std::enable_if_t< - std::is_base_of::value>> + tags::DEVICE, + ACCESS> { private: - static constexpr bool is_device_space_{std::is_same::value}; - static constexpr bool is_read_{ std::is_same::value || std::is_same::value}; @@ -180,88 +174,81 @@ class SmartField< public: using T = typename FieldType::value_type; + KOKKOS_FUNCTION SmartField(FieldType fieldRef) : stkField_(fieldRef) {} SmartField(const SmartField& src) : stkField_(src.stkField_), is_copy_constructed_(true) { + KOKKOS_IF_ON_HOST( if (is_read_) { - if (is_device_space_) { - stkField_.sync_to_device(); - } else { - stkField_.sync_to_host(); - } + stkField_.sync_to_device(); } else { stkField_.clear_sync_state(); - } + }); } + KOKKOS_FUNCTION ~SmartField() { - if (is_write_) { - if (is_copy_constructed_) { + KOKKOS_IF_ON_HOST( + if (is_write_ && is_copy_constructed_) { // NgpFieldBase 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. - if (is_device_space_) - stkField_.modify_on_device(); - else - stkField_.modify_on_host(); - } - } + stkField_.modify_on_device(); + }); } //************************************************************ - // Host functions (Remove KOKKOS_INLINE_FUNCTION decorators) + // Device functions //************************************************************ - template - inline std::enable_if_t::value, unsigned> - get_ordinal() const + KOKKOS_INLINE_FUNCTION + unsigned get_ordinal() const { return stkField_.get_ordinal(); } // --- Default Accessors - template - inline std::enable_if_t< - std::is_same::value && !std::is_same::value, + template + KOKKOS_INLINE_FUNCTION std::enable_if_t::value, T>& get(const Mesh& ngpMesh, stk::mesh::Entity entity, int component) const { return stkField_.get(ngpMesh, entity, component); } - template - inline std::enable_if_t< - std::is_same::value && !std::is_same::value, + template + KOKKOS_INLINE_FUNCTION std::enable_if_t< + !std::is_same::value, T>& get(stk::mesh::FastMeshIndex& index, int component) const { return stkField_.get(index, component); } - template - inline std::enable_if_t< - std::is_same::value && !std::is_same::value, + template + KOKKOS_INLINE_FUNCTION std::enable_if_t< + !std::is_same::value, T>& get(MeshIndex index, int component) const { return stkField_.get(index, component); } - template - inline std::enable_if_t< - std::is_same::value && !std::is_same::value, + template + KOKKOS_INLINE_FUNCTION std::enable_if_t< + !std::is_same::value, T>& operator()(const stk::mesh::FastMeshIndex& index, int component) const { return stkField_(index, component); } - template - inline std::enable_if_t< - std::is_same::value && !std::is_same::value, + template + KOKKOS_INLINE_FUNCTION std::enable_if_t< + !std::is_same::value, T>& operator()(const MeshIndex index, int component) const { @@ -269,102 +256,152 @@ class SmartField< } // --- Const Accessors - template - inline const std::enable_if_t< - std::is_same::value && std::is_same::value, + template + KOKKOS_INLINE_FUNCTION const std::enable_if_t< + std::is_same::value, T>& get(const Mesh& ngpMesh, stk::mesh::Entity entity, int component) const { return stkField_.get(ngpMesh, entity, component); } - template - inline const std::enable_if_t< - std::is_same::value && std::is_same::value, + template + KOKKOS_INLINE_FUNCTION const std::enable_if_t< + std::is_same::value, T>& get(stk::mesh::FastMeshIndex& index, int component) const { return stkField_.get(index, component); } - template - inline const std::enable_if_t< - std::is_same::value && std::is_same::value, + template + KOKKOS_INLINE_FUNCTION const std::enable_if_t< + std::is_same::value, T>& get(MeshIndex index, int component) const { return stkField_.get(index, component); } - template - inline const std::enable_if_t< - std::is_same::value && std::is_same::value, + template + KOKKOS_INLINE_FUNCTION const std::enable_if_t< + std::is_same::value, T>& operator()(const stk::mesh::FastMeshIndex& index, int component) const { return stkField_(index, component); } - template - inline const std::enable_if_t< - std::is_same::value && std::is_same::value, + template + KOKKOS_INLINE_FUNCTION const std::enable_if_t< + std::is_same::value, T>& operator()(const MeshIndex index, int component) const { return stkField_(index, component); } +}; + +// HOST implementations +// +// These should always be used as part of lambda/functor captures +// using copy by value. +// +template +class SmartField< + FieldType, + tags::HOST, + ACCESS> +{ +private: + static constexpr bool is_read_{ + std::is_same::value || + std::is_same::value}; + + static constexpr bool is_write_{ + std::is_same::value || + std::is_same::value}; + + FieldType stkField_; + const bool is_copy_constructed_{false}; + +public: + using T = typename FieldType::value_type; + + SmartField(FieldType fieldRef) : stkField_(fieldRef) {} + + SmartField(const SmartField& src) + : stkField_(src.stkField_), is_copy_constructed_(true) + { + if (is_read_) { + stkField_.sync_to_host(); + } else { + stkField_.clear_sync_state(); + } + } + + ~SmartField() + { + if (is_write_) { + if (is_copy_constructed_) { + // NgpFieldBase 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. + stkField_.modify_on_host(); + } + } + } //************************************************************ - // Device functions + // Host functions (Remove KOKKOS_INLINE_FUNCTION decorators) //************************************************************ - template - KOKKOS_INLINE_FUNCTION - std::enable_if_t::value, unsigned> - get_ordinal() const + inline unsigned + get_ordinal() const { return stkField_.get_ordinal(); } // --- Default Accessors - template - KOKKOS_INLINE_FUNCTION std::enable_if_t< - std::is_same::value && !std::is_same::value, + template + inline std::enable_if_t< + !std::is_same::value, T>& get(const Mesh& ngpMesh, stk::mesh::Entity entity, int component) const { return stkField_.get(ngpMesh, entity, component); } - template - KOKKOS_INLINE_FUNCTION std::enable_if_t< - std::is_same::value && !std::is_same::value, + template + inline std::enable_if_t< + !std::is_same::value, T>& get(stk::mesh::FastMeshIndex& index, int component) const { return stkField_.get(index, component); } - template - KOKKOS_INLINE_FUNCTION std::enable_if_t< - std::is_same::value && !std::is_same::value, + template + inline std::enable_if_t< + !std::is_same::value, T>& get(MeshIndex index, int component) const { return stkField_.get(index, component); } - template - KOKKOS_INLINE_FUNCTION std::enable_if_t< - std::is_same::value && !std::is_same::value, + template + inline std::enable_if_t< + !std::is_same::value, T>& operator()(const stk::mesh::FastMeshIndex& index, int component) const { return stkField_(index, component); } - template - KOKKOS_INLINE_FUNCTION std::enable_if_t< - std::is_same::value && !std::is_same::value, + template + inline std::enable_if_t< + !std::is_same::value, T>& operator()(const MeshIndex index, int component) const { @@ -372,45 +409,45 @@ class SmartField< } // --- Const Accessors - template - KOKKOS_INLINE_FUNCTION const std::enable_if_t< - std::is_same::value && std::is_same::value, + template + inline const std::enable_if_t< + std::is_same::value, T>& get(const Mesh& ngpMesh, stk::mesh::Entity entity, int component) const { return stkField_.get(ngpMesh, entity, component); } - template - KOKKOS_INLINE_FUNCTION const std::enable_if_t< - std::is_same::value && std::is_same::value, + template + inline const std::enable_if_t< + std::is_same::value, T>& get(stk::mesh::FastMeshIndex& index, int component) const { return stkField_.get(index, component); } - template - KOKKOS_INLINE_FUNCTION const std::enable_if_t< - std::is_same::value && std::is_same::value, + template + inline const std::enable_if_t< + std::is_same::value, T>& get(MeshIndex index, int component) const { return stkField_.get(index, component); } - template - KOKKOS_INLINE_FUNCTION const std::enable_if_t< - std::is_same::value && std::is_same::value, + template + inline const std::enable_if_t< + std::is_same::value, T>& operator()(const stk::mesh::FastMeshIndex& index, int component) const { return stkField_(index, component); } - template - KOKKOS_INLINE_FUNCTION const std::enable_if_t< - std::is_same::value && std::is_same::value, + template + inline const std::enable_if_t< + std::is_same::value, T>& operator()(const MeshIndex index, int component) const { diff --git a/src/SmartField.C b/src/SmartField.C index 4fc1948a9..2faf621d7 100644 --- a/src/SmartField.C +++ b/src/SmartField.C @@ -22,9 +22,9 @@ using namespace tags; template class SmartField, HOST, READ_WRITE> #define EXPLICIT_TYPE_INSTANTIATOR_LEGACY(T) \ - template class SmartField, HOST, READ>; \ - template class SmartField, HOST, WRITE_ALL>; \ - template class SmartField, HOST, READ_WRITE> + template class SmartField, LEGACY, READ>; \ + template class SmartField, LEGACY, WRITE_ALL>; \ + template class SmartField, LEGACY, READ_WRITE> EXPLICIT_TYPE_INSTANTIATOR_NGP(int); EXPLICIT_TYPE_INSTANTIATOR_NGP(double); From 9ad8018fe1035a56c1512c5b97a695246a40be0c Mon Sep 17 00:00:00 2001 From: Philip Sakievich Date: Tue, 26 Sep 2023 21:40:01 -0600 Subject: [PATCH 39/40] Test on device and format --- include/SmartField.h | 150 +++++++++++++------------------------------ src/SmartField.C | 4 +- 2 files changed, 48 insertions(+), 106 deletions(-) diff --git a/include/SmartField.h b/include/SmartField.h index 54eac76cd..9928ae3a3 100644 --- a/include/SmartField.h +++ b/include/SmartField.h @@ -53,11 +53,7 @@ using namespace tags; * * NOTE: this implementation makes heavy use of SFINAE */ -template < - typename FieldType, - typename MEMSPACE, - typename ACCESS, - typename Enable = void> +template class SmartField { }; @@ -68,12 +64,7 @@ class SmartField // This Type should be used as close to a bucket loop as possible, and not // stored as a class member since sync/modify are marked in the ctor/dtor template -class SmartField< - FieldType, - LEGACY, - ACCESS, - typename std::enable_if_t< - std::is_base_of::value>> +class SmartField { private: @@ -154,10 +145,7 @@ class SmartField< // using copy by value. // template -class SmartField< - FieldType, - tags::DEVICE, - ACCESS> +class SmartField { private: static constexpr bool is_read_{ @@ -177,27 +165,25 @@ class SmartField< KOKKOS_FUNCTION SmartField(FieldType fieldRef) : stkField_(fieldRef) {} + KOKKOS_FUNCTION SmartField(const SmartField& src) : stkField_(src.stkField_), is_copy_constructed_(true) { KOKKOS_IF_ON_HOST( - if (is_read_) { - stkField_.sync_to_device(); - } else { - stkField_.clear_sync_state(); - }); + if (is_read_) { stkField_.sync_to_device(); } else { + stkField_.clear_sync_state(); + }); } KOKKOS_FUNCTION ~SmartField() { - KOKKOS_IF_ON_HOST( - if (is_write_ && is_copy_constructed_) { - // NgpFieldBase 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. - stkField_.modify_on_device(); + KOKKOS_IF_ON_HOST(if (is_write_ && is_copy_constructed_) { + // NgpFieldBase 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. + stkField_.modify_on_device(); }); } @@ -205,51 +191,39 @@ class SmartField< // Device functions //************************************************************ KOKKOS_INLINE_FUNCTION - unsigned get_ordinal() const - { - return stkField_.get_ordinal(); - } + unsigned get_ordinal() const { return stkField_.get_ordinal(); } // --- Default Accessors template - KOKKOS_INLINE_FUNCTION std::enable_if_t::value, - T>& + KOKKOS_INLINE_FUNCTION std::enable_if_t::value, T>& get(const Mesh& ngpMesh, stk::mesh::Entity entity, int component) const { return stkField_.get(ngpMesh, entity, component); } template - KOKKOS_INLINE_FUNCTION std::enable_if_t< - !std::is_same::value, - T>& + KOKKOS_INLINE_FUNCTION std::enable_if_t::value, T>& get(stk::mesh::FastMeshIndex& index, int component) const { return stkField_.get(index, component); } template - KOKKOS_INLINE_FUNCTION std::enable_if_t< - !std::is_same::value, - T>& + KOKKOS_INLINE_FUNCTION std::enable_if_t::value, T>& get(MeshIndex index, int component) const { return stkField_.get(index, component); } template - KOKKOS_INLINE_FUNCTION std::enable_if_t< - !std::is_same::value, - T>& + KOKKOS_INLINE_FUNCTION std::enable_if_t::value, T>& operator()(const stk::mesh::FastMeshIndex& index, int component) const { return stkField_(index, component); } template - KOKKOS_INLINE_FUNCTION std::enable_if_t< - !std::is_same::value, - T>& + KOKKOS_INLINE_FUNCTION std::enable_if_t::value, T>& operator()(const MeshIndex index, int component) const { return stkField_(index, component); @@ -257,46 +231,41 @@ class SmartField< // --- Const Accessors template - KOKKOS_INLINE_FUNCTION const std::enable_if_t< - std::is_same::value, - T>& - get(const Mesh& ngpMesh, stk::mesh::Entity entity, int component) const + KOKKOS_INLINE_FUNCTION const + std::enable_if_t::value, T>& + get(const Mesh& ngpMesh, stk::mesh::Entity entity, int component) const { return stkField_.get(ngpMesh, entity, component); } template - KOKKOS_INLINE_FUNCTION const std::enable_if_t< - std::is_same::value, - T>& - get(stk::mesh::FastMeshIndex& index, int component) const + KOKKOS_INLINE_FUNCTION const + std::enable_if_t::value, T>& + get(stk::mesh::FastMeshIndex& index, int component) const { return stkField_.get(index, component); } template - KOKKOS_INLINE_FUNCTION const std::enable_if_t< - std::is_same::value, - T>& - get(MeshIndex index, int component) const + KOKKOS_INLINE_FUNCTION const + std::enable_if_t::value, T>& + get(MeshIndex index, int component) const { return stkField_.get(index, component); } template - KOKKOS_INLINE_FUNCTION const std::enable_if_t< - std::is_same::value, - T>& - operator()(const stk::mesh::FastMeshIndex& index, int component) const + KOKKOS_INLINE_FUNCTION const + std::enable_if_t::value, T>& + operator()(const stk::mesh::FastMeshIndex& index, int component) const { return stkField_(index, component); } template - KOKKOS_INLINE_FUNCTION const std::enable_if_t< - std::is_same::value, - T>& - operator()(const MeshIndex index, int component) const + KOKKOS_INLINE_FUNCTION const + std::enable_if_t::value, T>& + operator()(const MeshIndex index, int component) const { return stkField_(index, component); } @@ -308,10 +277,7 @@ class SmartField< // using copy by value. // template -class SmartField< - FieldType, - tags::HOST, - ACCESS> +class SmartField { private: static constexpr bool is_read_{ @@ -356,53 +322,39 @@ class SmartField< //************************************************************ // Host functions (Remove KOKKOS_INLINE_FUNCTION decorators) //************************************************************ - inline unsigned - get_ordinal() const - { - return stkField_.get_ordinal(); - } + inline unsigned get_ordinal() const { return stkField_.get_ordinal(); } // --- Default Accessors template - inline std::enable_if_t< - !std::is_same::value, - T>& + inline std::enable_if_t::value, T>& get(const Mesh& ngpMesh, stk::mesh::Entity entity, int component) const { return stkField_.get(ngpMesh, entity, component); } template - inline std::enable_if_t< - !std::is_same::value, - T>& + inline std::enable_if_t::value, T>& get(stk::mesh::FastMeshIndex& index, int component) const { return stkField_.get(index, component); } template - inline std::enable_if_t< - !std::is_same::value, - T>& + inline std::enable_if_t::value, T>& get(MeshIndex index, int component) const { return stkField_.get(index, component); } template - inline std::enable_if_t< - !std::is_same::value, - T>& + inline std::enable_if_t::value, T>& operator()(const stk::mesh::FastMeshIndex& index, int component) const { return stkField_(index, component); } template - inline std::enable_if_t< - !std::is_same::value, - T>& + inline std::enable_if_t::value, T>& operator()(const MeshIndex index, int component) const { return stkField_(index, component); @@ -410,45 +362,35 @@ class SmartField< // --- Const Accessors template - inline const std::enable_if_t< - std::is_same::value, - T>& + inline const std::enable_if_t::value, T>& get(const Mesh& ngpMesh, stk::mesh::Entity entity, int component) const { return stkField_.get(ngpMesh, entity, component); } template - inline const std::enable_if_t< - std::is_same::value, - T>& + inline const std::enable_if_t::value, T>& get(stk::mesh::FastMeshIndex& index, int component) const { return stkField_.get(index, component); } template - inline const std::enable_if_t< - std::is_same::value, - T>& + inline const std::enable_if_t::value, T>& get(MeshIndex index, int component) const { return stkField_.get(index, component); } template - inline const std::enable_if_t< - std::is_same::value, - T>& + inline const std::enable_if_t::value, T>& operator()(const stk::mesh::FastMeshIndex& index, int component) const { return stkField_(index, component); } template - inline const std::enable_if_t< - std::is_same::value, - T>& + inline const std::enable_if_t::value, T>& operator()(const MeshIndex index, int component) const { return stkField_(index, component); diff --git a/src/SmartField.C b/src/SmartField.C index 2faf621d7..6b1b48d1c 100644 --- a/src/SmartField.C +++ b/src/SmartField.C @@ -22,8 +22,8 @@ using namespace tags; template class SmartField, HOST, READ_WRITE> #define EXPLICIT_TYPE_INSTANTIATOR_LEGACY(T) \ - template class SmartField, LEGACY, READ>; \ - template class SmartField, LEGACY, WRITE_ALL>; \ + template class SmartField, LEGACY, READ>; \ + template class SmartField, LEGACY, WRITE_ALL>; \ template class SmartField, LEGACY, READ_WRITE> EXPLICIT_TYPE_INSTANTIATOR_NGP(int); From d68eba4e0d6cb7d8a497354d38a075099a30ad0b Mon Sep 17 00:00:00 2001 From: Philip Sakievich Date: Tue, 26 Sep 2023 21:53:29 -0600 Subject: [PATCH 40/40] Add some convenience type names --- include/SmartField.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/SmartField.h b/include/SmartField.h index 9928ae3a3..bd880af2d 100644 --- a/include/SmartField.h +++ b/include/SmartField.h @@ -434,6 +434,13 @@ struct MakeSmartField return SmartField, DEVICE, ACCESS>(field); } }; + +template +using SmartDeviceField = SmartField; +template +using SmartHostField = SmartField; +template +using SmartLegacyField = SmartField; } // namespace sierra::nalu #endif