LCOV - code coverage report
Current view: top level - src/kokkos/systems - KokkosFESystem.K (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #33416 (b10b36) with base 9fbd27 Lines: 140 143 97.9 %
Date: 2026-07-23 16:15:30 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             : 
      21             : namespace Moose::Kokkos
      22             : {
      23             : 
      24        2988 : FESystem::FESystem(SystemBase & system)
      25        1630 :   : System(system), AssemblyHolder(system.feProblem().kokkosAssembly())
      26             : {
      27        2988 :   setupVariables();
      28        2988 :   setupDofs();
      29        2988 :   setupCoupling();
      30             : 
      31        2988 :   if (dynamic_cast<NonlinearSystemBase *>(&_system))
      32        2051 :     setupNodalBCDofs();
      33             : 
      34        2988 :   _qp_solutions.create(MAX_TAG);
      35        2988 :   _qp_solutions_grad.create(MAX_TAG);
      36        2988 : }
      37             : 
      38          49 : FESystem::FESystem(System & base, SystemBase & system)
      39          26 :   : System(base), AssemblyHolder(system.feProblem().kokkosAssembly())
      40             : {
      41          49 :   setupVariables();
      42          49 :   setupDofs();
      43             : 
      44          49 :   if (dynamic_cast<NonlinearSystemBase *>(&_system))
      45           2 :     setupNodalBCDofs();
      46             : 
      47          49 :   _qp_solutions.create(MAX_TAG);
      48          49 :   _qp_solutions_grad.create(MAX_TAG);
      49          49 : }
      50             : 
      51             : void
      52        3037 : FESystem::setupVariables()
      53             : {
      54        3037 :   auto & sys = _system.system();
      55             : 
      56        3037 :   _var_fe_types.create(_num_vars);
      57             : 
      58        7102 :   for (unsigned int var = 0; var < _num_vars; ++var)
      59        4065 :     _var_fe_types[var] = kokkosAssembly().getFETypeID(sys.variable_type(var));
      60             : 
      61        3037 :   _var_fe_types.copyToDevice();
      62        3037 : }
      63             : 
      64             : void
      65        2988 : FESystem::setupCoupling()
      66             : {
      67        2988 :   if (auto * const nl_system = dynamic_cast<NonlinearSystemBase *>(&_system))
      68             :   {
      69        2051 :     _coupling.create(_num_vars);
      70             : 
      71        2051 :     std::map<unsigned int, std::vector<unsigned int>> coupling;
      72             : 
      73        2051 :     auto & ce = _system.feProblem().couplingEntries(0, nl_system->number());
      74             : 
      75        5280 :     for (const auto & [ivar, jvar] : ce)
      76        3229 :       if (ivar->number() != jvar->number())
      77         718 :         coupling[ivar->number()].push_back(jvar->number());
      78             : 
      79        4566 :     for (const auto var : make_range(_num_vars))
      80        2515 :       _coupling[var] = coupling[var];
      81             : 
      82        2051 :     _coupling.copyToDevice();
      83        2051 :   }
      84        2988 : }
      85             : 
      86             : void
      87        3037 : FESystem::setupDofs()
      88             : {
      89        3037 :   auto & sys = _system.system();
      90             : 
      91        3037 :   auto num_nodes = kokkosMesh().getNumLocalNodes();
      92             : 
      93        3037 :   _local_node_dof_index.create(_num_vars);
      94             : 
      95        1381 :   auto * const solution =
      96        1656 :       libMesh::cast_ptr<PetscVector<Number> *>(sys.current_local_solution.get());
      97             : 
      98             : #ifdef MOOSE_ENABLE_KOKKOS_GPU
      99             :   // Kokkos array thinks OpenMP clause is device code when using OpenMP backend
     100        1381 : #pragma omp parallel for
     101             : #endif
     102        3858 :   for (unsigned int var = 0; var < _num_vars; ++var)
     103             :   {
     104        2202 :     std::vector<dof_id_type> dof_indices;
     105             : 
     106        2202 :     _local_node_dof_index[var].create(num_nodes);
     107        2202 :     _local_node_dof_index[var] = libMesh::DofObject::invalid_id;
     108             : 
     109      876993 :     for (const auto node : kokkosMesh().getLocalNodes())
     110      874791 :       if (node->processor_id() == _comm.rank())
     111             :       {
     112      867028 :         const auto id = kokkosMesh().getContiguousNodeID(node);
     113             : 
     114      867028 :         _dof_map.dof_indices(node, dof_indices, var);
     115             : 
     116      867028 :         if (dof_indices.size())
     117             :         {
     118      840061 :           for (unsigned int i = 1; i < dof_indices.size(); ++i)
     119           0 :             if (dof_indices[i] != dof_indices[i - 1] + 1)
     120           0 :               mooseError("Kokkos system error: a variable has multiple DOFs on a node, but the DOF "
     121             :                          "indices are discontiguous. This is not supported.");
     122             : 
     123      840061 :           _local_node_dof_index[var][id] = solution->map_global_to_local_index(dof_indices[0]);
     124             :         }
     125             :       }
     126        2202 :   }
     127             : 
     128        3037 :   _local_node_dof_index.copyToDeviceNested();
     129        3037 : }
     130             : 
     131             : void
     132        2053 : FESystem::setupNodalBCDofs()
     133             : {
     134        2053 :   auto & nl_system = static_cast<NonlinearSystemBase &>(_system);
     135             : 
     136        2053 :   _nbc_matrix_tag_dof.create(MAX_TAG);
     137             : 
     138        5492 :   for (auto bc : nl_system.getKokkosNodalBCWarehouse().getActiveObjects())
     139             :   {
     140        3439 :     auto nbc = static_cast<NodalBCBase *>(bc.get());
     141             : 
     142        3439 :     auto matrix_tags = nbc->getMatrixTags({});
     143             : 
     144       10504 :     for (auto tag : matrix_tags)
     145        7065 :       getNodalBCDofs(nbc, _nbc_matrix_tag_dof[tag]);
     146        3439 :   }
     147             : 
     148        2053 :   _nbc_matrix_tag_dof.copyToDeviceNested();
     149        2053 : }
     150             : 
     151             : void
     152        7065 : FESystem::getNodalBCDofs(const NodalBCBase * nbc, Array<bool> & dofs)
     153             : {
     154        7065 :   auto var = nbc->variable().number();
     155             : 
     156        7065 :   if (!dofs.isAlloc())
     157             :   {
     158        3770 :     dofs.create(_num_local_dofs + _num_ghost_dofs);
     159        3770 :     dofs = false;
     160             :   }
     161             : 
     162       46293 :   for (auto node : nbc->getContiguousNodes())
     163       46293 :     dofs[_local_node_dof_index[var][node]] = true;
     164             : 
     165             :   // Let remote processes know about ghost DOFs associated with nodal BCs not to contribute on them
     166             : 
     167        7065 :   auto num_procs = _comm.size();
     168             : 
     169       21195 :   std::vector<std::vector<char>> send(num_procs), recv(num_procs);
     170             : 
     171       17578 :   for (processor_id_type proc = 0; proc < num_procs; proc++)
     172       26029 :     for (auto dof : _local_comm_list[proc])
     173       15516 :       send[proc].push_back(dofs[dof]);
     174             : 
     175       17578 :   for (processor_id_type proc = 0; proc < num_procs; proc++)
     176       10513 :     _comm.scatter(send, recv[proc], proc);
     177             : 
     178       17578 :   for (processor_id_type proc = 0; proc < num_procs; proc++)
     179       26029 :     for (dof_id_type i = 0; i < _ghost_comm_list[proc].size(); ++i)
     180       15516 :       dofs[_ghost_comm_list[proc][i]] = recv[proc][i];
     181        7065 : }
     182             : 
     183             : void
     184      137101 : FESystem::reinit()
     185             : {
     186      467345 :   for (auto tag : _active_solution_tags)
     187             :   {
     188      330244 :     if (!_qp_solutions[tag].isAlloc())
     189        4673 :       _qp_solutions[tag].create(kokkosMesh().getNumSubdomains(), _num_vars);
     190             : 
     191      330244 :     if (!_qp_solutions_grad[tag].isAlloc())
     192        4673 :       _qp_solutions_grad[tag].create(kokkosMesh().getNumSubdomains(), _num_vars);
     193             : 
     194      675630 :     for (auto subdomain : _mesh.meshSubdomains())
     195             :     {
     196      345386 :       auto sid = kokkosMesh().getContiguousSubdomainID(subdomain);
     197             : 
     198      722351 :       for (auto var : _active_variables)
     199             :       {
     200      376965 :         if (!_var_subdomain_active(var, sid))
     201         626 :           continue;
     202             : 
     203      376339 :         if (!_qp_solutions[tag](sid, var).isAlloc())
     204        6586 :           _qp_solutions[tag](sid, var).createDevice(kokkosAssembly().getNumQps(sid));
     205             : 
     206      376339 :         if (!_qp_solutions_grad[tag](sid, var).isAlloc())
     207        6586 :           _qp_solutions_grad[tag](sid, var).createDevice(kokkosAssembly().getNumQps(sid));
     208             :       }
     209             :     }
     210             : 
     211      330244 :     _qp_solutions[tag].copyToDevice();
     212      330244 :     _qp_solutions_grad[tag].copyToDevice();
     213             :   }
     214             : 
     215      137101 :   _qp_solutions.copyToDevice();
     216      137101 :   _qp_solutions_grad.copyToDevice();
     217             : 
     218      137101 :   dof_id_type num_elems = kokkosMesh().getNumLocalElements();
     219             : 
     220      137101 :   _thread.resize(kokkosAssembly().getMaxQpsPerElem(),
     221             :                  num_elems,
     222             :                  _active_variables.size(),
     223             :                  _active_solution_tags.size());
     224             : 
     225      137101 :   ::Kokkos::RangePolicy<ExecSpace, ::Kokkos::IndexType<ThreadID>> policy(0, _thread.size());
     226      137101 :   ::Kokkos::parallel_for(policy, *this);
     227      137101 :   ::Kokkos::fence();
     228      137101 : }
     229             : 
     230             : KOKKOS_FUNCTION void
     231    67863764 : FESystem::operator()(const ThreadID tid) const
     232             : {
     233    67863764 :   auto qp = _thread(tid, 0);
     234    67863764 :   auto elem = _thread(tid, 1);
     235    67863764 :   auto var = _active_variables(_thread(tid, 2));
     236    67863764 :   auto tag = _active_solution_tags(_thread(tid, 3));
     237             : 
     238    67863764 :   auto info = kokkosMesh().getElementInfo(elem);
     239    67863764 :   auto sid = info.subdomain;
     240    67863764 :   auto elem_type = info.type;
     241             : 
     242    67863764 :   if (!_var_subdomain_active(var, sid))
     243        3872 :     return;
     244             : 
     245    67859892 :   auto fe_type = _var_fe_types[var];
     246    67859892 :   auto num_dofs = kokkosAssembly().getNumDofs(elem_type, fe_type);
     247    67859892 :   auto num_qps = kokkosAssembly().getNumQps(info);
     248    67859892 :   auto qp_offset = kokkosAssembly().getQpOffset(info);
     249             : 
     250    67859892 :   if (qp >= num_qps)
     251           0 :     return;
     252             : 
     253    67859892 :   auto & phi = kokkosAssembly().getPhi(sid, elem_type, fe_type);
     254    67859892 :   auto & grad_phi = kokkosAssembly().getGradPhi(sid, elem_type, fe_type);
     255    67859892 :   auto jacobian = kokkosAssembly().getJacobian(info, qp);
     256             : 
     257    67859892 :   Real value = 0;
     258    67859892 :   Real3 grad = 0;
     259             : 
     260   371507360 :   for (unsigned int i = 0; i < num_dofs; ++i)
     261             :   {
     262   303647468 :     auto vector = getVectorDofValue(getElemLocalDofIndex(elem, i, var), tag);
     263             : 
     264   303647468 :     value += vector * phi(i, qp);
     265   303647468 :     grad += vector * (jacobian * grad_phi(i, qp));
     266             :   }
     267             : 
     268    67859892 :   getVectorQpValue(info, qp_offset + qp, var, tag) = value;
     269    67859892 :   getVectorQpGrad(info, qp_offset + qp, var, tag) = grad;
     270             : }
     271             : 
     272             : } // namespace Moose::Kokkos

Generated by: LCOV version 1.14