Source code for dualmesh.ad
# SPDX-License-Identifier: LGPL-2.1-or-later
"""Elementary functions that work for both floats and AD numbers.
Kernels written in Python receive :class:`dualmesh.ADReal` values, whose
derivatives with respect to the local degrees of freedom are carried along so
that the Jacobian used by Newton's method stays exact. Use these functions
instead of :mod:`math` inside such kernels::
import dualmesh as dm
class ArrheniusReaction(dm.PythonKernel):
def compute_source(self, ctx):
temperature = ctx.value(self.temperature_index)
return self.pre_exponential * dm.exp(-self.activation / temperature)
"""
from __future__ import annotations
import builtins
import math
from . import _core
ADReal = _core.ADReal
def _dispatch(name):
ad_function = getattr(_core, name)
math_function = getattr(math, name)
def wrapper(value):
if isinstance(value, ADReal):
return ad_function(value)
return math_function(value)
wrapper.__name__ = name
wrapper.__doc__ = f"{name}(x) for floats and AD numbers."
return wrapper
sqrt = _dispatch("sqrt")
exp = _dispatch("exp")
log = _dispatch("log")
sin = _dispatch("sin")
cos = _dispatch("cos")
tanh = _dispatch("tanh")
[docs]
def abs(value): # noqa: A001 - mirrors the builtin on purpose
"""Absolute value for floats and AD numbers."""
if isinstance(value, ADReal):
return _core.abs(value)
return builtins.abs(value)
[docs]
def pow(base, exponent): # noqa: A001 - mirrors the builtin on purpose
"""Power for floats and AD numbers."""
if isinstance(base, ADReal) or isinstance(exponent, ADReal):
return base**exponent
return base**exponent