LCOV - code coverage report
Current view: top level - include/utils - ADUtils.h (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 419b9d Lines: 2 13 15.4 %
Date: 2025-08-08 20:01:16 Functions: 1 2 50.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://mooseframework.inl.gov
       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 "MooseError.h"
      13             : #include "MooseTypes.h"
      14             : 
      15             : class SubProblem;
      16             : class SystemBase;
      17             : namespace libMesh
      18             : {
      19             : class Elem;
      20             : }
      21             : 
      22             : namespace Moose
      23             : {
      24             : /**
      25             :  * Whether we are using global AD indexing
      26             :  */
      27             : inline bool
      28        7268 : globalADIndexing()
      29             : {
      30        7268 :   return true;
      31             : }
      32             : 
      33             : /**
      34             :  * Helper function for computing automatic differentiation offset. Let's explain how our derivative
      35             :  * index numbering scheme works:
      36             :  *
      37             :  * Let's just think about continuous finite elements for a second. We use a variable major
      38             :  * numbering scheme, such that each variables indices are in a contiguous block. Let's imagine we
      39             :  * have two variables, u and v, and we're on a \p QUAD4. The AD indices will be ordered like this:
      40             :  *
      41             :  * u0, u1, u2, u3, v0, v1, v2, v3
      42             :  *
      43             :  * \p max_dofs_per_elem should be for a \p QUAD4: 4. For a \p QUAD9, 9. \p HEX27, 27. Etc. For
      44             :  * CFEM the offset will be simply be the \p max_dofs_per_elem number times the \p var_num. So for u
      45             :  * on a \p QUAD4: 4 * 0 = 0. For v: 4 * 1. So u indices start at index 0, v indices start at
      46             :  * index 4.
      47             :  *
      48             :  * With DFEM or interface kernels it's a little more complicated. We essentially already have an
      49             :  * indices block that is \p num_vars_in_system * \p max_dofs_per_elem long, so in our two var,
      50             :  * \p QUAD4 example: 4 * 2 = 8. So what we do is that if we are on a neighbor element, we do an
      51             :  * additional offset by \p num_vars_in_system * \p max_dofs_per_elem. So now our derivative indices
      52             :  * are ordered like this:
      53             :  *
      54             :  * u0, u1, u2, u3, v0, v1, v2, v3, u0_neighbor, u1_neighbor, u2_neighbor, u3_neighbor, v0_neighbor,
      55             :  * v1_neighbor, v2_neighbor, v3_neighbor
      56             :  *
      57             :  * Finally if a lower-dimensional element is involved, then we another offset of \p
      58             :  * num_vars_in_system * \p max_dofs_per_elem:
      59             :  *
      60             :  * u0, u1, u2, u3, v0, v1, v2, v3, u0_neighbor, u1_neighbor, u2_neighbor, u3_neighbor, v0_neighbor,
      61             :  * v1_neighbor, v2_neighbor, v3_neighbor, u0_lower, u1_lower, u2_lower, u3_lower, v0_lower,
      62             :  * v1_lower, v2_lower, v3_lower
      63             :  *
      64             :  * Note that a lower dimensional block will have less indices than a higher dimensional one, but we
      65             :  * do not optimize for that consideration at this time
      66             :  *
      67             :  * @param var_num The variable number we are calculating the offset for
      68             :  * @param max_dofs_per_elem The maximum number of degrees of freedom for any one variable on an
      69             :  * element
      70             :  * @param element_type The "type" of element that we are on. Current options are
      71             :  * \p ElementType::Element, \p ElementType::Neighbor, and \p ElementType::Lower
      72             :  * @param num_vars_in_system The number of vars in the system. This is used in offset calculation
      73             :  * unless \p element_type is \p ElementType::Element
      74             :  * @return The automatic differentiation indexing offset
      75             :  *
      76             :  */
      77             : inline std::size_t
      78           0 : adOffset(unsigned int var_num,
      79             :          std::size_t max_dofs_per_elem,
      80             :          ElementType element_type = ElementType::Element,
      81             :          unsigned int num_vars_in_system = 0)
      82             : {
      83             :   // If our element type is anything other than ElementType::Element, then the user must
      84             :   // supply num_vars_in_system in order to calculate the offset
      85             :   mooseAssert(element_type == ElementType::Element || num_vars_in_system,
      86             :               "If our element type is anything other than ElementType::Element, then you "
      87             :               "must supply num_vars_in_system in order to calculate the offset");
      88             : 
      89           0 :   switch (element_type)
      90             :   {
      91           0 :     case ElementType::Element:
      92           0 :       return var_num * max_dofs_per_elem;
      93             : 
      94           0 :     case ElementType::Neighbor:
      95           0 :       return num_vars_in_system * max_dofs_per_elem + var_num * max_dofs_per_elem;
      96             : 
      97           0 :     case ElementType::Lower:
      98           0 :       return 2 * num_vars_in_system * max_dofs_per_elem + var_num * max_dofs_per_elem;
      99             : 
     100           0 :     default:
     101           0 :       mooseError(
     102             :           "Unsupported element type ",
     103           0 :           static_cast<typename std::underlying_type<decltype(element_type)>::type>(element_type));
     104             :   }
     105             : }
     106             : 
     107             : inline std::size_t
     108             : adOffset(unsigned int var_num,
     109             :          std::size_t max_dofs_per_elem,
     110             :          DGJacobianType dg_jacobian_type,
     111             :          unsigned int num_vars_in_system = 0)
     112             : {
     113             :   if (dg_jacobian_type == DGJacobianType::ElementElement ||
     114             :       dg_jacobian_type == DGJacobianType::NeighborElement)
     115             :     return adOffset(var_num, max_dofs_per_elem, ElementType::Element);
     116             :   else
     117             :     return adOffset(var_num, max_dofs_per_elem, ElementType::Neighbor, num_vars_in_system);
     118             : }
     119             : 
     120             : /**
     121             :  * Generate a map from global dof index to derivative value
     122             :  */
     123             : std::unordered_map<dof_id_type, Real>
     124             : globalDofIndexToDerivative(const ADReal & ad_real,
     125             :                            const SystemBase & sys,
     126             :                            ElementType elem_type = ElementType::Element,
     127             :                            THREAD_ID tid = 0);
     128             : 
     129             : /**
     130             :  * Generate a map from global dof index to derivative value for a (probably quadrature-point-based)
     131             :  * container like a material property or a variable value
     132             :  */
     133             : template <typename T>
     134             : auto
     135             : globalDofIndexToDerivative(const T & ad_real_container,
     136             :                            const SystemBase & sys,
     137             :                            ElementType elem_type = ElementType::Element,
     138             :                            THREAD_ID tid = 0)
     139             :     -> std::vector<std::unordered_map<
     140             :         dof_id_type,
     141             :         typename std::enable_if<std::is_same<ADReal, typename T::value_type>::value, Real>::type>>
     142             : {
     143             :   std::vector<std::unordered_map<dof_id_type, Real>> ret_val(ad_real_container.size());
     144             : 
     145             :   for (MooseIndex(ad_real_container) i = 0; i < ad_real_container.size(); ++i)
     146             :     ret_val[i] = globalDofIndexToDerivative(ad_real_container[i], sys, elem_type, tid);
     147             : 
     148             :   return ret_val;
     149             : }
     150             : 
     151             : /**
     152             :  * @returns whether we should be doing derivatives
     153             :  */
     154             : bool doDerivatives(const SubProblem & subproblem, const SystemBase & sys);
     155             : }

Generated by: LCOV version 1.14