LCOV - code coverage report
Current view: top level - include/utils - MathUtils.h (source / functions) Hit Total Coverage
Test: idaholab/moose framework: d8769b Lines: 91 96 94.8 %
Date: 2025-11-07 20:01:30 Functions: 36 44 81.8 %
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 "Moose.h"
      13             : #include "MooseError.h"
      14             : #include "MooseTypes.h"
      15             : #include "libmesh/libmesh.h"
      16             : #include "libmesh/utility.h"
      17             : #include "libmesh/numeric_vector.h"
      18             : #include "libmesh/compare_types.h"
      19             : #include "libmesh/point.h"
      20             : 
      21             : namespace MathUtils
      22             : {
      23             : 
      24             : /// std::sqrt is not constexpr, so we add sqrt(2) as a constant (used in Mandel notation)
      25             : static constexpr Real sqrt2 = 1.4142135623730951;
      26             : 
      27             : Real poly1Log(Real x, Real tol, unsigned int derivative_order);
      28             : Real poly2Log(Real x, Real tol, unsigned int derivative_order);
      29             : Real poly3Log(Real x, Real tol, unsigned int derivative_order);
      30             : Real poly4Log(Real x, Real tol, unsigned int derivative_order);
      31             : Real taylorLog(Real x);
      32             : /**
      33             :  * Evaluate Cartesian coordinates of any center point of a triangle given Barycentric
      34             :  * coordinates of center point and Cartesian coordinates of triangle's vertices
      35             :  * @param p0,p1,p2 are the three non-collinear vertices in Cartesian coordinates
      36             :  * @param b0,b1,b2 is the center point in barycentric coordinates with b0+b1+b2=1, e.g.
      37             :  * (1/3,1/3,1/3) for a centroid
      38             :  * @return the center point of triangle in Cartesian coordinates
      39             :  */
      40             : Point barycentricToCartesian2D(const Point & p0,
      41             :                                const Point & p1,
      42             :                                const Point & p2,
      43             :                                const Real b0,
      44             :                                const Real b1,
      45             :                                const Real b2);
      46             : /**
      47             :  * Evaluate Cartesian coordinates of any center point of a tetrahedron given Barycentric
      48             :  * coordinates of center point and Cartesian coordinates of tetrahedon's vertices
      49             :  * @param p0,p1,p2,p3 are the three non-coplanar vertices in Cartesian coordinates
      50             :  * @param b0,b1,b2,b3 is the center point in barycentric coordinates with b0+b1+b2+b3=1, e.g.
      51             :  * (1/4,1/4,1/4,1/4) for a centroid.
      52             :  * @return the center point of tetrahedron in Cartesian coordinates
      53             :  */
      54             : Point barycentricToCartesian3D(const Point & p0,
      55             :                                const Point & p1,
      56             :                                const Point & p2,
      57             :                                const Point & p3,
      58             :                                const Real b0,
      59             :                                const Real b1,
      60             :                                const Real b2,
      61             :                                const Real b3);
      62             : /**
      63             :  * Evaluate circumcenter of a triangle given three arbitrary points
      64             :  * @param p0,p1,p2 are the three non-collinear vertices in Cartesian coordinates
      65             :  * @return the circumcenter in Cartesian coordinates
      66             :  */
      67             : Point circumcenter2D(const Point & p0, const Point & p1, const Point & p2);
      68             : /**
      69             :  * Evaluate circumcenter of a tetrahedrom given four arbitrary points
      70             :  * @param p0,p1,p2,p3 are the four non-coplanar vertices in Cartesian coordinates
      71             :  * @return the circumcenter in Cartesian coordinates
      72             :  */
      73             : Point circumcenter3D(const Point & p0, const Point & p1, const Point & p2, const Point & p3);
      74             : 
      75             : template <typename T>
      76             : T
      77          16 : round(T x)
      78             : {
      79          16 :   return ::round(x); // use round from math.h
      80             : }
      81             : 
      82             : template <typename T>
      83             : T
      84       41877 : sign(T x)
      85             : {
      86       41877 :   return x >= 0.0 ? 1.0 : -1.0;
      87             : }
      88             : 
      89             : template <typename T>
      90             : T
      91   615961759 : pow(T x, int e)
      92             : {
      93   615961759 :   bool neg = false;
      94   615961759 :   T result = 1.0;
      95             : 
      96   615961759 :   if (e < 0)
      97             :   {
      98           4 :     neg = true;
      99           4 :     e = -e;
     100             :   }
     101             : 
     102  1231442207 :   while (e)
     103             :   {
     104             :     // if bit 0 is set multiply the current power of two factor of the exponent
     105   615480448 :     if (e & 1)
     106   410401020 :       result *= x;
     107             : 
     108             :     // x is incrementally set to consecutive powers of powers of two
     109   615480448 :     x *= x;
     110             : 
     111             :     // bit shift the exponent down
     112   615480448 :     e >>= 1;
     113             :   }
     114             : 
     115   615962207 :   return neg ? 1.0 / result : result;
     116         448 : }
     117             : 
     118             : template <typename T>
     119             : T
     120             : heavyside(T x)
     121             : {
     122             :   return x < 0.0 ? 0.0 : 1.0;
     123             : }
     124             : 
     125             : template <typename T>
     126             : T
     127             : regularizedHeavyside(const T & x, Real smoothing_length)
     128             : {
     129             :   if (x <= -smoothing_length)
     130             :     return 0.0;
     131             :   else if (x < smoothing_length)
     132             :   {
     133             :     using std::sin;
     134             :     return 0.5 * (1 + sin(libMesh::pi * x / 2 / smoothing_length));
     135             :   }
     136             :   else
     137             :     return 1.0;
     138             : }
     139             : 
     140             : template <typename T>
     141             : T
     142             : regularizedHeavysideDerivative(const T & x, Real smoothing_length)
     143             : {
     144             :   if (x < smoothing_length && x > -smoothing_length)
     145             :   {
     146             :     using std::cos;
     147             :     return 0.25 * libMesh::pi / smoothing_length * (cos(libMesh::pi * x / 2 / smoothing_length));
     148             :   }
     149             :   else
     150             :     return 0.0;
     151             : }
     152             : 
     153             : template <typename T>
     154             : T
     155             : positivePart(T x)
     156             : {
     157             :   return x > 0.0 ? x : 0.0;
     158             : }
     159             : 
     160             : template <typename T>
     161             : T
     162             : negativePart(T x)
     163             : {
     164             :   return x < 0.0 ? x : 0.0;
     165             : }
     166             : 
     167             : template <
     168             :     typename T,
     169             :     typename T2,
     170             :     typename T3,
     171             :     typename std::enable_if<libMesh::ScalarTraits<T>::value && libMesh::ScalarTraits<T2>::value &&
     172             :                                 libMesh::ScalarTraits<T3>::value,
     173             :                             int>::type = 0>
     174             : void
     175     5646488 : addScaled(const T & a, const T2 & b, T3 & result)
     176             : {
     177     5646488 :   result += a * b;
     178     5646488 : }
     179             : 
     180             : template <typename T,
     181             :           typename T2,
     182             :           typename T3,
     183             :           typename std::enable_if<libMesh::ScalarTraits<T>::value, int>::type = 0>
     184             : void
     185       62316 : addScaled(const T & scalar,
     186             :           const libMesh::NumericVector<T2> & numeric_vector,
     187             :           libMesh::NumericVector<T3> & result)
     188             : {
     189       62316 :   result.add(scalar, numeric_vector);
     190       62316 : }
     191             : 
     192             : template <
     193             :     typename T,
     194             :     typename T2,
     195             :     template <typename>
     196             :     class W,
     197             :     template <typename>
     198             :     class W2,
     199             :     typename std::enable_if<std::is_same<typename W<T>::index_type, unsigned int>::value &&
     200             :                                 std::is_same<typename W2<T2>::index_type, unsigned int>::value,
     201             :                             int>::type = 0>
     202             : typename libMesh::CompareTypes<T, T2>::supertype
     203   133584148 : dotProduct(const W<T> & a, const W2<T2> & b)
     204             : {
     205   133584148 :   return a * b;
     206             : }
     207             : 
     208             : template <typename T,
     209             :           typename T2,
     210             :           template <typename>
     211             :           class W,
     212             :           template <typename>
     213             :           class W2,
     214             :           typename std::enable_if<std::is_same<typename W<T>::index_type,
     215             :                                                std::tuple<unsigned int, unsigned int>>::value &&
     216             :                                       std::is_same<typename W2<T2>::index_type,
     217             :                                                    std::tuple<unsigned int, unsigned int>>::value,
     218             :                                   int>::type = 0>
     219             : typename libMesh::CompareTypes<T, T2>::supertype
     220           0 : dotProduct(const W<T> & a, const W2<T2> & b)
     221             : {
     222           0 :   return a.contract(b);
     223             : }
     224             : 
     225             : /**
     226             :  * Evaluate a polynomial with the coefficients c at x. Note that the Polynomial
     227             :  * form is
     228             :  *   c[0]*x^s + c[1]*x^(s-1) + c[2]*x^(s-2) + ... + c[s-2]*x^2 + c[s-1]*x + c[s]
     229             :  * where s = c.size()-1 , which is counter intuitive!
     230             :  *
     231             :  * This function will be DEPRECATED soon (10/22/2020)
     232             :  *
     233             :  * The coefficient container type can be any container that provides an index
     234             :  * operator [] and a .size() method (e.g. std::vector, std::array). The return
     235             :  * type is the supertype of the container value type and the argument x.
     236             :  * The supertype is the type that can represent both number types.
     237             :  */
     238             : template <typename C,
     239             :           typename T,
     240             :           typename R = typename libMesh::CompareTypes<typename C::value_type, T>::supertype>
     241             : R
     242         368 : poly(const C & c, const T x, const bool derivative = false)
     243             : {
     244         368 :   const auto size = c.size();
     245         368 :   if (size == 0)
     246           0 :     return 0.0;
     247             : 
     248         368 :   R value = c[0];
     249         368 :   if (derivative)
     250             :   {
     251          94 :     value *= size - 1;
     252         916 :     for (std::size_t i = 1; i < size - 1; ++i)
     253         822 :       value = value * x + c[i] * (size - i - 1);
     254             :   }
     255             :   else
     256             :   {
     257        1370 :     for (std::size_t i = 1; i < size; ++i)
     258        1096 :       value = value * x + c[i];
     259             :   }
     260             : 
     261         368 :   return value;
     262             : }
     263             : 
     264             : /**
     265             :  * Evaluate a polynomial with the coefficients c at x. Note that the Polynomial
     266             :  * form is
     267             :  *   c[0] + c[1] * x + c[2] * x^2 + ...
     268             :  * The coefficient container type can be any container that provides an index
     269             :  * operator [] and a .size() method (e.g. std::vector, std::array). The return
     270             :  * type is the supertype of the container value type and the argument x.
     271             :  * The supertype is the type that can represent both number types.
     272             :  */
     273             : template <typename C,
     274             :           typename T,
     275             :           typename R = typename libMesh::CompareTypes<typename C::value_type, T>::supertype>
     276             : R
     277          10 : polynomial(const C & c, const T x)
     278             : {
     279          10 :   auto size = c.size();
     280          10 :   if (size == 0)
     281           0 :     return 0.0;
     282             : 
     283          10 :   size--;
     284          10 :   R value = c[size];
     285          54 :   for (std::size_t i = 1; i <= size; ++i)
     286          44 :     value = value * x + c[size - i];
     287             : 
     288          10 :   return value;
     289             : }
     290             : 
     291             : /**
     292             :  * Returns the derivative of polynomial(c, x) with respect to x
     293             :  */
     294             : template <typename C,
     295             :           typename T,
     296             :           typename R = typename libMesh::CompareTypes<typename C::value_type, T>::supertype>
     297             : R
     298          10 : polynomialDerivative(const C & c, const T x)
     299             : {
     300          10 :   auto size = c.size();
     301          10 :   if (size <= 1)
     302           0 :     return 0.0;
     303             : 
     304          10 :   size--;
     305          10 :   R value = c[size] * size;
     306          44 :   for (std::size_t i = 1; i < size; ++i)
     307          34 :     value = value * x + c[size - i] * (size - i);
     308             : 
     309          10 :   return value;
     310             : }
     311             : 
     312             : template <typename T, typename T2>
     313             : T
     314          90 : clamp(const T & x, T2 lowerlimit, T2 upperlimit)
     315             : {
     316          90 :   if (x < lowerlimit)
     317          18 :     return lowerlimit;
     318          72 :   if (x > upperlimit)
     319          18 :     return upperlimit;
     320          54 :   return x;
     321             : }
     322             : 
     323             : template <typename T, typename T2>
     324             : T
     325         180 : smootherStep(T x, T2 start, T2 end, bool derivative = false)
     326             : {
     327             :   mooseAssert("start < end", "Start value must be lower than end value for smootherStep");
     328         180 :   if (x <= start)
     329          36 :     return 0.0;
     330         144 :   else if (x >= end)
     331             :   {
     332          36 :     if (derivative)
     333          18 :       return 0.0;
     334             :     else
     335          18 :       return 1.0;
     336             :   }
     337         108 :   x = (x - start) / (end - start);
     338         108 :   if (derivative)
     339          54 :     return 30.0 * libMesh::Utility::pow<2>(x) * (x * (x - 2.0) + 1.0) / (end - start);
     340          54 :   return libMesh::Utility::pow<3>(x) * (x * (x * 6.0 - 15.0) + 10.0);
     341             : }
     342             : 
     343             : enum class ComputeType
     344             : {
     345             :   value,
     346             :   derivative
     347             : };
     348             : 
     349             : template <ComputeType compute_type, typename X, typename S, typename E>
     350             : auto
     351          12 : smootherStep(const X & x, const S & start, const E & end)
     352             : {
     353             :   mooseAssert("start < end", "Start value must be lower than end value for smootherStep");
     354          12 :   if (x <= start)
     355           4 :     return 0.0;
     356           8 :   else if (x >= end)
     357             :   {
     358             :     if constexpr (compute_type == ComputeType::derivative)
     359           2 :       return 0.0;
     360             :     if constexpr (compute_type == ComputeType::value)
     361           2 :       return 1.0;
     362             :   }
     363           4 :   const auto u = (x - start) / (end - start);
     364             :   if constexpr (compute_type == ComputeType::derivative)
     365           2 :     return 30.0 * libMesh::Utility::pow<2>(u) * (u * (u - 2.0) + 1.0) / (end - start);
     366             :   if constexpr (compute_type == ComputeType::value)
     367           2 :     return libMesh::Utility::pow<3>(u) * (u * (u * 6.0 - 15.0) + 10.0);
     368             : }
     369             : 
     370             : /**
     371             :  * Helper function templates to set a variable to zero.
     372             :  * Specializations may have to be implemented (for examples see
     373             :  * RankTwoTensor, RankFourTensor).
     374             :  */
     375             : template <typename T>
     376             : inline void
     377       56993 : mooseSetToZero(T & v)
     378             : {
     379             :   /**
     380             :    * The default for non-pointer types is to assign zero.
     381             :    * This should either do something sensible, or throw a compiler error.
     382             :    * Otherwise the T type is designed badly.
     383             :    */
     384       56993 :   v = 0;
     385       56993 : }
     386             : template <typename T>
     387             : inline void
     388             : mooseSetToZero(T *&)
     389             : {
     390             :   mooseError("mooseSetToZero does not accept pointers");
     391             : }
     392             : 
     393             : template <>
     394             : inline void
     395             : mooseSetToZero(std::vector<Real> & vec)
     396             : {
     397             :   for (auto & v : vec)
     398             :     v = 0.;
     399             : }
     400             : 
     401             : /**
     402             :  * generate a complete multi index table for given dimension and order
     403             :  * i.e. given dim = 2, order = 2, generated table will have the following content
     404             :  * 0 0
     405             :  * 1 0
     406             :  * 0 1
     407             :  * 2 0
     408             :  * 1 1
     409             :  * 0 2
     410             :  * The first number in each entry represents the order of the first variable, i.e. x;
     411             :  * The second number in each entry represents the order of the second variable, i.e. y.
     412             :  * Multiplication is implied between numbers in each entry, i.e. 1 1 represents x^1 * y^1
     413             :  *
     414             :  * @param dim dimension of the multi-index, here dim = mesh dimension
     415             :  * @param order generate the multi-index up to certain order
     416             :  * @return a data structure holding entries representing the complete multi index
     417             :  */
     418             : std::vector<std::vector<unsigned int>> multiIndex(unsigned int dim, unsigned int order);
     419             : 
     420             : template <ComputeType compute_type, typename X, typename X1, typename X2, typename Y1, typename Y2>
     421             : auto
     422           4 : linearInterpolation(const X & x, const X1 & x1, const X2 & x2, const Y1 & y1, const Y2 & y2)
     423             : {
     424           4 :   const auto m = (y2 - y1) / (x2 - x1);
     425             :   if constexpr (compute_type == ComputeType::derivative)
     426           2 :     return m;
     427             :   if constexpr (compute_type == ComputeType::value)
     428           2 :     return m * (x - x1) + y1;
     429             : }
     430             : 
     431             : /**
     432             :  * perform modulo operator for Euclidean division that ensures a non-negative result
     433             :  * @param dividend dividend of the modulo operation
     434             :  * @param divisor divisor of the modulo operation
     435             :  * @return the non-negative remainder when the dividend is divided by the divisor
     436             :  */
     437             : template <typename T1, typename T2>
     438             : std::size_t
     439       10560 : euclideanMod(T1 dividend, T2 divisor)
     440             : {
     441       10560 :   return (dividend % divisor + divisor) % divisor;
     442             : }
     443             : 
     444             : /**
     445             :  * automatic prefixing for naming material properties based on gradients of coupled
     446             :  * variables/functors
     447             :  */
     448             : template <typename T>
     449             : T
     450        2083 : gradName(const T & base_prop_name)
     451             : {
     452        2083 :   return "grad_" + base_prop_name;
     453             : }
     454             : 
     455             : /**
     456             :  * automatic prefixing for naming material properties based on time derivatives of coupled
     457             :  * variables/functors
     458             :  */
     459             : template <typename T>
     460             : T
     461        4429 : timeDerivName(const T & base_prop_name)
     462             : {
     463        4429 :   return "d" + base_prop_name + "_dt";
     464             : }
     465             : 
     466             : /**
     467             :  * Computes the Kronecker product of two matrices.
     468             :  * @param product Reference to the product matrix
     469             :  * @param mat_A Reference to the first matrix
     470             :  * @param mat_B Reference to the other matrix
     471             :  */
     472             : void kron(RealEigenMatrix & product, const RealEigenMatrix & mat_A, const RealEigenMatrix & mat_B);
     473             : 
     474             : } // namespace MathUtils
     475             : 
     476             : /// A helper function for MathUtils::multiIndex
     477             : std::vector<std::vector<unsigned int>> multiIndexHelper(unsigned int N, unsigned int K);

Generated by: LCOV version 1.14