LCOV - code coverage report
Current view: top level - src/kokkos/systems - KokkosFESystem.K (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 329044 Lines: 191 193 99.0 %
Date: 2026-08-03 21:12:22 Functions: 9 9 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://www.mooseframework.org
       3             : //*
       4             : //* All rights reserved, see COPYRIGHT for full restrictions
       5             : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
       6             : //*
       7             : //* Licensed under LGPL 2.1, please see LICENSE for details
       8             : //* https://www.gnu.org/licenses/lgpl-2.1.html
       9             : 
      10             : #include "KokkosFESystem.h"
      11             : #include "KokkosNodalBCBase.h"
      12             : 
      13             : #include "MooseMesh.h"
      14             : #include "Assembly.h"
      15             : #include "NonlinearSystemBase.h"
      16             : #include "LinearSystem.h"
      17             : #include "FEProblemBase.h"
      18             : 
      19             : #include "libmesh/system.h"
      20             : #include "libmesh/fe_interface.h"
      21             : 
      22             : namespace Moose::Kokkos
      23             : {
      24             : 
      25        3150 : FESystem::FESystem(SystemBase & system)
      26        1714 :   : System(system), AssemblyHolder(system.feProblem().kokkosAssembly())
      27             : {
      28        3150 :   setupVariables();
      29        3150 :   setupDofs();
      30        3150 :   setupCoupling();
      31             : 
      32        3150 :   if (dynamic_cast<NonlinearSystemBase *>(&_system))
      33        2213 :     setupNodalBCDofs();
      34             : 
      35        3150 :   _qp_solutions.create(MAX_TAG);
      36        3150 :   _qp_solutions_grad.create(MAX_TAG);
      37        3150 :   _qp_vector_solutions.create(MAX_TAG);
      38        3150 :   _qp_vector_solutions_grad.create(MAX_TAG);
      39        3150 :   _qp_vector_solutions_curl.create(MAX_TAG);
      40        3150 : }
      41             : 
      42          49 : FESystem::FESystem(System & base, SystemBase & system)
      43          26 :   : System(base), AssemblyHolder(system.feProblem().kokkosAssembly())
      44             : {
      45          49 :   setupVariables();
      46          49 :   setupDofs();
      47             : 
      48          49 :   if (dynamic_cast<NonlinearSystemBase *>(&_system))
      49           2 :     setupNodalBCDofs();
      50             : 
      51          49 :   _qp_solutions.create(MAX_TAG);
      52          49 :   _qp_solutions_grad.create(MAX_TAG);
      53          49 :   _qp_vector_solutions.create(MAX_TAG);
      54          49 :   _qp_vector_solutions_grad.create(MAX_TAG);
      55          49 :   _qp_vector_solutions_curl.create(MAX_TAG);
      56          49 : }
      57             : 
      58             : void
      59        3199 : FESystem::setupVariables()
      60             : {
      61        3199 :   auto & sys = _system.system();
      62             : 
      63        3199 :   _var_fe_types.create(_num_vars);
      64        3199 :   _var_is_vector.create(_num_vars);
      65             : 
      66        7523 :   for (unsigned int var = 0; var < _num_vars; ++var)
      67             :   {
      68        4324 :     const auto fe_type = sys.variable_type(var);
      69             : 
      70        4324 :     _var_fe_types[var] = kokkosAssembly().getFETypeID(fe_type);
      71        4324 :     _var_is_vector[var] = FEInterface::field_type(fe_type) == libMesh::TYPE_VECTOR;
      72             :   }
      73             : 
      74        3199 :   _var_fe_types.copyToDevice();
      75        3199 :   _var_is_vector.copyToDevice();
      76        3199 : }
      77             : 
      78             : void
      79        3150 : FESystem::setupCoupling()
      80             : {
      81        3150 :   if (auto * const nl_system = dynamic_cast<NonlinearSystemBase *>(&_system))
      82             :   {
      83        2213 :     _coupling.create(_num_vars);
      84             : 
      85        2213 :     std::map<unsigned int, std::vector<unsigned int>> coupling;
      86             : 
      87        2213 :     auto & ce = _system.feProblem().couplingEntries(0, nl_system->number());
      88             : 
      89        6099 :     for (const auto & [ivar, jvar] : ce)
      90        3886 :       if (ivar->number() != jvar->number())
      91        1116 :         coupling[ivar->number()].push_back(jvar->number());
      92             : 
      93        4987 :     for (const auto var : make_range(_num_vars))
      94        2774 :       _coupling[var] = coupling[var];
      95             : 
      96        2213 :     _coupling.copyToDevice();
      97        2213 :   }
      98        3150 : }
      99             : 
     100             : void
     101        3199 : FESystem::setupDofs()
     102             : {
     103        3199 :   auto & sys = _system.system();
     104             : 
     105        3199 :   auto num_nodes = kokkosMesh().getNumLocalNodes();
     106             : 
     107        3199 :   _local_node_dof_index.create(_num_vars);
     108             : 
     109        1459 :   auto * const solution =
     110        1740 :       libMesh::cast_ptr<PetscVector<Number> *>(sys.current_local_solution.get());
     111             : 
     112             : #ifdef MOOSE_ENABLE_KOKKOS_GPU
     113             :   // Kokkos array thinks OpenMP clause is device code when using OpenMP backend
     114        1459 : #pragma omp parallel for
     115             : #endif
     116        4077 :   for (unsigned int var = 0; var < _num_vars; ++var)
     117             :   {
     118        2337 :     std::vector<dof_id_type> dof_indices;
     119             : 
     120        2337 :     _local_node_dof_index[var].create(num_nodes);
     121        2337 :     _local_node_dof_index[var] = libMesh::DofObject::invalid_id;
     122             : 
     123      914767 :     for (const auto node : kokkosMesh().getLocalNodes())
     124      912430 :       if (node->processor_id() == _comm.rank())
     125             :       {
     126      904183 :         const auto id = kokkosMesh().getContiguousNodeID(node);
     127             : 
     128      904183 :         _dof_map.dof_indices(node, dof_indices, var);
     129             : 
     130      904183 :         if (dof_indices.size())
     131             :         {
     132      873981 :           for (unsigned int i = 1; i < dof_indices.size(); ++i)
     133       14165 :             if (dof_indices[i] != dof_indices[i - 1] + 1)
     134           0 :               mooseError("Kokkos system error: a variable has multiple DOFs on a node, but the DOF "
     135             :                          "indices are discontiguous. This is not supported.");
     136             : 
     137      859816 :           _local_node_dof_index[var][id] = solution->map_global_to_local_index(dof_indices[0]);
     138             :         }
     139             :       }
     140        2337 :   }
     141             : 
     142        3199 :   _local_node_dof_index.copyToDeviceNested();
     143        3199 : }
     144             : 
     145             : void
     146        2215 : FESystem::setupNodalBCDofs()
     147             : {
     148        2215 :   auto & nl_system = static_cast<NonlinearSystemBase &>(_system);
     149             : 
     150        2215 :   _nbc_matrix_tag_dof.create(MAX_TAG);
     151             : 
     152        5952 :   for (auto bc : nl_system.getKokkosNodalBCWarehouse().getActiveObjects())
     153             :   {
     154        3737 :     auto nbc = static_cast<NodalBCBase *>(bc.get());
     155             : 
     156        3737 :     auto matrix_tags = nbc->getMatrixTags({});
     157             : 
     158       11398 :     for (auto tag : matrix_tags)
     159        7661 :       getNodalBCDofs(nbc, _nbc_matrix_tag_dof[tag]);
     160        3737 :   }
     161             : 
     162        2215 :   _nbc_matrix_tag_dof.copyToDeviceNested();
     163        2215 : }
     164             : 
     165             : void
     166        7661 : FESystem::getNodalBCDofs(const NodalBCBase * nbc, Array<bool> & dofs)
     167             : {
     168        7661 :   auto var = nbc->variable().number();
     169        7661 :   auto num_dofs = _var_is_vector[var] ? kokkosAssembly().getDimension() : 1;
     170             : 
     171        7661 :   if (!dofs.isAlloc())
     172             :   {
     173        4012 :     dofs.create(_num_local_dofs + _num_ghost_dofs);
     174        4012 :     dofs = false;
     175             :   }
     176             : 
     177       58087 :   for (auto node : nbc->getContiguousNodes())
     178             :   {
     179       50426 :     auto dof = _local_node_dof_index[var][node];
     180             : 
     181       50426 :     if (dof != libMesh::DofObject::invalid_id)
     182      102204 :       for (const auto i : make_range(num_dofs))
     183       53858 :         dofs[dof + i] = true;
     184        7661 :   }
     185             : 
     186             :   // Let remote processes know about ghost DOFs associated with nodal BCs not to contribute on them
     187             : 
     188        7661 :   auto num_procs = _comm.size();
     189             : 
     190       22983 :   std::vector<std::vector<char>> send(num_procs), recv(num_procs);
     191             : 
     192       19074 :   for (processor_id_type proc = 0; proc < num_procs; proc++)
     193       36421 :     for (auto dof : _local_comm_list[proc])
     194       25008 :       send[proc].push_back(dofs[dof]);
     195             : 
     196       19074 :   for (processor_id_type proc = 0; proc < num_procs; proc++)
     197       11413 :     _comm.scatter(send, recv[proc], proc);
     198             : 
     199       19074 :   for (processor_id_type proc = 0; proc < num_procs; proc++)
     200       36421 :     for (dof_id_type i = 0; i < _ghost_comm_list[proc].size(); ++i)
     201       25008 :       dofs[_ghost_comm_list[proc][i]] = recv[proc][i];
     202        7661 : }
     203             : 
     204             : void
     205      144746 : FESystem::reinit()
     206             : {
     207      494167 :   for (auto tag : _active_solution_tags)
     208             :   {
     209      349421 :     if (!_qp_solutions[tag].isAlloc())
     210        4936 :       _qp_solutions[tag].create(kokkosMesh().getNumSubdomains(), _num_vars);
     211             : 
     212      349421 :     if (!_qp_solutions_grad[tag].isAlloc())
     213        4936 :       _qp_solutions_grad[tag].create(kokkosMesh().getNumSubdomains(), _num_vars);
     214             : 
     215      349421 :     if (!_qp_vector_solutions[tag].isAlloc())
     216        4936 :       _qp_vector_solutions[tag].create(kokkosMesh().getNumSubdomains(), _num_vars);
     217             : 
     218      349421 :     if (!_qp_vector_solutions_grad[tag].isAlloc())
     219        4936 :       _qp_vector_solutions_grad[tag].create(kokkosMesh().getNumSubdomains(), _num_vars);
     220             : 
     221      349421 :     if (!_qp_vector_solutions_curl[tag].isAlloc())
     222        4936 :       _qp_vector_solutions_curl[tag].create(kokkosMesh().getNumSubdomains(), _num_vars);
     223             : 
     224      730233 :     for (auto subdomain : _mesh.meshSubdomains())
     225             :     {
     226      380812 :       auto sid = kokkosMesh().getContiguousSubdomainID(subdomain);
     227             : 
     228      797223 :       for (auto var : _active_variables)
     229             :       {
     230      416411 :         if (!_var_subdomain_active(var, sid))
     231         626 :           continue;
     232             : 
     233      415785 :         if (_var_is_vector[var])
     234             :         {
     235       37930 :           if (!_qp_vector_solutions[tag](sid, var).isAlloc())
     236         515 :             _qp_vector_solutions[tag](sid, var).createDevice(kokkosAssembly().getNumQps(sid));
     237             : 
     238       37930 :           if (!_qp_vector_solutions_grad[tag](sid, var).isAlloc())
     239         515 :             _qp_vector_solutions_grad[tag](sid, var).createDevice(kokkosAssembly().getNumQps(sid));
     240             : 
     241       37930 :           if (!_qp_vector_solutions_curl[tag](sid, var).isAlloc())
     242         515 :             _qp_vector_solutions_curl[tag](sid, var).createDevice(kokkosAssembly().getNumQps(sid));
     243             :         }
     244             :         else
     245             :         {
     246      377855 :           if (!_qp_solutions[tag](sid, var).isAlloc())
     247        6720 :             _qp_solutions[tag](sid, var).createDevice(kokkosAssembly().getNumQps(sid));
     248             : 
     249      377855 :           if (!_qp_solutions_grad[tag](sid, var).isAlloc())
     250        6720 :             _qp_solutions_grad[tag](sid, var).createDevice(kokkosAssembly().getNumQps(sid));
     251             :         }
     252             :       }
     253             :     }
     254             : 
     255      349421 :     _qp_solutions[tag].copyToDevice();
     256      349421 :     _qp_solutions_grad[tag].copyToDevice();
     257      349421 :     _qp_vector_solutions[tag].copyToDevice();
     258      349421 :     _qp_vector_solutions_grad[tag].copyToDevice();
     259      349421 :     _qp_vector_solutions_curl[tag].copyToDevice();
     260             :   }
     261             : 
     262      144746 :   _qp_solutions.copyToDevice();
     263      144746 :   _qp_solutions_grad.copyToDevice();
     264      144746 :   _qp_vector_solutions.copyToDevice();
     265      144746 :   _qp_vector_solutions_grad.copyToDevice();
     266      144746 :   _qp_vector_solutions_curl.copyToDevice();
     267             : 
     268      144746 :   dof_id_type num_elems = kokkosMesh().getNumLocalElements();
     269             : 
     270      144746 :   _thread.resize(kokkosAssembly().getMaxQpsPerElem(),
     271             :                  num_elems,
     272             :                  _active_variables.size(),
     273             :                  _active_solution_tags.size());
     274             : 
     275      144746 :   ::Kokkos::RangePolicy<ExecSpace, ::Kokkos::IndexType<ThreadID>> policy(0, _thread.size());
     276      144746 :   ::Kokkos::parallel_for(policy, *this);
     277      144746 :   ::Kokkos::fence();
     278      144746 : }
     279             : 
     280             : KOKKOS_FUNCTION void
     281    70666403 : FESystem::operator()(const ThreadID tid) const
     282             : {
     283    70666403 :   auto qp = _thread(tid, 0);
     284    70666403 :   auto elem = _thread(tid, 1);
     285    70666403 :   auto var = _active_variables(_thread(tid, 2));
     286    70666403 :   auto tag = _active_solution_tags(_thread(tid, 3));
     287             : 
     288    70666403 :   auto info = kokkosMesh().getElementInfo(elem);
     289    70666403 :   auto sid = info.subdomain;
     290    70666403 :   auto elem_type = info.type;
     291             : 
     292    70666403 :   if (!_var_subdomain_active(var, sid))
     293        3872 :     return;
     294             : 
     295    70662531 :   auto fe_type = _var_fe_types[var];
     296    70662531 :   auto num_dofs = kokkosAssembly().getNumDofs(elem_type, fe_type);
     297    70662531 :   auto num_qps = kokkosAssembly().getNumQps(info);
     298    70662531 :   auto qp_offset = kokkosAssembly().getQpOffset(info);
     299             : 
     300    70662531 :   if (qp >= num_qps)
     301           0 :     return;
     302             : 
     303    70662531 :   if (_var_is_vector[var])
     304             :   {
     305     2516965 :     auto & phi = kokkosAssembly().getVectorPhi(sid, elem_type, fe_type);
     306     2516965 :     auto & grad_phi = kokkosAssembly().getVectorGradPhi(sid, elem_type, fe_type);
     307     2516965 :     auto jacobian = kokkosAssembly().getJacobian(info, qp).transpose();
     308             : 
     309     2516965 :     Real3 value = 0;
     310     2516965 :     Real33 grad = 0;
     311             : 
     312    30885525 :     for (unsigned int i = 0; i < num_dofs; ++i)
     313             :     {
     314    28368560 :       auto vector = getVectorDofValue(getElemLocalDofIndex(elem, i, var), tag);
     315             : 
     316    28368560 :       value += vector * phi(i, qp);
     317    28368560 :       grad += vector * grad_phi(i, qp);
     318             :     }
     319             : 
     320     2516965 :     grad = grad * jacobian;
     321             : 
     322     2516965 :     getVectorQpVectorValue(info, qp_offset + qp, var, tag) = value;
     323     2516965 :     getVectorQpVectorGrad(info, qp_offset + qp, var, tag) = grad;
     324     2516965 :     getVectorQpVectorCurl(info, qp_offset + qp, var, tag) =
     325     5033930 :         curlFromVectorGradient(grad, kokkosAssembly().getDimension());
     326             :   }
     327             :   else
     328             :   {
     329    68145566 :     auto & phi = kokkosAssembly().getPhi(sid, elem_type, fe_type);
     330    68145566 :     auto & grad_phi = kokkosAssembly().getGradPhi(sid, elem_type, fe_type);
     331    68145566 :     auto jacobian = kokkosAssembly().getJacobian(info, qp);
     332             : 
     333    68145566 :     Real value = 0;
     334    68145566 :     Real3 grad = 0;
     335             : 
     336   372949230 :     for (unsigned int i = 0; i < num_dofs; ++i)
     337             :     {
     338   304803664 :       auto vector = getVectorDofValue(getElemLocalDofIndex(elem, i, var), tag);
     339             : 
     340   304803664 :       value += vector * phi(i, qp);
     341   304803664 :       grad += vector * grad_phi(i, qp);
     342             :     }
     343             : 
     344    68145566 :     grad = jacobian * grad;
     345             : 
     346    68145566 :     getVectorQpValue(info, qp_offset + qp, var, tag) = value;
     347    68145566 :     getVectorQpGrad(info, qp_offset + qp, var, tag) = grad;
     348             :   }
     349             : }
     350             : 
     351             : } // namespace Moose::Kokkos

Generated by: LCOV version 1.14