From 341f65f3f6ceb8118ae2ba036920be90e26a7e4c Mon Sep 17 00:00:00 2001 From: Namjae Choi Date: Thu, 2 Apr 2026 16:40:15 -0600 Subject: [PATCH 01/14] Enable Kokkos MetaPhysicL #32699 --- framework/kokkos.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/kokkos.mk b/framework/kokkos.mk index 46c86b60c917..8c7c010235b5 100644 --- a/framework/kokkos.mk +++ b/framework/kokkos.mk @@ -110,7 +110,7 @@ else CXXFLAGS += -DMOOSE_ENABLE_KOKKOS_GPU=1 endif -KOKKOS_CXXFLAGS += -DMOOSE_KOKKOS_SCOPE=1 -fPIC +KOKKOS_CXXFLAGS += -DMOOSE_KOKKOS_SCOPE=1 -DMETAPHYSICL_KOKKOS_COMPILATION=1 -fPIC KOKKOS_LDFLAGS += $(libmesh_LDFLAGS) KOKKOS_INCLUDE = $(libmesh_INCLUDE) KOKKOS_LIBS = $(libmesh_LIBS) From d199fc241c5e17c7feaa5863235c01b9edfc4ec4 Mon Sep 17 00:00:00 2001 From: Namjae Choi Date: Thu, 2 Apr 2026 16:41:51 -0600 Subject: [PATCH 02/14] Support computing residual and Jacobian together #32699 --- .../include/systems/NonlinearSystemBase.h | 8 +- .../systems/KokkosNonlinearSystemBase.K | 116 ++++++++++++++++++ framework/src/systems/NonlinearSystemBase.C | 41 ++++--- 3 files changed, 150 insertions(+), 15 deletions(-) diff --git a/framework/include/systems/NonlinearSystemBase.h b/framework/include/systems/NonlinearSystemBase.h index 3b13512533dd..121d001b8964 100644 --- a/framework/include/systems/NonlinearSystemBase.h +++ b/framework/include/systems/NonlinearSystemBase.h @@ -347,6 +347,11 @@ class NonlinearSystemBase : public SolverSystem, public PerfGraphInterface void computeResidualAndJacobianInternal(const std::set & vector_tags, const std::set & matrix_tags); +#ifdef MOOSE_KOKKOS_ENABLED + void computeKokkosResidualAndJacobian(const std::set & vector_tags, + const std::set & matrix_tags); +#endif + /** * Form a residual vector for a given tag */ @@ -802,7 +807,8 @@ class NonlinearSystemBase : public SolverSystem, public PerfGraphInterface /** * compute the residual and Jacobian for nodal boundary conditions */ - void computeNodalBCsResidualAndJacobian(); + void computeNodalBCsResidualAndJacobian(const std::set & vector_tags, + const std::set & matrix_tags); /** * Form multiple matrices for all the tags. Users should not call this func directly. diff --git a/framework/src/kokkos/systems/KokkosNonlinearSystemBase.K b/framework/src/kokkos/systems/KokkosNonlinearSystemBase.K index ff1afa436e27..9f91b74ca0c7 100644 --- a/framework/src/kokkos/systems/KokkosNonlinearSystemBase.K +++ b/framework/src/kokkos/systems/KokkosNonlinearSystemBase.K @@ -416,3 +416,119 @@ NonlinearSystemBase::computeKokkosJacobian(const std::set & tags) system.clearActiveSolutionTags(); } } + +void +NonlinearSystemBase::computeKokkosResidualAndJacobian(const std::set & vector_tags, + const std::set & matrix_tags) +{ + TIME_SECTION("computeKokkosResidualAndJacobian", 1); + + if (!_kokkos_kernels.size() && !_kokkos_nodal_kernels.size() && !_kokkos_integrated_bcs.size() && + !_kokkos_nodal_bcs.size()) + return; + + // Resolve dependencies + + auto & systems = _fe_problem.getKokkosSystems(); + + systems[number()].setActiveResidualTags(vector_tags); + systems[number()].setActiveMatrixTags(matrix_tags); + + std::set needed_moose_vars; + std::set needed_fe_var_vector_tags; + std::unordered_set needed_mat_props; + + for (auto tag : _fe_problem.getVectorTags(Moose::VECTOR_TAG_SOLUTION)) + needed_fe_var_vector_tags.insert(tag._id); + + _kokkos_kernels.updateVariableDependency(needed_moose_vars); + _kokkos_kernels.updateFEVariableCoupledVectorTagDependency(needed_fe_var_vector_tags); + _kokkos_kernels.updateMatPropDependency(needed_mat_props); + + _kokkos_nodal_kernels.updateVariableDependency(needed_moose_vars); + _kokkos_nodal_kernels.updateFEVariableCoupledVectorTagDependency(needed_fe_var_vector_tags); + + _kokkos_integrated_bcs.updateVariableDependency(needed_moose_vars); + _kokkos_integrated_bcs.updateFEVariableCoupledVectorTagDependency(needed_fe_var_vector_tags); + _kokkos_integrated_bcs.updateMatPropDependency(needed_mat_props); + + _kokkos_nodal_bcs.updateVariableDependency(needed_moose_vars); + _kokkos_nodal_bcs.updateFEVariableCoupledVectorTagDependency(needed_fe_var_vector_tags); + + if (needed_mat_props.size()) + { + _fe_problem.getKokkosMaterialsWarehouse().updateVariableDependency(needed_moose_vars); + _fe_problem.getKokkosMaterialsWarehouse().updateFEVariableCoupledVectorTagDependency( + needed_fe_var_vector_tags); + } + + // Copy vectors and cache variable values at element quadature points + + for (auto & system : systems) + { + system.setActiveVariables(needed_moose_vars); + system.setActiveSolutionTags(needed_fe_var_vector_tags); + + { + TIME_SECTION("KokkosPreallocateAndCopy", 1); + system.sync(Moose::Kokkos::MemcpyType::HOST_TO_DEVICE); + } + { + TIME_SECTION("KokkosReinit", 1); + system.reinit(); + } + } + + systems.copyToDevice(); + + { + TIME_SECTION("KokkosMaterial", 1); + + // Compute material properties + + if (needed_mat_props.size()) + { + _fe_problem.prepareKokkosMaterials(needed_mat_props); + _fe_problem.reinitKokkosMaterials(); + } + } + + { + TIME_SECTION("KokkosKernel", 1); + + // Compute kernels + + for (auto kernel : _kokkos_kernels.getActiveObjects()) + kernel->computeResidualAndJacobian(); + + for (auto nodal_kernel : _kokkos_nodal_kernels.getActiveObjects()) + nodal_kernel->computeResidualAndJacobian(); + + for (auto ibc : _kokkos_integrated_bcs.getActiveObjects()) + ibc->computeResidualAndJacobian(); + + /// Nodal BC residuals are computed separately + for (auto nbc : _kokkos_nodal_bcs.getActiveObjects()) + nbc->computeJacobian(); + } + + // Close and restore vectors and matrices + + { + TIME_SECTION("KokkosCopy", 1); + + for (auto & system : systems) + system.sync(Moose::Kokkos::MemcpyType::DEVICE_TO_HOST); + } + + // Clear + + systems[number()].clearActiveResidualTags(); + systems[number()].clearActiveMatrixTags(); + + for (auto & system : systems) + { + system.clearActiveVariables(); + system.clearActiveSolutionTags(); + } +} diff --git a/framework/src/systems/NonlinearSystemBase.C b/framework/src/systems/NonlinearSystemBase.C index 1e4ad58587ff..2ae8e3a99ce0 100644 --- a/framework/src/systems/NonlinearSystemBase.C +++ b/framework/src/systems/NonlinearSystemBase.C @@ -933,7 +933,7 @@ NonlinearSystemBase::computeResidualAndJacobianTags(const std::set & vect residual.close(); } - computeNodalBCsResidualAndJacobian(); + computeNodalBCsResidualAndJacobian(vector_tags, matrix_tags); closeTaggedVectors(vector_tags); closeTaggedMatrices(matrix_tags); } @@ -1775,13 +1775,6 @@ NonlinearSystemBase::computeResidualInternal(const std::set & tags) residualSetup(); -#ifdef MOOSE_KOKKOS_ENABLED - if (_fe_problem.hasKokkosResidualObjects()) - computeKokkosResidual(tags); -#endif - - const auto vector_tag_data = _fe_problem.getVectorTags(tags); - // Residual contributions from UOs - for now this is used for ray tracing // and ray kernels that contribute to the residual (think line sources) std::vector uos; @@ -1803,6 +1796,11 @@ NonlinearSystemBase::computeResidualInternal(const std::set & tags) for (unsigned int tid = 0; tid < libMesh::n_threads(); tid++) _fe_problem.reinitScalars(tid); +#ifdef MOOSE_KOKKOS_ENABLED + if (_fe_problem.hasKokkosResidualObjects()) + computeKokkosResidual(tags); +#endif + // residual contributions from the domain PARALLEL_TRY { @@ -2045,6 +2043,11 @@ NonlinearSystemBase::computeResidualAndJacobianInternal(const std::set & for (unsigned int tid = 0; tid < libMesh::n_threads(); tid++) _fe_problem.reinitScalars(tid); +#ifdef MOOSE_KOKKOS_ENABLED + if (_fe_problem.hasKokkosResidualObjects()) + computeKokkosResidualAndJacobian(vector_tags, matrix_tags); +#endif + // residual contributions from the domain PARALLEL_TRY { @@ -2172,8 +2175,18 @@ NonlinearSystemBase::computeNodalBCs(const std::set & tags) } void -NonlinearSystemBase::computeNodalBCsResidualAndJacobian() +NonlinearSystemBase::computeNodalBCsResidualAndJacobian( + [[maybe_unused]] const std::set & vector_tags, const std::set &) { +#ifdef MOOSE_KOKKOS_ENABLED + if (_fe_problem.hasKokkosResidualObjects()) + computeKokkosNodalBCs(vector_tags); +#endif + + // Return early if there is no nodal kernel + if (!_nodal_bcs.size()) + return; + PARALLEL_TRY { const ConstBndNodeRange & bnd_nodes = _fe_problem.getCurrentAlgebraicBndNodeRange(); @@ -2884,11 +2897,6 @@ NonlinearSystemBase::computeJacobianInternal(const std::set & tags) jacobianSetup(); -#ifdef MOOSE_KOKKOS_ENABLED - if (_fe_problem.hasKokkosResidualObjects()) - computeKokkosJacobian(tags); -#endif - // Jacobian contributions from UOs - for now this is used for ray tracing // and ray kernels that contribute to the Jacobian (think line sources) std::vector uos; @@ -2910,6 +2918,11 @@ NonlinearSystemBase::computeJacobianInternal(const std::set & tags) for (unsigned int tid = 0; tid < libMesh::n_threads(); tid++) _fe_problem.reinitScalars(tid); +#ifdef MOOSE_KOKKOS_ENABLED + if (_fe_problem.hasKokkosResidualObjects()) + computeKokkosJacobian(tags); +#endif + PARALLEL_TRY { // We would like to compute ScalarKernels, block NodalKernels, FVFluxKernels, and mortar objects From 27c2382cef97630a54cc8f03b68c5f2dd9e9ad74 Mon Sep 17 00:00:00 2001 From: Namjae Choi Date: Tue, 21 Apr 2026 15:42:33 -0600 Subject: [PATCH 03/14] Setup for Kokkos AD #32699 --- .../doc/content/syntax/KokkosBCs/index.md | 4 +- framework/include/base/Assembly.h | 6 +- framework/include/interfaces/Coupleable.h | 98 +++++ .../include/interfaces/TaggingInterface.h | 18 - framework/include/kokkos/base/KokkosDatum.h | 25 ++ .../include/kokkos/base/KokkosDispatcher.h | 36 ++ .../kokkos/base/KokkosResidualObject.h | 81 +++- framework/include/kokkos/base/KokkosTypes.h | 280 +++++++++---- .../include/kokkos/base/KokkosVariable.h | 87 +++- .../include/kokkos/base/KokkosVariableValue.h | 376 ++++++++++++++--- .../kokkos/bcs/KokkosADCoupledVarNeumannBC.h | 50 +++ .../include/kokkos/bcs/KokkosADIntegratedBC.h | 141 +++++++ .../include/kokkos/bcs/KokkosADNeumannBC.h | 37 ++ .../include/kokkos/bcs/KokkosADNodalBC.h | 99 +++++ .../include/kokkos/bcs/KokkosDirichletBC.h | 8 +- .../kokkos/bcs/KokkosDirichletBCBase.h | 39 +- .../kernels/KokkosADCoupledTimeDerivative.h | 39 ++ .../kokkos/kernels/KokkosADDiffusion.h | 33 ++ .../include/kokkos/kernels/KokkosADKernel.h | 144 +++++++ .../kokkos/kernels/KokkosADTimeDerivative.h | 33 ++ .../kokkos/kernels/KokkosADTimeKernel.h | 37 ++ .../include/kokkos/systems/KokkosSystem.h | 222 +++++++++- framework/include/kokkos/utils/KokkosADReal.h | 30 ++ framework/src/base/Assembly.C | 10 + framework/src/interfaces/TaggingInterface.C | 18 + framework/src/kokkos/base/KokkosVariable.K | 42 +- .../kokkos/bcs/KokkosADCoupledVarNeumannBC.K | 35 ++ .../src/kokkos/bcs/KokkosADIntegratedBC.K | 74 ++++ framework/src/kokkos/bcs/KokkosADNeumannBC.K | 32 ++ framework/src/kokkos/bcs/KokkosADNodalBC.K | 67 ++++ framework/src/kokkos/bcs/KokkosDirichletBC.K | 15 +- .../src/kokkos/bcs/KokkosDirichletBCBase.K | 18 +- .../src/kokkos/interfaces/KokkosCoupleable.K | 379 +++++++++++++++++- .../kernels/KokkosADCoupledTimeDerivative.K | 27 ++ .../src/kokkos/kernels/KokkosADDiffusion.K | 23 ++ framework/src/kokkos/kernels/KokkosADKernel.K | 74 ++++ .../kokkos/kernels/KokkosADTimeDerivative.K | 26 ++ .../src/kokkos/kernels/KokkosADTimeKernel.K | 31 ++ .../kokkos/bcs/KokkosCoupledDirichletBC.h | 6 +- 39 files changed, 2581 insertions(+), 219 deletions(-) create mode 100644 framework/include/kokkos/bcs/KokkosADCoupledVarNeumannBC.h create mode 100644 framework/include/kokkos/bcs/KokkosADIntegratedBC.h create mode 100644 framework/include/kokkos/bcs/KokkosADNeumannBC.h create mode 100644 framework/include/kokkos/bcs/KokkosADNodalBC.h create mode 100644 framework/include/kokkos/kernels/KokkosADCoupledTimeDerivative.h create mode 100644 framework/include/kokkos/kernels/KokkosADDiffusion.h create mode 100644 framework/include/kokkos/kernels/KokkosADKernel.h create mode 100644 framework/include/kokkos/kernels/KokkosADTimeDerivative.h create mode 100644 framework/include/kokkos/kernels/KokkosADTimeKernel.h create mode 100644 framework/include/kokkos/utils/KokkosADReal.h create mode 100644 framework/src/kokkos/bcs/KokkosADCoupledVarNeumannBC.K create mode 100644 framework/src/kokkos/bcs/KokkosADIntegratedBC.K create mode 100644 framework/src/kokkos/bcs/KokkosADNeumannBC.K create mode 100644 framework/src/kokkos/bcs/KokkosADNodalBC.K create mode 100644 framework/src/kokkos/kernels/KokkosADCoupledTimeDerivative.K create mode 100644 framework/src/kokkos/kernels/KokkosADDiffusion.K create mode 100644 framework/src/kokkos/kernels/KokkosADKernel.K create mode 100644 framework/src/kokkos/kernels/KokkosADTimeDerivative.K create mode 100644 framework/src/kokkos/kernels/KokkosADTimeKernel.K diff --git a/framework/doc/content/syntax/KokkosBCs/index.md b/framework/doc/content/syntax/KokkosBCs/index.md index 1529b4f9955f..02f541c6bdb9 100644 --- a/framework/doc/content/syntax/KokkosBCs/index.md +++ b/framework/doc/content/syntax/KokkosBCs/index.md @@ -42,7 +42,7 @@ To keep the consistency between interfaces, however, it is still passed as an ar `_current_node`, which is a pointer to the current libMesh node object, does not have a direct replacement. Instead, the node index can be queried by `datum.node()` and used to retrieve mesh data from the Kokkos mesh object. The node coordinate can also be obtained by `datum.q_point(qp)`. -As a result, the following residual function in `DirichletBCBase`: +As a result, the following residual function: ```cpp Real @@ -52,7 +52,7 @@ DirichletBCBase::computeQpResidual() } ``` -becomes the following in `Moose::Kokkos::DirichletBCBase`: +becomes the following: ```cpp template diff --git a/framework/include/base/Assembly.h b/framework/include/base/Assembly.h index 0f49fce3a54a..c4a47bb8f7de 100644 --- a/framework/include/base/Assembly.h +++ b/framework/include/base/Assembly.h @@ -1825,11 +1825,7 @@ class Assembly void saveLocalADArray(std::vector & re, unsigned int i, unsigned int ntest, - const ADRealEigenVector & v) const - { - for (unsigned int j = 0; j < v.size(); ++j, i += ntest) - re[i] += v(j); - } + const ADRealEigenVector & v) const; /** * Helper function for assembling diagonal Jacobian contriubutions on local diff --git a/framework/include/interfaces/Coupleable.h b/framework/include/interfaces/Coupleable.h index 1bd15d7dc495..4498b9eaf068 100644 --- a/framework/include/interfaces/Coupleable.h +++ b/framework/include/interfaces/Coupleable.h @@ -1950,6 +1950,104 @@ class Coupleable unsigned int comp = 0) const; Moose::Kokkos::VariableValue kokkosCoupledNodalDots(const std::string & var_name) const; + Moose::Kokkos::ADVariableValue kokkosADCoupledVectorTagValueByName(const std::string & var_name, + const std::string & tag_name, + unsigned int comp = 0) const; + Moose::Kokkos::ADVariableValue + kokkosADCoupledVectorTagValuesByName(const std::string & var_name, + const std::string & tag_name) const; + Moose::Kokkos::ADVariableGradient kokkosADCoupledVectorTagGradientByName( + const std::string & var_name, const std::string & tag_name, unsigned int comp = 0) const; + Moose::Kokkos::ADVariableGradient + kokkosADCoupledVectorTagGradientsByName(const std::string & var_name, + const std::string & tag_name) const; + Moose::Kokkos::ADVariableValue kokkosADCoupledVectorTagNodalValueByName( + const std::string & var_name, const std::string & tag_name, unsigned int comp = 0) const; + Moose::Kokkos::ADVariableValue + kokkosADCoupledVectorTagNodalValuesByName(const std::string & var_name, + const std::string & tag_name) const; + Moose::Kokkos::ADVariableValue kokkosADCoupledVectorTagDofValueByName( + const std::string & var_name, const std::string & tag_name, unsigned int comp = 0) const; + Moose::Kokkos::ADVariableValue + kokkosADCoupledVectorTagDofValuesByName(const std::string & var_name, + const std::string & tag_name) const; + + Moose::Kokkos::ADVariableValue kokkosADCoupledVectorTagValue(const std::string & var_name, + const std::string & tag_param_name, + unsigned int comp = 0) const; + Moose::Kokkos::ADVariableValue + kokkosADCoupledVectorTagValues(const std::string & var_name, + const std::string & tag_param_name) const; + Moose::Kokkos::ADVariableGradient + kokkosADCoupledVectorTagGradient(const std::string & var_name, + const std::string & tag_param_name, + unsigned int comp = 0) const; + Moose::Kokkos::ADVariableGradient + kokkosADCoupledVectorTagGradients(const std::string & var_name, + const std::string & tag_param_name) const; + Moose::Kokkos::ADVariableValue + kokkosADCoupledVectorTagNodalValue(const std::string & var_name, + const std::string & tag_param_name, + unsigned int comp = 0) const; + Moose::Kokkos::ADVariableValue + kokkosADCoupledVectorTagNodalValues(const std::string & var_name, + const std::string & tag_param_name) const; + Moose::Kokkos::ADVariableValue + kokkosADCoupledVectorTagDofValue(const std::string & var_name, + const std::string & tag_param_name, + unsigned int comp = 0) const; + Moose::Kokkos::ADVariableValue + kokkosADCoupledVectorTagDofValues(const std::string & var_name, + const std::string & tag_param_name) const; + + Moose::Kokkos::ADVariableValue kokkosADCoupledValue(const std::string & var_name, + unsigned int comp = 0) const; + Moose::Kokkos::ADVariableValue kokkosADCoupledValues(const std::string & var_name) const; + Moose::Kokkos::ADVariableGradient kokkosADCoupledGradient(const std::string & var_name, + unsigned int comp = 0) const; + Moose::Kokkos::ADVariableGradient kokkosADCoupledGradients(const std::string & var_name) const; + Moose::Kokkos::ADVariableValue kokkosADCoupledNodalValue(const std::string & var_name, + unsigned int comp = 0) const; + Moose::Kokkos::ADVariableValue kokkosADCoupledNodalValues(const std::string & var_name) const; + Moose::Kokkos::ADVariableValue kokkosADCoupledDofValue(const std::string & var_name, + unsigned int comp = 0) const; + Moose::Kokkos::ADVariableValue kokkosADCoupledDofValues(const std::string & var_name) const; + + Moose::Kokkos::ADVariableValue kokkosADCoupledValueOld(const std::string & var_name, + unsigned int comp = 0) const; + Moose::Kokkos::ADVariableValue kokkosADCoupledValuesOld(const std::string & var_name) const; + Moose::Kokkos::ADVariableGradient kokkosADCoupledGradientOld(const std::string & var_name, + unsigned int comp = 0) const; + Moose::Kokkos::ADVariableGradient kokkosADCoupledGradientsOld(const std::string & var_name) const; + Moose::Kokkos::ADVariableValue kokkosADCoupledNodalValueOld(const std::string & var_name, + unsigned int comp = 0) const; + Moose::Kokkos::ADVariableValue kokkosADCoupledNodalValuesOld(const std::string & var_name) const; + Moose::Kokkos::ADVariableValue kokkosADCoupledDofValueOld(const std::string & var_name, + unsigned int comp = 0) const; + Moose::Kokkos::ADVariableValue kokkosADCoupledDofValuesOld(const std::string & var_name) const; + + Moose::Kokkos::ADVariableValue kokkosADCoupledValueOlder(const std::string & var_name, + unsigned int comp = 0) const; + Moose::Kokkos::ADVariableValue kokkosADCoupledValuesOlder(const std::string & var_name) const; + Moose::Kokkos::ADVariableGradient kokkosADCoupledGradientOlder(const std::string & var_name, + unsigned int comp = 0) const; + Moose::Kokkos::ADVariableGradient + kokkosADCoupledGradientsOlder(const std::string & var_name) const; + Moose::Kokkos::ADVariableValue kokkosADCoupledNodalValueOlder(const std::string & var_name, + unsigned int comp = 0) const; + Moose::Kokkos::ADVariableValue + kokkosADCoupledNodalValuesOlder(const std::string & var_name) const; + Moose::Kokkos::ADVariableValue kokkosADCoupledDofValueOlder(const std::string & var_name, + unsigned int comp = 0) const; + Moose::Kokkos::ADVariableValue kokkosADCoupledDofValuesOlder(const std::string & var_name) const; + + Moose::Kokkos::ADVariableValue kokkosADCoupledDot(const std::string & var_name, + unsigned int comp = 0) const; + Moose::Kokkos::ADVariableValue kokkosADCoupledDots(const std::string & var_name) const; + Moose::Kokkos::ADVariableValue kokkosADCoupledNodalDot(const std::string & var_name, + unsigned int comp = 0) const; + Moose::Kokkos::ADVariableValue kokkosADCoupledNodalDots(const std::string & var_name) const; + Moose::Kokkos::Scalar kokkosCoupledDotDu(const std::string & var_name, unsigned int comp = 0) const; diff --git a/framework/include/interfaces/TaggingInterface.h b/framework/include/interfaces/TaggingInterface.h index a7b4e88f446e..ff3df3d35d61 100644 --- a/framework/include/interfaces/TaggingInterface.h +++ b/framework/include/interfaces/TaggingInterface.h @@ -680,21 +680,3 @@ TaggingInterface::setResidual(SystemBase & sys, const SetResidualFunctor set_res if (sys.hasVector(tag_id)) set_residual_functor(sys.getVector(tag_id)); } - -inline void -TaggingInterface::addResiduals(Assembly & assembly, const ADResidualsPacket & packet) -{ - addResiduals(assembly, packet.residuals, packet.dof_indices, packet.scaling_factor); -} - -inline void -TaggingInterface::addResidualsAndJacobian(Assembly & assembly, const ADResidualsPacket & packet) -{ - addResidualsAndJacobian(assembly, packet.residuals, packet.dof_indices, packet.scaling_factor); -} - -inline void -TaggingInterface::addJacobian(Assembly & assembly, const ADResidualsPacket & packet) -{ - addJacobian(assembly, packet.residuals, packet.dof_indices, packet.scaling_factor); -} diff --git a/framework/include/kokkos/base/KokkosDatum.h b/framework/include/kokkos/base/KokkosDatum.h index 6cb116d1d4ae..2dac4cdadb65 100644 --- a/framework/include/kokkos/base/KokkosDatum.h +++ b/framework/include/kokkos/base/KokkosDatum.h @@ -389,6 +389,7 @@ class AssemblyDatum : public Datum const unsigned int comp = 0) : Datum(elem, side, assembly, systems), _tag(ivar.tag()), + _sys(ivar.sys(comp)), _ivar(ivar.var(comp)), _jvar(jvar), _ife(systems[ivar.sys(comp)].getFETypeID(_ivar)), @@ -415,6 +416,7 @@ class AssemblyDatum : public Datum const unsigned int comp = 0) : Datum(node, assembly, systems), _tag(ivar.tag()), + _sys(ivar.sys(comp)), _ivar(ivar.var(comp)), _jvar(jvar), _ife(systems[ivar.sys(comp)].getFETypeID(_ivar)), @@ -437,6 +439,11 @@ class AssemblyDatum : public Datum * @returns The number of local DOFs */ KOKKOS_FUNCTION unsigned int n_jdofs() const { return _n_jdofs; } + /** + * Get the system number of variable + * @returns The system number of variable + */ + KOKKOS_FUNCTION unsigned int sys() const { return _sys; } /** * Get the variable number * @returns The variable number @@ -467,12 +474,26 @@ class AssemblyDatum : public Datum * @returns The variable FE type ID */ KOKKOS_FUNCTION unsigned int jfe() const { return _jfe; } + /** + * Set whether to compute derivatives for automatic differentiation (AD) + * @param flag Whether to compute derivatives + */ + KOKKOS_FUNCTION void do_derivatives(const bool flag) { _do_derivatives = flag; } + /** + * Get whether to compute derivatives for automatic differentiation (AD) + * @returns Whether to compute derivatives + */ + KOKKOS_FUNCTION bool do_derivatives() const { return _do_derivatives; } protected: /** * Solution tag ID */ const TagID _tag; + /** + * System number + */ + const unsigned int _sys; /** * Variable numbers */ @@ -485,6 +506,10 @@ class AssemblyDatum : public Datum * Number of local DOFs */ const unsigned int _n_idofs = 1, _n_jdofs = 1; + /** + * Whether to compute derivatives for automatic differentiation (AD) + */ + bool _do_derivatives = true; }; } // namespace Moose::Kokkos diff --git a/framework/include/kokkos/base/KokkosDispatcher.h b/framework/include/kokkos/base/KokkosDispatcher.h index a94db4bf2266..26a77e898975 100644 --- a/framework/include/kokkos/base/KokkosDispatcher.h +++ b/framework/include/kokkos/base/KokkosDispatcher.h @@ -403,6 +403,42 @@ class DispatcherRegistry #define registerKokkosBoundaryConditionAliased(app, classname, alias) \ registerKokkosResidualObjectAliased(app, classname, alias) +// AD Kernel, NodalKernel, BC + +#define callRegisterKokkosADResidualObjectFunction(classname, objectname) \ + static char registerKokkosADResidualObject##classname() \ + { \ + using namespace Moose::Kokkos; \ + \ + DispatcherRegistry::addDispatcher(objectname); \ + \ + return 0; \ + } \ + \ + static char combineNames(kokkos_dispatcher_ad_residual_object_##classname, __COUNTER__) = \ + registerKokkosADResidualObject##classname() + +#define registerKokkosADResidualObject(app, classname) \ + registerMooseObject(app, classname); \ + callRegisterKokkosADResidualObjectFunction(classname, #classname) + +#define registerKokkosADResidualObjectAliased(app, classname, alias) \ + registerMooseObjectAliased(app, classname, alias); \ + callRegisterKokkosADResidualObjectFunction(classname, alias) + +#define registerKokkosADKernel(app, classname) registerKokkosADResidualObject(app, classname) +#define registerKokkosADKernelAliased(app, classname, alias) \ + registerKokkosADResidualObjectAliased(app, classname, alias) + +#define registerKokkosADNodalKernel(app, classname) registerKokkosADResidualObject(app, classname) +#define registerKokkosADNodalKernelAliased(app, classname, alias) \ + registerKokkosADResidualObjectAliased(app, classname, alias) + +#define registerKokkosADBoundaryCondition(app, classname) \ + registerKokkosADResidualObject(app, classname) +#define registerKokkosADBoundaryConditionAliased(app, classname, alias) \ + registerKokkosADResidualObjectAliased(app, classname, alias) + // Material #define callRegisterKokkosMaterialFunction(classname, objectname) \ diff --git a/framework/include/kokkos/base/KokkosResidualObject.h b/framework/include/kokkos/base/KokkosResidualObject.h index 26be9b30dae8..83a0475bda0b 100644 --- a/framework/include/kokkos/base/KokkosResidualObject.h +++ b/framework/include/kokkos/base/KokkosResidualObject.h @@ -64,7 +64,7 @@ class ResidualObject : public ::ResidualObject, { mooseError("computeOffDiagJacobian() is not used for Kokkos residual objects."); } - virtual void computeResidualAndJacobian() override final + virtual void computeResidualAndJacobian() override { computeResidual(); computeJacobian(); @@ -155,6 +155,18 @@ class ResidualObject : public ::ResidualObject, const unsigned int j, const unsigned int jvar, const unsigned int comp = 0) const; + /** + * Accumulate local elemental Jacobian contribution to tagged matrices using automatic + * differentiation (AD) + * @param local_ke The local elemental Jacobian contribution + * @param datum The AssemblyDatum object of the current thread + * @param i The test function DOF index + * @param comp The variable component + */ + KOKKOS_FUNCTION void accumulateTaggedElementalMatrix(const DNDerivativeType & local_ke, + const AssemblyDatum & datum, + const unsigned int i, + const unsigned int comp = 0) const; /** * Accumulate or set local nodal Jacobian contribution to tagged matrices * @param add The flag whether to add or set the local residual @@ -168,6 +180,18 @@ class ResidualObject : public ::ResidualObject, const ContiguousNodeID node, const unsigned int jvar, const unsigned int comp = 0) const; + /** + * Accumulate or set local nodal Jacobian contribution to tagged matrices using automatic + * differentiation (AD) + * @param add The flag whether to add or set the local residual + * @param local_ke The local elemental Jacobian contribution + * @param node The contiguous node ID + * @param comp The variable component + */ + KOKKOS_FUNCTION void accumulateTaggedNodalMatrix(const bool add, + const DNDerivativeType & local_ke, + const ContiguousNodeID node, + const unsigned int comp = 0) const; /** * The common loop structure template for computing elemental residual @@ -265,6 +289,29 @@ ResidualObject::accumulateTaggedElementalMatrix(const Real local_ke, } } +KOKKOS_FUNCTION inline void +ResidualObject::accumulateTaggedElementalMatrix(const DNDerivativeType & local_ke, + const AssemblyDatum & datum, + const unsigned int i, + const unsigned int comp) const +{ + auto & sys = kokkosSystem(_kokkos_var.sys(comp)); + auto row = sys.getElemLocalDofIndex(datum.elem().id, i, _kokkos_var.var(comp)); + + for (dof_id_type t = 0; t < _matrix_tags.size(); ++t) + { + auto tag = _matrix_tags[t]; + + if (sys.isMatrixTagActive(tag) && !sys.hasNodalBCMatrixTag(row, tag)) + for (unsigned int j = 0; j < local_ke.size(); ++j) + { + auto col = local_ke.raw_index(j); + + ::Kokkos::atomic_add(&sys.getMatrixValue(row, col, tag), local_ke.raw_at(j)); + } + } +} + KOKKOS_FUNCTION inline void ResidualObject::accumulateTaggedNodalMatrix(const bool add, const Real local_ke, @@ -298,6 +345,38 @@ ResidualObject::accumulateTaggedNodalMatrix(const bool add, } } +KOKKOS_FUNCTION inline void +ResidualObject::accumulateTaggedNodalMatrix(const bool add, + const DNDerivativeType & local_ke, + const ContiguousNodeID node, + const unsigned int comp) const +{ + auto & sys = kokkosSystem(_kokkos_var.sys(comp)); + auto row = sys.getNodeLocalDofIndex(node, 0, _kokkos_var.var(comp)); + + for (dof_id_type t = 0; t < _matrix_tags.size(); ++t) + { + auto tag = _matrix_tags[t]; + auto & matrix = sys.getMatrix(tag); + + if (sys.isMatrixTagActive(tag)) + { + if (!add) + matrix.zero(row); + + for (unsigned int j = 0; j < local_ke.size(); ++j) + { + auto col = local_ke.raw_index(j); + + if (add) + matrix(row, col) += local_ke.raw_at(j); + else + matrix(row, col) = local_ke.raw_at(j); + } + } + } +} + template KOKKOS_FUNCTION void ResidualObject::computeResidualInternal(AssemblyDatum & datum, function body) const diff --git a/framework/include/kokkos/base/KokkosTypes.h b/framework/include/kokkos/base/KokkosTypes.h index 0bd85ea266b8..6eff5006da8f 100644 --- a/framework/include/kokkos/base/KokkosTypes.h +++ b/framework/include/kokkos/base/KokkosTypes.h @@ -13,6 +13,10 @@ #include "KokkosScalar.h" #include "KokkosJaggedArray.h" +#ifdef MOOSE_KOKKOS_SCOPE +#include "KokkosADReal.h" +#endif + #include "MooseError.h" #include "MooseUtils.h" @@ -21,32 +25,44 @@ namespace Moose::Kokkos { +template +struct Vector3; + +using Real3 = Vector3; +using ADReal3 = Vector3; + struct Real33; -struct Real3 +template +struct Vector3 { - Real v[3]; + T v[3]; #ifdef MOOSE_KOKKOS_SCOPE - Real3(const libMesh::TypeVector & vector); - KOKKOS_INLINE_FUNCTION Real3() { *this = 0; } - KOKKOS_INLINE_FUNCTION Real3(const Real scalar) { *this = scalar; } - KOKKOS_INLINE_FUNCTION Real3(const Real3 & vector) { *this = vector; } - KOKKOS_INLINE_FUNCTION Real3(const Real x, const Real y, const Real z); - - KOKKOS_INLINE_FUNCTION Real3 operator-() const; - KOKKOS_INLINE_FUNCTION Real & operator()(unsigned int i) { return v[i]; } - KOKKOS_INLINE_FUNCTION Real operator()(unsigned int i) const { return v[i]; } - - Real3 & operator=(const libMesh::TypeVector & vector); - KOKKOS_INLINE_FUNCTION Real3 & operator=(const Real3 & vector); - KOKKOS_INLINE_FUNCTION Real3 & operator=(const Real scalar); - - KOKKOS_INLINE_FUNCTION void operator+=(const Real scalar); - KOKKOS_INLINE_FUNCTION void operator+=(const Real3 vector); - KOKKOS_INLINE_FUNCTION void operator-=(const Real scalar); - KOKKOS_INLINE_FUNCTION void operator-=(const Real3 vector); - KOKKOS_INLINE_FUNCTION void operator*=(const Real scalar); + Vector3(const libMesh::TypeVector & vector); + KOKKOS_INLINE_FUNCTION Vector3() { *this = T(0); } + KOKKOS_INLINE_FUNCTION Vector3(const T & scalar) { *this = scalar; } + KOKKOS_INLINE_FUNCTION Vector3(const Vector3 & vector) { *this = vector; } + KOKKOS_INLINE_FUNCTION Vector3(const T & x, const T & y, const T & z); + + KOKKOS_INLINE_FUNCTION Vector3 operator-() const; + KOKKOS_INLINE_FUNCTION T & operator()(unsigned int i) { return v[i]; } + KOKKOS_INLINE_FUNCTION const T & operator()(unsigned int i) const { return v[i]; } + + Vector3 & operator=(const libMesh::TypeVector & vector); + + template + KOKKOS_INLINE_FUNCTION Vector3 & operator=(const Vector3 & vector); + KOKKOS_INLINE_FUNCTION Vector3 & operator=(const Vector3 & vector); + KOKKOS_INLINE_FUNCTION Vector3 & operator=(const T & scalar); + + template + KOKKOS_INLINE_FUNCTION void operator+=(const Vector3 & vector); + KOKKOS_INLINE_FUNCTION void operator+=(const T & scalar); + template + KOKKOS_INLINE_FUNCTION void operator-=(const Vector3 & vector); + KOKKOS_INLINE_FUNCTION void operator-=(const T & scalar); + KOKKOS_INLINE_FUNCTION void operator*=(const T & scalar); KOKKOS_INLINE_FUNCTION Real norm() const; KOKKOS_INLINE_FUNCTION Real dot_product(const Real3 vector) const; @@ -82,42 +98,59 @@ struct Real33 #ifdef MOOSE_KOKKOS_SCOPE -inline Real3::Real3(const libMesh::TypeVector & vector) +template +Vector3::Vector3(const libMesh::TypeVector & vector) { v[0] = vector(0); v[1] = vector(1); v[2] = vector(2); } +template KOKKOS_INLINE_FUNCTION -Real3::Real3(const Real x, const Real y, const Real z) +Vector3::Vector3(const T & x, const T & y, const T & z) { v[0] = x; v[1] = y; v[2] = z; } -KOKKOS_INLINE_FUNCTION Real3 -Real3::operator-() const +template +Vector3 & +Vector3::operator=(const libMesh::TypeVector & vector) { - Real3 vector(*this); + v[0] = vector(0); + v[1] = vector(1); + v[2] = vector(2); + + return *this; +} + +template +KOKKOS_INLINE_FUNCTION Vector3 +Vector3::operator-() const +{ + Vector3 vector(*this); vector *= -1; return vector; } -inline Real3 & -Real3::operator=(const libMesh::TypeVector & vector) +template +KOKKOS_INLINE_FUNCTION Vector3 & +Vector3::operator=(const Vector3 & vector) { - v[0] = vector(0); - v[1] = vector(1); - v[2] = vector(2); + v[0] = vector.v[0]; + v[1] = vector.v[1]; + v[2] = vector.v[2]; return *this; } -KOKKOS_INLINE_FUNCTION Real3 & -Real3::operator=(const Real3 & vector) +template +template +KOKKOS_INLINE_FUNCTION Vector3 & +Vector3::operator=(const Vector3 & vector) { v[0] = vector.v[0]; v[1] = vector.v[1]; @@ -126,8 +159,9 @@ Real3::operator=(const Real3 & vector) return *this; } -KOKKOS_INLINE_FUNCTION Real3 & -Real3::operator=(const Real scalar) +template +KOKKOS_INLINE_FUNCTION Vector3 & +Vector3::operator=(const T & scalar) { v[0] = scalar; v[1] = scalar; @@ -136,60 +170,133 @@ Real3::operator=(const Real scalar) return *this; } +template +template KOKKOS_INLINE_FUNCTION void -Real3::operator+=(const Real scalar) -{ - v[0] += scalar; - v[1] += scalar; - v[2] += scalar; -} - -KOKKOS_INLINE_FUNCTION void -Real3::operator+=(const Real3 vector) +Vector3::operator+=(const Vector3 & vector) { v[0] += vector.v[0]; v[1] += vector.v[1]; v[2] += vector.v[2]; } +template KOKKOS_INLINE_FUNCTION void -Real3::operator-=(const Real scalar) +Vector3::operator+=(const T & scalar) { - v[0] -= scalar; - v[1] -= scalar; - v[2] -= scalar; + v[0] += scalar; + v[1] += scalar; + v[2] += scalar; } +template +template KOKKOS_INLINE_FUNCTION void -Real3::operator-=(const Real3 vector) +Vector3::operator-=(const Vector3 & vector) { v[0] -= vector.v[0]; v[1] -= vector.v[1]; v[2] -= vector.v[2]; } +template KOKKOS_INLINE_FUNCTION void -Real3::operator*=(const Real scalar) +Vector3::operator-=(const T & scalar) +{ + v[0] -= scalar; + v[1] -= scalar; + v[2] -= scalar; +} + +template +KOKKOS_INLINE_FUNCTION void +Vector3::operator*=(const T & scalar) { v[0] *= scalar; v[1] *= scalar; v[2] *= scalar; } +template +KOKKOS_INLINE_FUNCTION Vector3 +operator+(const T & left, const Vector3 & right) +{ + return {left + right.v[0], left + right.v[1], left + right.v[2]}; +} + +template +KOKKOS_INLINE_FUNCTION Vector3 +operator+(const Vector3 & left, const T & right) +{ + return {left.v[0] + right, left.v[1] + right, left.v[2] + right}; +} + +template +KOKKOS_INLINE_FUNCTION Vector3 +operator+(const Vector3 & left, const Vector3 & right) +{ + return {left.v[0] + right.v[0], left.v[1] + right.v[1], left.v[2] + right.v[2]}; +} + +template +KOKKOS_INLINE_FUNCTION Vector3 +operator-(const T & left, const Vector3 & right) +{ + return {left - right.v[0], left - right.v[1], left - right.v[2]}; +} + +template +KOKKOS_INLINE_FUNCTION Vector3 +operator-(const Vector3 & left, const T & right) +{ + return {left.v[0] - right, left.v[1] - right, left.v[2] - right}; +} + +template +KOKKOS_INLINE_FUNCTION Vector3 +operator-(const Vector3 & left, const Vector3 & right) +{ + return {left.v[0] - right.v[0], left.v[1] - right.v[1], left.v[2] - right.v[2]}; +} + +template +KOKKOS_INLINE_FUNCTION Vector3 +operator*(const T & left, const Vector3 & right) +{ + return {left * right.v[0], left * right.v[1], left * right.v[2]}; +} + +template +KOKKOS_INLINE_FUNCTION Vector3 +operator*(const Vector3 & left, const T & right) +{ + return {left.v[0] * right, left.v[1] * right, left.v[2] * right}; +} + +template +KOKKOS_INLINE_FUNCTION T +operator*(const Vector3 & left, const Vector3 & right) +{ + return left.v[0] * right.v[0] + left.v[1] * right.v[1] + left.v[2] * right.v[2]; +} + +template <> KOKKOS_INLINE_FUNCTION Real -Real3::norm() const +Vector3::norm() const { return std::sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); } +template <> KOKKOS_INLINE_FUNCTION Real -Real3::dot_product(const Real3 vector) const +Vector3::dot_product(const Real3 vector) const { return v[0] * vector.v[0] + v[1] * vector.v[1] + v[2] * vector.v[2]; } +template <> KOKKOS_INLINE_FUNCTION Real3 -Real3::cross_product(const Real3 vector) const +Vector3::cross_product(const Real3 vector) const { Real3 cross; @@ -200,8 +307,9 @@ Real3::cross_product(const Real3 vector) const return cross; } +template <> KOKKOS_INLINE_FUNCTION Real33 -Real3::cartesian_product(const Real3 vector) const +Vector3::cartesian_product(const Real3 vector) const { Real33 tensor; @@ -325,24 +433,6 @@ Real33::col(const unsigned int j) const return Real3(a[0][j], a[1][j], a[2][j]); } -KOKKOS_INLINE_FUNCTION Real3 -operator*(const Real left, const Real3 right) -{ - return {left * right.v[0], left * right.v[1], left * right.v[2]}; -} - -KOKKOS_INLINE_FUNCTION Real3 -operator*(const Real3 left, const Real right) -{ - return {left.v[0] * right, left.v[1] * right, left.v[2] * right}; -} - -KOKKOS_INLINE_FUNCTION Real -operator*(const Real3 left, const Real3 right) -{ - return left.v[0] * right.v[0] + left.v[1] * right.v[1] + left.v[2] * right.v[2]; -} - KOKKOS_INLINE_FUNCTION Real3 operator*(const Real33 left, const Real3 right) { @@ -376,12 +466,6 @@ operator+(const Real3 left, const Real right) return {left.v[0] + right, left.v[1] + right, left.v[2] + right}; } -KOKKOS_INLINE_FUNCTION Real3 -operator+(const Real3 left, const Real3 right) -{ - return {left.v[0] + right.v[0], left.v[1] + right.v[1], left.v[2] + right.v[2]}; -} - KOKKOS_INLINE_FUNCTION Real3 operator-(const Real left, const Real3 right) { @@ -395,9 +479,45 @@ operator-(const Real3 left, const Real right) } KOKKOS_INLINE_FUNCTION Real3 -operator-(const Real3 left, const Real3 right) +operator*(const Real left, const Real3 right) { - return {left.v[0] - right.v[0], left.v[1] - right.v[1], left.v[2] - right.v[2]}; + return {left * right.v[0], left * right.v[1], left * right.v[2]}; +} + +KOKKOS_INLINE_FUNCTION Real3 +operator*(const Real3 left, const Real right) +{ + return {left.v[0] * right, left.v[1] * right, left.v[2] * right}; +} + +template ::type, ADReal>::value>::type> +KOKKOS_INLINE_FUNCTION ADReal3 +operator*(const Real3 left, const T & right) +{ + return {left(0) * right, left(1) * right, left(2) * right}; +} + +template ::type, ADReal>::value>::type> +KOKKOS_INLINE_FUNCTION ADReal3 +operator*(const T & left, const Real3 right) +{ + return {left * right(0), left * right(1), left * right(2)}; +} + +KOKKOS_INLINE_FUNCTION ADReal +operator*(const Real3 left, const ADReal3 & right) +{ + return left(0) * right(0) + left(1) * right(1) + left(2) * right(2); +} + +KOKKOS_INLINE_FUNCTION ADReal +operator*(const ADReal3 & left, const Real3 right) +{ + return left(0) * right(0) + left(1) * right(1) + left(2) * right(2); } #endif diff --git a/framework/include/kokkos/base/KokkosVariable.h b/framework/include/kokkos/base/KokkosVariable.h index eddf6b23a278..50c116f9edf9 100644 --- a/framework/include/kokkos/base/KokkosVariable.h +++ b/framework/include/kokkos/base/KokkosVariable.h @@ -38,42 +38,100 @@ class Variable * @param variable The MOOSE variable * @param tag The vector tag ID */ - Variable(const MooseVariableBase & variable, const TagID tag) { init(variable, tag); } + Variable(const MooseVariableFieldBase & variable, const TagID tag) { init(variable, tag); } /** * Constructor * Initialize the variable with a MOOSE variable and vector tag name * @param variable The MOOSE variable * @param tag_name The vector tag name */ - Variable(const MooseVariableBase & variable, const TagName & tag_name = Moose::SOLUTION_TAG) + Variable(const MooseVariableFieldBase & variable, const TagName & tag_name = Moose::SOLUTION_TAG) { init(variable, tag_name); } + /** + * Constructor + * Initialize the variable with multiple MOOSE variables and vector tag ID + * @param variables The MOOSE variables + * @param tag The vector tag ID + */ + ///@{ + Variable(const std::vector & variables, const TagID tag) + { + init(variables, tag); + } + Variable(const std::vector & variables, const TagID tag) + { + init(variables, tag); + } + ///@} + /** + * Constructor + * Initialize the variable with multiple MOOSE variables and vector tag name + * @param variables The MOOSE variables + * @param tag The vector tag ID + */ + ///@{ + Variable(const std::vector & variables, + const TagName & tag_name = Moose::SOLUTION_TAG) + { + init(variables, tag_name); + } + Variable(const std::vector & variables, + const TagName & tag_name = Moose::SOLUTION_TAG) + { + init(variables, tag_name); + } + ///@} /** * Initialize the variable with a MOOSE variable and vector tag ID * @param variable The MOOSE variable * @param tag The vector tag ID */ - void init(const MooseVariableBase & variable, const TagID tag); + void init(const MooseVariableFieldBase & variable, const TagID tag); /** * Initialize the variable with a MOOSE variable and vector tag name * @param variable The MOOSE variable * @param tag_name The vector tag name */ - void init(const MooseVariableBase & variable, const TagName & tag_name = Moose::SOLUTION_TAG); + void init(const MooseVariableFieldBase & variable, + const TagName & tag_name = Moose::SOLUTION_TAG); /** - * Initialize the variable with coupled MOOSE variables - * @param variables The coupled MOOSE variables + * Initialize the variable with multiple MOOSE variables and vector tag ID + * @param variables The MOOSE variables * @param tag The vector tag ID */ - void - init(const std::vector & variables, const TagID tag, CoupleableKey); + ///@{ + void init(const std::vector & variables, const TagID tag); + void init(const std::vector & variables, const TagID tag); + ///@} + /** + * Initialize the variable with multiple MOOSE variables and vector tag name + * @param variables The MOOSE variables + * @param tag_name The vector tag name + */ + ///@{ + void init(const std::vector & variables, + const TagName & tag_name = Moose::SOLUTION_TAG); + void init(const std::vector & variables, + const TagName & tag_name = Moose::SOLUTION_TAG); + ///@} /** * Initialize the variable with coupled default values * @param values The default coupled values */ void init(const std::vector & values, CoupleableKey); + /** + * Get the MOOSE variable of a component + * @param comp The variable component + * @returns The MOOSE variable + */ + const MooseVariableFieldBase * mooseVar(unsigned int comp = 0) + { + return _moose_var.size() ? _moose_var[comp] : nullptr; + } + /** * Get whether the variable is initialized * @returns Whether the variable is initialized @@ -89,6 +147,11 @@ class Variable * @returns Whether the variable is nodal */ KOKKOS_FUNCTION bool nodal() const { return _nodal; } + /** + * Get whether the tag is time derivative + * @returns Whether the tag is time derivative + */ + KOKKOS_FUNCTION bool dot() const { return _dot; } /** * Get the number of components * @returns The number of components @@ -136,6 +199,10 @@ class Variable * Whether the variable is nodal */ bool _nodal = false; + /** + * Whether the tag is time derivative + */ + bool _dot = false; /** * Number of components */ @@ -144,6 +211,10 @@ class Variable * Vector tag ID */ TagID _tag = Moose::INVALID_TAG_ID; + /** + * MOOSE variable of each component + */ + Array _moose_var; /** * Variable number of each component */ diff --git a/framework/include/kokkos/base/KokkosVariableValue.h b/framework/include/kokkos/base/KokkosVariableValue.h index 0cadb3e76c0d..6ab00fa6467c 100644 --- a/framework/include/kokkos/base/KokkosVariableValue.h +++ b/framework/include/kokkos/base/KokkosVariableValue.h @@ -11,7 +11,7 @@ #include "KokkosDatum.h" -#include "MooseVariableBase.h" +#include "MooseVariableFieldBase.h" namespace Moose::Kokkos { @@ -109,37 +109,75 @@ class VariableTestGradient : datum.assembly().getGradPhiFace(elem.subdomain, elem.type, fe)(side)(i, qp)); } }; + +using ADVariablePhiValue = VariablePhiValue; +using ADVariablePhiGradient = VariablePhiGradient; +using ADVariableTestValue = VariableTestValue; +using ADVariableTestGradient = VariableTestGradient; + ///@} /** * The Kokkos wrapper classes for MOOSE-like variable value access */ ///@{ -class VariableValue +template +class VariableValueTempl { + using real_type = std::conditional_t; + public: /** * Default constructor */ - VariableValue() = default; + VariableValueTempl() = default; /** * Constructor * @param var The Kokkos variable * @param dof Whether to get DOF values */ - VariableValue(Variable var, bool dof = false) : _var(var), _dof(dof) {} + VariableValueTempl(Variable var, bool dof = false) : _var(var), _dof(dof) {} /** * Constructor * @param var The MOOSE variable * @param tag The vector tag name * @param dof Whether to get DOF values */ - VariableValue(const MooseVariableBase & var, - const TagName & tag = Moose::SOLUTION_TAG, - bool dof = false) + VariableValueTempl(const MooseVariableFieldBase & var, + const TagName & tag = Moose::SOLUTION_TAG, + bool dof = false) : _var(var, tag), _dof(dof) { } + /** + * Constructor + * @param vars The MOOSE variables + * @param tag The vector tag name + * @param dof Whether to get DOF values + */ + ///@{ + VariableValueTempl(const std::vector & vars, + const TagName & tag = Moose::SOLUTION_TAG, + bool dof = false) + : _var(vars, tag), _dof(dof) + { + } + VariableValueTempl(const std::vector & vars, + const TagName & tag = Moose::SOLUTION_TAG, + bool dof = false) + : _var(vars, tag), _dof(dof) + { + } + ///@} + + /** + * Copy constructor for parallel dispatch + */ + VariableValueTempl(const VariableValueTempl & object); + /** + * Copy assignment operator + */ + VariableValueTempl & operator=(const VariableValueTempl & object); /** * Get whether the variable was coupled @@ -150,11 +188,24 @@ class VariableValue /** * Get the current variable value * @param datum The Datum object of the current thread - * @param qp The local quadrature point index + * @param idx The local quadrature point or DOF index * @param comp The variable component * @returns The variable value */ - KOKKOS_FUNCTION Real operator()(Datum & datum, unsigned int qp, unsigned int comp = 0) const; + KOKKOS_FUNCTION auto operator()(Datum & datum, unsigned int idx, unsigned int comp = 0) const + { + return get(datum, idx, comp); + } + + /** + * Get the current variable value + * @param datum The AssemblyDatum object of the current thread + * @param idx The local quadrature point or DOF index + * @param comp The variable component + * @returns The variable value + */ + KOKKOS_FUNCTION auto + operator()(AssemblyDatum & datum, unsigned int idx, unsigned int comp = 0) const; /** * Get the Kokkos variable @@ -163,37 +214,184 @@ class VariableValue KOKKOS_FUNCTION const Variable & variable() const { return _var; } private: + /** + * Get the current variable value + * @param datum The Datum object of the current thread + * @param idx The local quadrature point or DOF index + * @param comp The variable component + * @param seed The derivative seed (only meaningful for AD) + * @returns The variable value + */ + KOKKOS_FUNCTION auto + get(Datum & datum, unsigned int idx, unsigned int comp = 0, Real seed = 0) const; + /** * Coupled Kokkos variable */ Variable _var; + /** + * Derivative seed of each component for AD + */ + Array _seed; /** * Flag whether DOF values are requested */ bool _dof = false; }; -class VariableGradient +template +VariableValueTempl::VariableValueTempl(const VariableValueTempl & object) + : _var(object._var), _seed(object._seed), _dof(object._dof) +{ + if constexpr (is_ad) + if (_var.coupled()) + { + if (!_seed.isAlloc()) + _seed.create(_var.components()); + + for (unsigned int comp = 0; comp < _var.components(); ++comp) + _seed[comp] = _var.dot() ? _var.mooseVar(comp)->sys().duDotDu(_var.var(comp)) : 1; + + _seed.copyToDevice(); + } +} + +template +VariableValueTempl & +VariableValueTempl::operator=(const VariableValueTempl & object) +{ + _var = object._var; + _dof = object._dof; + + return *this; +} + +template +KOKKOS_FUNCTION auto +VariableValueTempl::operator()(AssemblyDatum & datum, + unsigned int idx, + unsigned int comp) const +{ + if constexpr (is_ad) + { + Real seed = + datum.do_derivatives() && _var.coupled() && _var.sys(comp) == datum.sys() ? _seed[comp] : 0; + + return get(datum, idx, comp, seed); + } + else + return get(datum, idx, comp); +} + +template +KOKKOS_FUNCTION auto +VariableValueTempl::get(Datum & datum, + unsigned int idx, + unsigned int comp, + [[maybe_unused]] Real seed) const { + KOKKOS_ASSERT(_var.initialized()); + + real_type value; + + if (_var.coupled()) + { + auto & sys = datum.system(_var.sys(comp)); + auto var = _var.var(comp); + auto tag = _var.tag(); + + if (_dof) + { + unsigned int dof; + + if (datum.isNodal()) + { + auto node = datum.node(); + dof = sys.getNodeLocalDofIndex(node, 0, var); + } + else + { + auto elem = datum.elem().id; + dof = sys.getElemLocalDofIndex(elem, idx, var); + } + + if constexpr (is_ad) + value = sys.getVectorDofADValue(dof, tag, seed); + else + value = sys.getVectorDofValue(dof, tag); + } + else + { + auto & elem = datum.elem(); + auto side = datum.side(); + + if constexpr (is_ad) + value = side == libMesh::invalid_uint + ? sys.getVectorQpADValue(elem, datum.qpOffset(), idx, var, tag, seed) + : sys.getVectorQpADValueFace(elem, side, idx, var, tag, seed); + else + value = side == libMesh::invalid_uint + ? sys.getVectorQpValue(elem, datum.qpOffset() + idx, var, tag) + : sys.getVectorQpValueFace(elem, side, idx, var, tag); + } + } + else + value = _var.value(comp); + + return value; +} + +template +class VariableGradientTempl +{ + using real3_type = std::conditional_t; + public: /** * Default constructor */ - VariableGradient() = default; + VariableGradientTempl() = default; /** * Constructor * @param var The Kokkos variable */ - VariableGradient(Variable var) : _var(var) {} + VariableGradientTempl(Variable var) : _var(var) {} /** * Constructor * @param var The MOOSE variable * @param tag The vector tag name */ - VariableGradient(const MooseVariableBase & var, const TagName & tag = Moose::SOLUTION_TAG) + VariableGradientTempl(const MooseVariableFieldBase & var, + const TagName & tag = Moose::SOLUTION_TAG) : _var(var, tag) { } + /** + * Constructor + * @param vars The MOOSE variables + * @param tag The vector tag name + */ + ///@{ + VariableGradientTempl(const std::vector & vars, + const TagName & tag = Moose::SOLUTION_TAG) + : _var(vars, tag) + { + } + VariableGradientTempl(const std::vector vars, + const TagName & tag = Moose::SOLUTION_TAG) + : _var(vars, tag) + { + } + ///@} + + /** + * Copy constructor for parallel dispatch + */ + VariableGradientTempl(const VariableGradientTempl & object); + /** + * Copy assignment operator + */ + VariableGradientTempl & operator=(const VariableGradientTempl & object); /** * Get whether the variable was coupled @@ -204,11 +402,24 @@ class VariableGradient /** * Get the current variable gradient * @param datum The Datum object of the current thread - * @param idx The local quadrature point or DOF index + * @param qp The local quadrature point index * @param comp The variable component * @returns The variable gradient */ - KOKKOS_FUNCTION Real3 operator()(Datum & datum, unsigned int idx, unsigned int comp = 0) const; + KOKKOS_FUNCTION auto operator()(Datum & datum, unsigned int qp, unsigned int comp = 0) const + { + return get(datum, qp, comp); + } + + /** + * Get the current variable gradient + * @param datum The AssemblyDatum object of the current thread + * @param qp The local quadrature point index + * @param comp The variable component + * @returns The variable gradient + */ + KOKKOS_FUNCTION auto + operator()(AssemblyDatum & datum, unsigned int qp, unsigned int comp = 0) const; /** * Get the Kokkos variable @@ -217,76 +428,125 @@ class VariableGradient KOKKOS_FUNCTION const Variable & variable() const { return _var; } private: + /** + * Get the current variable gradient + * @param datum The Datum object of the current thread + * @param qp The local quadrature point index + * @param comp The variable component + * @param seed The derivative seed (only meaningful for AD) + * @returns The variable gradient + */ + KOKKOS_FUNCTION auto + get(Datum & datum, unsigned int qp, unsigned int comp = 0, Real seed = 0) const; + /** * Coupled Kokkos variable */ Variable _var; + /** + * Derivative seed of each component for AD + */ + Array _seed; }; -///@} -KOKKOS_FUNCTION inline Real -VariableValue::operator()(Datum & datum, unsigned int idx, unsigned int comp) const +template +VariableGradientTempl::VariableGradientTempl(const VariableGradientTempl & object) + : _var(object._var), _seed(object._seed) { - KOKKOS_ASSERT(_var.initialized()); - - if (_var.coupled()) - { - auto & sys = datum.system(_var.sys(comp)); - auto var = _var.var(comp); - auto tag = _var.tag(); - - if (_dof) + if constexpr (is_ad) + if (_var.coupled()) { - unsigned int dof; + if (!_seed.isAlloc()) + _seed.create(_var.components()); - if (datum.isNodal()) - { - auto node = datum.node(); - dof = sys.getNodeLocalDofIndex(node, 0, var); - } - else - { - auto elem = datum.elem().id; - dof = sys.getElemLocalDofIndex(elem, idx, var); - } + for (unsigned int comp = 0; comp < _var.components(); ++comp) + _seed[comp] = _var.dot() ? _var.mooseVar(comp)->sys().duDotDu(_var.var(comp)) : 1; - return sys.getVectorDofValue(dof, tag); + _seed.copyToDevice(); } - else - { - auto & elem = datum.elem(); - auto side = datum.side(); - auto offset = datum.qpOffset(); +} - return side == libMesh::invalid_uint ? sys.getVectorQpValue(elem, offset + idx, var, tag) - : sys.getVectorQpValueFace(elem, side, idx, var, tag); - } +template +VariableGradientTempl & +VariableGradientTempl::operator=(const VariableGradientTempl & object) +{ + _var = object._var; + + return *this; +} + +template +KOKKOS_FUNCTION auto +VariableGradientTempl::operator()(AssemblyDatum & datum, + unsigned int qp, + unsigned int comp) const +{ + if constexpr (is_ad) + { + Real seed = + datum.do_derivatives() && _var.coupled() && _var.sys(comp) == datum.sys() ? _seed[comp] : 0; + + return get(datum, qp, comp, seed); } else - return _var.value(comp); + return get(datum, qp, comp); } -KOKKOS_FUNCTION inline Real3 -VariableGradient::operator()(Datum & datum, unsigned int qp, unsigned int comp) const +template +KOKKOS_FUNCTION auto +VariableGradientTempl::get(Datum & datum, + unsigned int qp, + unsigned int comp, + [[maybe_unused]] Real seed) const { KOKKOS_ASSERT(_var.initialized()); + real3_type grad; + if (_var.coupled()) { KOKKOS_ASSERT(!datum.isNodal()); auto & elem = datum.elem(); auto side = datum.side(); - auto offset = datum.qpOffset(); - return side == libMesh::invalid_uint - ? datum.system(_var.sys(comp)) - .getVectorQpGrad(elem, offset + qp, _var.var(comp), _var.tag()) - : datum.system(_var.sys(comp)) - .getVectorQpGradFace(elem, side, datum.J(qp), qp, _var.var(comp), _var.tag()); + if constexpr (is_ad) + grad = + side == libMesh::invalid_uint + ? datum.system(_var.sys(comp)) + .getVectorQpADGrad( + elem, datum.J(qp), datum.qpOffset(), qp, _var.var(comp), _var.tag(), seed) + : datum.system(_var.sys(comp)) + .getVectorQpADGradFace( + elem, side, datum.J(qp), qp, _var.var(comp), _var.tag(), seed); + else + grad = + side == libMesh::invalid_uint + ? datum.system(_var.sys(comp)) + .getVectorQpGrad(elem, datum.qpOffset() + qp, _var.var(comp), _var.tag()) + : datum.system(_var.sys(comp)) + .getVectorQpGradFace(elem, side, datum.J(qp), qp, _var.var(comp), _var.tag()); } - else - return Real3(0); + + return grad; } +using VariableValue = VariableValueTempl; +using ADVariableValue = VariableValueTempl; +using VariableGradient = VariableGradientTempl; +using ADVariableGradient = VariableGradientTempl; + +template <> +struct ArrayDeepCopy +{ + static constexpr bool value = true; +}; + +template <> +struct ArrayDeepCopy +{ + static constexpr bool value = true; +}; +///@} + } // namespace Moose::Kokkos diff --git a/framework/include/kokkos/bcs/KokkosADCoupledVarNeumannBC.h b/framework/include/kokkos/bcs/KokkosADCoupledVarNeumannBC.h new file mode 100644 index 000000000000..6574abac57b8 --- /dev/null +++ b/framework/include/kokkos/bcs/KokkosADCoupledVarNeumannBC.h @@ -0,0 +1,50 @@ +//* This file is part of the MOOSE framework +//* https://mooseframework.inl.gov +//* +//* All rights reserved, see COPYRIGHT for full restrictions +//* https://github.com/idaholab/moose/blob/master/COPYRIGHT +//* +//* Licensed under LGPL 2.1, please see LICENSE for details +//* https://www.gnu.org/licenses/lgpl-2.1.html + +#pragma once + +#include "KokkosADIntegratedBC.h" + +/** + * Implements a Neumann BC where grad(u)=_coupled_var on the boundary. + * Uses the term produced from integrating the diffusion operator by parts. + */ +class KokkosADCoupledVarNeumannBC : public Moose::Kokkos::ADIntegratedBC +{ +public: + static InputParameters validParams(); + + KokkosADCoupledVarNeumannBC(const InputParameters & parameters); + + template + KOKKOS_FUNCTION Moose::Kokkos::ADReal + computeQpResidual(const unsigned int i, const unsigned int qp, AssemblyDatum & datum) const; + +protected: + /// Variable providing the value of grad(u) on the boundary. + const Moose::Kokkos::ADVariableValue _coupled_var; + + /// The identifying number of the coupled variable + const unsigned int _coupled_num; + + /// A coefficient that is multiplied with the residual contribution + const Real _coef; + + /// Scale factor + const Moose::Kokkos::ADVariableValue _scale_factor; +}; + +template +KOKKOS_FUNCTION Moose::Kokkos::ADReal +KokkosADCoupledVarNeumannBC::computeQpResidual(const unsigned int i, + const unsigned int qp, + AssemblyDatum & datum) const +{ + return -_test(datum, i, qp) * _scale_factor(datum, qp) * _coef * _coupled_var(datum, qp); +} diff --git a/framework/include/kokkos/bcs/KokkosADIntegratedBC.h b/framework/include/kokkos/bcs/KokkosADIntegratedBC.h new file mode 100644 index 000000000000..6d87a82fa89a --- /dev/null +++ b/framework/include/kokkos/bcs/KokkosADIntegratedBC.h @@ -0,0 +1,141 @@ +//* This file is part of the MOOSE framework +//* https://www.mooseframework.org +//* +//* All rights reserved, see COPYRIGHT for full restrictions +//* https://github.com/idaholab/moose/blob/master/COPYRIGHT +//* +//* Licensed under LGPL 2.1, please see LICENSE for details +//* https://www.gnu.org/licenses/lgpl-2.1.html + +#pragma once + +#include "KokkosIntegratedBCBase.h" + +namespace Moose::Kokkos +{ + +/** + * The base class for a user to derive their own Kokkos integrated boundary conditions using + * automatic differentiation (AD). + * + * The user should define computeQpResidual() as inlined public methods in their derived class (not + * virtual override). The signature of computeQpResidual() expected to be defined in the derived + * class is as follows: + * + * @tparam Derived The object type + * @param i The element-local DOF index + * @param qp The local quadrature point index + * @param datum The AssemblyDatum object of the current thread + * @returns The residual contribution + * + * template + * KOKKOS_FUNCTION Moose::Kokkos::ADReal computeQpResidual(const unsigned int i, + * const unsigned int qp, + * AssemblyDatum & datum) const; + * + * Note that computeQpJacobian() and computeQpOffDiagJacobian() are unused for AD integrated + * boundary conditions. + */ +class ADIntegratedBC : public IntegratedBCBase +{ +public: + static InputParameters validParams(); + + /** + * Constructor + */ + ADIntegratedBC(const InputParameters & parameters); + + virtual void computeResidual() override; + virtual void computeJacobian() override; + virtual void computeResidualAndJacobian() override; + + /** + * The parallel computation entry function called by Kokkos + */ + template + KOKKOS_FUNCTION void operator()(ResidualLoop, const ThreadID tid, const Derived & bc) const; + + /** + * Compute residual + * @param bc The boundary condition object of the final derived type + * @param datum The AssemblyDatum object of the current thread + */ + template + KOKKOS_FUNCTION void computeResidualInternal(const Derived & bc, AssemblyDatum & datum) const; + +protected: + /** + * Dispatch parallel calculation + */ + virtual void dispatch(); + + /** + * Current test function + */ + const ADVariableTestValue _test; + /** + * Gradient of the current test function + */ + const ADVariableTestGradient _grad_test; + /** + * Current shape function + */ + const ADVariablePhiValue _phi; + /** + * Gradient of the current shape function + */ + const ADVariablePhiGradient _grad_phi; + /** + * Current solution at quadrature points + */ + const ADVariableValue _u; + /** + * Gradient of the current solution at quadrature points + */ + const ADVariableGradient _grad_u; + /** + * Whether computing residual + */ + bool _computing_residual = false; + /** + * Whether computing Jacobian + */ + bool _computing_jacobian = false; +}; + +template +KOKKOS_FUNCTION void +ADIntegratedBC::operator()(ResidualLoop, const ThreadID tid, const Derived & bc) const +{ + auto [elem, side] = kokkosBoundaryElementSideID(_thread(tid, 1)); + + AssemblyDatum datum( + elem, side, kokkosAssembly(), kokkosSystems(), _kokkos_var, _kokkos_var.var()); + + datum.set_local_parallel(_thread(tid, 0), _thread.size(0)); + + datum.do_derivatives(_computing_jacobian); + + bc.computeResidualInternal(bc, datum); +} + +template +KOKKOS_FUNCTION void +ADIntegratedBC::computeResidualInternal(const Derived & bc, AssemblyDatum & datum) const +{ + for (unsigned int i = datum.local_thread_id(); i < datum.n_dofs(); i += datum.num_local_threads()) + { + ADReal local_re = 0; + + for (unsigned int qp = 0; qp < datum.n_qps(); ++qp) + local_re += datum.JxW(qp) * bc.template computeQpResidual(i, qp, datum); + + if (_computing_residual) + accumulateTaggedElementalResidual(local_re.value(), datum.elem().id, i); + if (_computing_jacobian) + accumulateTaggedElementalMatrix(local_re.derivatives(), datum, i); + } +} + +} // namespace Moose::Kokkos diff --git a/framework/include/kokkos/bcs/KokkosADNeumannBC.h b/framework/include/kokkos/bcs/KokkosADNeumannBC.h new file mode 100644 index 000000000000..c5cd63ddba53 --- /dev/null +++ b/framework/include/kokkos/bcs/KokkosADNeumannBC.h @@ -0,0 +1,37 @@ +//* This file is part of the MOOSE framework +//* https://www.mooseframework.org +//* +//* All rights reserved, see COPYRIGHT for full restrictions +//* https://github.com/idaholab/moose/blob/master/COPYRIGHT +//* +//* Licensed under LGPL 2.1, please see LICENSE for details +//* https://www.gnu.org/licenses/lgpl-2.1.html + +#pragma once + +#include "KokkosADIntegratedBC.h" + +class KokkosADNeumannBC : public Moose::Kokkos::ADIntegratedBC +{ +public: + static InputParameters validParams(); + + KokkosADNeumannBC(const InputParameters & parameters); + + template + KOKKOS_FUNCTION Moose::Kokkos::ADReal + computeQpResidual(const unsigned int i, const unsigned int qp, AssemblyDatum & datum) const; + +private: + /// Value of grad(u) on the boundary. + const Real _value; +}; + +template +KOKKOS_FUNCTION Moose::Kokkos::ADReal +KokkosADNeumannBC::computeQpResidual(const unsigned int i, + const unsigned int qp, + AssemblyDatum & datum) const +{ + return -_test(datum, i, qp) * _value; +} diff --git a/framework/include/kokkos/bcs/KokkosADNodalBC.h b/framework/include/kokkos/bcs/KokkosADNodalBC.h new file mode 100644 index 000000000000..72763a1c1130 --- /dev/null +++ b/framework/include/kokkos/bcs/KokkosADNodalBC.h @@ -0,0 +1,99 @@ +//* This file is part of the MOOSE framework +//* https://www.mooseframework.org +//* +//* All rights reserved, see COPYRIGHT for full restrictions +//* https://github.com/idaholab/moose/blob/master/COPYRIGHT +//* +//* Licensed under LGPL 2.1, please see LICENSE for details +//* https://www.gnu.org/licenses/lgpl-2.1.html + +#pragma once + +#include "KokkosNodalBCBase.h" + +namespace Moose::Kokkos +{ + +/** + * The base class for a user to derive their own Kokkos nodal boundary conditions using automatic + * differentiation (AD). + * + * The user should define computeQpResidual() as inlined public methods in their derived class (not + * virtual override). The signature of computeQpResidual() expected to be defined in the derived + * class is as follows: + * + * @tparam Derived The object type + * @param qp The dummy quadrature point index (= 0) + * @param datum The AssemblyDatum object of the current thread + * @returns The residual contribution + * + * template + * KOKKOS_FUNCTION Moose::Kokkos::ADReal computeQpResidual(const unsigned int qp, + * AssemblyDatum & datum) const; + * + * Note that computeQpJacobian() and computeQpOffDiagJacobian() are unused for AD nodal boundary + * conditions. + */ +class ADNodalBC : public NodalBCBase +{ +public: + static InputParameters validParams(); + + /** + * Constructor + */ + ADNodalBC(const InputParameters & parameters); + + virtual void computeResidual() override; + virtual void computeJacobian() override; + virtual void computeResidualAndJacobian() override; + + /** + * The parallel computation entry function called by Kokkos + */ + template + KOKKOS_FUNCTION void operator()(ResidualLoop, const ThreadID tid, const Derived & bc) const; + +protected: + /** + * Dispatch parallel calculation + */ + virtual void dispatch(); + + /** + * Current solution at nodes + */ + const ADVariableValue _u; + /** + * Whether computing residual + */ + bool _computing_residual = false; + /** + * Whether computing Jacobian + */ + bool _computing_jacobian = false; +}; + +template +KOKKOS_FUNCTION void +ADNodalBC::operator()(ResidualLoop, const ThreadID tid, const Derived & bc) const +{ + auto node = kokkosBoundaryNodeID(tid); + auto & sys = kokkosSystem(_kokkos_var.sys()); + + if (!sys.isNodalDefined(node, _kokkos_var.var())) + return; + + AssemblyDatum datum(node, kokkosAssembly(), kokkosSystems(), _kokkos_var, _kokkos_var.var()); + + datum.do_derivatives(_computing_jacobian); + + ADReal local_re = bc.template computeQpResidual(0, datum); + + if (_computing_residual) + accumulateTaggedNodalResidual(false, local_re.value(), node); + if (_computing_jacobian) + accumulateTaggedNodalMatrix(false, local_re.derivatives(), node); +} + +} // namespace Moose::Kokkos diff --git a/framework/include/kokkos/bcs/KokkosDirichletBC.h b/framework/include/kokkos/bcs/KokkosDirichletBC.h index 4d154fd4a6a9..dfae6b32270b 100644 --- a/framework/include/kokkos/bcs/KokkosDirichletBC.h +++ b/framework/include/kokkos/bcs/KokkosDirichletBC.h @@ -11,12 +11,13 @@ #include "KokkosDirichletBCBase.h" -class KokkosDirichletBC : public Moose::Kokkos::DirichletBCBase +template +class KokkosDirichletBCTempl : public Moose::Kokkos::DirichletBCBaseTempl { public: static InputParameters validParams(); - KokkosDirichletBC(const InputParameters & parameters); + KokkosDirichletBCTempl(const InputParameters & parameters); KOKKOS_FUNCTION Real computeValue(const unsigned int /* qp */, AssemblyDatum & /* datum */) const { @@ -26,3 +27,6 @@ class KokkosDirichletBC : public Moose::Kokkos::DirichletBCBase protected: const Moose::Kokkos::Scalar _value; }; + +typedef KokkosDirichletBCTempl KokkosDirichletBC; +typedef KokkosDirichletBCTempl KokkosADDirichletBC; diff --git a/framework/include/kokkos/bcs/KokkosDirichletBCBase.h b/framework/include/kokkos/bcs/KokkosDirichletBCBase.h index 850c41b33eb5..9fd9b66b0c16 100644 --- a/framework/include/kokkos/bcs/KokkosDirichletBCBase.h +++ b/framework/include/kokkos/bcs/KokkosDirichletBCBase.h @@ -10,6 +10,7 @@ #pragma once #include "KokkosNodalBC.h" +#include "KokkosADNodalBC.h" namespace Moose::Kokkos { @@ -17,15 +18,18 @@ namespace Moose::Kokkos /** * The base Kokkos boundary condition of a Dirichlet type */ -class DirichletBCBase : public NodalBC +template +class DirichletBCBaseTempl : public std::conditional_t { + using real_type = std::conditional_t; + public: static InputParameters validParams(); /** * Constructor */ - DirichletBCBase(const InputParameters & parameters); + DirichletBCBaseTempl(const InputParameters & parameters); /** * Get whether the value is to be preset @@ -53,9 +57,19 @@ class DirichletBCBase : public NodalBC KOKKOS_FUNCTION void operator()(PresetLoop, const ThreadID tid, const Derived & bc) const; template - KOKKOS_FUNCTION Real computeQpResidual(const unsigned int qp, AssemblyDatum & datum) const; + KOKKOS_FUNCTION auto computeQpResidual(const unsigned int qp, AssemblyDatum & datum) const; + + using Base = std::conditional_t; + using Base::operator(); - using NodalBC::operator(); +protected: + using Base::_kokkos_var; + using Base::_u; + using Base::kokkosAssembly; + using Base::kokkosBoundaryNodeID; + using Base::kokkosSystem; + using Base::kokkosSystems; + using Base::numKokkosBoundaryNodes; private: /** @@ -68,9 +82,10 @@ class DirichletBCBase : public NodalBC TagID _solution_tag; }; +template template KOKKOS_FUNCTION void -DirichletBCBase::operator()(PresetLoop, const ThreadID tid, const Derived & bc) const +DirichletBCBaseTempl::operator()(PresetLoop, const ThreadID tid, const Derived & bc) const { auto node = kokkosBoundaryNodeID(tid); auto & sys = kokkosSystem(_kokkos_var.sys()); @@ -84,17 +99,25 @@ DirichletBCBase::operator()(PresetLoop, const ThreadID tid, const Derived & bc) sys.getVectorDofValue(dof, _solution_tag) = bc.computeValue(0, datum); } +template template -KOKKOS_FUNCTION Real -DirichletBCBase::computeQpResidual(const unsigned int qp, AssemblyDatum & datum) const +KOKKOS_FUNCTION auto +DirichletBCBaseTempl::computeQpResidual(const unsigned int qp, AssemblyDatum & datum) const { auto bc = static_cast(this); - return _u(datum, qp) - bc->computeValue(qp, datum); + return _u(datum, qp) - real_type(bc->computeValue(qp, datum)); } +typedef DirichletBCBaseTempl DirichletBCBase; +typedef DirichletBCBaseTempl ADDirichletBCBase; + } // namespace Moose::Kokkos #define registerKokkosDirichletBC(app, classname) \ registerKokkosBoundaryCondition(app, classname); \ registerKokkosAdditionalOperation(classname, PresetLoop) + +#define registerKokkosADDirichletBC(app, classname) \ + registerKokkosADBoundaryCondition(app, classname); \ + registerKokkosAdditionalOperation(classname, PresetLoop) diff --git a/framework/include/kokkos/kernels/KokkosADCoupledTimeDerivative.h b/framework/include/kokkos/kernels/KokkosADCoupledTimeDerivative.h new file mode 100644 index 000000000000..00865a75a09d --- /dev/null +++ b/framework/include/kokkos/kernels/KokkosADCoupledTimeDerivative.h @@ -0,0 +1,39 @@ +//* This file is part of the MOOSE framework +//* https://mooseframework.inl.gov +//* +//* All rights reserved, see COPYRIGHT for full restrictions +//* https://github.com/idaholab/moose/blob/master/COPYRIGHT +//* +//* Licensed under LGPL 2.1, please see LICENSE for details +//* https://www.gnu.org/licenses/lgpl-2.1.html + +#pragma once + +#include "KokkosADKernel.h" + +/** + * This calculates the time derivative for a coupled variable + **/ +class KokkosADCoupledTimeDerivative : public Moose::Kokkos::ADKernel +{ +public: + static InputParameters validParams(); + + KokkosADCoupledTimeDerivative(const InputParameters & parameters); + + template + KOKKOS_FUNCTION Moose::Kokkos::ADReal + computeQpResidual(const unsigned int i, const unsigned int qp, AssemblyDatum & datum) const; + +protected: + const Moose::Kokkos::ADVariableValue _v_dot; +}; + +template +KOKKOS_FUNCTION Moose::Kokkos::ADReal +KokkosADCoupledTimeDerivative::computeQpResidual(const unsigned int i, + const unsigned int qp, + AssemblyDatum & datum) const +{ + return _test(datum, i, qp) * _v_dot(datum, qp); +} diff --git a/framework/include/kokkos/kernels/KokkosADDiffusion.h b/framework/include/kokkos/kernels/KokkosADDiffusion.h new file mode 100644 index 000000000000..39d1b1a27cd7 --- /dev/null +++ b/framework/include/kokkos/kernels/KokkosADDiffusion.h @@ -0,0 +1,33 @@ +//* This file is part of the MOOSE framework +//* https://mooseframework.inl.gov +//* +//* All rights reserved, see COPYRIGHT for full restrictions +//* https://github.com/idaholab/moose/blob/master/COPYRIGHT +//* +//* Licensed under LGPL 2.1, please see LICENSE for details +//* https://www.gnu.org/licenses/lgpl-2.1.html + +#pragma once + +#include "KokkosADKernel.h" + +class KokkosADDiffusion : public Moose::Kokkos::ADKernel +{ +public: + static InputParameters validParams(); + + KokkosADDiffusion(const InputParameters & parameters); + + template + KOKKOS_FUNCTION Moose::Kokkos::ADReal + computeQpResidual(const unsigned int i, const unsigned int qp, AssemblyDatum & datum) const; +}; + +template +KOKKOS_FUNCTION Moose::Kokkos::ADReal +KokkosADDiffusion::computeQpResidual(const unsigned int i, + const unsigned int qp, + AssemblyDatum & datum) const +{ + return _grad_u(datum, qp) * _grad_test(datum, i, qp); +} diff --git a/framework/include/kokkos/kernels/KokkosADKernel.h b/framework/include/kokkos/kernels/KokkosADKernel.h new file mode 100644 index 000000000000..90c2008b1fcb --- /dev/null +++ b/framework/include/kokkos/kernels/KokkosADKernel.h @@ -0,0 +1,144 @@ +//* This file is part of the MOOSE framework +//* https://www.mooseframework.org +//* +//* All rights reserved, see COPYRIGHT for full restrictions +//* https://github.com/idaholab/moose/blob/master/COPYRIGHT +//* +//* Licensed under LGPL 2.1, please see LICENSE for details +//* https://www.gnu.org/licenses/lgpl-2.1.html + +#pragma once + +#include "KokkosKernelBase.h" + +namespace Moose::Kokkos +{ + +/** + * The base class for a user to derive their own Kokkos kernels using automatic differentiation + * (AD). + * + * The user should define computeQpResidual() as inlined public method in their derived class (not + * virtual override). The signature of computeQpResidual() expected to be defined in the derived + * class is as follows: + * + * @tparam Derived The object type + * @param i The element-local DOF index + * @param qp The local quadrature point index + * @param datum The AssemblyDatum object of the current thread + * @returns The residual contribution + * + * template + * KOKKOS_FUNCTION Moose::Kokkos::ADReal computeQpResidual(const unsigned int i, + * const unsigned int qp, + * AssemblyDatum & datum) const; + * + * Note that computeQpJacobian() and computeQpOffDiagJacobian() are unused for AD kernels. + */ +class ADKernel : public KernelBase +{ +public: + static InputParameters validParams(); + + /** + * Constructor + */ + ADKernel(const InputParameters & parameters); + + virtual void computeResidual() override; + virtual void computeJacobian() override; + virtual void computeResidualAndJacobian() override; + + /** + * The parallel computation entry function called by Kokkos + */ + template + KOKKOS_FUNCTION void operator()(ResidualLoop, const ThreadID tid, const Derived & kernel) const; + + /** + * Compute residual + * @param kernel The kernel object of the final derived type + * @param datum The AssemblyDatum object of the current thread + */ + template + KOKKOS_FUNCTION void computeResidualInternal(const Derived & kernel, AssemblyDatum & datum) const; + +protected: + /** + * Dispatch parallel calculation + */ + virtual void dispatch(); + + /** + * Current test function + */ + const ADVariableTestValue _test; + /** + * Gradient of the current test function + */ + const ADVariableTestGradient _grad_test; + /** + * Current shape function + */ + const ADVariablePhiValue _phi; + /** + * Gradient of the current shape function + */ + const ADVariablePhiGradient _grad_phi; + /** + * Current solution at quadrature points + */ + const ADVariableValue _u; + /** + * Gradient of the current solution at quadrature points + */ + const ADVariableGradient _grad_u; + /** + * Whether computing residual + */ + bool _computing_residual = false; + /** + * Whether computing Jacobian + */ + bool _computing_jacobian = false; +}; + +template +KOKKOS_FUNCTION void +ADKernel::operator()(ResidualLoop, const ThreadID tid, const Derived & kernel) const +{ + auto elem = kokkosBlockElementID(_thread(tid, 1)); + + AssemblyDatum datum(elem, + libMesh::invalid_uint, + kokkosAssembly(), + kokkosSystems(), + _kokkos_var, + _kokkos_var.var()); + + datum.set_local_parallel(_thread(tid, 0), _thread.size(0)); + + datum.do_derivatives(_computing_jacobian); + + kernel.computeResidualInternal(kernel, datum); +} + +template +KOKKOS_FUNCTION void +ADKernel::computeResidualInternal(const Derived & kernel, AssemblyDatum & datum) const +{ + for (unsigned int i = datum.local_thread_id(); i < datum.n_dofs(); i += datum.num_local_threads()) + { + ADReal local_re = 0; + + for (unsigned int qp = 0; qp < datum.n_qps(); ++qp) + local_re += datum.JxW(qp) * kernel.template computeQpResidual(i, qp, datum); + + if (_computing_residual) + accumulateTaggedElementalResidual(local_re.value(), datum.elem().id, i); + if (_computing_jacobian) + accumulateTaggedElementalMatrix(local_re.derivatives(), datum, i); + } +} + +} // namespace Moose::Kokkos diff --git a/framework/include/kokkos/kernels/KokkosADTimeDerivative.h b/framework/include/kokkos/kernels/KokkosADTimeDerivative.h new file mode 100644 index 000000000000..b9fee32c6a18 --- /dev/null +++ b/framework/include/kokkos/kernels/KokkosADTimeDerivative.h @@ -0,0 +1,33 @@ +//* This file is part of the MOOSE framework +//* https://mooseframework.inl.gov +//* +//* All rights reserved, see COPYRIGHT for full restrictions +//* https://github.com/idaholab/moose/blob/master/COPYRIGHT +//* +//* Licensed under LGPL 2.1, please see LICENSE for details +//* https://www.gnu.org/licenses/lgpl-2.1.html + +#pragma once + +#include "KokkosADTimeKernel.h" + +class KokkosADTimeDerivative : public Moose::Kokkos::ADTimeKernel +{ +public: + static InputParameters validParams(); + + KokkosADTimeDerivative(const InputParameters & parameters); + + template + KOKKOS_FUNCTION Moose::Kokkos::ADReal + computeQpResidual(const unsigned int i, const unsigned int qp, AssemblyDatum & datum) const; +}; + +template +KOKKOS_FUNCTION Moose::Kokkos::ADReal +KokkosADTimeDerivative::computeQpResidual(const unsigned int i, + const unsigned int qp, + AssemblyDatum & datum) const +{ + return _test(datum, i, qp) * _u_dot(datum, qp); +} diff --git a/framework/include/kokkos/kernels/KokkosADTimeKernel.h b/framework/include/kokkos/kernels/KokkosADTimeKernel.h new file mode 100644 index 000000000000..30dda62b341d --- /dev/null +++ b/framework/include/kokkos/kernels/KokkosADTimeKernel.h @@ -0,0 +1,37 @@ +//* This file is part of the MOOSE framework +//* https://www.mooseframework.org +//* +//* All rights reserved, see COPYRIGHT for full restrictions +//* https://github.com/idaholab/moose/blob/master/COPYRIGHT +//* +//* Licensed under LGPL 2.1, please see LICENSE for details +//* https://www.gnu.org/licenses/lgpl-2.1.html + +#pragma once + +#include "KokkosADKernel.h" + +namespace Moose::Kokkos +{ + +/** + * The base class for Kokkos time-derivative kernels + */ +class ADTimeKernel : public ADKernel +{ +public: + static InputParameters validParams(); + + /** + * Constructor + */ + ADTimeKernel(const InputParameters & parameters); + +protected: + /** + * Time derivative of the current solution at quadrature points + */ + const ADVariableValue _u_dot; +}; + +} // namespace Moose::Kokkos diff --git a/framework/include/kokkos/systems/KokkosSystem.h b/framework/include/kokkos/systems/KokkosSystem.h index ee118a39824b..15fef0c6893e 100644 --- a/framework/include/kokkos/systems/KokkosSystem.h +++ b/framework/include/kokkos/systems/KokkosSystem.h @@ -287,10 +287,20 @@ class System : public MeshHolder, public AssemblyHolder * @param tag The vector tag * @returns The DOF value */ - KOKKOS_FUNCTION Real & getVectorDofValue(dof_id_type dof, TagID tag) const + KOKKOS_FUNCTION Real & getVectorDofValue(const dof_id_type dof, const TagID tag) const { return _vectors[tag][dof]; } + /** + * Get the DOF value of a tagged vector for automatic differentiation (AD) + * @param dof The local DOF index + * @param tag The vector tag + * @param seed The derivative seed + * @returns The DOF AD value with optional seed derivative + */ + KOKKOS_FUNCTION ADReal getVectorDofADValue(const dof_id_type dof, + const TagID tag, + const Real seed) const; /** * Get the quadrature value of a variable from a tagged vector * @param info The element information object @@ -299,11 +309,29 @@ class System : public MeshHolder, public AssemblyHolder * @param tag The vector tag * @returns The quadrature value */ - KOKKOS_FUNCTION Real & - getVectorQpValue(ElementInfo info, dof_id_type qp, unsigned int var, TagID tag) const + KOKKOS_FUNCTION Real & getVectorQpValue(const ElementInfo info, + const dof_id_type qp, + const unsigned int var, + const TagID tag) const { return _qp_solutions[tag](info.subdomain, var)[qp]; } + /** + * Get the quadrature value of a variable from a tagged vector for automatic differentiation (AD) + * @param info The element information object + * @param offset The offset into the global quadrature point index + * @param qp The local quadrature point index + * @param var The variable number + * @param tag The vector tag + * @param seed The derivative seed + * @returns The quadrature AD value + */ + KOKKOS_FUNCTION ADReal getVectorQpADValue(const ElementInfo info, + const dof_id_type offset, + const dof_id_type qp, + const unsigned int var, + const TagID tag, + const Real seed) const; /** * Get the quadrature gradient of a variable from a tagged vector * @param info The element information object @@ -312,11 +340,32 @@ class System : public MeshHolder, public AssemblyHolder * @param tag The vector tag * @returns The quadrature gradient */ - KOKKOS_FUNCTION Real3 & - getVectorQpGrad(ElementInfo info, dof_id_type qp, unsigned int var, TagID tag) const + KOKKOS_FUNCTION Real3 & getVectorQpGrad(const ElementInfo info, + const dof_id_type qp, + const unsigned int var, + const TagID tag) const { return _qp_solutions_grad[tag](info.subdomain, var)[qp]; } + /** + * Get the quadrature gradient of a variable from a tagged vector for automatic differentiation + * (AD) + * @param info The element information object + * @param jacobian The inverse Jacobian matrix + * @param offset The offset into the global quadrature point index + * @param qp The local quadrature point index + * @param var The variable number + * @param tag The vector tag + * @param seed The derivative seed + * @returns The quadrature AD gradient + */ + KOKKOS_FUNCTION ADReal3 getVectorQpADGrad(const ElementInfo info, + const Real33 jacobian, + const dof_id_type offset, + const dof_id_type qp, + const unsigned int var, + const TagID tag, + const Real seed) const; /** * Get the face quadrature value of a variable from a tagged vector * @param info The element information object @@ -331,6 +380,23 @@ class System : public MeshHolder, public AssemblyHolder const unsigned int qp, const unsigned int var, const TagID tag) const; + /** + * Get the face quadrature value of a variable from a tagged vector for automatic differentiation + * (AD) + * @param info The element information object + * @param side The side index + * @param qp The local quadrature point index + * @param var The vriable number + * @param tag The vector tag + * @param seed The derivative seed + * @returns The face quadrature AD value + */ + KOKKOS_FUNCTION ADReal getVectorQpADValueFace(const ElementInfo info, + const unsigned int side, + const unsigned int qp, + const unsigned int var, + const TagID tag, + const Real seed) const; /** * Get the face quadrature gradient of a variable from a tagged vector * @param info The element information object @@ -347,6 +413,25 @@ class System : public MeshHolder, public AssemblyHolder const unsigned int qp, const unsigned int var, const TagID tag) const; + /** + * Get the face quadrature gradient of a variable from a tagged vector for automatic + * differentiation (AD) + * @param info The element information object + * @param side The side index + * @param jacobian The inverse Jacobian matrix + * @param qp The local quadrature point index + * @param var The variable number + * @param tag The vector tag + * @param seed The derivative seed + * @returns The face quadrature AD gradient + */ + KOKKOS_FUNCTION ADReal3 getVectorQpADGradFace(const ElementInfo info, + const unsigned int side, + const Real33 jacobian, + const unsigned int qp, + const unsigned int var, + const TagID tag, + const Real seed) const; /** * Get an entry from a tagged matrix * @param row The local row index @@ -512,9 +597,75 @@ class System : public MeshHolder, public AssemblyHolder }; #ifdef MOOSE_KOKKOS_SCOPE +KOKKOS_FUNCTION inline ADReal +System::getVectorDofADValue(const dof_id_type dof, TagID tag, const Real seed) const +{ + ADReal value = _vectors[tag][dof]; + + if (seed != 0) + value.derivatives().insert(_local_to_global_dof_index[dof]) = seed; + + return value; +} + +KOKKOS_FUNCTION inline ADReal +System::getVectorQpADValue(const ElementInfo info, + const dof_id_type offset, + const dof_id_type qp, + const unsigned int var, + const TagID tag, + const Real seed) const +{ + ADReal value = 0; + + if (seed == 0) + value = getVectorQpValue(info, offset + qp, var, tag); + else + { + auto fe = _var_fe_types[var]; + auto n_dofs = kokkosAssembly().getNumDofs(info.type, fe); + auto & phi = kokkosAssembly().getPhi(info.subdomain, info.type, fe); + + for (unsigned int i = 0; i < n_dofs; ++i) + value += getVectorDofADValue(getElemLocalDofIndex(info.id, i, var), tag, seed) * phi(i, qp); + } + + return value; +} + +KOKKOS_FUNCTION inline ADReal3 +System::getVectorQpADGrad(const ElementInfo info, + const Real33 jacobian, + const dof_id_type offset, + const dof_id_type qp, + const unsigned int var, + const TagID tag, + const Real seed) const +{ + ADReal3 grad; + + if (seed == 0) + grad = getVectorQpGrad(info, offset + qp, var, tag); + else + { + auto fe = _var_fe_types[var]; + auto n_dofs = kokkosAssembly().getNumDofs(info.type, fe); + auto & grad_phi = kokkosAssembly().getGradPhi(info.subdomain, info.type, fe); + + for (unsigned int i = 0; i < n_dofs; ++i) + grad += getVectorDofADValue(getElemLocalDofIndex(info.id, i, var), tag, seed) * + (jacobian * grad_phi(i, qp)); + } + + return grad; +} + KOKKOS_FUNCTION inline Real -System::getVectorQpValueFace( - ElementInfo info, unsigned int side, unsigned int qp, unsigned int var, TagID tag) const +System::getVectorQpValueFace(const ElementInfo info, + const unsigned int side, + const unsigned int qp, + const unsigned int var, + const TagID tag) const { auto fe = _var_fe_types[var]; auto n_dofs = kokkosAssembly().getNumDofs(info.type, fe); @@ -527,19 +678,40 @@ System::getVectorQpValueFace( return value; } + +KOKKOS_FUNCTION inline ADReal +System::getVectorQpADValueFace(const ElementInfo info, + const unsigned int side, + const unsigned int qp, + const unsigned int var, + const TagID tag, + const Real seed) const +{ + auto fe = _var_fe_types[var]; + auto n_dofs = kokkosAssembly().getNumDofs(info.type, fe); + auto & phi = kokkosAssembly().getPhiFace(info.subdomain, info.type, fe)(side); + + ADReal value = 0; + + for (unsigned int i = 0; i < n_dofs; ++i) + value += getVectorDofADValue(getElemLocalDofIndex(info.id, i, var), tag, seed) * phi(i, qp); + + return value; +} + KOKKOS_FUNCTION inline Real3 -System::getVectorQpGradFace(ElementInfo info, - unsigned int side, - Real33 jacobian, - unsigned int qp, - unsigned int var, - TagID tag) const +System::getVectorQpGradFace(const ElementInfo info, + const unsigned int side, + const Real33 jacobian, + const unsigned int qp, + const unsigned int var, + const TagID tag) const { auto fe = _var_fe_types[var]; auto n_dofs = kokkosAssembly().getNumDofs(info.type, fe); auto & grad_phi = kokkosAssembly().getGradPhiFace(info.subdomain, info.type, fe)(side); - Real3 grad = 0; + Real3 grad; for (unsigned int i = 0; i < n_dofs; ++i) grad += getVectorDofValue(getElemLocalDofIndex(info.id, i, var), tag) * @@ -547,6 +719,28 @@ System::getVectorQpGradFace(ElementInfo info, return grad; } + +KOKKOS_FUNCTION inline ADReal3 +System::getVectorQpADGradFace(const ElementInfo info, + const unsigned int side, + const Real33 jacobian, + const unsigned int qp, + const unsigned int var, + const TagID tag, + const Real seed) const +{ + auto fe = _var_fe_types[var]; + auto n_dofs = kokkosAssembly().getNumDofs(info.type, fe); + auto & grad_phi = kokkosAssembly().getGradPhiFace(info.subdomain, info.type, fe)(side); + + ADReal3 grad; + + for (unsigned int i = 0; i < n_dofs; ++i) + grad += getVectorDofADValue(getElemLocalDofIndex(info.id, i, var), tag, seed) * + (jacobian * grad_phi(i, qp)); + + return grad; +} #endif /** diff --git a/framework/include/kokkos/utils/KokkosADReal.h b/framework/include/kokkos/utils/KokkosADReal.h new file mode 100644 index 000000000000..08336318e044 --- /dev/null +++ b/framework/include/kokkos/utils/KokkosADReal.h @@ -0,0 +1,30 @@ +//* This file is part of the MOOSE framework +//* https://mooseframework.inl.gov +//* +//* All rights reserved, see COPYRIGHT for full restrictions +//* https://github.com/idaholab/moose/blob/master/COPYRIGHT +//* +//* Licensed under LGPL 2.1, please see LICENSE for details +//* https://www.gnu.org/licenses/lgpl-2.1.html + +#pragma once + +#include "ADRealForward.h" + +namespace Moose::Kokkos +{ + +using MetaPhysicL::KokkosSemiDynamicSparseNumberArray; + +typedef KokkosSemiDynamicSparseNumberArray> + DNDerivativeType; + +template +using DNDerivativeSize = + KokkosSemiDynamicSparseNumberArray>; + +typedef DualNumber ADReal; + +} // namespace Moose::Kokkos diff --git a/framework/src/base/Assembly.C b/framework/src/base/Assembly.C index ae09fd1e342f..025294918932 100644 --- a/framework/src/base/Assembly.C +++ b/framework/src/base/Assembly.C @@ -3787,6 +3787,16 @@ Assembly::elementVolume(const Elem * elem) const return vol; } +void +Assembly::saveLocalADArray(std::vector & re, + unsigned int i, + unsigned int ntest, + const ADRealEigenVector & v) const +{ + for (unsigned int j = 0; j < v.size(); ++j, i += ntest) + re[i] += v(j); +} + void Assembly::addCachedJacobian(GlobalDataKey) { diff --git a/framework/src/interfaces/TaggingInterface.C b/framework/src/interfaces/TaggingInterface.C index 29b679be2c52..2bb4bb7518d2 100644 --- a/framework/src/interfaces/TaggingInterface.C +++ b/framework/src/interfaces/TaggingInterface.C @@ -460,6 +460,24 @@ TaggingInterface::assignTaggedLocalMatrix() *ke = _local_ke; } +void +TaggingInterface::addResiduals(Assembly & assembly, const ADResidualsPacket & packet) +{ + addResiduals(assembly, packet.residuals, packet.dof_indices, packet.scaling_factor); +} + +void +TaggingInterface::addResidualsAndJacobian(Assembly & assembly, const ADResidualsPacket & packet) +{ + addResidualsAndJacobian(assembly, packet.residuals, packet.dof_indices, packet.scaling_factor); +} + +void +TaggingInterface::addJacobian(Assembly & assembly, const ADResidualsPacket & packet) +{ + addJacobian(assembly, packet.residuals, packet.dof_indices, packet.scaling_factor); +} + #ifndef NDEBUG void TaggingInterface::checkForNans() const diff --git a/framework/src/kokkos/base/KokkosVariable.K b/framework/src/kokkos/base/KokkosVariable.K index b00b73837611..b92342e7b386 100644 --- a/framework/src/kokkos/base/KokkosVariable.K +++ b/framework/src/kokkos/base/KokkosVariable.K @@ -16,13 +16,13 @@ namespace Moose::Kokkos { void -Variable::init(const MooseVariableBase & variable, const TagName & tag_name) +Variable::init(const MooseVariableFieldBase & variable, const TagName & tag_name) { init(variable, variable.sys().feProblem().getVectorTagID(tag_name)); } void -Variable::init(const MooseVariableBase & variable, const TagID tag) +Variable::init(const MooseVariableFieldBase & variable, const TagID tag) { _initialized = true; _coupled = true; @@ -30,23 +30,48 @@ Variable::init(const MooseVariableBase & variable, const TagID tag) _components = variable.count(); _tag = tag; + _moose_var.createHost(_components); _var.create(_components); _sys.create(_components); for (unsigned int comp = 0; comp < _components; ++comp) { + _moose_var[comp] = &variable; _var[comp] = variable.number() + comp; _sys[comp] = variable.sys().number(); } _var.copyToDevice(); _sys.copyToDevice(); + + const auto & problem = variable.sys().feProblem(); + + if (problem.vectorTagExists(Moose::SOLUTION_DOT_TAG)) + _dot = tag == problem.getVectorTagID(Moose::SOLUTION_DOT_TAG); +} + +void +Variable::init(const std::vector & variables, const TagName & tag_name) +{ + init(std::vector(variables.begin(), variables.end()), + variables[0]->sys().feProblem().getVectorTagID(tag_name)); +} + +void +Variable::init(const std::vector & variables, + const TagName & tag_name) +{ + init(variables, variables[0]->sys().feProblem().getVectorTagID(tag_name)); +} + +void +Variable::init(const std::vector & variables, const TagID tag) +{ + init(std::vector(variables.begin(), variables.end()), tag); } void -Variable::init(const std::vector & variables, - const TagID tag, - CoupleableKey) +Variable::init(const std::vector & variables, const TagID tag) { _initialized = true; _coupled = true; @@ -54,6 +79,7 @@ Variable::init(const std::vector & variables, _components = variables.size(); _tag = tag; + _moose_var.createHost(_components); _var.create(_components); _sys.create(_components); @@ -61,12 +87,18 @@ Variable::init(const std::vector & variables, { _nodal = _nodal && variables[comp]->isNodal(); + _moose_var[comp] = variables[comp]; _var[comp] = variables[comp]->number(); _sys[comp] = variables[comp]->sys().number(); } _var.copyToDevice(); _sys.copyToDevice(); + + const auto & problem = variables[0]->sys().feProblem(); + + if (problem.vectorTagExists(Moose::SOLUTION_DOT_TAG)) + _dot = tag == problem.getVectorTagID(Moose::SOLUTION_DOT_TAG); } void diff --git a/framework/src/kokkos/bcs/KokkosADCoupledVarNeumannBC.K b/framework/src/kokkos/bcs/KokkosADCoupledVarNeumannBC.K new file mode 100644 index 000000000000..6ccebcd64e2a --- /dev/null +++ b/framework/src/kokkos/bcs/KokkosADCoupledVarNeumannBC.K @@ -0,0 +1,35 @@ +//* This file is part of the MOOSE framework +//* https://mooseframework.inl.gov +//* +//* All rights reserved, see COPYRIGHT for full restrictions +//* https://github.com/idaholab/moose/blob/master/COPYRIGHT +//* +//* Licensed under LGPL 2.1, please see LICENSE for details +//* https://www.gnu.org/licenses/lgpl-2.1.html + +#include "KokkosADCoupledVarNeumannBC.h" + +registerKokkosADResidualObject("MooseApp", KokkosADCoupledVarNeumannBC); + +InputParameters +KokkosADCoupledVarNeumannBC::validParams() +{ + InputParameters params = ADIntegratedBC::validParams(); + params.addRequiredCoupledVar("v", "Coupled variable setting the gradient on the boundary."); + params.addCoupledVar("scale_factor", 1., "Scale factor to multiply the heat flux with"); + params.addParam( + "coef", 1.0, "Coefficent ($\\sigma$) multiplier for the coupled force term."); + params.addClassDescription("Imposes the integrated boundary condition " + "$\\frac{\\partial u}{\\partial n}=v$, " + "where $v$ is a variable."); + return params; +} + +KokkosADCoupledVarNeumannBC::KokkosADCoupledVarNeumannBC(const InputParameters & parameters) + : ADIntegratedBC(parameters), + _coupled_var(kokkosADCoupledValue("v")), + _coupled_num(coupled("v")), + _coef(getParam("coef")), + _scale_factor(kokkosADCoupledValue("scale_factor")) +{ +} diff --git a/framework/src/kokkos/bcs/KokkosADIntegratedBC.K b/framework/src/kokkos/bcs/KokkosADIntegratedBC.K new file mode 100644 index 000000000000..89a6a1f31a3d --- /dev/null +++ b/framework/src/kokkos/bcs/KokkosADIntegratedBC.K @@ -0,0 +1,74 @@ +//* This file is part of the MOOSE framework +//* https://www.mooseframework.org +//* +//* All rights reserved, see COPYRIGHT for full restrictions +//* https://github.com/idaholab/moose/blob/master/COPYRIGHT +//* +//* Licensed under LGPL 2.1, please see LICENSE for details +//* https://www.gnu.org/licenses/lgpl-2.1.html + +#include "KokkosADIntegratedBC.h" + +namespace Moose::Kokkos +{ + +InputParameters +ADIntegratedBC::validParams() +{ + InputParameters params = IntegratedBCBase::validParams(); + return params; +} + +ADIntegratedBC::ADIntegratedBC(const InputParameters & parameters) + : IntegratedBCBase(parameters, Moose::VarFieldType::VAR_FIELD_STANDARD), + _test(), + _grad_test(), + _phi(), + _grad_phi(), + _u(_var), + _grad_u(_var) +{ + addMooseVariableDependency(&_var); +} + +void +ADIntegratedBC::computeResidual() +{ + _computing_residual = true; + _computing_jacobian = false; + + dispatch(); +} + +void +ADIntegratedBC::computeJacobian() +{ + _computing_residual = false; + _computing_jacobian = true; + + dispatch(); +} + +void +ADIntegratedBC::computeResidualAndJacobian() +{ + _computing_residual = true; + _computing_jacobian = true; + + dispatch(); +} + +void +ADIntegratedBC::dispatch() +{ + _thread.resize(_num_local_threads, numKokkosBoundarySides()); + + Policy policy(0, _thread.size()); + + if (!_residual_dispatcher) + _residual_dispatcher = DispatcherRegistry::build(this, type()); + + _residual_dispatcher->parallelFor(policy); +} + +} // namespace Moose::Kokkos diff --git a/framework/src/kokkos/bcs/KokkosADNeumannBC.K b/framework/src/kokkos/bcs/KokkosADNeumannBC.K new file mode 100644 index 000000000000..2b0f10226d79 --- /dev/null +++ b/framework/src/kokkos/bcs/KokkosADNeumannBC.K @@ -0,0 +1,32 @@ +//* This file is part of the MOOSE framework +//* https://www.mooseframework.org +//* +//* All rights reserved, see COPYRIGHT for full restrictions +//* https://github.com/idaholab/moose/blob/master/COPYRIGHT +//* +//* Licensed under LGPL 2.1, please see LICENSE for details +//* https://www.gnu.org/licenses/lgpl-2.1.html + +#include "KokkosADNeumannBC.h" + +registerKokkosADResidualObject("MooseApp", KokkosADNeumannBC); + +InputParameters +KokkosADNeumannBC::validParams() +{ + InputParameters params = ADIntegratedBC::validParams(); + params.addParam("value", + 0.0, + "For a Laplacian problem, the value of the gradient dotted with the " + "normals on the boundary."); + params.declareControllable("value"); + params.addClassDescription("Imposes the integrated boundary condition " + "$\\frac{\\partial u}{\\partial n}=h$, " + "where $h$ is a constant, controllable value."); + return params; +} + +KokkosADNeumannBC::KokkosADNeumannBC(const InputParameters & parameters) + : ADIntegratedBC(parameters), _value(getParam("value")) +{ +} diff --git a/framework/src/kokkos/bcs/KokkosADNodalBC.K b/framework/src/kokkos/bcs/KokkosADNodalBC.K new file mode 100644 index 000000000000..e1b74090a411 --- /dev/null +++ b/framework/src/kokkos/bcs/KokkosADNodalBC.K @@ -0,0 +1,67 @@ +//* This file is part of the MOOSE framework +//* https://www.mooseframework.org +//* +//* All rights reserved, see COPYRIGHT for full restrictions +//* https://github.com/idaholab/moose/blob/master/COPYRIGHT +//* +//* Licensed under LGPL 2.1, please see LICENSE for details +//* https://www.gnu.org/licenses/lgpl-2.1.html + +#include "KokkosADNodalBC.h" + +namespace Moose::Kokkos +{ + +InputParameters +ADNodalBC::validParams() +{ + InputParameters params = NodalBCBase::validParams(); + return params; +} + +ADNodalBC::ADNodalBC(const InputParameters & parameters) + : NodalBCBase(parameters, Moose::VarFieldType::VAR_FIELD_STANDARD), + _u(_var, Moose::SOLUTION_TAG, true) +{ + addMooseVariableDependency(&_var); +} + +void +ADNodalBC::computeResidual() +{ + _computing_residual = true; + _computing_jacobian = false; + + dispatch(); +} + +void +ADNodalBC::computeJacobian() +{ + _computing_residual = false; + _computing_jacobian = true; + + dispatch(); +} + +void +ADNodalBC::computeResidualAndJacobian() +{ + _computing_residual = true; + _computing_jacobian = true; + + dispatch(); +} + +void +ADNodalBC::dispatch() +{ + Policy policy(0, numKokkosBoundaryNodes()); + + if (!_residual_dispatcher) + _residual_dispatcher = DispatcherRegistry::build(this, type()); + + _residual_dispatcher->parallelFor(policy); +} + +} // namespace Moose::Kokkos diff --git a/framework/src/kokkos/bcs/KokkosDirichletBC.K b/framework/src/kokkos/bcs/KokkosDirichletBC.K index 01da93bbffef..c8e584adc02d 100644 --- a/framework/src/kokkos/bcs/KokkosDirichletBC.K +++ b/framework/src/kokkos/bcs/KokkosDirichletBC.K @@ -10,11 +10,13 @@ #include "KokkosDirichletBC.h" registerKokkosDirichletBC("MooseApp", KokkosDirichletBC); +registerKokkosADDirichletBC("MooseApp", KokkosADDirichletBC); +template InputParameters -KokkosDirichletBC::validParams() +KokkosDirichletBCTempl::validParams() { - InputParameters params = DirichletBCBase::validParams(); + InputParameters params = Moose::Kokkos::DirichletBCBaseTempl::validParams(); params.addRequiredParam("value", "Value of the BC"); params.declareControllable("value"); params.addClassDescription("Imposes the essential boundary condition $u=g$, where $g$ " @@ -22,7 +24,12 @@ KokkosDirichletBC::validParams() return params; } -KokkosDirichletBC::KokkosDirichletBC(const InputParameters & parameters) - : DirichletBCBase(parameters), _value(getParam("value")) +template +KokkosDirichletBCTempl::KokkosDirichletBCTempl(const InputParameters & parameters) + : Moose::Kokkos::DirichletBCBaseTempl(parameters), + _value(this->template getParam("value")) { } + +template class KokkosDirichletBCTempl; +template class KokkosDirichletBCTempl; diff --git a/framework/src/kokkos/bcs/KokkosDirichletBCBase.K b/framework/src/kokkos/bcs/KokkosDirichletBCBase.K index e0b11667d2be..121b3ffce13c 100644 --- a/framework/src/kokkos/bcs/KokkosDirichletBCBase.K +++ b/framework/src/kokkos/bcs/KokkosDirichletBCBase.K @@ -12,30 +12,36 @@ namespace Moose::Kokkos { +template InputParameters -DirichletBCBase::validParams() +DirichletBCBaseTempl::validParams() { - InputParameters params = NodalBC::validParams(); + InputParameters params = Base::validParams(); params.addParam( "preset", true, "Whether or not to preset the BC (apply the value before the solve begins)."); return params; } -DirichletBCBase::DirichletBCBase(const InputParameters & parameters) - : NodalBC(parameters), _preset(getParam("preset")) +template +DirichletBCBaseTempl::DirichletBCBaseTempl(const InputParameters & parameters) + : Base(parameters), _preset(this->template getParam("preset")) { } +template void -DirichletBCBase::presetSolution(TagID tag) +DirichletBCBaseTempl::presetSolution(TagID tag) { _solution_tag = tag; Policy policy(0, numKokkosBoundaryNodes()); - auto dispatcher = DispatcherRegistry::build(this, type()); + auto dispatcher = DispatcherRegistry::build(this, this->type()); dispatcher->parallelFor(policy); } +template class DirichletBCBaseTempl; +template class DirichletBCBaseTempl; + } // namespace Moose::Kokkos diff --git a/framework/src/kokkos/interfaces/KokkosCoupleable.K b/framework/src/kokkos/interfaces/KokkosCoupleable.K index 737b2d185740..040c75f8da1c 100644 --- a/framework/src/kokkos/interfaces/KokkosCoupleable.K +++ b/framework/src/kokkos/interfaces/KokkosCoupleable.K @@ -13,6 +13,8 @@ #include "SystemBase.h" #include "FEProblemBase.h" +using CoupleableKey = Moose::Kokkos::Variable::CoupleableKey; + Moose::Kokkos::Variable Coupleable::kokkosCoupledVectorTagVariable(const std::string & var_name, const std::string & tag_name, @@ -34,10 +36,10 @@ Coupleable::kokkosCoupledVectorTagVariable(const std::string & var_name, const_cast(this)->addFEVariableCoupleableVectorTag(tag); - variable.init({var}, tag, {}); + variable.init(*var, tag); } else - variable.init({_c_parameters.defaultCoupledValue(var_name, comp)}, {}); + variable.init({_c_parameters.defaultCoupledValue(var_name, comp)}, CoupleableKey{}); return variable; } @@ -52,7 +54,7 @@ Coupleable::kokkosCoupledVectorTagVariables(const std::string & var_name, if (isCoupled(var_name)) { - std::vector vars; + std::vector vars; for (unsigned int comp = 0; comp < components; ++comp) { @@ -71,7 +73,7 @@ Coupleable::kokkosCoupledVectorTagVariables(const std::string & var_name, const_cast(this)->addFEVariableCoupleableVectorTag(tag); - variable.init({vars}, tag, {}); + variable.init(vars, tag); } else { @@ -80,7 +82,7 @@ Coupleable::kokkosCoupledVectorTagVariables(const std::string & var_name, for (unsigned int comp = 0; comp < components; ++comp) default_values[comp] = _c_parameters.defaultCoupledValue(var_name, comp); - variable.init(default_values, {}); + variable.init(default_values, CoupleableKey{}); } return variable; @@ -91,7 +93,7 @@ Coupleable::kokkosZeroVariable() const { Moose::Kokkos::Variable variable; - variable.init({0}, {}); + variable.init({0}, CoupleableKey{}); return variable; } @@ -459,6 +461,371 @@ Coupleable::kokkosCoupledNodalDots(const std::string & var_name) const return kokkosCoupledVectorTagNodalValuesByName(var_name, Moose::SOLUTION_DOT_TAG); } +Moose::Kokkos::ADVariableValue +Coupleable::kokkosADCoupledVectorTagValueByName(const std::string & var_name, + const std::string & tag_name, + unsigned int comp) const +{ + auto variable = kokkosCoupledVectorTagVariable(var_name, tag_name, comp); + + return Moose::Kokkos::ADVariableValue(variable); +} + +Moose::Kokkos::ADVariableValue +Coupleable::kokkosADCoupledVectorTagValuesByName(const std::string & var_name, + const std::string & tag_name) const +{ + auto variable = kokkosCoupledVectorTagVariables(var_name, tag_name); + + return Moose::Kokkos::ADVariableValue(variable); +} + +Moose::Kokkos::ADVariableGradient +Coupleable::kokkosADCoupledVectorTagGradientByName(const std::string & var_name, + const std::string & tag_name, + unsigned int comp) const +{ + auto variable = kokkosCoupledVectorTagVariable(var_name, tag_name, comp); + + return Moose::Kokkos::ADVariableGradient(variable); +} + +Moose::Kokkos::ADVariableGradient +Coupleable::kokkosADCoupledVectorTagGradientsByName(const std::string & var_name, + const std::string & tag_name) const +{ + auto variable = kokkosCoupledVectorTagVariables(var_name, tag_name); + + return Moose::Kokkos::ADVariableGradient(variable); +} + +Moose::Kokkos::ADVariableValue +Coupleable::kokkosADCoupledVectorTagNodalValueByName(const std::string & var_name, + const std::string & tag_name, + unsigned int comp) const +{ + auto variable = kokkosCoupledVectorTagVariable(var_name, tag_name, comp); + + if (!variable.nodal()) + mooseError("Cannot get nodal values from the coupled variable '", + var_name, + "', because the associated variable is not nodal."); + + return Moose::Kokkos::ADVariableValue(variable, true); +} + +Moose::Kokkos::ADVariableValue +Coupleable::kokkosADCoupledVectorTagNodalValuesByName(const std::string & var_name, + const std::string & tag_name) const +{ + auto variable = kokkosCoupledVectorTagVariables(var_name, tag_name); + + if (!variable.nodal()) + mooseError("Cannot get nodal values from the coupled variable '", + var_name, + "', because the associated variable is not nodal."); + + return Moose::Kokkos::ADVariableValue(variable, true); +} + +Moose::Kokkos::ADVariableValue +Coupleable::kokkosADCoupledVectorTagDofValueByName(const std::string & var_name, + const std::string & tag_name, + unsigned int comp) const +{ + auto variable = kokkosCoupledVectorTagVariable(var_name, tag_name, comp); + + return Moose::Kokkos::ADVariableValue(variable, true); +} + +Moose::Kokkos::ADVariableValue +Coupleable::kokkosADCoupledVectorTagDofValuesByName(const std::string & var_name, + const std::string & tag_name) const +{ + auto variable = kokkosCoupledVectorTagVariables(var_name, tag_name); + + return Moose::Kokkos::ADVariableValue(variable, true); +} + +Moose::Kokkos::ADVariableValue +Coupleable::kokkosADCoupledVectorTagValue(const std::string & var_name, + const std::string & tag_param_name, + unsigned int comp) const +{ + if (!_c_parameters.isParamValid(tag_param_name)) + mooseError("Tag name parameter '", tag_param_name, "' is invalid"); + + TagName tag_name = _c_parameters.get(tag_param_name); + + return kokkosADCoupledVectorTagValueByName(var_name, tag_name, comp); +} + +Moose::Kokkos::ADVariableValue +Coupleable::kokkosADCoupledVectorTagValues(const std::string & var_name, + const std::string & tag_param_name) const +{ + if (!_c_parameters.isParamValid(tag_param_name)) + mooseError("Tag name parameter '", tag_param_name, "' is invalid"); + + TagName tag_name = _c_parameters.get(tag_param_name); + + return kokkosADCoupledVectorTagValuesByName(var_name, tag_name); +} + +Moose::Kokkos::ADVariableGradient +Coupleable::kokkosADCoupledVectorTagGradient(const std::string & var_name, + const std::string & tag_param_name, + unsigned int comp) const +{ + if (!_c_parameters.isParamValid(tag_param_name)) + mooseError("Tag name parameter '", tag_param_name, "' is invalid"); + + TagName tag_name = _c_parameters.get(tag_param_name); + + return kokkosADCoupledVectorTagGradientByName(var_name, tag_name, comp); +} + +Moose::Kokkos::ADVariableGradient +Coupleable::kokkosADCoupledVectorTagGradients(const std::string & var_name, + const std::string & tag_param_name) const +{ + if (!_c_parameters.isParamValid(tag_param_name)) + mooseError("Tag name parameter '", tag_param_name, "' is invalid"); + + TagName tag_name = _c_parameters.get(tag_param_name); + + return kokkosADCoupledVectorTagGradientsByName(var_name, tag_name); +} + +Moose::Kokkos::ADVariableValue +Coupleable::kokkosADCoupledVectorTagNodalValue(const std::string & var_name, + const std::string & tag_param_name, + unsigned int comp) const +{ + if (!_c_parameters.isParamValid(tag_param_name)) + mooseError("Tag name parameter '", tag_param_name, "' is invalid"); + + TagName tag_name = _c_parameters.get(tag_param_name); + + return kokkosADCoupledVectorTagNodalValueByName(var_name, tag_name, comp); +} + +Moose::Kokkos::ADVariableValue +Coupleable::kokkosADCoupledVectorTagNodalValues(const std::string & var_name, + const std::string & tag_param_name) const +{ + if (!_c_parameters.isParamValid(tag_param_name)) + mooseError("Tag name parameter '", tag_param_name, "' is invalid"); + + TagName tag_name = _c_parameters.get(tag_param_name); + + return kokkosADCoupledVectorTagNodalValuesByName(var_name, tag_name); +} + +Moose::Kokkos::ADVariableValue +Coupleable::kokkosADCoupledVectorTagDofValue(const std::string & var_name, + const std::string & tag_param_name, + unsigned int comp) const +{ + if (!_c_parameters.isParamValid(tag_param_name)) + mooseError("Tag name parameter '", tag_param_name, "' is invalid"); + + TagName tag_name = _c_parameters.get(tag_param_name); + + return kokkosADCoupledVectorTagDofValueByName(var_name, tag_name, comp); +} + +Moose::Kokkos::ADVariableValue +Coupleable::kokkosADCoupledVectorTagDofValues(const std::string & var_name, + const std::string & tag_param_name) const +{ + if (!_c_parameters.isParamValid(tag_param_name)) + mooseError("Tag name parameter '", tag_param_name, "' is invalid"); + + TagName tag_name = _c_parameters.get(tag_param_name); + + return kokkosADCoupledVectorTagDofValuesByName(var_name, tag_name); +} + +Moose::Kokkos::ADVariableValue +Coupleable::kokkosADCoupledValue(const std::string & var_name, unsigned int comp) const +{ + return _c_nodal ? kokkosADCoupledVectorTagNodalValueByName(var_name, Moose::SOLUTION_TAG, comp) + : kokkosADCoupledVectorTagValueByName(var_name, Moose::SOLUTION_TAG, comp); +} + +Moose::Kokkos::ADVariableValue +Coupleable::kokkosADCoupledValues(const std::string & var_name) const +{ + return _c_nodal ? kokkosADCoupledVectorTagNodalValuesByName(var_name, Moose::SOLUTION_TAG) + : kokkosADCoupledVectorTagValuesByName(var_name, Moose::SOLUTION_TAG); +} + +Moose::Kokkos::ADVariableGradient +Coupleable::kokkosADCoupledGradient(const std::string & var_name, unsigned int comp) const +{ + return kokkosADCoupledVectorTagGradientByName(var_name, Moose::SOLUTION_TAG, comp); +} + +Moose::Kokkos::ADVariableGradient +Coupleable::kokkosADCoupledGradients(const std::string & var_name) const +{ + return kokkosADCoupledVectorTagGradientsByName(var_name, Moose::SOLUTION_TAG); +} + +Moose::Kokkos::ADVariableValue +Coupleable::kokkosADCoupledNodalValue(const std::string & var_name, unsigned int comp) const +{ + return kokkosADCoupledVectorTagNodalValueByName(var_name, Moose::SOLUTION_TAG, comp); +} + +Moose::Kokkos::ADVariableValue +Coupleable::kokkosADCoupledNodalValues(const std::string & var_name) const +{ + return kokkosADCoupledVectorTagNodalValuesByName(var_name, Moose::SOLUTION_TAG); +} + +Moose::Kokkos::ADVariableValue +Coupleable::kokkosADCoupledDofValue(const std::string & var_name, unsigned int comp) const +{ + return kokkosADCoupledVectorTagDofValueByName(var_name, Moose::SOLUTION_TAG, comp); +} + +Moose::Kokkos::ADVariableValue +Coupleable::kokkosADCoupledDofValues(const std::string & var_name) const +{ + return kokkosADCoupledVectorTagDofValuesByName(var_name, Moose::SOLUTION_TAG); +} + +Moose::Kokkos::ADVariableValue +Coupleable::kokkosADCoupledValueOld(const std::string & var_name, unsigned int comp) const +{ + return _c_nodal + ? kokkosADCoupledVectorTagNodalValueByName(var_name, Moose::OLD_SOLUTION_TAG, comp) + : kokkosADCoupledVectorTagValueByName(var_name, Moose::OLD_SOLUTION_TAG, comp); +} + +Moose::Kokkos::ADVariableValue +Coupleable::kokkosADCoupledValuesOld(const std::string & var_name) const +{ + return _c_nodal ? kokkosADCoupledVectorTagNodalValuesByName(var_name, Moose::OLD_SOLUTION_TAG) + : kokkosADCoupledVectorTagValuesByName(var_name, Moose::OLD_SOLUTION_TAG); +} + +Moose::Kokkos::ADVariableGradient +Coupleable::kokkosADCoupledGradientOld(const std::string & var_name, unsigned int comp) const +{ + return kokkosADCoupledVectorTagGradientByName(var_name, Moose::OLD_SOLUTION_TAG, comp); +} + +Moose::Kokkos::ADVariableGradient +Coupleable::kokkosADCoupledGradientsOld(const std::string & var_name) const +{ + return kokkosADCoupledVectorTagGradientsByName(var_name, Moose::OLD_SOLUTION_TAG); +} + +Moose::Kokkos::ADVariableValue +Coupleable::kokkosADCoupledNodalValueOld(const std::string & var_name, unsigned int comp) const +{ + return kokkosADCoupledVectorTagNodalValueByName(var_name, Moose::OLD_SOLUTION_TAG, comp); +} + +Moose::Kokkos::ADVariableValue +Coupleable::kokkosADCoupledNodalValuesOld(const std::string & var_name) const +{ + return kokkosADCoupledVectorTagNodalValuesByName(var_name, Moose::OLD_SOLUTION_TAG); +} + +Moose::Kokkos::ADVariableValue +Coupleable::kokkosADCoupledDofValueOld(const std::string & var_name, unsigned int comp) const +{ + return kokkosADCoupledVectorTagDofValueByName(var_name, Moose::OLD_SOLUTION_TAG, comp); +} + +Moose::Kokkos::ADVariableValue +Coupleable::kokkosADCoupledDofValuesOld(const std::string & var_name) const +{ + return kokkosADCoupledVectorTagDofValuesByName(var_name, Moose::OLD_SOLUTION_TAG); +} + +Moose::Kokkos::ADVariableValue +Coupleable::kokkosADCoupledValueOlder(const std::string & var_name, unsigned int comp) const +{ + return _c_nodal + ? kokkosADCoupledVectorTagNodalValueByName(var_name, Moose::OLDER_SOLUTION_TAG, comp) + : kokkosADCoupledVectorTagValueByName(var_name, Moose::OLDER_SOLUTION_TAG, comp); +} + +Moose::Kokkos::ADVariableValue +Coupleable::kokkosADCoupledValuesOlder(const std::string & var_name) const +{ + return _c_nodal ? kokkosADCoupledVectorTagNodalValuesByName(var_name, Moose::OLDER_SOLUTION_TAG) + : kokkosADCoupledVectorTagValuesByName(var_name, Moose::OLDER_SOLUTION_TAG); +} + +Moose::Kokkos::ADVariableGradient +Coupleable::kokkosADCoupledGradientOlder(const std::string & var_name, unsigned int comp) const +{ + return kokkosADCoupledVectorTagGradientByName(var_name, Moose::OLDER_SOLUTION_TAG, comp); +} + +Moose::Kokkos::ADVariableGradient +Coupleable::kokkosADCoupledGradientsOlder(const std::string & var_name) const +{ + return kokkosADCoupledVectorTagGradientsByName(var_name, Moose::OLDER_SOLUTION_TAG); +} + +Moose::Kokkos::ADVariableValue +Coupleable::kokkosADCoupledNodalValueOlder(const std::string & var_name, unsigned int comp) const +{ + return kokkosADCoupledVectorTagNodalValueByName(var_name, Moose::OLDER_SOLUTION_TAG, comp); +} + +Moose::Kokkos::ADVariableValue +Coupleable::kokkosADCoupledNodalValuesOlder(const std::string & var_name) const +{ + return kokkosADCoupledVectorTagNodalValuesByName(var_name, Moose::OLDER_SOLUTION_TAG); +} + +Moose::Kokkos::ADVariableValue +Coupleable::kokkosADCoupledDofValueOlder(const std::string & var_name, unsigned int comp) const +{ + return kokkosADCoupledVectorTagDofValueByName(var_name, Moose::OLDER_SOLUTION_TAG, comp); +} + +Moose::Kokkos::ADVariableValue +Coupleable::kokkosADCoupledDofValuesOlder(const std::string & var_name) const +{ + return kokkosADCoupledVectorTagDofValuesByName(var_name, Moose::OLDER_SOLUTION_TAG); +} + +Moose::Kokkos::ADVariableValue +Coupleable::kokkosADCoupledDot(const std::string & var_name, unsigned int comp) const +{ + return _c_nodal + ? kokkosADCoupledVectorTagNodalValueByName(var_name, Moose::SOLUTION_DOT_TAG, comp) + : kokkosADCoupledVectorTagValueByName(var_name, Moose::SOLUTION_DOT_TAG, comp); +} + +Moose::Kokkos::ADVariableValue +Coupleable::kokkosADCoupledDots(const std::string & var_name) const +{ + return _c_nodal ? kokkosADCoupledVectorTagNodalValuesByName(var_name, Moose::SOLUTION_DOT_TAG) + : kokkosADCoupledVectorTagValuesByName(var_name, Moose::SOLUTION_DOT_TAG); +} + +Moose::Kokkos::ADVariableValue +Coupleable::kokkosADCoupledNodalDot(const std::string & var_name, unsigned int comp) const +{ + return kokkosADCoupledVectorTagNodalValueByName(var_name, Moose::SOLUTION_DOT_TAG, comp); +} + +Moose::Kokkos::ADVariableValue +Coupleable::kokkosADCoupledNodalDots(const std::string & var_name) const +{ + return kokkosADCoupledVectorTagNodalValuesByName(var_name, Moose::SOLUTION_DOT_TAG); +} + Moose::Kokkos::Scalar Coupleable::kokkosCoupledDotDu(const std::string & var_name, unsigned int comp) const { diff --git a/framework/src/kokkos/kernels/KokkosADCoupledTimeDerivative.K b/framework/src/kokkos/kernels/KokkosADCoupledTimeDerivative.K new file mode 100644 index 000000000000..f9c864b71abe --- /dev/null +++ b/framework/src/kokkos/kernels/KokkosADCoupledTimeDerivative.K @@ -0,0 +1,27 @@ +//* This file is part of the MOOSE framework +//* https://mooseframework.inl.gov +//* +//* All rights reserved, see COPYRIGHT for full restrictions +//* https://github.com/idaholab/moose/blob/master/COPYRIGHT +//* +//* Licensed under LGPL 2.1, please see LICENSE for details +//* https://www.gnu.org/licenses/lgpl-2.1.html + +#include "KokkosADCoupledTimeDerivative.h" + +registerKokkosADResidualObject("MooseApp", KokkosADCoupledTimeDerivative); + +InputParameters +KokkosADCoupledTimeDerivative::validParams() +{ + InputParameters params = ADKernel::validParams(); + params.addClassDescription("Time derivative Kernel that acts on a coupled variable. Weak form: " + "$(\\psi_i, \\frac{\\partial v_h}{\\partial t})$."); + params.addRequiredCoupledVar("v", "Coupled variable"); + return params; +} + +KokkosADCoupledTimeDerivative::KokkosADCoupledTimeDerivative(const InputParameters & parameters) + : ADKernel(parameters), _v_dot(kokkosADCoupledDot("v")) +{ +} diff --git a/framework/src/kokkos/kernels/KokkosADDiffusion.K b/framework/src/kokkos/kernels/KokkosADDiffusion.K new file mode 100644 index 000000000000..1c90afacf2d1 --- /dev/null +++ b/framework/src/kokkos/kernels/KokkosADDiffusion.K @@ -0,0 +1,23 @@ +//* This file is part of the MOOSE framework +//* https://mooseframework.inl.gov +//* +//* All rights reserved, see COPYRIGHT for full restrictions +//* https://github.com/idaholab/moose/blob/master/COPYRIGHT +//* +//* Licensed under LGPL 2.1, please see LICENSE for details +//* https://www.gnu.org/licenses/lgpl-2.1.html + +#include "KokkosADDiffusion.h" + +registerKokkosADKernel("MooseApp", KokkosADDiffusion); + +InputParameters +KokkosADDiffusion::validParams() +{ + auto params = ADKernel::validParams(); + params.addClassDescription("Same as `KokkosDiffusion` in terms of physics/residual, but the " + "Jacobian is computed using forward automatic differentiation"); + return params; +} + +KokkosADDiffusion::KokkosADDiffusion(const InputParameters & parameters) : ADKernel(parameters) {} diff --git a/framework/src/kokkos/kernels/KokkosADKernel.K b/framework/src/kokkos/kernels/KokkosADKernel.K new file mode 100644 index 000000000000..0bb46458610d --- /dev/null +++ b/framework/src/kokkos/kernels/KokkosADKernel.K @@ -0,0 +1,74 @@ +//* This file is part of the MOOSE framework +//* https://www.mooseframework.org +//* +//* All rights reserved, see COPYRIGHT for full restrictions +//* https://github.com/idaholab/moose/blob/master/COPYRIGHT +//* +//* Licensed under LGPL 2.1, please see LICENSE for details +//* https://www.gnu.org/licenses/lgpl-2.1.html + +#include "KokkosADKernel.h" + +namespace Moose::Kokkos +{ + +InputParameters +ADKernel::validParams() +{ + InputParameters params = KernelBase::validParams(); + return params; +} + +ADKernel::ADKernel(const InputParameters & parameters) + : KernelBase(parameters, Moose::VarFieldType::VAR_FIELD_STANDARD), + _test(), + _grad_test(), + _phi(), + _grad_phi(), + _u(_var), + _grad_u(_var) +{ + addMooseVariableDependency(&_var); +} + +void +ADKernel::computeResidual() +{ + _computing_residual = true; + _computing_jacobian = false; + + dispatch(); +} + +void +ADKernel::computeJacobian() +{ + _computing_residual = false; + _computing_jacobian = true; + + dispatch(); +} + +void +ADKernel::computeResidualAndJacobian() +{ + _computing_residual = true; + _computing_jacobian = true; + + dispatch(); +} + +void +ADKernel::dispatch() +{ + _thread.resize(_num_local_threads, numKokkosBlockElements()); + + Policy policy(0, _thread.size()); + + if (!_residual_dispatcher) + _residual_dispatcher = DispatcherRegistry::build(this, type()); + + _residual_dispatcher->parallelFor(policy); +} + +} // namespace Moose::Kokkos diff --git a/framework/src/kokkos/kernels/KokkosADTimeDerivative.K b/framework/src/kokkos/kernels/KokkosADTimeDerivative.K new file mode 100644 index 000000000000..d9a001756ae0 --- /dev/null +++ b/framework/src/kokkos/kernels/KokkosADTimeDerivative.K @@ -0,0 +1,26 @@ +//* This file is part of the MOOSE framework +//* https://www.mooseframework.org +//* +//* All rights reserved, see COPYRIGHT for full restrictions +//* https://github.com/idaholab/moose/blob/master/COPYRIGHT +//* +//* Licensed under LGPL 2.1, please see LICENSE for details +//* https://www.gnu.org/licenses/lgpl-2.1.html + +#include "KokkosADTimeDerivative.h" + +registerKokkosADResidualObject("MooseApp", KokkosADTimeDerivative); + +InputParameters +KokkosADTimeDerivative::validParams() +{ + InputParameters params = ADTimeKernel::validParams(); + params.addClassDescription("The time derivative operator with the weak form of $(\\psi_i, " + "\\frac{\\partial u_h}{\\partial t})$."); + return params; +} + +KokkosADTimeDerivative::KokkosADTimeDerivative(const InputParameters & parameters) + : ADTimeKernel(parameters) +{ +} diff --git a/framework/src/kokkos/kernels/KokkosADTimeKernel.K b/framework/src/kokkos/kernels/KokkosADTimeKernel.K new file mode 100644 index 000000000000..5ab594801f5a --- /dev/null +++ b/framework/src/kokkos/kernels/KokkosADTimeKernel.K @@ -0,0 +1,31 @@ +//* This file is part of the MOOSE framework +//* https://www.mooseframework.org +//* +//* All rights reserved, see COPYRIGHT for full restrictions +//* https://github.com/idaholab/moose/blob/master/COPYRIGHT +//* +//* Licensed under LGPL 2.1, please see LICENSE for details +//* https://www.gnu.org/licenses/lgpl-2.1.html + +#include "KokkosADTimeKernel.h" + +namespace Moose::Kokkos +{ + +InputParameters +ADTimeKernel::validParams() +{ + InputParameters params = ADKernel::validParams(); + + params.set("vector_tags") = "time"; + params.set("matrix_tags") = "system time"; + + return params; +} + +ADTimeKernel::ADTimeKernel(const InputParameters & parameters) + : ADKernel(parameters), _u_dot(_var, Moose::SOLUTION_DOT_TAG) +{ +} + +} // namespace Moose::Kokkos diff --git a/test/include/kokkos/bcs/KokkosCoupledDirichletBC.h b/test/include/kokkos/bcs/KokkosCoupledDirichletBC.h index 1ac35c45a2af..23c1faab1886 100644 --- a/test/include/kokkos/bcs/KokkosCoupledDirichletBC.h +++ b/test/include/kokkos/bcs/KokkosCoupledDirichletBC.h @@ -49,8 +49,10 @@ template KOKKOS_FUNCTION Real KokkosCoupledDirichletBC::computeQpResidual(const unsigned int qp, AssemblyDatum & datum) const { - return _c * _u(datum, qp) + _u(datum, qp) * _u(datum, qp) + _v(datum, qp) * _v(datum, qp) - - _value; + Real u = _u(datum, qp); + Real v = _v(datum, qp); + + return _c * u + u * u + v * v - _value; } template From c1eede82cd88a19e45ff58b840bf0136318eb58a Mon Sep 17 00:00:00 2001 From: Namjae Choi Date: Tue, 21 Apr 2026 21:54:30 -0600 Subject: [PATCH 04/14] Add tests #32699 --- .../kokkos_ad_coupled_var_neumann_nl_out.e | Bin 0 -> 36244 bytes .../gold/kokkos_ad_coupled_var_neumann_out.e | Bin 0 -> 34052 bytes .../kokkos_ad_coupled_var_neumann.i | 69 ++++++++++++++++++ .../kokkos_ad_coupled_var_neumann_nl.i | 64 ++++++++++++++++ .../kokkos/bcs/ad_coupled_var_neumann/tests | 34 +++++++++ .../2d_diffusion/kokkos_2d_diffusion_test.i | 7 -- ...okkos_2d_ad_diffusion_neumannbc_test_out.e | Bin 0 -> 43036 bytes .../gold/kokkos_2d_ad_diffusion_test_out.e | Bin 0 -> 42864 bytes .../kokkos_2d_ad_diffusion_neumannbc_test.i | 48 ++++++++++++ .../kokkos_2d_ad_diffusion_test.i | 48 ++++++++++++ test/tests/kokkos/kernels/ad_diffusion/tests | 32 ++++++++ ...kkos_ad_coupled_time_derivative_test_out.e | Bin 0 -> 52008 bytes .../gold/kokkos_ad_time_derivative_test_out.e | Bin 0 -> 53744 bytes .../kokkos_ad_coupled_time_derivative_test.i | 60 +++++++++++++++ .../kokkos_ad_time_derivative_test.i | 51 +++++++++++++ .../kokkos/kernels/ad_time_derivative/tests | 58 +++++++++++++++ 16 files changed, 464 insertions(+), 7 deletions(-) create mode 100644 test/tests/kokkos/bcs/ad_coupled_var_neumann/gold/kokkos_ad_coupled_var_neumann_nl_out.e create mode 100644 test/tests/kokkos/bcs/ad_coupled_var_neumann/gold/kokkos_ad_coupled_var_neumann_out.e create mode 100644 test/tests/kokkos/bcs/ad_coupled_var_neumann/kokkos_ad_coupled_var_neumann.i create mode 100644 test/tests/kokkos/bcs/ad_coupled_var_neumann/kokkos_ad_coupled_var_neumann_nl.i create mode 100644 test/tests/kokkos/bcs/ad_coupled_var_neumann/tests create mode 100644 test/tests/kokkos/kernels/ad_diffusion/gold/kokkos_2d_ad_diffusion_neumannbc_test_out.e create mode 100644 test/tests/kokkos/kernels/ad_diffusion/gold/kokkos_2d_ad_diffusion_test_out.e create mode 100644 test/tests/kokkos/kernels/ad_diffusion/kokkos_2d_ad_diffusion_neumannbc_test.i create mode 100644 test/tests/kokkos/kernels/ad_diffusion/kokkos_2d_ad_diffusion_test.i create mode 100644 test/tests/kokkos/kernels/ad_diffusion/tests create mode 100644 test/tests/kokkos/kernels/ad_time_derivative/gold/kokkos_ad_coupled_time_derivative_test_out.e create mode 100644 test/tests/kokkos/kernels/ad_time_derivative/gold/kokkos_ad_time_derivative_test_out.e create mode 100644 test/tests/kokkos/kernels/ad_time_derivative/kokkos_ad_coupled_time_derivative_test.i create mode 100644 test/tests/kokkos/kernels/ad_time_derivative/kokkos_ad_time_derivative_test.i create mode 100644 test/tests/kokkos/kernels/ad_time_derivative/tests diff --git a/test/tests/kokkos/bcs/ad_coupled_var_neumann/gold/kokkos_ad_coupled_var_neumann_nl_out.e b/test/tests/kokkos/bcs/ad_coupled_var_neumann/gold/kokkos_ad_coupled_var_neumann_nl_out.e new file mode 100644 index 0000000000000000000000000000000000000000..fb97c6c7d9db9b31c101cc7b06ec4654c999cff3 GIT binary patch literal 36244 zcmeHQ&5zv3b?=Ss)r>T2Cs`XX5E!Un4LE_Jv1UeEX%=X-XQh!MSYNTUn*d6{u*qT% zSN!OZ?9q%4{sWvtF1f6ngAWE0{|P?(WMFL=u(7a#J=pNVu;GQ_Lk>Rpkl(A1=0}t4 zDT=$^fx0l9CW}?SdR4FLz4~}nyn5~WUknBVy3XQynSKKvS!tH|(F9L}!QbLqBfr3p zIPU)u*C)Mrme4P*^~?`BBJe35loR12JEZUw|4cLsE!Pj}^(Szx({mKNJSCsO;B&av z$d3n{0(}@gGYE83|_$Xl8$GkJX3LrcHy7;F6b!ve_CPq5y5N`jKKbk!m*}2 zL7L(P;cSq<#7W7M(k%LIE5CC(ek6j4a0NdKR`xrzsklTri+uW#7bD1j!fylD8C>V= zsc#+fB=zG6kAqL)df}`8b9RW|GY$Tq_k!5Yz$t4Q`%z{+juRL3KcR9b-Vpt3xYj*C zK-tI_g?A!*r{45|aI4YknIPq*6aMwb9tccG-JBq9*u;N*^ zse%n&4(%g9B>sZ`7AnppJD~U)m*M^#uD`)`R@9xx2eC?o=%M1__ zfTuE{^45;-|5rYo`4fI+*kj?-5_au7^RQ2rgPQkl$SNSdfER^zzvgFE|e{M#T|W|2?` zZ4!gk@}am7aKW9U`!y$yBJN~VFDZZ29*A$6ck3hvt?YPOXnQa2U%Rm{B#Wfw+XxSL z?w|2*LxeA4p2K{A<%>tko+JS)X)~b z`9U?F;)#$W&GG)@zwmB@Dxyvg&lKmcaH;afo%FjV?gktGhTjd+6;{F>v{cUC_r+%sW%S**$vqu?PyK#>N4U`s)bo!e^5`eZ|6NbG(a+WU z_ue7*!_hBPxL+#&U#al#tM|WF@qVMi{Z@thoeKAX3io>z?hi8D>iIRJ za?l=P&<92<4gI~OHlf=uwMCNm)c#3^l0G6GLwZBYX_A2?+ei+Pe4#c>ZSrMYpT$M} zS&gZ2Nv06C#@A`+baYxeJ)NdbSEo%ng3{MCXgV}4njTG)rc2XSrBBnP>CtrP^mV#A zJ)Mrm*SM5lx(J{0O!uFg;a{seY<(+UzEb0s$7%`j3cH$cJL4`JAG6zc@7~{Mue1bT z{;Gz+X9i?f;}G3zm)*j!i|r+oS;(U-Wk_o|K?@<+=H^%AUl_+Jw=$k)=Uslt19skL z^}YH{pPf%5o{GTMTecIAeLF(>o12>h_NE-Eu$$0M9f>MYc|Cz@#Q5crKukgmYvSm& zQV_ET$yi0^Yb@ram2PSY;T?4+B(0jGFJHcByZp-T?)b{(EpL3qc3i&gIJ-NSckG>u?hYSsZF{>FyurQw2lt&tIL3B1 zw=QjNRf8{ozJF`~Uax>xXGwxu#~xsapXV1v`A=v(cj7~~eUV+b^4iXY*DhTU#kY*c z{Uh$oGJ70wfr&w9I2FKUz-_`j5#X`}|NQUKU{Ix}vy5HGAiR&J(s!O7{%g;OjQNr6 zWd0$~TV3gH$o?*hEth-tEXe+TdFlk{XTBX+UJ{3vn9ZQ61DbUbz(aOx@4^242g{*k zh&n*bY2-u>+08p|?%h)J0?T0;vx6Xhj7gCRB-bIg{{1nhE>fx?hs>-&Gv>_F44EAV zvGZsSqv04cFGB^0aRg*{4y5nQ0cjKo@n8u=4U_*4+1?uu?k+Do9fGk2APs2_D8{bM zsOEq)CfDTD{0`ZTy*KXP*Ew4H+k4Ynnxbidhp%5v`<4%;G_;3j?BV8DXt2>2nZ(y| zJd0dAIj-R`HNB-{n-a+cf*GGIi32OMCyQ;*T-q?^`sp;V9nk_85W4{KNa*F-93#u7 z;)^kUlqEK1#ITldw2<#k6bisYOq^kcu3C^?0R3 zhWDUO(M2u0E)+JfLjn(3dJLT!mTGUy1I0=?`hrbv$S$-*UwlP4ts-{FuK9`Y90WXj z{pw=;1s?*OVZftXi)*3Ra6rDwb)gVF1;4Sa4B65_Z;48xqoGPm5{E2;>_Bg)6s`Gz zV!6IOu~HlT5WiY!NPL<0Z5W#-97}7GpoRZk>R}Uc0=x@_n97|ss%CR8Kg4jkFNM;~ ztL|@v))TXEJyA&ozeMYuVA8LUAp%@!y|T9NQn95PZ4eP%09RU%s%Gv^gVwt$7vA5r zlRI+Ry;b{B-kw9P=fvF0*;={lqNF|qH5yN?3C}Xvouo6*^N$KtcIhAXu0~VGhN*~$ z>6^GP9ipi0Qig|x94_1r*$EZ^N;>6K=;cG$z4SF6r7~Nhmsg|FLKUgIr7~QNMyV8X z*G1Z_Mx%N8(cNhnjhYJB)o8TL<8I^S=W#T8X!SQ9B_1r%daKcBovJJNQ5mkZ9+g7w zR$8x6LF#X*uulCP>`Lp^Gk5MwT<(4FxJ2ujE+O?i);k4@tcLs}|G56wxQx(MmlQnkI6BQ*bEl5B` zAGlM>x_PyswF*poiG6O^M`kC^fhCN3!0o^e$F6O`c8$oZw-2n;Ai4Na1q`w{m^VGs zWw_SWlrBwASp?Z*7d{aHUf8 z&5yJ)3R#$0(<%0_)hrkqG-K8Du(C{R!6mUUuiR0bgqCx_oku6C)qoU+9Rg5^g=fH0 z6t)_62rf4lSj`*8iW0DB%GVc zm~**EAt?brx9lT2&81BV5c^Ym1*~ZqGt)vn%d4Ids0%*sMy%A>@3D?@L`PV z-jRn*cC)FAEer+X#O;t>+}^#o`|9QG-4o>-fS%`yorYB?`8;Hgrwzo^dNU?FNibQV z!o)V=DLN0+c;4v*Qw(@a@(}xrsUo`mVWSH8vXPQffMh&ehiEPw6kwf#qEZy~(3HZa z>}tR-Z<(|dP$e{?CVFT zy@5WW(6k3D#GMsSX&_ny`;36dGBy#-IU>sNnJ8TBBX*!rj_#Utskv}a{lccMc4rD} z`bnZF&8v-~u&F(pSL}ILxL)InGBj#>Xvp@F7`WG(I+#-^0Oi3L!Zfr}xy@%qM7Q5M zOljkt9)qI`fn9PPnF7GfPBOW9W^AXWc0z60blye}yeA24ljuZ{a>mW;Vfx6QTKtIS zS|A?OuqkiN=Jk+vFNPlW&XX-vU6xG+Y#IkJscoEJ>X2pFpJ#M{OPLZ#_a4`okS_KNMy()+?Nu{0s$XY(xM zu$?hB$ySPP{%8t#3Z|XE#*>H#ALD&K!rIyOJ+GHpanV0qvPsdrVt)vmH5w%iRYo#C z@w}NnFRH0qIQOSGVlyG#)H!o$v(&&_RjfG;?KebJ?t>_<(JuxedyT`8%hY@#x3T{j!D zm6BRgid2Trp&{8yNfG07XFBkqm>;#0`m@`8^{k{$!Qhb&Me0Z2Niif=z?+XYpn;F+ zq;9Jc?KJ1mwxyf^O=p(;$O&dRLllR-z$OM$_mhJ-%_oM;o1UDyufRM@TNXn{%WvB2 zZ_X46Se>z-lh^@Jo!QYq(uo6w(d)XDPz-_Lq_FC@&;D0H0|u-EF&@NoN!FC zWg`UI6Ql^C9St6h0}FRe0(EIP(LS zEDn`$h#zxUh0c#FF=vW{v$>Mkhpnov(WuSR{tdMoSvFOpx%isPD=EI_(#)tFmki8^ zDW+>u_{Kni2Mf36Oc4iVH&4TwmtpJdVV8P1v1d5pJc!4321{?UCn#mxyxQoV2dYg5 z6Il9cKoQYA%d`$0aNApelCWUP$xT^=#Ex+2RqB^jU4caNEJw|fhHzo=Yf53Wq>+H8 z{llnP(sTo)rQ{$Wv)bAd?XbA8e|_(bTPHnH5hn!YLWU@+I&<5(`sz2wg{hk%QzW2T zE<`^J3UgB66V6$}fw)Pd+N{1%ie7dPtj7oVL<)^|aVncSP|RG~9HFVqGq`xu1+eD) zrySV4r5yK7;c?hAg-`mX@JYWEK8GXvRhFx=<74pr@UArO>uu@=yO5?+9=TSXVKT`a zb7@lmB>PoN$mX(302=pTX)A`W+w59Sm)aZqzkj>a?U4pW^FU1C@nm3mxrG~Af0 z0JZqh)LZJ1<#frBK1OO8S$1O&pUo-evUG1wAs45Nb8HDK0qKV!`_j!jHy_;GyTu;d zyp2<%_wQNzcdmV@sZrA6N9@j;O0Wx4#0l1m7HK(!rWJb<_RN$?gfD%?<@Tn@!>>70 z4)A%l0zmcFd|1)@q%J;$#uMxctCFUk&70m^X+sT^h~{P3`@l!d68oMokF-cu*nV!A zZO#;YP|w34)Sed4Sj`L6Jj*#CHfAm!C~wY`3Lqv}LLk%EAcO;;!M+8O*i}F>KrA3) z=R%WUsr9F`R_R-QYWoaWfR$P* ziQa}6wZgKCr!dn>!)b4n5hq(aBj!!-qqil#fBT+6VN#aWz+&MbetHLKQ>h0_z$uRY z43*eWlB*|rMS!MVVszX4{-S|53!0m=nTn#G17nZUso0rL_X`du$w$SLTe#a^hy>8O zo!5LbZ@#AxeZycDRt8jEn4&i+T1kyU?E*N({;0;Wh558Ib?C4syJ?eRCkl&z)lG`e z4p=$Jq6=W_#-=WSuyTNHLwJm8gK=bKLD*F5k;LxxH2zbdMsd=&+)vk=nrasw#&3lh zo%Ki^i7(F%{h-g}?IQ{Eob$$`FpFB^CQqitUOX>Yg-R93- zfy^Phe)H=m|4!O~ayH*UP7hVrCCl|ojtY6mZqp|!b^U)GJ5^iRP0{qBQng=)GygVR z9U!(U>a2Ik@`teTD#WQ8;*+47uKc%4S7b?dPV*yeWrlu9q~QB^ywYDNQfN9${9$zG z+U88nl@vNlZRaI)sW!rV8mFY?1y{H;r?6)=s=3|Uuh1zyZJrTCQE9DoN}m%H^oMd*N8f#$+_y&G zQ@`KeA$M`~1M&RdqaTa#FN}Vo{NMG+9gKdi-oN(_xgU*wp~C%A`Tt6Ve_y@-wTL$v z{YHiRtqAw6(eFgKOQR1|xZjI#zM}I55gPv#olg~=Z;vFMJBrSyiq3(eb7v&!^c0;> nN0QEW6rF>Sr1R-W(z!E|bpCK8>GTwxgHf5zoeG^3U7r6B3w--` literal 0 HcmV?d00001 diff --git a/test/tests/kokkos/bcs/ad_coupled_var_neumann/gold/kokkos_ad_coupled_var_neumann_out.e b/test/tests/kokkos/bcs/ad_coupled_var_neumann/gold/kokkos_ad_coupled_var_neumann_out.e new file mode 100644 index 0000000000000000000000000000000000000000..8bd19633d2d8ffb2d58f95f335d7230c7fc310db GIT binary patch literal 34052 zcmeHQ36LDsc^*k1X(fS#IRye*5+EVavZpQ>TC3faSV^k`E#eR`>Y3@;Z8S4In(2{t z2^ef+ATEdEaIoaUM+kNxwyQ95+xPe1umAqvd;dH7UDMsOdSW0DAf^E)(vO?TP{v7H$w6EN0&{_>tuUl`!#unZkv1B7D+FFg%~1lFTMTQ7ggQd{+~%lXle1kP`@u08_~` z<0b<|foa}#C>-B`t3Y4^aFlv3lrbIoEOik4j1`3*1^lC>3@b@7trR0<&y;dPDKm|C ziW`(OgM3d;hD@eOKCi6=ue}7XL-MAp_aue5z;y8QcobL6qqt%o#TD{)8BBhWmLlD( zWXwhq9S`0NUW;$cpNn8ew1SYKfyJ2WRdk?F%cm)N>#MM>>`hr!Y9$!O0Ojn~Iy! z5aJU`n%RVrOor^N(=5Xrn=pp01Z@Sj6oL^BIzxO`$<#nIP3cb)cDQ@UmM@?#lK|x= zgP`tk*=O*t$qbJwiE9-%2B70R2)L;q@E^jb(sqh=p~5n)Ngp9?opGAf*Mt8B&o}Y9 zDVZ7bK5>IL;rOmuf(kT|o{I4K?_=0%?^DkohpVew0A<3R;-#OccdLb+ zqu~K1mlYr79t|j$CwI<8U{00waJ8^ZPbHU?C*{rrl*^a92TUcmTG)SPSeXt?R?3z3 z4yqs>=KL3~mE0;}Po<2ho;~E!>=+7^j{2VK(WfqhufnQy5C&BuY&0*dircX=9KC$G z%xfiA>3dw6us;C*s9i=JrNkB$HH{KZ)OGO7l-=x$xL5ETBLG+Bxsm%2W(EtSdY^oT zZ5!jD9Od+Q7pF4)(eA|TP}+>37Run7_fG(rZ_0sp>HXftX-s2vkA6NFgx5;f{ClM7 z*tV!Jf}!u*OZNrk3nu>QPfEV>pKcdUSN;p~zVi2bPwLA5g$%F!*J8ry%Kw#oUitt1 zuXI1wmH(!cr~G|hc#oT>U$H*L?=OB|vHWqlB1y~U|9JY+@V+p{?hg_>Q{_SVDj$_! z%>Ssb$J8sTemPKI*=eKw7nuFX|3>@!y`0F^myNns^=+elRgX5>SM`6ReO1pl+E?vS zgMC#lEBRsDacnUhQ6^N{8XR)U+!JiaPF1=c2*k};MFD}TI#iW#;7V4GLd|zoKZt!I z_R;t~#C{>aF{T3i2IF^?`i|lE1pEH%r_Tb||7E|H{Z;lu+1F#=jpI=#0keUVfm47v zz^TA#!0CVn%mwBF^MNyfGl8>!1;9e!Y+w;^4#0ljVxSo~4`>0{rDgY&{pJp!6IcQ) z1=t5)4y*vq2QC0OhH@dG11o_pU=`2}uus|xtOnKq7Xf|1T3{Wp9_R-)02_f#z-HiL zU<)t+TmozbE(IW8Az(XT0AU~kL;-#l#(+U!2(W-_fE_>_pyek4 z8=x8Q1kwQe%{1C9unX7?3a{&#Y9aE2azyUvm}o+^`K3Y zN1A#p1jr*zJ!tFXk)|Gt0P;v{0LuV*q^aAv0D07jx-ABpB~9H}M#v*g-C6+hNK+4% z9r8$1k2Zij($s@xiagTPqXQt1H1%LvBabxoV7ViYG<91FkVl=UhboVxsmBV*BTYTd zmpszc;{wSeO+A8=N1A$ED0!r*hc0=fsmDryJkr#o3s@;>>b43XZ#h8Sx`7@^Q@38p zBTd~_OCD+Jwnp+uQ@4vGk2H1blRVPYW3A+oUJ0xN$RkZX)&t~`rf&TJdDMxzZ2&e( zn!0V0Jkr!{v*eMcZWl`)Y3jB`@<>y+0m&mxJuZUNprQ77tl zIdFxfsoOTmBTe0|lswYZ?JCJ5P2H}RJkr!HBzdH%+jf9F($viWwo972g#q$NQ@02} z9(AH_QNWZmb&E+JY3ep8d8Db^kmQl3ZkFVcrXJTw9_j7C4uCw;)FTd%N1A#h0P;vv zwA(!&DBx&dCNK*)2KX3oEN~ofJa7VVB5)Eg z8#oy_1(*Yz3Y-R<4rst!U>-0ZI0HBnI15++ECkL576In~=K_m?X5c)a1!x7@fOen* z=meGkOMzv;azK^w3qS{f3jrNi33LIgfNr1%=mk~-Yk-S@K42}d4p1@=D#9 z_qBkwzy36PO+o(DsFxW=kE6&a^*L@uj~0*ciJ=@GpdD0wEm47xAbcBi{;5N2)8D` zgo5+ig&Xs{93ycn`w*yg+X+ldMz!^r{?@wEgV}_cbTS%lVJu_J^ZPKuv3Kttw~Vhf zH=pPIC2Tumh8#2FEVfgQw%F2C9_7u2He1wSt2c?O^vuo=lZMmTN?nV1Ssq=eu+fi25dbabw0Z509o`hG9J zYV~W&-48Jo?X)kM$~xL=EDb2O(hpIQvaj042C&gyqHPRNVhs;5#t)^{jK2NnqUXS6x^klw<<91|6 zi3}F3pw_oxYu9?Ya;ADp@}ZcKu;L?SBnGwhU287x+OUSb>>3=!R4mQ@%Q6L8j%CC{ zSj-Uxg{Csk)f46N_+UmZGxA4oLHb-5s)CyI0CQq$AvK|dplw)Z-5fY2UxGIZ_ z10k51GSFMQiqvJSKy;6klKwT^hR)Z4*>XYR9s;$^s_uiclF6l`sBJja(Wrc(b%gC~ zGHRqtR}Vpr-=(!X3Pc%p(sn%L7=vSri+?-Rw5XLy#f^w)@5e~2N1&M$9Zo7c)&(^V zU)1g>!5ntd1{SPgDe&-^c-N(&5V#BL+OUAGI3ep1XeCl{D}oP_Qm&pTH@*qTYz$w6 z2zQ~MSXlo<<$5$MlO0|H1hvcv>e@uD`OK#(_P>H!kCnC}Lvhnt)m?*B3e4iORvC9R zgvx)2T?HxBC~^;C8uEhShaXG*V)^y+N%M^P);4 z<-f)rZ=?zv=X#2s*XoToQmV2z6dI{+Zx;!^syBFhNGdi~jM;c2rSjMF>nSORKqFNc z$-=8(Zos|lq)0(i!6x8v`*`#Qve9!j(+z3&G|k95HntgImA)Jk!Dh3(eDPn~RP3^| zkL`C1)~eKHucy;qv4>58TO8AfayqXjhct{t%oGNRllV9r4yCM!fn9o*W2VLA4+Q${ zV`Ewe!$9o4dIMHz6T`e&j9i7yn4LD6U)Wa}3P&Z1Bm$?{AeIxg<>5=|m_pWMc5s zPsZT$yVCc3J$4um8DVY-G*h9`lp8I3L2a?G9;c?oh5cFO#}8Xu;Hu`X3P6FS6w9fI z%E81$qY7Wuhd|8PO8d)6$s>ZAoSdmD$_r2+FqASPJB-1CkD#EI!v5n(jpDE_MPmsb zj$t!jHWkHGc%E{C3~C*1%R81YS=zR|rg%eOEEW|z1B*p@*FkMJ7Z=p*G%Z=#ZbYVZ z`pIP}uv}KxC6LJ&%O+7ljdc*{(+;5_1(vhypyngKNNJIVX)|87?9~-z3aprhEz5l5 zvas6_RwAIWFOi7;E7$^oXj!mKAwO#lR3J7a7LGsEA<%0$St*uENB@~3TVgbs5pG^g zCkhkNPxa57(=;itoGn7bnsc~7U^&wfQTAmvkYo&tZbvAF2H(z2&3Jk3Uqd0#I}pH| zAew_LLG=soOA7}n+o2t_vn~ZeEjH=A5mXeHe#SaV2(JMQsCQIC> zz>41i^+cI_`6;-h^Ith|f~Ke~&X*k27K~_%wU*{iF0`)h_$+388mZyoH*V8+NKE=S zs-~e)(QFR++D26leYMQBiYPaHRaKQaDgVo~s?>+D)arFYE(CMA;q_rmR>>4T#$if* zOq-ZfrvyO()*w3nW+=+ zgc7~4s1=Jfs(UExu+sA6L!tN8g9OQ{^Xm$XxYPxs-0=FaO7$fTtCTt=c+{}rYem#r z8*f_*UyCQF0f;|iuk~Msp*1ZGeA)q7e;QZdx93klAoxv7Fqse}NHf$xPc;bkuZkYIxMb zA||n@-+$2?tsHW-fmb=?>Iz@&N|iz9dRjf4)t*bR5=4#bc5>E@Q5$t&aS3T)`A@@& zUn%v}HiJeMCqc*Uuz{oDLWAj|_RoLOQ|&s;#=-h0o|c{;dH+%7JaF7JVq-*kVqw^| zFT+6AU|9loA7!kaI)H*SarL2=v;gQaiwzhJM#9l{P=dRyZs%@@Y1nKskqtUJlx~!MuFJ4jL1` zFHlSJi7=Wr49iyPl<@u6*u#ku8*xS@`#0>7Mr%0IXbrDzw1(FMPJj=s^Kx8qT+ zxeoa70&d&r?Rjt5I0n{Zr#Q`Zw&sM1wPBFo_=|vJ1*y(Tk_H9WnjJ{o`jxtzk#inrYbKV+r$evFnJ z|7qw6#OK)%Hjfy|L5%$I_f3?J^=c?09=D4|fgshtz|4@nTd7mR_n#@K|FaxW2@PR% z)E;woM;#iDBqQG1(h~YH%6_+oIcB7>mBTKl?2$-R*?*LWqejWNN@hI*i3#^_=GSbf;rMx9OodT*P@MOb!5rq8 zNd={&|5lG{IK3^X;|GZO`hY4GICmEBe(!GXjNTV;qAJg>E#`mJ*ErjiZp>M|PYZVa z{K{wijy=P-*6{m8I+i`_x7-=P)%ad+HU9tT8NZ(14Z9va>z9H@&+0u;zL)Q{o#ETw zUVFF~MEnn#-=S)}C5%fPPl53i_^?wzf75$ouHD@)uVsCdYoCkxANBQtw!h_`ueF`^ z8*ZPd-^bhK18slHJwM(qdj(hicjNc`cHg&WEpm4(nSHMPHU4&uaPG%v{_&Wl&N=RN zcRw|7=bdl6woZcOUswz`b+f!24JH_67Hj?q}D$y7qc^@9&ba@4xxF zyXWt3&#WAH!o9a`?OpGD@(1qUthERGFMrp4p#LY+AOB#fd;gJd%-s6g-R`$Od#nAM z;RoCYzw)IUR=?u7-yfX&dis^q-0w}f`H@*KUFZIA_2=J@JZie`>o+et`Q1(K;2D4Z z{F9U4%IP<}=_`M`rqp>mK^U^KYGaqxmm1{;J@!VafRV-{^l`%@ry6Nnv)y8qo@DEf1Bqf7u|R1 z&)&Pi-DU2)=Rf9L<=*h--emK)Om}}^gZFx@94CL$KHD`CztlnG4pm^*u(Mvs0(|z{_8sJ;hNvSqzikv_XwT# zu<#R4=(LA$Kn5?<94WvwfRx$jN2-TG9VQo#krY=EroF tr)^i=t+O0`@4XJ4<>!C&U+XM4kNwWkSzdnq{7PMvleVq8C?6LM{~sYI;bZ^+ literal 0 HcmV?d00001 diff --git a/test/tests/kokkos/bcs/ad_coupled_var_neumann/kokkos_ad_coupled_var_neumann.i b/test/tests/kokkos/bcs/ad_coupled_var_neumann/kokkos_ad_coupled_var_neumann.i new file mode 100644 index 000000000000..f68b674e7ff7 --- /dev/null +++ b/test/tests/kokkos/bcs/ad_coupled_var_neumann/kokkos_ad_coupled_var_neumann.i @@ -0,0 +1,69 @@ +[Mesh] + type = GeneratedMesh + dim = 2 + xmin = 0 + xmax = 1 + ymin = 0 + ymax = 1 + nx = 10 + ny = 10 +[] + +[Variables] + [u] + order = FIRST + family = LAGRANGE + [] +[] + +[Kernels] + [diff] + type = KokkosADDiffusion + variable = u + [] +[] + +[AuxVariables] + [coupled_bc_var] + [] +[] + +[ICs] + [coupled_bc_var] + type = FunctionIC + variable = coupled_bc_var + function = set_coupled_bc_var + [] +[] + +[Functions] + [set_coupled_bc_var] + type = ParsedFunction + expression = 'y - 0.5' + [] +[] + +[BCs] + [left] + type = KokkosADDirichletBC + variable = u + boundary = 3 + value = 0 + [] + + [right] + type = KokkosADCoupledVarNeumannBC + variable = u + boundary = 1 + v = coupled_bc_var + [] +[] + +[Executioner] + type = Steady + residual_and_jacobian_together = true +[] + +[Outputs] + exodus = true +[] diff --git a/test/tests/kokkos/bcs/ad_coupled_var_neumann/kokkos_ad_coupled_var_neumann_nl.i b/test/tests/kokkos/bcs/ad_coupled_var_neumann/kokkos_ad_coupled_var_neumann_nl.i new file mode 100644 index 000000000000..51df5d747d1b --- /dev/null +++ b/test/tests/kokkos/bcs/ad_coupled_var_neumann/kokkos_ad_coupled_var_neumann_nl.i @@ -0,0 +1,64 @@ +[Mesh] + type = GeneratedMesh + dim = 1 + nx = 20 +[] + +[Variables] + [u][] + [v][] +[] + +[Kernels] + [diff] + type = KokkosADDiffusion + variable = u + [] + [diff_v] + type = KokkosADDiffusion + variable = v + [] +[] + +[BCs] + [left] + type = KokkosADDirichletBC + variable = u + boundary = 'left' + value = 0 + [] + [right] + type = KokkosADCoupledVarNeumannBC + variable = u + boundary = 'right' + v = v + [] + [v_left] + type = KokkosADDirichletBC + variable = v + boundary = 'left' + value = 0 + [] + [v_right] + type = KokkosADDirichletBC + variable = v + boundary = 'right' + value = 1 + [] +[] + +[Preconditioning] + [smp] + type = SMP + full = true + [] +[] + +[Executioner] + type = Steady + residual_and_jacobian_together = true +[] + +[Outputs] + exodus = true +[] diff --git a/test/tests/kokkos/bcs/ad_coupled_var_neumann/tests b/test/tests/kokkos/bcs/ad_coupled_var_neumann/tests new file mode 100644 index 000000000000..746d4c7642fb --- /dev/null +++ b/test/tests/kokkos/bcs/ad_coupled_var_neumann/tests @@ -0,0 +1,34 @@ +[Tests] + issues = '#30655' + design = 'KokkosADCoupledVarNeumannBC.md' + + [test] + type = 'Exodiff' + input = 'kokkos_ad_coupled_var_neumann.i' + exodiff = 'kokkos_ad_coupled_var_neumann_out.e' + requirement = 'The Kokkos system shall support coupled Neumann type boundary conditions using automatic differentiation.' + capabilities = 'kokkos' + compute_devices = 'cpu cuda' + [] + + [nonlinear] + requirement = 'When coupling nonlinear variables into a Neumann type boundary condition using automatic differentiation, the Kokkos system shall' + [exo] + type = Exodiff + input = 'kokkos_ad_coupled_var_neumann_nl.i' + exodiff = 'kokkos_ad_coupled_var_neumann_nl_out.e' + detail = 'generate accurate results' + capabilities = 'kokkos' + compute_devices = 'cpu cuda' + [] + [jac] + type = PetscJacobianTester + run_sim = True + input = 'kokkos_ad_coupled_var_neumann_nl.i' + difference_tol = 1e-6 + detail = 'generate a perfect Jacobian' + capabilities = 'kokkos' + compute_devices = 'cpu cuda' + [] + [] +[] diff --git a/test/tests/kokkos/kernels/2d_diffusion/kokkos_2d_diffusion_test.i b/test/tests/kokkos/kernels/2d_diffusion/kokkos_2d_diffusion_test.i index 4c4fd888434d..88dc89dde162 100644 --- a/test/tests/kokkos/kernels/2d_diffusion/kokkos_2d_diffusion_test.i +++ b/test/tests/kokkos/kernels/2d_diffusion/kokkos_2d_diffusion_test.i @@ -17,8 +17,6 @@ [] [Variables] - active = 'u' - [u] order = FIRST family = LAGRANGE @@ -26,8 +24,6 @@ [] [Kernels] - active = 'diff' - [diff] type = KokkosDiffusion variable = u @@ -35,9 +31,6 @@ [] [BCs] - # BCs cannot be preset due to Jacobian test - active = 'left right' - [left] type = KokkosDirichletBC variable = u diff --git a/test/tests/kokkos/kernels/ad_diffusion/gold/kokkos_2d_ad_diffusion_neumannbc_test_out.e b/test/tests/kokkos/kernels/ad_diffusion/gold/kokkos_2d_ad_diffusion_neumannbc_test_out.e new file mode 100644 index 0000000000000000000000000000000000000000..f20f4a3cfad7d8929309a095e7b2f8ed5120bddc GIT binary patch literal 43036 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 s-O*e4|(|q(f|Me literal 0 HcmV?d00001 diff --git a/test/tests/kokkos/kernels/ad_diffusion/kokkos_2d_ad_diffusion_neumannbc_test.i b/test/tests/kokkos/kernels/ad_diffusion/kokkos_2d_ad_diffusion_neumannbc_test.i new file mode 100644 index 000000000000..e75377b3d6e7 --- /dev/null +++ b/test/tests/kokkos/kernels/ad_diffusion/kokkos_2d_ad_diffusion_neumannbc_test.i @@ -0,0 +1,48 @@ +[Mesh] + [square] + type = GeneratedMeshGenerator + nx = 2 + ny = 2 + dim = 2 + [] +[] + +[Variables] + [u] + order = FIRST + family = LAGRANGE + [] +[] + +[Kernels] + [diff] + type = KokkosADDiffusion + variable = u + [] +[] + +[BCs] + [left] + type = KokkosADDirichletBC + variable = u + boundary = 3 + value = 0 + [] + [right] + type = KokkosADNeumannBC + variable = u + boundary = 1 + value = 1 + [] +[] + +[Executioner] + type = Steady + + solve_type = NEWTON + residual_and_jacobian_together = true +[] + +[Outputs] + exodus = true +[] diff --git a/test/tests/kokkos/kernels/ad_diffusion/kokkos_2d_ad_diffusion_test.i b/test/tests/kokkos/kernels/ad_diffusion/kokkos_2d_ad_diffusion_test.i new file mode 100644 index 000000000000..2b2314f9fae5 --- /dev/null +++ b/test/tests/kokkos/kernels/ad_diffusion/kokkos_2d_ad_diffusion_test.i @@ -0,0 +1,48 @@ +[Mesh] + [square] + type = GeneratedMeshGenerator + nx = 2 + ny = 2 + dim = 2 + [] +[] + +[Variables] + [u] + order = FIRST + family = LAGRANGE + [] +[] + +[Kernels] + [diff] + type = KokkosADDiffusion + variable = u + [] +[] + +[BCs] + [left] + type = KokkosADDirichletBC + variable = u + boundary = 3 + value = 0 + [] + [right] + type = KokkosADDirichletBC + variable = u + boundary = 1 + value = 1 + [] +[] + +[Executioner] + type = Steady + + solve_type = NEWTON + residual_and_jacobian_together = true +[] + +[Outputs] + exodus = true +[] diff --git a/test/tests/kokkos/kernels/ad_diffusion/tests b/test/tests/kokkos/kernels/ad_diffusion/tests new file mode 100644 index 000000000000..b3d164963306 --- /dev/null +++ b/test/tests/kokkos/kernels/ad_diffusion/tests @@ -0,0 +1,32 @@ +[Tests] + issues = '#32699' + + [dirichlet] + type = Exodiff + input = 'kokkos_2d_ad_diffusion_test.i' + exodiff = 'kokkos_2d_ad_diffusion_test_out.e' + requirement = 'The Kokkos system shall provide an ability to solve a 2D diffusion problem with Dirichlet boundary conditions using automatic differentation.' + design = 'KokkosADDiffusion.md KokkosADDirichletBC.md' + capabilities = 'kokkos' + compute_devices = 'cpu cuda' + [] + [neumann] + type = Exodiff + input = 'kokkos_2d_ad_diffusion_neumannbc_test.i' + exodiff = 'kokkos_2d_ad_diffusion_neumannbc_test_out.e' + requirement = 'The Kokkos system shall provide an ability to solve a 2D diffusion problem with Neumann boundary conditions using automatic differentation.' + design = 'KokkosADDiffusion.md KokkosADNeumannBC.md' + capabilities = 'kokkos' + compute_devices = 'cpu cuda' + [] + [jacobian] + type = PetscJacobianTester + input = 'kokkos_2d_ad_diffusion_test.i' + cli_args = 'Outputs/exodus=false' + recover = false + requirement = 'The Kokkos system shall provide exact Jacobian using automatic differentation.' + design = 'framework_stp.md' + capabilities = 'kokkos' + compute_devices = 'cpu cuda' + [] +[] diff --git a/test/tests/kokkos/kernels/ad_time_derivative/gold/kokkos_ad_coupled_time_derivative_test_out.e b/test/tests/kokkos/kernels/ad_time_derivative/gold/kokkos_ad_coupled_time_derivative_test_out.e new file mode 100644 index 0000000000000000000000000000000000000000..4a7538b92f8201b2506d70625ce7b5a43cfb960c GIT binary patch literal 52008 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 literal 0 HcmV?d00001 diff --git a/test/tests/kokkos/kernels/ad_time_derivative/gold/kokkos_ad_time_derivative_test_out.e b/test/tests/kokkos/kernels/ad_time_derivative/gold/kokkos_ad_time_derivative_test_out.e new file mode 100644 index 0000000000000000000000000000000000000000..20f8c257834e8bd6ae8d51e272156a14217a0558 GIT binary patch literal 53744 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 Date: Tue, 21 Apr 2026 22:13:01 -0600 Subject: [PATCH 05/14] Add object markdowns #32699 --- .../kokkos/bcs/KokkosADCoupledVarNeumannBC.md | 20 +++++++++++++++++++ .../source/kokkos/bcs/KokkosADDirichletBC.md | 20 +++++++++++++++++++ .../source/kokkos/bcs/KokkosADNeumannBC.md | 20 +++++++++++++++++++ .../kernels/KokkosADCoupledTimeDerivative.md | 20 +++++++++++++++++++ .../kokkos/kernels/KokkosADDiffusion.md | 20 +++++++++++++++++++ .../kokkos/kernels/KokkosADTimeDerivative.md | 20 +++++++++++++++++++ 6 files changed, 120 insertions(+) create mode 100644 framework/doc/content/source/kokkos/bcs/KokkosADCoupledVarNeumannBC.md create mode 100644 framework/doc/content/source/kokkos/bcs/KokkosADDirichletBC.md create mode 100644 framework/doc/content/source/kokkos/bcs/KokkosADNeumannBC.md create mode 100644 framework/doc/content/source/kokkos/kernels/KokkosADCoupledTimeDerivative.md create mode 100644 framework/doc/content/source/kokkos/kernels/KokkosADDiffusion.md create mode 100644 framework/doc/content/source/kokkos/kernels/KokkosADTimeDerivative.md diff --git a/framework/doc/content/source/kokkos/bcs/KokkosADCoupledVarNeumannBC.md b/framework/doc/content/source/kokkos/bcs/KokkosADCoupledVarNeumannBC.md new file mode 100644 index 000000000000..2090e43710f8 --- /dev/null +++ b/framework/doc/content/source/kokkos/bcs/KokkosADCoupledVarNeumannBC.md @@ -0,0 +1,20 @@ +# KokkosADCoupledVarNeumannBC + +!if! function=hasCapability('kokkos') + +This is the Kokkos version of [ADCoupledVarNeumannBC](CoupledVarNeumannBC.md). See the original document for details. + +## Example Input Syntax + +!listing test/tests/kokkos/bcs/ad_coupled_var_neumann/kokkos_ad_coupled_var_neumann.i start=[right] end=[] include-end=true + +!syntax parameters /BCs/KokkosADCoupledVarNeumannBC + +!syntax inputs /BCs/KokkosADCoupledVarNeumannBC + +!syntax children /BCs/KokkosADCoupledVarNeumannBC + +!if-end! + +!else +!include kokkos/kokkos_warning.md diff --git a/framework/doc/content/source/kokkos/bcs/KokkosADDirichletBC.md b/framework/doc/content/source/kokkos/bcs/KokkosADDirichletBC.md new file mode 100644 index 000000000000..26949349b010 --- /dev/null +++ b/framework/doc/content/source/kokkos/bcs/KokkosADDirichletBC.md @@ -0,0 +1,20 @@ +# KokkosADDirichletBC + +!if! function=hasCapability('kokkos') + +This is the Kokkos version of [ADDirichletBC](ADDirichletBC.md). See the original document for details. + +## Example Input Syntax + +!listing test/tests/kokkos/kernels/ad_diffusion/kokkos_2d_ad_diffusion_test.i start=[left] end=[] include-end=true + +!syntax parameters /BCs/KokkosADDirichletBC + +!syntax inputs /BCs/KokkosADDirichletBC + +!syntax children /BCs/KokkosADDirichletBC + +!if-end! + +!else +!include kokkos/kokkos_warning.md diff --git a/framework/doc/content/source/kokkos/bcs/KokkosADNeumannBC.md b/framework/doc/content/source/kokkos/bcs/KokkosADNeumannBC.md new file mode 100644 index 000000000000..78e63a312dbf --- /dev/null +++ b/framework/doc/content/source/kokkos/bcs/KokkosADNeumannBC.md @@ -0,0 +1,20 @@ +# KokkosADNeumannBC + +!if! function=hasCapability('kokkos') + +This is the Kokkos version of [ADNeumannBC](ADNeumannBC.md). See the original document for details. + +## Example Input Syntax + +!listing test/tests/kokkos/kernels/ad_diffusion/kokkos_2d_ad_diffusion_neumannbc_test.i start=[right] end=[] include-end=true + +!syntax parameters /BCs/KokkosADNeumannBC + +!syntax inputs /BCs/KokkosADNeumannBC + +!syntax children /BCs/KokkosADNeumannBC + +!if-end! + +!else +!include kokkos/kokkos_warning.md diff --git a/framework/doc/content/source/kokkos/kernels/KokkosADCoupledTimeDerivative.md b/framework/doc/content/source/kokkos/kernels/KokkosADCoupledTimeDerivative.md new file mode 100644 index 000000000000..bbc3a84dbc41 --- /dev/null +++ b/framework/doc/content/source/kokkos/kernels/KokkosADCoupledTimeDerivative.md @@ -0,0 +1,20 @@ +# KokkosADCoupledTimeDerivative + +!if! function=hasCapability('kokkos') + +This is the Kokkos version of [ADCoupledTimeDerivative](ADCoupledTimeDerivative.md). See the original document for details. + +## Example Input Syntax + +!listing test/tests/kokkos/kernels/ad_time_derivative/kokkos_ad_coupled_time_derivative_test.i start=[time_v] end=[] include-end=true + +!syntax parameters /Kernels/KokkosADCoupledTimeDerivative + +!syntax inputs /Kernels/KokkosADCoupledTimeDerivative + +!syntax children /Kernels/KokkosADCoupledTimeDerivative + +!if-end! + +!else +!include kokkos/kokkos_warning.md diff --git a/framework/doc/content/source/kokkos/kernels/KokkosADDiffusion.md b/framework/doc/content/source/kokkos/kernels/KokkosADDiffusion.md new file mode 100644 index 000000000000..bd3d38e3dff2 --- /dev/null +++ b/framework/doc/content/source/kokkos/kernels/KokkosADDiffusion.md @@ -0,0 +1,20 @@ +# KokkosADDiffusion + +!if! function=hasCapability('kokkos') + +This is the Kokkos version of [ADDiffusion](ADDiffusion.md). See the original document for details. + +## Example Input Syntax + +!listing test/tests/kokkos/kernels/ad_diffusion/kokkos_2d_ad_diffusion_test.i start=[diff] end=[] include-end=true + +!syntax parameters /Kernels/KokkosADDiffusion + +!syntax inputs /Kernels/KokkosADDiffusion + +!syntax children /Kernels/KokkosADDiffusion + +!if-end! + +!else +!include kokkos/kokkos_warning.md diff --git a/framework/doc/content/source/kokkos/kernels/KokkosADTimeDerivative.md b/framework/doc/content/source/kokkos/kernels/KokkosADTimeDerivative.md new file mode 100644 index 000000000000..90fddf7d4883 --- /dev/null +++ b/framework/doc/content/source/kokkos/kernels/KokkosADTimeDerivative.md @@ -0,0 +1,20 @@ +# KokkosADTimeDerivative + +!if! function=hasCapability('kokkos') + +This is the Kokkos version of [ADTimeDerivative](ADTimeDerivative.md). See the original document for details. + +## Example Input Syntax + +!listing test/tests/kokkos/kernels/ad_time_derivative/kokkos_ad_coupled_time_derivative_test.i start=[time_u] end=[] include-end=true + +!syntax parameters /Kernels/KokkosADTimeDerivative + +!syntax inputs /Kernels/KokkosADTimeDerivative + +!syntax children /Kernels/KokkosADTimeDerivative + +!if-end! + +!else +!include kokkos/kokkos_warning.md From 26ec621a567e1ed0d0c3683e7acc415c891e3bc7 Mon Sep 17 00:00:00 2001 From: Namjae Choi Date: Tue, 21 Apr 2026 22:13:17 -0600 Subject: [PATCH 06/14] Update documentations #32699 --- framework/doc/content/syntax/KokkosBCs/index.md | 7 +++---- .../doc/content/syntax/KokkosKernels/index.md | 17 ++++++++++++++++- modules/doc/content/newsletter/2019/2019_05.md | 2 +- .../doc/content/workshop/systems/kernels.md | 2 +- 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/framework/doc/content/syntax/KokkosBCs/index.md b/framework/doc/content/syntax/KokkosBCs/index.md index 02f541c6bdb9..1489d444eb32 100644 --- a/framework/doc/content/syntax/KokkosBCs/index.md +++ b/framework/doc/content/syntax/KokkosBCs/index.md @@ -8,12 +8,11 @@ Before reading this documentation, consider reading the following materials firs - [Getting Started with Kokkos-MOOSE](syntax/Kokkos/index.md) to understand the programming practices for Kokkos-MOOSE, - [Kokkos Kernels System](syntax/KokkosKernels/index.md) to understand the common design pattern of objects in Kokkos-MOOSE. -!alert note -Kokkos-MOOSE boundary conditions do not support automatic differention yet. - The basic design pattern of Kokkos-MOOSE kernels described in [Kokkos Kernels System](syntax/Kokkos/index.md) applies to the boundary conditions as well. You can create your own integrated and nodal boundary conditions by subclassing `Moose::Kokkos::IntegratedBC` and `Moose::Kokkos::NodalBC`, respectively, and following the same pattern with kernels including registering your boundary conditions with either `registerKokkosBoundaryCondition()` or `registerKokkosResidualObject()`. -Especially, integrated boundary conditions have identical interfaces with kernels, so they will not be explained here in detail. +[Automatic differentiation (AD)](automatic_differentiation/index.md) versions of boundary conditions are also available and can be derived and registered in an analogous manner with the [AD kernels](syntax/KokkosKernels/index.md#kokkos_ad_kernel). + +Integrated boundary conditions have identical interfaces with kernels, so they will not be explained here in detail. See the following source codes of `KokkosCoupledVarNeumannBC` for an example of an integrated boundary condition: !listing framework/include/kokkos/bcs/KokkosCoupledVarNeumannBC.h id=kokkos-neumann-header diff --git a/framework/doc/content/syntax/KokkosKernels/index.md b/framework/doc/content/syntax/KokkosKernels/index.md index 275d4ab8469c..4be74635e24c 100644 --- a/framework/doc/content/syntax/KokkosKernels/index.md +++ b/framework/doc/content/syntax/KokkosKernels/index.md @@ -8,7 +8,7 @@ Before reading this documentation, consider reading the following materials firs - [Getting Started with Kokkos-MOOSE](syntax/Kokkos/index.md) to understand the programming practices for Kokkos-MOOSE. !alert note -Kokkos-MOOSE kernels do not support coupling with scalar variables and automatic differention yet. +Kokkos-MOOSE kernels do not support coupling with scalar variables yet. The Kokkos-MOOSE kernels are designed to resemble the original MOOSE kernels as much as possible for easier porting and adaptation. However, some differences still exist due to the fundamentally different programming paradigm between CPU and GPU. @@ -198,6 +198,21 @@ See the following source codes of `KokkosCoupledTimeDerivative` for an example o !listing framework/src/kokkos/kernels/KokkosCoupledTimeDerivative.K id=kokkos-time-derivative-source language=cpp caption=The `KokkosCoupledTimeDerivative` source file. +## Automatic Differentiation id=kokkos_ad_kernel + +Kokkos-MOOSE kernels also support [automatic differentiation (AD)](automatic_differentiation/index.md). +AD kernels can be derived from `Moose::Kokkos::ADKernel` and should be registered with either `registerKokkosADKernel()` or `registerKokkosADResidualObject()`. +AD kernels requires `computeQpResidual()` to be defined with the following signature, where everything remains the same with the ordinary kernels except the return type being `Moose::Kokkos::ADReal`: + +```cpp +template +KOKKOS_FUNCTION Moose::Kokkos::ADReal computeQpResidual(const unsigned int i, + const unsigned int qp, + AssemblyDatum & datum) const; +``` + +`computeQpJacobian()` and `computeQpOffDiagJacobian()` are unused, as AD automatically assembles Jacobian. + !syntax list /Kernels objects=True actions=False subsystems=False !if-end! diff --git a/modules/doc/content/newsletter/2019/2019_05.md b/modules/doc/content/newsletter/2019/2019_05.md index d8d48dfee014..a55ec0d3f0b7 100644 --- a/modules/doc/content/newsletter/2019/2019_05.md +++ b/modules/doc/content/newsletter/2019/2019_05.md @@ -50,7 +50,7 @@ The need to include the `` template argument for AD objects is no long the MOOSEDocs syntax calls. For example, the following command can be used to list the available parameters for the `ADDiffusion` object. -!listing ADDiffusion.md line=syntax parameters +!listing source/kernels/ADDiffusion.md line=syntax parameters ## What is a Requirement? diff --git a/tutorials/darcy_thermo_mech/doc/content/workshop/systems/kernels.md b/tutorials/darcy_thermo_mech/doc/content/workshop/systems/kernels.md index 286c7fc246d0..3aecabdb6f8b 100644 --- a/tutorials/darcy_thermo_mech/doc/content/workshop/systems/kernels.md +++ b/tutorials/darcy_thermo_mech/doc/content/workshop/systems/kernels.md @@ -65,7 +65,7 @@ where $\psi_i$ are the test functions and $u_h$ is the finite element solution. ## ADDiffusion.h -!listing ADDiffusion.h +!listing include/kernels/ADDiffusion.h !--- From 647b499aaebf7616bf42511effa1db1f9af5300d Mon Sep 17 00:00:00 2001 From: Namjae Choi Date: Mon, 27 Apr 2026 12:41:05 -0600 Subject: [PATCH 07/14] Unify residual object registration macro #30655 --- .../doc/content/syntax/KokkosBCs/index.md | 2 +- .../doc/content/syntax/KokkosKernels/index.md | 4 +-- .../syntax/KokkosNodalKernels/index.md | 2 +- .../include/kokkos/base/KokkosDispatcher.h | 25 ------------------- .../kokkos/bcs/KokkosDirichletBCBase.h | 4 +-- .../kokkos/bcs/KokkosDirectionalNeumannBC.K | 2 +- .../src/kokkos/bcs/KokkosEigenDirichletBC.K | 2 +- .../src/kokkos/kernels/KokkosADDiffusion.K | 2 +- .../KokkosHeatConductionTimeDerivative.K | 2 +- 9 files changed, 10 insertions(+), 35 deletions(-) diff --git a/framework/doc/content/syntax/KokkosBCs/index.md b/framework/doc/content/syntax/KokkosBCs/index.md index 1489d444eb32..6e99d9c18b66 100644 --- a/framework/doc/content/syntax/KokkosBCs/index.md +++ b/framework/doc/content/syntax/KokkosBCs/index.md @@ -9,7 +9,7 @@ Before reading this documentation, consider reading the following materials firs - [Kokkos Kernels System](syntax/KokkosKernels/index.md) to understand the common design pattern of objects in Kokkos-MOOSE. The basic design pattern of Kokkos-MOOSE kernels described in [Kokkos Kernels System](syntax/Kokkos/index.md) applies to the boundary conditions as well. -You can create your own integrated and nodal boundary conditions by subclassing `Moose::Kokkos::IntegratedBC` and `Moose::Kokkos::NodalBC`, respectively, and following the same pattern with kernels including registering your boundary conditions with either `registerKokkosBoundaryCondition()` or `registerKokkosResidualObject()`. +You can create your own integrated and nodal boundary conditions by subclassing `Moose::Kokkos::IntegratedBC` and `Moose::Kokkos::NodalBC`, respectively, and following the same pattern with kernels including registering your boundary conditions with `registerKokkosResidualObject()`. [Automatic differentiation (AD)](automatic_differentiation/index.md) versions of boundary conditions are also available and can be derived and registered in an analogous manner with the [AD kernels](syntax/KokkosKernels/index.md#kokkos_ad_kernel). Integrated boundary conditions have identical interfaces with kernels, so they will not be explained here in detail. diff --git a/framework/doc/content/syntax/KokkosKernels/index.md b/framework/doc/content/syntax/KokkosKernels/index.md index 4be74635e24c..e3ca11da1b30 100644 --- a/framework/doc/content/syntax/KokkosKernels/index.md +++ b/framework/doc/content/syntax/KokkosKernels/index.md @@ -13,7 +13,7 @@ Kokkos-MOOSE kernels do not support coupling with scalar variables yet. The Kokkos-MOOSE kernels are designed to resemble the original MOOSE kernels as much as possible for easier porting and adaptation. However, some differences still exist due to the fundamentally different programming paradigm between CPU and GPU. You can create your own kernel by subclassing `Moose::Kokkos::Kernel` as is done in the original MOOSE by inheriting `Kernel`. -However, your kernel should now be registered with either `registerKokkosKernel()` or `registerKokkosResidualObject()` instead of `registerMooseObject()`. +However, your kernel should now be registered with `registerKokkosResidualObject()` instead of `registerMooseObject()`. Also, the signatures of hook methods are different. In the original MOOSE, the following virtual functions should or optionally have been overriden: @@ -201,7 +201,7 @@ See the following source codes of `KokkosCoupledTimeDerivative` for an example o ## Automatic Differentiation id=kokkos_ad_kernel Kokkos-MOOSE kernels also support [automatic differentiation (AD)](automatic_differentiation/index.md). -AD kernels can be derived from `Moose::Kokkos::ADKernel` and should be registered with either `registerKokkosADKernel()` or `registerKokkosADResidualObject()`. +AD kernels can be derived from `Moose::Kokkos::ADKernel` and should be registered with `registerKokkosADResidualObject()`. AD kernels requires `computeQpResidual()` to be defined with the following signature, where everything remains the same with the ordinary kernels except the return type being `Moose::Kokkos::ADReal`: ```cpp diff --git a/framework/doc/content/syntax/KokkosNodalKernels/index.md b/framework/doc/content/syntax/KokkosNodalKernels/index.md index ff5cd3509072..45ec4ef48715 100644 --- a/framework/doc/content/syntax/KokkosNodalKernels/index.md +++ b/framework/doc/content/syntax/KokkosNodalKernels/index.md @@ -9,7 +9,7 @@ Before reading this documentation, consider reading the following materials firs - [Kokkos Kernels System](syntax/KokkosKernels/index.md) to understand the common design pattern of objects in Kokkos-MOOSE, - [Kokkos BCs System](syntax/KokkosBCs/index.md) to understand the design pattern of nodal boundary conditions in Kokkos-MOOSE. -You can create your own nodal kernels by inheriting `Moose::Kokkos::NodalKernel` and following the same pattern with kernels and boundary conditions including registering with either `registerKokkosNodalKernel()` or `registerKokkosResidualObject()`. +You can create your own nodal kernels by inheriting `Moose::Kokkos::NodalKernel` and following the same pattern with kernels and boundary conditions including registering with `registerKokkosResidualObject()`. The interfaces of nodal kernels are identical to the nodal boundary conditions described in [Kokkos BCs System](syntax/KokkosBCs/index.md), so they will not be explained here in detail. See the following source codes of `KokkosCoupledForceNodalKernel` for an example of a nodal kernel: diff --git a/framework/include/kokkos/base/KokkosDispatcher.h b/framework/include/kokkos/base/KokkosDispatcher.h index 26a77e898975..0ad71a1ed5d0 100644 --- a/framework/include/kokkos/base/KokkosDispatcher.h +++ b/framework/include/kokkos/base/KokkosDispatcher.h @@ -391,18 +391,6 @@ class DispatcherRegistry registerMooseObjectAliased(app, classname, alias); \ callRegisterKokkosResidualObjectFunction(classname, alias) -#define registerKokkosKernel(app, classname) registerKokkosResidualObject(app, classname) -#define registerKokkosKernelAliased(app, classname, alias) \ - registerKokkosResidualObjectAliased(app, classname, alias) - -#define registerKokkosNodalKernel(app, classname) registerKokkosResidualObject(app, classname) -#define registerKokkosNodalKernelAliased(app, classname, alias) \ - registerKokkosResidualObjectAliased(app, classname, alias) - -#define registerKokkosBoundaryCondition(app, classname) registerKokkosResidualObject(app, classname) -#define registerKokkosBoundaryConditionAliased(app, classname, alias) \ - registerKokkosResidualObjectAliased(app, classname, alias) - // AD Kernel, NodalKernel, BC #define callRegisterKokkosADResidualObjectFunction(classname, objectname) \ @@ -426,19 +414,6 @@ class DispatcherRegistry registerMooseObjectAliased(app, classname, alias); \ callRegisterKokkosADResidualObjectFunction(classname, alias) -#define registerKokkosADKernel(app, classname) registerKokkosADResidualObject(app, classname) -#define registerKokkosADKernelAliased(app, classname, alias) \ - registerKokkosADResidualObjectAliased(app, classname, alias) - -#define registerKokkosADNodalKernel(app, classname) registerKokkosADResidualObject(app, classname) -#define registerKokkosADNodalKernelAliased(app, classname, alias) \ - registerKokkosADResidualObjectAliased(app, classname, alias) - -#define registerKokkosADBoundaryCondition(app, classname) \ - registerKokkosADResidualObject(app, classname) -#define registerKokkosADBoundaryConditionAliased(app, classname, alias) \ - registerKokkosADResidualObjectAliased(app, classname, alias) - // Material #define callRegisterKokkosMaterialFunction(classname, objectname) \ diff --git a/framework/include/kokkos/bcs/KokkosDirichletBCBase.h b/framework/include/kokkos/bcs/KokkosDirichletBCBase.h index 9fd9b66b0c16..f9f0d7b7a5e1 100644 --- a/framework/include/kokkos/bcs/KokkosDirichletBCBase.h +++ b/framework/include/kokkos/bcs/KokkosDirichletBCBase.h @@ -115,9 +115,9 @@ typedef DirichletBCBaseTempl ADDirichletBCBase; } // namespace Moose::Kokkos #define registerKokkosDirichletBC(app, classname) \ - registerKokkosBoundaryCondition(app, classname); \ + registerKokkosResidualObject(app, classname); \ registerKokkosAdditionalOperation(classname, PresetLoop) #define registerKokkosADDirichletBC(app, classname) \ - registerKokkosADBoundaryCondition(app, classname); \ + registerKokkosADResidualObject(app, classname); \ registerKokkosAdditionalOperation(classname, PresetLoop) diff --git a/framework/src/kokkos/bcs/KokkosDirectionalNeumannBC.K b/framework/src/kokkos/bcs/KokkosDirectionalNeumannBC.K index 39bf9413031d..15de677c2bd6 100644 --- a/framework/src/kokkos/bcs/KokkosDirectionalNeumannBC.K +++ b/framework/src/kokkos/bcs/KokkosDirectionalNeumannBC.K @@ -9,7 +9,7 @@ #include "KokkosDirectionalNeumannBC.h" -registerKokkosBoundaryCondition("MooseApp", KokkosDirectionalNeumannBC); +registerKokkosResidualObject("MooseApp", KokkosDirectionalNeumannBC); InputParameters KokkosDirectionalNeumannBC::validParams() diff --git a/framework/src/kokkos/bcs/KokkosEigenDirichletBC.K b/framework/src/kokkos/bcs/KokkosEigenDirichletBC.K index 9244c7f72542..34e42924c7ff 100644 --- a/framework/src/kokkos/bcs/KokkosEigenDirichletBC.K +++ b/framework/src/kokkos/bcs/KokkosEigenDirichletBC.K @@ -9,7 +9,7 @@ #include "KokkosEigenDirichletBC.h" -registerKokkosBoundaryCondition("MooseApp", KokkosEigenDirichletBC); +registerKokkosResidualObject("MooseApp", KokkosEigenDirichletBC); InputParameters KokkosEigenDirichletBC::validParams() diff --git a/framework/src/kokkos/kernels/KokkosADDiffusion.K b/framework/src/kokkos/kernels/KokkosADDiffusion.K index 1c90afacf2d1..3036525def84 100644 --- a/framework/src/kokkos/kernels/KokkosADDiffusion.K +++ b/framework/src/kokkos/kernels/KokkosADDiffusion.K @@ -9,7 +9,7 @@ #include "KokkosADDiffusion.h" -registerKokkosADKernel("MooseApp", KokkosADDiffusion); +registerKokkosADResidualObject("MooseApp", KokkosADDiffusion); InputParameters KokkosADDiffusion::validParams() diff --git a/modules/heat_transfer/src/kokkos/kernels/KokkosHeatConductionTimeDerivative.K b/modules/heat_transfer/src/kokkos/kernels/KokkosHeatConductionTimeDerivative.K index 1217bc09f52b..c48cb9bfa7c3 100644 --- a/modules/heat_transfer/src/kokkos/kernels/KokkosHeatConductionTimeDerivative.K +++ b/modules/heat_transfer/src/kokkos/kernels/KokkosHeatConductionTimeDerivative.K @@ -9,7 +9,7 @@ #include "KokkosHeatConductionTimeDerivative.h" -registerKokkosKernel("HeatTransferApp", KokkosHeatConductionTimeDerivative); +registerKokkosResidualObject("HeatTransferApp", KokkosHeatConductionTimeDerivative); InputParameters KokkosHeatConductionTimeDerivative::validParams() From 362904c531703de498fd023255041e2169998340 Mon Sep 17 00:00:00 2001 From: Namjae Choi Date: Mon, 4 May 2026 11:34:33 -0600 Subject: [PATCH 08/14] Remove datum.reinit() #30655 --- framework/include/kokkos/base/KokkosDatum.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/framework/include/kokkos/base/KokkosDatum.h b/framework/include/kokkos/base/KokkosDatum.h index 2dac4cdadb65..b4745c44b7ee 100644 --- a/framework/include/kokkos/base/KokkosDatum.h +++ b/framework/include/kokkos/base/KokkosDatum.h @@ -179,11 +179,6 @@ class Datum */ KOKKOS_FUNCTION Real3 normals(const unsigned int qp); - /** - * Deprecated, will be removed - */ - KOKKOS_FUNCTION void reinit() {} - /** * Set local parallelization option * @param local_thread_id The current local thread ID From ade6f8b3e94c652b295fac0b7cd39ea5dd1e7b83 Mon Sep 17 00:00:00 2001 From: Namjae Choi Date: Fri, 8 May 2026 14:00:27 -0600 Subject: [PATCH 09/14] Pad jagged array data by one to avoid reading the end of data #30655 --- framework/include/kokkos/base/KokkosJaggedArray.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/include/kokkos/base/KokkosJaggedArray.h b/framework/include/kokkos/base/KokkosJaggedArray.h index ba837117424e..87560a8fddfb 100644 --- a/framework/include/kokkos/base/KokkosJaggedArray.h +++ b/framework/include/kokkos/base/KokkosJaggedArray.h @@ -411,7 +411,7 @@ JaggedArray::finalize() _dims.copyToDevice(); _offsets.copyToDevice(); - _data.create(_offsets.last() + stride); + _data.create(_offsets.last() + stride + 1); _finalized = true; } From 87b28daea3ec1849cd3c894678cd053ea173523e Mon Sep 17 00:00:00 2001 From: Namjae Choi Date: Mon, 11 May 2026 17:17:51 -0600 Subject: [PATCH 10/14] Address comments 1 #32699 --- framework/include/kokkos/base/KokkosVariable.h | 9 +++++++++ framework/include/kokkos/base/KokkosVariableValue.h | 8 +++++--- framework/src/kokkos/base/KokkosVariable.K | 12 ++++++++++++ 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/framework/include/kokkos/base/KokkosVariable.h b/framework/include/kokkos/base/KokkosVariable.h index 50c116f9edf9..f630e2d90699 100644 --- a/framework/include/kokkos/base/KokkosVariable.h +++ b/framework/include/kokkos/base/KokkosVariable.h @@ -152,6 +152,11 @@ class Variable * @returns Whether the tag is time derivative */ KOKKOS_FUNCTION bool dot() const { return _dot; } + /** + * Get whether the tag is old/older value + * @returns Whether the tag is old/older value + */ + KOKKOS_FUNCTION bool old() const { return _old; } /** * Get the number of components * @returns The number of components @@ -203,6 +208,10 @@ class Variable * Whether the tag is time derivative */ bool _dot = false; + /** + * Whether the tag is old/older value + */ + bool _old = false; /** * Number of components */ diff --git a/framework/include/kokkos/base/KokkosVariableValue.h b/framework/include/kokkos/base/KokkosVariableValue.h index 6ab00fa6467c..7b6bf288d8bd 100644 --- a/framework/include/kokkos/base/KokkosVariableValue.h +++ b/framework/include/kokkos/base/KokkosVariableValue.h @@ -250,7 +250,8 @@ VariableValueTempl::VariableValueTempl(const VariableValueTempl & _seed.create(_var.components()); for (unsigned int comp = 0; comp < _var.components(); ++comp) - _seed[comp] = _var.dot() ? _var.mooseVar(comp)->sys().duDotDu(_var.var(comp)) : 1; + _seed[comp] = + _var.dot() ? _var.mooseVar(comp)->sys().duDotDu(_var.var(comp)) : (_var.old() ? 0 : 1); _seed.copyToDevice(); } @@ -377,7 +378,7 @@ class VariableGradientTempl : _var(vars, tag) { } - VariableGradientTempl(const std::vector vars, + VariableGradientTempl(const std::vector & vars, const TagName & tag = Moose::SOLUTION_TAG) : _var(vars, tag) { @@ -460,7 +461,8 @@ VariableGradientTempl::VariableGradientTempl(const VariableGradientTempl< _seed.create(_var.components()); for (unsigned int comp = 0; comp < _var.components(); ++comp) - _seed[comp] = _var.dot() ? _var.mooseVar(comp)->sys().duDotDu(_var.var(comp)) : 1; + _seed[comp] = + _var.dot() ? _var.mooseVar(comp)->sys().duDotDu(_var.var(comp)) : (_var.old() ? 0 : 1); _seed.copyToDevice(); } diff --git a/framework/src/kokkos/base/KokkosVariable.K b/framework/src/kokkos/base/KokkosVariable.K index b92342e7b386..a89f0654e381 100644 --- a/framework/src/kokkos/base/KokkosVariable.K +++ b/framework/src/kokkos/base/KokkosVariable.K @@ -48,6 +48,12 @@ Variable::init(const MooseVariableFieldBase & variable, const TagID tag) if (problem.vectorTagExists(Moose::SOLUTION_DOT_TAG)) _dot = tag == problem.getVectorTagID(Moose::SOLUTION_DOT_TAG); + + if (problem.vectorTagExists(Moose::OLD_SOLUTION_TAG)) + _old = _old || tag == problem.getVectorTagID(Moose::OLD_SOLUTION_TAG); + + if (problem.vectorTagExists(Moose::OLDER_SOLUTION_TAG)) + _old = _old || tag == problem.getVectorTagID(Moose::OLDER_SOLUTION_TAG); } void @@ -99,6 +105,12 @@ Variable::init(const std::vector & variables, co if (problem.vectorTagExists(Moose::SOLUTION_DOT_TAG)) _dot = tag == problem.getVectorTagID(Moose::SOLUTION_DOT_TAG); + + if (problem.vectorTagExists(Moose::OLD_SOLUTION_TAG)) + _old = _old || tag == problem.getVectorTagID(Moose::OLD_SOLUTION_TAG); + + if (problem.vectorTagExists(Moose::OLDER_SOLUTION_TAG)) + _old = _old || tag == problem.getVectorTagID(Moose::OLDER_SOLUTION_TAG); } void From 3a693464f65153a54b1cd5156ae22a1e35c27a28 Mon Sep 17 00:00:00 2001 From: Namjae Choi Date: Thu, 14 May 2026 09:21:28 -0600 Subject: [PATCH 11/14] Address comments 2 #32699 --- framework/doc/content/syntax/KokkosKernels/index.md | 4 ++-- framework/include/kokkos/base/KokkosJaggedArray.h | 3 +++ framework/include/kokkos/base/KokkosTypes.h | 2 +- framework/include/kokkos/bcs/KokkosADCoupledVarNeumannBC.h | 3 --- framework/src/kokkos/base/KokkosResidualObject.K | 3 +++ framework/src/kokkos/base/KokkosVariable.K | 4 ++-- framework/src/kokkos/bcs/KokkosADCoupledVarNeumannBC.K | 1 - test/tests/kokkos/kernels/ad_diffusion/tests | 2 +- test/tests/kokkos/kernels/ad_time_derivative/tests | 4 ++-- 9 files changed, 14 insertions(+), 12 deletions(-) diff --git a/framework/doc/content/syntax/KokkosKernels/index.md b/framework/doc/content/syntax/KokkosKernels/index.md index e3ca11da1b30..c09c0b601d23 100644 --- a/framework/doc/content/syntax/KokkosKernels/index.md +++ b/framework/doc/content/syntax/KokkosKernels/index.md @@ -202,7 +202,7 @@ See the following source codes of `KokkosCoupledTimeDerivative` for an example o Kokkos-MOOSE kernels also support [automatic differentiation (AD)](automatic_differentiation/index.md). AD kernels can be derived from `Moose::Kokkos::ADKernel` and should be registered with `registerKokkosADResidualObject()`. -AD kernels requires `computeQpResidual()` to be defined with the following signature, where everything remains the same with the ordinary kernels except the return type being `Moose::Kokkos::ADReal`: +AD kernels require `computeQpResidual()` to be defined with the following signature, where everything remains the same with the ordinary kernels except the return type being `Moose::Kokkos::ADReal`: ```cpp template @@ -211,7 +211,7 @@ KOKKOS_FUNCTION Moose::Kokkos::ADReal computeQpResidual(const unsigned int i, AssemblyDatum & datum) const; ``` -`computeQpJacobian()` and `computeQpOffDiagJacobian()` are unused, as AD automatically assembles Jacobian. +`computeQpJacobian()` and `computeQpOffDiagJacobian()` are unused, as AD automatically assembles the Jacobian. !syntax list /Kernels objects=True actions=False subsystems=False diff --git a/framework/include/kokkos/base/KokkosJaggedArray.h b/framework/include/kokkos/base/KokkosJaggedArray.h index 87560a8fddfb..48d8b30033d2 100644 --- a/framework/include/kokkos/base/KokkosJaggedArray.h +++ b/framework/include/kokkos/base/KokkosJaggedArray.h @@ -411,6 +411,9 @@ JaggedArray::finalize() _dims.copyToDevice(); _offsets.copyToDevice(); + + // Pad an extra element at the end to avoid accessing the bound in the following operators when + // the last inner array has zero size _data.create(_offsets.last() + stride + 1); _finalized = true; diff --git a/framework/include/kokkos/base/KokkosTypes.h b/framework/include/kokkos/base/KokkosTypes.h index 6eff5006da8f..2f28905028aa 100644 --- a/framework/include/kokkos/base/KokkosTypes.h +++ b/framework/include/kokkos/base/KokkosTypes.h @@ -40,7 +40,7 @@ struct Vector3 #ifdef MOOSE_KOKKOS_SCOPE Vector3(const libMesh::TypeVector & vector); - KOKKOS_INLINE_FUNCTION Vector3() { *this = T(0); } + KOKKOS_INLINE_FUNCTION Vector3() { *this = T{}; } KOKKOS_INLINE_FUNCTION Vector3(const T & scalar) { *this = scalar; } KOKKOS_INLINE_FUNCTION Vector3(const Vector3 & vector) { *this = vector; } KOKKOS_INLINE_FUNCTION Vector3(const T & x, const T & y, const T & z); diff --git a/framework/include/kokkos/bcs/KokkosADCoupledVarNeumannBC.h b/framework/include/kokkos/bcs/KokkosADCoupledVarNeumannBC.h index 6574abac57b8..9e76cce88af1 100644 --- a/framework/include/kokkos/bcs/KokkosADCoupledVarNeumannBC.h +++ b/framework/include/kokkos/bcs/KokkosADCoupledVarNeumannBC.h @@ -30,9 +30,6 @@ class KokkosADCoupledVarNeumannBC : public Moose::Kokkos::ADIntegratedBC /// Variable providing the value of grad(u) on the boundary. const Moose::Kokkos::ADVariableValue _coupled_var; - /// The identifying number of the coupled variable - const unsigned int _coupled_num; - /// A coefficient that is multiplied with the residual contribution const Real _coef; diff --git a/framework/src/kokkos/base/KokkosResidualObject.K b/framework/src/kokkos/base/KokkosResidualObject.K index 20fbc513a1f2..84cbb127ba99 100644 --- a/framework/src/kokkos/base/KokkosResidualObject.K +++ b/framework/src/kokkos/base/KokkosResidualObject.K @@ -52,6 +52,9 @@ ResidualObject::ResidualObject(const InputParameters & parameters, _dt(TransientInterface::_dt), _dt_old(TransientInterface::_dt_old) { + if (_var.isVector()) + paramError("variable", "Kokkos residual objects do not support vector variables yet."); + _kokkos_var.init(_var); } diff --git a/framework/src/kokkos/base/KokkosVariable.K b/framework/src/kokkos/base/KokkosVariable.K index a89f0654e381..e7bbfca3c45a 100644 --- a/framework/src/kokkos/base/KokkosVariable.K +++ b/framework/src/kokkos/base/KokkosVariable.K @@ -50,7 +50,7 @@ Variable::init(const MooseVariableFieldBase & variable, const TagID tag) _dot = tag == problem.getVectorTagID(Moose::SOLUTION_DOT_TAG); if (problem.vectorTagExists(Moose::OLD_SOLUTION_TAG)) - _old = _old || tag == problem.getVectorTagID(Moose::OLD_SOLUTION_TAG); + _old = tag == problem.getVectorTagID(Moose::OLD_SOLUTION_TAG); if (problem.vectorTagExists(Moose::OLDER_SOLUTION_TAG)) _old = _old || tag == problem.getVectorTagID(Moose::OLDER_SOLUTION_TAG); @@ -107,7 +107,7 @@ Variable::init(const std::vector & variables, co _dot = tag == problem.getVectorTagID(Moose::SOLUTION_DOT_TAG); if (problem.vectorTagExists(Moose::OLD_SOLUTION_TAG)) - _old = _old || tag == problem.getVectorTagID(Moose::OLD_SOLUTION_TAG); + _old = tag == problem.getVectorTagID(Moose::OLD_SOLUTION_TAG); if (problem.vectorTagExists(Moose::OLDER_SOLUTION_TAG)) _old = _old || tag == problem.getVectorTagID(Moose::OLDER_SOLUTION_TAG); diff --git a/framework/src/kokkos/bcs/KokkosADCoupledVarNeumannBC.K b/framework/src/kokkos/bcs/KokkosADCoupledVarNeumannBC.K index 6ccebcd64e2a..0fd9fa4e31c7 100644 --- a/framework/src/kokkos/bcs/KokkosADCoupledVarNeumannBC.K +++ b/framework/src/kokkos/bcs/KokkosADCoupledVarNeumannBC.K @@ -28,7 +28,6 @@ KokkosADCoupledVarNeumannBC::validParams() KokkosADCoupledVarNeumannBC::KokkosADCoupledVarNeumannBC(const InputParameters & parameters) : ADIntegratedBC(parameters), _coupled_var(kokkosADCoupledValue("v")), - _coupled_num(coupled("v")), _coef(getParam("coef")), _scale_factor(kokkosADCoupledValue("scale_factor")) { diff --git a/test/tests/kokkos/kernels/ad_diffusion/tests b/test/tests/kokkos/kernels/ad_diffusion/tests index b3d164963306..0492fb5d358f 100644 --- a/test/tests/kokkos/kernels/ad_diffusion/tests +++ b/test/tests/kokkos/kernels/ad_diffusion/tests @@ -24,7 +24,7 @@ input = 'kokkos_2d_ad_diffusion_test.i' cli_args = 'Outputs/exodus=false' recover = false - requirement = 'The Kokkos system shall provide exact Jacobian using automatic differentation.' + requirement = 'The Kokkos system shall provide an exact Jacobian using automatic differentation.' design = 'framework_stp.md' capabilities = 'kokkos' compute_devices = 'cpu cuda' diff --git a/test/tests/kokkos/kernels/ad_time_derivative/tests b/test/tests/kokkos/kernels/ad_time_derivative/tests index 57a6ad7696d3..5b512c5f8137 100644 --- a/test/tests/kokkos/kernels/ad_time_derivative/tests +++ b/test/tests/kokkos/kernels/ad_time_derivative/tests @@ -17,7 +17,7 @@ run_sim = True ratio_tol = 1e-7 difference_tol = 1e-6 - requirement = 'The Jacobian from KokkosADTimeDerivative shall be perfect.' + requirement = 'The Jacobian from a Kokkos-based time derivative kernel shall be perfect.' design = 'KokkosADTimeDerivative.md' capabilities = 'kokkos' compute_devices = 'cpu cuda' @@ -39,7 +39,7 @@ run_sim = True ratio_tol = 1e-7 difference_tol = 1e-6 - requirement = 'The Jacobian from KokkosADCoupledTimeDerivative shall be perfect.' + requirement = 'The Jacobian from a Kokkos-based coupled variable time derivative kernel shall be perfect.' design = 'KokkosADCoupledTimeDerivative.md' capabilities = 'kokkos' compute_devices = 'cpu cuda' From 9503798aaad6f5cc899365580d6b344b3d98c41d Mon Sep 17 00:00:00 2001 From: Namjae Choi Date: Thu, 14 May 2026 13:15:32 -0600 Subject: [PATCH 12/14] Improve Kokkos documentations #30655 --- framework/doc/content/syntax/Kokkos/index.md | 23 +++++++++++++++---- .../doc/content/syntax/KokkosKernels/index.md | 13 +++++------ 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/framework/doc/content/syntax/Kokkos/index.md b/framework/doc/content/syntax/Kokkos/index.md index aeb48cad6c6a..2f60c6d45834 100644 --- a/framework/doc/content/syntax/Kokkos/index.md +++ b/framework/doc/content/syntax/Kokkos/index.md @@ -317,7 +317,7 @@ For example, a postprocessor value which is always provided as read-only can be !alert note The data type should be copy-constructable. -### Static Polymorphism with Curiously Recurring Template Pattern (CRTP) id=kokkos_crtp +### Static Polymorphism id=kokkos_crtp The primary challenge in porting MOOSE to GPU lies in its heavy reliance on dynamic polymorphism using virtual functions. Polymorphism is the centerpiece of the +*template method pattern*+, which is a behavioral design pattern in object-oriented programming that establishes the skeleton of an algorithm in a base class while permitting derived classes to override certain steps without altering the algorithm’s overall structure, and it is the key design pattern of MOOSE. @@ -332,8 +332,9 @@ Furthermore, not every GPU backend supports virtual functions. Aside from portability, using virtual functions on GPU should be avoided if possible for performance, especially when the virtual functions are called in critical paths. The vtable lookup itself incurs overheads, and using function pointers prevents inlining. GPU compilers heavily rely on the inlining to generate an optimized code, and being unable to inline functions will likely lead to a performance hit. +Therefore, any polymorphism on GPU should be implemented statically. -Therefore, any polymorphism on GPU should be implemented statically, which can be achieved by the CRTP. +While not directly being used in Kokkos-MOOSE, the most famous static polymorphism design pattern is the Curiously Recurring Template Pattern (CRTP). The CRTP is a programming idiom that involves a class template inheriting from a template instantiation of itself, which is a technique used to achieve static (compile-time) polymorphism. The following pseudo-codes demonstrate a typical template method pattern implemented with the dynamic polymorphism and its equivalent implementation with the static polymorphism using the CRTP: @@ -405,9 +406,21 @@ Because the class type of the final derived class should be seen by the base cla If you accidentally derive a class from a non-template class, the base class will not be able to see the derived class. In this case, you are encouraged to prevent unintended inheritance by explicitly adding the `final` keyword to the last level derived class. -The Kokkos-MOOSE base classes are carefully designed to avoid the CRTP by leveraging a registry design pattern where external dispatchers are registered together with the objects. -Namely, the base classes themselves are not template classes, which alleviates the burden of users in dealing with class templates. -The hook methods provided by Kokkos-MOOSE are also template functions with respect to your object type, so you can directly cast `this` pointer in the hook methods without having to rely on class templates. +Kokkos-MOOSE is carefully designed to avoid the CRTP by leveraging a registry design pattern, where external dispatchers are registered together with the objects. +However, the basic principles of static polymorphism in the CRTP (templates, static casting of `this`, methods being public, function hiding) are still applicable and important to understand. +In Kokkos-MOOSE, the base classes are not template classes, which alleviates the burden of users in dealing with class templates. +Instead, the hook methods provided by Kokkos-MOOSE are template functions with respect to your object type, so you can directly cast `this` pointer in the hook methods without having to rely on class templates. +For example, the `computeQpResidual` hook method of Kokkos-MOOSE [Kernels](syntax/KokkosKernels/index.md) is defined as a template function: + +```cpp +template +KOKKOS_FUNCTION Real computeQpResidual(const unsigned int i, + const unsigned int qp, + AssemblyDatum & datum) const; +``` + +The function template argument `Derived` replaces the class template argument in the CRTP and corresponds to your derived object type. +You can safely cast `this` pointer to the `Derived` type statically in your base class and directly call derived class methods, which are still required to be public methods. ### Separate Compilation diff --git a/framework/doc/content/syntax/KokkosKernels/index.md b/framework/doc/content/syntax/KokkosKernels/index.md index c09c0b601d23..9f8e9f4806f5 100644 --- a/framework/doc/content/syntax/KokkosKernels/index.md +++ b/framework/doc/content/syntax/KokkosKernels/index.md @@ -47,8 +47,7 @@ KOKKOS_FUNCTION Real computeQpOffDiagJacobian(const unsigned int i, AssemblyDatum & datum) const; ``` -The template argument `Derived` corresponds to your object type, and you can safely cast `this` pointer to the `Derived` type statically in your base class. -It can be useful for implementing polymorphism in a [CRTP-like](syntax/Kokkos/index.md#kokkos_crtp) fashion, as you can directly call the derived class methods using the cast pointer. +The template argument `Derived` can be used for implementing static polymorphism in a [CRTP-like](syntax/Kokkos/index.md#kokkos_crtp) fashion by statically casting `this` pointer to the derived type and directly calling the derived class methods using the cast pointer. Analogously to the original MOOSE, `computeQpResidual()` must be provided in the derived class, and the definition of `computeQpJacobian()` and `computeQpOffDiagJacobian()` are optional. The optional methods have default definitions in the base class, and redefining them in the derived class hides the base class definitions. @@ -99,13 +98,13 @@ KokkosDiffusion::computeQpJacobian(const unsigned int i, } ``` -See the following source codes of `KokkosCoupledForce` for another example of a kernel: +See the following source codes of `KokkosBodyForce` for another example of a kernel: -!listing framework/include/kokkos/kernels/KokkosCoupledForce.h id=kokkos-force-header - caption=The `KokkosCoupledForce` header file. +!listing framework/include/kokkos/kernels/KokkosBodyForce.h id=kokkos-force-header + caption=The `KokkosBodyForce` header file. -!listing framework/src/kokkos/kernels/KokkosCoupledForce.K id=kokkos-force-source language=cpp - caption=The `KokkosCoupledForce` source file. +!listing framework/src/kokkos/kernels/KokkosBodyForce.K id=kokkos-force-source language=cpp + caption=The `KokkosBodyForce` source file. !alert note [Every GPU function needs to be inlineable](syntax/Kokkos/index.md#kokkos_execution_space) and thus should be defined in headers. From 3e3d51e41efc9296b1265c450290c735ba96434f Mon Sep 17 00:00:00 2001 From: Namjae Choi Date: Mon, 18 May 2026 20:03:02 -0600 Subject: [PATCH 13/14] Address comments 3 #32699 --- framework/include/kokkos/systems/KokkosSystem.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/framework/include/kokkos/systems/KokkosSystem.h b/framework/include/kokkos/systems/KokkosSystem.h index 15fef0c6893e..e0209174ca3b 100644 --- a/framework/include/kokkos/systems/KokkosSystem.h +++ b/framework/include/kokkos/systems/KokkosSystem.h @@ -711,7 +711,7 @@ System::getVectorQpGradFace(const ElementInfo info, auto n_dofs = kokkosAssembly().getNumDofs(info.type, fe); auto & grad_phi = kokkosAssembly().getGradPhiFace(info.subdomain, info.type, fe)(side); - Real3 grad; + Real3 grad = 0; for (unsigned int i = 0; i < n_dofs; ++i) grad += getVectorDofValue(getElemLocalDofIndex(info.id, i, var), tag) * @@ -733,7 +733,7 @@ System::getVectorQpADGradFace(const ElementInfo info, auto n_dofs = kokkosAssembly().getNumDofs(info.type, fe); auto & grad_phi = kokkosAssembly().getGradPhiFace(info.subdomain, info.type, fe)(side); - ADReal3 grad; + ADReal3 grad = ADReal(0); for (unsigned int i = 0; i < n_dofs; ++i) grad += getVectorDofADValue(getElemLocalDofIndex(info.id, i, var), tag, seed) * From 28bde298bae0c97feabba5dc34c709f31cb358ef Mon Sep 17 00:00:00 2001 From: Namjae Choi Date: Tue, 19 May 2026 07:43:43 -0600 Subject: [PATCH 14/14] Leave some useful changes from separate nodal BC assembly #32699 --- .../kokkos/base/KokkosResidualObject.h | 6 +- .../include/kokkos/systems/KokkosMatrix.h | 4 + .../include/systems/NonlinearSystemBase.h | 20 +- .../kokkos/systems/KokkosAuxiliarySystem.K | 7 +- .../systems/KokkosNonlinearSystemBase.K | 50 ++-- framework/src/systems/NonlinearSystemBase.C | 260 +++++++++--------- 6 files changed, 186 insertions(+), 161 deletions(-) diff --git a/framework/include/kokkos/base/KokkosResidualObject.h b/framework/include/kokkos/base/KokkosResidualObject.h index 83a0475bda0b..e90367032d67 100644 --- a/framework/include/kokkos/base/KokkosResidualObject.h +++ b/framework/include/kokkos/base/KokkosResidualObject.h @@ -131,7 +131,7 @@ class ResidualObject : public ::ResidualObject, const unsigned int comp = 0) const; /** * Accumulate or set local nodal residual contribution to tagged vectors - * @param add The flag whether to add or set the local residual + * @param add Whether to add or set the local residual * @param local_re The local nodal residual contribution * @param node The contiguous node ID * @param comp The variable component @@ -169,7 +169,7 @@ class ResidualObject : public ::ResidualObject, const unsigned int comp = 0) const; /** * Accumulate or set local nodal Jacobian contribution to tagged matrices - * @param add The flag whether to add or set the local residual + * @param add Whether to add or set the local Jacobian * @param local_ke The local nodal Jacobian contribution * @param node The contiguous node ID * @param jvar The variable number for column @@ -183,7 +183,7 @@ class ResidualObject : public ::ResidualObject, /** * Accumulate or set local nodal Jacobian contribution to tagged matrices using automatic * differentiation (AD) - * @param add The flag whether to add or set the local residual + * @param add Whether to add or set the local Jacobian * @param local_ke The local elemental Jacobian contribution * @param node The contiguous node ID * @param comp The variable component diff --git a/framework/include/kokkos/systems/KokkosMatrix.h b/framework/include/kokkos/systems/KokkosMatrix.h index bfc0e7904a56..acf724f204c6 100644 --- a/framework/include/kokkos/systems/KokkosMatrix.h +++ b/framework/include/kokkos/systems/KokkosMatrix.h @@ -36,6 +36,10 @@ class Matrix * Destructor */ ~Matrix() { destroy(); } + /** + * Get PETSc matrix handle + */ + Mat mat() { return _matrix; } /** * Free all data and reset */ diff --git a/framework/include/systems/NonlinearSystemBase.h b/framework/include/systems/NonlinearSystemBase.h index 121d001b8964..25c5eaa0ba2d 100644 --- a/framework/include/systems/NonlinearSystemBase.h +++ b/framework/include/systems/NonlinearSystemBase.h @@ -780,32 +780,40 @@ class NonlinearSystemBase : public SolverSystem, public PerfGraphInterface */ void computeResidualInternal(const std::set & tags); +#ifdef MOOSE_KOKKOS_ENABLED /** * Compute residual with Kokkos objects */ -#ifdef MOOSE_KOKKOS_ENABLED void computeKokkosResidual(const std::set & tags); - void computeKokkosNodalBCs(const std::set & tags); + /** + * Compute Kokkos nodal BCs + */ + void computeKokkosNodalBCsResidual(const std::set & tags); #endif /** * Enforces nodal boundary conditions. The boundary condition will be implemented * in the residual using all the tags in the system. */ - void computeNodalBCs(NumericVector & residual); + void computeNodalBCsResidual(NumericVector & residual); /** * Form a residual for BCs that at least has one of the given tags. */ - void computeNodalBCs(NumericVector & residual, const std::set & tags); + void computeNodalBCsResidual(NumericVector & residual, const std::set & tags); /** * Form multiple tag-associated residual vectors for the given tags. */ - void computeNodalBCs(const std::set & tags); + void computeNodalBCsResidual(const std::set & tags); + + /** + * Compute the Jacobian for nodal boundary conditions + */ + void computeNodalBCsJacobian(const std::set & tags); /** - * compute the residual and Jacobian for nodal boundary conditions + * Compute the residual and Jacobian together for nodal boundary conditions */ void computeNodalBCsResidualAndJacobian(const std::set & vector_tags, const std::set & matrix_tags); diff --git a/framework/src/kokkos/systems/KokkosAuxiliarySystem.K b/framework/src/kokkos/systems/KokkosAuxiliarySystem.K index 9326c5037eb8..91350a0774e9 100644 --- a/framework/src/kokkos/systems/KokkosAuxiliarySystem.K +++ b/framework/src/kokkos/systems/KokkosAuxiliarySystem.K @@ -31,7 +31,8 @@ AuxiliarySystem::kokkosCompute(ExecFlagType type) { TIME_SECTION("computeKokkosAuxKernel", 3); - if (!_kokkos_elemental_aux_storage[type].size() && !_kokkos_nodal_aux_storage[type].size()) + if (!_kokkos_elemental_aux_storage[type].hasActiveObjects() && + !_kokkos_nodal_aux_storage[type].hasActiveObjects()) return; auto & systems = _fe_problem.getKokkosSystems(); @@ -104,10 +105,10 @@ AuxiliarySystem::kokkosCompute(ExecFlagType type) // Compute auxiliary kernels - for (auto nodal : _kokkos_nodal_aux_storage[type].getActiveObjects()) + for (auto & nodal : _kokkos_nodal_aux_storage[type].getActiveObjects()) nodal->compute(); - for (auto elemental : _kokkos_elemental_aux_storage[type].getActiveObjects()) + for (auto & elemental : _kokkos_elemental_aux_storage[type].getActiveObjects()) elemental->compute(); } diff --git a/framework/src/kokkos/systems/KokkosNonlinearSystemBase.K b/framework/src/kokkos/systems/KokkosNonlinearSystemBase.K index 9f91b74ca0c7..4fa9d276883b 100644 --- a/framework/src/kokkos/systems/KokkosNonlinearSystemBase.K +++ b/framework/src/kokkos/systems/KokkosNonlinearSystemBase.K @@ -112,7 +112,7 @@ NonlinearSystemBase::setKokkosInitialSolution() systems.copyToDevice(); - for (auto nbc : _kokkos_preset_nodal_bcs.getActiveObjects()) + for (auto & nbc : _kokkos_preset_nodal_bcs.getActiveObjects()) std::static_pointer_cast(nbc)->presetSolution(tag); Kokkos::fence(); @@ -168,7 +168,8 @@ NonlinearSystemBase::computeKokkosResidual(const std::set & tags) needed_fe_var_vector_tags); } - // Copy vectors and cache variable values at element quadature points + // Copy solution vectors and residuals and cache variable values at element quadature + // points for (auto & system : systems) { @@ -204,13 +205,13 @@ NonlinearSystemBase::computeKokkosResidual(const std::set & tags) // Compute kernels - for (auto kernel : kernels.getActiveObjects()) + for (auto & kernel : kernels.getActiveObjects()) kernel->computeResidual(); - for (auto nodal_kernel : nodal_kernels.getActiveObjects()) + for (auto & nodal_kernel : nodal_kernels.getActiveObjects()) nodal_kernel->computeResidual(); - for (auto ibc : integrated_bcs.getActiveObjects()) + for (auto & ibc : integrated_bcs.getActiveObjects()) ibc->computeResidual(); } @@ -235,15 +236,15 @@ NonlinearSystemBase::computeKokkosResidual(const std::set & tags) } void -NonlinearSystemBase::computeKokkosNodalBCs(const std::set & tags) +NonlinearSystemBase::computeKokkosNodalBCsResidual(const std::set & tags) { - TIME_SECTION("computeKokkosNodalBC", 1); + TIME_SECTION("computeKokkosNodalBCsResidual", 1); // Get warehouses const auto & nodal_bcs = _kokkos_nodal_bcs.getVectorTagsObjectWarehouse(tags, 0); - if (!nodal_bcs.size()) + if (!nodal_bcs.hasActiveObjects()) return; // Resolve dependencies @@ -259,7 +260,7 @@ NonlinearSystemBase::computeKokkosNodalBCs(const std::set & tags) nodal_bcs.updateFEVariableCoupledVectorTagDependency(needed_fe_var_vector_tags); - // Copy vectors + // Copy solution vectors and residuals for (auto & system : systems) { @@ -278,7 +279,7 @@ NonlinearSystemBase::computeKokkosNodalBCs(const std::set & tags) // Compute kernels - for (auto nbc : nodal_bcs.getActiveObjects()) + for (auto & nbc : nodal_bcs.getActiveObjects()) nbc->computeResidual(); } @@ -311,7 +312,8 @@ NonlinearSystemBase::computeKokkosJacobian(const std::set & tags) const auto & integrated_bcs = _kokkos_integrated_bcs.getMatrixTagsObjectWarehouse(tags, 0); const auto & nodal_bcs = _kokkos_nodal_bcs.getMatrixTagsObjectWarehouse(tags, 0); - if (!kernels.size() && !nodal_kernels.size() && !integrated_bcs.size() && !nodal_bcs.size()) + if (!kernels.hasActiveObjects() && !nodal_kernels.hasActiveObjects() && + !integrated_bcs.hasActiveObjects() && !nodal_bcs.hasActiveObjects()) return; // Resolve dependencies @@ -348,7 +350,8 @@ NonlinearSystemBase::computeKokkosJacobian(const std::set & tags) needed_fe_var_vector_tags); } - // Copy vectors and cache variable values at element quadature points + // Copy solution vectors, initialize matrices, and cache variable values at element quadature + // points for (auto & system : systems) { @@ -384,16 +387,16 @@ NonlinearSystemBase::computeKokkosJacobian(const std::set & tags) // Compute kernels - for (auto kernel : kernels.getActiveObjects()) + for (auto & kernel : kernels.getActiveObjects()) kernel->computeJacobian(); - for (auto nodal_kernel : nodal_kernels.getActiveObjects()) + for (auto & nodal_kernel : nodal_kernels.getActiveObjects()) nodal_kernel->computeJacobian(); - for (auto ibc : integrated_bcs.getActiveObjects()) + for (auto & ibc : integrated_bcs.getActiveObjects()) ibc->computeJacobian(); - for (auto nbc : nodal_bcs.getActiveObjects()) + for (auto & nbc : nodal_bcs.getActiveObjects()) nbc->computeJacobian(); } @@ -423,8 +426,8 @@ NonlinearSystemBase::computeKokkosResidualAndJacobian(const std::set & ve { TIME_SECTION("computeKokkosResidualAndJacobian", 1); - if (!_kokkos_kernels.size() && !_kokkos_nodal_kernels.size() && !_kokkos_integrated_bcs.size() && - !_kokkos_nodal_bcs.size()) + if (!_kokkos_kernels.hasActiveObjects() && !_kokkos_nodal_kernels.hasActiveObjects() && + !_kokkos_integrated_bcs.hasActiveObjects() && !_kokkos_nodal_bcs.hasActiveObjects()) return; // Resolve dependencies @@ -462,7 +465,8 @@ NonlinearSystemBase::computeKokkosResidualAndJacobian(const std::set & ve needed_fe_var_vector_tags); } - // Copy vectors and cache variable values at element quadature points + // Copy solution vectors and residuals, initialize matrices, and cache variable values at element + // quadature points for (auto & system : systems) { @@ -498,17 +502,17 @@ NonlinearSystemBase::computeKokkosResidualAndJacobian(const std::set & ve // Compute kernels - for (auto kernel : _kokkos_kernels.getActiveObjects()) + for (auto & kernel : _kokkos_kernels.getActiveObjects()) kernel->computeResidualAndJacobian(); - for (auto nodal_kernel : _kokkos_nodal_kernels.getActiveObjects()) + for (auto & nodal_kernel : _kokkos_nodal_kernels.getActiveObjects()) nodal_kernel->computeResidualAndJacobian(); - for (auto ibc : _kokkos_integrated_bcs.getActiveObjects()) + for (auto & ibc : _kokkos_integrated_bcs.getActiveObjects()) ibc->computeResidualAndJacobian(); /// Nodal BC residuals are computed separately - for (auto nbc : _kokkos_nodal_bcs.getActiveObjects()) + for (auto & nbc : _kokkos_nodal_bcs.getActiveObjects()) nbc->computeJacobian(); } diff --git a/framework/src/systems/NonlinearSystemBase.C b/framework/src/systems/NonlinearSystemBase.C index 2ae8e3a99ce0..ba1b52e3d11e 100644 --- a/framework/src/systems/NonlinearSystemBase.C +++ b/framework/src/systems/NonlinearSystemBase.C @@ -875,7 +875,7 @@ NonlinearSystemBase::computeResidualTags(const std::set & tags) // We don't want to do nodal bcs or anything else return; - computeNodalBCs(tags); + computeNodalBCsResidual(tags); closeTaggedVectors(tags); // If we are debugging residuals we need one more assignment to have the ghosted copy up to @@ -2090,7 +2090,7 @@ NonlinearSystemBase::computeResidualAndJacobianInternal(const std::set & } void -NonlinearSystemBase::computeNodalBCs(NumericVector & residual) +NonlinearSystemBase::computeNodalBCsResidual(NumericVector & residual) { _nl_vector_tags.clear(); @@ -2099,26 +2099,27 @@ NonlinearSystemBase::computeNodalBCs(NumericVector & residual) _nl_vector_tags.insert(residual_vector_tag._id); associateVectorToTag(residual, residualVectorTag()); - computeNodalBCs(residual, _nl_vector_tags); + computeNodalBCsResidual(residual, _nl_vector_tags); disassociateVectorFromTag(residual, residualVectorTag()); } void -NonlinearSystemBase::computeNodalBCs(NumericVector & residual, const std::set & tags) +NonlinearSystemBase::computeNodalBCsResidual(NumericVector & residual, + const std::set & tags) { associateVectorToTag(residual, residualVectorTag()); - computeNodalBCs(tags); + computeNodalBCsResidual(tags); disassociateVectorFromTag(residual, residualVectorTag()); } void -NonlinearSystemBase::computeNodalBCs(const std::set & tags) +NonlinearSystemBase::computeNodalBCsResidual(const std::set & tags) { #ifdef MOOSE_KOKKOS_ENABLED if (_fe_problem.hasKokkosResidualObjects()) - computeKokkosNodalBCs(tags); + computeKokkosNodalBCsResidual(tags); #endif // We need to close the diag_save_in variables on the aux system before NodalBCBases clear the @@ -2137,7 +2138,7 @@ NonlinearSystemBase::computeNodalBCs(const std::set & tags) nbc_warehouse = &(_nodal_bcs.getVectorTagsObjectWarehouse(tags, 0)); // Return early if there is no nodal kernel - if (!nbc_warehouse->size()) + if (!nbc_warehouse->hasActiveObjects()) return; PARALLEL_TRY @@ -2174,17 +2175,138 @@ NonlinearSystemBase::computeNodalBCs(const std::set & tags) _Re_non_time->close(); } +void +NonlinearSystemBase::computeNodalBCsJacobian(const std::set & tags) +{ + // We need to close the save_in variables on the aux system before NodalBCBases clear the dofs + // on boundary nodes + if (_has_diag_save_in) + _fe_problem.getAuxiliarySystem().solution().close(); + + MooseObjectWarehouse * nbc_warehouse; + + // Select nodal kernels + if (tags.size() == _fe_problem.numMatrixTags() || !tags.size()) + nbc_warehouse = &_nodal_bcs; + else if (tags.size() == 1) + nbc_warehouse = &(_nodal_bcs.getMatrixTagObjectWarehouse(*(tags.begin()), 0)); + else + nbc_warehouse = &(_nodal_bcs.getMatrixTagsObjectWarehouse(tags, 0)); + + // Return early if there is no nodal kernel + if (!nbc_warehouse->hasActiveObjects()) + return; + + PARALLEL_TRY + { + // We may be switching from add to set. Moreover, we rely on a call to MatZeroRows to enforce + // the nodal boundary condition constraints which requires that the matrix be truly assembled + // as opposed to just flushed. Consequently we can't do the following despite any desire to + // keep our initial sparsity pattern honored (see https://gitlab.com/petsc/petsc/-/issues/852) + // + // flushTaggedMatrices(tags); + closeTaggedMatrices(tags); + + // Cache the information about which BCs are coupled to which + // variables, so we don't have to figure it out for each node. + std::map> bc_involved_vars; + const std::set & all_boundary_ids = _mesh.getBoundaryIDs(); + for (const auto & bid : all_boundary_ids) + { + // Get reference to all the NodalBCs for this ID. This is only + // safe if there are NodalBCBases there to be gotten... + if (nbc_warehouse->hasActiveBoundaryObjects(bid)) + { + const auto & bcs = nbc_warehouse->getActiveBoundaryObjects(bid); + for (const auto & bc : bcs) + { + const std::vector & coupled_moose_vars = bc->getCoupledMooseVars(); + + // Create the set of "involved" MOOSE nonlinear vars, which includes all coupled vars + // and the BC's own variable + std::set & var_set = bc_involved_vars[bc->name()]; + for (const auto & coupled_var : coupled_moose_vars) + if (coupled_var->kind() == Moose::VAR_SOLVER) + var_set.insert(coupled_var->number()); + + var_set.insert(bc->variable().number()); + } + } + } + + // reinit scalar variables again. This reinit does not re-fill any of the scalar variable + // solution arrays because that was done above. It only will reorder the derivative + // information for AD calculations to be suitable for NodalBC calculations + for (unsigned int tid = 0; tid < libMesh::n_threads(); tid++) + _fe_problem.reinitScalars(tid, true); + + // Get variable coupling list. We do all the NodalBCBase stuff on + // thread 0... The couplingEntries() data structure determines + // which variables are "coupled" as far as the preconditioner is + // concerned, not what variables a boundary condition specifically + // depends on. + auto & coupling_entries = _fe_problem.couplingEntries(/*_tid=*/0, this->number()); + + // Compute Jacobians for NodalBCBases + const ConstBndNodeRange & bnd_nodes = _fe_problem.getCurrentAlgebraicBndNodeRange(); + for (const auto & bnode : bnd_nodes) + { + BoundaryID boundary_id = bnode->_bnd_id; + Node * node = bnode->_node; + + if (nbc_warehouse->hasActiveBoundaryObjects(boundary_id) && + node->processor_id() == processor_id()) + { + _fe_problem.reinitNodeFace(node, boundary_id, 0); + + const auto & bcs = nbc_warehouse->getActiveBoundaryObjects(boundary_id); + for (const auto & bc : bcs) + { + // Get the set of involved MOOSE vars for this BC + std::set & var_set = bc_involved_vars[bc->name()]; + + // Loop over all the variables whose Jacobian blocks are + // actually being computed, call computeOffDiagJacobian() + // for each one which is actually coupled (otherwise the + // value is zero.) + for (const auto & it : coupling_entries) + { + unsigned int ivar = it.first->number(), jvar = it.second->number(); + + // We are only going to call computeOffDiagJacobian() if: + // 1.) the BC's variable is ivar + // 2.) jvar is "involved" with the BC (including jvar==ivar), and + // 3.) the BC should apply. + if ((bc->variable().number() == ivar) && var_set.count(jvar) && bc->shouldApply()) + bc->computeOffDiagJacobian(jvar); + } + + const auto & coupled_scalar_vars = bc->getCoupledMooseScalarVars(); + for (const auto & jvariable : coupled_scalar_vars) + if (hasScalarVariable(jvariable->name())) + bc->computeOffDiagJacobianScalar(jvariable->number()); + } + } + } // end loop over boundary nodes + + // Set the cached NodalBCBase values in the Jacobian matrix + _fe_problem.assembly(0, number()).setCachedJacobian(Assembly::GlobalDataKey{}); + } + PARALLEL_CATCH; +} + void NonlinearSystemBase::computeNodalBCsResidualAndJacobian( - [[maybe_unused]] const std::set & vector_tags, const std::set &) + [[maybe_unused]] const std::set & vector_tags, + [[maybe_unused]] const std::set & matrix_tags) { #ifdef MOOSE_KOKKOS_ENABLED if (_fe_problem.hasKokkosResidualObjects()) - computeKokkosNodalBCs(vector_tags); + computeKokkosNodalBCsResidual(vector_tags); #endif // Return early if there is no nodal kernel - if (!_nodal_bcs.size()) + if (!_nodal_bcs.hasActiveObjects()) return; PARALLEL_TRY @@ -3110,121 +3232,7 @@ NonlinearSystemBase::computeJacobianInternal(const std::set & tags) } PARALLEL_CATCH; - // We need to close the save_in variables on the aux system before NodalBCBases clear the dofs - // on boundary nodes - if (_has_diag_save_in) - _fe_problem.getAuxiliarySystem().solution().close(); - - PARALLEL_TRY - { - MooseObjectWarehouse * nbc_warehouse; - // Select nodal kernels - if (tags.size() == _fe_problem.numMatrixTags() || !tags.size()) - nbc_warehouse = &_nodal_bcs; - else if (tags.size() == 1) - nbc_warehouse = &(_nodal_bcs.getMatrixTagObjectWarehouse(*(tags.begin()), 0)); - else - nbc_warehouse = &(_nodal_bcs.getMatrixTagsObjectWarehouse(tags, 0)); - - if (nbc_warehouse->hasActiveObjects()) - { - // We may be switching from add to set. Moreover, we rely on a call to MatZeroRows to enforce - // the nodal boundary condition constraints which requires that the matrix be truly assembled - // as opposed to just flushed. Consequently we can't do the following despite any desire to - // keep our initial sparsity pattern honored (see https://gitlab.com/petsc/petsc/-/issues/852) - // - // flushTaggedMatrices(tags); - closeTaggedMatrices(tags); - - // Cache the information about which BCs are coupled to which - // variables, so we don't have to figure it out for each node. - std::map> bc_involved_vars; - const std::set & all_boundary_ids = _mesh.getBoundaryIDs(); - for (const auto & bid : all_boundary_ids) - { - // Get reference to all the NodalBCs for this ID. This is only - // safe if there are NodalBCBases there to be gotten... - if (nbc_warehouse->hasActiveBoundaryObjects(bid)) - { - const auto & bcs = nbc_warehouse->getActiveBoundaryObjects(bid); - for (const auto & bc : bcs) - { - const std::vector & coupled_moose_vars = - bc->getCoupledMooseVars(); - - // Create the set of "involved" MOOSE nonlinear vars, which includes all coupled vars - // and the BC's own variable - std::set & var_set = bc_involved_vars[bc->name()]; - for (const auto & coupled_var : coupled_moose_vars) - if (coupled_var->kind() == Moose::VAR_SOLVER) - var_set.insert(coupled_var->number()); - - var_set.insert(bc->variable().number()); - } - } - } - - // reinit scalar variables again. This reinit does not re-fill any of the scalar variable - // solution arrays because that was done above. It only will reorder the derivative - // information for AD calculations to be suitable for NodalBC calculations - for (unsigned int tid = 0; tid < libMesh::n_threads(); tid++) - _fe_problem.reinitScalars(tid, true); - - // Get variable coupling list. We do all the NodalBCBase stuff on - // thread 0... The couplingEntries() data structure determines - // which variables are "coupled" as far as the preconditioner is - // concerned, not what variables a boundary condition specifically - // depends on. - auto & coupling_entries = _fe_problem.couplingEntries(/*_tid=*/0, this->number()); - - // Compute Jacobians for NodalBCBases - const ConstBndNodeRange & bnd_nodes = _fe_problem.getCurrentAlgebraicBndNodeRange(); - for (const auto & bnode : bnd_nodes) - { - BoundaryID boundary_id = bnode->_bnd_id; - Node * node = bnode->_node; - - if (nbc_warehouse->hasActiveBoundaryObjects(boundary_id) && - node->processor_id() == processor_id()) - { - _fe_problem.reinitNodeFace(node, boundary_id, 0); - - const auto & bcs = nbc_warehouse->getActiveBoundaryObjects(boundary_id); - for (const auto & bc : bcs) - { - // Get the set of involved MOOSE vars for this BC - std::set & var_set = bc_involved_vars[bc->name()]; - - // Loop over all the variables whose Jacobian blocks are - // actually being computed, call computeOffDiagJacobian() - // for each one which is actually coupled (otherwise the - // value is zero.) - for (const auto & it : coupling_entries) - { - unsigned int ivar = it.first->number(), jvar = it.second->number(); - - // We are only going to call computeOffDiagJacobian() if: - // 1.) the BC's variable is ivar - // 2.) jvar is "involved" with the BC (including jvar==ivar), and - // 3.) the BC should apply. - if ((bc->variable().number() == ivar) && var_set.count(jvar) && bc->shouldApply()) - bc->computeOffDiagJacobian(jvar); - } - - const auto & coupled_scalar_vars = bc->getCoupledMooseScalarVars(); - for (const auto & jvariable : coupled_scalar_vars) - if (hasScalarVariable(jvariable->name())) - bc->computeOffDiagJacobianScalar(jvariable->number()); - } - } - } // end loop over boundary nodes - - // Set the cached NodalBCBase values in the Jacobian matrix - _fe_problem.assembly(0, number()).setCachedJacobian(Assembly::GlobalDataKey{}); - } - } - PARALLEL_CATCH; - + computeNodalBCsJacobian(tags); closeTaggedMatrices(tags); // We need to close the save_in variables on the aux system before NodalBCBases clear the dofs