LCOV - code coverage report
Current view: top level - include/kokkos/base - KokkosAssembly.h (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #31706 (f8ed4a) with base bb0a08 Lines: 95 102 93.1 %
Date: 2025-11-03 17:23:24 Functions: 22 24 91.7 %
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             : #pragma once
      11             : 
      12             : #include "KokkosTypes.h"
      13             : 
      14             : #include "MooseMesh.h"
      15             : 
      16             : #include "libmesh/elem_range.h"
      17             : #include "libmesh/fe_base.h"
      18             : #include "libmesh/fe_type.h"
      19             : 
      20             : class FEProblemBase;
      21             : 
      22             : namespace Moose
      23             : {
      24             : namespace Kokkos
      25             : {
      26             : 
      27             : /**
      28             :  * The Kokkos assembly class
      29             :  */
      30             : class Assembly : public MeshHolder
      31             : {
      32             : public:
      33             :   /**
      34             :    * Constructor
      35             :    * @param problem The MOOSE problem
      36             :    */
      37             :   Assembly(FEProblemBase & problem);
      38             :   /**
      39             :    * Initialize assembly
      40             :    */
      41             :   void init();
      42             : 
      43             : #ifdef MOOSE_KOKKOS_SCOPE
      44             :   /**
      45             :    * Get the FE type ID
      46             :    * @param type The libMesh FEType object
      47             :    * @returns The FE type ID
      48             :    */
      49        1424 :   unsigned int getFETypeID(FEType type) const { return libmesh_map_find(_fe_type_map, type); }
      50             :   /**
      51             :    * Get the mesh dimension
      52             :    * @returns The mesh dimension
      53             :    */
      54           0 :   KOKKOS_FUNCTION unsigned int getDimension() const { return _dimension; }
      55             :   /**
      56             :    * Get the maximum number of quadrature points per element in the current partition
      57             :    * @returns The maximum number of quadrature points per element
      58             :    */
      59       77394 :   KOKKOS_FUNCTION unsigned int getMaxQpsPerElem() const { return _max_qps_per_elem; }
      60             :   /**
      61             :    * Get the total number of elemental quadrature points in a subdomain
      62             :    * @param subdomain The contiguous subdomain ID
      63             :    * @returns The number of quadrature points
      64             :    */
      65        4959 :   KOKKOS_FUNCTION dof_id_type getNumQps(ContiguousSubdomainID subdomain) const
      66             :   {
      67        4959 :     return _n_subdomain_qps[subdomain];
      68             :   }
      69             :   /**
      70             :    * Get the number of quadrature points of an element
      71             :    * @param info The element information object
      72             :    * @returns The number of quadrature points
      73             :    */
      74    46944259 :   KOKKOS_FUNCTION unsigned int getNumQps(ElementInfo info) const { return _n_qps[info.id]; }
      75             :   /**
      76             :    * Get the total number of facial quadrature points in a subdomain
      77             :    * Note: this number does not represent the real number of facial quadrature points but only
      78             :    * counts the facial quadrature points that need global caching, such as face material properties
      79             :    * @param subdomain The contiguous subdomain ID
      80             :    * @returns The number of quadrature points
      81             :    */
      82        1169 :   KOKKOS_FUNCTION dof_id_type getNumFaceQps(ContiguousSubdomainID subdomain) const
      83             :   {
      84        1169 :     return _n_subdomain_qps_face[subdomain];
      85             :   }
      86             :   /**
      87             :    * Get the number of quadrature points of a side of an element
      88             :    * @param info The element information object
      89             :    * @param side The side index
      90             :    * @returns The number of quadrature points
      91             :    */
      92      121790 :   KOKKOS_FUNCTION unsigned int getNumFaceQps(ElementInfo info, unsigned int side) const
      93             :   {
      94      121790 :     return _n_qps_face(side, info.id);
      95             :   }
      96             :   /**
      97             :    * Get the starting offset of quadrature points of an element into the global quadrature point
      98             :    * index
      99             :    * @param info The element information object
     100             :    * @returns The starting offset
     101             :    */
     102   134970399 :   KOKKOS_FUNCTION dof_id_type getQpOffset(ElementInfo info) const { return _qp_offset[info.id]; }
     103             :   /**
     104             :    * Get the starting offset of quadrature points of a side of an element into the global quadrature
     105             :    * point index
     106             :    * @param info The element information object
     107             :    * @param side The side index
     108             :    * @returns The starting offset
     109             :    */
     110      121790 :   KOKKOS_FUNCTION dof_id_type getQpFaceOffset(ElementInfo info, unsigned int side) const
     111             :   {
     112      121790 :     return _qp_offset_face(side, info.id);
     113             :   }
     114             :   /**
     115             :    * Get the number of DOFs of a FE type for an element type
     116             :    * @param elem_type The element type ID
     117             :    * @param fe_type The FE type ID
     118             :    * @returns The number of DOFs
     119             :    */
     120    49264550 :   KOKKOS_FUNCTION unsigned int getNumDofs(unsigned int elem_type, unsigned int fe_type) const
     121             :   {
     122    49264550 :     return _n_dofs(elem_type, fe_type);
     123             :   }
     124             :   /**
     125             :    * Get the shape functions of a FE type for an element type and subdomain
     126             :    * @param subdomain The contiguous subdomain ID
     127             :    * @param elem_type The element type ID
     128             :    * @param fe_type The FE type ID
     129             :    * @returns The shape functions at quadrature points
     130             :    */
     131             :   KOKKOS_FUNCTION const auto &
     132   147323516 :   getPhi(ContiguousSubdomainID subdomain, unsigned int elem_type, unsigned int fe_type) const
     133             :   {
     134   147323516 :     return _phi(subdomain, elem_type, fe_type);
     135             :   }
     136             :   /**
     137             :    * Get the face shape functions of a FE type for an element type and subdomain
     138             :    * @param subdomain The contiguous subdomain ID
     139             :    * @param elem_type The element type ID
     140             :    * @param fe_type The FE type ID
     141             :    * @returns The shape functions of all sides at quadrature points
     142             :    */
     143             :   KOKKOS_FUNCTION const auto &
     144      666240 :   getPhiFace(ContiguousSubdomainID subdomain, unsigned int elem_type, unsigned int fe_type) const
     145             :   {
     146      666240 :     return _phi_face(subdomain, elem_type, fe_type);
     147             :   }
     148             :   /**
     149             :    * Get the gradient of shape functions of a FE type for an element type and subdomain
     150             :    * @param subdomain The contiguous subdomain ID
     151             :    * @param elem_type The element type ID
     152             :    * @param fe_type The FE type ID
     153             :    * @returns The gradient of shape functions at quadrature points
     154             :    */
     155             :   KOKKOS_FUNCTION const auto &
     156   102653020 :   getGradPhi(ContiguousSubdomainID subdomain, unsigned int elem_type, unsigned int fe_type) const
     157             :   {
     158   102653020 :     return _grad_phi(subdomain, elem_type, fe_type);
     159             :   }
     160             :   /**
     161             :    * Get the gradient of face shape functions of a FE type for an element type and subdomain
     162             :    * @param subdomain The contiguous subdomain ID
     163             :    * @param elem_type The element type ID
     164             :    * @param fe_type The FE type ID
     165             :    * @returns The gradient of shape functions of all sides at quadrature points
     166             :    */
     167           0 :   KOKKOS_FUNCTION const auto & getGradPhiFace(ContiguousSubdomainID subdomain,
     168             :                                               unsigned int elem_type,
     169             :                                               unsigned int fe_type) const
     170             :   {
     171           0 :     return _grad_phi_face(subdomain, elem_type, fe_type);
     172             :   }
     173             :   /**
     174             :    * Get the inverse of Jacobian matrix of an element quadrature point
     175             :    * @param info The element information object
     176             :    * @param qp The local quadrature point index
     177             :    * @returns The inverse of Jacobian matrix
     178             :    */
     179    57938676 :   KOKKOS_FUNCTION Real33 getJacobian(ElementInfo info, unsigned int qp) const
     180             :   {
     181    57938676 :     return _jacobian[info.subdomain][getQpOffset(info) + qp];
     182             :   }
     183             :   /**
     184             :    * Get the transformed Jacobian weight of an element quadrature point
     185             :    * @param info The element information object
     186             :    * @param qp The local quadrature point index
     187             :    * @returns The inverse of Jacobian matrix
     188             :    */
     189    15104840 :   KOKKOS_FUNCTION Real getJxW(ElementInfo info, unsigned int qp) const
     190             :   {
     191    15104840 :     return _jxw[info.subdomain][getQpOffset(info) + qp];
     192             :   }
     193             :   /**
     194             :    * Get the coordinate of an element quadrature point
     195             :    * @param info The element information object
     196             :    * @param qp The local quadrature point index
     197             :    * @returns The inverse of Jacobian matrix
     198             :    */
     199    15104840 :   KOKKOS_FUNCTION Real3 getQPoint(ElementInfo info, unsigned int qp) const
     200             :   {
     201    15104840 :     return _xyz[info.subdomain][getQpOffset(info) + qp];
     202             :   }
     203             : 
     204             :   /**
     205             :    * Get the coordinate transform factor for a point in a subdomain
     206             :    * @param subdomain The contiguous subdomain ID
     207             :    * @param point The point coordinate
     208             :    * @returns The coordinate transform factor
     209             :    */
     210             :   KOKKOS_FUNCTION Real coordTransformFactor(const ContiguousSubdomainID subdomain,
     211             :                                             const Real3 point) const;
     212             :   /**
     213             :    * Compute physical transformation data for an element
     214             :    * @param info The element information object
     215             :    * @param qp The local quadrature point index
     216             :    * @param jacobian The pointer to store the inverse of Jacobian matrix
     217             :    * @param JxW The pointer to store transformed Jacobian weight
     218             :    * @param q_points The pointer to store physical quadrature point coordinate
     219             :    */
     220             :   KOKKOS_FUNCTION void computePhysicalMap(const ElementInfo info,
     221             :                                           const unsigned int qp,
     222             :                                           Real33 * const jacobian,
     223             :                                           Real * const JxW,
     224             :                                           Real3 * const q_points) const;
     225             :   /**
     226             :    * Compute physical transformation data for a side
     227             :    * @param info The element information object
     228             :    * @param side The side index
     229             :    * @param qp The local quadrature point index
     230             :    * @param jacobian The pointer to store the inverse of Jacobian matrix
     231             :    * @param JxW The pointer to store transformed Jacobian weight
     232             :    * @param q_points The pointer to store physical quadrature point coordinate
     233             :    */
     234             :   KOKKOS_FUNCTION void computePhysicalMap(const ElementInfo info,
     235             :                                           const unsigned int side,
     236             :                                           const unsigned int qp,
     237             :                                           Real33 * const jacobian,
     238             :                                           Real * const JxW,
     239             :                                           Real3 * const q_points) const;
     240             : 
     241             :   /**
     242             :    * Kokkos function for caching physical maps on element quadrature points
     243             :    */
     244             :   KOKKOS_FUNCTION void operator()(const ThreadID tid) const;
     245             : 
     246             :   /**
     247             :    * Get the list of boundaries to cache face material properties
     248             :    * @returns The list of boundaries
     249             :    */
     250         563 :   const auto & getMaterialBoundaries() const { return _material_boundaries; }
     251             : #endif
     252             : 
     253             : private:
     254             :   /**
     255             :    * Initialize quadrature data
     256             :    */
     257             :   void initQuadrature();
     258             :   /**
     259             :    * Initialize shape data
     260             :    */
     261             :   void initShape();
     262             :   /**
     263             :    * Cache physical maps on element quadrature points
     264             :    */
     265             :   void cachePhysicalMap();
     266             : 
     267             :   /**
     268             :    * Reference of the MOOSE problem
     269             :    */
     270             :   FEProblemBase & _problem;
     271             :   /**
     272             :    * Reference of the MOOSE mesh
     273             :    */
     274             :   MooseMesh & _mesh;
     275             :   /**
     276             :    * FE type ID map
     277             :    */
     278             :   std::map<FEType, unsigned int> _fe_type_map;
     279             : 
     280             :   /**
     281             :    * Mesh dimension
     282             :    */
     283             :   const unsigned int _dimension;
     284             :   /**
     285             :    * Coordinate system type of each subdomain
     286             :    */
     287             :   Array<Moose::CoordinateSystemType> _coord_type;
     288             :   /**
     289             :    * Radial coordinate index in cylindrical coordinate system
     290             :    */
     291             :   unsigned int _rz_radial_coord = libMesh::invalid_uint;
     292             :   /**
     293             :    * General axisymmetric axis of each subdomain in cylindrical coordinate system
     294             :    */
     295             :   Array<Pair<Real3, Real3>> _rz_axis;
     296             : 
     297             :   /**
     298             :    * Starting offset into the global quadrature point index
     299             :    */
     300             :   ///@{
     301             :   Array<dof_id_type> _qp_offset;
     302             :   Array2D<dof_id_type> _qp_offset_face;
     303             :   ///@}
     304             :   /**
     305             :    * Number of quadrature points
     306             :    */
     307             :   ///@{
     308             :   Array<unsigned int> _n_qps;
     309             :   Array2D<unsigned int> _n_qps_face;
     310             : 
     311             :   unsigned int _max_qps_per_elem = 0;
     312             : 
     313             :   Array<dof_id_type> _n_subdomain_qps;
     314             :   Array<dof_id_type> _n_subdomain_qps_face;
     315             :   ///@}
     316             :   /**
     317             :    * Quadrature points and weights for reference elements
     318             :    */
     319             :   ///@{
     320             :   Array2D<Array<Real3>> _q_points;
     321             :   Array2D<Array<Array<Real3>>> _q_points_face;
     322             :   Array2D<Array<Real>> _weights;
     323             :   Array2D<Array<Array<Real>>> _weights_face;
     324             :   ///@}
     325             :   /**
     326             :    * Shape functions for reference elements
     327             :    */
     328             :   ///@{
     329             :   Array3D<Array2D<Real>> _phi;
     330             :   Array3D<Array<Array2D<Real>>> _phi_face;
     331             :   Array3D<Array2D<Real3>> _grad_phi;
     332             :   Array3D<Array<Array2D<Real3>>> _grad_phi_face;
     333             :   Array2D<unsigned int> _n_dofs;
     334             :   ///@}
     335             :   /**
     336             :    * Shape functions for computing reference-to-physical maps
     337             :    */
     338             :   ///@{
     339             :   Array2D<Array2D<Real>> _map_phi;
     340             :   Array2D<Array<Array2D<Real>>> _map_phi_face;
     341             :   Array2D<Array<Array2D<Real>>> _map_psi_face;
     342             :   Array2D<Array2D<Real3>> _map_grad_phi;
     343             :   Array2D<Array<Array2D<Real3>>> _map_grad_phi_face;
     344             :   Array2D<Array<Array2D<Real3>>> _map_grad_psi_face;
     345             :   ///@}
     346             :   /**
     347             :    * Cached physical maps on element quadrature points
     348             :    */
     349             :   ///@{
     350             :   Array<Array<Real33>> _jacobian;
     351             :   Array<Array<Real>> _jxw;
     352             :   Array<Array<Real3>> _xyz;
     353             :   ///@}
     354             : 
     355             :   /**
     356             :    * Boundaries to cache face material properties
     357             :    */
     358             :   std::set<BoundaryID> _material_boundaries;
     359             : };
     360             : 
     361             : #ifdef MOOSE_KOKKOS_SCOPE
     362             : KOKKOS_FUNCTION inline Real
     363      228180 : Assembly::coordTransformFactor(const ContiguousSubdomainID subdomain, const Real3 point) const
     364             : {
     365      228180 :   switch (_coord_type[subdomain])
     366             :   {
     367      225240 :     case Moose::COORD_XYZ:
     368      225240 :       return 1;
     369        2800 :     case Moose::COORD_RZ:
     370        2800 :       if (_rz_radial_coord == libMesh::invalid_uint)
     371           0 :         return 2 * M_PI *
     372           0 :                (point - _rz_axis[subdomain].first).cross_product(_rz_axis[subdomain].second).norm();
     373             :       else
     374        2800 :         return 2 * M_PI * point(_rz_radial_coord);
     375         140 :     case Moose::COORD_RSPHERICAL:
     376         140 :       return 4 * M_PI * point(0) * point(0);
     377           0 :     default:
     378           0 :       return 0;
     379             :   }
     380             : }
     381             : 
     382             : KOKKOS_FUNCTION inline void
     383      122216 : Assembly::computePhysicalMap(const ElementInfo info,
     384             :                              const unsigned int qp,
     385             :                              Real33 * const jacobian,
     386             :                              Real * const JxW,
     387             :                              Real3 * const q_points) const
     388             : {
     389      122216 :   auto sid = info.subdomain;
     390      122216 :   auto eid = info.id;
     391      122216 :   auto elem_type = info.type;
     392      122216 :   auto num_nodes = kokkosMesh().getNumNodes(elem_type);
     393             : 
     394      122216 :   auto & phi = _map_phi(sid, elem_type);
     395      122216 :   auto & grad_phi = _map_grad_phi(sid, elem_type);
     396             : 
     397      122216 :   Real33 J;
     398      122216 :   Real3 xyz;
     399             : 
     400      673852 :   for (unsigned int node = 0; node < num_nodes; ++node)
     401             :   {
     402      551636 :     auto points = kokkosMesh().getNodePoint(kokkosMesh().getContiguousNodeID(eid, node));
     403             : 
     404      551636 :     if (jacobian || JxW)
     405      551636 :       J += grad_phi(node, qp).cartesian_product(points);
     406             : 
     407      551636 :     xyz += phi(node, qp) * points;
     408             :   }
     409             : 
     410      122216 :   if (jacobian)
     411      122216 :     *jacobian = J.inverse(_dimension);
     412      122216 :   if (JxW)
     413      122216 :     *JxW =
     414      122216 :         J.determinant(_dimension) * _weights(sid, elem_type)[qp] * coordTransformFactor(sid, xyz);
     415      122216 :   if (q_points)
     416      122216 :     *q_points = xyz;
     417      122216 : }
     418             : 
     419             : KOKKOS_FUNCTION inline void
     420      105964 : Assembly::computePhysicalMap(const ElementInfo info,
     421             :                              const unsigned int side,
     422             :                              const unsigned int qp,
     423             :                              Real33 * const jacobian,
     424             :                              Real * const JxW,
     425             :                              Real3 * const q_points) const
     426             : {
     427      105964 :   auto sid = info.subdomain;
     428      105964 :   auto eid = info.id;
     429      105964 :   auto elem_type = info.type;
     430      105964 :   auto num_nodes = kokkosMesh().getNumNodes(elem_type);
     431      105964 :   auto num_side_nodes = kokkosMesh().getNumNodes(elem_type, side);
     432             : 
     433      105964 :   auto & phi = _map_phi_face(sid, elem_type)(side);
     434      105964 :   auto & grad_phi = _map_grad_phi_face(sid, elem_type)(side);
     435             : 
     436      105964 :   Real33 J;
     437      105964 :   Real3 xyz;
     438             : 
     439      528768 :   for (unsigned int node = 0; node < num_nodes; ++node)
     440             :   {
     441      422804 :     auto points = kokkosMesh().getNodePoint(kokkosMesh().getContiguousNodeID(eid, node));
     442             : 
     443      422804 :     if (jacobian)
     444      422804 :       J += grad_phi(node, qp).cartesian_product(points);
     445             : 
     446      422804 :     if (JxW || q_points)
     447      422804 :       xyz += phi(node, qp) * points;
     448             :   }
     449             : 
     450      105964 :   if (jacobian)
     451      105964 :     *jacobian = J.inverse(_dimension);
     452      105964 :   if (q_points)
     453      105964 :     *q_points = xyz;
     454             : 
     455      105964 :   if (JxW)
     456             :   {
     457      105964 :     Real33 J;
     458             : 
     459      105964 :     auto & grad_psi = _map_grad_psi_face(sid, elem_type)(side);
     460             : 
     461      317366 :     for (unsigned int node = 0; node < num_side_nodes; ++node)
     462             :     {
     463      211402 :       auto points = kokkosMesh().getNodePoint(kokkosMesh().getContiguousNodeID(eid, side, node));
     464             : 
     465      211402 :       J += grad_psi(node, qp).cartesian_product(points);
     466             :     }
     467             : 
     468      105964 :     *JxW = ::Kokkos::sqrt((J * J.transpose()).determinant(_dimension - 1)) *
     469      105964 :            _weights_face(sid, elem_type)[side][qp] * coordTransformFactor(sid, xyz);
     470             :   }
     471      105964 : }
     472             : #endif
     473             : 
     474             : /**
     475             :  * The Kokkos interface that holds the host reference of the Kokkos assembly and copies it to device
     476             :  * during parallel dispatch.
     477             :  * Maintains synchronization between host and device Kokkos assemblies and provides access to the
     478             :  * appropriate Kokkos assembly depending on the architecture.
     479             :  */
     480             : class AssemblyHolder
     481             : {
     482             : public:
     483             :   /**
     484             :    * Constructor
     485             :    * @param assembly The Kokkos assembly
     486             :    */
     487        5747 :   AssemblyHolder(const Assembly & assembly) : _assembly_host(assembly), _assembly_device(assembly)
     488             :   {
     489        5747 :   }
     490             :   /**
     491             :    * Copy constructor
     492             :    */
     493      300793 :   AssemblyHolder(const AssemblyHolder & holder)
     494      247294 :     : _assembly_host(holder._assembly_host), _assembly_device(holder._assembly_host)
     495             :   {
     496      300793 :   }
     497             : 
     498             : #ifdef MOOSE_KOKKOS_SCOPE
     499             :   /**
     500             :    * Get the const reference of the Kokkos assembly
     501             :    * @returns The const reference of the Kokkos assembly depending on the architecture this function
     502             :    * is being called on
     503             :    */
     504   264135718 :   KOKKOS_FUNCTION const Assembly & kokkosAssembly() const
     505             :   {
     506   264135718 :     KOKKOS_IF_ON_HOST(return _assembly_host;)
     507             : 
     508   264051943 :     return _assembly_device;
     509             :   }
     510             : #endif
     511             : 
     512             : private:
     513             :   /**
     514             :    * Host reference of the Kokkos assembly
     515             :    */
     516             :   const Assembly & _assembly_host;
     517             :   /**
     518             :    * Device copy of the Kokkos assembly
     519             :    */
     520             :   const Assembly _assembly_device;
     521             : };
     522             : 
     523             : } // namespace Kokkos
     524             : } // namespace Moose

Generated by: LCOV version 1.14