LCOV - code coverage report
Current view: top level - src/kokkos/linearfvkernels - KokkosLinearFVFluxKernel.K (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #33416 (b10b36) with base 9fbd27 Lines: 104 119 87.4 %
Date: 2026-07-23 16:15:30 Functions: 6 6 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 "KokkosLinearFVFluxKernel.h"
      11             : #include "KokkosLinearFVBoundaryCondition.h"
      12             : #include "LinearFVBoundaryCondition.h"
      13             : 
      14             : #include "Attributes.h"
      15             : #include "FEProblemBase.h"
      16             : #include "MooseMesh.h"
      17             : 
      18             : #include <algorithm>
      19             : #include <map>
      20             : 
      21             : namespace Moose::Kokkos
      22             : {
      23             : 
      24             : InputParameters
      25        4710 : LinearFVFluxKernel::validParams()
      26             : {
      27        4710 :   auto params = LinearFVKernel::validParams();
      28        4710 :   params.registerSystemAttributeName("LinearFVFluxKernel");
      29        9420 :   params.addPrivateParam<bool>("_kokkos_flux_kernel", true);
      30        4710 :   return params;
      31           0 : }
      32             : 
      33         229 : LinearFVFluxKernel::LinearFVFluxKernel(const InputParameters & parameters)
      34         116 :   : LinearFVKernel(parameters)
      35             : {
      36         229 : }
      37             : 
      38        1689 : LinearFVFluxKernel::LinearFVFluxKernel(const LinearFVFluxKernel & object)
      39             :   : LinearFVKernel(object),
      40         867 :     _bc_data(object._bc_data),
      41         867 :     _bc_index(object._bc_index),
      42         867 :     _internal_face_ids(object._internal_face_ids),
      43        1734 :     _boundary_face_ids(object._boundary_face_ids)
      44             : {
      45        1689 : }
      46             : 
      47             : void
      48         229 : LinearFVFluxKernel::initialSetup()
      49             : {
      50         113 :   const auto n_elems =
      51         116 :       libMesh::cast_int<MOOSE_KOKKOS_INDEX_TYPE>(kokkosMesh().getNumLocalElements());
      52         113 :   const auto max_sides =
      53         116 :       libMesh::cast_int<MOOSE_KOKKOS_INDEX_TYPE>(_subproblem.mesh().getMaxSidesPerElem());
      54         229 :   _bc_index.create(max_sides, n_elems);
      55         229 :   _bc_index = -1;
      56             : 
      57             :   // Build a compact list of Kokkos linear FV BC data and attach each BC worklist's packed index to
      58             :   // the boundary faces where this kernel's variable is active.
      59         229 :   const auto sys_num = _var.sys();
      60         229 :   const auto var_num = _var.var();
      61         229 :   const auto var_name = _var.mooseVar()->name();
      62             : 
      63         229 :   std::vector<LinearFVBoundaryCondition *> bcs;
      64         229 :   _fe_problem.theWarehouse()
      65         116 :       .query()
      66         116 :       .template condition<AttribSysNum>(sys_num)
      67         116 :       .template condition<AttribSystem>("LinearFVBoundaryCondition")
      68         116 :       .template condition<AttribKokkos>(true)
      69         232 :       .template condition<AttribThread>(0)
      70         116 :       .queryInto(bcs);
      71             : 
      72         229 :   std::vector<LinearFVBoundaryCondition::BoundaryData> bc_data;
      73             : #ifdef DEBUG
      74             :   std::vector<LinearFVBoundaryCondition *> bc_objects;
      75             : #endif
      76         229 :   std::map<FaceID, BoundaryFaceID> bc_faces;
      77         229 :   auto & mesh = _subproblem.mesh();
      78         229 :   const auto * const kokkos_mesh = mesh.getKokkosMesh();
      79             : 
      80         704 :   for (auto * bc : bcs)
      81             :   {
      82         475 :     const auto & variable = bc->variable();
      83             : 
      84         475 :     if (variable.var() == var_num)
      85             :     {
      86         395 :       const auto bc_index = libMesh::cast_int<int>(bc_data.size());
      87         395 :       bc_data.push_back(bc->boundaryData());
      88             : #ifdef DEBUG
      89             :       bc_objects.push_back(bc);
      90             : #endif
      91             : 
      92        3419 :       for (const auto bc_face_index : make_range(bc->numBoundaryFaces()))
      93             :       {
      94        3024 :         const auto [contiguous_elem, side] = bc->boundaryFaceID(bc_face_index);
      95        3024 :         const FaceID face{contiguous_elem, side};
      96             : 
      97             : #ifdef DEBUG
      98             :         if (bc_face_index)
      99             :           mooseAssert(
     100             :               bc->boundaryFaceID(bc_face_index - 1) < face,
     101             :               "Kokkos linear FV boundary face worklists must be ordered by (element, side)");
     102             : #endif
     103             : 
     104        3024 :         auto & existing_index = _bc_index(side, contiguous_elem);
     105             : 
     106             :         // Ambiguous boundary data would make flux kernels non-deterministic.
     107        3024 :         if (existing_index != -1)
     108           0 :           mooseError("Kokkos linear FV flux kernel '",
     109           0 :                      name(),
     110             :                      "' found multiple Kokkos boundary conditions for variable '",
     111             :                      var_name,
     112             :                      "' on contiguous element ",
     113             :                      contiguous_elem,
     114             :                      ", side ",
     115             :                      side,
     116             :                      ".");
     117             : 
     118        3024 :         existing_index = bc_index;
     119        3024 :         bc_faces.emplace(face, BoundaryFaceID{contiguous_elem, side, bc_index, bc_face_index});
     120             :       }
     121             :     }
     122         475 :   }
     123             : 
     124         229 :   std::vector<FaceID> internal_face_ids;
     125         229 :   std::vector<BoundaryFaceID> boundary_face_ids;
     126             : 
     127         229 :   const auto * const variable = _var.mooseVar();
     128         458 :   for (const auto block : blockIDs())
     129       45007 :     for (const auto elem : mesh.getMesh().active_local_subdomain_elements_ptr_range(block))
     130             :     {
     131       22389 :       const auto contiguous_elem = kokkos_mesh->getContiguousElementID(elem);
     132             : 
     133      105535 :       for (const auto side : make_range(elem->n_sides()))
     134             :       {
     135       83146 :         const auto * const neighbor = elem->neighbor_ptr(side);
     136             : 
     137             :         mooseAssert(!neighbor || neighbor != libMesh::remote_elem,
     138             :                     "We should have properly ghosted side neighbors for FV");
     139       83146 :         if (neighbor && variable->activeOnSubdomain(neighbor->subdomain_id()))
     140       79042 :           internal_face_ids.push_back({contiguous_elem, side});
     141             :         else
     142             :         {
     143        4104 :           const auto bc_face = bc_faces.find({contiguous_elem, side});
     144             : 
     145        4104 :           if (bc_face != bc_faces.end())
     146        3024 :             boundary_face_ids.push_back(bc_face->second);
     147             :         }
     148             :       }
     149         229 :     }
     150             : 
     151         229 :   std::sort(internal_face_ids.begin(), internal_face_ids.end());
     152         229 :   std::sort(boundary_face_ids.begin(), boundary_face_ids.end());
     153             : 
     154             : #ifdef DEBUG
     155             :   for (const auto i : index_range(boundary_face_ids))
     156             :   {
     157             :     const auto & face = boundary_face_ids[i];
     158             :     mooseAssert(face.bc_index >= 0 &&
     159             :                     libMesh::cast_int<std::size_t>(face.bc_index) < bc_objects.size(),
     160             :                 "Boundary face has an invalid compact boundary condition index");
     161             :     mooseAssert(_bc_index(face.side, face.elem) == face.bc_index,
     162             :                 "Boundary face does not map to its expected compact boundary condition index");
     163             : 
     164             :     const auto * const bc = bc_objects[face.bc_index];
     165             :     mooseAssert(face.bc_face_index < bc->numBoundaryFaces(),
     166             :                 "Boundary face has an invalid BC-local packed index");
     167             :     const auto expected_face = bc->boundaryFaceID(face.bc_face_index);
     168             :     mooseAssert(expected_face.first == face.elem && expected_face.second == face.side,
     169             :                 "Boundary face does not map to its expected BC-local packed index");
     170             : 
     171             :     if (i && boundary_face_ids[i - 1].bc_index == face.bc_index)
     172             :       mooseAssert(boundary_face_ids[i - 1].bc_face_index < face.bc_face_index,
     173             :                   "Boundary faces and their BC-local packed indices have inconsistent ordering");
     174             :   }
     175             : #endif
     176             : 
     177         229 :   _internal_face_ids = internal_face_ids;
     178         229 :   _boundary_face_ids = boundary_face_ids;
     179             : 
     180             : #ifndef NDEBUG
     181             :   _bc_index.copyToDevice();
     182             : #endif
     183         229 :   _bc_data.create(libMesh::cast_int<MOOSE_KOKKOS_INDEX_TYPE>(bc_data.size()));
     184         624 :   for (const auto i : index_range(bc_data))
     185         395 :     _bc_data[i] = bc_data[i];
     186         229 :   _bc_data.copyToDevice();
     187             : 
     188             :   // Non-Kokkos BCs are never called by Kokkos flux kernels; they would be silently
     189             :   // ignored, producing wrong results. Reject them early for this variable.
     190         229 :   std::vector<::LinearFVBoundaryCondition *> non_kokkos_bcs;
     191         229 :   _fe_problem.theWarehouse()
     192         116 :       .query()
     193         116 :       .template condition<AttribSysNum>(sys_num)
     194         116 :       .template condition<AttribSystem>("LinearFVBoundaryCondition")
     195         116 :       .template condition<AttribKokkos>(false)
     196         232 :       .template condition<AttribThread>(0)
     197         116 :       .queryInto(non_kokkos_bcs);
     198             : 
     199         229 :   for (auto * bc : non_kokkos_bcs)
     200             :   {
     201           0 :     const auto & variable = bc->variable();
     202             : 
     203           0 :     if (variable.number() == var_num)
     204           0 :       mooseError("Kokkos linear FV flux kernel '",
     205           0 :                  name(),
     206             :                  "' found non-Kokkos boundary condition '",
     207           0 :                  bc->name(),
     208             :                  "' (type '",
     209           0 :                  bc->type(),
     210             :                  "') for variable '",
     211           0 :                  variable.name(),
     212             :                  "'. Non-Kokkos BCs are not called by Kokkos flux kernels and will produce "
     213             :                  "incorrect results. Use the Kokkos equivalent, e.g. "
     214             :                  "'KokkosLinearFVFunctorDirichletBC'.");
     215             :   }
     216         229 : }
     217             : 
     218             : void
     219         340 : LinearFVFluxKernel::computeRightHandSide()
     220             : {
     221         340 :   if (hasInternalRightHandSideContribution() && _internal_face_ids.size())
     222             :   {
     223           0 :     Policy policy(0, _internal_face_ids.size());
     224           0 :     if (!_internal_rhs_dispatcher)
     225           0 :       _internal_rhs_dispatcher = DispatcherRegistry::build<InternalRightHandSideLoop>(this, type());
     226           0 :     _internal_rhs_dispatcher->parallelFor(policy);
     227           0 :   }
     228             : 
     229         340 :   if (_boundary_face_ids.size())
     230             :   {
     231         340 :     Policy policy(0, _boundary_face_ids.size());
     232         340 :     if (!_boundary_rhs_dispatcher)
     233         223 :       _boundary_rhs_dispatcher = DispatcherRegistry::build<BoundaryRightHandSideLoop>(this, type());
     234         340 :     _boundary_rhs_dispatcher->parallelFor(policy);
     235         340 :   }
     236         340 : }
     237             : 
     238             : void
     239         340 : LinearFVFluxKernel::computeMatrix()
     240             : {
     241         340 :   if (DispatcherRegistry::hasUserMethod<InternalMatrixLoop>(type()) && _internal_face_ids.size())
     242             :   {
     243         340 :     Policy policy(0, _internal_face_ids.size());
     244         340 :     if (!_internal_matrix_dispatcher)
     245         223 :       _internal_matrix_dispatcher = DispatcherRegistry::build<InternalMatrixLoop>(this, type());
     246         340 :     _internal_matrix_dispatcher->parallelFor(policy);
     247         340 :   }
     248             : 
     249         340 :   if (DispatcherRegistry::hasUserMethod<BoundaryMatrixLoop>(type()) && _boundary_face_ids.size())
     250             :   {
     251         340 :     Policy policy(0, _boundary_face_ids.size());
     252         340 :     if (!_boundary_matrix_dispatcher)
     253         223 :       _boundary_matrix_dispatcher = DispatcherRegistry::build<BoundaryMatrixLoop>(this, type());
     254         340 :     _boundary_matrix_dispatcher->parallelFor(policy);
     255         340 :   }
     256         340 : }
     257             : 
     258             : } // namespace Moose::Kokkos

Generated by: LCOV version 1.14