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

Generated by: LCOV version 1.14